Merge mozilla-central to autoland
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Thu, 14 Jul 2016 13:49:32 +0200
changeset 330013 29c9b171623423acdf3aa228be457c56eee42839
parent 330012 cb1812acfcd1ed05706e0bd9405668d11516cfd4 (current diff)
parent 330010 08f8a5aacd8308a73f6040fe522be7ba38497561 (diff)
child 330014 63c2807a44393a652c63953909d96ecfa87811ad
push id9858
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 14:37:10 +0000
treeherdermozilla-aurora@203106ef6cb6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone50.0a1
Merge mozilla-central to autoland
devtools/client/shared/widgets/mdn-docs-frame.xhtml
devtools/client/themes/images/debugger-blackbox.png
devtools/client/themes/images/debugger-blackbox@2x.png
devtools/client/themes/images/debugger-pause.png
devtools/client/themes/images/debugger-pause@2x.png
devtools/client/themes/images/debugger-play.png
devtools/client/themes/images/debugger-play@2x.png
devtools/client/themes/images/debugger-prettyprint.png
devtools/client/themes/images/debugger-prettyprint@2x.png
devtools/client/themes/images/debugger-step-in.png
devtools/client/themes/images/debugger-step-in@2x.png
devtools/client/themes/images/debugger-step-out.png
devtools/client/themes/images/debugger-step-out@2x.png
devtools/client/themes/images/fast-forward.png
devtools/client/themes/images/fast-forward@2x.png
devtools/client/themes/images/itemToggle.png
devtools/client/themes/images/itemToggle@2x.png
devtools/client/themes/images/rewind.png
devtools/client/themes/images/rewind@2x.png
devtools/client/themes/images/timeline-filter.svg
--- a/chrome/nsChromeRegistryChrome.cpp
+++ b/chrome/nsChromeRegistryChrome.cpp
@@ -118,25 +118,27 @@ nsChromeRegistryChrome::Init()
   bool safeMode = false;
   nsCOMPtr<nsIXULRuntime> xulrun (do_GetService(XULAPPINFO_SERVICE_CONTRACTID));
   if (xulrun)
     xulrun->GetInSafeMode(&safeMode);
 
   nsCOMPtr<nsIPrefService> prefserv (do_GetService(NS_PREFSERVICE_CONTRACTID));
   nsCOMPtr<nsIPrefBranch> prefs;
 
-  if (safeMode)
-    prefserv->GetDefaultBranch(nullptr, getter_AddRefs(prefs));
-  else
-    prefs = do_QueryInterface(prefserv);
+  if (prefserv) {
+    if (safeMode) {
+      prefserv->GetDefaultBranch(nullptr, getter_AddRefs(prefs));
+    } else {
+      prefs = do_QueryInterface(prefserv);
+    }
+  }
 
   if (!prefs) {
     NS_WARNING("Could not get pref service!");
-  }
-  else {
+  } else {
     nsXPIDLCString provider;
     rv = prefs->GetCharPref(SELECTED_SKIN_PREF, getter_Copies(provider));
     if (NS_SUCCEEDED(rv))
       mSelectedSkin = provider;
 
     SelectLocaleFromPref(prefs);
 
     rv = prefs->AddObserver(MATCH_OS_LOCALE_PREF, this, true);
--- a/devtools/client/aboutdebugging/test/browser_addons_debug_bootstrapped.js
+++ b/devtools/client/aboutdebugging/test/browser_addons_debug_bootstrapped.js
@@ -1,12 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 "use strict";
 
+// Avoid test timeouts that can occur while waiting for the "addon-console-works" message.
+requestLongerTimeout(2);
+
 const ADDON_ID = "test-devtools@mozilla.org";
 const ADDON_NAME = "test-devtools";
 
 const { BrowserToolboxProcess } = Cu.import("resource://devtools/client/framework/ToolboxProcess.jsm", {});
 
 add_task(function* () {
   yield new Promise(resolve => {
     let options = {"set": [
--- a/devtools/client/canvasdebugger/canvasdebugger.xul
+++ b/devtools/client/canvasdebugger/canvasdebugger.xul
@@ -29,17 +29,17 @@
           <toolbarbutton id="record-snapshot"
                          class="devtools-toolbarbutton"
                          oncommand="SnapshotsListView._onRecordButtonClick()"
                          tooltiptext="&canvasDebuggerUI.recordSnapshot.tooltip;"
                          hidden="true"/>
           <toolbarbutton id="import-snapshot"
                          class="devtools-toolbarbutton"
                          oncommand="SnapshotsListView._onImportButtonClick()"
-                         label="&canvasDebuggerUI.importSnapshot;"/>
+                         tooltiptext="&canvasDebuggerUI.importSnapshot;"/>
         </hbox>
       </toolbar>
       <vbox id="snapshots-list" flex="1"/>
     </vbox>
 
     <vbox id="debugging-pane" class="devtools-main-content" flex="1">
       <hbox id="reload-notice"
             class="notice-container"
--- a/devtools/client/debugger/test/mochitest/browser_dbg_sources-webext-contentscript.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_sources-webext-contentscript.js
@@ -37,17 +37,17 @@ function test() {
     let options = {
       source: `moz-extension://${uuid}/webext-content-script.js`,
       line: 1
     };
     [,, gPanel] = yield initDebugger(TAB_URL, options);
     gDebugger = gPanel.panelWin;
     gSources = gDebugger.DebuggerView.Sources;
 
-    is(gSources.values.length, 1, "Should have 1 source");
+    is(gSources.values.length, 2, "Should have 2 sources");
 
     let item = gSources.getItemForAttachment(attachment => {
       return attachment.source.url.includes("moz-extension");
     });
 
     ok(item, "Got the expected WebExtensions ContentScript source");
     ok(item && item.attachment.source.url.includes(item.attachment.group),
        "The source is in the expected source group");
--- a/devtools/client/framework/menu.js
+++ b/devtools/client/framework/menu.js
@@ -59,17 +59,27 @@ Menu.prototype.insert = function (pos, m
  *
  * @param {int} screenX
  * @param {int} screenY
  * @param Toolbox toolbox (non standard)
  *        Needed so we in which window to inject XUL
  */
 Menu.prototype.popup = function (screenX, screenY, toolbox) {
   let doc = toolbox.doc;
-  let popup = doc.createElement("menupopup");
+  let popupset = doc.querySelector("popupset");
+  // See bug 1285229, on Windows, opening the same popup multiple times in a
+  // row ends up duplicating the popup. The newly inserted popup doesn't
+  // dismiss the old one. So remove any previously displayed popup before
+  // opening a new one.
+  let popup = popupset.querySelector("menupopup[menu-api=\"true\"]");
+  if (popup) {
+    popup.hidePopup();
+  }
+
+  popup = doc.createElement("menupopup");
   popup.setAttribute("menu-api", "true");
 
   if (this.id) {
     popup.id = this.id;
   }
   this._createMenuItems(popup);
 
   // Remove the menu from the DOM once it's hidden.
@@ -81,17 +91,17 @@ Menu.prototype.popup = function (screenX
   });
 
   popup.addEventListener("popupshown", (e) => {
     if (e.target === popup) {
       this.emit("open");
     }
   });
 
-  doc.querySelector("popupset").appendChild(popup);
+  popupset.appendChild(popup);
   popup.openPopupAtScreen(screenX, screenY, true);
 };
 
 Menu.prototype._createMenuItems = function (parent) {
   let doc = parent.ownerDocument;
   this.menuitems.forEach(item => {
     if (!item.visible) {
       return;
--- a/devtools/client/framework/toolbox.xul
+++ b/devtools/client/framework/toolbox.xul
@@ -1,13 +1,14 @@
 <?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/. -->
 <?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://devtools/skin/toolbox.css" type="text/css"?>
 <?xml-stylesheet href="resource://devtools/client/shared/components/notification-box.css" type="text/css"?>
 
 <?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
 
 <!DOCTYPE window [
 <!ENTITY % toolboxDTD SYSTEM "chrome://devtools/locale/toolbox.dtd" >
 %toolboxDTD;
 <!ENTITY % editMenuStrings SYSTEM "chrome://global/locale/editMenuOverlay.dtd">
--- a/devtools/client/inspector/markup/markup.js
+++ b/devtools/client/inspector/markup/markup.js
@@ -2640,35 +2640,33 @@ function MarkupElementContainer(markupVi
   } else {
     throw new Error("Invalid node for MarkupElementContainer");
   }
 
   this.tagLine.appendChild(this.editor.elt);
 }
 
 MarkupElementContainer.prototype = Heritage.extend(MarkupContainer.prototype, {
-  _buildEventTooltipContent: function (target, tooltip) {
+  _buildEventTooltipContent: Task.async(function* (target, tooltip) {
     if (target.hasAttribute("data-event")) {
-      tooltip.hide(target);
-
-      this.node.getEventListenerInfo().then(listenerInfo => {
-        let toolbox = this.markup._inspector.toolbox;
-        setEventTooltip(tooltip, listenerInfo, toolbox);
-        // Disable the image preview tooltip while we display the event details
-        this.markup._disableImagePreviewTooltip();
-        tooltip.once("hidden", () => {
-          // Enable the image preview tooltip after closing the event details
-          this.markup._enableImagePreviewTooltip();
-        });
-        tooltip.show(target);
+      yield tooltip.hide();
+
+      let listenerInfo = yield this.node.getEventListenerInfo();
+
+      let toolbox = this.markup._inspector.toolbox;
+      setEventTooltip(tooltip, listenerInfo, toolbox);
+      // Disable the image preview tooltip while we display the event details
+      this.markup._disableImagePreviewTooltip();
+      tooltip.once("hidden", () => {
+        // Enable the image preview tooltip after closing the event details
+        this.markup._enableImagePreviewTooltip();
       });
-      return true;
+      tooltip.show(target);
     }
-    return undefined;
-  },
+  }),
 
   /**
    * Generates the an image preview for this Element. The element must be an
    * image or canvas (@see isPreviewable).
    *
    * @return {Promise} that is resolved with an object of form
    *         { data, size: { naturalWidth, naturalHeight, resizeRatio } } where
    *         - data is the data-uri for the image preview.
--- a/devtools/client/inspector/markup/test/browser_markup_load_01.js
+++ b/devtools/client/inspector/markup/test/browser_markup_load_01.js
@@ -53,17 +53,17 @@ add_task(function* () {
 });
 
 function* chooseWithInspectElementContextMenu(selector, testActor) {
   yield BrowserTestUtils.synthesizeMouseAtCenter(selector, {
     type: "contextmenu",
     button: 2
   }, gBrowser.selectedBrowser);
 
-  yield testActor.synthesizeKey({key: "Q", options: {}});
+  yield EventUtils.synthesizeKey("Q", {});
 }
 
 function waitForLinkedBrowserEvent(tab, event) {
   let def = defer();
   tab.linkedBrowser.addEventListener(event, function cb() {
     tab.linkedBrowser.removeEventListener(event, cb, true);
     def.resolve();
   }, true);
--- a/devtools/client/inspector/markup/test/helper_events_test_runner.js
+++ b/devtools/client/inspector/markup/test/helper_events_test_runner.js
@@ -97,15 +97,15 @@ function* checkEventsForNode(test, inspe
     }
 
     // Make sure the header is not hidden by scrollbars before clicking.
     header.scrollIntoView();
 
     EventUtils.synthesizeMouseAtCenter(header, {}, type.ownerGlobal);
     yield tooltip.once("event-tooltip-ready");
 
-    let editor = tooltip.eventEditors.get(contentBox).editor;
+    let editor = tooltip.eventTooltip._eventEditors.get(contentBox).editor;
     is(editor.getText(), expected[i].handler,
        "handler matches for " + cssSelector);
   }
 
   tooltip.hide();
 }
--- a/devtools/client/inspector/rules/test/browser_rules_context-menu-show-mdn-docs-02.js
+++ b/devtools/client/inspector/rules/test/browser_rules_context-menu-show-mdn-docs-02.js
@@ -7,17 +7,17 @@
  * with the MDN docs tooltip.
  *
  * If you display the context click on a property name in the rule view, you
  * should see a menu item "Show MDN Docs". If you click that item, the MDN
  * docs tooltip should be shown, containing docs from MDN for that property.
  *
  * This file tests that:
  * - clicking the context menu item shows the tooltip
- * - pressing "Escape" while the tooltip is showing hides the tooltip
+ * - the tooltip content matches the property name for which the context menu was opened
  */
 
 "use strict";
 
 const {setBaseCssDocsUrl} =
   require("devtools/client/shared/widgets/MdnDocsWidget");
 
 const PROPERTYNAME = "color";
@@ -31,20 +31,17 @@ const TEST_DOC = `
     </body>
   </html>
 `;
 
 add_task(function* () {
   yield addTab("data:text/html;charset=utf8," + encodeURIComponent(TEST_DOC));
   let {inspector, view} = yield openRuleView();
   yield selectNode("div", inspector);
-  yield testShowAndHideMdnTooltip(view);
-});
 
-function* testShowMdnTooltip(view) {
   setBaseCssDocsUrl(URL_ROOT);
 
   info("Setting the popupNode for the MDN docs tooltip");
 
   let {nameSpan} = getRuleViewProperty(view, "element", PROPERTYNAME);
 
   let allMenuItems = openStyleContextMenuAndGetAllItems(view, nameSpan.firstChild);
   let menuitemShowMdnDocs = allMenuItems.find(item => item.label ===
@@ -52,35 +49,13 @@ function* testShowMdnTooltip(view) {
 
   let cssDocs = view.tooltips.cssDocs;
 
   info("Showing the MDN docs tooltip");
   let onShown = cssDocs.tooltip.once("shown");
   menuitemShowMdnDocs.click();
   yield onShown;
   ok(true, "The MDN docs tooltip was shown");
-}
-
-/**
- * Test that:
- *  - the MDN tooltip is shown when we click the context menu item
- *  - the tooltip's contents have been initialized (we don't fully
- *  test this here, as it's fully tested with the tooltip test code)
- *  - the tooltip is hidden when we press Escape
- */
-function* testShowAndHideMdnTooltip(view) {
-  yield testShowMdnTooltip(view);
 
   info("Quick check that the tooltip contents are set");
-  let cssDocs = view.tooltips.cssDocs;
-
-  // FIXME: Remove the comment below when bug 1246896 is fixed.
-  /* eslint-disable mozilla/no-cpows-in-tests */
-  let tooltipDocument = cssDocs.tooltip.content.contentDocument;
-  let h1 = tooltipDocument.getElementById("property-name");
+  let h1 = cssDocs.tooltip.container.querySelector(".mdn-property-name");
   is(h1.textContent, PROPERTYNAME, "The MDN docs tooltip h1 is correct");
-
-  info("Simulate pressing the 'Escape' key");
-  let onHidden = cssDocs.tooltip.once("hidden");
-  EventUtils.sendKey("escape");
-  yield onHidden;
-  ok(true, "The MDN docs tooltip was hidden on pressing 'escape'");
-}
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/rules/test/browser_rules_css-docs-tooltip_closes-on-escape.js
@@ -0,0 +1,51 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Test that the CssDocs tooltip of the ruleview can be closed when pressing the Escape
+ * key.
+ */
+
+"use strict";
+
+const {setBaseCssDocsUrl} =
+  require("devtools/client/shared/widgets/MdnDocsWidget");
+
+const PROPERTYNAME = "color";
+
+const TEST_URI = `
+  <html>
+    <body>
+      <div style="color: red">
+        Test "Show MDN Docs" closes on escape
+      </div>
+    </body>
+  </html>
+`;
+
+/**
+ * Test that the tooltip is hidden when we press Escape
+ */
+add_task(function* () {
+  yield addTab("data:text/html;charset=utf8," + encodeURIComponent(TEST_URI));
+  let {inspector, view} = yield openRuleView();
+  yield selectNode("div", inspector);
+
+  setBaseCssDocsUrl(URL_ROOT);
+
+  info("Retrieve a valid anchor for the CssDocs tooltip");
+  let {nameSpan} = getRuleViewProperty(view, "element", PROPERTYNAME);
+
+  info("Showing the MDN docs tooltip");
+  let onShown = view.tooltips.cssDocs.tooltip.once("shown");
+  view.tooltips.cssDocs.show(nameSpan, PROPERTYNAME);
+  yield onShown;
+  ok(true, "The MDN docs tooltip was shown");
+
+  info("Simulate pressing the 'Escape' key");
+  let onHidden = view.tooltips.cssDocs.tooltip.once("hidden");
+  EventUtils.sendKey("escape");
+  yield onHidden;
+  ok(true, "The MDN docs tooltip was hidden on pressing 'escape'");
+});
--- a/devtools/client/inspector/shared/style-inspector-overlays.js
+++ b/devtools/client/inspector/shared/style-inspector-overlays.js
@@ -15,19 +15,21 @@
 const {getColor} = require("devtools/client/shared/theme");
 const {HTMLTooltip} = require("devtools/client/shared/widgets/HTMLTooltip");
 const {
   getImageDimensions,
   setImageTooltip,
   setBrokenImageTooltip,
 } = require("devtools/client/shared/widgets/tooltip/ImageTooltipHelper");
 const {
+  CssDocsTooltip,
+} = require("devtools/client/shared/widgets/tooltip/CssDocsTooltip");
+const {
   SwatchColorPickerTooltip,
   SwatchCubicBezierTooltip,
-  CssDocsTooltip,
   SwatchFilterTooltip
 } = require("devtools/client/shared/widgets/Tooltip");
 const EventEmitter = require("devtools/shared/event-emitter");
 const promise = require("promise");
 const {Task} = require("devtools/shared/task");
 const Services = require("Services");
 
 const PREF_IMAGE_TOOLTIP_SIZE = "devtools.inspector.imagePreviewTooltipSize";
@@ -271,32 +273,31 @@ TooltipsOverlay.prototype = {
    * Add the tooltips overlay to the view. This will start tracking mouse
    * movements and display tooltips when needed
    */
   addToView: function () {
     if (this._isStarted || this._isDestroyed) {
       return;
     }
 
-    let panelDoc = this.view.inspector.panelDoc;
+    let { toolbox } = this.view.inspector;
 
     // Image, fonts, ... preview tooltip
-    this.previewTooltip = new HTMLTooltip(this.view.inspector.toolbox, {
+    this.previewTooltip = new HTMLTooltip(toolbox, {
       type: "arrow",
       useXulWrapper: true
     });
     this.previewTooltip.startTogglingOnHover(this.view.element,
       this._onPreviewTooltipTargetHover.bind(this));
 
     // MDN CSS help tooltip
-    this.cssDocs = new CssDocsTooltip(panelDoc);
+    this.cssDocs = new CssDocsTooltip(toolbox);
 
     if (this.isRuleView) {
       // Color picker tooltip
-      let { toolbox } = this.view.inspector;
       this.colorPicker = new SwatchColorPickerTooltip(toolbox);
       // Cubic bezier tooltip
       this.cubicBezier = new SwatchCubicBezierTooltip(toolbox);
       // Filter editor tooltip
       this.filterEditor = new SwatchFilterTooltip(toolbox);
     }
 
     this._isStarted = true;
@@ -388,17 +389,17 @@ TooltipsOverlay.prototype = {
       this.colorPicker.hide();
     }
 
     if (this.isRuleView && this.cubicBezier.tooltip.isVisible()) {
       this.cubicBezier.revert();
       this.cubicBezier.hide();
     }
 
-    if (this.isRuleView && this.cssDocs.tooltip.isShown()) {
+    if (this.isRuleView && this.cssDocs.tooltip.isVisible()) {
       this.cssDocs.hide();
     }
 
     if (this.isRuleView && this.filterEditor.tooltip.isVisible()) {
       this.filterEditor.revert();
       this.filterEdtior.hide();
     }
 
--- a/devtools/client/jar.mn
+++ b/devtools/client/jar.mn
@@ -123,17 +123,16 @@ devtools.jar:
     content/framework/dev-edition-promo/dev-edition-logo.png (framework/dev-edition-promo/dev-edition-logo.png)
     content/inspector/inspector.xul (inspector/inspector.xul)
     content/inspector/inspector.css (inspector/inspector.css)
     content/framework/connect/connect.xhtml (framework/connect/connect.xhtml)
     content/framework/connect/connect.css (framework/connect/connect.css)
     content/framework/connect/connect.js (framework/connect/connect.js)
     content/shared/widgets/graphs-frame.xhtml (shared/widgets/graphs-frame.xhtml)
     content/shared/widgets/cubic-bezier.css (shared/widgets/cubic-bezier.css)
-    content/shared/widgets/mdn-docs-frame.xhtml (shared/widgets/mdn-docs-frame.xhtml)
     content/shared/widgets/mdn-docs.css (shared/widgets/mdn-docs.css)
     content/shared/widgets/filter-widget.css (shared/widgets/filter-widget.css)
     content/shared/widgets/spectrum.css (shared/widgets/spectrum.css)
     content/eyedropper/eyedropper.xul (eyedropper/eyedropper.xul)
     content/eyedropper/crosshairs.css (eyedropper/crosshairs.css)
     content/eyedropper/nocursor.css (eyedropper/nocursor.css)
     content/aboutdebugging/aboutdebugging.xhtml (aboutdebugging/aboutdebugging.xhtml)
     content/aboutdebugging/aboutdebugging.css (aboutdebugging/aboutdebugging.css)
@@ -146,16 +145,17 @@ devtools.jar:
 %   skin devtools classic/1.0 %skin/
     skin/devtools-browser.css (themes/devtools-browser.css)
     skin/common.css (themes/common.css)
     skin/splitters.css (themes/splitters.css)
     skin/dark-theme.css (themes/dark-theme.css)
     skin/light-theme.css (themes/light-theme.css)
     skin/firebug-theme.css (themes/firebug-theme.css)
     skin/toolbars.css (themes/toolbars.css)
+    skin/toolbox.css (themes/toolbox.css)
     skin/tooltips.css (themes/tooltips.css)
     skin/variables.css (themes/variables.css)
     skin/images/add.svg (themes/images/add.svg)
     skin/images/filters.svg (themes/images/filters.svg)
     skin/images/filter-swatch.svg (themes/images/filter-swatch.svg)
     skin/images/angle-swatch.svg (themes/images/angle-swatch.svg)
     skin/images/pseudo-class.svg (themes/images/pseudo-class.svg)
     skin/images/controls.png (themes/images/controls.png)
@@ -196,60 +196,49 @@ devtools.jar:
     skin/eyedropper.css (themes/eyedropper.css)
     skin/canvasdebugger.css (themes/canvasdebugger.css)
     skin/debugger.css (themes/debugger.css)
     skin/netmonitor.css (themes/netmonitor.css)
     skin/dom.css (themes/dom.css)
     skin/performance.css (themes/performance.css)
     skin/memory.css (themes/memory.css)
     skin/promisedebugger.css (themes/promisedebugger.css)
-    skin/images/timeline-filter.svg (themes/images/timeline-filter.svg)
     skin/scratchpad.css (themes/scratchpad.css)
     skin/shadereditor.css (themes/shadereditor.css)
     skin/storage.css (themes/storage.css)
     skin/splitview.css (themes/splitview.css)
     skin/styleeditor.css (themes/styleeditor.css)
     skin/webaudioeditor.css (themes/webaudioeditor.css)
     skin/components-frame.css (themes/components-frame.css)
     skin/components-h-split-box.css (themes/components-h-split-box.css)
     skin/jit-optimizations.css (themes/jit-optimizations.css)
     skin/images/magnifying-glass.png (themes/images/magnifying-glass.png)
     skin/images/magnifying-glass@2x.png (themes/images/magnifying-glass@2x.png)
     skin/images/magnifying-glass-light.png (themes/images/magnifying-glass-light.png)
     skin/images/magnifying-glass-light@2x.png (themes/images/magnifying-glass-light@2x.png)
     skin/images/filter.svg (themes/images/filter.svg)
     skin/images/search.svg (themes/images/search.svg)
-    skin/images/itemToggle.png (themes/images/itemToggle.png)
-    skin/images/itemToggle@2x.png (themes/images/itemToggle@2x.png)
+    skin/images/itemToggle.svg (themes/images/itemToggle.svg)
     skin/images/itemArrow-dark-rtl.svg (themes/images/itemArrow-dark-rtl.svg)
     skin/images/itemArrow-dark-ltr.svg (themes/images/itemArrow-dark-ltr.svg)
     skin/images/itemArrow-rtl.svg (themes/images/itemArrow-rtl.svg)
     skin/images/itemArrow-ltr.svg (themes/images/itemArrow-ltr.svg)
     skin/images/noise.png (themes/images/noise.png)
     skin/images/dropmarker.svg (themes/images/dropmarker.svg)
     skin/layout.css (themes/layout.css)
     skin/images/geometry-editor.svg (themes/images/geometry-editor.svg)
-    skin/images/debugger-pause.png (themes/images/debugger-pause.png)
-    skin/images/debugger-pause@2x.png (themes/images/debugger-pause@2x.png)
-    skin/images/debugger-play.png (themes/images/debugger-play.png)
-    skin/images/debugger-play@2x.png (themes/images/debugger-play@2x.png)
-    skin/images/fast-forward.png (themes/images/fast-forward.png)
-    skin/images/fast-forward@2x.png (themes/images/fast-forward@2x.png)
-    skin/images/rewind.png (themes/images/rewind.png)
-    skin/images/rewind@2x.png (themes/images/rewind@2x.png)
-    skin/images/debugger-step-in.png (themes/images/debugger-step-in.png)
-    skin/images/debugger-step-in@2x.png (themes/images/debugger-step-in@2x.png)
-    skin/images/debugger-step-out.png (themes/images/debugger-step-out.png)
-    skin/images/debugger-step-out@2x.png (themes/images/debugger-step-out@2x.png)
-    skin/images/debugger-step-over.png (themes/images/debugger-step-over.png)
-    skin/images/debugger-step-over@2x.png (themes/images/debugger-step-over@2x.png)
-    skin/images/debugger-blackbox.png (themes/images/debugger-blackbox.png)
-    skin/images/debugger-blackbox@2x.png (themes/images/debugger-blackbox@2x.png)
-    skin/images/debugger-prettyprint.png (themes/images/debugger-prettyprint.png)
-    skin/images/debugger-prettyprint@2x.png (themes/images/debugger-prettyprint@2x.png)
+    skin/images/pause.svg (themes/images/pause.svg)
+    skin/images/play.svg (themes/images/play.svg)
+    skin/images/fast-forward.svg (themes/images/fast-forward.svg)
+    skin/images/rewind.svg (themes/images/rewind.svg)
+    skin/images/debugger-step-in.svg (themes/images/debugger-step-in.svg)
+    skin/images/debugger-step-out.svg (themes/images/debugger-step-out.svg)
+    skin/images/debugger-step-over.svg (themes/images/debugger-step-over.svg)
+    skin/images/debugger-blackbox.svg (themes/images/debugger-blackbox.svg)
+    skin/images/debugger-prettyprint.svg (themes/images/debugger-prettyprint.svg)
     skin/images/debugger-toggleBreakpoints.svg (themes/images/debugger-toggleBreakpoints.svg)
     skin/images/tracer-icon.png (themes/images/tracer-icon.png)
     skin/images/tracer-icon@2x.png (themes/images/tracer-icon@2x.png)
     skin/images/responsivemode/responsive-se-resizer.png (themes/images/responsivemode/responsive-se-resizer.png)
     skin/images/responsivemode/responsive-se-resizer@2x.png (themes/images/responsivemode/responsive-se-resizer@2x.png)
     skin/images/responsivemode/responsive-vertical-resizer.png (themes/images/responsivemode/responsive-vertical-resizer.png)
     skin/images/responsivemode/responsive-vertical-resizer@2x.png (themes/images/responsivemode/responsive-vertical-resizer@2x.png)
     skin/images/responsivemode/responsive-horizontal-resizer.png (themes/images/responsivemode/responsive-horizontal-resizer.png)
@@ -337,16 +326,17 @@ devtools.jar:
     skin/tooltip/arrow-vertical-light@2x.png (themes/tooltip/arrow-vertical-light@2x.png)
     skin/images/reload.svg (themes/images/reload.svg)
     skin/images/security-state-broken.svg (themes/images/security-state-broken.svg)
     skin/images/security-state-insecure.svg (themes/images/security-state-insecure.svg)
     skin/images/security-state-local.svg (themes/images/security-state-local.svg)
     skin/images/security-state-secure.svg (themes/images/security-state-secure.svg)
     skin/images/security-state-weak.svg (themes/images/security-state-weak.svg)
     skin/images/diff.svg (themes/images/diff.svg)
+    skin/images/import.svg (themes/images/import.svg)
     skin/images/pane-collapse.svg (themes/images/pane-collapse.svg)
     skin/images/pane-expand.svg (themes/images/pane-expand.svg)
 
     # Firebug Theme
     skin/images/firebug/read-only.svg (themes/images/firebug/read-only.svg)
     skin/images/firebug/spinner.png (themes/images/firebug/spinner.png)
     skin/images/firebug/twisty-closed-firebug.svg (themes/images/firebug/twisty-closed-firebug.svg)
     skin/images/firebug/twisty-open-firebug.svg (themes/images/firebug/twisty-open-firebug.svg)
--- a/devtools/client/memory/components/toolbar.js
+++ b/devtools/client/memory/components/toolbar.js
@@ -267,19 +267,17 @@ module.exports = createClass({
           ),
 
           dom.button(
             {
               id: "import-snapshot",
               className: "devtools-toolbarbutton import-snapshot devtools-button",
               onClick: onImportClick,
               title: L10N.getStr("import-snapshot"),
-              "data-text-only": true,
-            },
-            L10N.getStr("import-snapshot")
+            }
           )
         ),
 
         dom.label(
           {
             id: "record-allocation-stacks-label",
             title: L10N.getStr("checkbox.recordAllocationStacks.tooltip"),
           },
--- a/devtools/client/performance/performance.xul
+++ b/devtools/client/performance/performance.xul
@@ -87,17 +87,17 @@
           <toolbarbutton id="clear-button"
                          class="devtools-toolbarbutton devtools-clear-icon"
                          tooltiptext="&performanceUI.clearButton;"/>
           <toolbarbutton id="main-record-button"
                          class="devtools-toolbarbutton record-button"
                          tooltiptext="&performanceUI.recordButton.tooltip;"/>
           <toolbarbutton id="import-button"
                          class="devtools-toolbarbutton"
-                         label="&performanceUI.importButton;"/>
+                         tooltiptext="&performanceUI.importButton;"/>
         </hbox>
       </toolbar>
       <vbox id="recordings-list" class="theme-sidebar" flex="1"/>
     </vbox>
 
     <!-- Main panel content -->
     <vbox id="performance-pane" flex="1">
 
--- a/devtools/client/shared/test/browser_mdn-docs-01.js
+++ b/devtools/client/shared/test/browser_mdn-docs-01.js
@@ -15,22 +15,18 @@
  *
  * In this file we test:
  * - the initial state of the document before the docs have loaded
  * - the state of the document after the docs have loaded
  */
 
 "use strict";
 
-const {CssDocsTooltip} = require("devtools/client/shared/widgets/Tooltip");
 const {setBaseCssDocsUrl, MdnDocsWidget} = require("devtools/client/shared/widgets/MdnDocsWidget");
 
-// frame to load the tooltip into
-const MDN_DOCS_TOOLTIP_FRAME = "chrome://devtools/content/shared/widgets/mdn-docs-frame.xhtml";
-
 /**
  * Test properties
  *
  * In the real tooltip, a CSS property name is used to look up an MDN page
  * for that property.
  * In the test code, the names defined here is used to look up a page
  * served by the test server.
  */
@@ -40,24 +36,26 @@ const BASIC_EXPECTED_SUMMARY = "A summar
 const BASIC_EXPECTED_SYNTAX = [{type: "comment", text: "/* The part we want   */"},
                                {type: "text", text: "\n"},
                                {type: "property-name", text: "this"},
                                {type: "text", text: ":"},
                                {type: "text", text: " "},
                                {type: "property-value", text: "is-the-part-we-want"},
                                {type: "text", text: ";"}];
 
-const URI_PARAMS = "?utm_source=mozilla&utm_medium=firefox-inspector&utm_campaign=default";
+const URI_PARAMS =
+  "?utm_source=mozilla&utm_medium=firefox-inspector&utm_campaign=default";
 
 add_task(function* () {
   setBaseCssDocsUrl(TEST_URI_ROOT);
 
   yield addTab("about:blank");
-  let [host, win, doc] = yield createHost("bottom", MDN_DOCS_TOOLTIP_FRAME);
-  let widget = new MdnDocsWidget(win.document);
+  let [host, win] = yield createHost("bottom", "data:text/html," +
+    "<div class='mdn-container'></div>");
+  let widget = new MdnDocsWidget(win.document.querySelector("div"));
 
   yield testTheBasics(widget);
 
   host.destroy();
   gBrowser.removeCurrentTab();
 });
 
 /**
--- a/devtools/client/shared/test/browser_mdn-docs-02.js
+++ b/devtools/client/shared/test/browser_mdn-docs-02.js
@@ -16,21 +16,20 @@
  * error conditions like parts of the document being missing.
  *
  * We also test that the tooltip properly handles the case where the page
  * doesn't exist at all.
  */
 
 "use strict";
 
-const {CssDocsTooltip} = require("devtools/client/shared/widgets/Tooltip");
-const {setBaseCssDocsUrl, MdnDocsWidget} = require("devtools/client/shared/widgets/MdnDocsWidget");
-
-// frame to load the tooltip into
-const MDN_DOCS_TOOLTIP_FRAME = "chrome://devtools/content/shared/widgets/mdn-docs-frame.xhtml";
+const {
+  setBaseCssDocsUrl,
+  MdnDocsWidget
+} = require("devtools/client/shared/widgets/MdnDocsWidget");
 
 const BASIC_EXPECTED_SUMMARY = "A summary of the property.";
 const BASIC_EXPECTED_SYNTAX = [{type: "comment", text: "/* The part we want   */"},
                                {type: "text", text: "\n"},
                                {type: "property-name", text: "this"},
                                {type: "text", text: ":"},
                                {type: "text", text: " "},
                                {type: "property-value", text: "is-the-part-we-want"},
@@ -95,43 +94,33 @@ const TEST_DATA = [{
   }
 }
 ];
 
 add_task(function* () {
   setBaseCssDocsUrl(TEST_URI_ROOT);
 
   yield addTab("about:blank");
-  let [host, win, doc] = yield createHost("bottom", MDN_DOCS_TOOLTIP_FRAME);
-  let widget = new MdnDocsWidget(win.document);
+  let [host, win] = yield createHost("bottom", "data:text/html," +
+    "<div class='mdn-container'></div>");
+  let widget = new MdnDocsWidget(win.document.querySelector("div"));
 
   for (let {desc, docsPageUrl, expectedContents} of TEST_DATA) {
     info(desc);
     yield widget.loadCssDocs(docsPageUrl);
     checkTooltipContents(widget.elements, expectedContents);
   }
   host.destroy();
   gBrowser.removeCurrentTab();
 });
 
-function* testNonExistentPage(widget) {
-  info("Test a property for which we don't have a page");
-  yield widget.loadCssDocs("i-dont-exist.html");
-  checkTooltipContents(widget.elements, {
-    propertyName: "i-dont-exist.html",
-    summary: ERROR_MESSAGE,
-    syntax: ""
-  });
-}
-
 /*
  * Utility function to check content of the tooltip.
  */
 function checkTooltipContents(doc, expected) {
-
   is(doc.heading.textContent,
      expected.propertyName,
      "Property name is correct");
 
   is(doc.summary.textContent,
      expected.summary,
      "Summary is correct");
 
--- a/devtools/client/shared/widgets/MdnDocsWidget.js
+++ b/devtools/client/shared/widgets/MdnDocsWidget.js
@@ -24,16 +24,18 @@
 
 "use strict";
 
 const Services = require("Services");
 const defer = require("devtools/shared/defer");
 const {getCSSLexer} = require("devtools/shared/css-lexer");
 const {gDevTools} = require("devtools/client/framework/devtools");
 
+const XHTML_NS = "http://www.w3.org/1999/xhtml";
+
 // Parameters for the XHR request
 // see https://developer.mozilla.org/en-US/docs/MDN/Kuma/API#Document_parameters
 const XHR_PARAMS = "?raw&macros";
 // URL for the XHR request
 var XHR_CSS_URL = "https://developer.mozilla.org/en-US/docs/Web/CSS/";
 
 // Parameters for the link to MDN in the tooltip, so
 // so we know which MDN visits come from this feature
@@ -82,17 +84,17 @@ function appendSyntaxHighlightedCSS(cssT
   let doc = parentElement.ownerDocument;
   let identClass = PROPERTY_NAME_COLOR;
   let lexer = getCSSLexer(cssText);
 
   /**
    * Create a SPAN node with the given text content and class.
    */
   function createStyledNode(textContent, className) {
-    let newNode = doc.createElement("span");
+    let newNode = doc.createElementNS(XHTML_NS, "span");
     newNode.classList.add(className);
     newNode.textContent = textContent;
     return newNode;
   }
 
   /**
    * If the symbol is ":", we will expect the next
    * "ident" token to be part of a property value.
@@ -219,42 +221,49 @@ function getCssDocs(cssProperty) {
 
   return deferred.promise;
 }
 
 exports.getCssDocs = getCssDocs;
 
 /**
  * The MdnDocsWidget is used by tooltip code that needs to display docs
- * from MDN in a tooltip. The tooltip code loads a document that contains the
- * basic structure of a docs tooltip (loaded from mdn-docs-frame.xhtml),
- * and passes this document into the widget's constructor.
+ * from MDN in a tooltip.
  *
  * In the constructor, the widget does some general setup that's not
  * dependent on the particular item we need docs for.
  *
  * After that, when the tooltip code needs to display docs for an item, it
  * asks the widget to retrieve the docs and update the document with them.
  *
- * @param {Document} tooltipDocument
- * A DOM document. The widget expects the document to have a particular
- * structure.
+ * @param {Element} tooltipContainer
+ * A DOM element where the MdnDocs widget markup should be created.
  */
-function MdnDocsWidget(tooltipDocument) {
+function MdnDocsWidget(tooltipContainer) {
+  tooltipContainer.innerHTML =
+    `<header>
+       <h1 class="mdn-property-name theme-fg-color5"></h1>
+     </header>
+     <div class="mdn-property-info">
+       <div class="mdn-summary"></div>
+       <pre class="mdn-syntax devtools-monospace"></pre>
+     </div>
+     <footer>
+       <a class="mdn-visit-page theme-link" href="#">Visit MDN (placeholder)</a>
+     </footer>`;
+
   // fetch all the bits of the document that we will manipulate later
   this.elements = {
-    heading: tooltipDocument.getElementById("property-name"),
-    summary: tooltipDocument.getElementById("summary"),
-    syntax: tooltipDocument.getElementById("syntax"),
-    info: tooltipDocument.getElementById("property-info"),
-    linkToMdn: tooltipDocument.getElementById("visit-mdn-page")
+    heading: tooltipContainer.querySelector(".mdn-property-name"),
+    summary: tooltipContainer.querySelector(".mdn-summary"),
+    syntax: tooltipContainer.querySelector(".mdn-syntax"),
+    info: tooltipContainer.querySelector(".mdn-property-info"),
+    linkToMdn: tooltipContainer.querySelector(".mdn-visit-page")
   };
 
-  this.doc = tooltipDocument;
-
   // get the localized string for the link text
   this.elements.linkToMdn.textContent =
     l10n.strings.GetStringFromName("docsTooltip.visitMDN");
 
   // listen for clicks and open in the browser window instead
   let mainWindow = Services.wm.getMostRecentWindow(gDevTools.chromeWindowType);
   this.elements.linkToMdn.addEventListener("click", function (e) {
     e.stopPropagation();
@@ -352,17 +361,16 @@ MdnDocsWidget.prototype = {
     initializeDocument(propertyName);
     getCssDocs(propertyName).then(finalizeDocument, gotError);
 
     return deferred.promise;
   },
 
   destroy: function () {
     this.elements = null;
-    this.doc = null;
   }
 };
 
 /**
  * L10N utility class
  */
 function L10N() {}
 L10N.prototype = {};
--- a/devtools/client/shared/widgets/Tooltip.js
+++ b/devtools/client/shared/widgets/Tooltip.js
@@ -4,17 +4,16 @@
 
 "use strict";
 
 const {Ci} = require("chrome");
 const defer = require("devtools/shared/defer");
 const {Spectrum} = require("devtools/client/shared/widgets/Spectrum");
 const {CubicBezierWidget} =
       require("devtools/client/shared/widgets/CubicBezierWidget");
-const {MdnDocsWidget} = require("devtools/client/shared/widgets/MdnDocsWidget");
 const {CSSFilterEditorWidget} = require("devtools/client/shared/widgets/FilterWidget");
 const {TooltipToggle} = require("devtools/client/shared/widgets/tooltip/TooltipToggle");
 const EventEmitter = require("devtools/shared/event-emitter");
 const {colorUtils} = require("devtools/client/shared/css-color");
 const Heritage = require("sdk/core/heritage");
 const {Eyedropper} = require("devtools/client/eyedropper/eyedropper");
 const {gDevTools} = require("devtools/client/framework/devtools");
 const Services = require("Services");
@@ -28,19 +27,17 @@ loader.lazyRequireGetter(this, "clearNam
 loader.lazyRequireGetter(this, "setNamedTimeout", "devtools/client/shared/widgets/view-helpers", true);
 
 XPCOMUtils.defineLazyModuleGetter(this, "VariablesView",
   "resource://devtools/client/shared/widgets/VariablesView.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "VariablesViewController",
   "resource://devtools/client/shared/widgets/VariablesViewController.jsm");
 
 const XHTML_NS = "http://www.w3.org/1999/xhtml";
-const MDN_DOCS_FRAME = "chrome://devtools/content/shared/widgets/mdn-docs-frame.xhtml";
 const ESCAPE_KEYCODE = Ci.nsIDOMKeyEvent.DOM_VK_ESCAPE;
-const RETURN_KEYCODE = Ci.nsIDOMKeyEvent.DOM_VK_RETURN;
 const POPUP_EVENTS = ["shown", "hidden", "showing", "hiding"];
 
 /**
  * Tooltip widget.
  *
  * This widget is intended at any tool that may need to show rich content in the
  * form of floating panels.
  * A common use case is image previewing in the CSS rule view, but more complex
@@ -548,42 +545,16 @@ Tooltip.prototype = {
 
     // load the document from url into the iframe
     iframe.setAttribute("src", url);
 
     // Put the iframe in the tooltip
     this.content = iframe;
 
     return def.promise;
-  },
-
-  /**
-   * Set the content of this tooltip to the MDN docs widget.
-   *
-   * This is called when the tooltip is first constructed.
-   *
-   * @return {promise} A promise which is resolved with an MdnDocsWidget.
-   *
-   * It loads the tooltip's structure from a separate XHTML file
-   * into an iframe. When the iframe is loaded it constructs
-   * an MdnDocsWidget and passes that into resolve.
-   *
-   * The caller can use the MdnDocsWidget to update the tooltip's
-   * UI with new content each time the tooltip is shown.
-   */
-  setMdnDocsContent: function () {
-    let dimensions = {width: "410", height: "300"};
-    return this.setIFrameContent(dimensions, MDN_DOCS_FRAME).then(onLoaded);
-
-    function onLoaded(iframe) {
-      let win = iframe.contentWindow.wrappedJSObject;
-      // create an MdnDocsWidget, initializing it with the content document
-      let widget = new MdnDocsWidget(win.document);
-      return widget;
-    }
   }
 };
 
 /**
  * Base class for all (color, gradient, ...)-swatch based value editors inside
  * tooltips
  *
  * @param {Toolbox} toolbox
@@ -1000,55 +971,16 @@ Heritage.extend(SwatchBasedEditorTooltip
     this.widget.then(widget => {
       widget.off("updated", this._onUpdate);
       widget.destroy();
     });
   }
 });
 
 /**
- * Tooltip for displaying docs for CSS properties from MDN.
- *
- * @param {XULDocument} doc
- */
-function CssDocsTooltip(doc) {
-  this.tooltip = new Tooltip(doc, {
-    consumeOutsideClick: true,
-    closeOnKeys: [ESCAPE_KEYCODE, RETURN_KEYCODE],
-    noAutoFocus: false
-  });
-  this.widget = this.tooltip.setMdnDocsContent();
-}
-
-module.exports.CssDocsTooltip = CssDocsTooltip;
-
-CssDocsTooltip.prototype = {
-  /**
-   * Load CSS docs for the given property,
-   * then display the tooltip.
-   */
-  show: function (anchor, propertyName) {
-    function loadCssDocs(widget) {
-      return widget.loadCssDocs(propertyName);
-    }
-
-    this.widget.then(loadCssDocs);
-    this.tooltip.show(anchor, "topcenter bottomleft");
-  },
-
-  hide: function () {
-    this.tooltip.hide();
-  },
-
-  destroy: function () {
-    this.tooltip.destroy();
-  }
-};
-
-/**
  * The swatch-based css filter tooltip class is a specific class meant to be
  * used along with rule-view's generated css filter swatches.
  * It extends the parent SwatchBasedEditorTooltip class.
  * It just wraps a standard Tooltip and sets its content with an instance of a
  * CSSFilterEditorWidget.
  *
  * @param {Toolbox} toolbox
  *        The devtools toolbox, needed to get the devtools main window.
deleted file mode 100644
--- a/devtools/client/shared/widgets/mdn-docs-frame.xhtml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?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/. -->
-<!DOCTYPE html>
-
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
-  <link rel="stylesheet" href="chrome://devtools/content/shared/widgets/mdn-docs.css" type="text/css"/>
-  <script type="application/javascript;version=1.8" src="chrome://devtools/content/shared/theme-switching.js"/>
-</head>
-<body class="theme-body">
-
-  <div id = "container">
-
-    <header>
-      <h1 id="property-name" class="theme-fg-color5"></h1>
-    </header>
-
-    <div id="property-info">
-      <div id="summary"></div>
-      <pre id="syntax" class="devtools-monospace"></pre>
-    </div>
-
-    <footer>
-      <a id="visit-mdn-page" class="theme-link" href="#">Visit MDN (placeholder)</a>
-    </footer>
-
-  </div>
-
-</body>
-</html>
\ No newline at end of file
--- a/devtools/client/shared/widgets/mdn-docs.css
+++ b/devtools/client/shared/widgets/mdn-docs.css
@@ -1,41 +1,39 @@
 /* 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/. */
 
-#visit-mdn-page {
-  display: inline-block;
-  padding: 1em 0;
-}
-
-html, body, #container {
-  height: 100%;
-  width: 100%;
-  margin: 0;
-  padding: 0;
-}
-
-#container {
+.mdn-container {
+  height: 300px;
+  margin: 4px;
+  overflow: auto;
+  box-sizing: border-box;
   display: flex;
   flex-direction: column;
 }
 
-header, footer {
+.mdn-container header,
+.mdn-container footer {
   flex: 1;
   padding: 0 1em;
 }
 
-#property-info {
+.mdn-property-info {
   flex: 10;
   padding: 0 1em;
   overflow: auto;
   transition: opacity 400ms ease-in;
 }
 
-#syntax {
+.mdn-syntax {
   margin-top: 1em;
 }
 
 .devtools-throbber {
+  align-self: center;
   opacity: 0;
-  align-self: center;
 }
+
+.mdn-visit-page {
+  display: inline-block;
+  padding: 1em 0;
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/shared/widgets/tooltip/CssDocsTooltip.js
@@ -0,0 +1,95 @@
+/* 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 {HTMLTooltip} = require("devtools/client/shared/widgets/HTMLTooltip");
+const {MdnDocsWidget} = require("devtools/client/shared/widgets/MdnDocsWidget");
+const XHTML_NS = "http://www.w3.org/1999/xhtml";
+
+loader.lazyRequireGetter(this, "KeyShortcuts",
+  "devtools/client/shared/key-shortcuts", true);
+
+const TOOLTIP_WIDTH = 418;
+const TOOLTIP_HEIGHT = 308;
+
+/**
+ * Tooltip for displaying docs for CSS properties from MDN.
+ *
+ * @param {Toolbox} toolbox
+ *        Toolbox used to create the tooltip.
+ */
+function CssDocsTooltip(toolbox) {
+  this.tooltip = new HTMLTooltip(toolbox, {
+    type: "arrow",
+    consumeOutsideClicks: true,
+    autofocus: true,
+    useXulWrapper: true,
+    stylesheet: "chrome://devtools/content/shared/widgets/mdn-docs.css",
+  });
+  this.widget = this.setMdnDocsContent();
+
+  // Initialize keyboard shortcuts
+  this.shortcuts = new KeyShortcuts({ window: toolbox.doc.defaultView });
+  this._onShortcut = this._onShortcut.bind(this);
+
+  this.shortcuts.on("Escape", this._onShortcut);
+  this.shortcuts.on("Return", this._onShortcut);
+}
+
+module.exports.CssDocsTooltip = CssDocsTooltip;
+
+CssDocsTooltip.prototype = {
+  /**
+   * Load CSS docs for the given property,
+   * then display the tooltip.
+   */
+  show: function (anchor, propertyName) {
+    this.tooltip.once("shown", () => {
+      this.widget.loadCssDocs(propertyName);
+    });
+    this.tooltip.show(anchor);
+  },
+
+  hide: function () {
+    this.tooltip.hide();
+  },
+
+  _onShortcut: function (shortcut, event) {
+    if (!this.tooltip.isVisible()) {
+      return;
+    }
+
+    event.stopPropagation();
+    if (shortcut === "Return") {
+      // If user is pressing return, do not prevent default and delay hiding the tooltip
+      // in case the focus is on the "Visit MDN page" link.
+      this.tooltip.doc.defaultView.setTimeout(this.hide.bind(this), 0);
+    } else {
+      // For any other key, preventDefault() and hide straight away.
+      event.preventDefault();
+      this.hide();
+    }
+  },
+
+  /**
+   * Set the content of this tooltip to the MDN docs widget. This is called when the
+   * tooltip is first constructed.
+   * The caller can use the MdnDocsWidget to update the tooltip's  UI with new content
+   * each time the tooltip is shown.
+   *
+   * @return {MdnDocsWidget} the created MdnDocsWidget instance.
+   */
+  setMdnDocsContent: function () {
+    let container = this.tooltip.doc.createElementNS(XHTML_NS, "div");
+    container.setAttribute("class", "mdn-container theme-body");
+    this.tooltip.setContent(container, {width: TOOLTIP_WIDTH, height: TOOLTIP_HEIGHT});
+    return new MdnDocsWidget(container);
+  },
+
+  destroy: function () {
+    this.shortcuts.destroy();
+    this.tooltip.destroy();
+  }
+};
--- a/devtools/client/shared/widgets/tooltip/EventTooltipHelper.js
+++ b/devtools/client/shared/widgets/tooltip/EventTooltipHelper.js
@@ -37,17 +37,20 @@ function setEventTooltip(tooltip, eventL
   let eventTooltip = new EventTooltip(tooltip, eventListenerInfos, toolbox);
   eventTooltip.init();
 }
 
 function EventTooltip(tooltip, eventListenerInfos, toolbox) {
   this._tooltip = tooltip;
   this._eventListenerInfos = eventListenerInfos;
   this._toolbox = toolbox;
-  this._tooltip.eventEditors = new WeakMap();
+  this._eventEditors = new WeakMap();
+
+  // Used in tests: add a reference to the EventTooltip instance on the HTMLTooltip.
+  this._tooltip.eventTooltip = this;
 
   this._headerClicked = this._headerClicked.bind(this);
   this._debugClicked = this._debugClicked.bind(this);
   this.destroy = this.destroy.bind(this);
 }
 
 EventTooltip.prototype = {
   init: function () {
@@ -140,17 +143,17 @@ EventTooltip.prototype = {
         dom0.textContent = level;
         dom0.setAttribute("title", level);
         attributesBox.appendChild(dom0);
       }
 
       // Content
       let content = doc.createElementNS(XHTML_NS, "div");
       let editor = new Editor(config);
-      this._tooltip.eventEditors.set(content, {
+      this._eventEditors.set(content, {
         editor: editor,
         handler: listener.handler,
         searchString: listener.searchString,
         uri: listener.origin,
         dom0: listener.DOM0,
         appended: false
       });
 
@@ -187,32 +190,32 @@ EventTooltip.prototype = {
       for (let node of contentNodes) {
         if (node !== content) {
           node.removeAttribute("open");
         }
       }
 
       content.setAttribute("open", "");
 
-      let eventEditors = this._tooltip.eventEditors.get(content);
+      let eventEditor = this._eventEditors.get(content);
 
-      if (eventEditors.appended) {
+      if (eventEditor.appended) {
         return;
       }
 
-      let {editor, handler} = eventEditors;
+      let {editor, handler} = eventEditor;
 
       let iframe = doc.createElementNS(XHTML_NS, "iframe");
       iframe.setAttribute("style", "width: 100%; height: 100%; border-style: none;");
 
       editor.appendTo(content, iframe).then(() => {
         let tidied = beautify.js(handler, { "indent_size": 2 });
         editor.setText(tidied);
 
-        eventEditors.appended = true;
+        eventEditor.appended = true;
 
         let container = header.parentElement.getBoundingClientRect();
         if (header.getBoundingClientRect().top < container.top) {
           header.scrollIntoView(true);
         } else if (content.getBoundingClientRect().bottom > container.bottom) {
           content.scrollIntoView(false);
         }
 
@@ -220,17 +223,17 @@ EventTooltip.prototype = {
       });
     }
   },
 
   _debugClicked: function (event) {
     let header = event.currentTarget;
     let content = header.nextElementSibling;
 
-    let {uri, searchString, dom0} = this._tooltip.eventEditors.get(content);
+    let {uri, searchString, dom0} = this._eventEditors.get(content);
 
     if (uri && uri !== "?") {
       // Save a copy of toolbox as it will be set to null when we hide the tooltip.
       let toolbox = this._toolbox;
 
       this._tooltip.hide();
 
       uri = uri.replace(/"/g, "");
@@ -285,21 +288,22 @@ EventTooltip.prototype = {
 
   destroy: function () {
     if (this._tooltip) {
       this._tooltip.off("hidden", this.destroy);
 
       let boxes = this.container.querySelectorAll(".event-tooltip-content-box");
 
       for (let box of boxes) {
-        let {editor} = this._tooltip.eventEditors.get(box);
+        let {editor} = this._eventEditors.get(box);
         editor.destroy();
       }
 
-      this._tooltip.eventEditors = null;
+      this._eventEditors = null;
+      this._tooltip.eventTooltip = null;
     }
 
     let headerNodes = this.container.querySelectorAll(".event-header");
 
     for (let node of headerNodes) {
       node.removeEventListener("click", this._headerClicked);
     }
 
--- a/devtools/client/shared/widgets/tooltip/moz.build
+++ b/devtools/client/shared/widgets/tooltip/moz.build
@@ -1,11 +1,12 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 DevToolsModules(
+    'CssDocsTooltip.js',
     'EventTooltipHelper.js',
     'ImageTooltipHelper.js',
     'TooltipToggle.js',
 )
--- a/devtools/client/styleeditor/styleeditor.xul
+++ b/devtools/client/styleeditor/styleeditor.xul
@@ -92,22 +92,20 @@
 
     <xul:box class="splitview-root devtools-responsive-container" context="sidebar-context">
       <xul:box class="splitview-controller">
         <xul:box class="splitview-main">
           <xul:toolbar class="devtools-toolbar">
              <xul:hbox class="devtools-toolbarbutton-group">
               <xul:toolbarbutton class="style-editor-newButton devtools-toolbarbutton"
                           accesskey="&newButton.accesskey;"
-                          tooltiptext="&newButton.tooltip;"
-                          label="&newButton.label;"/>
+                          tooltiptext="&newButton.tooltip;"/>
               <xul:toolbarbutton class="style-editor-importButton devtools-toolbarbutton"
                           accesskey="&importButton.accesskey;"
-                          tooltiptext="&importButton.tooltip;"
-                          label="&importButton.label;"/>
+                          tooltiptext="&importButton.tooltip;"/>
             </xul:hbox>
             <xul:spacer/>
             <xul:toolbarbutton id="style-editor-options"
                         class="devtools-toolbarbutton devtools-option-toolbarbutton"
                         tooltiptext="&optionsButton.tooltip;"
                         popup="style-editor-options-popup"/>
           </xul:toolbar>
         </xul:box>
--- a/devtools/client/themes/animationinspector.css
+++ b/devtools/client/themes/animationinspector.css
@@ -2,44 +2,35 @@
  * 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/. */
 
 /* Animation-inspector specific theme variables */
 
 .theme-dark {
   --even-animation-timeline-background-color: rgba(255,255,255,0.03);
   --command-pick-image: url(chrome://devtools/skin/images/command-pick.svg);
-  --pause-image: url(chrome://devtools/skin/images/debugger-pause.png);
-  --pause-image-2x: url(chrome://devtools/skin/images/debugger-pause@2x.png);
-  --rewind-image: url(chrome://devtools/skin/images/rewind.png);
-  --rewind-image-2x: url(chrome://devtools/skin/images/rewind@2x.png);
-  --play-image: url(chrome://devtools/skin/images/debugger-play.png);
-  --play-image-2x: url(chrome://devtools/skin/images/debugger-play@2x.png);
+  --pause-image: url(chrome://devtools/skin/images/pause.svg);
+  --rewind-image: url(chrome://devtools/skin/images/rewind.svg);
+  --play-image: url(chrome://devtools/skin/images/play.svg);
 }
 
 .theme-light {
   --even-animation-timeline-background-color: rgba(128,128,128,0.03);
   --command-pick-image: url(chrome://devtools/skin/images/command-pick.svg);
-  --pause-image: url(chrome://devtools/skin/images/debugger-pause.png);
-  --pause-image-2x: url(chrome://devtools/skin/images/debugger-pause@2x.png);
-  --rewind-image: url(chrome://devtools/skin/images/rewind.png);
-  --rewind-image-2x: url(chrome://devtools/skin/images/rewind@2x.png);
-  --play-image: url(chrome://devtools/skin/images/debugger-play.png);
-  --play-image-2x: url(chrome://devtools/skin/images/debugger-play@2x.png);
+  --pause-image: url(chrome://devtools/skin/images/pause.svg);
+  --rewind-image: url(chrome://devtools/skin/images/rewind.svg);
+  --play-image: url(chrome://devtools/skin/images/play.svg);
 }
 
 .theme-firebug {
   --even-animation-timeline-background-color: rgba(128,128,128,0.03);
   --command-pick-image: url(chrome://devtools/skin/images/firebug/command-pick.svg);
   --pause-image: url(chrome://devtools/skin/images/firebug/pause.svg);
-  --pause-image-2x: url(chrome://devtools/skin/images/firebug/pause.svg);
   --rewind-image: url(chrome://devtools/skin/images/firebug/rewind.svg);
-  --rewind-image-2x: url(chrome://devtools/skin/images/firebug/rewind.svg);
   --play-image: url(chrome://devtools/skin/images/firebug/play.svg);
-  --play-image-2x: url(chrome://devtools/skin/images/firebug/play.svg);
 }
 
 :root {
   /* How high should toolbars be */
   --toolbar-height: 20px;
   /* How wide should the sidebar be (should be wide enough to contain long
      property names like 'border-bottom-right-radius' without ellipsis) */
   --timeline-sidebar-width: 200px;
@@ -179,30 +170,16 @@ body {
 #rewind-timeline::before {
   background-image: var(--rewind-image);
 }
 
 .pause-button.paused::before {
   background-image: var(--play-image);
 }
 
-@media (min-resolution: 1.1dppx) {
-  .pause-button::before {
-    background-image: var(--pause-image-2x);
-  }
-
-  .pause-button.paused::before {
-    background-image: var(--play-image-2x);
-  }
-
-  #rewind-timeline::before {
-    background-image: var(--rewind-image-2x);
-  }
-}
-
 #timeline-rate select.devtools-button {
   -moz-appearance: none;
   text-align: center;
   font-family: inherit;
   color: var(--theme-body-color);
   font-size: 1em;
   position: absolute;
   top: 0;
--- a/devtools/client/themes/canvasdebugger.css
+++ b/devtools/client/themes/canvasdebugger.css
@@ -46,16 +46,20 @@
 #snapshots-pane {
   border-inline-end: 1px solid var(--theme-splitter-color);
 }
 
 #record-snapshot {
   list-style-image: url("chrome://devtools/skin/images/profiler-stopwatch.svg");
 }
 
+#import-snapshot {
+  list-style-image: url("images/import.svg");
+}
+
 /* Snapshots items */
 
 .snapshot-item-thumbnail {
   image-rendering: -moz-crisp-edges;
   background-image: var(--checkerboard-pattern);
   background-size: 12px 12px, 12px 12px;
   background-position: 0px 0px, 6px 6px;
   background-repeat: repeat, repeat;
@@ -104,47 +108,29 @@
 
 #snapshots-list .selected label {
   /* Text inside a selected item should not be custom colored. */
   color: inherit !important;
 }
 
 /* Debugging pane controls */
 #resume {
-  list-style-image: url(images/debugger-play.png);
+  list-style-image: url(images/play.svg);
 }
 
 #step-over {
-  list-style-image: url(images/debugger-step-over.png);
+  list-style-image: url(images/debugger-step-over.svg);
 }
 
 #step-in {
-  list-style-image: url(images/debugger-step-in.png);
+  list-style-image: url(images/debugger-step-in.svg);
 }
 
 #step-out {
-  list-style-image: url(images/debugger-step-out.png);
-}
-
-@media (min-resolution: 1.1dppx) {
-  #resume {
-    list-style-image: url(images/debugger-play@2x.png);
-  }
-
-  #step-over {
-    list-style-image: url(images/debugger-step-over@2x.png);
-  }
-
-  #step-in {
-    list-style-image: url(images/debugger-step-in@2x.png);
-  }
-
-  #step-out {
-    list-style-image: url(images/debugger-step-out@2x.png);
-  }
+  list-style-image: url(images/debugger-step-out.svg);
 }
 
 #calls-slider {
   padding-inline-end: 24px;
 }
 
 #calls-slider .scale-slider {
   margin: 0;
@@ -191,26 +177,18 @@
   padding-bottom: 2px;
   border-inline-end: 1px solid var(--theme-splitter-color);
   margin-inline-end: 6px;
   background-color: var(--theme-sidebar-background);
   color: var(--theme-content-color3);
 }
 
 .selected .call-item-gutter {
-  background-image: url("images/editor-debug-location.png");
-  background-repeat: no-repeat;
-  background-position: 6px center;
-  background-size: 12px;
-}
-
-@media (min-resolution: 1.1dppx) {
-  .selected .call-item-gutter {
-    background-image: url("images/editor-debug-location@2x.png");
-  }
+  background-color: #2cbb0f;
+  color: white;
 }
 
 .call-item-index {
   text-align: end;
 }
 
 .call-item-context {
   color: var(--theme-highlight-orange);
--- a/devtools/client/themes/debugger.css
+++ b/devtools/client/themes/debugger.css
@@ -89,66 +89,44 @@
 
 /* Sources toolbar */
 
 #sources-toolbar > .devtools-toolbarbutton,
 #sources-controls > .devtools-toolbarbutton {
   min-width: 32px;
 }
 
-:root:not(.theme-firebug) #sources-toolbar .devtools-toolbarbutton:not([label]) {
-  -moz-image-region: rect(0,16px,16px,0);
-}
-
-@media (min-resolution: 1.1dppx) {
-  :root:not(.theme-firebug) #sources-toolbar .devtools-toolbarbutton:not([label]) {
-    -moz-image-region: rect(0,32px,32px,0);
-  }
-}
-
 #black-box {
-  list-style-image: url(images/debugger-blackbox.png);
-}
-
-@media (min-resolution: 1.1dppx) {
-  #black-box {
-    list-style-image: url(images/debugger-blackbox@2x.png);
-  }
+  list-style-image: url(images/debugger-blackbox.svg);
 }
 
 .theme-firebug #black-box {
   list-style-image: url(images/firebug/debugger-blackbox.svg);
 }
 
 #pretty-print {
-  list-style-image: url(images/debugger-prettyprint.png);
-}
-
-@media (min-resolution: 1.1dppx) {
-  #pretty-print {
-    list-style-image: url(images/debugger-prettyprint@2x.png);
-  }
+  list-style-image: url(images/debugger-prettyprint.svg);
 }
 
 .theme-firebug #pretty-print {
   list-style-image: url(images/firebug/debugger-prettyprint.svg);
 }
 
 #toggle-breakpoints {
   list-style-image: url(images/debugger-toggleBreakpoints.svg);
-  -moz-image-region: rect(0,32px,16px,16px) !important;
+  -moz-image-region: rect(0,32px,16px,16px);
 }
 
 .theme-firebug #toggle-breakpoints {
   list-style-image: url(images/firebug/debugger-toggleBreakpoints.svg);
-  -moz-image-region: unset !important;
+  -moz-image-region: unset;
 }
 
 #toggle-breakpoints[checked] {
-  -moz-image-region: rect(0,16px,16px,0) !important;
+  -moz-image-region: rect(0,16px,16px,0);
 }
 
 #toggle-breakpoints[checked] > image {
   /* This button has a special checked image, don't make it blue */
   filter: none;
 }
 
 #toggle-promise-debugger {
@@ -167,27 +145,19 @@
   display: none;
 }
 
 /* Debugger unblackbox button */
 
 #black-boxed-message-button > .button-box > .button-icon {
   width: 16px;
   height: 16px;
-  background-image: url(images/debugger-blackbox.png);
+  background-image: url(images/debugger-blackbox.svg);
   background-position: 0 0;
-  background-size: 32px 16px;
-  background-repeat: no-repeat;
-  margin-inline-end: 5px;
-}
-
-@media (min-resolution: 1.1dppx) {
-  #black-boxed-message-button > .button-box > .button-icon {
-    background-image: url(images/debugger-blackbox@2x.png);
-  }
+  background-size: cover;
 }
 
 /* Black box message and source progress meter */
 
 #black-boxed-message,
 #source-progress-container {
   /* Prevent the container deck from aquiring the size from this message. */
   min-width: 1px;
@@ -567,69 +537,45 @@
 
 .theme-light .dbg-results-line-contents-string[match=true] {
   color: var(--theme-body-color);
 }
 
 /* Toolbar controls */
 
 #resume {
-  list-style-image: url(images/debugger-pause.png);
+  list-style-image: url(images/pause.svg);
 }
 
 #resume[checked] {
-  list-style-image: url(images/debugger-play.png);
-}
-
-@media (min-resolution: 1.1dppx) {
-  #resume {
-    list-style-image: url(images/debugger-pause@2x.png);
-  }
-
-  #resume[checked] {
-    list-style-image: url(images/debugger-play@2x.png);
-  }
+  list-style-image: url(images/play.svg);
 }
 
 .theme-firebug #resume {
   list-style-image: url(images/firebug/pause.svg);
 }
 
 .theme-firebug #resume[checked] {
   list-style-image: url(images/firebug/play.svg);
 }
 
 #resume[break-on-next] {
   background: var(--theme-highlight-lightorange);
 }
 
 #step-over {
-  list-style-image: url(images/debugger-step-over.png);
+  list-style-image: url(images/debugger-step-over.svg);
 }
 
 #step-in {
-  list-style-image: url(images/debugger-step-in.png);
+  list-style-image: url(images/debugger-step-in.svg);
 }
 
 #step-out {
-  list-style-image: url(images/debugger-step-out.png);
-}
-
-@media (min-resolution: 1.1dppx) {
-  #step-over {
-    list-style-image: url(images/debugger-step-over@2x.png);
-  }
-
-  #step-in {
-    list-style-image: url(images/debugger-step-in@2x.png);
-  }
-
-  #step-out {
-    list-style-image: url(images/debugger-step-out@2x.png);
-  }
+  list-style-image: url(images/debugger-step-out.svg);
 }
 
 .theme-firebug #step-over {
   list-style-image: url(images/firebug/debugger-step-over.svg);
 }
 
 .theme-firebug #step-in {
   list-style-image: url(images/firebug/debugger-step-in.svg);
--- a/devtools/client/themes/firebug-theme.css
+++ b/devtools/client/themes/firebug-theme.css
@@ -239,15 +239,12 @@
   border-width: 1px !important;
   min-width: 24px;
 }
 
 .theme-firebug .devtools-toolbarbutton {
   min-width: 24px;
 }
 
-.theme-firebug #command-button-frames {
-  min-width: 32px;
-}
 
 .theme-firebug #element-picker {
   min-height: 21px;
 }
--- a/devtools/client/themes/images/add.svg
+++ b/devtools/client/themes/images/add.svg
@@ -1,9 +1,6 @@
 <!-- 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 width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-  <g fill="#babec3">
-    <rect x="3" y="7" width="10" height="2" />
-    <rect x="7" y="3" width="2" height="10" />
-  </g>
-</svg>
\ No newline at end of file
+<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <path d="M8.5 8.5V14a.5.5 0 1 1-1 0V8.5H2a.5.5 0 0 1 0-1h5.5V2a.5.5 0 0 1 1 0v5.5H14a.5.5 0 1 1 0 1H8.5z"/>
+</svg>
--- a/devtools/client/themes/images/clear.svg
+++ b/devtools/client/themes/images/clear.svg
@@ -1,7 +1,7 @@
 <!-- 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 width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="#babec3">
-  <path d="M6 3h3V2c0-.003-3 0-3 0-.002 0 0 1 0 1zm-5 .5c0-.276.226-.5.494-.5h12.012c.273 0 .494.232.494.5 0 .276-.226.5-.494.5H1.494C1.22 4 1 3.768 1 3.5zM5 3V2c0-.553.444-1 1-1h3c.552 0 1 .443 1 1v1H5z"/>
-  <path d="M5 13h1V7H5v6zm4 0h1V7H9v6zm3-8v8.998c-.046.553-.45 1.002-1 1.002H4c-.55 0-.954-.456-1-1.002V5h9zm-5 8h1V7H7v6z"/>
+<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <path d="M5 3h3V2c0-.003-3 0-3 0-.002 0 0 1 0 1zm-5 .5A.5.5 0 0 1 .494 3h12.012a.5.5 0 0 1 0 1H.494A.502.502 0 0 1 0 3.5zM4 3V2c0-.553.444-1 1-1h3c.552 0 1 .443 1 1v1H4zM5 11V6a.5.5 0 0 0-1 0v5a.5.5 0 1 0 1 0zM7 11V6a.5.5 0 0 0-1 0v5a.5.5 0 1 0 1 0zM9 11V6a.5.5 0 0 0-1 0v5a.5.5 0 1 0 1 0z"/>
+  <path d="M3 4v9h7V4H3zm0-1h7a1 1 0 0 1 1 1v9a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1z"/>
 </svg>
--- a/devtools/client/themes/images/command-noautohide.svg
+++ b/devtools/client/themes/images/command-noautohide.svg
@@ -1,8 +1,6 @@
 <!-- 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 width="16" height="16" viewBox="0 0 30 29" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
-  <g fill-rule="evenodd">
-    <path d="M3 1v11c0-1.104-.896-2-2-2h11c-1.104 0-2 .896-2 2V1c0 1.104.896 2 2 2H1c1.104 0 2-.896 2-2zM0 1c0-.553.447-1 1-1h11c.553 0 1 .447 1 1v11c0 .553-.447 1-1 1H1c-.553 0-1-.447-1-1V1zM20 1v11c0-1.104-.896-2-2-2h11c-1.104 0-2 .896-2 2V1c0 1.104.896 2 2 2H18c1.104 0 2-.896 2-2zm-3 0c0-.553.447-1 1-1h11c.553 0 1 .447 1 1v11c0 .553-.447 1-1 1H18c-.553 0-1-.447-1-1V1zM20 17v11c0-1.104-.896-2-2-2h11c-1.104 0-2 .896-2 2V17c0 1.104.896 2 2 2H18c1.104 0 2-.896 2-2zm-3 0c0-.553.447-1 1-1h11c.553 0 1 .447 1 1v11c0 .553-.447 1-1 1H18c-.553 0-1-.447-1-1V17zM3 17v11c0-1.104-.896-2-2-2h11c-1.104 0-2 .896-2 2V17c0 1.104.896 2 2 2H1c1.104 0 2-.896 2-2zm-3 0c0-.553.447-1 1-1h11c.553 0 1 .447 1 1v11c0 .553-.447 1-1 1H1c-.553 0-1-.447-1-1V17z"/>
-  </g>
-</svg>
\ No newline at end of file
+<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <path d="M2 1.99v4.02C2 6 2 6 1.99 6h4.02C6 6 6 6 6 6.01V1.99C6 2 6 2 6.01 2H1.99C2 2 2 2 2 1.99zm-1 0c0-.546.451-.99.99-.99h4.02c.546 0 .99.451.99.99v4.02c0 .546-.451.99-.99.99H1.99A.996.996 0 0 1 1 6.01V1.99zM10 1.99v4.02C10 6 10 6 9.99 6h4.02C14 6 14 6 14 6.01V1.99c0 .01 0 .01.01.01H9.99C10 2 10 2 10 1.99zm-1 0c0-.546.451-.99.99-.99h4.02c.546 0 .99.451.99.99v4.02c0 .546-.451.99-.99.99H9.99A.996.996 0 0 1 9 6.01V1.99zM10 9.99v4.02c0-.01 0-.01-.01-.01h4.02c-.01 0-.01 0-.01.01V9.99c0 .01 0 .01.01.01H9.99c.01 0 .01 0 .01-.01zm-1 0c0-.546.451-.99.99-.99h4.02c.546 0 .99.451.99.99v4.02c0 .546-.451.99-.99.99H9.99a.996.996 0 0 1-.99-.99V9.99zM2 9.99v4.02C2 14 2 14 1.99 14h4.02C6 14 6 14 6 14.01V9.99c0 .01 0 .01.01.01H1.99C2 10 2 10 2 9.99zm-1 0c0-.546.451-.99.99-.99h4.02c.546 0 .99.451.99.99v4.02c0 .546-.451.99-.99.99H1.99a.996.996 0 0 1-.99-.99V9.99z"/>
+</svg>
--- a/devtools/client/themes/images/command-paintflashing.svg
+++ b/devtools/client/themes/images/command-paintflashing.svg
@@ -1,7 +1,7 @@
 <!-- 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" viewBox="0 0 16 16" fill="whitesmoke">
-  <path opacity="0.5" d="M4 11h10v3H4z"/>
-  <path d="M4.7 6.1h7.6c.4 0 .7-.1.7-.5s-.3-.5-.7-.5H8.9V2.3c0-.4-.1-.7-.5-.7s-.5.4-.5.7v2.8H4.7c-.4 0-.7.1-.7.5s.3.5.7.5zM13.3 6.8H3.9c-.4 0-.8.4-.8.9v6.2c0 .4.3.9.8.9h9.4c.4 0 .8-.4.8-.9V7.7s-.6-.9-.8-.9zm-.2 7h-9v-6h9v6z"/>
+<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <path d="M3 6.997v6.006c0-.006.003-.003.002-.003h9.996c-.001 0 .002-.003.002.003V6.997c0 .006-.003.003-.002.003H3.002C3.003 7 3 7.003 3 6.997zm-1 0C2 6.447 2.456 6 3.002 6h9.996C13.55 6 14 6.453 14 6.997v6.006c0 .55-.456.997-1.002.997H3.002A1.004 1.004 0 0 1 2 13.003V6.997zM8.5 4V1.5a.5.5 0 0 0-1 0V4H4a.5.5 0 0 0 0 1h8a.5.5 0 1 0 0-1H8.5z"/>
+  <path fill-opacity=".3" d="M13 10v3H3v-3z"/>
 </svg>
--- a/devtools/client/themes/images/command-pick.svg
+++ b/devtools/client/themes/images/command-pick.svg
@@ -1,8 +1,9 @@
 <!-- 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" viewBox="0 0 16 16" fill="whitesmoke">
-  <path opacity="0.5" d="M8.1 8l1.5 5.5 3.7-3z"/>
-  <path d="M12.7 2H.8c-.4 0-.8.5-.8.9v8.8c0 .5.4 1.3.8 1.3h6.5l.1-1H1V3h12v5.4l1 .8V2.9c0-.4-.8-.9-1.3-.9zM11.2 12.2l2.4 2.3.7-.6-2.4-2.4z"/>
-  <path d="M8.8 7.6c-.4-.1-.9-.1-1.2.2-.2.3-.1 1-.1 1l2.1 5.4 4.7-3.8-5.5-2.8zm-.5.7l4.4 2.2-2.8 2.2-1.6-4.4z"/>
+<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <path d="M15 7.667V3.002A1.01 1.01 0 0 0 13.993 2H2.007C1.45 2 1 2.449 1 3.002v9.996C1 13.544 1.45 14 2.007 14h6.818l-.37-1H2V3h12v4.334l1 .333z"/>
+  <path fill-opacity=".3" d="M9 8l1.981 5.843 4.044-3.966z"/>
+  <path d="M8.526 8.16l1.982 5.844a.5.5 0 0 0 .824.196l4.043-3.966a.5.5 0 0 0-.202-.835L9.15 7.523a.5.5 0 0 0-.623.638zm.948-.32l-.623.637 6.025 1.877-.201-.834-4.044 3.966.824.197-1.981-5.844z"/>
+  <path d="M12.674 12.39l1.973 1.964a.5.5 0 1 0 .706-.708L13.38 11.68a.5.5 0 0 0-.706.709z"/>
 </svg>
--- a/devtools/client/themes/images/command-scratchpad.svg
+++ b/devtools/client/themes/images/command-scratchpad.svg
@@ -1,7 +1,7 @@
 <!-- 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" viewBox="0 0 16 16" fill="whitesmoke">
-  <path d="M13.2 3h-1.3v-.8c0-.3-.3-.6-.6-.6s-.6.3-.6.6V3H7.8v-.8c0-.3-.3-.6-.6-.6s-.7.2-.7.6V3H3.7v-.8c0-.3-.3-.6-.6-.6s-.6.2-.6.6V3H.8c-.4 0-.8.4-.8.9v10.2c0 .4.3.9.8.9h12.4c.4 0 .8-.4.8-.9V3.9s-.6-.9-.8-.9zM13 14H1V3.9h12V14z"/>
-  <path d="M8.7 12.1h-6c-.3 0-.5-.2-.5-.5s.2-.5.5-.5h6c.3 0 .5.2.5.5s-.3.5-.5.5zM11.5 9.9H5.4c-.3 0-.5-.2-.5-.5s.2-.5.5-.5h6.1c.3 0 .5.2.5.5s-.2.5-.5.5zM7.7 7.8H3c-.3 0-.5-.2-.5-.5s.2-.5.5-.5h4.7c.3 0 .5.2.5.5s-.2.5-.5.5z"/>
+<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <path d="M5 1.5a.5.5 0 0 0-1 0v2a.5.5 0 0 0 1 0v-2zM8.5 3.5v-2a.5.5 0 0 0-1 0v2a.5.5 0 0 0 1 0zM12 3.5v-2a.5.5 0 1 0-1 0v2a.5.5 0 1 0 1 0zM5 7h4a.5.5 0 0 0 0-1H5a.5.5 0 0 0 0 1zM5 11h2a.5.5 0 1 0 0-1H5a.5.5 0 1 0 0 1zM6 9h5a.5.5 0 1 0 0-1H6a.5.5 0 0 0 0 1z"/>
+  <path d="M3 3.996v9.008c0-.003 0-.004.002-.004h9.996c-.001 0 .002-.003.002.004V3.996c0 .003 0 .004-.002.004H3.002C3.003 4 3 4.003 3 3.996zm-1 0C2 3.446 2.456 3 3.002 3h9.996A.998.998 0 0 1 14 3.996v9.008c0 .55-.456.996-1.002.996H3.002A.998.998 0 0 1 2 13.004V3.996z"/>
 </svg>
deleted file mode 100644
index c64f4bb92fa980e97bafb5bd5ff8ab2ddef9a278..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
new file mode 100644
--- /dev/null
+++ b/devtools/client/themes/images/debugger-blackbox.svg
@@ -0,0 +1,7 @@
+<!-- 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 width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <circle cx="8" cy="8.5" r="1.5"/>
+  <path d="M15.498 8.28l-.001-.03v-.002-.004l-.002-.018-.004-.031c0-.002 0-.002 0 0l-.004-.035.006.082c-.037-.296-.133-.501-.28-.661-.4-.522-.915-1.042-1.562-1.604-1.36-1.182-2.74-1.975-4.178-2.309a6.544 6.544 0 0 0-2.755-.042c-.78.153-1.565.462-2.369.91C3.252 5.147 2.207 6 1.252 7.035c-.216.233-.36.398-.499.577-.338.437-.338 1 0 1.437.428.552.941 1.072 1.59 1.635 1.359 1.181 2.739 1.975 4.177 2.308.907.21 1.829.223 2.756.043.78-.153 1.564-.462 2.369-.91 1.097-.612 2.141-1.464 3.097-2.499.217-.235.36-.398.498-.578.12-.128.216-.334.248-.554 0 .01 0 .01-.008.04l.013-.079-.001.011.003-.031.001-.017v.005l.001-.02v.008l.002-.03.001-.05-.001-.044v-.004-.004zm-.954.045v.007l.001.004V8.33v.012l-.001.01v-.005-.005l.002-.015-.001.008c-.002.014-.002.014 0 0l-.007.084c.003-.057-.004-.041-.014-.031-.143.182-.27.327-.468.543-.89.963-1.856 1.752-2.86 2.311-.724.404-1.419.677-2.095.81a5.63 5.63 0 0 1-2.374-.036c-1.273-.295-2.523-1.014-3.774-2.101-.604-.525-1.075-1.001-1.457-1.496-.054-.07-.054-.107 0-.177.117-.152.244-.298.442-.512.89-.963 1.856-1.752 2.86-2.311.724-.404 1.419-.678 2.095-.81a5.631 5.631 0 0 1 2.374.036c1.272.295 2.523 1.014 3.774 2.101.603.524 1.074 1 1.457 1.496.035.041.043.057.046.076 0 .01 0 .01.008.043l-.009-.047.003.02-.002-.013v-.008.016c0-.004 0-.004 0 0v-.004z"/>
+</svg>
deleted file mode 100644
index 2dd33d2fa0337ff2e6c1056dd548e498d65044ba..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 5863380b0d373db4f5982ef4fc9a1754d46b9ede..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 3d38eccd2af098728d1a18ba3755d2ddd5312245..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 2bde10cb475dbab35236b4a2003a0dcec5e5118b..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index b6b06502e830a8de7e3003d7e6497799784f9180..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index fb59dcc33dba6f686feff4ccd5d56c716515610b..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
new file mode 100644
--- /dev/null
+++ b/devtools/client/themes/images/debugger-prettyprint.svg
@@ -0,0 +1,6 @@
+<!-- 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 width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <path d="M5.5 2C3.565 2 2.806 3.12 3.065 4.587c.239 1.346.117 1.76-.435 2.39l-.054.06c-.252.288-.39.474-.523.74L1.94 8l.112.224c.132.265.27.45.523.739l.054.06c.552.63.674 1.044.435 2.39C2.802 12.904 3.527 14 5.5 14a.5.5 0 1 0 0-1c-1.291 0-1.614-.487-1.45-1.413.292-1.65.081-2.37-.669-3.223l-.053-.06c-.2-.229-.296-.357-.38-.528v.448c.084-.17.18-.299.38-.528l.053-.06c.75-.854.961-1.573.67-3.223C3.89 3.515 4.24 3 5.5 3a.5.5 0 1 0 0-1zM10.5 3c1.26 0 1.609.515 1.45 1.413-.292 1.65-.081 2.37.669 3.223l.053.06c.2.229.296.357.38.528v-.448c-.084.17-.18.299-.38.528l-.053.06c-.75.854-.961 1.573-.67 3.223.165.926-.158 1.413-1.449 1.413a.5.5 0 1 0 0 1c1.973 0 2.698-1.096 2.435-2.587-.239-1.346-.117-1.76.435-2.39l.054-.06c.252-.288.39-.474.523-.74L14.06 8l-.112-.224c-.132-.265-.27-.45-.523-.739l-.054-.06c-.552-.63-.674-1.044-.435-2.39C13.194 3.12 12.435 2 10.5 2a.5.5 0 0 0 0 1z"/>
+</svg>
deleted file mode 100644
index e3791bfa13a63a525029f55a45559e79530ab307..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index b16b706024e7cdb35b06eb09b898f8165051ebe8..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
new file mode 100644
--- /dev/null
+++ b/devtools/client/themes/images/debugger-step-in.svg
@@ -0,0 +1,6 @@
+<!-- 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 width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <path d="M1.5 14.042h4.095a.5.5 0 0 0 0-1H1.5a.5.5 0 1 0 0 1zM7.5 3v6.983L4.364 6.657a.5.5 0 0 0-.728.686l4 4.243a.51.51 0 0 0 .021.02.5.5 0 0 0 .71-.024l3.997-4.239a.5.5 0 1 0-.728-.686L8.5 9.983V2.5a.5.5 0 0 0-.536-.5H1.536C1.24 2 1 2.224 1 2.5s.24.5.536.5H7.5zM10.5 14.042h4.095a.5.5 0 0 0 0-1H10.5a.5.5 0 1 0 0 1z"/>
+</svg>
deleted file mode 100644
index c0b45008e1d28eb7e29d5a7d06ac6bb2a7af38b8..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 859c727cdbf559957cb9a0e5365b651609b7e0e5..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
new file mode 100644
--- /dev/null
+++ b/devtools/client/themes/images/debugger-step-out.svg
@@ -0,0 +1,6 @@
+<!-- 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 width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <path d="M5 13.5H1a.5.5 0 1 0 0 1h4a.5.5 0 1 0 0-1zM12 13.5H8a.5.5 0 1 0 0 1h4a.5.5 0 1 0 0-1zM6.11 5.012A.427.427 0 0 1 6.21 5h7.083L9.646 1.354a.5.5 0 1 1 .708-.708l4.5 4.5a.498.498 0 0 1 0 .708l-4.5 4.5a.5.5 0 0 1-.708-.708L13.293 6H6.5v5.5a.5.5 0 1 1-1 0v-6a.5.5 0 0 1 .61-.488z"/>
+</svg>
deleted file mode 100644
index 1c19679354bcde539334d1e8b72ac52ec34014bc..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
new file mode 100644
--- /dev/null
+++ b/devtools/client/themes/images/debugger-step-over.svg
@@ -0,0 +1,7 @@
+<!-- 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 width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <path d="M13.297 6.912C12.595 4.39 10.167 2.5 7.398 2.5A5.898 5.898 0 0 0 1.5 8.398a.5.5 0 0 0 1 0A4.898 4.898 0 0 1 7.398 3.5c2.75 0 5.102 2.236 5.102 4.898v.004L8.669 7.029a.5.5 0 0 0-.338.942l4.462 1.598a.5.5 0 0 0 .651-.34.506.506 0 0 0 .02-.043l2-5a.5.5 0 1 0-.928-.372l-1.24 3.098z"/>
+  <circle cx="7" cy="12" r="1"/>
+</svg>
--- a/devtools/client/themes/images/debugger-toggleBreakpoints.svg
+++ b/devtools/client/themes/images/debugger-toggleBreakpoints.svg
@@ -1,6 +1,6 @@
 <!-- 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="16" fill="#babec3">
-  <path d="M1 5c-.553 0-1 .45-1 .99v4.02c0 .546.447.99 1 .99h12l3-3-3-3H1zm16 6c-.553 0-1-.45-1-.99V5.99c0-.546.45-.99 1.008-.99h8.577l3.208-3.207.707-.707L30.914 2.5l-.707.707-11 11-.707.707-1.414-1.414.707-.707L19.586 11H17zm12 0l3-3-2.18-2.697L24 11h5z"/>
+<svg width="32" height="16" viewBox="0 0 32 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <path d="M3.233 11.25l-.417 1H1.712C.763 12.25 0 11.574 0 10.747V6.503C0 5.675.755 5 1.712 5h4.127l-.417 1H1.597C1.257 6 1 6.225 1 6.503v4.244c0 .277.267.503.597.503h1.636zM7.405 11.02L7 12.056c.865.01 2.212-.024 2.315-.04.112-.016.112-.016.185-.035.075-.02.156-.046.251-.082.152-.056.349-.138.592-.244.415-.182.962-.435 1.612-.744l.138-.066a179.35 179.35 0 0 0 2.255-1.094c1.191-.546 1.191-2.074-.025-2.632l-.737-.34A3547.554 3547.554 0 0 0 9.732 5c-.029.11-.065.222-.11.336l-.232.596c.894.408 4.56 2.107 4.56 2.107.458.21.458.596 0 .806L9.197 11.02H7.405zM20.462 14.192l5-12a.5.5 0 0 0-.924-.384l-5 12a.5.5 0 0 0 .924.384zM19.233 11.25l-.417 1h-1.104c-.949 0-1.712-.676-1.712-1.503V6.503C16 5.675 16.755 5 17.712 5h4.127l-.417 1h-3.825c-.34 0-.597.225-.597.503v4.244c0 .277.267.503.597.503h1.636zM23.405 11.02L23 12.056c.865.01 2.212-.024 2.315-.04.112-.016.112-.016.185-.035.075-.02.156-.046.251-.082.152-.056.349-.138.592-.244.415-.182.962-.435 1.612-.744l.138-.066a179.35 179.35 0 0 0 2.255-1.094c1.191-.546 1.191-2.074-.025-2.632l-.737-.34A3547.554 3547.554 0 0 0 25.732 5c-.029.11-.065.222-.11.336l-.232.596c.894.408 4.56 2.107 4.56 2.107.458.21.458.596 0 .806l-4.753 2.174h-1.792z"/>
 </svg>
--- a/devtools/client/themes/images/diff.svg
+++ b/devtools/client/themes/images/diff.svg
@@ -1,7 +1,9 @@
 <!-- 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 height="16" width="16" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="#babec3">
-  <path d="M10.2 4.1c-.6 0-1.2.2-1.8.4-.6-.4-1.4-.6-2.2-.6-2.5 0-4.6 2.1-4.6 4.6s2.1 4.6 4.6 4.6c.9 0 1.6-.2 2.3-.7.5.2 1.1.4 1.7.4 2.4 0 4.3-1.9 4.3-4.3.1-2.4-1.9-4.4-4.3-4.4zm-4 7.9c-1.9 0-3.5-1.6-3.5-3.5S4.2 5 6.2 5c.3 0 .7 0 1 .1-.8.9-1.4 2.1-1.4 3.4 0 1.3.6 2.5 1.5 3.3-.4.1-.8.2-1.1.2zm2.1-.7c-.9-.6-1.4-1.6-1.4-2.8 0-1.1.6-2.1 1.4-2.8.8.6 1.4 1.6 1.4 2.8 0 1.1-.6 2.1-1.4 2.8z"/>
-  <path d="M7.6 8c-.2 0-.3-.1-.4-.2-.1-.2 0-.4.2-.5l1.1-.6c.2-.1.4 0 .5.2.1.2 0 .4-.2.5l-1.1.5c0 .1-.1.1-.1.1zM7.6 9.1c-.1 0-.3-.1-.4-.2-.1-.2 0-.4.2-.5l1.1-.6c.3-.1.5 0 .6.2.1.2 0 .4-.2.5l-1.1.6h-.2zM7.8 10.3c-.1 0-.3-.1-.4-.2-.1-.2 0-.4.2-.5L8.8 9c.2-.1.4 0 .5.2.1.2 0 .4-.2.5l-1.1.6h-.2z"/>
+<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <path d="M6 13A5 5 0 1 0 6 3a5 5 0 0 0 0 10zm0-.91a4.09 4.09 0 1 1 0-8.18 4.09 4.09 0 0 1 0 8.18z"/>
+  <path d="M10 13a5 5 0 1 0 0-10 5 5 0 0 0 0 10zm0-.91a4.09 4.09 0 1 1 0-8.18 4.09 4.09 0 0 1 0 8.18z"/>
+  <path d="M7.146 8.854l1 1a.5.5 0 0 0 .708-.708l-1-1a.5.5 0 1 0-.708.708zM7.146 6.854l1 1a.5.5 0 1 0 .708-.708l-1-1a.5.5 0 1 0-.708.708z"/>
+  <path d="M12.656 11.723c-2.044 1.169-3.872 1.015-4.282.577-.41-.438 2.115-1.269 2.115-3.925 0-2.657-2.115-4.827-2.115-4.827s2.919-.47 4.282.624c1.364 1.094 2.12 1.975 1.85 3.828-.103.703.194 2.555-1.85 3.723z" fill-opacity=".3"/>
 </svg>
--- a/devtools/client/themes/images/dock-bottom.svg
+++ b/devtools/client/themes/images/dock-bottom.svg
@@ -1,6 +1,6 @@
 <!-- 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="16" height="16" viewBox="0 0 16 16" fill="whitesmoke">
-  <path d="M11.9 13.5V3.9c0-.3-.3-.7-.7-.7H2c-.3 0-.7.2-.7.7v9.6c0 .3.3.7.7.7h9.2c.6-.1.7-.6.7-.7zM2.1 9.3V4h9v5.3h-9zm0 3.9v-3h9v3h-9z"/>
+<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <path d="M10.004 3H.996C.999 3 1 3 1 3.002v9.996c0-.001.003.002-.004.002h9.008c-.003 0-.004 0-.004-.002V3.002c0 .001-.003-.002.004-.002zm0-1c.55 0 .996.456.996 1.002v9.996A.998.998 0 0 1 10.004 14H.996C.446 14 0 13.544 0 12.998V3.002A.998.998 0 0 1 .996 2h9.008zm-.41 8H.996v1h9.01v-1h-.41z"/>
 </svg>
--- a/devtools/client/themes/images/dock-side.svg
+++ b/devtools/client/themes/images/dock-side.svg
@@ -1,6 +1,3 @@
-<!-- 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="16" height="16" viewBox="0 0 16 16" fill="whitesmoke">
-  <path d="M-1.5 3.2h-9.6c-.1 0-.2.1-.2.2V13c0 .1.1.2.2.2h9.6c.1 0 .2-.1.2-.2V3.4c0-.1-.1-.2-.2-.2zm-3.6 8.9h-5V4.4h5v7.7zm3.2-.1h-2.7V4.4h2.7V12zM11.1 3.2H.9c-.3 0-.7.3-.7.7v9.2c0 .3.2.7.7.7h10.2c.3 0 .7-.3.7-.7V3.9c-.1-.6-.6-.7-.7-.7zM6.9 13H1.1V4H7v9zm4 0h-3V4h3v9z"/>
+<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <path d="M1 2.996v9.008c0-.003 0-.004.002-.004h9.996c-.001 0 .002-.003.002.004V2.996c0 .003 0 .004-.002.004H1.002C1.003 3 1 3.003 1 2.996zm-1 0C0 2.446.456 2 1.002 2h9.996A.998.998 0 0 1 12 2.996v9.008c0 .55-.456.996-1.002.996H1.002A.998.998 0 0 1 0 12.004V2.996zm8 .413V12h1V3H8v.41z"/>
 </svg>
--- a/devtools/client/themes/images/dock-undock.svg
+++ b/devtools/client/themes/images/dock-undock.svg
@@ -1,7 +1,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="16" height="16" viewBox="0 0 16 16" fill="whitesmoke">
-  <path d="M4.3 2.8v5.9c0 .2.2.4.5.4h5.7c.2 0 .5-.2.5-.4V2.8c0-.2-.2-.4-.5-.4H4.8c-.4 0-.5.3-.5.4zm5.8 2.8v2.6h-5V5.6h5zm0-2.5V5h-5V3.1h5z"/>
-  <path d="M7.1 9.9v2.2h-5V9.7h1.2V9H2.1V7h1.2v-.7H1.7c-.4 0-.5.3-.5.4v5.9c0 .2.2.4.5.4h5.7c.2 0 .5-.2.5-.4V9.9h-.8z"/>
+<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <path d="M13.003 1.941H6.997c.008 0 .003.004.003.008v6.102c0 .004.004.008-.003.008h6.006c-.008 0-.003-.004-.003-.008V1.949c0-.004-.004-.008.003-.008zm0-.941c.55 0 .997.43.997.95v6.1c0 .525-.453.95-.997.95H6.997C6.447 9 6 8.57 6 8.05v-6.1c0-.525.453-.95.997-.95h6.006z"/>
+  <path d="M9 9.91v-.278h1v1.183c0 .516-.453.935-.997.935H2.997c-.55 0-.997-.43-.997-.95V4.7c0-.525.444-.95 1.006-.95h2.288v.941H3.006C3 4.691 3 4.691 3 4.7v6.102c0 .004.004.008-.003.008h6.006c-.004 0-.003-.001-.003.006v-.248-.657-.278h1v1.183c0 .516-.453.935-.997.935H2.997c-.55 0-.997-.43-.997-.95V4.7c0-.525.444-.95 1.006-.95h2.288v.941H3.006C3 4.691 3 4.691 3 4.7v6.102c0 .004.004.008-.003.008h6.006c-.004 0-.003-.001-.003.006v-.248-.657z"/>
+  <path d="M12.52 5H6.976v1h6.046V5zM6.5 7H2.975v1H7V7z"/>
 </svg>
deleted file mode 100644
index 5cbc7274f071b80e6660f23f3ddd66f1aca7af86..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
new file mode 100644
--- /dev/null
+++ b/devtools/client/themes/images/fast-forward.svg
@@ -0,0 +1,6 @@
+<!-- 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 width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <path d="M4 12.5l8-5-8-5v10zm-1 0v-10a1 1 0 0 1 1.53-.848l8 5a1 1 0 0 1 0 1.696l-8 5A1 1 0 0 1 3 12.5zM15 12.497l-.04-7.342-.01-1.658A.488.488 0 0 0 14.474 3a.488.488 0 0 0-.473.503l.05 9a.488.488 0 0 0 .477.497.488.488 0 0 0 .473-.503z"/>
+</svg>
deleted file mode 100644
index 345d07cea08f86cd1095c1e5ceb953dc75efddd5..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/devtools/client/themes/images/filter.svg
+++ b/devtools/client/themes/images/filter.svg
@@ -1,7 +1,7 @@
 <!-- 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="16" height="16" viewBox="0 0 16 16" fill="#aaa">
-  <path fill-opacity="0.3" d="M6.6 8.4c0-.6-1.7.3-1.7-.3C4.9 7.7 2.4 4 2.4 4h11.3s-2.5 3.4-2.5 4.1c0 .3-2.1-.1-2.1.3v5.9H7s-.4-3.9-.4-5.9z"/>
-  <path d="M2 2v2.3l2.7 4.5h1.6v5.5s1.1.6 1.8.6c.5 0 1.8-.6 1.8-.6V8.8h1.6L14 4.3V2H2zm10.8 2l-2.1 3.6H8.5v5.9c-.1 0-.1.1-.2.1-.2.1-.3.1-.3.1s-.1 0-.2-.1c-.1 0-.2-.1-.3-.1V7.6H5.4L3.2 4v-.8h9.5V4z"/>
+  <path fill-opacity=".3" d="M6.6 8.4c0-.6-1.7.3-1.7-.3 0-.4-1.7-2.7-1.7-2.7H13s-1.8 2-1.8 2.7c0 .3-2.1-.1-2.1.3v6.1H7s-.4-4.1-.4-6.1z"/>
+  <path d="M2 2v2.3L4.7 9H6v5.4l2.1 1 1.8-.9V9h1.3L14 4.3V2H2zm11 2l-2.2 4H9v5.8l-.9.4-1.1-.5V8H5.2L3 4V3h10v1z"/>
 </svg>
new file mode 100644
--- /dev/null
+++ b/devtools/client/themes/images/import.svg
@@ -0,0 +1,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 width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <path d="M7.864 1.417c-.123-.13-.305-.185-.48-.144-.173.04-.312.172-.363.343-.05.17-.007.357.116.487l4 4.243c.19.2.506.21.707.02.2-.188.21-.505.02-.706l-4-4.243z"/>
+  <path d="M7.136 1.414l-4 4.243c-.19.2-.18.518.02.707.202.19.52.18.708-.02l4-4.244c.123-.13.166-.316.115-.487-.052-.17-.19-.302-.365-.343-.174-.04-.356.014-.48.144zM1.5 8c-.276 0-.5.224-.5.5v5c0 .2.224.5.5.5h12c.276 0 .5-.3.5-.5v-5c0-.276-.224-.5-.5-.5h-3c-.28 0-.5.224-.5.5s.22.5.5.5H13v4H2V9h2.5c.27 0 .5-.224.5-.5S4.77 8 4.5 8h-3z"/>
+  <path d="M7 2v9c0 .276.224.5.5.5s.5-.224.5-.5V2c0-.276-.224-.5-.5-.5S7 1.724 7 2z"/>
+</svg>
deleted file mode 100644
index dc30c224dcb26262855aae0a6271b0f2ee4cae6b..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
new file mode 100644
--- /dev/null
+++ b/devtools/client/themes/images/itemToggle.svg
@@ -0,0 +1,7 @@
+<!-- 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 width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <circle cx="8" cy="8.5" r="1.5"/>
+  <path d="M15.498 8.28l-.001-.03v-.002-.004l-.002-.018-.004-.031c0-.002 0-.002 0 0l-.004-.035.006.082c-.037-.296-.133-.501-.28-.661-.4-.522-.915-1.042-1.562-1.604-1.36-1.182-2.74-1.975-4.178-2.309a6.544 6.544 0 0 0-2.755-.042c-.78.153-1.565.462-2.369.91C3.252 5.147 2.207 6 1.252 7.035c-.216.233-.36.398-.499.577-.338.437-.338 1 0 1.437.428.552.941 1.072 1.59 1.635 1.359 1.181 2.739 1.975 4.177 2.308.907.21 1.829.223 2.756.043.78-.153 1.564-.462 2.369-.91 1.097-.612 2.141-1.464 3.097-2.499.217-.235.36-.398.498-.578.12-.128.216-.334.248-.554 0 .01 0 .01-.008.04l.013-.079-.001.011.003-.031.001-.017v.005l.001-.02v.008l.002-.03.001-.05-.001-.044v-.004-.004zm-.954.045v.007l.001.004V8.33v.012l-.001.01v-.005-.005l.002-.015-.001.008c-.002.014-.002.014 0 0l-.007.084c.003-.057-.004-.041-.014-.031-.143.182-.27.327-.468.543-.89.963-1.856 1.752-2.86 2.311-.724.404-1.419.677-2.095.81a5.63 5.63 0 0 1-2.374-.036c-1.273-.295-2.523-1.014-3.774-2.101-.604-.525-1.075-1.001-1.457-1.496-.054-.07-.054-.107 0-.177.117-.152.244-.298.442-.512.89-.963 1.856-1.752 2.86-2.311.724-.404 1.419-.678 2.095-.81a5.631 5.631 0 0 1 2.374.036c1.272.295 2.523 1.014 3.774 2.101.603.524 1.074 1 1.457 1.496.035.041.043.057.046.076 0 .01 0 .01.008.043l-.009-.047.003.02-.002-.013v-.008.016c0-.004 0-.004 0 0v-.004z"/>
+</svg>
deleted file mode 100644
index 90421287cc6c9631cb8c182a9e89697fe71b22f7..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/devtools/client/themes/images/pane-collapse.svg
+++ b/devtools/client/themes/images/pane-collapse.svg
@@ -1,6 +1,9 @@
 <!-- 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 width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="#babec3">
-  <path d="M2 2h12v12H2V2zm1 1h7v10H3V3zm6 5l-4 3V5l4 3z" fill-rule="evenodd"/>
+<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <path fill-opacity=".3" d="M12 3h2v10h-2z"/>
+  <path d="M2 3.002v9.996c0-.004.006.002.007.002h11.986c.005 0 .007-.002.007-.002V3.002c0 .004-.006-.002-.007-.002H2.007C2.002 3 2 3.002 2 3.002zm-1 0C1 2.45 1.45 2 2.007 2h11.986A1.01 1.01 0 0 1 15 3.002v9.996C15 13.55 14.55 14 13.993 14H2.007A1.01 1.01 0 0 1 1 12.998V3.002zm10 .453V13h1V3h-1v.455z"/>
+  <path d="M5 10.25l3-1.875L5 6.5v3.75zm-1 0V6.5a1 1 0 0 1 1.53-.848l3 1.875a1 1 0 0 1 0 1.696l-3 1.875A1 1 0 0 1 4 10.25z"/>
+  <path fill-opacity=".3" d="M4.5 10.75V6L9 8.375z"/>
 </svg>
--- a/devtools/client/themes/images/pane-expand.svg
+++ b/devtools/client/themes/images/pane-expand.svg
@@ -1,6 +1,9 @@
 <!-- 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 width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="#babec3">
-  <path d="M2 2h12v12H2V2zm1 1h7v10H3V3zm1 5l4 3V5L4 8z" fill-rule="evenodd"/>
+<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <path fill-opacity=".3" d="M12 3h2v10h-2z"/>
+  <path d="M2 3.002v9.996c0-.004.006.002.007.002h11.986c.005 0 .007-.002.007-.002V3.002c0 .004-.006-.002-.007-.002H2.007C2.002 3 2 3.002 2 3.002zm-1 0C1 2.45 1.45 2 2.007 2h11.986A1.01 1.01 0 0 1 15 3.002v9.996C15 13.55 14.55 14 13.993 14H2.007A1.01 1.01 0 0 1 1 12.998V3.002zm10 .453V13h1V3h-1v.455z"/>
+  <path d="M8 6.5L5 8.375l3 1.875V6.5zm1 0v3.75a1 1 0 0 1-1.53.848l-3-1.875a1 1 0 0 1 0-1.696l3-1.875A1 1 0 0 1 9 6.5z"/>
+  <path fill-opacity=".3" d="M8.5 6v4.75L4 8.375z"/>
 </svg>
new file mode 100644
--- /dev/null
+++ b/devtools/client/themes/images/pause.svg
@@ -0,0 +1,6 @@
+<!-- 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 width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <path d="M5 12.503l.052-9a.5.5 0 0 0-1-.006l-.052 9a.5.5 0 0 0 1 .006zM12 12.497l-.05-9A.488.488 0 0 0 11.474 3a.488.488 0 0 0-.473.503l.05 9a.488.488 0 0 0 .477.497.488.488 0 0 0 .473-.503z"/>
+</svg>
--- a/devtools/client/themes/images/performance-icons.svg
+++ b/devtools/client/themes/images/performance-icons.svg
@@ -1,45 +1,42 @@
 <!-- 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="16px" height="16px">
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="whitesmoke">
   <style>
-    g {
-      fill: #babec3;
-    }
     g:not(:target) {
       display: none;
     }
   </style>
   <g id="overview-markers">
-    <rect x="0px" y="3px" width="5px" height="2.5px" rx="1" ry="1"/>
-    <rect x="7px" y="3px" width="9px" height="2.5px" rx="1" ry="1"/>
-    <rect x="0px" y="7px" width="9px" height="2.5px" rx="1" ry="1"/>
-    <rect x="10px" y="7px" width="6px" height="2.5px" rx="1" ry="1"/>
-    <rect x="4px" y="11px" width="5px" height="2.5px" rx="1" ry="1"/>
-    <rect x="12px" y="11px" width="4px" height="2.5px" rx="1" ry="1"/>
+    <rect x="0" y="4" width="5" height="1"/>
+    <rect x="7" y="4" width="9" height="1"/>
+    <rect x="0" y="8" width="8" height="1"/>
+    <rect x="10" y="8" width="6" height="1"/>
+    <rect x="0" y="12" width="9" height="1"/>
+    <rect x="12" y="12" width="4" height="1"/>
   </g>
   <g id="overview-frames">
-    <rect x="1px" y="4px" width="2px" height="12px" rx="1" ry="1"/>
-    <rect x="5px" y="12px" width="2px" height="4px" rx="1" ry="1"/>
-    <rect x="9px" y="9px" width="2px" height="7px" rx="1" ry="1"/>
-    <rect x="13px" y="7px" width="2px" height="9px" rx="1" ry="1"/>
+    <rect x="1" y="4" width="2" height="12" rx="1" ry="1"/>
+    <rect x="5" y="12" width="2" height="4" rx="1" ry="1"/>
+    <rect x="9" y="9" width="2" height="7" rx="1" ry="1"/>
+    <rect x="13" y="7" width="2" height="9" rx="1" ry="1"/>
   </g>
   <g id="details-waterfall">
-    <rect x="0px" y="3px" width="9px" height="2.5px" rx="1" ry="1"/>
-    <rect x="5px" y="7px" width="8px" height="2.5px" rx="1" ry="1"/>
-    <rect x="7px" y="11px" width="9px" height="2.5px" rx="1" ry="1"/>
+    <rect x="0" y="4" width="9" height="1"/>
+    <rect x="5" y="8" width="8" height="1"/>
+    <rect x="7" y="12" width="9" height="1"/>
   </g>
   <g id="details-call-tree">
-    <rect x="0px" y="3px" width="16px" height="2px" rx="1" ry="1"/>
-    <rect x="0px" y="6px" width="8px" height="2px" rx="1" ry="1"/>
-    <rect x="0px" y="9px" width="11px" height="2px" rx="1" ry="1"/>
-    <rect x="0px" y="12px" width="6px" height="2px" rx="1" ry="1"/>
+    <rect x="1" y="4" width="10" height="1"/>
+    <rect x="5" y="7" width="10" height="1"/>
+    <rect x="1" y="10" width="10" height="1"/>
+    <rect x="5" y="13" width="10" height="1"/>
   </g>
   <g id="details-flamegraph">
-    <rect x="0px" y="3px" width="16px" height="2px" rx="1" ry="1"/>
-    <rect x="0px" y="6px" width="8px" height="2px" rx="1" ry="1"/>
-    <rect x="10px" y="6px" width="6px" height="2px" rx="1" ry="1"/>
-    <rect x="2px" y="9px" width="6px" height="2px" rx="1" ry="1"/>
-    <rect x="5px" y="12px" width="3px" height="2px" rx="1" ry="1"/>
+    <rect x="0" y="4" width="16" height="1"/>
+    <rect x="0" y="7" width="8" height="1"/>
+    <rect x="10" y="7" width="6" height="1"/>
+    <rect x="2" y="10" width="6" height="1"/>
+    <rect x="5" y="13" width="3" height="1"/>
   </g>
 </svg>
new file mode 100644
--- /dev/null
+++ b/devtools/client/themes/images/play.svg
@@ -0,0 +1,6 @@
+<!-- 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 width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <path d="M4 12.5l8-5-8-5v10zm-1 0v-10a1 1 0 0 1 1.53-.848l8 5a1 1 0 0 1 0 1.696l-8 5A1 1 0 0 1 3 12.5z" fill-rule="evenodd"/>
+</svg>
--- a/devtools/client/themes/images/power.svg
+++ b/devtools/client/themes/images/power.svg
@@ -1,14 +1,7 @@
-<!--
-Logo from raphaeljs.com, MIT License
-
-Copyright © 2008 Dmitry Baranovskiy
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-
-The software is provided “as is”, without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or the use or other dealings in the software.
--->
-<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg">
-  <path stroke="#babec3" stroke-width="0" fill="#babec3" d="m10.89891,2.50043c-0.49827,-0.24134 -1.09841,-0.03411 -1.34129,0.46514c-0.24185,0.49928 -0.03311,1.09942 0.46517,1.34128c1.56306,0.76071 2.64193,2.36094 2.64092,4.21555c-0.00501,2.58626 -2.09749,4.6787 -4.68322,4.68321c-2.58623,-0.005 -4.67869,-2.09746 -4.68371,-4.68321c-0.001,-1.85561 1.07834,-3.45731 2.64294,-4.21654c0.49928,-0.24185 0.7065,-0.84201 0.46514,-1.34129c-0.24185,-0.49825 -0.84098,-0.70697 -1.34029,-0.46513c-2.23396,1.08135 -3.77446,3.37351 -3.77545,6.02296c0.00099,3.69518 2.99518,6.68989 6.69138,6.69088c3.6957,-0.00099 6.69037,-2.9957 6.69089,-6.69088c-0.00102,-2.64846 -1.53948,-4.9391 -3.77247,-6.02197zm-2.91842,4.9346c0.55398,0 1.00309,-0.44861 1.00309,-1.00357l0,-4.68373c0,-0.55446 -0.44911,-1.00309 -1.00309,-1.00309c-0.555,0 -1.00358,0.44911 -1.00358,1.00309l0,4.68321c0,0.55499 0.44858,1.00409 1.00358,1.00409z"/>
+<!-- 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 width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <path d="M8 14.5a5.5 5.5 0 1 0 0-11 5.5 5.5 0 0 0 0 11zm0-1a4.5 4.5 0 1 1 0-9 4.5 4.5 0 0 1 0 9z"/>
+  <path d="M8.5 7.5v-6a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0z"/>
 </svg>
--- a/devtools/client/themes/images/profiler-stopwatch.svg
+++ b/devtools/client/themes/images/profiler-stopwatch.svg
@@ -1,17 +1,11 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <g fill="#babec3" fill-rule="evenodd">
-    <path d="m8,1c-3.9,0-7,3.1-7,7s3.1,7 7,7c3.9,0 7-3.1 7-7s-3.1-7-7-7zm-.1,12c-2.8,0-5-2.2-5-5 0-2.8 2.2-5 5-5s5,2.2 5,5c0,2.8-2.2,5-5,5z"/>
-    <path d="m8,6.9c.6,0 1.1,.5 1.1,1.1 0,.6-.5,1.1-1.1,1.1-.6,0-1.1-.5-1.1-1.1 0-.6 .5-1.1 1.1-1.1z"/>
-    <path d="m11.3,4.6l-3.9,2.5 1.5,1.4 2.4-3.9z"/>
-    <path opacity=".4" d="m4.6,10c.7,1.2 2,2 3.4,2 1.5,0 2.7-.8 3.4-2h-6.8z"/>
-    <g opacity=".3">
-      <path d="m7.1,5.1l-.6-1.3-.9,.4 .7,1.3c.2-.1 .5-.3 .8-.4z"/>
-      <path d="m9.8,5.6l.7-1.4-.9-.4-.7,1.3c.3,.2 .6,.3 .9,.5z"/>
-      <path d="m10.8,7c.1,.3 .2,.7 .2,1h2v-1h-2.2z"/>
-      <path d="m5,8c0-.3 .1-.7 .2-1h-2.2l-.1,1h2.1z"/>
-    </g>
+<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <g fill-rule="evenodd">
+    <path d="M15 9.004C14.51 12.394 11.578 15 8.035 15 4.15 15 1 11.866 1 8s3.15-7 7.036-7c1.941 0 3.7.783 4.972 2.048l-.709.709A6.027 6.027 0 0 0 8.036 2c-3.33 0-6.03 2.686-6.03 6s2.7 6 6.03 6a6.023 6.023 0 0 0 5.946-4.993l1.017-.003z"/>
+    <path d="M4.137 9H3.1a5.002 5.002 0 0 0 9.8 0h-.965a4.023 4.023 0 0 1-3.9 3 4.023 4.023 0 0 1-3.898-3z" fill-opacity=".5"/>
+    <path d="M8.036 11a2.994 2.994 0 0 0 2.987-3c0-1.657-1.338-3-2.987-3a2.994 2.994 0 0 0-2.988 3c0 1.657 1.338 3 2.988 3zm0-1c1.11 0 2.011-.895 2.011-2s-.9-2-2.011-2c-1.111 0-2.012.895-2.012 2s.9 2 2.012 2z"/>
+    <path d="M10.354 6.354l4-4a.5.5 0 0 0-.708-.708l-4 4a.5.5 0 1 0 .708.708z"/>
   </g>
 </svg>
--- a/devtools/client/themes/images/pseudo-class.svg
+++ b/devtools/client/themes/images/pseudo-class.svg
@@ -1,20 +1,7 @@
 <!-- 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 width="16" height="16" viewBox="0 0 16 16" color="#babec3" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-  <defs>
-    <rect id="class-block-maskBG" width="8" height="8" fill="#fff"/>
-    <rect id="class-block" width="8" height="8" rx="1" ry="1"/>
-    <mask id="mask-block-solid">
-      <use xlink:href="#class-block-maskBG"/>
-      <use xlink:href="#class-block" transform="translate(3 3)" fill="#000"/>
-    </mask>
-  </defs>
-  <rect x=".5" y=".5" width="7" height="7" rx="1" ry="1" mask="url(#mask-block-solid)" fill="none" stroke="currentColor" stroke-width="1"/>
-  <use xlink:href="#class-block" mask="url(#mask-block-solid)" fill="currentColor" fill-opacity=".4"/>
-  <use xlink:href="#class-block" mask="url(#mask-block-solid)" fill="currentColor" transform="translate(4 4)"/>
-  <g transform="translate(8 8)" fill="currentColor">
-    <path d="M2.5,0C2.2,0,2,0.2,2,0.5C2,0.8,2.2,1,2.5,1C2.8,1,3,0.8,3,0.5 C3,0.2,2.8,0,2.5,0z M4.5,0C4.2,0,4,0.2,4,0.5C4,0.8,4.2,1,4.5,1C4.8,1,5,0.8,5,0.5C5,0.2,4.8,0,4.5,0z M0.5,6C0.8,6,1,5.8,1,5.5 C1,5.2,0.8,5,0.5,5C0.2,5,0,5.2,0,5.5C0,5.8,0.2,6,0.5,6z M0.5,4C0.8,4,1,3.8,1,3.5C1,3.2,0.8,3,0.5,3C0.2,3,0,3.2,0,3.5 C0,3.8,0.2,4,0.5,4z M7.5,2C7.2,2,7,2.2,7,2.5C7,2.8,7.2,3,7.5,3C7.8,3,8,2.8,8,2.5C8,2.2,7.8,2,7.5,2z M7.5,4C7.2,4,7,4.2,7,4.5 C7,4.8,7.2,5,7.5,5C7.8,5,8,4.8,8,4.5C8,4.2,7.8,4,7.5,4z M5.5,7C5.2,7,5,7.2,5,7.5C5,7.8,5.2,8,5.5,8C5.8,8,6,7.8,6,7.5 C6,7.2,5.8,7,5.5,7z M3.5,7C3.2,7,3,7.2,3,7.5C3,7.8,3.2,8,3.5,8C3.8,8,4,7.8,4,7.5C4,7.2,3.8,7,3.5,7z M0.5,2C0.8,2,1,1.8,1,1.5v-1 C1,0.2,0.8,0,0.5,0C0.2,0,0,0.2,0,0.5v1C0,1.8,0.2,2,0.5,2z M8,0.5C8,0.2,7.8,0,7.5,0h-1C6.2,0,6,0.2,6,0.5C6,0.8,6.2,1,6.5,1h1 C7.8,1,8,0.8,8,0.5z M7.5,6C7.2,6,7,6.2,7,6.5v1C7,7.8,7.2,8,7.5,8C7.8,8,8,7.8,8,7.5v-1C8,6.2,7.8,6,7.5,6z M1.5,7h-1 C0.2,7,0,7.2,0,7.5C0,7.8,0.2,8,0.5,8h1C1.8,8,2,7.8,2,7.5C2,7.2,1.8,7,1.5,7z"/>
-    <use xlink:href="#class-block" fill-opacity=".2"/>
-  </g>
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="whitesmoke">
+  <path d="M11 7V5.5c0-.3-.2-.5-.5-.5h-5c-.3 0-.5.2-.5.5v5c0 .3.2.5.5.5h1.9V7.5c0-.3.2-.5.5-.5H11zM3 7H.8c-.1 0-.6 0-.7-.7-.1-.2-.1-.4-.1-.6v-5C0 .5 0 .3.2.1.4 0 .6 0 .7 0h5.2c.3 0 .6 0 .8.2.2.1.3.3.3.5V3H3v4zM1 6h1V2.7c0-.2.1-.4.2-.5.3-.2.6-.2.8-.2h3V1H1v5z"/>
+  <path d="M9 9h1v1H9V9zm5 1h-1V9h1v1zm-2 0h-1V9h1v1zm3-1h1v1h-1V9zm1 5h-1v-1h1v1zm0-2h-1v-1h1v1zm-1 3h1v1h-1v-1zm-1 1h-1v-1h1v1zm-2 0h-1v-1h1v1zm-3-1h1v1H9v-1zm1-1H9v-1h1v1zm0-2H9v-1h1v1z"/>
 </svg>
deleted file mode 100644
index 3e8b4db747311a8ac511e3db2cb2dab6a5541ad7..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
new file mode 100644
--- /dev/null
+++ b/devtools/client/themes/images/rewind.svg
@@ -0,0 +1,6 @@
+<!-- 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 width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <path d="M13 2.5l-8 5 8 5v-10zm1 0v10a1 1 0 0 1-1.53.848l-8-5a1 1 0 0 1 0-1.696l8-5A1 1 0 0 1 14 2.5zM2 12.497l-.04-7.342-.01-1.658A.488.488 0 0 0 1.474 3 .488.488 0 0 0 1 3.503l.05 9a.488.488 0 0 0 .477.497.488.488 0 0 0 .473-.503z"/>
+</svg>
deleted file mode 100644
index c6fee45f3da3d5d4bdda03779dac7cbcd73337c9..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
--- a/devtools/client/themes/images/timeline-filter.svg
+++ /dev/null
@@ -1,6 +0,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/. -->
-<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="#babec3" d="M2,2v3l5,4v6h2v-6l5,-4v-3L14,2z"/>
-</svg>
--- a/devtools/client/themes/images/tool-canvas.svg
+++ b/devtools/client/themes/images/tool-canvas.svg
@@ -1,7 +1,9 @@
 <!-- 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="16" height="16" viewBox="0 0 16 16" fill="whitesmoke">
-  <path opacity="0.5" d="M3.7 3.6H2.1c-.1 0-.1.1-.1.1v1.6c0 .1.1.1.1.1h1.6c.1 0 .1-.1.1-.1V3.7c.1-.1 0-.1-.1-.1zM3.7 7.3H2.1c-.1 0-.1.1-.1.1V9c0 .1.1.1.1.1h1.6c.1 0 .1-.1.1-.1V7.5c.1-.1 0-.2-.1-.2zM3.7 11.1H2.1c-.1 0-.1.1-.1.1v1.6c0 .1.1.1.1.1h1.6c.1 0 .1-.1.1-.1v-1.6c.1 0 0-.1-.1-.1zM6.1 5.5H4.5c-.1 0-.1.1-.1.1v1.6c0 .1.1.1.1.1h1.6c.1 0 .1-.1.1-.1l-.1-1.7c.2 0 .1 0 0 0zM6.1 9.2H4.5c-.1 0-.1.1-.1.1V11c0 .1.1.1.1.1h1.6c.1 0 .1-.1.1-.1V9.4c.1-.1 0-.2-.1-.2zM8.3 3.6H6.7c-.1 0-.1.1-.1.1v1.6c0 .1.1.1.1.1h1.6c.1 0 .1-.1.1-.1V3.7c.1-.1 0-.1-.1-.1zM8.3 7.3H6.7c-.1 0-.1.1-.1.1V9c0 .1.1.1.1.1h1.6c.1 0 .1-.1.1-.1V7.5c.1-.1 0-.2-.1-.2zM8.3 11.1H6.7c-.1 0-.1.1-.1.1v1.6c0 .1.1.1.1.1h1.6c.1 0 .1-.1.1-.1v-1.6c.1 0 0-.1-.1-.1zM10.6 5.5H9c-.1 0-.1.1-.1.1v1.6c0 .1.1.1.1.1h1.6c.1 0 .1-.1.1-.1V5.6c0-.1 0-.1-.1-.1zM10.6 9.2H9c-.1 0-.1.1-.1.1V11c0 .1.1.1.1.1h1.6c.1 0 .1-.1.1-.1V9.4c0-.1 0-.2-.1-.2zM12.9 3.6h-1.6c-.1 0-.1.1-.1.1v1.6c0 .1.1.1.1.1h1.6c.1.1.1 0 .1-.1V3.7c0-.1 0-.1-.1-.1zM12.9 7.3h-1.6c-.1 0-.1.1-.1.1V9c0 .1.1.1.1.1h1.6c.1.1.1.1.1 0V7.5c0-.1 0-.2-.1-.2zM12.9 11.1h-1.6c-.1 0-.1.1-.1.1v1.6c0 .1.1.1.1.1h1.6c.1 0 .1-.1.1-.1v-1.6s0-.1-.1-.1z"/>
-  <path d="M13.2 2.8H1.8c-.4 0-.8.4-.8.9v9.2c0 .4.3.9.8.9h11.4c.4 0 .8-.4.8-.9V3.7c0-.7-.6-.9-.8-.9zm-.2 10H2v-9h11v9z"/>
+<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <g fill-rule="evenodd">
+    <path d="M1 2.007C1 1.45 1.45 1 2.007 1h11.986C14.55 1 15 1.45 15 2.007v11.986C15 14.55 14.55 15 13.993 15H2.007C1.45 15 1 14.55 1 13.993V2.007zM2 2h12v12H2V2z"/>
+    <path d="M3 3h2v2H3zM11 3h2v2h-2zM7 3h2v2H7zM3 7h2v2H3zM11 7h2v2h-2zM7 7h2v2H7zM5 5h2v2H5zM9 5h2v2H9zM3 11h2v2H3zM11 11h2v2h-2zM7 11h2v2H7zM5 9h2v2H5zM9 9h2v2H9z" opacity="0.5"/>
+  </g>
 </svg>
--- a/devtools/client/themes/images/tool-debugger-paused.svg
+++ b/devtools/client/themes/images/tool-debugger-paused.svg
@@ -1,7 +1,6 @@
 <!-- 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="16" height="16" viewBox="0 0 16 16" fill="#5FC749">
-  <path d="M8.2 1.7C4.8 1.7 2 4.4 2 7.9s2.7 6.3 6.3 6.3c3.5 0 6.3-2.7 6.3-6.3-.1-3.4-2.9-6.2-6.4-6.2zm0 11.4C5.3 13.1 3 10.8 3 7.9s2.3-5.2 5.2-5.2 5.2 2.3 5.2 5.2c0 3-2.2 5.2-5.2 5.2z"/>
-  <path d="M11.4 7.5L10 6.2c-.1-.1-.2-.1-.4-.1H5.7c-.1 0-.2.1-.2.2v3.2c0 .1.1.4.2.4h4c.1 0 .2-.1.2-.1l1.5-1.7c.2-.1.2-.4 0-.6z"/>
+<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="#5FC749">
+  <path d="M2 5v6c0 .109.039.342.144.553.15.297.374.447.856.447h9l-.78.375 4-5v1.25l-4-5L12 4H3c-.482 0-.707.15-.856.447A1.403 1.403 0 0 0 2 5zM1 5s0-2 2-2h9l4 5-4 5H3c-2 0-2-2-2-2V5z"/>
 </svg>
--- a/devtools/client/themes/images/tool-debugger.svg
+++ b/devtools/client/themes/images/tool-debugger.svg
@@ -1,7 +1,6 @@
 <!-- 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="16" height="16" viewBox="0 0 16 16" fill="whitesmoke">
-  <path d="M8.2 1.7C4.8 1.7 2 4.4 2 7.9s2.7 6.3 6.3 6.3c3.5 0 6.3-2.7 6.3-6.3-.1-3.4-2.9-6.2-6.4-6.2zm0 11.4C5.3 13.1 3 10.8 3 7.9 3 5 5.3 2.7 8.2 2.7c2.9 0 5.2 2.3 5.2 5.2 0 3-2.2 5.2-5.2 5.2z"/>
-  <path d="M6.5 5.3c-.2 0-.4.2-.4.4v4.5c0 .2.3.4.5.4s.5-.2.5-.4V5.7c0-.2-.3-.4-.5-.4M9.5 5.3c-.2 0-.4.2-.4.4v4.5c0 .2.3.4.5.4s.5-.2.5-.4V5.7c0-.2-.3-.4-.5-.4"/>
+<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <path d="M2 5v6c0 .109.039.342.144.553.15.297.374.447.856.447h9l-.78.375 4-5v1.25l-4-5L12 4H3c-.482 0-.707.15-.856.447A1.403 1.403 0 0 0 2 5zM1 5s0-2 2-2h9l4 5-4 5H3c-2 0-2-2-2-2V5z"/>
 </svg>
--- a/devtools/client/themes/images/tool-dom.svg
+++ b/devtools/client/themes/images/tool-dom.svg
@@ -1,6 +1,6 @@
 <!-- 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 height="16" width="16" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="whitesmoke">
-  <path d="M.2 6.3l3.5 3.6c.1.1.3.2.5.2h.9c.3 0 .5-.2.6-.4.1-.2.1-.5-.1-.7l-3-3.1 3-2.9c.2-.2.3-.5.2-.7-.2-.4-.5-.5-.7-.5h-.9c-.2 0-.4 0-.5.2L.2 5.4c-.3.2-.3.6 0 .9M15.8 9.7l-3.5-3.6c-.1-.1-.3-.2-.5-.2h-.9c-.3 0-.5.2-.6.4-.1.2-.1.5.1.7l3 3.1-3 2.9c-.2.2-.3.5-.2.7.1.3.3.4.6.4h.9c.2 0 .3-.1.5-.2l3.5-3.4c.4-.1.4-.5.1-.8"/>
-</svg>
\ No newline at end of file
+<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <path d="M6.052 1.13L1.164 5.57a.5.5 0 0 0 0 .74l5 4.56a.5.5 0 0 0 .673-.74l-5-4.559v.74l4.887-4.44a.5.5 0 0 0-.672-.741zM10.948 14.87l4.888-4.44a.5.5 0 0 0 0-.74l-5-4.56a.5.5 0 1 0-.673.74l5 4.559v-.74l-4.887 4.44a.5.5 0 0 0 .672.741z"/>
+</svg>
--- a/devtools/client/themes/images/tool-inspector.svg
+++ b/devtools/client/themes/images/tool-inspector.svg
@@ -1,6 +1,7 @@
 <!-- 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="16" height="16" viewBox="0 0 16 16" fill="whitesmoke">
-  <path d="M14.3 7.7H13V4.8c0-.7-.6-.9-.8-.9H8.3V2.4c.1-.3-.2-.6-.5-.6s-.6.3-.6.6v1.5H2.9c-.5 0-.9.4-.9.9v3H.7c-.3 0-.6.3-.6.6s.3.6.6.6H2v3c0 .4.3.9.8.9h4.3v1.3c0 .3.3.6.6.6s.6-.3.6-.6v-1.3h3.9c.4 0 .8-.4.8-.9V8.9h1.2c.3 0 .6-.3.6-.6s-.2-.6-.5-.6zM12 11.9H3v-7h9v7z"/>
+<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <path d="M3 3.995v8.01c0-.01.005-.005.002-.005h9.996c-.001 0 .002-.003.002.005v-8.01c0 .01-.005.005-.002.005H3.002C3.003 4 3 4.003 3 3.995zm-1 0C2 3.445 2.456 3 3.002 3h9.996C13.55 3 14 3.456 14 3.995v8.01c0 .55-.456.995-1.002.995H3.002A1.005 1.005 0 0 1 2 12.005v-8.01z"/>
+  <path d="M8.5 3.5V2a.5.5 0 0 0-1 0v1.5a.5.5 0 0 0 1 0zM1 8.5h1a.5.5 0 0 0 0-1H1a.5.5 0 0 0 0 1zM14 8.5h1a.5.5 0 1 0 0-1h-1a.5.5 0 1 0 0 1zM8.5 14v-1.5a.5.5 0 1 0-1 0V14a.5.5 0 1 0 1 0z"/>
 </svg>
--- a/devtools/client/themes/images/tool-memory-active.svg
+++ b/devtools/client/themes/images/tool-memory-active.svg
@@ -1,7 +1,10 @@
 <!-- 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="16" height="16" viewBox="0 0 16 16" fill="#5FC749">
-  <path opacity="0.2" d="M5.2 2.9l5.7.1v9.4H5.2V2.9z"/>
-  <path d="M10.5 2.2h-5c-.4 0-.8.4-.8.9v9.2c0 .4.3.9.8.9h5c.4 0 .8-.4.8-.9V3.1s-.6-.9-.8-.9zm-.2 10H5.7v-9h4.6v9zM15.5 6.6c-.1 0-.3-.1-.4-.2l-1.5-1.7-.9.9c-.2.2-.5.2-.7 0-.2-.2-.2-.5 0-.7l1.3-1.3c.1-.1.2-.1.4-.1.1 0 .3.1.4.2l1.9 2c.2.2.2.5 0 .7-.3.2-.4.2-.5.2zM15.5 9.7c-.1 0-.3-.1-.4-.2l-1.5-1.7-.9.9c-.2.3-.5.3-.7.1-.2-.2-.2-.5 0-.7l1.3-1.2c.1-.1.2-.1.4-.1.1 0 .3.1.4.2L16 9c.2.2.2.5 0 .7h-.5zM15.5 12.7c-.1 0-.3-.1-.4-.2l-1.5-1.7-.9.9c-.2.2-.5.2-.7 0-.2-.2-.2-.5 0-.7l1.3-1.2c.1-.1.2-.1.4-.1.1 0 .3.1.4.2l1.9 2c.2.2.2.5 0 .7-.3.1-.4.1-.5.1zM.5 6.6c.1 0 .3-.1.4-.2l1.5-1.7.9.9c.2.2.5.2.7 0 .2-.2.2-.5 0-.7L2.7 3.7c-.1-.1-.2-.1-.3-.1-.2 0-.3 0-.4.1l-1.9 2c-.2.3-.1.6.1.8.1.1.2.1.3.1zM.5 9.7c.1 0 .3-.1.4-.2l1.5-1.7.9.9c.2.3.5.3.7.1.2-.2.2-.6 0-.8L2.7 6.8c-.1-.1-.2-.1-.3-.1-.2 0-.3 0-.4.1l-1.9 2c-.2.2-.2.5 0 .7.2.2.3.2.4.2zM.5 12.7c.1 0 .3-.1.4-.2l1.5-1.7.9.9c.2.3.5.3.7.1.2-.2.2-.5 0-.7L2.7 9.8c-.1-.1-.2-.1-.3-.1-.2 0-.3 0-.4.1l-1.9 2c-.2.2-.2.5 0 .7.2.2.3.2.4.2z"/>
+<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="#5FC749">
+  <path d="M4.727 8.055l-1.96-1a.5.5 0 0 0-.573.083L.655 8.602a.5.5 0 1 0 .69.725l1.539-1.465-.572.083 1.96 1a.5.5 0 1 0 .455-.89z"/>
+  <path d="M4.727 10.055l-1.96-1a.5.5 0 0 0-.573.083L.655 10.602a.5.5 0 1 0 .69.725l1.539-1.465-.572.083 1.96 1a.5.5 0 1 0 .455-.89zM11.727 10.945l1.961-1-.572-.083 1.54 1.465a.5.5 0 1 0 .689-.725l-1.54-1.464a.5.5 0 0 0-.571-.083l-1.961 1a.5.5 0 1 0 .454.89z"/>
+  <path d="M11.727 8.945l1.961-1-.572-.083 1.54 1.465a.5.5 0 1 0 .689-.725l-1.54-1.464a.5.5 0 0 0-.571-.083l-1.961 1a.5.5 0 1 0 .454.89z"/>
+  <path d="M11.727 6.945l1.961-1-.572-.083 1.54 1.465a.5.5 0 1 0 .689-.725l-1.54-1.464a.5.5 0 0 0-.571-.083l-1.961 1a.5.5 0 1 0 .454.89zM4.727 6.055l-1.96-1a.5.5 0 0 0-.573.083L.655 6.602a.5.5 0 1 0 .69.725l1.539-1.465-.572.083 1.96 1a.5.5 0 1 0 .455-.89z"/>
+  <path d="M5 3.002v9.996c0-.001.003.002-.003.002h6.006c-.006 0-.003-.003-.003-.002V3.002c0 .001-.003-.002.003-.002H4.997c.006 0 .003.003.003.002zm-1 0C4 2.45 4.453 2 4.997 2h6.006c.55 0 .997.456.997 1.002v9.996c0 .553-.453 1.002-.997 1.002H4.997C4.447 14 4 13.544 4 12.998V3.002z"/>
 </svg>
--- a/devtools/client/themes/images/tool-memory.svg
+++ b/devtools/client/themes/images/tool-memory.svg
@@ -1,7 +1,10 @@
 <!-- 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="16" height="16" viewBox="0 0 16 16" fill="whitesmoke">
-  <path opacity="0.2" d="M5.2 2.9l5.7.1v9.4H5.2V2.9z"/>
-  <path d="M10.5 2.2h-5c-.4 0-.8.4-.8.9v9.2c0 .4.3.9.8.9h5c.4 0 .8-.4.8-.9V3.1s-.6-.9-.8-.9zm-.2 10H5.7v-9h4.6v9zM15.5 6.6c-.1 0-.3-.1-.4-.2l-1.5-1.7-.9.9c-.2.2-.5.2-.7 0-.2-.2-.2-.5 0-.7l1.3-1.3c.1-.1.2-.1.4-.1.1 0 .3.1.4.2l1.9 2c.2.2.2.5 0 .7-.3.2-.4.2-.5.2zM15.5 9.7c-.1 0-.3-.1-.4-.2l-1.5-1.7-.9.9c-.2.3-.5.3-.7.1-.2-.2-.2-.5 0-.7l1.3-1.2c.1-.1.2-.1.4-.1.1 0 .3.1.4.2L16 9c.2.2.2.5 0 .7h-.5zM15.5 12.7c-.1 0-.3-.1-.4-.2l-1.5-1.7-.9.9c-.2.2-.5.2-.7 0-.2-.2-.2-.5 0-.7l1.3-1.2c.1-.1.2-.1.4-.1.1 0 .3.1.4.2l1.9 2c.2.2.2.5 0 .7-.3.1-.4.1-.5.1zM.5 6.6c.1 0 .3-.1.4-.2l1.5-1.7.9.9c.2.2.5.2.7 0 .2-.2.2-.5 0-.7L2.7 3.7c-.1-.1-.2-.1-.3-.1-.2 0-.3 0-.4.1l-1.9 2c-.2.3-.1.6.1.8.1.1.2.1.3.1zM.5 9.7c.1 0 .3-.1.4-.2l1.5-1.7.9.9c.2.3.5.3.7.1.2-.2.2-.6 0-.8L2.7 6.8c-.1-.1-.2-.1-.3-.1-.2 0-.3 0-.4.1l-1.9 2c-.2.2-.2.5 0 .7.2.2.3.2.4.2zM.5 12.7c.1 0 .3-.1.4-.2l1.5-1.7.9.9c.2.3.5.3.7.1.2-.2.2-.5 0-.7L2.7 9.8c-.1-.1-.2-.1-.3-.1-.2 0-.3 0-.4.1l-1.9 2c-.2.2-.2.5 0 .7.2.2.3.2.4.2z"/>
+<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <path d="M4.727 8.055l-1.96-1a.5.5 0 0 0-.573.083L.655 8.602a.5.5 0 1 0 .69.725l1.539-1.465-.572.083 1.96 1a.5.5 0 1 0 .455-.89z"/>
+  <path d="M4.727 10.055l-1.96-1a.5.5 0 0 0-.573.083L.655 10.602a.5.5 0 1 0 .69.725l1.539-1.465-.572.083 1.96 1a.5.5 0 1 0 .455-.89zM11.727 10.945l1.961-1-.572-.083 1.54 1.465a.5.5 0 1 0 .689-.725l-1.54-1.464a.5.5 0 0 0-.571-.083l-1.961 1a.5.5 0 1 0 .454.89z"/>
+  <path d="M11.727 8.945l1.961-1-.572-.083 1.54 1.465a.5.5 0 1 0 .689-.725l-1.54-1.464a.5.5 0 0 0-.571-.083l-1.961 1a.5.5 0 1 0 .454.89z"/>
+  <path d="M11.727 6.945l1.961-1-.572-.083 1.54 1.465a.5.5 0 1 0 .689-.725l-1.54-1.464a.5.5 0 0 0-.571-.083l-1.961 1a.5.5 0 1 0 .454.89zM4.727 6.055l-1.96-1a.5.5 0 0 0-.573.083L.655 6.602a.5.5 0 1 0 .69.725l1.539-1.465-.572.083 1.96 1a.5.5 0 1 0 .455-.89z"/>
+  <path d="M5 3.002v9.996c0-.001.003.002-.003.002h6.006c-.006 0-.003-.003-.003-.002V3.002c0 .001-.003-.002.003-.002H4.997c.006 0 .003.003.003.002zm-1 0C4 2.45 4.453 2 4.997 2h6.006c.55 0 .997.456.997 1.002v9.996c0 .553-.453 1.002-.997 1.002H4.997C4.447 14 4 13.544 4 12.998V3.002z"/>
 </svg>
--- a/devtools/client/themes/images/tool-network.svg
+++ b/devtools/client/themes/images/tool-network.svg
@@ -1,9 +1,9 @@
 <!-- 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="16" height="16" viewBox="0 0 16 16" fill="whitesmoke">
-  <path opacity="0.5" d="M10.7 3.3c0-.2-.2-.4-.4-.4H2.8c-.2 0-.4.3-.4.5s.2.5.4.5h7.5c.2 0 .4-.3.4-.5"/>
-  <path d="M12.7 6.4c0-.2-.2-.4-.4-.4H4.8c-.2 0-.4.3-.4.5s.2.5.4.5h7.5c.2 0 .4-.3.4-.5"/>
-  <path opacity="0.5" d="M10.7 9.3c0-.2-.2-.4-.4-.4H3.8c-.2 0-.4.3-.4.5s.2.5.4.5h6.5c.2 0 .4-.3.4-.5"/>
-  <path d="M6.7 12.3c0-.2-.2-.4-.4-.4H2.8c-.2 0-.4.3-.4.5s.2.5.4.5h3.5c.2 0 .4-.3.4-.5"/>
+<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <rect fill-opacity=".5" x="2" y="3" width="8" height="1" rx=".5"/>
+  <rect x="6" y="6" width="8" height="1" rx=".5"/>
+  <rect fill-opacity=".5" x="4" y="9" width="8" height="1" rx=".5"/>
+  <rect x="2" y="12" width="5" height="1" rx=".5"/>
 </svg>
--- a/devtools/client/themes/images/tool-options.svg
+++ b/devtools/client/themes/images/tool-options.svg
@@ -1,7 +1,7 @@
 <!-- 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="16" height="16" viewBox="0 0 16 16" fill="whitesmoke">
-  <path d="M12.3 10.8c.1-.2.2-.6.3-.6h2.1V6.8h-2.1c-.1 0-.2-.3-.3-.6l.6-.5c.2-.2.3-.3.3-.6 0-.2-.1-.4-.3-.6l-.7-.5c-.3-.3-.9-.3-1.2 0l-.4.6c-.3-.2-.6-.3-.6-.4V2.1H6.6v2.1c0 .1-.3.2-.6.3L5.6 4c-.4-.3-.9-.3-1.2 0l-.7.7c-.3.3-.3.9 0 1.2l.6.4c-.1.2-.2.5-.3.5H1.9v3.4H4c.1 0 .2.3.3.6L3 12l2 2 1-1.4c.2.1.6.2.6.3V15H10v-2.1c0-.1.3-.2.6-.3l.5.6c.3.3.9.3 1.2 0l.7-.7c.2-.2.2-.4.2-.6 0-.2-.1-.4-.3-.6l-.6-.5zm.1 1.1l-.7.7h-.1-.1l-.8-.8c-.1-.1-.3-.1-.5-.1-.3.2-.6.4-.9.4-.2 0-.2.2-.2.4V14H7.5v-1.5c0-.2 0-.3-.2-.4-.4-.1-.7-.2-1-.4-.1 0-.1-.1-.2-.1s-.2 0-.3.1l-.9 1h-.2L4 12v-.1-.1l1-1c.1-.1.1-.3.1-.5-.2-.1-.3-.3-.4-.7 0-.2-.2-.2-.4-.2H2.8V7.7h1.5c.2 0 .3 0 .4-.2.1-.4.2-.7.4-1 .1-.1.1-.3-.1-.4l-.7-.8v-.1l.7-.7h.2l.8.8c0 .1.2.1.4 0 .3-.2.5-.3.9-.4.2 0 .2-.2.2-.4V3h1.7v1.5c0 .2 0 .3.2.4.4.1.7.2 1 .4.1.1.3.1.4-.1l.8-.8h.1l.7.7v.2l-.8.8c-.1.1-.1.3-.1.5.2.3.4.6.4.9 0 .2.2.2.4.2h1.5v1.7h-1.5c-.2 0-.3 0-.4.2-.1.4-.2.7-.4 1-.1.2-.1.3.1.4l.8.8v.1z"/>
-  <path d="M8.3 6C6.9 6 5.7 7.1 5.7 8.6s1.2 2.6 2.6 2.6 2.6-1.2 2.6-2.6S9.7 6 8.3 6zm0 4.4c-1 0-1.8-.8-1.8-1.8s.8-1.8 1.8-1.8 1.8.8 1.8 1.8-.8 1.8-1.8 1.8z"/>
+<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <path d="M8.513 3.416v-.918A.502.502 0 0 0 8.012 2h-.999c-.273 0-.5.226-.5.498V4.07l-.6.262c-.274.12-.534.27-.775.449l-.527.39-.567-.328-.796-.46a.502.502 0 0 0-.682.185l-.5.864a.504.504 0 0 0 .182.683l.795.46.567.326-.073.65a4.055 4.055 0 0 0 0 .898l.073.65-.567.327-.795.459a.502.502 0 0 0-.181.683l.499.864c.137.237.446.32.682.185l.796-.46.567-.327.527.39c.24.177.5.328.775.448l.6.262v1.572c0 .272.225.498.5.498h.999c.273 0 .5-.226.5-.498V11.93l.6-.262c.274-.12.534-.27.775-.449l.527-.39.567.328.796.46a.502.502 0 0 0 .682-.185l.5-.864a.504.504 0 0 0-.182-.683l-.795-.46-.567-.326.073-.65a4.055 4.055 0 0 0 0-.898l-.073-.65.567-.327.795-.459a.502.502 0 0 0 .181-.683l-.499-.864a.504.504 0 0 0-.682-.185l-.796.46-.567.327-.527-.39c-.24-.177-.5-.328-.775-.448l-.6-.262v-.654zm1 0c.345.15.67.34.968.56l.796-.459a1.504 1.504 0 0 1 2.048.55l.5.865a1.502 1.502 0 0 1-.548 2.05l-.795.459a5.055 5.055 0 0 1 0 1.118l.795.46c.717.414.958 1.337.547 2.049l-.499.864a1.502 1.502 0 0 1-2.048.55l-.796-.458c-.299.22-.623.41-.968.56v.918c0 .827-.679 1.498-1.501 1.498h-.999c-.829 0-1.5-.675-1.5-1.498v-.918c-.345-.15-.67-.34-.97-.56l-.795.459a1.504 1.504 0 0 1-2.048-.55l-.5-.865a1.502 1.502 0 0 1 .548-2.05l.795-.459a5.055 5.055 0 0 1 0-1.118l-.795-.46A1.504 1.504 0 0 1 1.2 4.932l.499-.864a1.502 1.502 0 0 1 2.048-.55l.796.458c.299-.22.624-.41.969-.56v-.918c0-.827.678-1.498 1.5-1.498h.999c.829 0 1.5.675 1.5 1.498v.918z"/>
+    <path d="M7.5 9a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm0 1a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"/>
 </svg>
--- a/devtools/client/themes/images/tool-profiler.svg
+++ b/devtools/client/themes/images/tool-profiler.svg
@@ -1,8 +1,9 @@
 <!-- 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="16" height="16" viewBox="0 0 16 16" fill="whitesmoke">
-  <path d="M6.9 7.8c-.3.1-.6.4-.6.7-.1.5.2 1 .7 1.1.3 0 .7-.1.9-.3l2.5-2.9-3.5 1.4z"/>
-  <path opacity="0.5" d="M4.7 10.6c.7 1.1 1.9 1.9 3.3 1.9s2.6-.8 3.3-1.9H4.7z"/>
-  <path d="M7.9 2.3C4.6 2.3 1.8 5 1.8 8.5s2.7 6.3 6.3 6.3c3.5 0 6.3-2.7 6.3-6.3-.2-3.4-3-6.2-6.5-6.2zm0 11.4c-2.9 0-5.2-2.3-5.2-5.2v-.4h1.8c.2 0 .4-.3.4-.5s-.2-.5-.4-.5H2.9C3.2 5.9 4 4.8 5 4.1l1.4 1.4c.2.1.6.1.7-.1.1-.1.2-.5.1-.6L6 3.7c.6-.2 1.2-.4 1.9-.4.8 0 1.5.2 2.2.5L9 4.8c-.1.1 0 .5.1.6.1.1.5.2.6.1L11 4.3c.9.7 1.6 1.7 1.9 2.8h-1.6c-.2 0-.4.3-.4.5s.2.5.4.5h1.8v.4c0 3-2.2 5.2-5.2 5.2z"/>
+<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke" fill-rule="evenodd">
+  <path d="M15 9.004C14.51 12.394 11.578 15 8.035 15 4.15 15 1 11.866 1 8s3.15-7 7.036-7c1.941 0 3.7.783 4.972 2.048l-.709.709A6.027 6.027 0 0 0 8.036 2c-3.33 0-6.03 2.686-6.03 6s2.7 6 6.03 6a6.023 6.023 0 0 0 5.946-4.993l1.017-.003z"/>
+  <path d="M4.137 9H3.1a5.002 5.002 0 0 0 9.8 0h-.965a4.023 4.023 0 0 1-3.9 3 4.023 4.023 0 0 1-3.898-3z" fill-opacity=".5"/>
+  <path d="M8.036 11a2.994 2.994 0 0 0 2.987-3c0-1.657-1.338-3-2.987-3a2.994 2.994 0 0 0-2.988 3c0 1.657 1.338 3 2.988 3zm0-1c1.11 0 2.011-.895 2.011-2s-.9-2-2.011-2c-1.111 0-2.012.895-2.012 2s.9 2 2.012 2z"/>
+  <path d="M10.354 6.354l4-4a.5.5 0 0 0-.708-.708l-4 4a.5.5 0 1 0 .708.708z"/>
 </svg>
--- a/devtools/client/themes/images/tool-scratchpad.svg
+++ b/devtools/client/themes/images/tool-scratchpad.svg
@@ -1,7 +1,7 @@
 <!-- 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="16" height="16" viewBox="0 0 16 16" fill="whitesmoke">
-  <path d="M13.2 3h-1.3v-.8c0-.3-.3-.6-.6-.6s-.6.3-.6.6V3H7.8v-.8c0-.3-.3-.6-.6-.6s-.7.2-.7.6V3H3.7v-.8c0-.3-.3-.6-.6-.6s-.6.2-.6.6V3H.8c-.4 0-.8.4-.8.9v10.2c0 .4.3.9.8.9h12.4c.4 0 .8-.4.8-.9V3.9s-.6-.9-.8-.9zM13 14H1V3.9h12V14z"/>
-  <path d="M8.7 12.1h-6c-.3 0-.5-.2-.5-.5s.2-.5.5-.5h6c.3 0 .5.2.5.5s-.3.5-.5.5zM11.5 9.9H5.4c-.3 0-.5-.2-.5-.5s.2-.5.5-.5h6.1c.3 0 .5.2.5.5s-.2.5-.5.5zM7.7 7.8H3c-.3 0-.5-.2-.5-.5s.2-.5.5-.5h4.7c.3 0 .5.2.5.5s-.2.5-.5.5z"/>
+<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <path d="M5 1.5a.5.5 0 0 0-1 0v2a.5.5 0 0 0 1 0v-2zM8.5 3.5v-2a.5.5 0 0 0-1 0v2a.5.5 0 0 0 1 0zM12 3.5v-2a.5.5 0 1 0-1 0v2a.5.5 0 1 0 1 0zM5 7h4a.5.5 0 0 0 0-1H5a.5.5 0 0 0 0 1zM5 11h2a.5.5 0 1 0 0-1H5a.5.5 0 1 0 0 1zM6 9h5a.5.5 0 1 0 0-1H6a.5.5 0 0 0 0 1z"/>
+  <path d="M3 3.996v9.008c0-.003 0-.004.002-.004h9.996c-.001 0 .002-.003.002.004V3.996c0 .003 0 .004-.002.004H3.002C3.003 4 3 4.003 3 3.996zm-1 0C2 3.446 2.456 3 3.002 3h9.996A.998.998 0 0 1 14 3.996v9.008c0 .55-.456.996-1.002.996H3.002A.998.998 0 0 1 2 13.004V3.996z"/>
 </svg>
--- a/devtools/client/themes/images/tool-shadereditor.svg
+++ b/devtools/client/themes/images/tool-shadereditor.svg
@@ -1,14 +1,12 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="whitesmoke">
-  <path opacity="0.2" d="M2.5 3.9l11.1 8.3-11.4.1.3-8.4z"/>
-  <path d="M-8.6 9.8l-5.5-5.5c-.3-.3-.8-.3-1 0-.3.3-.3.8 0 1l5.5 5.5c.1.1.3.2.5.2s.4-.1.5-.2c.2-.3.2-.7 0-1z"/>
-  <path d="M-6 11.2V2.9c.5-.2.9-.7.9-1.3C-5.1.8-5.8.1-6.6.1-7.3.1-7.9.6-8 1.3h-8.1c-.1-.7-.7-1.2-1.4-1.2-.8 0-1.5.7-1.5 1.5 0 .6.4 1.2 1 1.4v8.2c-.6.2-1 .7-1 1.4 0 .8.7 1.5 1.5 1.5.5 0 1-.3 1.3-.7h8.5c.3.4.7.7 1.3.7.8 0 1.5-.7 1.5-1.5-.2-.6-.6-1.2-1.1-1.4zm-10-7.9h8v8h-8v-8z"/>
-  <circle cx="14.9" cy="2.6" r="1.1"/>
-  <circle cx="1.1" cy="2.6" r="1.1"/>
-  <circle cx="1.3" cy="13.5" r="1.1"/>
-  <circle cx="14.9" cy="13.2" r="1.1"/>
-  <path d="M13.4 2.9H2.6c-.4 0-.8.4-.8.9V12c0 .4.3.9.8.9h10.8c.4 0 .8-.4.8-.9V3.8c0-.7-.6-.9-.8-.9zm-.2 8.3L3.5 3.9h9.7v7.3zM2.8 4.6l9.6 7.3H2.8V4.6z"/>
-  <path opacity="0.2" d="M8.3 4.1H6.7c-.1 0-.1.1-.1.1v1.6c0 .1.1.1.1.1h1.6c.1 0 .1-.1.1-.1V4.2c.1-.1 0-.1-.1-.1zM10.6 5.8H9c-.1 0-.1.1-.1.1v1.6c0 .1.1.1.1.1h1.6c.1 0 .1-.1.1-.1V5.9c0-.1 0-.1-.1-.1zM12.7 4.2h-1.6c-.1 0-.1.1-.1.1v1.6c0 .1.1.1.1.1h1.6c.1.1.1 0 .1-.1V4.3c0-.1 0-.1-.1-.1zM12.8 7.7h-1.6c-.1 0-.1.1-.1.1v1.6c0 .1.1.1.1.1h1.6c.1.1.1.1.1 0V7.9c0-.1 0-.2-.1-.2z"/>
+<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <path d="M2 4v8h12V4H2zm0-1h12a1 1 0 0 1 1 1v8a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1z"/>
+  <circle cx="1" cy="3" r="1"/>
+  <circle cx="1" cy="13" r="1"/>
+  <circle cx="15" cy="13" r="1"/>
+  <circle cx="15" cy="3" r="1"/>
+  <path d="M1.215 3.911l13 9 .411.285.57-.822-.411-.285-13-9-.411-.285-.57.822z"/>
+  <path fill-opacity=".3" d="M8 5h2v2H8zM8 8h2v2L9 8.711zM5 5.962V5h2v2h-.828l-.729-.368zM11 5h2v2h-2zM11 8h2v2h-2z"/>
 </svg>
--- a/devtools/client/themes/images/tool-storage.svg
+++ b/devtools/client/themes/images/tool-storage.svg
@@ -1,11 +1,7 @@
 <!-- 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="16" height="16" viewBox="0 0 16 16" fill="whitesmoke">
-  <path d="M6.2 28C.3 28 .3 26.2.3 25.8V25c0-1.7 3.6-2.1 5.9-2.1s6.1.4 6.1 2.1v.8c0 .4-.2 2.2-6.1 2.2z"/>
-  <path d="M6.2 30c-6 0-5.9-2.1-5.9-2.1v1.8c0 .4 0 2.3 5.8 2.3 6 0 6.2-1.9 6.2-2.3V28s0 2-6.1 2z"/>
-  <path d="M6.2 33.7c-6 0-5.9-2.1-5.9-2.1v1.8c0 .4 0 2.3 5.8 2.3 6 0 6.2-1.9 6.2-2.3v-1.6c0-.2 0 1.8-6.1 1.9z"/>
-  <path d="M-4.1-3.1h-2.6v-1.5c0-.8-1-1.5-1.8-1.5h-2.4c-.8 0-1.8.7-1.8 1.5v1.5h-2.6c-.8 0-1.4.6-1.4 1.4v6.5c0 .8.6 1.1 1.4 1.1h11.2c.8 0 1.4-.3 1.4-1.1v-6.5c-.1-.8-.7-1.4-1.4-1.4zm.3 8h-12v-7h4v-3h4v3h3.9l.1 7z"/>
-  <path d="M-9.8-1.3c-1.3 0-2.4 1.1-2.4 2.4s1.1 2.4 2.4 2.4 2.4-1.1 2.4-2.4c0-1.3-1-2.4-2.4-2.4zm0 3.5c-.7 0-1.2-.5-1.2-1.1S-10.4 0-9.8 0s1.2.5 1.2 1.1-.5 1.1-1.2 1.1z"/>
-  <path d="M14 6.9v-3c0-2.8-10.3-2.8-10.3 0V12.3c.1 1.4 2.7 2.1 5.2 2.1s5-.7 5.1-2.1V6.9c0 .1 0 0 0 0zM4.7 5.2c1 .5 2.6.8 4.2.8s3.1-.3 4.1-.8V7c-.1.4-1.4 1-4 1-2.5 0-4.2-.6-4.3-1V5.2zm4.2-2.4c2.7 0 4.1.8 4.1 1.1S11.6 5 8.9 5c-2.7 0-4.2-.8-4.2-1.1s1.5-1.1 4.2-1.1zM4.7 8.2c1 .5 2.7.8 4.3.8 1.5 0 3-.3 4-.8v1c-.1.4-1.4 1.1-4 1.1s-4.2-.7-4.3-1.1v-1zm4.2 5.2c-2.6 0-4.1-.7-4.2-1.1v-1.9c1 .6 2.7.8 4.3.8 1.6 0 3.1-.3 4-.8v1.9c-.1.3-1.6 1.1-4.1 1.1z"/>
+<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <path d="M7.5 7.556c3.006 0 5.5-1.136 5.5-2.778C13 3.136 10.506 2 7.5 2S2 3.136 2 4.778C2 6.42 4.494 7.556 7.5 7.556zm0-1c-2.517 0-4.5-.903-4.5-1.778S4.983 3 7.5 3s4.5.903 4.5 1.778-1.983 1.778-4.5 1.778zM7.5 14.445c3.006 0 5.5-1.137 5.5-2.778 0-.878-.595-1.606-1.657-2.081-.244-.11-.473-.107-.778-.033-.056.014-.565.158-.765.205-.626.148-1.342.231-2.3.231-.973 0-1.683-.082-2.273-.225a18.574 18.574 0 0 1-.673-.193c-.277-.076-.479-.089-.707-.005l-.035.014C2.638 10.064 2 10.756 2 11.667c0 1.641 2.494 2.778 5.5 2.778zm0-1c-2.517 0-4.5-.904-4.5-1.778 0-.432.354-.816 1.194-1.163h-.002c-.012.005.003.006.097.032-.056-.016.474.144.702.2.669.162 1.458.253 2.509.253 1.035 0 1.828-.092 2.53-.257.228-.054.74-.2.77-.207a.756.756 0 0 1 .134-.027c.734.329 1.066.735 1.066 1.169 0 .874-1.983 1.778-4.5 1.778z"/>
+  <path d="M7.5 10.945c3.006 0 5.5-1.137 5.5-2.778 0-.873-.62-1.601-1.693-2.082-.244-.109-.472-.106-.773-.032-.051.013-.551.158-.75.206-.615.147-1.326.23-2.284.23-.973 0-1.68-.082-2.265-.225a17.077 17.077 0 0 1-.66-.19c-.27-.076-.467-.092-.692-.015l-.054.02C2.65 6.568 2 7.259 2 8.168c0 1.641 2.494 2.778 5.5 2.778zm0-1C4.983 9.945 3 9.04 3 8.167c0-.426.364-.813 1.21-1.163l-.003.001c-.011.004.005.005.099.032-.079-.022.465.143.69.198.665.163 1.452.254 2.504.254 1.036 0 1.825-.092 2.517-.258.228-.054.733-.2.758-.207a.766.766 0 0 1 .124-.026c.748.335 1.101.75 1.101 1.169 0 .874-1.983 1.778-4.5 1.778z"/>
 </svg>
--- a/devtools/client/themes/images/tool-styleeditor.svg
+++ b/devtools/client/themes/images/tool-styleeditor.svg
@@ -1,6 +1,6 @@
 <!-- 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="16" height="16" viewBox="0 0 16 16" fill="whitesmoke">
-  <path d="M-13 9.3h-.3c-1.6 0-2.5-.9-2.5-2.3 0-.4.1-.8.1-1.2.1-.4.2-.7.2-1.1 0-.3 0-.5-.6-.5-.3 0-.5-.2-.5-.5V3c0-.3.2-.5.5-.5.6 0 .6-.2.6-.5s-.1-.6-.1-1c-.1-.4-.2-.8-.2-1.2 0-1.4.9-2.3 2.5-2.3h.3c.3 0 .5.2.5.5v.7c0 .3-.2.5-.5.5h-.3c-.3.1-.5.1-.5.7 0 .2 0 .5.1.9 0 .3.1.7.1 1.1 0 .6-.2 1.1-.5 1.5.2.3.5.7.5 1.5 0 .3 0 .7-.1 1.1-.1.3-.1.6-.1.9 0 .6.2.7.6.7h.2c.3 0 .5.2.5.5v.7c0 .2-.2.5-.5.5zm7.1 0h-.3c-.3 0-.5-.2-.5-.5v-.7c0-.3.2-.5.5-.5h.2c.4 0 .6-.1.6-.7 0-.2 0-.4-.1-.7V6c0-.3-.1-.7-.1-1.1 0-.7.2-1.2.5-1.5-.3-.3-.5-.8-.5-1.5 0-.4.1-.7.1-1.1V.6c0-.2.1-.5.1-.7 0-.5-.1-.7-.6-.7h-.2c-.3 0-.5-.2-.5-.5V-2c0-.3.2-.5.5-.5h.3c1.5 0 2.5.8 2.5 2.3 0 .4-.1.8-.1 1.1-.1.5-.2.8-.2 1.1 0 .3 0 .5.6.5.3 0 .5.2.5.5v.7c0 .3-.2.5-.5.5-.5 0-.6.2-.6.5s0 .7.1 1 .1.8.1 1.2c.1 1.5-.8 2.4-2.4 2.4zM13.5 7.7c-.6-.1-1-.3-1.2-.6-.1-.2-.2-.5-.2-.9v-1c0-.8-.1-1.3-.4-1.7-.4-.6-1.2-1-2.2-1h-.3v1.2h.2c.5 0 .9.3 1.1.7.1.2.2.6.2 1.1V6c0 .6.1 1.1.2 1.5.2.4.4.7.8.8-.4.2-.6.5-.8.9-.2.3-.2.8-.2 1.4v.9c0 .5-.1.8-.3 1.1-.3.2-.6.4-1 .4h-.2v1.2h.3c.7-.1 1.3-.3 1.8-.6.5-.4.8-1 .8-1.9v-1.2c0-.4.1-.7.2-.9.2-.4.6-.6 1.2-.7h.2V7.8l-.2-.1zM2.8 7.5c.2-.4.2-.9.2-1.4v-.9c0-.5.1-.8.3-1.1.2-.2.5-.4.9-.4h.2V2.5h-.3c-.6.1-1.2.3-1.7.6-.5.4-.8 1.1-.8 1.9v1.2c0 .4-.1.7-.2.9-.2.4-.6.6-1.2.7H0v1.1h.2c.6.1 1 .3 1.2.6.1.2.2.5.2.9v1c0 .8.1 1.3.4 1.7.4.6 1.2 1 2.2 1h.3v-1.2h-.2c-.5 0-.9-.3-1.1-.7-.1 0-.2-.4-.2-.9v-.7c0-.6 0-1-.2-1.4-.2-.4-.4-.7-.8-.8.4-.2.6-.5.8-.9zM-2 16.6c-.4 0-.8-.1-.8-.8 0-.3.1-.7.2-1 .1-.4.2-.8.2-1.2 0-1.2-1.3-1.6-2.1-1.6-.7 0-1 .3-1 .5s.2.4.5.4h.2l.1-.2s.1-.1.3-.1c.3 0 .5.2.5.6 0 .4 0 .8-.1 1.1 0 .4-.1.8-.1 1.3 0 .6.4 1 .8 1.2-.5.2-.8.6-.8 1.2 0 .5 0 .9.1 1.3 0 .4.1.7.1 1.1 0 .3-.2.6-.5.6-.2 0-.3-.1-.3-.1l-.1-.2H-5c-.3.1-.5.2-.5.4s.3.5 1 .5c.8 0 2.1-.4 2.1-1.6 0-.4-.1-.8-.2-1.2-.1-.4-.2-.7-.2-1 0-.7.4-.8.8-.8h.5v-.7H-2z"/>
+<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke">
+  <path d="M5.5 2C3.565 2 2.806 3.12 3.065 4.587c.239 1.346.117 1.76-.435 2.39l-.054.06c-.252.288-.39.474-.523.74L1.94 8l.112.224c.132.265.27.45.523.739l.054.06c.552.63.674 1.044.435 2.39C2.802 12.904 3.527 14 5.5 14a.5.5 0 1 0 0-1c-1.291 0-1.614-.487-1.45-1.413.292-1.65.081-2.37-.669-3.223l-.053-.06c-.2-.229-.296-.357-.38-.528v.448c.084-.17.18-.299.38-.528l.053-.06c.75-.854.961-1.573.67-3.223C3.89 3.515 4.24 3 5.5 3a.5.5 0 1 0 0-1zM10.5 3c1.26 0 1.609.515 1.45 1.413-.292 1.65-.081 2.37.669 3.223l.053.06c.2.229.296.357.38.528v-.448c-.084.17-.18.299-.38.528l-.053.06c-.75.854-.961 1.573-.67 3.223.165.926-.158 1.413-1.449 1.413a.5.5 0 1 0 0 1c1.973 0 2.698-1.096 2.435-2.587-.239-1.346-.117-1.76.435-2.39l.054-.06c.252-.288.39-.474.523-.74L14.06 8l-.112-.224c-.132-.265-.27-.45-.523-.739l-.054-.06c-.552-.63-.674-1.044-.435-2.39C13.194 3.12 12.435 2 10.5 2a.5.5 0 0 0 0 1z"/>
 </svg>
--- a/devtools/client/themes/images/tool-webconsole.svg
+++ b/devtools/client/themes/images/tool-webconsole.svg
@@ -1,7 +1,7 @@
 <!-- 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="16" height="16" viewBox="0 0 16 16" fill="whitesmoke">
-  <path d="M6.8 9.3c0-.2 0-.3-.2-.4L4.9 7.2c-.3-.3-.7-.3-.9 0s-.3.6 0 .9l1.3 1.4L4 10.9c-.3.3-.3.6 0 .9s.6.3.9 0L6.7 10c.1-.2.2-.5.1-.7z"/>
-  <path d="M13.2 3H1.8c-.4 0-.8.4-.8.9v9.2s.3.9.8.9h11.4c.4 0 .8-.4.8-.9V3.9c0-.7-.6-.9-.8-.9zM13 13H2V6h11v7zm0-8H2V4h11v1z"/>
+<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="whitesmoke" fill-rule="evenodd">
+  <path d="M14 4V3H2v1h12zm0 1v8H2V5h12zM1 3.002C1 2.45 1.45 2 2.007 2h11.986A1.01 1.01 0 0 1 15 3.002v9.996C15 13.55 14.55 14 13.993 14H2.007A1.01 1.01 0 0 1 1 12.998V3.002z"/>
+  <path d="M4.09 7.859l2.062 2-.006-.713-2.061 2.062a.5.5 0 0 0 .707.707l2.062-2.061a.5.5 0 0 0-.006-.713l-2.061-2a.5.5 0 1 0-.697.718z"/>
 </svg>
--- a/devtools/client/themes/memory.css
+++ b/devtools/client/themes/memory.css
@@ -110,28 +110,26 @@ html, body, #app, #memory-tool {
 #clear-snapshots::before {
   background-image: url(chrome://devtools/skin/images/clear.svg);
 }
 
 #diff-snapshots::before {
   background-image: url(chrome://devtools/skin/images/diff.svg);
 }
 
+#import-snapshot::before {
+  background-image: url(chrome://devtools/skin/images/import.svg);
+}
+
 #record-allocation-stacks-label,
 #pop-view-button-label {
   border-inline-end: 1px solid var(--theme-splitter-color);
   padding-inline-end: 5px;
 }
 
-#import-snapshot,
-#clear-snapshots {
-  -moz-box-align: center;
-  flex-grow: 1;
-}
-
 .spacer {
   flex: 1;
 }
 
 #filter {
   align-self: stretch;
   margin: 2px;
 }
--- a/devtools/client/themes/performance.css
+++ b/devtools/client/themes/performance.css
@@ -5,26 +5,26 @@
 
 /* CSS Variables specific to this panel that aren't defined by the themes */
 .theme-dark {
   --cell-border-color: rgba(255,255,255,0.15);
   --cell-border-color-light: rgba(255,255,255,0.1);
   --focus-cell-border-color: rgba(255,255,255,0.5);
   --row-alt-background-color: rgba(86, 117, 185, 0.15);
   --row-hover-background-color: rgba(86, 117, 185, 0.25);
-  --filter-image: url(chrome://devtools/skin/images/timeline-filter.svg);
+  --filter-image: url(chrome://devtools/skin/images/filter.svg);
 }
 
 .theme-light {
   --cell-border-color: rgba(0,0,0,0.15);
   --cell-border-color-light: rgba(0,0,0,0.1);
   --focus-cell-border-color: rgba(0,0,0,0.3);
   --row-alt-background-color: rgba(76,158,217,0.1);
   --row-hover-background-color: rgba(76,158,217,0.2);
-  --filter-image: url(chrome://devtools/skin/images/timeline-filter.svg);
+  --filter-image: url(chrome://devtools/skin/images/filter.svg);
 }
 
 .theme-firebug {
   --cell-border-color: rgba(0,0,0,0.15);
   --cell-border-color-light: rgba(0,0,0,0.1);
   --focus-cell-border-color: rgba(0,0,0,0.3);
   --row-alt-background-color: rgba(76,158,217,0.1);
   --row-hover-background-color: rgba(76,158,217,0.2);
@@ -86,21 +86,25 @@
 }
 
 /* Recording buttons */
 
 #main-record-button {
   list-style-image: url(images/profiler-stopwatch.svg);
 }
 
-#main-record-button .button-icon {
+#import-button {
+  list-style-image: url(images/import.svg);
+}
+
+#main-record-button .button-icon, #import-button .button-icon {
   margin: 0;
 }
 
-#main-record-button .button-text {
+#main-record-button .button-text, #import-button .button-text {
   display: none;
 }
 
 .notice-container .record-button {
   padding: 5px !important;
 }
 
 .notice-container .record-button[checked],
--- a/devtools/client/themes/styleeditor.css
+++ b/devtools/client/themes/styleeditor.css
@@ -1,13 +1,21 @@
 /* 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/. */
 
+.style-editor-newButton {
+  list-style-image: url(images/add.svg);
+}
+
+.style-editor-importButton {
+  list-style-image: url(images/import.svg);
+}
+
 .stylesheet-title,
 .stylesheet-name {
   text-decoration: none;
 }
 
 .stylesheet-name {
   font-size: 13px;
 }
@@ -95,33 +103,27 @@
 
 .media-condition-unmatched {
   opacity: 0.4;
 }
 
 .stylesheet-enabled {
   padding: 8px 0;
   margin: 0 8px;
-  background-image: url(images/itemToggle.png);
+  background-image: url(images/itemToggle.svg);
   background-repeat: no-repeat;
   background-clip: content-box;
-  background-position: 0 8px;
-  background-size: 48px 24px;
+  background-position: center;
+  background-size: 16px;
   width: 24px;
   height: 40px;
 }
 
-@media (min-resolution: 1.1dppx) {
-  .stylesheet-enabled {
-    background-image: url(images/itemToggle@2x.png);
-  }
-}
-
 .disabled > .stylesheet-enabled {
-  background-position: -24px 8px;
+  opacity: 0.3;
 }
 
 /* Invert all toggle icons but the one in the active row for light theme */
 .theme-light .splitview-nav > li:not(.splitview-active) .stylesheet-enabled {
   filter: invert(1);
 }
 
 .splitview-nav > li > .stylesheet-enabled:focus,
--- a/devtools/client/themes/toolbars.css
+++ b/devtools/client/themes/toolbars.css
@@ -748,74 +748,16 @@
 }
 
 .command-button:hover:active::before,
 .command-button[checked=true]::before,
 .command-button[open=true]::before {
   opacity: 1;
 }
 
-/* Toolbox command buttons */
-
-#command-button-paintflashing::before {
-  background-image: var(--command-paintflashing-image);
-}
-
-#command-button-screenshot::before {
-  background-image: var(--command-screenshot-image);
-}
-
-#command-button-responsive::before {
-  background-image: var(--command-responsive-image);
-}
-
-#command-button-scratchpad::before {
-  background-image: var(--command-scratchpad-image);
-}
-
-#command-button-pick::before {
-  background-image: var(--command-pick-image);
-}
-
-#command-button-splitconsole::before {
-  background-image: var(--command-splitconsole-image);
-}
-
-#command-button-noautohide::before {
-  background-image: var(--command-noautohide-image);
-}
-
-#command-button-eyedropper::before {
-  background-image: var(--command-eyedropper-image);
-}
-
-#command-button-rulers::before {
-  background-image: var(--command-rulers-image);
-}
-
-#command-button-measure::before {
-  background-image: var(--command-measure-image);
-}
-
-#command-button-frames::before {
-  background-image: var(--command-frames-image);
-}
-
-#command-button-frames {
-  background: url("chrome://devtools/skin/images/dropmarker.svg") no-repeat right;
-
-  /* Override background-size from the command-button.
-    The drop down arrow is smaller */
-  background-size: 8px 4px !important;
-}
-
-#command-button-frames:-moz-dir(rtl) {
-  background-position: left;
-}
-
 /* Tabs */
 
 .devtools-tabbar {
   -moz-appearance: none;
   min-height: 24px;
   border: 0px solid;
   border-bottom-width: 1px;
   padding: 0;
new file mode 100644
--- /dev/null
+++ b/devtools/client/themes/toolbox.css
@@ -0,0 +1,63 @@
+/* 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/. */
+
+ /* Toolbox command buttons */
+
+#command-button-paintflashing::before {
+   background-image: var(--command-paintflashing-image);
+ }
+
+#command-button-screenshot::before {
+   background-image: var(--command-screenshot-image);
+ }
+
+#command-button-responsive::before {
+ background-image: var(--command-responsive-image);
+}
+
+#command-button-scratchpad::before {
+ background-image: var(--command-scratchpad-image);
+}
+
+#command-button-pick::before {
+ background-image: var(--command-pick-image);
+}
+
+#command-button-splitconsole::before {
+ background-image: var(--command-splitconsole-image);
+}
+
+#command-button-noautohide::before {
+ background-image: var(--command-noautohide-image);
+}
+
+#command-button-eyedropper::before {
+ background-image: var(--command-eyedropper-image);
+}
+
+#command-button-rulers::before {
+ background-image: var(--command-rulers-image);
+}
+
+#command-button-measure::before {
+ background-image: var(--command-measure-image);
+}
+
+#command-button-frames::before {
+ background-image: var(--command-frames-image);
+}
+
+#command-button-frames {
+ background: url("chrome://devtools/skin/images/dropmarker.svg") no-repeat right;
+
+ /* Override background-size from the command-button.
+   The drop down arrow is smaller */
+ background-size: 8px 4px !important;
+ min-width: 32px;
+}
+
+#command-button-frames:-moz-dir(rtl) {
+ background-position: left;
+}
--- a/devtools/shared/css-lexer.js
+++ b/devtools/shared/css-lexer.js
@@ -1068,16 +1068,19 @@ Scanner.prototype = {
     aToken.mIdent.length = 0;
 
     let ch = this.Peek();
     // Do we have a string?
     if (ch == QUOTATION_MARK || ch == APOSTROPHE) {
       this.ScanString(aToken);
       if (aToken.mType == eCSSToken_Bad_String) {
         aToken.mType = eCSSToken_Bad_URL;
+        // Flag us as having been a Bad_String.
+        aToken.mInteger2 = 1;
+        this.ConsumeBadURLRemnants(aToken);
         return;
       }
     } else {
       // Otherwise, this is the start of a non-quoted url (which may be empty).
       aToken.mSymbol = 0;
       this.GatherText(IS_URL_CHAR, aToken.mIdent);
     }
 
@@ -1088,19 +1091,54 @@ Scanner.prototype = {
     if (ch < 0 || ch == RIGHT_PARENTHESIS) {
       this.Advance();
       aToken.mType = eCSSToken_URL;
       if (ch < 0) {
         this.AddEOFCharacters(eEOFCharacters_CloseParen);
       }
     } else {
       aToken.mType = eCSSToken_Bad_URL;
+      if (aToken.mSymbol != 0) {
+        // Flag us as having been a String, not a Bad_String.
+        aToken.mInteger2 = 0;
+      }
+      this.ConsumeBadURLRemnants(aToken);
     }
   },
 
+  ConsumeBadURLRemnants: function (aToken) {
+    aToken.mInteger = aToken.mIdent.length;
+    let ch = this.Peek();
+    do {
+      if (ch < 0) {
+        this.AddEOFCharacters(eEOFCharacters_CloseParen);
+        break;
+      }
+
+      if (ch == REVERSE_SOLIDUS && this.GatherEscape(aToken.mIdent, false)) {
+        // Nothing else needs to be done here for the moment; we've consumed the
+        // backslash and following escape.
+      } else {
+        // We always want to consume this character.
+        if (IsVertSpace(ch)) {
+          this.AdvanceLine();
+        } else {
+          this.Advance();
+        }
+        if (ch == 0) {
+          aToken.mIdent.push(UCS2_REPLACEMENT_CHAR);
+        } else {
+          aToken.mIdent.push(ch);
+        }
+      }
+
+      ch = this.Peek();
+    } while (ch != RIGHT_PARENTHESIS);
+  },
+
   /**
    * Primary scanner entry point.  Consume one token and fill in
    * |aToken| accordingly.  Will skip over any number of comments first,
    * and will also skip over rather than return whitespace and comment
    * tokens, depending on the value of |aSkip|.
    *
    * Returns true if it successfully consumed a token, false if EOF has
    * been reached.  Will always advance the current read position by at
--- a/devtools/shared/tests/unit/test_csslexer.js
+++ b/devtools/shared/tests/unit/test_csslexer.js
@@ -123,18 +123,19 @@ var LEX_TESTS = [
   ["23px", ["dimension:px"]],
   ["23%", ["percentage"]],
   ["url(http://example.com)", ["url:http://example.com"]],
   ["url('http://example.com')", ["url:http://example.com"]],
   ["url(  'http://example.com'  )",
              ["url:http://example.com"]],
   // In CSS Level 3, this is an ordinary URL, not a BAD_URL.
   ["url(http://example.com", ["url:http://example.com"]],
-  // See bug 1153981 to understand why this gets a SYMBOL token.
-  ["url(http://example.com @", ["bad_url:http://example.com", "symbol:@"]],
+  // We end up losing the whitespace before the '@' because it's skipped by the
+  // lexer before we discover we have a BAD_URL token.
+  ["url(http://example.com @", ["bad_url:http://example.com@"]],
   ["quo\\ting", ["ident:quoting"]],
   ["'bad string\n", ["bad_string:bad string", "whitespace"]],
   ["~=", ["includes"]],
   ["|=", ["dashmatch"]],
   ["^=", ["beginsmatch"]],
   ["$=", ["endsmatch"]],
   ["*=", ["containsmatch"]],
 
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -1942,18 +1942,17 @@ WebGLContext::DidRefresh()
     if (gl) {
         gl->FlushIfHeavyGLCallsSinceLastFlush();
     }
 }
 
 bool
 WebGLContext::ValidateCurFBForRead(const char* funcName,
                                    const webgl::FormatUsageInfo** const out_format,
-                                   uint32_t* const out_width, uint32_t* const out_height,
-                                   GLenum* const out_mode)
+                                   uint32_t* const out_width, uint32_t* const out_height)
 {
     if (!mBoundReadFramebuffer) {
         const GLenum readBufferMode = gl->Screen()->GetReadBufferMode();
         if (readBufferMode == LOCAL_GL_NONE) {
             ErrorInvalidOperation("%s: Can't read from backbuffer when readBuffer mode is"
                                   " NONE.",
                                   funcName);
             return false;
@@ -1967,22 +1966,21 @@ WebGLContext::ValidateCurFBForRead(const
         auto effFormat = mOptions.alpha ? webgl::EffectiveFormat::RGBA8
                                         : webgl::EffectiveFormat::RGB8;
 
         *out_format = mFormatUsage->GetUsage(effFormat);
         MOZ_ASSERT(*out_format);
 
         *out_width = mWidth;
         *out_height = mHeight;
-        *out_mode = gl->Screen()->GetReadBufferMode();
         return true;
     }
 
     return mBoundReadFramebuffer->ValidateForRead(funcName, out_format, out_width,
-                                                  out_height, out_mode);
+                                                  out_height);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
 WebGLContext::ScopedMaskWorkaround::ScopedMaskWorkaround(WebGLContext& webgl)
     : mWebGL(webgl)
     , mFakeNoAlpha(ShouldFakeNoAlpha(webgl))
     , mFakeNoDepth(ShouldFakeNoDepth(webgl))
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -1310,18 +1310,17 @@ protected:
                                       WebGLTexDimensions dims);
 
     bool ValidateUniformLocationForProgram(WebGLUniformLocation* location,
                                            WebGLProgram* program,
                                            const char* funcName);
 
     bool ValidateCurFBForRead(const char* funcName,
                               const webgl::FormatUsageInfo** const out_format,
-                              uint32_t* const out_width, uint32_t* const out_height,
-                              GLenum* const out_mode);
+                              uint32_t* const out_width, uint32_t* const out_height);
 
     void Invalidate();
     void DestroyResourcesAndContext();
 
     void MakeContextCurrent() const;
 
     // helpers
 
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -1593,18 +1593,17 @@ WebGLContext::ReadPixels(GLint x, GLint 
 
     //////
 
     MakeContextCurrent();
 
     const webgl::FormatUsageInfo* srcFormat;
     uint32_t srcWidth;
     uint32_t srcHeight;
-    GLenum srcMode;
-    if (!ValidateCurFBForRead("readPixels", &srcFormat, &srcWidth, &srcHeight, &srcMode))
+    if (!ValidateCurFBForRead("readPixels", &srcFormat, &srcWidth, &srcHeight))
         return;
 
     // Check the format and type params to assure they are an acceptable pair (as per spec)
     auto srcType = srcFormat->format->componentType;
     GLenum mainReadFormat;
     GLenum mainReadType;
     switch (srcType) {
         case webgl::ComponentType::Float:
--- a/dom/canvas/WebGLContextState.cpp
+++ b/dom/canvas/WebGLContextState.cpp
@@ -377,34 +377,32 @@ WebGLContext::GetParameter(JSContext* cx
         case LOCAL_GL_GENERATE_MIPMAP_HINT: {
             GLint i = 0;
             gl->fGetIntegerv(pname, &i);
             return JS::NumberValue(uint32_t(i));
         }
         case LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE: {
             const webgl::FormatUsageInfo* usage;
             uint32_t width, height;
-            GLenum mode;
-            if (!ValidateCurFBForRead(funcName, &usage, &width, &height, &mode))
+            if (!ValidateCurFBForRead(funcName, &usage, &width, &height))
                 return JS::NullValue();
 
             GLint i = 0;
             if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) {
                 gl->fGetIntegerv(pname, &i);
             } else {
                 i = LOCAL_GL_UNSIGNED_BYTE;
             }
 
             return JS::NumberValue(uint32_t(i));
         }
         case LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT: {
             const webgl::FormatUsageInfo* usage;
             uint32_t width, height;
-            GLenum mode;
-            if (!ValidateCurFBForRead(funcName, &usage, &width, &height, &mode))
+            if (!ValidateCurFBForRead(funcName, &usage, &width, &height))
                 return JS::NullValue();
 
             GLint i = 0;
             if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) {
                 gl->fGetIntegerv(pname, &i);
             } else {
                 i = LOCAL_GL_RGBA;
             }
--- a/dom/canvas/WebGLFramebuffer.cpp
+++ b/dom/canvas/WebGLFramebuffer.cpp
@@ -1197,36 +1197,34 @@ WebGLFramebuffer::FinalizeAttachments() 
     }
 
     FinalizeDrawAndReadBuffers(gl, mColorAttachment0.IsDefined());
 }
 
 bool
 WebGLFramebuffer::ValidateForRead(const char* funcName,
                                   const webgl::FormatUsageInfo** const out_format,
-                                  uint32_t* const out_width, uint32_t* const out_height,
-                                  GLenum* const out_mode)
+                                  uint32_t* const out_width, uint32_t* const out_height)
 {
     if (!ValidateAndInitAttachments(funcName))
         return false;
 
     if (mReadBufferMode == LOCAL_GL_NONE) {
-        mContext->ErrorInvalidOperation("%s: Read buffer mode must not be"
-                                        " NONE.", funcName);
+        mContext->ErrorInvalidOperation("%s: Read buffer mode must not be NONE.",
+                                        funcName);
         return false;
     }
 
     const auto attachPoint = GetAttachPoint(mReadBufferMode);
     if (!attachPoint || !attachPoint->IsDefined()) {
         mContext->ErrorInvalidOperation("%s: The attachment specified for reading is"
                                         " null.", funcName);
         return false;
     }
 
-    *out_mode = mReadBufferMode;
     *out_format = attachPoint->Format();
     attachPoint->Size(out_width, out_height);
     return true;
 }
 
 static bool
 AttachmentsDontMatch(const WebGLFBAttachPoint& a, const WebGLFBAttachPoint& b)
 {
--- a/dom/canvas/WebGLFramebuffer.h
+++ b/dom/canvas/WebGLFramebuffer.h
@@ -281,18 +281,17 @@ public:
     bool ValidateAndInitAttachments(const char* funcName);
 
     void InvalidateFramebufferStatus() const {
         mIsKnownFBComplete = false;
     }
 
     bool ValidateForRead(const char* info,
                          const webgl::FormatUsageInfo** const out_format,
-                         uint32_t* const out_width, uint32_t* const out_height,
-                         GLenum* const out_mode);
+                         uint32_t* const out_width, uint32_t* const out_height);
 
     JS::Value GetAttachmentParameter(const char* funcName, JSContext* cx, GLenum target,
                                      GLenum attachment, GLenum pname,
                                      ErrorResult* const out_error);
 };
 
 } // namespace mozilla
 
--- a/dom/canvas/WebGLTexture.h
+++ b/dom/canvas/WebGLTexture.h
@@ -247,16 +247,17 @@ protected:
                                        GLint level, uint32_t width, uint32_t height,
                                        uint32_t depth,
                                        WebGLTexture::ImageInfo** const out_imageInfo);
     bool ValidateTexImageSelection(const char* funcName, TexImageTarget target,
                                    GLint level, GLint xOffset, GLint yOffset,
                                    GLint zOffset, uint32_t width, uint32_t height,
                                    uint32_t depth,
                                    WebGLTexture::ImageInfo** const out_imageInfo);
+    bool ValidateCopyTexImageForFeedback(const char* funcName, uint32_t level) const;
 
     bool ValidateUnpack(const char* funcName, const webgl::TexUnpackBlob* blob,
                         bool isFunc3D, const webgl::PackingInfo& srcPI) const;
 public:
     void TexStorage(const char* funcName, TexTarget target, GLsizei levels,
                     GLenum sizedFormat, GLsizei width, GLsizei height, GLsizei depth);
 protected:
     void TexImage(const char* funcName, TexImageTarget target, GLint level,
--- a/dom/canvas/WebGLTextureUpload.cpp
+++ b/dom/canvas/WebGLTextureUpload.cpp
@@ -1908,23 +1908,48 @@ ValidateCopyDestUsage(const char* funcNa
                                      " dest: %s)",
                                      funcName, srcFormat->name, dstFormat->name);
         return nullptr;
     }
 
     return dstUsage;
 }
 
+bool
+WebGLTexture::ValidateCopyTexImageForFeedback(const char* funcName, uint32_t level) const
+{
+    const auto& fb = mContext->mBoundReadFramebuffer;
+    if (fb) {
+        const auto readBuffer = fb->ReadBufferMode();
+        MOZ_ASSERT(readBuffer != LOCAL_GL_NONE);
+        const uint32_t colorAttachment = readBuffer - LOCAL_GL_COLOR_ATTACHMENT0;
+        const auto& attach = fb->ColorAttachment(colorAttachment);
+
+        if (attach.Texture() == this &&
+            uint32_t(attach.MipLevel()) == level)
+        {
+            // Note that the TexImageTargets *don't* have to match for this to be
+            // undefined per GLES 3.0.4 p211, thus an INVALID_OP in WebGL.
+            mContext->ErrorInvalidOperation("%s: Feedback loop detected, as this texture"
+                                            " is already attached to READ_FRAMEBUFFER's"
+                                            " READ_BUFFER-selected COLOR_ATTACHMENT%u.",
+                                            funcName, colorAttachment);
+            return false;
+        }
+    }
+    return true;
+}
+
 // There is no CopyTexImage3D.
 void
 WebGLTexture::CopyTexImage2D(TexImageTarget target, GLint level, GLenum internalFormat,
                              GLint x, GLint y, GLsizei rawWidth, GLsizei rawHeight,
                              GLint border)
 {
-    const char funcName[] = "CopyTexImage2D";
+    const char funcName[] = "copyTexImage2D";
 
     ////////////////////////////////////
     // Get dest info
 
     uint32_t width, height, depth;
     if (!ValidateExtents(mContext, funcName, rawWidth, rawHeight, 1, border, &width,
                          &height, &depth))
     {
@@ -1940,30 +1965,22 @@ WebGLTexture::CopyTexImage2D(TexImageTar
     MOZ_ASSERT(imageInfo);
 
     ////////////////////////////////////
     // Get source info
 
     const webgl::FormatUsageInfo* srcUsage;
     uint32_t srcWidth;
     uint32_t srcHeight;
-    GLenum srcMode;
-    if (!mContext->ValidateCurFBForRead(funcName, &srcUsage, &srcWidth, &srcHeight,
-                                        &srcMode))
+    if (!mContext->ValidateCurFBForRead(funcName, &srcUsage, &srcWidth, &srcHeight))
         return;
     auto srcFormat = srcUsage->format;
 
-    // GLES 3.0.4 p145:
-    // "Calling CopyTexSubImage3D, CopyTexImage2D, or CopyTexSubImage2D will result in an
-    //  INVALID_OPERATION error if any of the following conditions is true: READ_BUFFER
-    //  is NONE"
-    if (srcMode == LOCAL_GL_NONE) {
-        mContext->ErrorInvalidOperation("%s: READ_BUFFER is NONE. ", funcName);
+    if (!ValidateCopyTexImageForFeedback(funcName, level))
         return;
-    }
 
     ////////////////////////////////////
     // Check that source and dest info are compatible
 
     const auto dstUsage = ValidateCopyDestUsage(funcName, mContext, srcFormat,
                                                 internalFormat);
     if (!dstUsage)
         return;
@@ -2081,30 +2098,22 @@ WebGLTexture::CopyTexSubImage(const char
     }
 
     ////////////////////////////////////
     // Get source info
 
     const webgl::FormatUsageInfo* srcUsage;
     uint32_t srcWidth;
     uint32_t srcHeight;
-    GLenum srcMode;
-    if (!mContext->ValidateCurFBForRead(funcName, &srcUsage, &srcWidth, &srcHeight,
-                                        &srcMode))
+    if (!mContext->ValidateCurFBForRead(funcName, &srcUsage, &srcWidth, &srcHeight))
         return;
     auto srcFormat = srcUsage->format;
 
-    // GLES 3.0.4 p145:
-    // "Calling CopyTexSubImage3D, CopyTexImage2D, or CopyTexSubImage2D will result in an
-    //  INVALID_OPERATION error if any of the following conditions is true: READ_BUFFER
-    //  is NONE"
-    if (srcMode == LOCAL_GL_NONE) {
-        mContext->ErrorInvalidOperation("%s: READ_BUFFER is NONE. ", funcName);
+    if (!ValidateCopyTexImageForFeedback(funcName, level))
         return;
-    }
 
     ////////////////////////////////////
     // Check that source and dest info are compatible
 
     if (!ValidateCopyTexImageFormats(mContext, funcName, srcFormat, dstFormat))
         return;
 
     ////////////////////////////////////
--- a/dom/canvas/test/webgl-conf/generated-mochitest.ini
+++ b/dom/canvas/test/webgl-conf/generated-mochitest.ini
@@ -3132,17 +3132,16 @@ skip-if = (os == 'android') || (os == 'l
 [generated/test_conformance__textures__tex-sub-image-2d.html]
 [generated/test_conformance__textures__texparameter-test.html]
 [generated/test_conformance__textures__texture-active-bind-2.html]
 [generated/test_conformance__textures__texture-active-bind.html]
 [generated/test_conformance__textures__texture-attachment-formats.html]
 [generated/test_conformance__textures__texture-clear.html]
 [generated/test_conformance__textures__texture-complete.html]
 [generated/test_conformance__textures__texture-copying-feedback-loops.html]
-fail-if = 1
 [generated/test_conformance__textures__texture-draw-with-2d-and-cube.html]
 [generated/test_conformance__textures__texture-fakeblack.html]
 [generated/test_conformance__textures__texture-formats-test.html]
 [generated/test_conformance__textures__texture-hd-dpi.html]
 [generated/test_conformance__textures__texture-mips.html]
 skip-if = (os == 'android' && debug)
 fail-if = (os == 'android')
 [generated/test_conformance__textures__texture-npot-video.html]
--- a/dom/canvas/test/webgl-conf/mochitest-errata.ini
+++ b/dom/canvas/test/webgl-conf/mochitest-errata.ini
@@ -34,18 +34,16 @@ skip-if = os == 'b2g' || ((os == 'linux'
 fail-if = 1
 [generated/test_conformance__context__context-lost.html]
 fail-if = 1
 [generated/test_conformance__glsl__misc__shaders-with-invariance.html]
 fail-if = 1
 [generated/test_conformance__glsl__misc__shaders-with-name-conflicts.html]
 [generated/test_conformance__renderbuffers__feedback-loop.html]
 fail-if = 1
-[generated/test_conformance__textures__texture-copying-feedback-loops.html]
-fail-if = 1
 
 ####################
 # Tests requesting non-local network connections.
 
 [generated/test_conformance__more__functions__readPixelsBadArgs.html]
 # (TODO) FATAL ERROR: Non-local network connections are disabled and a connection attempt to www.opengl.org (45.55.206.190) was made.
 skip-if = 1
 
--- a/dom/media/tests/mochitest/mochitest.ini
+++ b/dom/media/tests/mochitest/mochitest.ini
@@ -161,16 +161,18 @@ skip-if = toolkit == 'gonk' # B2G emulat
 skip-if = toolkit == 'gonk' # B2G emulator is too slow to handle a two-way audio call reliably
 [test_peerConnection_offerRequiresReceiveAudio.html]
 [test_peerConnection_offerRequiresReceiveVideo.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_offerRequiresReceiveVideoAudio.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
 [test_peerConnection_promiseSendOnly.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
+[test_peerConnection_renderAfterRenegotiation.html]
+skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
 [test_peerConnection_restartIce.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version # b2g (Bug 1059867)
 [test_peerConnection_restartIceNoBundle.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version # b2g (Bug 1059867)
 [test_peerConnection_restartIceNoBundleNoRtcpMux.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version # b2g (Bug 1059867)
 [test_peerConnection_restartIceNoRtcpMux.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version # b2g (Bug 1059867)
copy from dom/media/tests/mochitest/test_peerConnection_promiseSendOnly.html
copy to dom/media/tests/mochitest/test_peerConnection_renderAfterRenegotiation.html
--- a/dom/media/tests/mochitest/test_peerConnection_promiseSendOnly.html
+++ b/dom/media/tests/mochitest/test_peerConnection_renderAfterRenegotiation.html
@@ -1,63 +1,85 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <script type="application/javascript" src="pc.js"></script>
+  <script type="application/javascript" src="/tests/dom/canvas/test/captureStream_common.js"></script>
 </head>
 <body>
 <pre id="test">
 <script type="application/javascript;version=1.8">
   createHTML({
-    bug: "1091898",
-    title: "PeerConnection with promises (sendonly)",
+    bug: "1273652",
+    title: "Video receiver still renders after renegotiation",
     visible: true
   });
 
   var pc1 = new RTCPeerConnection();
   var pc2 = new RTCPeerConnection();
 
   var add = (pc, can, failed) => can && pc.addIceCandidate(can).catch(failed);
   pc1.onicecandidate = e => add(pc2, e.candidate, generateErrorCallback());
   pc2.onicecandidate = e => add(pc1, e.candidate, generateErrorCallback());
 
   var v1, v2;
   var delivered = new Promise(resolve => pc2.ontrack = e => {
     // Test RTCTrackEvent here.
     ok(e.streams.length > 0, "has streams");
     ok(e.streams[0].getTrackById(e.track.id), "has track");
     ok(pc2.getReceivers().some(receiver => receiver == e.receiver), "has receiver");
-    if (e.streams[0].getTracks().length == 2) {
+    if (e.streams[0].getTracks().length == 1) {
       // Test RTCTrackEvent required args here.
       mustThrowWith("RTCTrackEvent wo/required args",
                     "TypeError", () => new RTCTrackEvent("track", {}));
       v2.srcObject = e.streams[0];
       resolve();
     }
   });
 
   runNetworkTest(function() {
-    v1 = createMediaElement('video', 'v1');
+    var h = new CaptureStreamTestHelper2D();
+    var canvas = document.createElement('canvas');
+    canvas.id = 'source_canvas';
+    canvas.width = canvas.height = 10;
+    document.getElementById('content').appendChild(canvas);
+
     v2 = createMediaElement('video', 'v2');
-    var canPlayThrough = new Promise(resolve => v2.canplaythrough = e => resolve());
-
     is(v2.currentTime, 0, "v2.currentTime is zero at outset");
 
-    navigator.mediaDevices.getUserMedia({ video: true, audio: true })
-    .then(stream => (v1.srcObject = stream).getTracks().forEach(t => pc1.addTrack(t, stream)))
-    .then(() => pc1.createOffer({})) // check that createOffer accepts arg.
+    h.drawColor(canvas, h.blue);
+    var stream = canvas.captureStream(0);
+    stream.getTracks().forEach(t => pc1.addTrack(t, stream));
+
+    pc1.createOffer({})
     .then(offer => pc1.setLocalDescription(offer))
     .then(() => pc2.setRemoteDescription(pc1.localDescription))
     .then(() => pc2.createAnswer({}))  // check that createAnswer accepts arg.
     .then(answer => pc2.setLocalDescription(answer))
     .then(() => pc1.setRemoteDescription(pc2.localDescription))
+
+    // re-negotiate to trigger the race condition in the jitter buffer
+    .then(() => pc1.createOffer({})) // check that createOffer accepts arg.
+    .then(offer => pc1.setLocalDescription(offer))
+    .then(() => pc2.setRemoteDescription(pc1.localDescription))
+    .then(() => pc2.createAnswer({}))
+    .then(answer => pc2.setLocalDescription(answer))
+    .then(() => pc1.setRemoteDescription(pc2.localDescription))
     .then(() => delivered)
-//    .then(() => canPlayThrough)    // why doesn't this fire?
-    .then(() => waitUntil(() => v2.currentTime > 0 && v2.srcObject.currentTime > 0))
-    .then(() => ok(v2.currentTime > 0, "v2.currentTime is moving (" + v2.currentTime + ")"))
-    .then(() => ok(true, "Connected."))
+
+    // now verify that actually something gets rendered into the remote video
+    // element
+    .then(() => h.waitForPixelColor(v2, h.blue, 128,
+                                    "pcRemote's video should become green"))
+    .then(() => {
+      stream.requestFrame();
+      h.drawColor(canvas, h.red);
+      })
+    .then(() => h.waitForPixelColor(v2, h.red, 128,
+                                    "pcRemote's video should become green"))
+
     .catch(reason => ok(false, "unexpected failure: " + reason))
     .then(networkTestFinished);
   });
 </script>
 </pre>
 </body>
 </html>
--- a/dom/webidl/CSSLexer.webidl
+++ b/dom/webidl/CSSLexer.webidl
@@ -31,18 +31,20 @@ enum CSSTokenType {
   // A string.
   "string",
   // A "bad string".  This can only be returned when a string is
   // unterminated at EOF.  (However, currently the lexer returns
   // ordinary STRING tokens in this situation.)
   "bad_string",
   // A URL.  |text| holds the URL.
   "url",
-  // A "bad URL".  This is a URL that is unterminated at EOF.  |text|
-  // holds the URL.
+  // A "bad URL".  This is a URL that either contains a bad_string or contains
+  // garbage after the string or unquoted URL test.  |text| holds the URL and
+  // potentially whatever garbage came after it, up to but not including the
+  // following ')'.
   "bad_url",
   // A "symbol" is any one-character symbol.  This corresponds to the
   // DELIM token in the CSS specification.
   "symbol",
   // The "~=" token.
   "includes",
   // The "|=" token.
   "dashmatch",
--- a/ipc/glue/MessageChannel.cpp
+++ b/ipc/glue/MessageChannel.cpp
@@ -2068,20 +2068,23 @@ MessageChannel::NotifyMaybeChannelError(
     if (ChannelClosing == mChannelState) {
         // the channel closed, but we received a "Goodbye" message warning us
         // about it. no worries
         mChannelState = ChannelClosed;
         NotifyChannelClosed();
         return;
     }
 
+    Clear();
+
     // Oops, error!  Let the listener know about it.
     mChannelState = ChannelError;
+
+    // After this, the channel may be deleted.
     mListener->OnChannelError();
-    Clear();
 }
 
 void
 MessageChannel::OnNotifyMaybeChannelError()
 {
     AssertWorkerThread();
     mMonitor->AssertNotCurrentThreadOwns();
 
@@ -2223,21 +2226,22 @@ MessageChannel::Close()
 void
 MessageChannel::NotifyChannelClosed()
 {
     mMonitor->AssertNotCurrentThreadOwns();
 
     if (ChannelClosed != mChannelState)
         NS_RUNTIMEABORT("channel should have been closed!");
 
+    Clear();
+
     // OK, the IO thread just closed the channel normally.  Let the
-    // listener know about it.
+    // listener know about it. After this point the channel may be
+    // deleted.
     mListener->OnChannelClose();
-
-    Clear();
 }
 
 void
 MessageChannel::DebugAbort(const char* file, int line, const char* cond,
                            const char* why,
                            bool reply)
 {
     printf_stderr("###!!! [MessageChannel][%s][%s:%d] "
--- a/ipc/ipdl/ipdl/lower.py
+++ b/ipc/ipdl/ipdl/lower.py
@@ -3238,16 +3238,17 @@ class _GenerateProtocolActorCode(ipdl.as
             makeHandlerMethod('OnCallReceived', self.interruptSwitch,
                               hasReply=1, dispatches=dispatches),
             Whitespace.NL
         ])
 
         destroysubtreevar = ExprVar('DestroySubtree')
         deallocsubtreevar = ExprVar('DeallocSubtree')
         deallocshmemvar = ExprVar('DeallocShmems')
+        deallocselfvar = ExprVar('Dealloc' + _actorName(ptype.name(), self.side))
 
         # OnProcesingError(code)
         codevar = ExprVar('aCode')
         reasonvar = ExprVar('aReason')
         onprocessingerror = MethodDefn(
             MethodDecl('OnProcessingError',
                        params=[ Param(_Result.Type(), codevar.name),
                                 Param(Type('char', const=1, ptr=1), reasonvar.name) ]))
@@ -3316,31 +3317,33 @@ class _GenerateProtocolActorCode(ipdl.as
 
         # OnChannelClose()
         onclose = MethodDefn(MethodDecl('OnChannelClose'))
         if ptype.isToplevel():
             onclose.addstmts([
                 StmtExpr(ExprCall(destroysubtreevar,
                                   args=[ _DestroyReason.NormalShutdown ])),
                 StmtExpr(ExprCall(deallocsubtreevar)),
-                StmtExpr(ExprCall(deallocshmemvar))
+                StmtExpr(ExprCall(deallocshmemvar)),
+                StmtExpr(ExprCall(deallocselfvar))
             ])
         else:
             onclose.addstmt(
                 _fatalError("`OnClose' called on non-toplevel actor"))
         self.cls.addstmts([ onclose, Whitespace.NL ])
 
         # OnChannelError()
         onerror = MethodDefn(MethodDecl('OnChannelError'))
         if ptype.isToplevel():
             onerror.addstmts([
                 StmtExpr(ExprCall(destroysubtreevar,
                                   args=[ _DestroyReason.AbnormalShutdown ])),
                 StmtExpr(ExprCall(deallocsubtreevar)),
-                StmtExpr(ExprCall(deallocshmemvar))
+                StmtExpr(ExprCall(deallocshmemvar)),
+                StmtExpr(ExprCall(deallocselfvar))
             ])
         else:
             onerror.addstmt(
                 _fatalError("`OnError' called on non-toplevel actor"))
         self.cls.addstmts([ onerror, Whitespace.NL ])
 
         # OnChannelConnected()
         onconnected = MethodDefn(MethodDecl('OnChannelConnected',
@@ -3552,16 +3555,19 @@ class _GenerateProtocolActorCode(ipdl.as
             foreachdealloc.addstmt(StmtExpr(_shmemDealloc(shmem)))
 
             deallocshmem.addstmts([
                 foreachdealloc,
                 StmtExpr(ExprCall(ExprSelect(p.shmemMapVar(), '.', 'Clear')))
             ])
             self.cls.addstmts([ deallocshmem, Whitespace.NL ])
 
+            deallocself = MethodDefn(MethodDecl(deallocselfvar.name, virtual=1))
+            self.cls.addstmts([ deallocself, Whitespace.NL ])
+
         self.implementPickling()
 
         ## private members
         self.cls.addstmt(StmtDecl(Decl(p.channelType(), 'mChannel')))
         if ptype.isToplevel():
             self.cls.addstmts([
                 StmtDecl(Decl(Type('IDMap', T=Type('ProtocolBase')),
                               p.actorMapVar().name)),
--- a/js/src/asmjs/AsmJS.cpp
+++ b/js/src/asmjs/AsmJS.cpp
@@ -2051,25 +2051,25 @@ class MOZ_STACK_CLASS ModuleValidator
         if (maybeField)
             fieldChars = StringToNewUTF8CharsZ(cx_, *maybeField);
         else
             fieldChars = DuplicateString("");
         if (!fieldChars)
             return false;
 
         // Declare which function is exported which gives us an index into the
-        // module ExportVector.
-        uint32_t exportIndex;
-        if (!mg_.declareExport(Move(fieldChars), func.index(), &exportIndex))
+        // module FuncExportVector.
+        uint32_t funcExportIndex;
+        if (!mg_.declareFuncExport(Move(fieldChars), func.index(), &funcExportIndex))
             return false;
 
         // The exported function might have already been exported in which case
         // the index will refer into the range of AsmJSExports.
-        MOZ_ASSERT(exportIndex <= asmJSMetadata_->asmJSExports.length());
-        return exportIndex < asmJSMetadata_->asmJSExports.length() ||
+        MOZ_ASSERT(funcExportIndex <= asmJSMetadata_->asmJSExports.length());
+        return funcExportIndex < asmJSMetadata_->asmJSExports.length() ||
                asmJSMetadata_->asmJSExports.emplaceBack(func.srcBegin() - asmJSMetadata_->srcStart,
                                                         func.srcEnd() - asmJSMetadata_->srcStart);
     }
     bool addFunction(PropertyName* name, uint32_t firstUse, Sig&& sig, Func** func) {
         uint32_t sigIndex;
         if (!declareSig(Move(sig), &sigIndex))
             return false;
         uint32_t funcIndex = numFunctions();
--- a/js/src/asmjs/WasmAST.h
+++ b/js/src/asmjs/WasmAST.h
@@ -546,22 +546,22 @@ class AstExport : public AstNode
     AstName name_;
     DefinitionKind kind_;
     AstRef func_;
 
   public:
     AstExport(AstName name, AstRef func)
       : name_(name), kind_(DefinitionKind::Function), func_(func)
     {}
-    explicit AstExport(AstName name)
-      : name_(name), kind_(DefinitionKind::Memory)
+    explicit AstExport(AstName name, DefinitionKind kind)
+      : name_(name), kind_(kind)
     {}
     AstName name() const { return name_; }
     DefinitionKind kind() const { return kind_; }
-    AstRef& func() { return func_; }
+    AstRef& func() { MOZ_ASSERT(kind_ == DefinitionKind::Function); return func_; }
 };
 
 class AstDataSegment : public AstNode
 {
     uint32_t offset_;
     AstName text_;
 
   public:
--- a/js/src/asmjs/WasmBinary.h
+++ b/js/src/asmjs/WasmBinary.h
@@ -64,17 +64,18 @@ enum class ValType
 enum class TypeConstructor
 {
     Function                             = 0x40
 };
 
 enum class DefinitionKind
 {
     Function                             = 0x00,
-    Memory                               = 0x01
+    Table                                = 0x01,
+    Memory                               = 0x02
 };
 
 enum class ResizableFlags
 {
     Default                              = 0x1,
     HasMaximum                           = 0x2,
     AllowedMask                          = 0x3
 };
--- a/js/src/asmjs/WasmBinaryToAST.cpp
+++ b/js/src/asmjs/WasmBinaryToAST.cpp
@@ -1257,17 +1257,18 @@ AstDecodeMemorySection(AstDecodeContext&
     if (!maxSize.isValid())
         return AstDecodeFail(c, "maximum memory size too big");
 
     uint8_t exported;
     if (!c.d.readFixedU8(&exported))
         return AstDecodeFail(c, "expected exported byte");
 
     if (exported) {
-        AstExport* export_ = new(c.lifo) AstExport(AstName(MOZ_UTF16("memory")));
+        AstName fieldName(MOZ_UTF16("memory"));
+        AstExport* export_ = new(c.lifo) AstExport(fieldName, DefinitionKind::Memory);
         if (!export_ || !c.module().append(export_))
             return false;
     }
 
     if (!c.d.finishSection(sectionStart, sectionSize))
         return AstDecodeFail(c, "memory section byte size mismatch");
 
     c.module().setMemory(AstResizable(initialSizePages, Some(maxSizePages)));
--- a/js/src/asmjs/WasmCode.cpp
+++ b/js/src/asmjs/WasmCode.cpp
@@ -279,40 +279,40 @@ DeserializeSig(const uint8_t* cursor, Si
 
 static size_t
 SizeOfSigExcludingThis(const Sig& sig, MallocSizeOf mallocSizeOf)
 {
     return sig.args().sizeOfExcludingThis(mallocSizeOf);
 }
 
 size_t
-Export::serializedSize() const
+FuncExport::serializedSize() const
 {
     return SerializedSigSize(sig_) +
            sizeof(pod);
 }
 
 uint8_t*
-Export::serialize(uint8_t* cursor) const
+FuncExport::serialize(uint8_t* cursor) const
 {
     cursor = SerializeSig(cursor, sig_);
     cursor = WriteBytes(cursor, &pod, sizeof(pod));
     return cursor;
 }
 
 const uint8_t*
-Export::deserialize(const uint8_t* cursor)
+FuncExport::deserialize(const uint8_t* cursor)
 {
     (cursor = DeserializeSig(cursor, &sig_)) &&
     (cursor = ReadBytes(cursor, &pod, sizeof(pod)));
     return cursor;
 }
 
 size_t
-Export::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
+FuncExport::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
 {
     return SizeOfSigExcludingThis(sig_, mallocSizeOf);
 }
 
 size_t
 FuncImport::serializedSize() const
 {
     return SerializedSigSize(sig_) +
@@ -444,34 +444,34 @@ CacheableChars::sizeOfExcludingThis(Mall
     return mallocSizeOf(get());
 }
 
 size_t
 Metadata::serializedSize() const
 {
     return sizeof(pod()) +
            SerializedVectorSize(funcImports) +
-           SerializedVectorSize(exports) +
+           SerializedVectorSize(funcExports) +
            SerializedPodVectorSize(tables) +
            SerializedPodVectorSize(memoryAccesses) +
            SerializedPodVectorSize(boundsChecks) +
            SerializedPodVectorSize(codeRanges) +
            SerializedPodVectorSize(callSites) +
            SerializedPodVectorSize(callThunks) +
            SerializedPodVectorSize(funcNames) +
            filename.serializedSize() +
            assumptions.serializedSize();
 }
 
 uint8_t*
 Metadata::serialize(uint8_t* cursor) const
 {
     cursor = WriteBytes(cursor, &pod(), sizeof(pod()));
     cursor = SerializeVector(cursor, funcImports);
-    cursor = SerializeVector(cursor, exports);
+    cursor = SerializeVector(cursor, funcExports);
     cursor = SerializePodVector(cursor, tables);
     cursor = SerializePodVector(cursor, memoryAccesses);
     cursor = SerializePodVector(cursor, boundsChecks);
     cursor = SerializePodVector(cursor, codeRanges);
     cursor = SerializePodVector(cursor, callSites);
     cursor = SerializePodVector(cursor, callThunks);
     cursor = SerializePodVector(cursor, funcNames);
     cursor = filename.serialize(cursor);
@@ -479,34 +479,34 @@ Metadata::serialize(uint8_t* cursor) con
     return cursor;
 }
 
 /* static */ const uint8_t*
 Metadata::deserialize(const uint8_t* cursor)
 {
     (cursor = ReadBytes(cursor, &pod(), sizeof(pod()))) &&
     (cursor = DeserializeVector(cursor, &funcImports)) &&
-    (cursor = DeserializeVector(cursor, &exports)) &&
+    (cursor = DeserializeVector(cursor, &funcExports)) &&
     (cursor = DeserializePodVector(cursor, &tables)) &&
     (cursor = DeserializePodVector(cursor, &memoryAccesses)) &&
     (cursor = DeserializePodVector(cursor, &boundsChecks)) &&
     (cursor = DeserializePodVector(cursor, &codeRanges)) &&
     (cursor = DeserializePodVector(cursor, &callSites)) &&
     (cursor = DeserializePodVector(cursor, &callThunks)) &&
     (cursor = DeserializePodVector(cursor, &funcNames)) &&
     (cursor = filename.deserialize(cursor)) &&
     (cursor = assumptions.deserialize(cursor));
     return cursor;
 }
 
 size_t
 Metadata::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
 {
     return SizeOfVectorExcludingThis(funcImports, mallocSizeOf) +
-           SizeOfVectorExcludingThis(exports, mallocSizeOf) +
+           SizeOfVectorExcludingThis(funcExports, mallocSizeOf) +
            tables.sizeOfExcludingThis(mallocSizeOf) +
            memoryAccesses.sizeOfExcludingThis(mallocSizeOf) +
            boundsChecks.sizeOfExcludingThis(mallocSizeOf) +
            codeRanges.sizeOfExcludingThis(mallocSizeOf) +
            callSites.sizeOfExcludingThis(mallocSizeOf) +
            callThunks.sizeOfExcludingThis(mallocSizeOf) +
            funcNames.sizeOfExcludingThis(mallocSizeOf) +
            filename.sizeOfExcludingThis(mallocSizeOf) +
--- a/js/src/asmjs/WasmCode.h
+++ b/js/src/asmjs/WasmCode.h
@@ -112,30 +112,30 @@ struct ShareableBytes : ShareableBase<Sh
     const uint8_t* begin() const { return bytes.begin(); }
     const uint8_t* end() const { return bytes.end(); }
     bool append(const uint8_t *p, uint32_t ct) { return bytes.append(p, ct); }
 };
 
 typedef RefPtr<ShareableBytes> MutableBytes;
 typedef RefPtr<const ShareableBytes> SharedBytes;
 
-// An Export represents a single function inside a wasm Module that has been
+// A FuncExport represents a single function inside a wasm Module that has been
 // exported one or more times.
 
-class Export
+class FuncExport
 {
     Sig sig_;
     struct CacheablePod {
         uint32_t funcIndex_;
         uint32_t stubOffset_;
     } pod;
 
   public:
-    Export() = default;
-    explicit Export(Sig&& sig, uint32_t funcIndex)
+    FuncExport() = default;
+    explicit FuncExport(Sig&& sig, uint32_t funcIndex)
       : sig_(Move(sig))
     {
         pod.funcIndex_ = funcIndex;
         pod.stubOffset_ = UINT32_MAX;
     }
     void initStubOffset(uint32_t stubOffset) {
         MOZ_ASSERT(pod.stubOffset_ == UINT32_MAX);
         pod.stubOffset_ = stubOffset;
@@ -147,20 +147,20 @@ class Export
     uint32_t funcIndex() const {
         return pod.funcIndex_;
     }
     uint32_t stubOffset() const {
         MOZ_ASSERT(pod.stubOffset_ != UINT32_MAX);
         return pod.stubOffset_;
     }
 
-    WASM_DECLARE_SERIALIZABLE(Export)
+    WASM_DECLARE_SERIALIZABLE(FuncExport)
 };
 
-typedef Vector<Export, 0, SystemAllocPolicy> ExportVector;
+typedef Vector<FuncExport, 0, SystemAllocPolicy> FuncExportVector;
 
 // An FuncImport contains the runtime metadata needed to implement a call to an
 // imported function. Each function import has two call stubs: an optimized path
 // into JIT code and a slow path into the generic C++ js::Invoke and these
 // offsets of these stubs are stored so that function-import callsites can be
 // dynamically patched at runtime.
 
 class FuncImport
@@ -410,35 +410,58 @@ typedef Vector<char16_t, 64> TwoByteName
 
 // Metadata holds all the data that is needed to describe compiled wasm code
 // at runtime (as opposed to data that is only used to statically link or
 // instantiate a module).
 //
 // Metadata is built incrementally by ModuleGenerator and then shared immutably
 // between modules.
 
-struct MetadataCacheablePod
+
+class MetadataCacheablePod
 {
+    static const uint32_t NO_START_FUNCTION = UINT32_MAX;
+    static_assert(NO_START_FUNCTION > MaxFuncs, "sentinel value");
+
+    uint32_t              startFuncExportIndex_;
+
+  public:
     ModuleKind            kind;
     MemoryUsage           memoryUsage;
     uint32_t              minMemoryLength;
     uint32_t              maxMemoryLength;
 
-    MetadataCacheablePod() { mozilla::PodZero(this); }
+    MetadataCacheablePod() {
+        mozilla::PodZero(this);
+        startFuncExportIndex_ = NO_START_FUNCTION;
+    }
+
+    bool hasStartFunction() const {
+        return startFuncExportIndex_ != NO_START_FUNCTION;
+    }
+    void initStartFuncExportIndex(uint32_t i) {
+        MOZ_ASSERT(!hasStartFunction());
+        startFuncExportIndex_ = i;
+        MOZ_ASSERT(hasStartFunction());
+    }
+    uint32_t startFuncExportIndex() const {
+        MOZ_ASSERT(hasStartFunction());
+        return startFuncExportIndex_;
+    }
 };
 
 struct Metadata : ShareableBase<Metadata>, MetadataCacheablePod
 {
     virtual ~Metadata() {}
 
     MetadataCacheablePod& pod() { return *this; }
     const MetadataCacheablePod& pod() const { return *this; }
 
     FuncImportVector      funcImports;
-    ExportVector          exports;
+    FuncExportVector      funcExports;
     TableDescVector       tables;
     MemoryAccessVector    memoryAccesses;
     BoundsCheckVector     boundsChecks;
     CodeRangeVector       codeRanges;
     CallSiteVector        callSites;
     CallThunkVector       callThunks;
     NameInBytecodeVector  funcNames;
     CacheableChars        filename;
--- a/js/src/asmjs/WasmCompile.cpp
+++ b/js/src/asmjs/WasmCompile.cpp
@@ -939,26 +939,26 @@ static bool
 DecodeExport(Decoder& d, bool newFormat, ModuleGenerator& mg, CStringSet* dupSet)
 {
     if (!newFormat) {
         uint32_t funcIndex;
         if (!d.readVarU32(&funcIndex))
             return Fail(d, "expected export internal index");
 
         if (funcIndex >= mg.numFuncSigs())
-            return Fail(d, "export function index out of range");
+            return Fail(d, "exported function index out of bounds");
 
         if (!CheckTypeForJS(d, mg.funcSig(funcIndex)))
             return false;
 
         UniqueChars fieldName = DecodeExportName(d, dupSet);
         if (!fieldName)
             return false;
 
-        return mg.declareExport(Move(fieldName), funcIndex);
+        return mg.declareFuncExport(Move(fieldName), funcIndex);
     }
 
     UniqueChars fieldName = DecodeExportName(d, dupSet);
     if (!fieldName)
         return false;
 
     uint32_t exportKind;
     if (!d.readVarU32(&exportKind))
@@ -966,30 +966,40 @@ DecodeExport(Decoder& d, bool newFormat,
 
     switch (DefinitionKind(exportKind)) {
       case DefinitionKind::Function: {
         uint32_t funcIndex;
         if (!d.readVarU32(&funcIndex))
             return Fail(d, "expected export internal index");
 
         if (funcIndex >= mg.numFuncSigs())
-            return Fail(d, "export function index out of range");
+            return Fail(d, "exported function index out of bounds");
 
         if (!CheckTypeForJS(d, mg.funcSig(funcIndex)))
             return false;
 
-        return mg.declareExport(Move(fieldName), funcIndex);
+        return mg.declareFuncExport(Move(fieldName), funcIndex);
+      }
+      case DefinitionKind::Table: {
+        uint32_t tableIndex;
+        if (!d.readVarU32(&tableIndex))
+            return Fail(d, "expected table index");
+
+        if (tableIndex >= mg.tables().length())
+            return Fail(d, "exported table index out of bounds");
+
+        return mg.addTableExport(Move(fieldName));
       }
       case DefinitionKind::Memory: {
         uint32_t memoryIndex;
         if (!d.readVarU32(&memoryIndex))
             return Fail(d, "expected memory index");
 
         if (memoryIndex > 0 || !mg.usesMemory())
-            return Fail(d, "memory index out of bounds");
+            return Fail(d, "exported memory index out of bounds");
 
         return mg.addMemoryExport(Move(fieldName));
       }
       default:
         return Fail(d, "unexpected export kind");
     }
 
     MOZ_CRASH("unreachable");
--- a/js/src/asmjs/WasmGenerator.cpp
+++ b/js/src/asmjs/WasmGenerator.cpp
@@ -94,17 +94,17 @@ ModuleGenerator::~ModuleGenerator()
 }
 
 bool
 ModuleGenerator::init(UniqueModuleGeneratorData shared, CompileArgs&& args,
                       Metadata* maybeAsmJSMetadata)
 {
     alwaysBaseline_ = args.alwaysBaseline;
 
-    if (!funcIndexToExport_.init())
+    if (!funcIndexToFuncExportIndex_.init())
         return false;
 
     linkData_.globalDataLength = AlignBytes(InitialGlobalDataBytes, sizeof(void*));;
 
     // asm.js passes in an AsmJSMetadata subclass to use instead.
     if (maybeAsmJSMetadata) {
         MOZ_ASSERT(shared->kind == ModuleKind::AsmJS);
         metadata_ = maybeAsmJSMetadata;
@@ -350,17 +350,17 @@ ModuleGenerator::finishCodegen()
 
     {
         TempAllocator alloc(&lifo_);
         MacroAssembler masm(MacroAssembler::AsmJSToken(), alloc);
 
         if (!entries.resize(numExports()))
             return false;
         for (uint32_t i = 0; i < numExports(); i++)
-            entries[i] = GenerateEntry(masm, metadata_->exports[i], usesMemory());
+            entries[i] = GenerateEntry(masm, metadata_->funcExports[i], usesMemory());
 
         if (!interpExits.resize(numFuncImports()))
             return false;
         if (!jitExits.resize(numFuncImports()))
             return false;
         for (uint32_t i = 0; i < numFuncImports(); i++) {
             interpExits[i] = GenerateInterpExit(masm, metadata_->funcImports[i], i);
             jitExits[i] = GenerateJitExit(masm, metadata_->funcImports[i], usesMemory());
@@ -375,17 +375,17 @@ ModuleGenerator::finishCodegen()
             return false;
     }
 
     // Adjust each of the resulting Offsets (to account for being merged into
     // masm_) and then create code ranges for all the stubs.
 
     for (uint32_t i = 0; i < numExports(); i++) {
         entries[i].offsetBy(offsetInWhole);
-        metadata_->exports[i].initStubOffset(entries[i].begin);
+        metadata_->funcExports[i].initStubOffset(entries[i].begin);
         if (!metadata_->codeRanges.emplaceBack(CodeRange::Entry, entries[i]))
             return false;
     }
 
     for (uint32_t i = 0; i < numFuncImports(); i++) {
         interpExits[i].offsetBy(offsetInWhole);
         metadata_->funcImports[i].initInterpExitOffset(interpExits[i].begin);
         if (!metadata_->codeRanges.emplaceBack(CodeRange::ImportInterpExit, interpExits[i]))
@@ -642,73 +642,78 @@ ModuleGenerator::numFuncImports() const
 const FuncImportGenDesc&
 ModuleGenerator::funcImport(uint32_t funcImportIndex) const
 {
     MOZ_ASSERT(shared_->funcImports[funcImportIndex].sig);
     return shared_->funcImports[funcImportIndex];
 }
 
 bool
-ModuleGenerator::declareExport(UniqueChars fieldName, uint32_t funcIndex, uint32_t* exportIndex)
+ModuleGenerator::declareFuncExport(UniqueChars fieldName, uint32_t funcIndex,
+                                   uint32_t* funcExportIndex /* = nullptr */)
 {
-    MOZ_ASSERT(!exportMap_.hasStartFunction());
+    MOZ_ASSERT(!metadata_->hasStartFunction());
 
-    if (!exportMap_.fieldNames.append(Move(fieldName)))
-        return false;
-
-    FuncIndexMap::AddPtr p = funcIndexToExport_.lookupForAdd(funcIndex);
+    FuncIndexMap::AddPtr p = funcIndexToFuncExportIndex_.lookupForAdd(funcIndex);
     if (p) {
-        if (exportIndex)
-            *exportIndex = p->value();
-        return exportMap_.fieldsToExports.append(p->value());
+        if (funcExportIndex)
+            *funcExportIndex = p->value();
+        return exports_.emplaceBack(Move(fieldName), p->value());
     }
 
-    uint32_t newExportIndex = metadata_->exports.length();
-    MOZ_ASSERT(newExportIndex < MaxExports);
+    uint32_t newFuncExportIndex = metadata_->funcExports.length();
+    MOZ_ASSERT(newFuncExportIndex < MaxExports);
 
-    if (exportIndex)
-        *exportIndex = newExportIndex;
+    if (funcExportIndex)
+        *funcExportIndex = newFuncExportIndex;
 
     Sig copy;
     if (!copy.clone(funcSig(funcIndex)))
         return false;
 
-    return metadata_->exports.emplaceBack(Move(copy), funcIndex) &&
-           exportMap_.fieldsToExports.append(newExportIndex) &&
-           funcIndexToExport_.add(p, funcIndex, newExportIndex);
+    return metadata_->funcExports.emplaceBack(Move(copy), funcIndex) &&
+           exports_.emplaceBack(Move(fieldName), newFuncExportIndex) &&
+           funcIndexToFuncExportIndex_.add(p, funcIndex, newFuncExportIndex);
 }
 
 uint32_t
 ModuleGenerator::numExports() const
 {
-    return metadata_->exports.length();
+    return metadata_->funcExports.length();
+}
+
+bool
+ModuleGenerator::addTableExport(UniqueChars fieldName)
+{
+    return exports_.emplaceBack(Move(fieldName), DefinitionKind::Table);
 }
 
 bool
 ModuleGenerator::addMemoryExport(UniqueChars fieldName)
 {
-    return exportMap_.fieldNames.append(Move(fieldName)) &&
-           exportMap_.fieldsToExports.append(MemoryExport);
+    return exports_.emplaceBack(Move(fieldName), DefinitionKind::Memory);
 }
 
 bool
 ModuleGenerator::setStartFunction(uint32_t funcIndex)
 {
-    FuncIndexMap::AddPtr p = funcIndexToExport_.lookupForAdd(funcIndex);
+    MOZ_ASSERT(!metadata_->hasStartFunction());
+
+    FuncIndexMap::AddPtr p = funcIndexToFuncExportIndex_.lookupForAdd(funcIndex);
     if (p) {
-        exportMap_.setStartFunction(p->value());
+        metadata_->initStartFuncExportIndex(p->value());
         return true;
     }
 
     Sig copy;
     if (!copy.clone(funcSig(funcIndex)))
         return false;
 
-    exportMap_.setStartFunction(metadata_->exports.length());
-    return metadata_->exports.emplaceBack(Move(copy), funcIndex);
+    metadata_->initStartFuncExportIndex(metadata_->funcExports.length());
+    return metadata_->funcExports.emplaceBack(Move(copy), funcIndex);
 }
 
 bool
 ModuleGenerator::startFuncDefs()
 {
     MOZ_ASSERT(!startedFuncDefs_);
     MOZ_ASSERT(!finishedFuncDefs_);
 
@@ -955,14 +960,14 @@ ModuleGenerator::finish(ImportVector&& i
     }
 
     if (!finishLinkData(code))
         return nullptr;
 
     return js::MakeUnique<Module>(Move(code),
                                   Move(linkData_),
                                   Move(imports),
-                                  Move(exportMap_),
+                                  Move(exports_),
                                   Move(dataSegments_),
                                   Move(elemSegments_),
                                   *metadata_,
                                   bytecode);
 }
--- a/js/src/asmjs/WasmGenerator.h
+++ b/js/src/asmjs/WasmGenerator.h
@@ -94,30 +94,30 @@ class MOZ_STACK_CLASS ModuleGenerator
     typedef Vector<IonCompileTask*, 0, SystemAllocPolicy> IonCompileTaskPtrVector;
 
     // Constant parameters
     bool                            alwaysBaseline_;
 
     // Data that is moved into the result of finish()
     LinkData                        linkData_;
     MutableMetadata                 metadata_;
-    ExportMap                       exportMap_;
+    ExportVector                    exports_;
     DataSegmentVector               dataSegments_;
     ElemSegmentVector               elemSegments_;
 
     // Data scoped to the ModuleGenerator's lifetime
     UniqueModuleGeneratorData       shared_;
     uint32_t                        numSigs_;
     uint32_t                        numTables_;
     LifoAlloc                       lifo_;
     jit::JitContext                 jcx_;
     jit::TempAllocator              masmAlloc_;
     jit::MacroAssembler             masm_;
     Uint32Vector                    funcIndexToCodeRange_;
-    FuncIndexMap                    funcIndexToExport_;
+    FuncIndexMap                    funcIndexToFuncExportIndex_;
     uint32_t                        lastPatchedCallsite_;
     uint32_t                        startOfUnpatchedBranches_;
     JumpSiteArray                   jumpThunks_;
 
     // Parallel compilation
     bool                            parallel_;
     uint32_t                        outstanding_;
     IonCompileTaskVector            tasks_;
@@ -168,20 +168,21 @@ class MOZ_STACK_CLASS ModuleGenerator
     MOZ_MUST_USE bool allocateGlobal(ValType type, bool isConst, uint32_t* index);
     const GlobalDesc& global(unsigned index) const { return shared_->globals[index]; }
 
     // Imports:
     uint32_t numFuncImports() const;
     const FuncImportGenDesc& funcImport(uint32_t funcImportIndex) const;
 
     // Exports:
-    MOZ_MUST_USE bool declareExport(UniqueChars fieldName, uint32_t funcIndex,
-                                    uint32_t* exportIndex = nullptr);
+    MOZ_MUST_USE bool declareFuncExport(UniqueChars fieldName, uint32_t funcIndex,
+                                        uint32_t* funcExportIndex = nullptr);
+    MOZ_MUST_USE bool addTableExport(UniqueChars fieldName);
+    MOZ_MUST_USE bool addMemoryExport(UniqueChars fieldName);
     uint32_t numExports() const;
-    MOZ_MUST_USE bool addMemoryExport(UniqueChars fieldName);
 
     // Function definitions:
     MOZ_MUST_USE bool startFuncDefs();
     MOZ_MUST_USE bool startFuncDef(uint32_t lineOrBytecode, FunctionGenerator* fg);
     MOZ_MUST_USE bool finishFuncDef(uint32_t funcIndex, FunctionGenerator* fg);
     MOZ_MUST_USE bool finishFuncDefs();
 
     // Start function:
--- a/js/src/asmjs/WasmInstance.cpp
+++ b/js/src/asmjs/WasmInstance.cpp
@@ -415,19 +415,19 @@ Instance::memoryBase() const
 
 size_t
 Instance::memoryLength() const
 {
     return memory_->buffer().byteLength();
 }
 
 bool
-Instance::callExport(JSContext* cx, uint32_t exportIndex, CallArgs args)
+Instance::callExport(JSContext* cx, uint32_t funcExportIndex, CallArgs args)
 {
-    const Export& exp = metadata_->exports[exportIndex];
+    const FuncExport& fe = metadata_->funcExports[funcExportIndex];
 
     // Enable/disable profiling in the Module to match the current global
     // profiling state. Don't do this if the Module is already active on the
     // stack since this would leave the Module in a state where profiling is
     // enabled but the stack isn't unwindable.
     if (profilingEnabled() != cx->runtime()->spsProfiler.enabled() && !activation()) {
         if (!toggleProfiling(cx))
             return false;
@@ -437,23 +437,23 @@ Instance::callExport(JSContext* cx, uint
     // array of 16-byte values where each value contains either a coerced int32
     // (in the low word), a double value (in the low dword) or a SIMD vector
     // value, with the coercions specified by the wasm signature. The external
     // entry point unpacks this array into the system-ABI-specified registers
     // and stack memory and then calls into the internal entry point. The return
     // value is stored in the first element of the array (which, therefore, must
     // have length >= 1).
     Vector<ExportArg, 8> exportArgs(cx);
-    if (!exportArgs.resize(Max<size_t>(1, exp.sig().args().length())))
+    if (!exportArgs.resize(Max<size_t>(1, fe.sig().args().length())))
         return false;
 
     RootedValue v(cx);
-    for (unsigned i = 0; i < exp.sig().args().length(); ++i) {
+    for (unsigned i = 0; i < fe.sig().args().length(); ++i) {
         v = i < args.length() ? args[i] : UndefinedValue();
-        switch (exp.sig().arg(i)) {
+        switch (fe.sig().arg(i)) {
           case ValType::I32:
             if (!ToInt32(cx, v, (int32_t*)&exportArgs[i]))
                 return false;
             break;
           case ValType::I64:
             MOZ_ASSERT(JitOptions.wasmTestMode, "no int64 in asm.js/wasm");
             if (!ReadI64Object(cx, v, (int64_t*)&exportArgs[i]))
                 return false;
@@ -528,17 +528,17 @@ Instance::callExport(JSContext* cx, uint
         // when running this module. Additionally, push a JitActivation so that
         // the optimized wasm-to-Ion FFI call path (which we want to be very
         // fast) can avoid doing so. The JitActivation is marked as inactive so
         // stack iteration will skip over it.
         WasmActivation activation(cx, *this);
         JitActivation jitActivation(cx, /* active */ false);
 
         // Call the per-exported-function trampoline created by GenerateEntry.
-        auto funcPtr = JS_DATA_TO_FUNC_PTR(ExportFuncPtr, codeSegment_->code() + exp.stubOffset());
+        auto funcPtr = JS_DATA_TO_FUNC_PTR(ExportFuncPtr, codeSegment_->code() + fe.stubOffset());
         if (!CALL_GENERATED_2(funcPtr, exportArgs.begin(), codeSegment_->globalData()))
             return false;
     }
 
     if (args.isConstructing()) {
         // By spec, when a function is called as a constructor and this function
         // returns a primary type, which is the case for all wasm exported
         // functions, the returned value is discarded and an empty object is
@@ -547,17 +547,17 @@ Instance::callExport(JSContext* cx, uint
         if (!obj)
             return false;
         args.rval().set(ObjectValue(*obj));
         return true;
     }
 
     void* retAddr = &exportArgs[0];
     JSObject* retObj = nullptr;
-    switch (exp.sig().ret()) {
+    switch (fe.sig().ret()) {
       case ExprType::Void:
         args.rval().set(UndefinedValue());
         break;
       case ExprType::I32:
         args.rval().set(Int32Value(*(int32_t*)retAddr));
         break;
       case ExprType::I64:
         MOZ_ASSERT(JitOptions.wasmTestMode, "no int64 in asm.js/wasm");
--- a/js/src/asmjs/WasmInstance.h
+++ b/js/src/asmjs/WasmInstance.h
@@ -25,18 +25,16 @@
 
 namespace js {
 
 class WasmActivation;
 class WasmInstanceObject;
 
 namespace wasm {
 
-class ExportMap;
-
 // Instance represents a wasm instance and provides all the support for runtime
 // execution of code in the instance. Instances share various immutable data
 // structures with the Module from which they were instantiated and other
 // instances instantiated from the same Module. However, an Instance has no
 // direct reference to its source Module which allows a Module to be destroyed
 // while it still has live Instances.
 
 class Instance
@@ -77,23 +75,24 @@ class Instance
              HandleWasmMemoryObject memory,
              SharedTableVector&& tables,
              Handle<FunctionVector> funcImports);
     ~Instance();
     void trace(JSTracer* trc);
 
     const CodeSegment& codeSegment() const { return *codeSegment_; }
     const Metadata& metadata() const { return *metadata_; }
+    const SharedTableVector& tables() const { return tables_; }
     SharedMem<uint8_t*> memoryBase() const;
     size_t memoryLength() const;
 
     // Execute the given export given the JS call arguments, storing the return
     // value in args.rval.
 
-    MOZ_MUST_USE bool callExport(JSContext* cx, uint32_t exportIndex, CallArgs args);
+    MOZ_MUST_USE bool callExport(JSContext* cx, uint32_t funcExportIndex, CallArgs args);
 
     // An instance has a profiling mode that is updated to match the runtime's
     // profiling mode when calling an instance's exports when there are no other
     // activations of the instance live on the stack. Once in profiling mode,
     // ProfilingFrameIterator can be used to asynchronously walk the stack.
     // Otherwise, the ProfilingFrameIterator will skip any activations of this
     // instance.
 
--- a/js/src/asmjs/WasmJS.cpp
+++ b/js/src/asmjs/WasmJS.cpp
@@ -105,16 +105,18 @@ GetImports(JSContext* cx, HandleObject i
           case DefinitionKind::Function:
             if (!IsFunctionObject(v))
                 return Throw(cx, "import object field is not a Function");
 
             if (!funcImports.append(&v.toObject().as<JSFunction>()))
                 return false;
 
             break;
+          case DefinitionKind::Table:
+            MOZ_CRASH("NYI");
           case DefinitionKind::Memory:
             if (!v.isObject() || !v.toObject().is<WasmMemoryObject>())
                 return Throw(cx, "import object field is not a Memory");
 
             MOZ_ASSERT(!memoryImport);
             memoryImport.set(&v.toObject().as<WasmMemoryObject>());
             break;
         }
@@ -568,33 +570,33 @@ WasmMemoryObject::construct(JSContext* c
     if (!memoryObj)
         return false;
 
     args.rval().setObject(*memoryObj);
     return true;
 }
 
 static bool
-IsMemoryBuffer(HandleValue v)
+IsMemory(HandleValue v)
 {
     return v.isObject() && v.toObject().is<WasmMemoryObject>();
 }
 
 static bool
 MemoryBufferGetterImpl(JSContext* cx, const CallArgs& args)
 {
     args.rval().setObject(args.thisv().toObject().as<WasmMemoryObject>().buffer());
     return true;
 }
 
 static bool
 MemoryBufferGetter(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    return CallNonGenericMethod<IsMemoryBuffer, MemoryBufferGetterImpl>(cx, args);
+    return CallNonGenericMethod<IsMemory, MemoryBufferGetterImpl>(cx, args);
 }
 
 const JSPropertySpec WasmMemoryObject::properties[] =
 {
     JS_PSG("buffer", MemoryBufferGetter, 0),
     JS_PS_END
 };
 
@@ -628,22 +630,21 @@ static const ClassOps WasmTableObject_cl
 const Class WasmTableObject::class_ =
 {
     "WebAssembly.Table",
     JSCLASS_DELAY_METADATA_BUILDER |
     JSCLASS_HAS_RESERVED_SLOTS(WasmTableObject::RESERVED_SLOTS),
     &WasmTableObject_classOps
 };
 
-const JSPropertySpec WasmTableObject::properties[] =
-{ JS_PS_END };
+/* static */ WasmTableObject*
+WasmTableObject::create(JSContext* cx, Table& table)
+{
+    RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmTable).toObject());
 
-/* static */ WasmTableObject*
-WasmTableObject::create(ExclusiveContext* cx, Table& table, HandleObject proto)
-{
     AutoSetNewObjectMetadata metadata(cx);
     auto* obj = NewObjectWithGivenProto<WasmTableObject>(cx, proto);
     if (!obj)
         return nullptr;
 
     obj->initReservedSlot(TABLE_SLOT, PrivateValue((void*)&table));
     table.AddRef();
     return obj;
@@ -683,25 +684,50 @@ WasmTableObject::construct(JSContext* cx
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_SIZE, "Table", "initial");
         return false;
     }
 
     SharedTable table = Table::create(cx, TableKind::AnyFunction, uint32_t(initialDbl));
     if (!table)
         return false;
 
-    RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmTable).toObject());
-    RootedWasmTableObject tableObj(cx, WasmTableObject::create(cx, *table, proto));
+    RootedWasmTableObject tableObj(cx, WasmTableObject::create(cx, *table));
     if (!tableObj)
         return false;
 
     args.rval().setObject(*tableObj);
     return true;
 }
 
+static bool
+IsTable(HandleValue v)
+{
+    return v.isObject() && v.toObject().is<WasmTableObject>();
+}
+
+static bool
+TableLengthGetterImpl(JSContext* cx, const CallArgs& args)
+{
+    args.rval().setNumber(args.thisv().toObject().as<WasmTableObject>().table().length());
+    return true;
+}
+
+static bool
+TableLengthGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    return CallNonGenericMethod<IsTable, TableLengthGetterImpl>(cx, args);
+}
+
+const JSPropertySpec WasmTableObject::properties[] =
+{
+    JS_PSG("length", TableLengthGetter, 0),
+    JS_PS_END
+};
+
 Table&
 WasmTableObject::table() const
 {
     return *(Table*)getReservedSlot(TABLE_SLOT).toPrivate();
 }
 
 // ============================================================================
 // WebAssembly class and static methods
--- a/js/src/asmjs/WasmJS.h
+++ b/js/src/asmjs/WasmJS.h
@@ -161,20 +161,19 @@ class WasmTableObject : public NativeObj
     static const unsigned TABLE_SLOT = 0;
   public:
     static const JSProtoKey KEY = JSProto_WasmTable;
     static const unsigned RESERVED_SLOTS = 1;
     static const Class class_;
     static const JSPropertySpec properties[];
     static bool construct(JSContext*, unsigned, Value*);
 
-    static WasmTableObject* create(ExclusiveContext* cx,
-                                   wasm::Table& table,
-                                   HandleObject proto);
+    static WasmTableObject* create(JSContext* cx, wasm::Table& table);
     wasm::Table& table() const;
 };
 
 typedef Rooted<WasmTableObject*> RootedWasmTableObject;
 typedef Handle<WasmTableObject*> HandleWasmTableObject;
+typedef MutableHandle<WasmTableObject*> MutableHandleWasmTableObject;
 
 } // namespace js
 
 #endif // wasm_js_h
--- a/js/src/asmjs/WasmModule.cpp
+++ b/js/src/asmjs/WasmModule.cpp
@@ -153,47 +153,64 @@ Import::deserialize(const uint8_t* curso
 
 size_t
 Import::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
 {
     return module.sizeOfExcludingThis(mallocSizeOf) +
            func.sizeOfExcludingThis(mallocSizeOf);
 }
 
-size_t
-ExportMap::serializedSize() const
+Export::Export(UniqueChars fieldName, uint32_t funcExportIndex)
+  : fieldName_(Move(fieldName))
+{
+    pod.kind_ = DefinitionKind::Function;
+    pod.funcExportIndex_ = funcExportIndex;
+}
+
+Export::Export(UniqueChars fieldName, DefinitionKind kind)
+  : fieldName_(Move(fieldName))
 {
-    return SerializedVectorSize(fieldNames) +
-           SerializedPodVectorSize(fieldsToExports) +
-           sizeof(uint32_t);
+    pod.kind_ = kind;
+    pod.funcExportIndex_ = 0;
+}
+
+uint32_t
+Export::funcExportIndex() const
+{
+    MOZ_ASSERT(pod.kind_ == DefinitionKind::Function);
+    return pod.funcExportIndex_;
+}
+
+size_t
+Export::serializedSize() const
+{
+    return fieldName_.serializedSize() +
+           sizeof(pod);
 }
 
 uint8_t*
-ExportMap::serialize(uint8_t* cursor) const
+Export::serialize(uint8_t* cursor) const
 {
-    cursor = SerializeVector(cursor, fieldNames);
-    cursor = SerializePodVector(cursor, fieldsToExports);
-    cursor = WriteScalar(cursor, startExportIndex);
+    cursor = fieldName_.serialize(cursor);
+    cursor = WriteBytes(cursor, &pod, sizeof(pod));
     return cursor;
 }
 
 const uint8_t*
-ExportMap::deserialize(const uint8_t* cursor)
+Export::deserialize(const uint8_t* cursor)
 {
-    (cursor = DeserializeVector(cursor, &fieldNames)) &&
-    (cursor = DeserializePodVector(cursor, &fieldsToExports)) &&
-    (cursor = ReadScalar(cursor, &startExportIndex));
+    (cursor = fieldName_.deserialize(cursor)) &&
+    (cursor = ReadBytes(cursor, &pod, sizeof(pod)));
     return cursor;
 }
 
 size_t
-ExportMap::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
+Export::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
 {
-    return SizeOfVectorExcludingThis(fieldNames, mallocSizeOf) &&
-           fieldsToExports.sizeOfExcludingThis(mallocSizeOf);
+    return fieldName_.sizeOfExcludingThis(mallocSizeOf);
 }
 
 size_t
 ElemSegment::serializedSize() const
 {
     return sizeof(tableIndex) +
            SerializedPodVectorSize(elems);
 }
@@ -221,30 +238,30 @@ ElemSegment::sizeOfExcludingThis(MallocS
 }
 
 size_t
 Module::serializedSize() const
 {
     return SerializedPodVectorSize(code_) +
            linkData_.serializedSize() +
            SerializedVectorSize(imports_) +
-           exportMap_.serializedSize() +
+           SerializedVectorSize(exports_) +
            SerializedPodVectorSize(dataSegments_) +
            SerializedVectorSize(elemSegments_) +
            metadata_->serializedSize() +
            SerializedPodVectorSize(bytecode_->bytes);
 }
 
 uint8_t*
 Module::serialize(uint8_t* cursor) const
 {
     cursor = SerializePodVector(cursor, code_);
     cursor = linkData_.serialize(cursor);
     cursor = SerializeVector(cursor, imports_);
-    cursor = exportMap_.serialize(cursor);
+    cursor = SerializeVector(cursor, exports_);
     cursor = SerializePodVector(cursor, dataSegments_);
     cursor = SerializeVector(cursor, elemSegments_);
     cursor = metadata_->serialize(cursor);
     cursor = SerializePodVector(cursor, bytecode_->bytes);
     return cursor;
 }
 
 /* static */ const uint8_t*
@@ -260,18 +277,18 @@ Module::deserialize(const uint8_t* curso
     if (!cursor)
         return nullptr;
 
     ImportVector imports;
     cursor = DeserializeVector(cursor, &imports);
     if (!cursor)
         return nullptr;
 
-    ExportMap exportMap;
-    cursor = exportMap.deserialize(cursor);
+    ExportVector exports;
+    cursor = DeserializeVector(cursor, &exports);
     if (!cursor)
         return nullptr;
 
     DataSegmentVector dataSegments;
     cursor = DeserializePodVector(cursor, &dataSegments);
     if (!cursor)
         return nullptr;
 
@@ -298,17 +315,17 @@ Module::deserialize(const uint8_t* curso
         return nullptr;
     cursor = DeserializePodVector(cursor, &bytecode->bytes);
     if (!cursor)
         return nullptr;
 
     *module = js::MakeUnique<Module>(Move(code),
                                      Move(linkData),
                                      Move(imports),
-                                     Move(exportMap),
+                                     Move(exports),
                                      Move(dataSegments),
                                      Move(elemSegments),
                                      *metadata,
                                      *bytecode);
     if (!*module)
         return nullptr;
 
     return cursor;
@@ -320,17 +337,17 @@ Module::addSizeOfMisc(MallocSizeOf mallo
                       ShareableBytes::SeenSet* seenBytes,
                       size_t* code,
                       size_t* data) const
 {
     *data += mallocSizeOf(this) +
              code_.sizeOfExcludingThis(mallocSizeOf) +
              linkData_.sizeOfExcludingThis(mallocSizeOf) +
              SizeOfVectorExcludingThis(imports_, mallocSizeOf) +
-             exportMap_.sizeOfExcludingThis(mallocSizeOf) +
+             SizeOfVectorExcludingThis(exports_, mallocSizeOf) +
              dataSegments_.sizeOfExcludingThis(mallocSizeOf) +
              SizeOfVectorExcludingThis(elemSegments_, mallocSizeOf) +
              metadata_->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenMetadata) +
              bytecode_->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenBytes);
 }
 
 // asm.js module instantiation supplies its own buffer, but for wasm, create and
 // initialize the buffer if one is requested. Either way, the buffer is wrapped
@@ -409,89 +426,98 @@ Module::instantiateTable(JSContext* cx, 
 
 static bool
 WasmCall(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     RootedFunction callee(cx, &args.callee().as<JSFunction>());
 
     Instance& instance = ExportedFunctionToInstance(callee);
-    uint32_t exportIndex = ExportedFunctionToExportIndex(callee);
+    uint32_t funcExportIndex = ExportedFunctionToExportIndex(callee);
 
-    return instance.callExport(cx, exportIndex, args);
+    return instance.callExport(cx, funcExportIndex, args);
 }
 
 static JSFunction*
-NewExportedFunction(JSContext* cx, Handle<WasmInstanceObject*> instanceObj, uint32_t exportIndex)
+NewExportedFunction(JSContext* cx, HandleWasmInstanceObject instanceObj, uint32_t funcExportIndex)
 {
     Instance& instance = instanceObj->instance();
     const Metadata& metadata = instance.metadata();
-    const Export& exp = metadata.exports[exportIndex];
-    unsigned numArgs = exp.sig().args().length();
+    const FuncExport& fe = metadata.funcExports[funcExportIndex];
+    unsigned numArgs = fe.sig().args().length();
 
-    RootedAtom name(cx, instance.getFuncAtom(cx, exp.funcIndex()));
+    RootedAtom name(cx, instance.getFuncAtom(cx, fe.funcIndex()));
     if (!name)
         return nullptr;
 
     JSFunction* fun = NewNativeConstructor(cx, WasmCall, numArgs, name,
                                            gc::AllocKind::FUNCTION_EXTENDED, GenericObject,
                                            JSFunction::ASMJS_CTOR);
     if (!fun)
         return nullptr;
 
     fun->setExtendedSlot(FunctionExtended::WASM_INSTANCE_SLOT, ObjectValue(*instanceObj));
-    fun->setExtendedSlot(FunctionExtended::WASM_EXPORT_INDEX_SLOT, Int32Value(exportIndex));
+    fun->setExtendedSlot(FunctionExtended::WASM_EXPORT_INDEX_SLOT, Int32Value(funcExportIndex));
     return fun;
 }
 
 static bool
 CreateExportObject(JSContext* cx,
                    HandleWasmInstanceObject instanceObj,
                    HandleWasmMemoryObject memoryObj,
-                   const ExportMap& exportMap,
-                   const Metadata& metadata,
+                   const ExportVector& exports,
                    MutableHandleObject exportObj)
 {
-    MOZ_ASSERT(exportMap.fieldNames.length() == exportMap.fieldsToExports.length());
+    const Instance& instance = instanceObj->instance();
+    const Metadata& metadata = instance.metadata();
+    const SharedTableVector& tables = instance.tables();
 
-    if (metadata.isAsmJS() &&
-        exportMap.fieldNames.length() == 1 &&
-        strlen(exportMap.fieldNames[0].get()) == 0)
-    {
+    if (metadata.isAsmJS() && exports.length() == 1 && strlen(exports[0].fieldName()) == 0) {
         exportObj.set(NewExportedFunction(cx, instanceObj, 0));
         return !!exportObj;
     }
 
     exportObj.set(JS_NewPlainObject(cx));
     if (!exportObj)
         return false;
 
     Rooted<ValueVector> vals(cx, ValueVector(cx));
-    for (size_t exportIndex = 0; exportIndex < metadata.exports.length(); exportIndex++) {
-        JSFunction* fun = NewExportedFunction(cx, instanceObj, exportIndex);
+    for (size_t i = 0; i < metadata.funcExports.length(); i++) {
+        JSFunction* fun = NewExportedFunction(cx, instanceObj, i);
         if (!fun || !vals.append(ObjectValue(*fun)))
             return false;
     }
 
-    for (size_t fieldIndex = 0; fieldIndex < exportMap.fieldNames.length(); fieldIndex++) {
-        const char* fieldName = exportMap.fieldNames[fieldIndex].get();
-        JSAtom* atom = AtomizeUTF8Chars(cx, fieldName, strlen(fieldName));
+    RootedWasmTableObject tableObj(cx);
+    for (const Export& exp : exports) {
+        JSAtom* atom = AtomizeUTF8Chars(cx, exp.fieldName(), strlen(exp.fieldName()));
         if (!atom)
             return false;
 
         RootedId id(cx, AtomToId(atom));
         RootedValue val(cx);
-        uint32_t exportIndex = exportMap.fieldsToExports[fieldIndex];
-        if (exportIndex == MemoryExport) {
+        switch (exp.kind()) {
+          case DefinitionKind::Function:
+            val = vals[exp.funcExportIndex()];
+            break;
+          case DefinitionKind::Table:
+            MOZ_ASSERT(tables.length() == 1);
+            if (!tableObj) {
+                tableObj = WasmTableObject::create(cx, *tables[0]);
+                if (!tableObj)
+                    return false;
+            }
+            val = ObjectValue(*tableObj);
+            break;
+          case DefinitionKind::Memory:
             if (metadata.assumptions.newFormat)
                 val = ObjectValue(*memoryObj);
             else
                 val = ObjectValue(memoryObj->buffer());
-        } else {
-            val = vals[exportIndex];
+            break;
         }
 
         if (!JS_DefinePropertyById(cx, exportObj, id, val, JSPROP_ENUMERATE))
             return false;
     }
 
     return true;
 }
@@ -544,17 +570,17 @@ Module::instantiate(JSContext* cx,
             return false;
 
         instanceObj->init(Move(instance));
     }
 
     // Create the export object.
 
     RootedObject exportObj(cx);
-    if (!CreateExportObject(cx, instanceObj, memory, exportMap_, *metadata_, &exportObj))
+    if (!CreateExportObject(cx, instanceObj, memory, exports_, &exportObj))
         return false;
 
     instanceObj->initExportsObject(exportObj);
 
     JSAtom* atom = Atomize(cx, ExportField, strlen(ExportField));
     if (!atom)
         return false;
     RootedId id(cx, AtomToId(atom));
@@ -566,19 +592,19 @@ Module::instantiate(JSContext* cx,
     // Done! Notify the Debugger of the new Instance.
 
     Debugger::onNewWasmInstance(cx, instanceObj);
 
     // Call the start function, if there's one. By specification, it does not
     // take any arguments nor does it return a value, so just create a dummy
     // arguments object.
 
-    if (exportMap_.hasStartFunction()) {
+    if (metadata_->hasStartFunction()) {
         FixedInvokeArgs<0> args(cx);
-        if (!instanceObj->instance().callExport(cx, exportMap_.startFunctionExportIndex(), args))
+        if (!instanceObj->instance().callExport(cx, metadata_->startFuncExportIndex(), args))
             return false;
     }
 
     return true;
 }
 
 bool
 wasm::IsExportedFunction(JSFunction* fun)
--- a/js/src/asmjs/WasmModule.h
+++ b/js/src/asmjs/WasmModule.h
@@ -98,59 +98,48 @@ struct Import
       : module(Move(module)), func(Move(func)), kind(kind)
     {}
 
     WASM_DECLARE_SERIALIZABLE(Import)
 };
 
 typedef Vector<Import, 0, SystemAllocPolicy> ImportVector;
 
-// ExportMap describes all of a single module's exports. The ExportMap describes
-// how the Exports (stored in Metadata) are mapped to the fields of the export
-// object produced by instantiation. The 'fieldNames' vector provides the list
-// of names of the module's exports. For each field name, 'fieldsToExports'
-// provides either:
-//  - the sentinel value MemoryExport indicating an export of linear memory; or
-//  - the index of an export into the ExportVector in Metadata
-//
-// ExportMap also contains the start function's export index, which maps to the
-// export that is called at each instantiation of a given module.
+// Export describes the export of a definition in a Module to a field in the
+// export object. For functions, Export stores an index into the
+// FuncExportVector in Metadata. For memory and table exports, there is
+// at most one (default) memory/table so no index is needed. Note: a single
+// definition can be exported by multiple Exports in the ExportVector.
 //
-// ExportMap is built incrementally by ModuleGenerator and then stored immutably
-// by Module.
-
-static const uint32_t MemoryExport = UINT32_MAX;
+// ExportVector is built incrementally by ModuleGenerator and then stored
+// immutably by Module.
 
-static const uint32_t NO_START_FUNCTION = UINT32_MAX;
-
-class ExportMap
+class Export
 {
-    uint32_t startExportIndex;
+    CacheableChars fieldName_;
+    struct CacheablePod {
+        DefinitionKind kind_;
+        uint32_t funcExportIndex_;
+    } pod;
 
   public:
-    CacheableCharsVector fieldNames;
-    Uint32Vector fieldsToExports;
+    Export() = default;
+    explicit Export(UniqueChars fieldName, uint32_t funcExportIndex);
+    explicit Export(UniqueChars fieldName, DefinitionKind kind);
 
-    ExportMap() : startExportIndex(NO_START_FUNCTION) {}
+    const char* fieldName() const { return fieldName_.get(); }
 
-    bool hasStartFunction() const {
-        return startExportIndex != NO_START_FUNCTION;
-    }
-    void setStartFunction(uint32_t index) {
-        MOZ_ASSERT(!hasStartFunction());
-        startExportIndex = index;
-    }
-    uint32_t startFunctionExportIndex() const {
-        MOZ_ASSERT(hasStartFunction());
-        return startExportIndex;
-    }
+    DefinitionKind kind() const { return pod.kind_; }
+    uint32_t funcExportIndex() const;
 
-    WASM_DECLARE_SERIALIZABLE(ExportMap)
+    WASM_DECLARE_SERIALIZABLE(Export)
 };
 
+typedef Vector<Export, 0, SystemAllocPolicy> ExportVector;
+
 // DataSegment describes the offset of a data segment in the bytecode that is
 // to be copied at a given offset into linear memory upon instantiation.
 
 struct DataSegment
 {
     uint32_t memoryOffset;
     uint32_t bytecodeOffset;
     uint32_t length;
@@ -189,38 +178,38 @@ typedef Vector<ElemSegment, 0, SystemAll
 // time it is instantiated. In the future, Module will store a shareable,
 // immutable CodeSegment that can be shared by all its instances.
 
 class Module
 {
     const Bytes             code_;
     const LinkData          linkData_;
     const ImportVector      imports_;
-    const ExportMap         exportMap_;
+    const ExportVector      exports_;
     const DataSegmentVector dataSegments_;
     const ElemSegmentVector elemSegments_;
     const SharedMetadata    metadata_;
     const SharedBytes       bytecode_;
 
     bool instantiateMemory(JSContext* cx, MutableHandleWasmMemoryObject memory) const;
     bool instantiateTable(JSContext* cx, const CodeSegment& cs, SharedTableVector* tables) const;
 
   public:
     Module(Bytes&& code,
            LinkData&& linkData,
            ImportVector&& imports,
-           ExportMap&& exportMap,
+           ExportVector&& exports,
            DataSegmentVector&& dataSegments,
            ElemSegmentVector&& elemSegments,
            const Metadata& metadata,
            const ShareableBytes& bytecode)
       : code_(Move(code)),
         linkData_(Move(linkData)),
         imports_(Move(imports)),
-        exportMap_(Move(exportMap)),
+        exports_(Move(exports)),
         dataSegments_(Move(dataSegments)),
         elemSegments_(Move(elemSegments)),
         metadata_(&metadata),
         bytecode_(&bytecode)
     {}
 
     const Metadata& metadata() const { return *metadata_; }
     const ImportVector& imports() const { return imports_; }
--- a/js/src/asmjs/WasmStubs.cpp
+++ b/js/src/asmjs/WasmStubs.cpp
@@ -91,17 +91,17 @@ static const unsigned FramePushedAfterSa
 #endif
 static const unsigned FramePushedForEntrySP = FramePushedAfterSave + sizeof(void*);
 
 // Generate a stub that enters wasm from a C++ caller via the native ABI.
 // The signature of the entry point is Module::CodePtr. The exported wasm
 // function has an ABI derived from its specific signature, so this function
 // must map from the ABI of CodePtr to the export's signature's ABI.
 Offsets
-wasm::GenerateEntry(MacroAssembler& masm, const Export& exp, bool usesHeap)
+wasm::GenerateEntry(MacroAssembler& masm, const FuncExport& fe, bool usesHeap)
 {
     masm.haltingAlign(CodeAlignment);
 
     Offsets offsets;
     offsets.begin = masm.currentOffset();
 
     // Save the return address if it wasn't already saved by the call insn.
 #if defined(JS_CODEGEN_ARM)
@@ -156,21 +156,21 @@ wasm::GenerateEntry(MacroAssembler& masm
     masm.storeStackPtr(Address(scratch, WasmActivation::offsetOfEntrySP()));
 
     // Dynamically align the stack since ABIStackAlignment is not necessarily
     // AsmJSStackAlignment. We'll use entrySP to recover the original stack
     // pointer on return.
     masm.andToStackPtr(Imm32(~(AsmJSStackAlignment - 1)));
 
     // Bump the stack for the call.
-    masm.reserveStack(AlignBytes(StackArgBytes(exp.sig().args()), AsmJSStackAlignment));
+    masm.reserveStack(AlignBytes(StackArgBytes(fe.sig().args()), AsmJSStackAlignment));
 
     // Copy parameters out of argv and into the registers/stack-slots specified by
     // the system ABI.
-    for (ABIArgValTypeIter iter(exp.sig().args()); !iter.done(); iter++) {
+    for (ABIArgValTypeIter iter(fe.sig().args()); !iter.done(); iter++) {
         unsigned argOffset = iter.index() * sizeof(ExportArg);
         Address src(argv, argOffset);
         MIRType type = iter.mirType();
         MOZ_ASSERT_IF(type == MIRType::Int64, JitOptions.wasmTestMode);
         switch (iter->kind()) {
           case ABIArg::GPR:
             if (type == MIRType::Int32)
                 masm.load32(src, iter->gpr());
@@ -248,28 +248,28 @@ wasm::GenerateEntry(MacroAssembler& masm
                 MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unexpected stack arg type");
             }
             break;
         }
     }
 
     // Call into the real function.
     masm.assertStackAlignment(AsmJSStackAlignment);
-    masm.call(CallSiteDesc(CallSiteDesc::Relative), exp.funcIndex());
+    masm.call(CallSiteDesc(CallSiteDesc::Relative), fe.funcIndex());
 
     // Recover the stack pointer value before dynamic alignment.
     masm.loadWasmActivation(scratch);
     masm.loadStackPtr(Address(scratch, WasmActivation::offsetOfEntrySP()));
     masm.setFramePushed(FramePushedForEntrySP);
 
     // Recover the 'argv' pointer which was saved before aligning the stack.
     masm.Pop(argv);
 
     // Store the return value in argv[0]
-    switch (exp.sig().ret()) {
+    switch (fe.sig().ret()) {
       case ExprType::Void:
         break;
       case ExprType::I32:
         masm.store32(ReturnReg, Address(argv, 0));
         break;
       case ExprType::I64:
         MOZ_ASSERT(JitOptions.wasmTestMode, "no int64 in asm.js/wasm");
         masm.store64(ReturnReg64, Address(argv, 0));
--- a/js/src/asmjs/WasmStubs.h
+++ b/js/src/asmjs/WasmStubs.h
@@ -22,21 +22,21 @@
 #include "asmjs/WasmTypes.h"
 
 namespace js {
 
 namespace jit { class MacroAssembler; }
 
 namespace wasm {
 
-class Export;
+class FuncExport;
 class FuncImport;
 
 extern Offsets
-GenerateEntry(jit::MacroAssembler& masm, const Export& exp, bool usesHeap);
+GenerateEntry(jit::MacroAssembler& masm, const FuncExport& fe, bool usesHeap);
 
 extern ProfilingOffsets
 GenerateInterpExit(jit::MacroAssembler& masm, const FuncImport& fi, uint32_t funcImportIndex);
 
 extern ProfilingOffsets
 GenerateJitExit(jit::MacroAssembler& masm, const FuncImport& fi, bool usesHeap);
 
 extern Offsets
--- a/js/src/asmjs/WasmTextToBinary.cpp
+++ b/js/src/asmjs/WasmTextToBinary.cpp
@@ -2480,18 +2480,20 @@ ParseExport(WasmParseContext& c)
         return nullptr;
 
     WasmToken exportee = c.ts.get();
     switch (exportee.kind()) {
       case WasmToken::Index:
         return new(c.lifo) AstExport(name.text(), AstRef(AstName(), exportee.index()));
       case WasmToken::Name:
         return new(c.lifo) AstExport(name.text(), AstRef(exportee.name(), AstNoIndex));
+      case WasmToken::Table:
+        return new(c.lifo) AstExport(name.text(), DefinitionKind::Table);
       case WasmToken::Memory:
-        return new(c.lifo) AstExport(name.text());
+        return new(c.lifo) AstExport(name.text(), DefinitionKind::Memory);
       default:
         break;
     }
 
     c.ts.generateError(exportee, c.error);
     return nullptr;
 
 }
@@ -3070,16 +3072,17 @@ ResolveModule(LifoAlloc& lifo, AstModule
             return r.fail("duplicate import");
 
         switch (imp->kind()) {
           case DefinitionKind::Function:
             if (!r.resolveSignature(imp->funcSig()))
                 return false;
             break;
           case DefinitionKind::Memory:
+          case DefinitionKind::Table:
             break;
         }
     }
 
     for (AstExport* export_ : module->exports()) {
         if (export_->kind() != DefinitionKind::Function)
             continue;
         if (!r.resolveFunction(export_->func()))
@@ -3549,16 +3552,18 @@ EncodeImport(Encoder& e, bool newFormat,
     if (!e.writeVarU32(uint32_t(imp.kind())))
         return false;
 
     switch (imp.kind()) {
       case DefinitionKind::Function:
         if (!e.writeVarU32(imp.funcSig().index()))
             return false;
         break;
+      case DefinitionKind::Table:
+        MOZ_CRASH("NYI");
       case DefinitionKind::Memory:
         if (!EncodeResizable(e, imp.memory()))
             return false;
         break;
     }
 
     return true;
 }
@@ -3646,16 +3651,17 @@ EncodeExport(Encoder& e, bool newFormat,
     if (!e.writeVarU32(uint32_t(exp.kind())))
         return false;
 
     switch (exp.kind()) {
       case DefinitionKind::Function:
         if (!e.writeVarU32(exp.func().index()))
             return false;
         break;
+      case DefinitionKind::Table:
       case DefinitionKind::Memory:
         if (!e.writeVarU32(0))
             return false;
         break;
     }
 
     return true;
 }
--- a/js/src/jit-test/tests/wasm/basic.js
+++ b/js/src/jit-test/tests/wasm/basic.js
@@ -24,18 +24,18 @@ assertEq(desc.enumerable, true);
 assertEq(desc.configurable, true);
 assertEq(desc.value(), undefined);
 
 wasmEvalText('(module (func) (func) (export "a" 0))');
 wasmEvalText('(module (func) (func) (export "a" 1))');
 wasmEvalText('(module (func $a) (func $b) (export "a" $a) (export "b" $b))');
 wasmEvalText('(module (func $a) (func $b) (export "a" $a) (export "b" $b))');
 
-assertErrorMessage(() => wasmEvalText('(module (func) (export "a" 1))'), TypeError, /export function index out of range/);
-assertErrorMessage(() => wasmEvalText('(module (func) (func) (export "a" 2))'), TypeError, /export function index out of range/);
+assertErrorMessage(() => wasmEvalText('(module (func) (export "a" 1))'), TypeError, /exported function index out of bounds/);
+assertErrorMessage(() => wasmEvalText('(module (func) (func) (export "a" 2))'), TypeError, /exported function index out of bounds/);
 
 var o = wasmEvalText('(module (func) (export "a" 0) (export "b" 0))');
 assertEq(Object.getOwnPropertyNames(o).sort().toString(), "a,b");
 assertEq(o.a.name, "wasm-function[0]");
 assertEq(o.b.name, "wasm-function[0]");
 assertEq(o.a === o.b, true);
 
 var o = wasmEvalText('(module (func) (func) (export "a" 0) (export "b" 1))');
--- a/js/src/jit-test/tests/wasm/import-export.js
+++ b/js/src/jit-test/tests/wasm/import-export.js
@@ -51,16 +51,17 @@ assertEq(new Instance(m3, {baz:{quux:()=
 const m5 = new Module(textToBinary('(module (import "a" "b" (memory 2)))'));
 assertErrorMessage(() => new Instance(m5, {a:{b:mem1Page}}), TypeError, /imported Memory with incompatible size/);
 assertEq(new Instance(m5, {a:{b:mem2Page}}) instanceof Instance, true);
 assertEq(new Instance(m5, {a:{b:mem3Page}}) instanceof Instance, true);
 assertEq(new Instance(m5, {a:{b:mem4Page}}) instanceof Instance, true);
 
 assertErrorMessage(() => new Module(textToBinary('(module (memory 2 1))')), TypeError, /maximum length less than initial length/);
 assertErrorMessage(() => new Module(textToBinary('(module (import "a" "b" (memory 2 1)))')), TypeError, /maximum length less than initial length/);
+assertErrorMessage(() => new Module(textToBinary('(module (table (resizable 2 1)))')), TypeError, /maximum length less than initial length/);
 
 // Import order:
 
 var arr = [];
 var importObj = {
     get foo() { arr.push("foo") },
     get baz() { arr.push("bad") },
 };
@@ -153,24 +154,67 @@ assertEq(e.foo(), undefined);
 assertEq(e.bar.buffer.byteLength, 64*1024);
 
 var code = textToBinary('(module (memory 1 1) (export "" memory))');
 var e = new Instance(new Module(code)).exports;
 assertEq(Object.keys(e).length, 1);
 assertEq(String(Object.keys(e)), "");
 assertEq(e[""] instanceof Memory, true);
 
+var code = textToBinary('(module (table) (export "tbl" table))');
+var e = new Instance(new Module(code)).exports;
+assertEq(Object.keys(e).join(), "tbl");
+assertEq(e.tbl instanceof Table, true);
+assertEq(e.tbl.length, 0);
+
+var code = textToBinary('(module (table (resizable 2)) (export "t1" table) (export "t2" table))');
+var e = new Instance(new Module(code)).exports;
+assertEq(Object.keys(e).join(), "t1,t2");
+assertEq(e.t1 instanceof Table, true);
+assertEq(e.t2 instanceof Table, true);
+assertEq(e.t1, e.t2);
+assertEq(e.t1.length, 2);
+
+var code = textToBinary('(module (table (resizable 2)) (memory 1 1) (func) (export "t" table) (export "m" memory) (export "f" 0))');
+var e = new Instance(new Module(code)).exports;
+assertEq(Object.keys(e).join(), "t,m,f");
+assertEq(e.f(), undefined);
+assertEq(e.t instanceof Table, true);
+assertEq(e.m instanceof Memory, true);
+assertEq(e.t.length, 2);
+
+var code = textToBinary('(module (table (resizable 1)) (memory 1 1) (func) (export "m" memory) (export "f" 0) (export "t" table))');
+var e = new Instance(new Module(code)).exports;
+assertEq(Object.keys(e).join(), "m,f,t");
+assertEq(e.f(), undefined);
+assertEq(e.t instanceof Table, true);
+assertEq(e.m instanceof Memory, true);
++assertEq(e.t.length, 1);
+
+var code = textToBinary('(module (table) (export "" table))');
+var e = new Instance(new Module(code)).exports;
+assertEq(Object.keys(e).length, 1);
+assertEq(String(Object.keys(e)), "");
+assertEq(e[""] instanceof Table, true);
++assertEq(e[""].length, 0);
+
 // Re-exports:
 
 var code = textToBinary('(module (import "a" "b" (memory 1 1)) (export "foo" memory) (export "bar" memory))');
 var mem = new Memory({initial:1});
 var e = new Instance(new Module(code), {a:{b:mem}}).exports;
 assertEq(mem, e.foo);
 assertEq(mem, e.bar);
 
+// Non-existent export errors
+
+assertErrorMessage(() => new Module(textToBinary('(module (export "a" 0))')), TypeError, /exported function index out of bounds/);
+assertErrorMessage(() => new Module(textToBinary('(module (export "a" memory))')), TypeError, /exported memory index out of bounds/);
+assertErrorMessage(() => new Module(textToBinary('(module (export "a" table))')), TypeError, /exported table index out of bounds/);
+
 // Default memory rules
 
 assertErrorMessage(() => new Module(textToBinary('(module (import "a" "b" (memory 1 1)) (memory 1 1))')), TypeError, /already have default memory/);
 assertErrorMessage(() => new Module(textToBinary('(module (import "a" "b" (memory 1 1)) (import "x" "y" (memory 2 2)))')), TypeError, /already have default memory/);
 
 // Data segments on imports
 
 var m = new Module(textToBinary(`
--- a/js/src/jit-test/tests/wasm/jsapi.js
+++ b/js/src/jit-test/tests/wasm/jsapi.js
@@ -190,8 +190,23 @@ assertEq(tableProto, tableProtoDesc.valu
 assertEq(String(tableProto), "[object Object]");
 assertEq(Object.getPrototypeOf(tableProto), Object.prototype);
 
 // 'WebAssembly.Table' instance objects
 const tbl1 = new Table({initial:1});
 assertEq(typeof tbl1, "object");
 assertEq(String(tbl1), "[object WebAssembly.Table]");
 assertEq(Object.getPrototypeOf(tbl1), tableProto);
+
+// 'WebAssembly.Table.prototype.length' accessor property
+const lengthDesc = Object.getOwnPropertyDescriptor(tableProto, 'length');
+assertEq(typeof lengthDesc.get, "function");
+assertEq(lengthDesc.set, undefined);
+assertEq(lengthDesc.enumerable, false);
+assertEq(lengthDesc.configurable, true);
+
+// 'WebAssembly.Table.prototype.length' getter
+const lengthGetter = lengthDesc.get;
+assertErrorMessage(() => lengthGetter.call(), TypeError, /called on incompatible undefined/);
+assertErrorMessage(() => lengthGetter.call({}), TypeError, /called on incompatible Object/);
+assertEq(typeof lengthGetter.call(tbl1), "number");
+assertEq(lengthGetter.call(tbl1), 1);
+
--- a/layout/base/DisplayListClipState.cpp
+++ b/layout/base/DisplayListClipState.cpp
@@ -31,29 +31,48 @@ DisplayListClipState::GetCurrentCombined
   } else {
     mCurrentCombinedClip =
       aBuilder->AllocateDisplayItemClip(*mClipContainingBlockDescendants);
   }
   return mCurrentCombinedClip;
 }
 
 void
+DisplayListClipState::SetScrollClipForContainingBlockDescendants(
+    nsDisplayListBuilder* aBuilder,
+    const DisplayItemScrollClip* aScrollClip)
+{
+  if (aBuilder->IsPaintingToWindow() &&
+      mClipContentDescendants &&
+      aScrollClip != mScrollClipContainingBlockDescendants &&
+      !DisplayItemScrollClip::IsAncestor(mClipContentDescendantsScrollClip, aScrollClip)) {
+    if (mClipContentDescendantsScrollClip && mClipContentDescendantsScrollClip->mScrollableFrame) {
+      mClipContentDescendantsScrollClip->mScrollableFrame->SetScrollsClipOnUnscrolledOutOfFlow();
+    }
+    mClipContentDescendantsScrollClip = nullptr;
+  }
+  mScrollClipContainingBlockDescendants = aScrollClip;
+  mStackingContextAncestorSC = DisplayItemScrollClip::PickAncestor(mStackingContextAncestorSC, aScrollClip);
+}
+
+void
 DisplayListClipState::ClipContainingBlockDescendants(const nsRect& aRect,
                                                      const nscoord* aRadii,
                                                      DisplayItemClip& aClipOnStack)
 {
   if (aRadii) {
     aClipOnStack.SetTo(aRect, aRadii);
   } else {
     aClipOnStack.SetTo(aRect);
   }
   if (mClipContainingBlockDescendants) {
     aClipOnStack.IntersectWith(*mClipContainingBlockDescendants);
   }
   mClipContainingBlockDescendants = &aClipOnStack;
+  mClipContentDescendantsScrollClip = GetCurrentInnermostScrollClip();
   mCurrentCombinedClip = nullptr;
 }
 
 void
 DisplayListClipState::ClipContentDescendants(const nsRect& aRect,
                                              const nscoord* aRadii,
                                              DisplayItemClip& aClipOnStack)
 {
@@ -192,11 +211,13 @@ DisplayListClipState::InsertInactiveScro
 DisplayListClipState::AutoSaveRestore::AutoSaveRestore(nsDisplayListBuilder* aBuilder)
   : mState(aBuilder->ClipState())
   , mSavedState(aBuilder->ClipState())
 #ifdef DEBUG
   , mClipUsed(false)
   , mRestored(false)
 #endif
   , mClearedForStackingContextContents(false)
-{}
+{
+  mState.mStackingContextAncestorSC = mState.GetCurrentInnermostScrollClip();
+}
 
 } // namespace mozilla
--- a/layout/base/DisplayListClipState.h
+++ b/layout/base/DisplayListClipState.h
@@ -24,16 +24,17 @@ namespace mozilla {
 class DisplayListClipState {
 public:
   DisplayListClipState()
     : mClipContentDescendants(nullptr)
     , mClipContainingBlockDescendants(nullptr)
     , mCurrentCombinedClip(nullptr)
     , mScrollClipContentDescendants(nullptr)
     , mScrollClipContainingBlockDescendants(nullptr)
+    , mClipContentDescendantsScrollClip(nullptr)
     , mStackingContextAncestorSC(nullptr)
   {}
 
   /**
    * Returns intersection of mClipContainingBlockDescendants and
    * mClipContentDescendants, allocated on aBuilder's arena.
    */
   const DisplayItemClip* GetCurrentCombinedClip(nsDisplayListBuilder* aBuilder);
@@ -69,21 +70,18 @@ public:
 
 private:
   void SetClipForContainingBlockDescendants(const DisplayItemClip* aClip)
   {
     mClipContainingBlockDescendants = aClip;
     mCurrentCombinedClip = nullptr;
   }
 
-  void SetScrollClipForContainingBlockDescendants(const DisplayItemScrollClip* aScrollClip)
-  {
-    mScrollClipContainingBlockDescendants = aScrollClip;
-    mStackingContextAncestorSC = DisplayItemScrollClip::PickAncestor(mStackingContextAncestorSC, aScrollClip);
-  }
+  void SetScrollClipForContainingBlockDescendants(nsDisplayListBuilder* aBuilder,
+                                                  const DisplayItemScrollClip* aScrollClip);
 
   void Clear()
   {
     mClipContentDescendants = nullptr;
     mClipContainingBlockDescendants = nullptr;
     mCurrentCombinedClip = nullptr;
     // We do not clear scroll clips.
   }
@@ -179,16 +177,21 @@ private:
 
   /**
    * The same for scroll clips.
    */
   const DisplayItemScrollClip* mScrollClipContentDescendants;
   const DisplayItemScrollClip* mScrollClipContainingBlockDescendants;
 
   /**
+   * The scroll clip that was in effect when mClipContentDescendants was set.
+   */
+  const DisplayItemScrollClip* mClipContentDescendantsScrollClip;
+
+  /**
    * A scroll clip that is an ancestor of all the scroll clips that were
    * "current" on this clip state since EnterStackingContextContents was
    * called.
    */
   const DisplayItemScrollClip* mStackingContextAncestorSC;
 };
 
 /**
@@ -426,19 +429,20 @@ public:
   /**
    * *aClip must survive longer than this object. Be careful!!!
    */
   void SetClipForContainingBlockDescendants(const DisplayItemClip* aClip)
   {
     mState.SetClipForContainingBlockDescendants(aClip);
   }
 
-  void SetScrollClipForContainingBlockDescendants(const DisplayItemScrollClip* aScrollClip)
+  void SetScrollClipForContainingBlockDescendants(nsDisplayListBuilder* aBuilder,
+                                                  const DisplayItemScrollClip* aScrollClip)
   {
-    mState.SetScrollClipForContainingBlockDescendants(aScrollClip);
+    mState.SetScrollClipForContainingBlockDescendants(aBuilder, aScrollClip);
   }
 
   /**
    * Intersects the given clip rect (with optional aRadii) with the current
    * mClipContainingBlockDescendants and sets mClipContainingBlockDescendants to
    * the result, stored in aClipOnStack.
    */
   void ClipContainingBlockDescendantsExtra(const nsRect& aRect,
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -2594,17 +2594,18 @@ nsIFrame::BuildDisplayListForStackingCon
 
   CreateOwnLayerIfNeeded(aBuilder, &resultList);
 
   aList->AppendToTop(&resultList);
 }
 
 static nsDisplayItem*
 WrapInWrapList(nsDisplayListBuilder* aBuilder,
-               nsIFrame* aFrame, nsDisplayList* aList)
+               nsIFrame* aFrame, nsDisplayList* aList,
+               const DisplayItemScrollClip* aScrollClip)
 {
   nsDisplayItem* item = aList->GetBottom();
   if (!item) {
     return nullptr;
   }
 
   // For perspective items we want to treat the 'frame' as being the transform
   // frame that created it. This stops the transform frame from wrapping another
@@ -2612,17 +2613,17 @@ WrapInWrapList(nsDisplayListBuilder* aBu
   // makes the perspective frame create one (so we have an atomic entry for z-index
   // sorting).
   nsIFrame *itemFrame = item->Frame();
   if (item->GetType() == nsDisplayItem::TYPE_PERSPECTIVE) {
     itemFrame = static_cast<nsDisplayPerspective*>(item)->TransformFrame();
   }
 
   if (item->GetAbove() || itemFrame != aFrame) {
-    return new (aBuilder) nsDisplayWrapList(aBuilder, aFrame, aList);
+    return new (aBuilder) nsDisplayWrapList(aBuilder, aFrame, aList, aScrollClip);
   }
   aList->RemoveBottom();
   return item;
 }
 
 void
 nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder*   aBuilder,
                                    nsIFrame*               aChild,
@@ -2798,32 +2799,32 @@ nsIFrame::BuildDisplayListForChild(nsDis
   DisplayListClipState::AutoClipMultiple clipState(aBuilder);
   CheckForApzAwareEventHandlers(aBuilder, child);
 
   if (savedOutOfFlowData) {
     aBuilder->SetBuildingInvisibleItems(false);
 
     clipState.SetClipForContainingBlockDescendants(
       &savedOutOfFlowData->mContainingBlockClip);
-    clipState.SetScrollClipForContainingBlockDescendants(
+    clipState.SetScrollClipForContainingBlockDescendants(aBuilder,
       savedOutOfFlowData->mContainingBlockScrollClip);
   } else if (GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO &&
              isPlaceholder) {
     NS_ASSERTION(dirty.IsEmpty(), "should have empty dirty rect");
     // Every item we build from now until we descent into an out of flow that
     // does have saved out of flow data should be invisible. This state gets
     // restored when AutoBuildingDisplayList gets out of scope.
     aBuilder->SetBuildingInvisibleItems(true);
 
     // If we have nested out-of-flow frames and the outer one isn't visible
     // then we won't have stored clip data for it. We can just clear the clip
     // instead since we know we won't render anything, and the inner out-of-flow
     // frame will setup the correct clip for itself.
     clipState.SetClipForContainingBlockDescendants(nullptr);
-    clipState.SetScrollClipForContainingBlockDescendants(nullptr);
+    clipState.SetScrollClipForContainingBlockDescendants(aBuilder, nullptr);
   }
 
   // Setup clipping for the parent's overflow:-moz-hidden-unscrollable,
   // or overflow:hidden on elements that don't support scrolling (and therefore
   // don't create nsHTML/XULScrollFrame). This clipping needs to not clip
   // anything directly rendered by the parent, only the rendering of its
   // children.
   // Don't use overflowClip to restrict the dirty rect, since some of the
@@ -2903,36 +2904,39 @@ nsIFrame::BuildDisplayListForChild(nsDis
     list.AppendToTop(pseudoStack.Outlines());
     extraPositionedDescendants.AppendToTop(pseudoStack.PositionedDescendants());
 #ifdef DEBUG
     DisplayDebugBorders(aBuilder, child, aLists);
 #endif
   }
 
   buildingForChild.RestoreBuildingInvisibleItemsValue();
-
+ 
   // Clear clip rect for the construction of the items below. Since we're
   // clipping all their contents, they themselves don't need to be clipped.
   clipState.Clear();
 
+  const DisplayItemScrollClip* containerItemScrollClip =
+    aBuilder->ClipState().CurrentAncestorScrollClipForStackingContextContents();
+
   if (isPositioned || isVisuallyAtomic ||
       (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT)) {
     // Genuine stacking contexts, and positioned pseudo-stacking-contexts,
     // go in this level.
     if (!list.IsEmpty()) {
-      nsDisplayItem* item = WrapInWrapList(aBuilder, child, &list);
+      nsDisplayItem* item = WrapInWrapList(aBuilder, child, &list, containerItemScrollClip);
       if (isSVG) {
         aLists.Content()->AppendNewToTop(item);
       } else {
         aLists.PositionedDescendants()->AppendNewToTop(item);
       }
     }
   } else if (!isSVG && disp->IsFloating(child)) {
     if (!list.IsEmpty()) {
-      aLists.Floats()->AppendNewToTop(WrapInWrapList(aBuilder, child, &list));
+      aLists.Floats()->AppendNewToTop(WrapInWrapList(aBuilder, child, &list, containerItemScrollClip));
     }
   } else {
     aLists.Content()->AppendToTop(&list);
   }
   // We delay placing the positioned descendants of positioned frames to here,
   // because in the absence of z-index this is the correct order for them.
   // This doesn't affect correctness because the positioned descendants list
   // is sorted by z-order and content in BuildDisplayListForStackingContext,
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -1886,16 +1886,17 @@ ScrollFrameHelper::ScrollFrameHelper(nsC
   , mWillBuildScrollableLayer(false)
   , mIsScrollParent(false)
   , mIsScrollableLayerInRootContainer(false)
   , mHasBeenScrolled(false)
   , mIgnoreMomentumScroll(false)
   , mTransformingByAPZ(false)
   , mScrollableByAPZ(false)
   , mZoomableByAPZ(false)
+  , mScrollsClipOnUnscrolledOutOfFlow(false)
   , mVelocityQueue(aOuter->PresContext())
   , mAsyncScrollEvent(END_DOM)
 {
   if (LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars) != 0) {
     mScrollbarActivity = new ScrollbarActivity(do_QueryFrame(aOuter));
   }
 
   EnsureFrameVisPrefsCached();
@@ -2114,16 +2115,22 @@ ScrollFrameHelper::HasPluginFrames()
 bool
 ScrollFrameHelper::HasPerspective() const
 {
   const nsStyleDisplay* disp = mOuter->StyleDisplay();
   return disp->mChildPerspective.GetUnit() != eStyleUnit_None;
 }
 
 void
+ScrollFrameHelper::SetScrollsClipOnUnscrolledOutOfFlow()
+{
+  mScrollsClipOnUnscrolledOutOfFlow = true;
+}
+
+void
 ScrollFrameHelper::ScrollToCSSPixels(const CSSIntPoint& aScrollPosition,
                                      nsIScrollableFrame::ScrollMode aMode)
 {
   nsPoint current = GetScrollPosition();
   CSSIntPoint currentCSSPixels = GetScrollPositionCSSPixels();
   nsPoint pt = CSSPoint::ToAppUnits(aScrollPosition);
   nscoord halfPixel = nsPresContext::CSSPixelsToAppUnits(0.5f);
   nsRect range(pt.x - halfPixel, pt.y - halfPixel, 2*halfPixel - 1, 2*halfPixel - 1);
@@ -2750,21 +2757,21 @@ ScrollFrameHelper::ScrollToImpl(nsPoint 
     // that needs to be painted. So even if the final tile-aligned displayport
     // is the same, we force a repaint for these elements. Bug 1254260 tracks
     // fixing this properly.
     nsRect displayPort;
     bool usingDisplayPort =
       nsLayoutUtils::GetHighResolutionDisplayPort(content, &displayPort);
     displayPort.MoveBy(-mScrolledFrame->GetPosition());
 
-    PAINT_SKIP_LOG("New scrollpos %s usingDP %d dpEqual %d scrollableByApz %d plugins %d perspective %d\n",
+    PAINT_SKIP_LOG("New scrollpos %s usingDP %d dpEqual %d scrollableByApz %d plugins %d perspective %d clip %d\n",
         Stringify(CSSPoint::FromAppUnits(GetScrollPosition())).c_str(),
         usingDisplayPort, displayPort.IsEqualEdges(oldDisplayPort),
-        mScrollableByAPZ, HasPluginFrames(), HasPerspective());
-    if (usingDisplayPort && displayPort.IsEqualEdges(oldDisplayPort) && !HasPerspective()) {
+        mScrollableByAPZ, HasPluginFrames(), HasPerspective(), mScrollsClipOnUnscrolledOutOfFlow);
+    if (usingDisplayPort && displayPort.IsEqualEdges(oldDisplayPort) && !HasPerspective() && !mScrollsClipOnUnscrolledOutOfFlow) {
       bool haveScrollLinkedEffects = content->GetComposedDoc()->HasScrollLinkedEffect();
       bool apzDisabled = haveScrollLinkedEffects && gfxPrefs::APZDisableForScrollLinkedEffects();
       if (!apzDisabled) {
         if (LastScrollOrigin() == nsGkAtoms::apz) {
           schedulePaint = false;
           PAINT_SKIP_LOG("Skipping due to APZ scroll\n");
         } else if (mScrollableByAPZ && !HasPluginFrames()) {
           nsIWidget* widget = presContext->GetNearestWidget();
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -381,16 +381,17 @@ public:
     }
     NotifyPluginFrames(aTransforming ? BEGIN_APZ : END_APZ);
   }
   bool IsTransformingByAPZ() const {
     return mTransformingByAPZ;
   }
   void SetScrollableByAPZ(bool aScrollable);
   void SetZoomableByAPZ(bool aZoomable);
+  void SetScrollsClipOnUnscrolledOutOfFlow();
 
   bool UsesContainerScrolling() const;
 
   ScrollSnapInfo GetScrollSnapInfo() const;
 
   bool DecideScrollableLayer(nsDisplayListBuilder* aBuilder,
                              nsRect* aDirtyRect,
                              bool aAllowCreateDisplayPort);
@@ -576,16 +577,18 @@ public:
   bool mScrollableByAPZ:1;
 
   // True if the APZ is allowed to zoom this scrollframe.
   bool mZoomableByAPZ:1;
 
   // True if we don't want the scrollbar to repaint itself right now.
   bool mSuppressScrollbarRepaints:1;
 
+  bool mScrollsClipOnUnscrolledOutOfFlow:1;
+
   mozilla::layout::ScrollVelocityQueue mVelocityQueue;
 
 protected:
   class AutoScrollbarRepaintSuppression;
   friend class AutoScrollbarRepaintSuppression;
   class AutoScrollbarRepaintSuppression {
   public:
     AutoScrollbarRepaintSuppression(ScrollFrameHelper* aHelper, bool aSuppress)
@@ -1001,16 +1004,19 @@ public:
     return mHelper.IsTransformingByAPZ();
   }
   void SetScrollableByAPZ(bool aScrollable) override {
     mHelper.SetScrollableByAPZ(aScrollable);
   }
   void SetZoomableByAPZ(bool aZoomable) override {
     mHelper.SetZoomableByAPZ(aZoomable);
   }
+  void SetScrollsClipOnUnscrolledOutOfFlow() override {
+    mHelper.SetScrollsClipOnUnscrolledOutOfFlow();
+  }
   
   ScrollSnapInfo GetScrollSnapInfo() const override {
     return mHelper.GetScrollSnapInfo();
   }
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override;
 #endif
@@ -1404,16 +1410,19 @@ public:
     return mHelper.IsTransformingByAPZ();
   }
   void SetScrollableByAPZ(bool aScrollable) override {
     mHelper.SetScrollableByAPZ(aScrollable);
   }
   void SetZoomableByAPZ(bool aZoomable) override {
     mHelper.SetZoomableByAPZ(aZoomable);
   }
+  void SetScrollsClipOnUnscrolledOutOfFlow() override {
+    mHelper.SetScrollsClipOnUnscrolledOutOfFlow();
+  }
   virtual bool DecideScrollableLayer(nsDisplayListBuilder* aBuilder,
                                      nsRect* aDirtyRect,
                                      bool aAllowCreateDisplayPort) override {
     return mHelper.DecideScrollableLayer(aBuilder, aDirtyRect, aAllowCreateDisplayPort);
   }
   virtual void NotifyApproximateFrameVisibilityUpdate() override {
     mHelper.NotifyApproximateFrameVisibilityUpdate();
   }
--- a/layout/generic/nsIScrollableFrame.h
+++ b/layout/generic/nsIScrollableFrame.h
@@ -459,11 +459,13 @@ public:
    * own displayport and schedule a timer to do that if it is safe.
    */
   virtual void TriggerDisplayPortExpiration() = 0;
 
   /**
    * Returns information required to determine where to snap to after a scroll.
    */
   virtual ScrollSnapInfo GetScrollSnapInfo() const = 0;
+
+  virtual void SetScrollsClipOnUnscrolledOutOfFlow() = 0;
 };
 
 #endif
--- a/layout/generic/nsViewportFrame.cpp
+++ b/layout/generic/nsViewportFrame.cpp
@@ -102,17 +102,17 @@ BuildDisplayListForTopLayerFrame(nsDispl
   DisplayListClipState::AutoClipMultiple clipState(aBuilder);
   nsDisplayListBuilder::OutOfFlowDisplayData*
     savedOutOfFlowData = nsDisplayListBuilder::GetOutOfFlowData(aFrame);
   if (savedOutOfFlowData) {
     dirty = savedOutOfFlowData->mDirtyRect;
     clipState.SetClipForContainingBlockDescendants(
       &savedOutOfFlowData->mContainingBlockClip);
     clipState.SetScrollClipForContainingBlockDescendants(
-      savedOutOfFlowData->mContainingBlockScrollClip);
+      aBuilder, savedOutOfFlowData->mContainingBlockScrollClip);
   }
   nsDisplayList list;
   aFrame->BuildDisplayListForStackingContext(aBuilder, dirty, &list);
   aList->AppendToTop(&list);
 }
 
 void
 ViewportFrame::BuildDisplayListForTopLayer(nsDisplayListBuilder* aBuilder,
--- a/layout/printing/crashtests/crashtests.list
+++ b/layout/printing/crashtests/crashtests.list
@@ -1,4 +1,4 @@
 load 509839-1.html
 load 509839-2.html
-load 576878.xhtml
+asserts-if(browserIsRemote,4) load 576878.xhtml
 load 793844.html
--- a/layout/reftests/css-parsing/invalid-url-handling.xhtml
+++ b/layout/reftests/css-parsing/invalid-url-handling.xhtml
@@ -17,27 +17,29 @@
   </style>
   <style type="text/css">
   /* not a URI token, but handled according to rules for parsing errors */
   #foo { background: url(foo"bar
   ) }
   #two { background-color: green; }
   </style>
   <style type="text/css">
-  /* not a URI token; the unterminated string ends at end of line, so
-     the brace never matches */
+  /* not a URI token, the invalid URI token consumes everything up to the ')'. */
+  #three { background-color: red; }
+  #foo { background: url(foo"bar) }
   #three { background-color: green; }
-  #foo { background: url(foo"bar) }
-  #three { background-color: red; }
   </style>
   <style type="text/css">
-  /* not a URI token; the unterminated string ends at end of line */
+  #four { background-color: green; }
+  /* not a URI token; the invalid URI token consumes everything up to the ')'
+     and then there is some garbage that prevents the next rule from being
+     parsed. */
   #foo { background: url(foo"bar) }
   ) }
-  #four { background-color: green; }
+  #four { background-color: red; }
   </style>
   <style type="text/css">
   /* not a URI token; the unterminated string ends at end of line, so
      the brace never matches */
   #five { background-color: green; }
   #foo { background: url("bar) }
   #five { background-color: red; }
   </style>
@@ -63,28 +65,30 @@
   /* perfectly good URI token (image is a 404, though) */
   #ten { background: url({) green; }
   </style>
   <style type="text/css">
   /* perfectly good URI token (image is a 404, though) */
   #eleven { background: url([) green; }
   </style>
   <style type="text/css">
-  /* not a URI token; brace matching should work only after invalid URI token */
-  #twelve { background: url(}{""{)}); background-color: green; }
+  /* not a URI token; brace matching is ignored while looking for the closing
+     ')' but is used after that. */
+  #twelve { background: url(}{""{)(}); background-color: green; }
   </style>
   <style type="text/css">
   /* invalid URI token absorbs the [ */
   #thirteen { background: url([""); background-color: green; }
   </style>
   <style type="text/css">
-  /* not a URI token; the opening ( is never matched */
+  /* not a URI token; the invalid URI token consumes everything up to the
+     next ')'. */
+  #fourteen { background-color: red; }
+  #foo { background: url(() }
   #fourteen { background-color: green; }
-  #foo { background: url(() }
-  #fourteen { background-color: red; }
   </style>
   <!-- The next three tests test that invalid URI tokens absorb [ and { -->
   <style type="text/css">
   #foo { background: url(a()); }
   #fifteen { background-color: green }
   </style>
   <style type="text/css">
   #foo { background: url([()); }
--- a/layout/style/nsCSSScanner.cpp
+++ b/layout/style/nsCSSScanner.cpp
@@ -255,23 +255,35 @@ nsCSSToken::AppendToString(nsString& aBu
       nsStyleUtil::AppendEscapedCSSIdent(mIdent, aBuffer);
       aBuffer.Append('(');
       break;
 
     case eCSSToken_URL:
     case eCSSToken_Bad_URL:
       aBuffer.AppendLiteral("url(");
       if (mSymbol != char16_t(0)) {
-        nsStyleUtil::AppendEscapedCSSString(mIdent, aBuffer, mSymbol);
+        if (mType == eCSSToken_URL) {
+          nsStyleUtil::AppendEscapedCSSString(mIdent, aBuffer, mSymbol);
+        } else {
+          // Only things up to mInteger were part of the string.
+          nsStyleUtil::AppendEscapedCSSString(StringHead(mIdent, mInteger),
+                                              aBuffer, mSymbol);
+          MOZ_ASSERT(mInteger2 == 0 || mInteger2 == 1);
+          if (mInteger2 == 1) {
+            // This was a Bad_String; strip off the closing quote.
+            aBuffer.Truncate(aBuffer.Length() - 1);
+          }
+
+          // Now append the remaining garbage.
+          aBuffer.Append(Substring(mIdent, mInteger));
+        }
       } else {
         aBuffer.Append(mIdent);
       }
-      if (mType == eCSSToken_URL) {
-        aBuffer.Append(char16_t(')'));
-      }
+      aBuffer.Append(char16_t(')'));
       break;
 
     case eCSSToken_Number:
       if (mIntegerValid) {
         aBuffer.AppendInt(mInteger, 10);
       } else {
         aBuffer.AppendFloat(mNumber);
       }
@@ -1161,16 +1173,19 @@ nsCSSScanner::NextURL(nsCSSToken& aToken
   aToken.mIdent.Truncate();
 
   int32_t ch = Peek();
   // Do we have a string?
   if (ch == '"' || ch == '\'') {
     ScanString(aToken);
     if (MOZ_UNLIKELY(aToken.mType == eCSSToken_Bad_String)) {
       aToken.mType = eCSSToken_Bad_URL;
+      // Flag us as having been a Bad_String.
+      aToken.mInteger2 = 1;
+      ConsumeBadURLRemnants(aToken);
       return;
     }
     MOZ_ASSERT(aToken.mType == eCSSToken_String, "unexpected token type");
 
   } else {
     // Otherwise, this is the start of a non-quoted url (which may be empty).
     aToken.mSymbol = char16_t(0);
     GatherText(IS_URL_CHAR, aToken.mIdent);
@@ -1184,19 +1199,56 @@ nsCSSScanner::NextURL(nsCSSToken& aToken
     Advance();
     aToken.mType = eCSSToken_URL;
     if (ch < 0) {
       AddEOFCharacters(eEOFCharacters_CloseParen);
     }
   } else {
     mSeenBadToken = true;
     aToken.mType = eCSSToken_Bad_URL;
+    if (aToken.mSymbol != 0) {
+      // Flag us as having been a String, not a Bad_String.
+      aToken.mInteger2 = 0;
+    }
+    ConsumeBadURLRemnants(aToken);
   }
 }
 
+void
+nsCSSScanner::ConsumeBadURLRemnants(nsCSSToken& aToken)
+{
+  aToken.mInteger = aToken.mIdent.Length();
+  int32_t ch = Peek();
+  do {
+    if (ch < 0) {
+      AddEOFCharacters(eEOFCharacters_CloseParen);
+      break;
+    }
+
+    if (ch == '\\' && GatherEscape(aToken.mIdent, false)) {
+      // Nothing else needs to be done here for the moment; we've consumed the
+      // backslash and following escape.
+    } else {
+      // We always want to consume this character.
+      if (IsVertSpace(ch)) {
+        AdvanceLine();
+      } else {
+        Advance();
+      }
+      if (ch == 0) {
+        aToken.mIdent.Append(UCS2_REPLACEMENT_CHAR);
+      } else {
+        aToken.mIdent.Append(ch);
+      }
+    }
+
+    ch = Peek();
+  } while (ch != ')');
+}
+
 /**
  * Primary scanner entry point.  Consume one token and fill in
  * |aToken| accordingly.  Will skip over any number of comments first,
  * and will also skip over rather than return whitespace and comment
  * tokens, depending on the value of |aSkip|.
  *
  * Returns true if it successfully consumed a token, false if EOF has
  * been reached.  Will always advance the current read position by at
--- a/layout/style/nsCSSScanner.h
+++ b/layout/style/nsCSSScanner.h
@@ -54,21 +54,30 @@ enum nsCSSTokenType {
   eCSSToken_Number,         // 1 -5 +2e3 3.14159 7.297352e-3
   eCSSToken_Dimension,      // 24px 8.5in
   eCSSToken_Percentage,     // 85% 1280.4%
 
   // String-like tokens.  In all cases, mIdent holds the text
   // belonging to the string, and mSymbol holds the delimiter
   // character, which may be ', ", or zero (only for unquoted URLs).
   // Bad_String and Bad_URL tokens are emitted when the closing
-  // delimiter or parenthesis was missing.
+  // delimiter was missing.  Bad_URL is also emitted if there was trailing
+  // garbage after the string or unquoted url value.
   eCSSToken_String,         // 'foo bar' "foo bar"
   eCSSToken_Bad_String,     // 'foo bar
   eCSSToken_URL,            // url(foobar) url("foo bar")
-  eCSSToken_Bad_URL,        // url(foo
+  // For Bad_URL tokens, we need to keep track of the following state:
+  // (1) Was there a quoted string?  If so, was it a String or Bad_String?
+  // (2) Was there trailing garbage, and if so what was it?
+  // We keep track of whether there was a quoted string by setting mSymbol as
+  // described above.  If that's nonzero, then mInteger2 indicates whether we
+  // have a String or Bad_String by taking on the values 0 and 1 respectively.
+  // mInteger indicates the start of trailing garbage in mIdent (and is set to
+  // mIdent.Length() when there is no trailing garbage).
+  eCSSToken_Bad_URL,        // url(foo') url('foo'a) url('foo
 
   // Any one-character symbol.  mSymbol holds the character.
   eCSSToken_Symbol,         // . ; { } ! *
 
   // Match operators.  These are single tokens rather than pairs of
   // Symbol tokens because css3-selectors forbids the presence of
   // comments between the two characters.  No value fields are used;
   // the token type indicates which operator.
@@ -250,16 +259,20 @@ class nsCSSScanner {
 
   // Get the body of an URL token (everything after the 'url(').
   // This is exposed for use by nsCSSParser::ParseMozDocumentRule,
   // which, for historical reasons, must make additional function
   // tokens behave like url().  Please do not add new uses to the
   // parser.
   void NextURL(nsCSSToken& aTokenResult);
 
+  // Implement the "consume the remnants of a bad url" algorithm from CSS3
+  // Syntax, except we don't consume the ')'.
+  void ConsumeBadURLRemnants(nsCSSToken& aToken);
+
   // This is exposed for use by nsCSSParser::ParsePseudoClassWithNthPairArg,
   // because "2n-1" is a single DIMENSION token, and "n-1" is a single
   // IDENT token, but the :nth() selector syntax wants to interpret
   // them the same as "2n -1" and "n -1" respectively.  Please do not
   // add new uses to the parser.
   //
   // Note: this function may not be used to back up over a line boundary.
   void Backup(uint32_t n);
--- a/layout/style/test/test_csslexer.js
+++ b/layout/style/test/test_csslexer.js
@@ -50,18 +50,19 @@ var LEX_TESTS = [
   ["23px", ["dimension:px"]],
   ["23%", ["percentage"]],
   ["url(http://example.com)", ["url:http://example.com"]],
   ["url('http://example.com')", ["url:http://example.com"]],
   ["url(  'http://example.com'  )",
              ["url:http://example.com"]],
   // In CSS Level 3, this is an ordinary URL, not a BAD_URL.
   ["url(http://example.com", ["url:http://example.com"]],
-  // See bug 1153981 to understand why this gets a SYMBOL token.
-  ["url(http://example.com @", ["bad_url:http://example.com", "symbol:@"]],
+  // We end up losing the whitespace before the '@' because it's skipped by the
+  // lexer before we discover we have a BAD_URL token.
+  ["url(http://example.com @", ["bad_url:http://example.com@"]],
   ["quo\\ting", ["ident:quoting"]],
   ["'bad string\n", ["bad_string:bad string", "whitespace"]],
   ["~=", ["includes"]],
   ["|=", ["dashmatch"]],
   ["^=", ["beginsmatch"]],
   ["$=", ["endsmatch"]],
   ["*=", ["containsmatch"]],
 
--- a/layout/style/test/test_parser_diagnostics_unprintables.html
+++ b/layout/style/test/test_parser_diagnostics_unprintables.html
@@ -40,17 +40,17 @@ const patterns = [
   { i: "x{@<t>: }",        o: "declaration but found \u2018@<i>\u2019." },
   // _String
   { i: "x{ '<t>'}" ,       o: "declaration but found \u2018'<s>'\u2019." },
   // _Bad_String
   { i: "x{ '<t>\n}",      o: "declaration but found \u2018'<s>\u2019." },
   // _URL
   { i: "x{ url('<t>')}",   o: "declaration but found \u2018url('<s>')\u2019." },
   // _Bad_URL
-  { i: "x{ url('<t>'.)}" , o: "declaration but found \u2018url('<s>'\u2019." }
+  { i: "x{ url('<t>'.)}" , o: "declaration but found \u2018url('<s>'.)\u2019." }
 ];
 
 // Blocks of characters to test, and how they should be escaped when
 // they appear in identifiers and string constants.
 const substitutions = [
   // ASCII printables that _can_ normally appear in identifiers,
   // so should of course _not_ be escaped.
   { t: "-_0123456789",               i: "-_0123456789",
--- a/media/webrtc/trunk/webrtc/modules/audio_processing/utility/delay_estimator.c
+++ b/media/webrtc/trunk/webrtc/modules/audio_processing/utility/delay_estimator.c
@@ -610,26 +610,43 @@ int WebRtc_ProcessBinarySpectrum(BinaryD
   //  2) The depth of the valley is deep enough
   //      (|value_best_candidate| < |minimum_probability|)
   //     and deeper than the best estimate so far
   //      (|value_best_candidate| < |last_delay_probability|)
   valid_candidate = ((valley_depth > kProbabilityOffset) &&
       ((value_best_candidate < self->minimum_probability) ||
           (value_best_candidate < self->last_delay_probability)));
 
+  // Check for nonstationary farend signal.
+  int non_stationary_farend = 0;
+  for (i = 0; i < self->history_size; ++i) {
+    if (self->farend->far_bit_counts[i] > 0) {
+      non_stationary_farend = 1;
+      break;
+    }
+  }
+
+  if (non_stationary_farend) {
+    // Only update the validation statistics when the farend is nonstationary
+    // as the underlying estimates are otherwise frozen.
+    UpdateRobustValidationStatistics(self, candidate_delay, valley_depth,
+                                     value_best_candidate);
+  }
+
   if (self->robust_validation_enabled) {
     int is_histogram_valid = 0;
-    UpdateRobustValidationStatistics(self, candidate_delay, valley_depth,
-                                     value_best_candidate);
     is_histogram_valid = HistogramBasedValidation(self, candidate_delay);
     valid_candidate = RobustValidation(self, candidate_delay, valid_candidate,
                                        is_histogram_valid);
 
   }
-  if (valid_candidate) {
+
+  // Only update the delay estimate when the farend is nonstationary and when
+  // a valid delay candidate is available.
+  if (non_stationary_farend && valid_candidate) {
     if (candidate_delay != self->last_delay) {
       self->last_delay_histogram =
           (self->histogram[candidate_delay] > kLastHistogramMax ?
               kLastHistogramMax : self->histogram[candidate_delay]);
       // Adjust the histogram if we made a change to |last_delay|, though it was
       // not the most likely one according to the histogram.
       if (self->histogram[candidate_delay] <
           self->histogram[self->compare_delay]) {
--- a/memory/replace/dmd/DMD.cpp
+++ b/memory/replace/dmd/DMD.cpp
@@ -1059,19 +1059,17 @@ public:
     , mSlopSize(0)
     , mAllocStackTrace(nullptr)
   {}
 
   explicit DeadBlock(const LiveBlock& aLb)
     : mReqSize(aLb.ReqSize())
     , mSlopSize(aLb.SlopSize())
     , mAllocStackTrace(aLb.AllocStackTrace())
-  {
-    MOZ_ASSERT(AllocStackTrace());
-  }
+  {}
 
   ~DeadBlock() {}
 
   size_t ReqSize()    const { return mReqSize; }
   size_t SlopSize()   const { return mSlopSize; }
 
   const StackTrace* AllocStackTrace() const
   {
@@ -1826,16 +1824,25 @@ WriteBlockContents(JSONWriter& aWriter, 
     }
   }
   aWriter.EndArray();
 }
 
 static void
 AnalyzeImpl(UniquePtr<JSONWriteFunc> aWriter)
 {
+  // Some blocks may have been allocated while creating |aWriter|. Those blocks
+  // will be freed at the end of this function when |write| is destroyed. The
+  // allocations will have occurred while intercepts were not blocked, so the
+  // frees better be as well, otherwise we'll get assertion failures.
+  // Therefore, this declaration must precede the AutoBlockIntercepts
+  // declaration, to ensure that |write| is destroyed *after* intercepts are
+  // unblocked.
+  JSONWriter writer(Move(aWriter));
+
   AutoBlockIntercepts block(Thread::Fetch());
   AutoLockState lock;
 
   // Allocate this on the heap instead of the stack because it's fairly large.
   auto locService = InfallibleAllocPolicy::new_<CodeAddressService>();
 
   StackTraceSet usedStackTraces;
   MOZ_ALWAYS_TRUE(usedStackTraces.init(512));
@@ -1843,17 +1850,16 @@ AnalyzeImpl(UniquePtr<JSONWriteFunc> aWr
   PointerSet usedPcs;
   MOZ_ALWAYS_TRUE(usedPcs.init(512));
 
   size_t iscSize;
 
   static int analysisCount = 1;
   StatusMsg("Dump %d {\n", analysisCount++);
 
-  JSONWriter writer(Move(aWriter));
   writer.Start();
   {
     writer.IntProperty("version", kOutputVersionNumber);
 
     writer.StartObjectProperty("invocation");
     {
       const char* var = gOptions->DMDEnvVar();
       if (var) {
--- a/mobile/android/base/java/org/mozilla/gecko/LauncherActivity.java
+++ b/mobile/android/base/java/org/mozilla/gecko/LauncherActivity.java
@@ -7,30 +7,31 @@ package org.mozilla.gecko;
 
 import android.app.Activity;
 import android.content.Intent;
 import android.os.Bundle;
 import android.support.customtabs.CustomTabsIntent;
 
 import org.mozilla.gecko.customtabs.CustomTabsActivity;
 import org.mozilla.gecko.db.BrowserContract;
+import org.mozilla.gecko.preferences.GeckoPreferences;
 import org.mozilla.gecko.tabqueue.TabQueueHelper;
 import org.mozilla.gecko.tabqueue.TabQueueService;
 
 /**
  * Activity that receives incoming Intents and dispatches them to the appropriate activities (e.g. browser, custom tabs, web app).
  */
 public class LauncherActivity extends Activity {
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
         GeckoAppShell.ensureCrashHandling();
 
-        if (AppConstants.MOZ_ANDROID_CUSTOM_TABS && isCustomTabsIntent()) {
+        if (AppConstants.MOZ_ANDROID_CUSTOM_TABS && isCustomTabsIntent() && isCustomTabsEnabled()) {
             dispatchCustomTabsIntent();
         } else if (isViewIntentWithURL()) {
             dispatchViewIntent();
         } else {
             dispatchNormalIntent();
         }
 
         finish();
@@ -79,9 +80,13 @@ public class LauncherActivity extends Ac
         return Intent.ACTION_VIEW.equals(intent.getAction())
                 && intent.getDataString() != null;
     }
 
     private boolean isCustomTabsIntent() {
         return isViewIntentWithURL()
                 && getIntent().hasExtra(CustomTabsIntent.EXTRA_SESSION);
     }
+
+    private boolean isCustomTabsEnabled() {
+        return GeckoSharedPrefs.forApp(this).getBoolean(GeckoPreferences.PREFS_CUSTOM_TABS, false);
+    }
 }
--- a/mobile/android/base/java/org/mozilla/gecko/db/BrowserProvider.java
+++ b/mobile/android/base/java/org/mozilla/gecko/db/BrowserProvider.java
@@ -795,28 +795,26 @@ public class BrowserProvider extends Sha
                 " LEFT OUTER JOIN " +
                 " (SELECT position FROM numbers WHERE position NOT IN (SELECT " + Bookmarks.POSITION + " " + pinnedSitesFromClause + ")) AS free_ids" +
                 " ON numbers.position > free_ids.position" +
                 " GROUP BY numbers.position" +
                 " ORDER BY numbers.position ASC" +
                 " LIMIT " + suggestedGridLimit;
 
         // Filter out: unvisited pages (history_id == -1) pinned (and other special) sites, deleted sites,
-        // pages which weren't visited locally, and about: pages.
+        // and about: pages.
         final String ignoreForTopSitesWhereClause =
                 "(" + Combined.HISTORY_ID + " IS NOT -1)" +
                 " AND " +
                 Combined.URL + " NOT IN (SELECT " +
                 Bookmarks.URL + " FROM bookmarks WHERE " +
                 DBUtils.qualifyColumn("bookmarks", Bookmarks.PARENT) + " < " + Bookmarks.FIXED_ROOT_ID + " AND " +
                 DBUtils.qualifyColumn("bookmarks", Bookmarks.IS_DELETED) + " == 0)" +
                 " AND " +
-                "(" + Combined.URL + " NOT LIKE ?)" +
-                " AND " +
-                "(" + Combined.LOCAL_VISITS_COUNT + " > 0)";
+                "(" + Combined.URL + " NOT LIKE ?)";
 
         final String[] ignoreForTopSitesArgs = new String[] {
                 AboutPages.URL_FILTER
         };
 
         // Stuff the suggested sites into SQL: this allows us to filter pinned and topsites out of the suggested
         // sites list as part of the final query (as opposed to walking cursors in java)
         final SuggestedSites suggestedSites = GeckoProfile.get(getContext(), uri.getQueryParameter(BrowserContract.PARAM_PROFILE)).getDB().getSuggestedSites();
--- a/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferences.java
+++ b/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferences.java
@@ -159,16 +159,17 @@ OnSharedPreferenceChangeListener
     private static final String PREFS_FAQ_LINK = NON_PREF_PREFIX + "faq.link";
     private static final String PREFS_FEEDBACK_LINK = NON_PREF_PREFIX + "feedback.link";
     public static final String PREFS_NOTIFICATIONS_CONTENT = NON_PREF_PREFIX + "notifications.content";
     public static final String PREFS_NOTIFICATIONS_CONTENT_LEARN_MORE = NON_PREF_PREFIX + "notifications.content.learn_more";
     public static final String PREFS_NOTIFICATIONS_WHATS_NEW = NON_PREF_PREFIX + "notifications.whats_new";
     public static final String PREFS_APP_UPDATE_LAST_BUILD_ID = "app.update.last_build_id";
     public static final String PREFS_READ_PARTNER_CUSTOMIZATIONS_PROVIDER = NON_PREF_PREFIX + "distribution.read_partner_customizations_provider";
     public static final String PREFS_READ_PARTNER_BOOKMARKS_PROVIDER = NON_PREF_PREFIX + "distribution.read_partner_bookmarks_provider";
+    public static final String PREFS_CUSTOM_TABS = NON_PREF_PREFIX + "customtabs";
 
     private static final String ACTION_STUMBLER_UPLOAD_PREF = "STUMBLER_PREF";
 
 
     // This isn't a Gecko pref, even if it looks like one.
     private static final String PREFS_BROWSER_LOCALE = "locale";
 
     public static final String PREFS_RESTORE_SESSION = NON_PREF_PREFIX + "restoreSession3";
@@ -876,16 +877,20 @@ OnSharedPreferenceChangeListener
                     }
                 } else if (PREFS_NOTIFICATIONS_CONTENT.equals(key) ||
                         PREFS_NOTIFICATIONS_CONTENT_LEARN_MORE.equals(key)) {
                     if (!FeedService.isInExperiment(this)) {
                         preferences.removePreference(pref);
                         i--;
                         continue;
                     }
+                } else if (PREFS_CUSTOM_TABS.equals(key) && !AppConstants.MOZ_ANDROID_CUSTOM_TABS) {
+                    preferences.removePreference(pref);
+                    i--;
+                    continue;
                 }
 
                 // Some Preference UI elements are not actually preferences,
                 // but they require a key to work correctly. For example,
                 // "Clear private data" requires a key for its state to be
                 // saved when the orientation changes. It uses the
                 // "android.not_a_preference.privacy.clear" key - which doesn't
                 // exist in Gecko - to satisfy this requirement.
--- a/mobile/android/base/locales/en-US/android_strings.dtd
+++ b/mobile/android/base/locales/en-US/android_strings.dtd
@@ -267,16 +267,22 @@
 
 <!ENTITY pref_tracking_protection_enabled "Enabled">
 <!ENTITY pref_tracking_protection_enabled_pb "Enabled in Private Browsing">
 <!ENTITY pref_tracking_protection_disabled "Disabled">
 
 <!ENTITY pref_whats_new_notification "What\'s new in &brandShortName;">
 <!ENTITY pref_whats_new_notification_summary "Learn about new features after an update">
 
+<!-- Custom Tabs is an Android API for allowing third-party apps to open URLs in a customized UI.
+     Instead of switching to the browser it appears as if the user stays in the third-party app.
+     For more see: https://developer.chrome.com/multidevice/android/customtabs -->
+<!ENTITY pref_custom_tabs "Custom Tabs">
+<!ENTITY pref_custom_tabs_summary "Allow third-party apps to open URLs with a customized look and feel. ">
+
 <!ENTITY tracking_protection_prompt_title "Now with Tracking Protection">
 <!ENTITY tracking_protection_prompt_text "Actively block tracking elements so you don\'t have to worry.">
 <!ENTITY tracking_protection_prompt_tip_text "Visit Privacy settings to learn more">
 <!ENTITY tracking_protection_prompt_action_button "Got it!">
 
 <!ENTITY tab_queue_toast_message3 "Tab saved in &brandShortName;">
 <!ENTITY tab_queue_toast_action "Open now">
 <!ENTITY tab_queue_prompt_title "Opening multiple links?">
--- a/mobile/android/base/resources/xml/preferences_advanced.xml
+++ b/mobile/android/base/resources/xml/preferences_advanced.xml
@@ -33,16 +33,21 @@
                     android:persistent="true" />
 
     <ListPreference android:key="browser.menu.showCharacterEncoding"
                     android:title="@string/pref_char_encoding"
                     android:entries="@array/pref_char_encoding_entries"
                     android:entryValues="@array/pref_char_encoding_values"
                     android:persistent="false" />
 
+    <SwitchPreference android:key="android.not_a_preference.customtabs"
+                      android:title="@string/pref_custom_tabs"
+                      android:summary="@string/pref_custom_tabs_summary"
+                      android:defaultValue="false" />
+
     <PreferenceCategory android:title="@string/pref_category_data_saver">
 
         <ListPreference android:key="browser.image_blocking"
                         android:title="@string/pref_tap_to_load_images_title2"
                         android:entries="@array/pref_browser_image_blocking_entries"
                         android:entryValues="@array/pref_browser_image_blocking_values"
                         android:persistent="false" />
 
--- a/mobile/android/base/strings.xml.in
+++ b/mobile/android/base/strings.xml.in
@@ -229,16 +229,19 @@
 
   <string name="pref_tracking_protection_enabled">&pref_tracking_protection_enabled;</string>
   <string name="pref_tracking_protection_enabled_pb">&pref_tracking_protection_enabled_pb;</string>
   <string name="pref_tracking_protection_disabled">&pref_tracking_protection_disabled;</string>
 
   <string name="pref_whats_new_notification">&pref_whats_new_notification;</string>
   <string name="pref_whats_new_notification_summary">&pref_whats_new_notification_summary;</string>
 
+  <string name="pref_custom_tabs">&pref_custom_tabs;</string>
+  <string name="pref_custom_tabs_summary">&pref_custom_tabs_summary;</string>
+
   <string name="pref_char_encoding">&pref_char_encoding;</string>
   <string name="pref_char_encoding_on">&pref_char_encoding_on;</string>
   <string name="pref_char_encoding_off">&pref_char_encoding_off;</string>
   <string name="pref_clear_private_data_now">&pref_clear_private_data2;</string>
   <string name="pref_clear_private_data_now_tablet">&pref_clear_private_data_now_tablet;</string>
   <string name="pref_clear_on_exit_title">&pref_clear_on_exit_title3;</string>
   <string name="pref_clear_on_exit_summary2">&pref_clear_on_exit_summary2;</string>
   <string name="pref_clear_on_exit_dialog_title">&pref_clear_on_exit_dialog_title;</string>
--- a/netwerk/base/Predictor.cpp
+++ b/netwerk/base/Predictor.cpp
@@ -387,21 +387,16 @@ Predictor::InstallObserver()
     mozilla::services::GetObserverService();
   if (!obs) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   rv = obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
-  if (!prefs) {
-    return NS_ERROR_NOT_AVAILABLE;
-  }
-
   Preferences::AddBoolVarCache(&mEnabled, PREDICTOR_ENABLED_PREF, true);
   Preferences::AddBoolVarCache(&mEnableHoverOnSSL,
                                PREDICTOR_SSL_HOVER_PREF, false);
 #ifdef NIGHTLY_BUILD
   Preferences::AddBoolVarCache(&mEnablePrefetch, PREDICTOR_PREFETCH_PREF, true);
 #else
   Preferences::AddBoolVarCache(&mEnablePrefetch, PREDICTOR_PREFETCH_PREF, false);
 #endif
--- a/netwerk/cache/nsCacheService.cpp
+++ b/netwerk/cache/nsCacheService.cpp
@@ -407,19 +407,22 @@ nsCacheProfilePrefObserver::Observe(nsIS
     } else if (!strcmp("suspend_process_notification", topic)) {
         // A suspended process may never return, so shutdown the cache to reduce
         // cache corruption.
         nsCacheService::GlobalInstance()->Shutdown();
     } else if (!strcmp("profile-do-change", topic)) {
         // profile after change
         mHaveProfile = true;
         nsCOMPtr<nsIPrefBranch> branch = do_GetService(NS_PREFSERVICE_CONTRACTID);
-        ReadPrefs(branch);
+        if (!branch) {
+            return NS_ERROR_FAILURE;
+        }
+        (void)ReadPrefs(branch);
         nsCacheService::OnProfileChanged();
-    
+
     } else if (!strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, topic)) {
 
         // ignore pref changes until we're done switch profiles
         if (!mHaveProfile)  
             return NS_OK;
 
         nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(subject, &rv);
         if (NS_FAILED(rv))  
--- a/netwerk/dns/ChildDNSService.cpp
+++ b/netwerk/dns/ChildDNSService.cpp
@@ -251,17 +251,16 @@ nsresult
 ChildDNSService::Init()
 {
   // Disable prefetching either by explicit preference or if a manual proxy
   // is configured
   bool disablePrefetch = false;
   int  proxyType = nsIProtocolProxyService::PROXYCONFIG_DIRECT;
 
   nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
-  prefs->GetBoolPref(kPrefNameDisablePrefetch, &disablePrefetch);
   if (prefs) {
     prefs->GetIntPref("network.proxy.type", &proxyType);
     prefs->GetBoolPref(kPrefNameDisablePrefetch, &disablePrefetch);
   }
 
   if (mFirstTime) {
     mFirstTime = false;
     if (prefs) {
--- a/netwerk/protocol/websocket/WebSocketChannel.cpp
+++ b/netwerk/protocol/websocket/WebSocketChannel.cpp
@@ -189,16 +189,19 @@ public:
   FailDelayManager()
   {
     MOZ_COUNT_CTOR(FailDelayManager);
 
     mDelaysDisabled = false;
 
     nsCOMPtr<nsIPrefBranch> prefService =
       do_GetService(NS_PREFSERVICE_CONTRACTID);
+    if (!prefService) {
+      return;
+    }
     bool boolpref = true;
     nsresult rv;
     rv = prefService->GetBoolPref("network.websocket.delay-failed-reconnects",
                                   &boolpref);
     if (NS_SUCCEEDED(rv) && !boolpref) {
       mDelaysDisabled = true;
     }
   }
--- a/startupcache/test/TestStartupCache.cpp
+++ b/startupcache/test/TestStartupCache.cpp
@@ -391,18 +391,22 @@ TestEarlyShutdown() {
 
 int main(int argc, char** argv)
 {
   ScopedXPCOM xpcom("Startup Cache");
   if (xpcom.failed())
     return 1;
 
   nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
+  if (!prefs) {
+    fail("prefs");
+    return 1;
+  }
   prefs->SetIntPref("hangmonitor.timeout", 0);
-  
+
   int rv = 0;
   nsresult scrv;
 
   // Register TestStartupCacheTelemetry
   nsCOMPtr<nsIFile> manifest;
   scrv = NS_GetSpecialDirectory(NS_GRE_DIR,
                                 getter_AddRefs(manifest));
   if (NS_FAILED(scrv)) {
--- a/toolkit/components/extensions/ExtensionContent.jsm
+++ b/toolkit/components/extensions/ExtensionContent.jsm
@@ -381,16 +381,22 @@ class ExtensionContext extends BaseConte
 
       this.sandbox = Cu.Sandbox(prin, {
         metadata,
         sandboxPrototype: contentWindow,
         wantXrays: true,
         isWebExtensionContentScript: true,
         wantGlobalProperties: ["XMLHttpRequest", "fetch"],
       });
+
+      Cu.evalInSandbox(`
+        window.JSON = JSON;
+        window.XMLHttpRequest = XMLHttpRequest;
+        window.fetch = fetch;
+      `, this.sandbox);
     }
 
     let delegate = {
       getSender(context, target, sender) {
         // Nothing to do here.
       },
     };
 
--- a/toolkit/components/extensions/test/mochitest/test_ext_permission_xhr.html
+++ b/toolkit/components/extensions/test/mochitest/test_ext_permission_xhr.html
@@ -12,24 +12,26 @@
 
 <script type="text/javascript">
 "use strict";
 
 /* eslint-disable mozilla/balanced-listeners */
 
 add_task(function* test_simple() {
   function runTests(cx) {
-    function xhr(url) {
-      return new Promise((resolve, reject) => {
-        let req = new XMLHttpRequest();
-        req.open("GET", url);
-        req.addEventListener("load", resolve);
-        req.addEventListener("error", reject);
-        req.send();
-      });
+    function xhr(XMLHttpRequest) {
+      return (url) => {
+        return new Promise((resolve, reject) => {
+          let req = new XMLHttpRequest();
+          req.open("GET", url);
+          req.addEventListener("load", resolve);
+          req.addEventListener("error", reject);
+          req.send();
+        });
+      };
     }
 
     function run(shouldFail, fetch) {
       function passListener() {
         browser.test.succeed(`${cx}.${fetch.name} pass listener`);
       }
 
       function failListener() {
@@ -38,20 +40,24 @@ add_task(function* test_simple() {
 
       if (shouldFail) {
         return fetch("http://example.org/example.txt").then(failListener, passListener);
       } else {
         return fetch("http://example.com/example.txt").then(passListener, failListener);
       }
     }
 
-    return run(true, xhr)
-      .then(() => run(false, xhr))
+    return run(true, xhr(XMLHttpRequest))
+      .then(() => run(false, xhr(XMLHttpRequest)))
+      .then(() => run(true, xhr(window.XMLHttpRequest)))
+      .then(() => run(false, xhr(window.XMLHttpRequest)))
       .then(() => run(true, fetch))
       .then(() => run(false, fetch))
+      .then(() => run(true, window.fetch))
+      .then(() => run(false, window.fetch))
       .catch(err => {
         browser.test.fail(`Error: ${err} :: ${err.stack}`);
         browser.test.notifyFail("permission_xhr");
       });
   }
 
   function background(runTests) {
     runTests("bg").then(() => {
--- a/toolkit/components/url-classifier/nsUrlClassifierUtils.cpp
+++ b/toolkit/components/url-classifier/nsUrlClassifierUtils.cpp
@@ -126,27 +126,27 @@ nsUrlClassifierUtils::GetKeyForURI(nsIUR
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsUrlClassifierUtils::GetProtocolVersion(const nsACString& aProvider,
                                          nsACString& aVersion)
 {
-  nsCOMPtr<nsIPrefBranch> prefBranch =
-    do_GetService(NS_PREFSERVICE_CONTRACTID);
-
-  nsPrintfCString prefName("browser.safebrowsing.provider.%s.pver",
-                           nsCString(aProvider).get());
+  nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID);
+  if (prefBranch) {
+      nsPrintfCString prefName("browser.safebrowsing.provider.%s.pver",
+                               nsCString(aProvider).get());
+      nsXPIDLCString version;
+      nsresult rv = prefBranch->GetCharPref(prefName.get(), getter_Copies(version));
 
-  nsXPIDLCString version;
-  nsresult rv = prefBranch->GetCharPref(prefName.get(), getter_Copies(version));
-
-  aVersion = NS_SUCCEEDED(rv) ? version
-                              : DEFAULT_PROTOCOL_VERSION;
+      aVersion = NS_SUCCEEDED(rv) ? version : DEFAULT_PROTOCOL_VERSION;
+  } else {
+      aVersion = DEFAULT_PROTOCOL_VERSION;
+  }
 
   return NS_OK;
 }
 
 /////////////////////////////////////////////////////////////////////////////
 // non-interface methods
 
 nsresult
--- a/xpcom/base/nsSystemInfo.cpp
+++ b/xpcom/base/nsSystemInfo.cpp
@@ -811,16 +811,25 @@ nsSystemInfo::Init()
                       sandInfo.CanSandboxMedia());
   }
 #endif // XP_LINUX && MOZ_SANDBOX
 
   return NS_OK;
 }
 
 #ifdef MOZ_WIDGET_ANDROID
+// Prerelease versions of Android use a letter instead of version numbers.
+// Unfortunately this breaks websites due to the user agent.
+// Chrome works around this by hardcoding an Android version when a
+// numeric version can't be obtained. We're doing the same.
+// This version will need to be updated whenever there is a new official
+// Android release.
+// See: https://cs.chromium.org/chromium/src/base/sys_info_android.cc?l=61
+#define DEFAULT_ANDROID_VERSION "6.0.99"
+
 /* static */
 void
 nsSystemInfo::GetAndroidSystemInfo(AndroidSystemInfo* aInfo)
 {
   MOZ_ASSERT(XRE_IsParentProcess());
 
   if (!mozilla::AndroidBridge::Bridge()) {
     aInfo->sdk_version() = 0;
@@ -833,17 +842,25 @@ nsSystemInfo::GetAndroidSystemInfo(Andro
     aInfo->device() = str;
   }
   if (mozilla::AndroidBridge::Bridge()->GetStaticStringField(
       "android/os/Build", "MANUFACTURER", str)) {
     aInfo->manufacturer() = str;
   }
   if (mozilla::AndroidBridge::Bridge()->GetStaticStringField(
       "android/os/Build$VERSION", "RELEASE", str)) {
-    aInfo->release_version() = str;
+    int major_version;
+    int minor_version;
+    int bugfix_version;
+    int num_read = sscanf(NS_ConvertUTF16toUTF8(str).get(), "%d.%d.%d", &major_version, &minor_version, &bugfix_version);
+    if (num_read == 0) {
+      aInfo->release_version() = NS_LITERAL_STRING(DEFAULT_ANDROID_VERSION);
+    } else {
+      aInfo->release_version() = str;
+    }
   }
   if (mozilla::AndroidBridge::Bridge()->GetStaticStringField(
       "android/os/Build", "HARDWARE", str)) {
     aInfo->hardware() = str;
   }
   int32_t sdk_version;
   if (!mozilla::AndroidBridge::Bridge()->GetStaticIntField(
       "android/os/Build$VERSION", "SDK_INT", &sdk_version)) {