Merge mozilla-central to beta. a=merge, l10n=me on a CLOSED TREE
authorRyan VanderMeulen <ryanvm@gmail.com>
Wed, 17 Jan 2018 10:16:16 -0500
changeset 453895 16dfec69b8b0e4c70f3438db5043dcd0b7bc97f0
parent 453690 4f3ef7e330c3dcd62d47190168034b494ab3e21c (current diff)
parent 453894 4e429d313fd2e0f9202271ee8f3fb798817ec3e7 (diff)
child 453896 95352ef5e38ee720c451c92177383833b5444665
push id1648
push usermtabara@mozilla.com
push dateThu, 01 Mar 2018 12:45:47 +0000
treeherdermozilla-release@cbb9688c2eeb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone59.0
Merge mozilla-central to beta. a=merge, l10n=me on a CLOSED TREE
browser/config/mozconfigs/win32/debug-searchfox
netwerk/protocol/http/nsHttpTransaction.cpp
taskcluster/docker/image_builder/HASH
taskcluster/docker/image_builder/VERSION
testing/mozharness/configs/builds/taskcluster_firefox_win32_clang_searchfox_debug.py
testing/talos/talos/webextensions/dummy/dummy-signed.xpi
testing/web-platform/meta/css/css-align/content-distribution/place-content-shorthand-004.html.ini
toolkit/components/backgroundhangmonitor/HangStack.cpp
toolkit/components/backgroundhangmonitor/HangStack.h
toolkit/components/resistfingerprinting/nsRFPService.cpp
--- a/.clang-format-ignore
+++ b/.clang-format-ignore
@@ -2,16 +2,17 @@
 build/clang-plugin/.*
 # The two templates cannot be formatted
 config/gcc-stl-wrapper.template.h
 config/msvc-stl-wrapper.template.h
 dom/base/test/.*
 dom/bindings/test/.*
 dom/media/gtest/.*
 gfx/testsd/.*
+.*/gtest/ExampleStylesheet.h
 image/test/.*
 ipc/ipdl/test/.*
 ipc/testshell/.*
 js/src/jsapi-tests/.*
 # See bug 1395584
 js/src/vm/Opcodes.h
 # Ignored because of bug 1342657
 layout/style/nsCSSPropAliasList.h
--- a/accessible/ipc/win/handler/AccessibleHandler.cpp
+++ b/accessible/ipc/win/handler/AccessibleHandler.cpp
@@ -1216,18 +1216,22 @@ static const GUID kUnsupportedServices[]
   // Unknown, queried by Windows
   {0x33f139ee, 0xe509, 0x47f7, {0xbf, 0x39, 0x83, 0x76, 0x44, 0xf7, 0x45, 0x76}},
   // Unknown, queried by Windows
   {0xFDA075CF, 0x7C8B, 0x498C, { 0xB5, 0x14, 0xA9, 0xCB, 0x52, 0x1B, 0xBF, 0xB4 }},
   // Unknown, queried by Windows
   {0x8EDAA462, 0x21F4, 0x4C87, { 0xA0, 0x12, 0xB3, 0xCD, 0xA3, 0xAB, 0x01, 0xFC }},
   // Unknown, queried by Windows
   {0xacd46652, 0x829d, 0x41cb, { 0xa5, 0xfc, 0x17, 0xac, 0xf4, 0x36, 0x61, 0xac }},
-  // Unknown, queried by Windows
-  {0xb96fdb85, 0x7204, 0x4724, { 0x84, 0x2b, 0xc7, 0x05, 0x9d, 0xed, 0xb9, 0xd0 }}
+  // SID_IsUIAutomationObject (undocumented), queried by Windows
+  {0xb96fdb85, 0x7204, 0x4724, { 0x84, 0x2b, 0xc7, 0x05, 0x9d, 0xed, 0xb9, 0xd0 }},
+  // IIS_IsOleaccProxy (undocumented), queried by Windows
+  {0x902697FA, 0x80E4, 0x4560, {0x80, 0x2A, 0xA1, 0x3F, 0x22, 0xA6, 0x47, 0x09}},
+  // IID_IHTMLElement, queried by JAWS
+  {0x3050F1FF, 0x98B5, 0x11CF, {0xBB, 0x82, 0x00, 0xAA, 0x00, 0xBD, 0xCE, 0x0B}}
 };
 
 /*** IServiceProvider ***/
 
 HRESULT
 AccessibleHandler::QueryService(REFGUID aServiceId, REFIID aIid,
                                 void** aOutInterface)
 {
@@ -1237,16 +1241,23 @@ AccessibleHandler::QueryService(REFGUID 
      of our own object to implement this just like a QI. */
   if (aIid == IID_IAccessible2_3 || aIid == IID_IAccessible2_2 ||
       aIid == IID_IAccessible2) {
     RefPtr<NEWEST_IA2_INTERFACE> ia2(this);
     ia2.forget(aOutInterface);
     return S_OK;
   }
 
+  // JAWS uses QueryService for these, but QI will work just fine and we can
+  // thus avoid a cross-process call. More importantly, if QS is used, the
+  // handler won't get used for that object, so our caching won't be used.
+  if (aIid == IID_IAccessibleAction || aIid == IID_IAccessibleText) {
+    return InternalQueryInterface(aIid, aOutInterface);
+  }
+
   for (uint32_t i = 0; i < ArrayLength(kUnsupportedServices); ++i) {
     if (aServiceId == kUnsupportedServices[i]) {
       return E_NOINTERFACE;
     }
   }
 
   if (!mServProvPassThru) {
     RefPtr<IUnknown> proxy(GetProxy());
--- a/accessible/tests/mochitest/elm/test_shadowroot.html
+++ b/accessible/tests/mochitest/elm/test_shadowroot.html
@@ -20,17 +20,17 @@
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
   <script>
     SimpleTest.waitForExplicitFinish();
     SpecialPowers.pushPrefEnv({
       set: [
-        ["dom.webcomponents.enabled", true]
+        ["dom.webcomponents.shadowdom.enabled", true]
       ]
     }, function() {
       // This test loads in an iframe, to ensure that the element instance is
       // loaded with the correct value of the preference.
       var iframe = document.createElement("iframe");
       iframe.src = "test_shadowroot_subframe.html";
       document.body.appendChild(iframe);
     });
--- a/accessible/tests/mochitest/hittest/test_shadowroot.html
+++ b/accessible/tests/mochitest/hittest/test_shadowroot.html
@@ -20,17 +20,17 @@
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
   <script>
     SimpleTest.waitForExplicitFinish();
     SpecialPowers.pushPrefEnv({
       set: [
-        ["dom.webcomponents.enabled", true]
+        ["dom.webcomponents.shadowdom.enabled", true]
       ]
     }, function() {
       // This test loads in an iframe, to ensure that the element instance is
       // loaded with the correct value of the preference.
       var iframe = document.createElement("iframe");
       iframe.src = "test_shadowroot_subframe.html";
       document.body.appendChild(iframe);
     });
--- a/accessible/tests/mochitest/treeupdate/test_bug1276857.html
+++ b/accessible/tests/mochitest/treeupdate/test_bug1276857.html
@@ -107,17 +107,17 @@
       gQueue.push(new runTest());
       gQueue.push(new runShadowTest());
       gQueue.invoke(); // will call SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     SpecialPowers.pushPrefEnv({
       set: [
-        ["dom.webcomponents.enabled", true]
+        ["dom.webcomponents.shadowdom.enabled", true]
       ]
     }, function() {
       // This test loads in an iframe, to ensure that the element instance is
       // loaded with the correct value of the preference.
       let iframe = document.createElement("iframe");
       iframe.id = "iframe";
       iframe.src = "test_bug1276857_subframe.html";
       addA11yLoadEvent(doTest, iframe.contentWindow);
--- a/browser/app/blocklist.xml
+++ b/browser/app/blocklist.xml
@@ -4596,16 +4596,19 @@
       <serialNumber>Fw==</serialNumber>
     </certItem>
     <certItem issuerName="MHYxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRTeW1hbnRlYyBDb3Jwb3JhdGlvbjEfMB0GA1UECxMWU3ltYW50ZWMgVHJ1c3QgTmV0d29yazEnMCUGA1UEAxMeU3ltYW50ZWMgV2ViIFBLSSBFQ0MgUm9vdCAtIEcx">
       <serialNumber>Gz4uHrL2usrTZrPCHeuF5g==</serialNumber>
     </certItem>
     <certItem issuerName="MIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA2IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHNQ==">
       <serialNumber>UWMOvf4tj/x5cQN2PXVSww==</serialNumber>
     </certItem>
+    <certItem issuerName="MHIxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJUWDEQMA4GA1UEBxMHSG91c3RvbjEVMBMGA1UEChMMY1BhbmVsLCBJbmMuMS0wKwYDVQQDEyRjUGFuZWwsIEluYy4gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHk=">
+      <serialNumber>NlLRZJFLco/An3cLAGjGgQ==</serialNumber>
+    </certItem>
     <certItem issuerName="MFwxCzAJBgNVBAYTAkJFMRUwEwYDVQQLEwxUcnVzdGVkIFJvb3QxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExGzAZBgNVBAMTElRydXN0ZWQgUm9vdCBDQSBHMg==">
       <serialNumber>e/fIfg2Dj2tkYIWVu2r82Cc=</serialNumber>
     </certItem>
     <certItem issuerName="MH4xCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRTeW1hbnRlYyBDb3Jwb3JhdGlvbjEfMB0GA1UECxMWU3ltYW50ZWMgVHJ1c3QgTmV0d29yazEvMC0GA1UEAxMmU3ltYW50ZWMgQ2xhc3MgMyBTZWN1cmUgU2VydmVyIENBIC0gRzQ=">
       <serialNumber>UMUwXwT1Z4juyQ/CNTf4mw==</serialNumber>
     </certItem>
     <certItem issuerName="MH4xCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRTeW1hbnRlYyBDb3Jwb3JhdGlvbjEfMB0GA1UECxMWU3ltYW50ZWMgVHJ1c3QgTmV0d29yazEvMC0GA1UEAxMmU3ltYW50ZWMgQ2xhc3MgMyBTZWN1cmUgU2VydmVyIENBIC0gRzQ=">
       <serialNumber>d8AtKymQwkOPDBj+hjPzFg==</serialNumber>
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1704,17 +1704,17 @@ pref("browser.crashReports.unsubmittedCh
 // Preferences for the form autofill system extension
 // The truthy values of "extensions.formautofill.available" are "on" and "detect",
 // any other value means autofill isn't available.
 // "detect" means it's enabled if conditions defined in the extension are met.
 #ifdef NIGHTLY_BUILD
 pref("extensions.formautofill.available", "on");
 pref("extensions.formautofill.creditCards.available", true);
 #elif MOZ_UPDATE_CHANNEL == release
-pref("extensions.formautofill.available", "staged-rollout");
+pref("extensions.formautofill.available", "detect");
 pref("extensions.formautofill.creditCards.available", false);
 #else
 pref("extensions.formautofill.available", "detect");
 pref("extensions.formautofill.creditCards.available", true);
 #endif
 pref("extensions.formautofill.addresses.enabled", true);
 pref("extensions.formautofill.creditCards.enabled", true);
 // Pref for shield/heartbeat to recognize users who have used Credit Card
--- a/browser/base/content/browser-tabsintitlebar.js
+++ b/browser/base/content/browser-tabsintitlebar.js
@@ -263,20 +263,16 @@ var TabsInTitlebar = {
       // Reset the margins and padding that might have been modified:
       titlebarContent.style.marginTop = "";
       titlebarContent.style.marginBottom = "";
       titlebar.style.marginBottom = "";
       menubar.style.paddingBottom = "";
     }
 
     ToolbarIconColor.inferFromText("tabsintitlebar", TabsInTitlebar.enabled);
-
-    if (document.documentElement.hasAttribute("customizing")) {
-      gCustomizeMode.updateLWTStyling();
-    }
   },
 
   _sizePlaceholder(type, width) {
     Array.forEach(document.querySelectorAll(".titlebar-placeholder[type='" + type + "']"),
                   function(node) { node.width = width; });
   },
 
   uninit() {
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -357,17 +357,17 @@ toolbarpaletteitem {
   }
 
   .webextension-browser-action[cui-areatype="menu-panel"]:-moz-lwtheme-darktext,
   toolbarpaletteitem[place="palette"] > .webextension-browser-action:-moz-lwtheme-darktext {
     list-style-image: var(--webextension-menupanel-image-dark, inherit);
   }
 
   .webextension-menuitem {
-    list-style-image: var(--webextension-menuitem-image, inherit);
+    list-style-image: var(--webextension-menuitem-image, inherit) !important;
   }
 }
 
 @media (min-resolution: 1.1dppx) {
   .webextension-browser-action {
     list-style-image: var(--webextension-toolbar-image-2x, inherit);
   }
 
@@ -389,17 +389,17 @@ toolbarpaletteitem {
   }
 
   .webextension-browser-action[cui-areatype="menu-panel"]:-moz-lwtheme-darktext,
   toolbarpaletteitem[place="palette"] > .webextension-browser-action:-moz-lwtheme-darktext {
     list-style-image: var(--webextension-menupanel-image-2x-dark, inherit);
   }
 
   .webextension-menuitem {
-    list-style-image: var(--webextension-menuitem-image-2x, inherit);
+    list-style-image: var(--webextension-menuitem-image-2x, inherit) !important;
   }
 }
 
 toolbarbutton.webextension-menuitem > .toolbarbutton-icon {
   width: 16px;
   height: 16px;
 }
 
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -291,18 +291,18 @@
       <toolbarbutton id="sidebar-switcher-tabs"
                      label="&syncedTabs.sidebar.label;"
                      class="subviewbutton subviewbutton-iconic"
                      observes="viewTabsSidebar"
                      oncommand="SidebarUI.show('viewTabsSidebar');">
         <observes element="viewTabsSidebar" attribute="checked"/>
       </toolbarbutton>
       <toolbarseparator/>
-      <vbox id="sidebar-extensions"></vbox>
-      <toolbarseparator/>
+      <!-- Extension toolbarbuttons go here. -->
+      <toolbarseparator id="sidebar-extensions-separator"/>
       <toolbarbutton id="sidebar-reverse-position"
                      class="subviewbutton"
                      oncommand="SidebarUI.reversePosition()"/>
       <toolbarseparator/>
       <toolbarbutton label="&sidebarMenuClose.label;"
                      class="subviewbutton"
                      oncommand="SidebarUI.hide()"/>
     </panel>
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -3432,55 +3432,64 @@
                                       true /* aCanceledOkay */);
 
             if (aCloseWindow)
               this._windowIsClosing = closeWindow(true, window.warnAboutClosingWindow);
           ]]>
         </body>
       </method>
 
-      <method name="_blurTab">
+      <method name="_findTabToBlurTo">
         <parameter name="aTab"/>
         <body>
           <![CDATA[
-            if (!aTab.selected)
-              return;
+            if (!aTab.selected) {
+              return null;
+            }
 
             if (aTab.owner &&
                 !aTab.owner.hidden &&
                 !aTab.owner.closing &&
                 Services.prefs.getBoolPref("browser.tabs.selectOwnerOnClose")) {
-              this.selectedTab = aTab.owner;
-              return;
+              return aTab.owner;
             }
 
             // Switch to a visible tab unless there aren't any others remaining
             let remainingTabs = this.visibleTabs;
             let numTabs = remainingTabs.length;
             if (numTabs == 0 || numTabs == 1 && remainingTabs[0] == aTab) {
               remainingTabs = Array.filter(this.tabs, function(tab) {
                 return !tab.closing;
               }, this);
             }
 
             // Try to find a remaining tab that comes after the given tab
-            var tab = aTab;
+            let tab = aTab;
             do {
               tab = tab.nextSibling;
             } while (tab && remainingTabs.indexOf(tab) == -1);
 
             if (!tab) {
               tab = aTab;
 
               do {
                 tab = tab.previousSibling;
               } while (tab && remainingTabs.indexOf(tab) == -1);
             }
 
-            this.selectedTab = tab;
+            return tab;
+          ]]>
+        </body>
+      </method>
+
+      <method name="_blurTab">
+        <parameter name="aTab"/>
+        <body>
+          <![CDATA[
+            this.selectedTab = this._findTabToBlurTo(aTab);
           ]]>
         </body>
       </method>
 
       <method name="swapBrowsersAndCloseOther">
         <parameter name="aOurTab"/>
         <parameter name="aOtherTab"/>
         <body>
@@ -5051,16 +5060,20 @@
               }
             },
 
             canWarmTab(tab) {
               if (!this.tabbrowser.tabWarmingEnabled) {
                 return false;
               }
 
+              if (!tab) {
+                return false;
+              }
+
               // If the tab is not yet inserted, closing, not remote,
               // crashed, already visible, or already requested, warming
               // up the tab makes no sense.
               if (this.minimizedOrFullyOccluded ||
                   !tab.linkedPanel ||
                   tab.closing ||
                   !tab.linkedBrowser.isRemoteBrowser ||
                   !tab.linkedBrowser.frameLoader.tabParent) {
@@ -7967,17 +7980,22 @@
           tabContainer._hoveredTab = this;
           if (this.linkedPanel && !this.selected) {
             this.linkedBrowser.unselectedTabHover(true);
             this.startUnselectedTabHoverTimer();
           }
 
           // Prepare connection to host beforehand.
           SessionStore.speculativeConnectOnTabHover(this);
-          tabContainer.tabbrowser.warmupTab(this);
+
+          let tabToWarm = this;
+          if (this.mOverCloseButton) {
+            tabToWarm = tabContainer.tabbrowser._findTabToBlurTo(this);
+          }
+          tabContainer.tabbrowser.warmupTab(tabToWarm);
         ]]></body>
       </method>
 
       <method name="_mouseleave">
         <body><![CDATA[
           let tabContainer = this.parentNode;
           if (tabContainer._beforeHoveredTab) {
             tabContainer._beforeHoveredTab.removeAttribute("beforehovered");
--- a/browser/base/content/test/contextMenu/browser.ini
+++ b/browser/base/content/test/contextMenu/browser.ini
@@ -1,7 +1,9 @@
 [DEFAULT]
 support-files =
   !/browser/base/content/test/general/contextmenu_common.js
   subtst_contextmenu_webext.html
+  test_contextmenu_links.html
 
 [browser_contextmenu_touch.js]
 skip-if = !(os == 'win' && os_version == '10.0')
+[browser_contextmenu_linkopen.js]
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/contextMenu/browser_contextmenu_linkopen.js
@@ -0,0 +1,69 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const TEST_LINK = "https://example.com/";
+const RESOURCE_LINK = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "https://example.com") + "test_contextmenu_links.html";
+
+async function activateContextAndWaitFor(selector, where) {
+  let contextMenuItem = "openlink";
+  let openPromise;
+  let closeMethod;
+  switch (where) {
+    case "tab":
+      contextMenuItem += "intab";
+      openPromise = BrowserTestUtils.waitForNewTab(gBrowser, TEST_LINK, false);
+      closeMethod = async (tab) => BrowserTestUtils.removeTab(tab);
+      break;
+    case "privatewindow":
+      contextMenuItem += "private";
+      openPromise = BrowserTestUtils.waitForNewWindow(TEST_LINK).then(win => {
+        ok(PrivateBrowsingUtils.isWindowPrivate(win), "Should have opened a private window.");
+        return win;
+      });
+      closeMethod = async (win) => BrowserTestUtils.closeWindow(win);
+      break;
+    case "window":
+      // No contextMenuItem suffix for normal new windows;
+      openPromise = BrowserTestUtils.waitForNewWindow(TEST_LINK).then(win => {
+        ok(!PrivateBrowsingUtils.isWindowPrivate(win), "Should have opened a normal window.");
+        return win;
+      });
+      closeMethod = async (win) => BrowserTestUtils.closeWindow(win);
+      break;
+  }
+  let contextMenu = document.getElementById("contentAreaContextMenu");
+  is(contextMenu.state, "closed", "checking if popup is closed");
+  let awaitPopupShown = BrowserTestUtils.waitForEvent(contextMenu, "popupshown");
+  await BrowserTestUtils.synthesizeMouse(selector, 0, 0, {
+      type: "contextmenu",
+      button: 2,
+      centered: true,
+    },
+    gBrowser.selectedBrowser);
+  await awaitPopupShown;
+  info("Popup Shown");
+  let awaitPopupHidden = BrowserTestUtils.waitForEvent(contextMenu, "popuphidden");
+  let domItem = contextMenu.querySelector("#context-" + contextMenuItem);
+  info("Going to click item " + domItem.id);
+  let bounds = domItem.getBoundingClientRect();
+  ok(bounds.height && bounds.width, "DOM context menu item " + where + " should be visible");
+  ok(!domItem.disabled, "DOM context menu item " + where + " shouldn't be disabled");
+  domItem.click();
+  contextMenu.hidePopup();
+  await awaitPopupHidden;
+
+  let openedThing = await openPromise;
+  await closeMethod(openedThing);
+}
+
+add_task(async function test_select_text_link() {
+  let testTab = await BrowserTestUtils.openNewForegroundTab(gBrowser, RESOURCE_LINK);
+  for (let elementID of ["test-link", "test-image-link", "svg-with-link", "svg-with-relative-link"]) {
+    for (let where of ["tab", "window", "privatewindow"]) {
+      await activateContextAndWaitFor("#" + elementID, where);
+    }
+  }
+  await BrowserTestUtils.removeTab(testTab);
+});
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/contextMenu/test_contextmenu_links.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Subtest for browser context menu links</title>
+</head>
+<body>
+Browser context menu link subtest.
+
+<a id="test-link" href="https://example.com">Click the monkey!</a>
+<a id="test-image-link" href="/"><img src="ctxmenu-image.png"></a>
+<svg id="svg-with-link" width=10 height=10><a xlink:href="https://example.com/"><circle cx="50%" cy="50%" r="50%" fill="blue"/></a></svg>
+<svg id="svg-with-relative-link" width=10 height=10><a xlink:href="/"><circle cx="50%" cy="50%" r="50%" fill="blue"/></a></svg>
+</body>
+</html>
--- a/browser/base/content/test/general/browser_bug553455.js
+++ b/browser/base/content/test/general/browser_bug553455.js
@@ -239,17 +239,17 @@ async function test_disabledInstall() {
   let triggers = encodeURIComponent(JSON.stringify({
     "XPI": "amosigned.xpi"
   }));
   BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
   let panel = await notificationPromise;
 
   let notification = panel.childNodes[0];
   is(notification.button.label, "Enable", "Should have seen the right button");
-  is(notification.getAttribute("label"),
+  is(notification.getAttribute("startlabel"),
      "Software installation is currently disabled. Click Enable and try again.");
 
   let closePromise = waitForNotificationClose();
   // Click on Enable
   EventUtils.synthesizeMouseAtCenter(notification.button, {});
   await closePromise;
 
   try {
@@ -270,17 +270,17 @@ async function test_blockedInstall() {
   }));
   BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
   let panel = await notificationPromise;
 
   let notification = panel.childNodes[0];
   is(notification.button.label, "Allow", "Should have seen the right button");
   is(notification.getAttribute("origin"), "example.com",
      "Should have seen the right origin host");
-  is(notification.getAttribute("label"),
+  is(notification.getAttribute("startlabel"),
      gApp + " prevented this site from asking you to install software on your computer.",
      "Should have seen the right message");
 
   let dialogPromise = waitForInstallDialog();
   // Click on Allow
   EventUtils.synthesizeMouse(notification.button, 20, 10, {});
   // Notification should have changed to progress notification
   ok(PopupNotifications.isPanelOpen, "Notification should still be open");
@@ -289,17 +289,17 @@ async function test_blockedInstall() {
   let installDialog = await dialogPromise;
 
   notificationPromise = waitForNotification("addon-install-restart");
   acceptInstallDialog(installDialog);
   panel = await notificationPromise;
 
   notification = panel.childNodes[0];
   is(notification.button.label, "Restart Now", "Should have seen the right button");
-  is(notification.getAttribute("label"),
+  is(notification.getAttribute("startlabel"),
      "XPI Test will be installed after you restart " + gApp + ".",
      "Should have seen the right message");
 
   let installs = await getInstalls();
   is(installs.length, 1, "Should be one pending install");
   installs[0].cancel();
   await removeTab();
 },
@@ -326,17 +326,17 @@ async function test_whitelistedInstall()
      "tab selected in response to the addon-install-confirmation notification");
 
   let notificationPromise = waitForNotification("addon-install-restart");
   acceptInstallDialog(installDialog);
   let panel = await notificationPromise;
 
   let notification = panel.childNodes[0];
   is(notification.button.label, "Restart Now", "Should have seen the right button");
-  is(notification.getAttribute("label"),
+  is(notification.getAttribute("startlabel"),
      "XPI Test will be installed after you restart " + gApp + ".",
      "Should have seen the right message");
 
   let installs = await getInstalls();
   is(installs.length, 1, "Should be one pending install");
   installs[0].cancel();
 
   Services.perms.remove(makeURI("http://example.com/"), "install");
@@ -352,17 +352,17 @@ async function test_failedDownload() {
   let triggers = encodeURIComponent(JSON.stringify({
     "XPI": "missing.xpi"
   }));
   BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
   await progressPromise;
   let panel = await failPromise;
 
   let notification = panel.childNodes[0];
-  is(notification.getAttribute("label"),
+  is(notification.getAttribute("startlabel"),
      "The add-on could not be downloaded because of a connection failure.",
      "Should have seen the right message");
 
   Services.perms.remove(makeURI("http://example.com/"), "install");
   await removeTab();
 },
 
 async function test_corruptFile() {
@@ -374,17 +374,17 @@ async function test_corruptFile() {
   let triggers = encodeURIComponent(JSON.stringify({
     "XPI": "corrupt.xpi"
   }));
   BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
   await progressPromise;
   let panel = await failPromise;
 
   let notification = panel.childNodes[0];
-  is(notification.getAttribute("label"),
+  is(notification.getAttribute("startlabel"),
      "The add-on downloaded from this site could not be installed " +
      "because it appears to be corrupt.",
      "Should have seen the right message");
 
   Services.perms.remove(makeURI("http://example.com/"), "install");
   await removeTab();
 },
 
@@ -397,17 +397,17 @@ async function test_incompatible() {
   let triggers = encodeURIComponent(JSON.stringify({
     "XPI": "incompatible.xpi"
   }));
   BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
   await progressPromise;
   let panel = await failPromise;
 
   let notification = panel.childNodes[0];
-  is(notification.getAttribute("label"),
+  is(notification.getAttribute("startlabel"),
      "XPI Test could not be installed because it is not compatible with " +
      gApp + " " + gVersion + ".",
      "Should have seen the right message");
 
   Services.perms.remove(makeURI("http://example.com/"), "install");
   await removeTab();
 },
 
@@ -536,17 +536,17 @@ async function test_allUnverified() {
   let triggers = encodeURIComponent(JSON.stringify({
     "Extension XPI": "restartless-unsigned.xpi"
   }));
   BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers);
   await progressPromise;
   let installDialog = await dialogPromise;
 
   let notification = document.getElementById("addon-install-confirmation-notification");
-  let message = notification.getAttribute("label");
+  let message = notification.getAttribute("startlabel");
   is(message, "Caution: This site would like to install an unverified add-on in " + gApp + ". Proceed at your own risk.");
 
   let container = document.getElementById("addon-install-confirmation-content");
   is(container.childNodes.length, 1, "Should be one item listed");
   is(container.childNodes[0].firstChild.getAttribute("value"), "XPI Test", "Should have the right add-on");
   is(container.childNodes[0].childNodes.length, 1, "Shouldn't have the unverified marker");
 
   let notificationPromise = waitForNotification("addon-installed");
@@ -574,17 +574,17 @@ async function test_url() {
   let installDialog = await dialogPromise;
 
   let notificationPromise = waitForNotification("addon-install-restart");
   acceptInstallDialog(installDialog);
   let panel = await notificationPromise;
 
   let notification = panel.childNodes[0];
   is(notification.button.label, "Restart Now", "Should have seen the right button");
-  is(notification.getAttribute("label"),
+  is(notification.getAttribute("startlabel"),
      "XPI Test will be installed after you restart " + gApp + ".",
      "Should have seen the right message");
 
   let installs = await getInstalls();
   is(installs.length, 1, "Should be one pending install");
   installs[0].cancel();
 
   await removeTab();
@@ -611,17 +611,17 @@ async function test_localFile() {
   gBrowser.loadURI(path);
   await failPromise;
 
   // Wait for the browser code to add the failure notification
   await waitForSingleNotification();
 
   let notification = PopupNotifications.panel.childNodes[0];
   is(notification.id, "addon-install-failed-notification", "Should have seen the install fail");
-  is(notification.getAttribute("label"),
+  is(notification.getAttribute("startlabel"),
      "This add-on could not be installed because it appears to be corrupt.",
      "Should have seen the right message");
 
   await removeTab();
 },
 
 async function test_tabClose() {
   if (!Services.prefs.getBoolPref("xpinstall.customConfirmationUI", false)) {
@@ -700,17 +700,17 @@ async function test_urlBar() {
   let installDialog = await dialogPromise;
 
   let notificationPromise = waitForNotification("addon-install-restart");
   acceptInstallDialog(installDialog);
   let panel = await notificationPromise;
 
   let notification = panel.childNodes[0];
   is(notification.button.label, "Restart Now", "Should have seen the right button");
-  is(notification.getAttribute("label"),
+  is(notification.getAttribute("startlabel"),
      "XPI Test will be installed after you restart " + gApp + ".",
      "Should have seen the right message");
 
   let installs = await getInstalls();
   is(installs.length, 1, "Should be one pending install");
   installs[0].cancel();
 
   await removeTab();
@@ -726,17 +726,17 @@ async function test_wrongHost() {
 
   let progressPromise = waitForProgressNotification();
   let notificationPromise = waitForNotification("addon-install-failed");
   gBrowser.loadURI(TESTROOT + "corrupt.xpi");
   await progressPromise;
   let panel = await notificationPromise;
 
   let notification = panel.childNodes[0];
-  is(notification.getAttribute("label"),
+  is(notification.getAttribute("startlabel"),
      "The add-on downloaded from this site could not be installed " +
      "because it appears to be corrupt.",
      "Should have seen the right message");
 
   await removeTab();
 },
 
 async function test_reload() {
@@ -753,17 +753,17 @@ async function test_reload() {
   let installDialog = await dialogPromise;
 
   let notificationPromise = waitForNotification("addon-install-restart");
   acceptInstallDialog(installDialog);
   let panel = await notificationPromise;
 
   let notification = panel.childNodes[0];
   is(notification.button.label, "Restart Now", "Should have seen the right button");
-  is(notification.getAttribute("label"),
+  is(notification.getAttribute("startlabel"),
      "XPI Test will be installed after you restart " + gApp + ".",
      "Should have seen the right message");
 
   function testFail() {
     ok(false, "Reloading should not have hidden the notification");
   }
   PopupNotifications.panel.addEventListener("popuphiding", testFail);
   let requestedUrl = TESTROOT2 + "enabled.html";
@@ -794,17 +794,17 @@ async function test_theme() {
   let installDialog = await dialogPromise;
 
   let notificationPromise = waitForNotification("addon-install-restart");
   acceptInstallDialog(installDialog);
   let panel = await notificationPromise;
 
   let notification = panel.childNodes[0];
   is(notification.button.label, "Restart Now", "Should have seen the right button");
-  is(notification.getAttribute("label"),
+  is(notification.getAttribute("startlabel"),
      "Theme Test will be installed after you restart " + gApp + ".",
      "Should have seen the right message");
 
   let addon = await new Promise(resolve => {
     AddonManager.getAddonByID("{972ce4c6-7e08-4474-a285-3208198ce6fd}", function(result) {
       resolve(result);
     });
   });
--- a/browser/base/content/test/popupNotifications/head.js
+++ b/browser/base/content/test/popupNotifications/head.js
@@ -198,17 +198,25 @@ function checkPopup(popup, notifyObj) {
     return;
   let icon = document.getAnonymousElementByAttribute(notification, "class",
                                                      "popup-notification-icon");
   if (notifyObj.id == "geolocation") {
     isnot(icon.boxObject.width, 0, "icon for geo displayed");
     ok(popup.anchorNode.classList.contains("notification-anchor-icon"),
        "notification anchored to icon");
   }
-  is(notification.getAttribute("label"), notifyObj.message, "message matches");
+
+  if (typeof notifyObj.message == "string") {
+    is(notification.getAttribute("startlabel"), notifyObj.message, "message matches");
+  } else {
+    is(notification.getAttribute("startlabel"), notifyObj.message.start, "message matches");
+    is(notification.getAttribute("hostname"), notifyObj.message.host, "message matches");
+    is(notification.getAttribute("endlabel"), notifyObj.message.end, "message matches");
+  }
+
   is(notification.id, notifyObj.id + "-notification", "id matches");
   if (notifyObj.mainAction) {
     is(notification.getAttribute("buttonlabel"), notifyObj.mainAction.label,
        "main action label matches");
     is(notification.getAttribute("buttonaccesskey"),
        notifyObj.mainAction.accessKey, "main action accesskey matches");
     is(notification.getAttribute("buttonhighlight"),
        (!notifyObj.mainAction.disableHighlight).toString(),
--- a/browser/base/content/test/tabPrompts/browser_openPromptInBackgroundTab.js
+++ b/browser/base/content/test/tabPrompts/browser_openPromptInBackgroundTab.js
@@ -70,10 +70,16 @@ add_task(async function() {
 
   // This is sync in non-e10s, but in e10s we need to wait for this, so yield anyway.
   // Note that the switchTab promise doesn't actually guarantee anything about *which*
   // tab ends up as selected when its event fires, so using that here wouldn't work.
   await openedTabSelectedPromise;
   // should be switched back
   ok(openedTab.selected, "Ta-dah, the other tab should now be selected again!");
 
+  // In e10s, with the conformant promise scheduling, we have to wait for next tick
+  // to ensure that the prompt is open before removing the opened tab, because the
+  // promise callback of 'openedTabSelectedPromise' could be done at the middle of
+  // RemotePrompt.openTabPrompt() while 'DOMModalDialogClosed' event is fired.
+  await TestUtils.waitForTick();
+
   await BrowserTestUtils.removeTab(openedTab);
 });
--- a/browser/components/customizableui/CustomizeMode.jsm
+++ b/browser/components/customizableui/CustomizeMode.jsm
@@ -273,18 +273,16 @@ CustomizeMode.prototype = {
               resolve();
             }
           };
 
           Services.obs.addObserver(delayedStartupObserver, "browser-delayed-startup-finished");
         });
       }
 
-      this.updateLWTStyling();
-
       CustomizableUI.dispatchToolboxEvent("beforecustomization", {}, window);
       CustomizableUI.notifyStartCustomizing(this.window);
 
       // Add a keypress listener to the document so that we can quickly exit
       // customization mode when pressing ESC.
       document.addEventListener("keypress", this);
 
       // Same goes for the menu button - if we're customizing, a click on the
@@ -310,18 +308,16 @@ CustomizeMode.prototype = {
       this._wrapToolbarItemSync(CustomizableUI.AREA_TABSTRIP);
 
       let customizableToolbars = document.querySelectorAll("toolbar[customizable=true]:not([autohide=true]):not([collapsed=true])");
       for (let toolbar of customizableToolbars)
         toolbar.setAttribute("customizing", true);
 
       await this._doTransition(true);
 
-      Services.obs.addObserver(this, "lightweight-theme-window-updated");
-
       // Let everybody in this window know that we're about to customize.
       CustomizableUI.dispatchToolboxEvent("customizationstarting", {}, window);
 
       await this._wrapToolbarItems();
       this.populatePalette();
 
       this._setupPaletteDragging();
 
@@ -405,19 +401,16 @@ CustomizeMode.prototype = {
     undoResetButton.hidden = resetButton.disabled = true;
 
     this._transitioning = true;
 
     (async () => {
       await this.depopulatePalette();
 
       await this._doTransition(false);
-      this.updateLWTStyling({});
-
-      Services.obs.removeObserver(this, "lightweight-theme-window-updated");
 
       if (this.browser.selectedTab == gTab) {
         if (gTab.linkedBrowser.currentURI.spec == "about:blank") {
           closeGlobalTab();
         } else {
           unregisterGlobalTab();
         }
       }
@@ -510,36 +503,16 @@ CustomizeMode.prototype = {
       docEl.setAttribute("customize-entered", true);
     } else {
       docEl.removeAttribute("customizing");
       docEl.removeAttribute("customize-entered");
     }
     return Promise.resolve();
   },
 
-  updateLWTStyling(aData) {
-    let docElement = this.document.documentElement;
-    if (!aData) {
-      let lwt = docElement._lightweightTheme;
-      aData = lwt.getData();
-    }
-    let headerURL = aData && aData.headerURL;
-    if (!headerURL) {
-      docElement.removeAttribute("customization-lwtheme");
-      return;
-    }
-    docElement.setAttribute("customization-lwtheme", "true");
-
-    let deck = this.document.getElementById("tab-view-deck");
-    let toolboxRect = this.window.gNavToolbox.getBoundingClientRect();
-    let height = toolboxRect.bottom;
-    deck.style.setProperty("--toolbox-rect-height", `${height}`);
-    deck.style.setProperty("--toolbox-rect-height-with-unit", `${height}px`);
-  },
-
   _getCustomizableChildForNode(aNode) {
     // NB: adjusted from _getCustomizableParent to keep that method fast
     // (it's used during drags), and avoid multiple DOM loops
     let areas = CustomizableUI.areas;
     // Caching this length is important because otherwise we'll also iterate
     // over items we add to the end from within the loop.
     let numberOfAreas = areas.length;
     for (let i = 0; i < numberOfAreas; i++) {
@@ -1168,17 +1141,16 @@ CustomizeMode.prototype = {
   _onToolbarVisibilityChange(aEvent) {
     let toolbar = aEvent.target;
     if (aEvent.detail.visible && toolbar.getAttribute("customizable") == "true") {
       toolbar.setAttribute("customizing", "true");
     } else {
       toolbar.removeAttribute("customizing");
     }
     this._onUIChange();
-    this.updateLWTStyling();
   },
 
   onWidgetMoved(aWidgetId, aArea, aOldPosition, aNewPosition) {
     this._onUIChange();
   },
 
   onWidgetAdded(aWidgetId, aArea, aPosition) {
     this._onUIChange();
@@ -1616,22 +1588,16 @@ CustomizeMode.prototype = {
       case "nsPref:changed":
         this._updateResetButton();
         this._updateUndoResetButton();
         if (AppConstants.CAN_DRAW_IN_TITLEBAR) {
           this._updateTitlebarCheckbox();
           this._updateDragSpaceCheckbox();
         }
         break;
-      case "lightweight-theme-window-updated":
-        if (aSubject == this.window) {
-          aData = JSON.parse(aData);
-          this.updateLWTStyling(aData);
-        }
-        break;
     }
   },
 
   _updateTitlebarCheckbox() {
     if (!AppConstants.CAN_DRAW_IN_TITLEBAR) {
       return;
     }
     let drawInTitlebar = Services.prefs.getBoolPref(kDrawInTitlebarPref, true);
--- a/browser/components/extensions/ext-browserAction.js
+++ b/browser/components/extensions/ext-browserAction.js
@@ -602,16 +602,21 @@ this.browserAction = class extends Exten
           browserAction.setProperty(tab, "enabled", true);
         },
 
         disable: function(tabId) {
           let tab = getTab(tabId);
           browserAction.setProperty(tab, "enabled", false);
         },
 
+        isEnabled: function(details) {
+          let tab = getTab(details.tabId);
+          return browserAction.getProperty(tab, "enabled");
+        },
+
         setTitle: function(details) {
           let tab = getTab(details.tabId);
 
           browserAction.setProperty(tab, "title", details.title);
         },
 
         getTitle: function(details) {
           let tab = getTab(details.tabId);
--- a/browser/components/extensions/ext-pageAction.js
+++ b/browser/components/extensions/ext-pageAction.js
@@ -36,17 +36,17 @@ this.pageAction = class extends Extensio
     let options = extension.manifest.page_action;
 
     let widgetId = makeWidgetId(extension.id);
     this.id = widgetId + "-page-action";
 
     this.tabManager = extension.tabManager;
 
     // If <all_urls> is present, the default is to show the page action.
-    let show = options.show_matches && options.show_matches.includes("<all_urls>");
+    let show = !!options.show_matches && options.show_matches.includes("<all_urls>");
     let showMatches = new MatchPatternSet(options.show_matches || []);
     let hideMatches = new MatchPatternSet(options.hide_matches || []);
 
     this.defaults = {
       show,
       showMatches,
       hideMatches,
       title: options.default_title || extension.name,
@@ -267,16 +267,21 @@ this.pageAction = class extends Extensio
           pageAction.setProperty(tab, "show", true);
         },
 
         hide(tabId) {
           let tab = tabTracker.getTab(tabId);
           pageAction.setProperty(tab, "show", false);
         },
 
+        isShown(details) {
+          let tab = tabTracker.getTab(details.tabId);
+          return pageAction.getProperty(tab, "show");
+        },
+
         setTitle(details) {
           let tab = tabTracker.getTab(details.tabId);
 
           // Clear the tab-specific title when given a null string.
           pageAction.setProperty(tab, "title", details.title || null);
         },
 
         getTitle(details) {
--- a/browser/components/extensions/ext-sidebarAction.js
+++ b/browser/components/extensions/ext-sidebarAction.js
@@ -1,14 +1,15 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
 // The ext-* files are imported into the same scopes.
 /* import-globals-from ext-browser.js */
+/* globals WINDOW_ID_CURRENT */
 
 Cu.import("resource://gre/modules/ExtensionParent.jsm");
 
 var {
   ExtensionError,
 } = ExtensionUtils;
 
 var {
@@ -183,17 +184,18 @@ this.sidebarAction = class extends Exten
     let toolbarbutton = document.createElementNS(XUL_NS, "toolbarbutton");
     toolbarbutton.setAttribute("id", this.buttonId);
     toolbarbutton.setAttribute("observes", this.id);
     toolbarbutton.setAttribute("class", "subviewbutton subviewbutton-iconic webextension-menuitem");
     this.setMenuIcon(toolbarbutton, details);
 
     document.getElementById("mainBroadcasterSet").appendChild(broadcaster);
     document.getElementById("viewSidebarMenu").appendChild(menuitem);
-    document.getElementById("sidebar-extensions").appendChild(toolbarbutton);
+    let separator = document.getElementById("sidebar-extensions-separator");
+    separator.parentNode.insertBefore(toolbarbutton, separator);
 
     return menuitem;
   }
 
   setMenuIcon(menuitem, details) {
     let getIcon = size => IconDetails.escapeUrl(
       IconDetails.getPreferredIcon(details.icon, this.extension, size).icon);
 
@@ -343,20 +345,30 @@ this.sidebarAction = class extends Exten
   }
 
   /**
    * Closes this sidebar action for the given window if this sidebar action is open.
    *
    * @param {ChromeWindow} window
    */
   close(window) {
+    if (this.isOpen(window)) {
+      window.SidebarUI.hide();
+    }
+  }
+
+  /**
+   * Checks whether this sidebar action is open in the given window.
+   *
+   * @param {ChromeWindow} window
+   * @returns {boolean}
+   */
+  isOpen(window) {
     let {SidebarUI} = window;
-    if (SidebarUI.isOpen && this.id == SidebarUI.currentID) {
-      SidebarUI.hide();
-    }
+    return SidebarUI.isOpen && this.id == SidebarUI.currentID;
   }
 
   getAPI(context) {
     let {extension} = context;
     const sidebarAction = this;
 
     function getTab(tabId) {
       if (tabId !== null) {
@@ -422,14 +434,23 @@ this.sidebarAction = class extends Exten
           let window = windowTracker.topWindow;
           sidebarAction.open(window);
         },
 
         close() {
           let window = windowTracker.topWindow;
           sidebarAction.close(window);
         },
+
+        isOpen(details) {
+          let {windowId} = details;
+          if (windowId == null) {
+            windowId = WINDOW_ID_CURRENT;
+          }
+          let window = windowTracker.getWindow(windowId, context);
+          return sidebarAction.isOpen(window);
+        },
       },
     };
   }
 };
 
 global.sidebarActionFor = this.sidebarAction.for;
--- a/browser/components/extensions/ext-tabs.js
+++ b/browser/components/extensions/ext-tabs.js
@@ -546,16 +546,24 @@ this.tabs = class extends ExtensionAPI {
           if (queryInfo.title !== null) {
             queryInfo.title = new MatchGlob(queryInfo.title);
           }
 
           return Array.from(tabManager.query(queryInfo, context),
                             tab => tab.convert());
         },
 
+        async captureTab(tabId, options) {
+          let nativeTab = getTabOrActive(tabId);
+          await tabListener.awaitTabReady(nativeTab);
+
+          let tab = tabManager.wrapTab(nativeTab);
+          return tab.capture(context, options);
+        },
+
         async captureVisibleTab(windowId, options) {
           let window = windowId == null ?
             windowTracker.topWindow :
             windowTracker.getWindow(windowId, context);
 
           let tab = tabManager.wrapTab(window.gBrowser.selectedTab);
           await tabListener.awaitTabReady(tab.nativeTab);
 
--- a/browser/components/extensions/schemas/browser_action.json
+++ b/browser/components/extensions/schemas/browser_action.json
@@ -413,16 +413,35 @@
             "type": "function",
             "name": "callback",
             "optional": true,
             "parameters": []
           }
         ]
       },
       {
+        "name": "isEnabled",
+        "type": "function",
+        "description": "Checks whether the browser action is enabled.",
+        "async": true,
+        "parameters": [
+          {
+            "name": "details",
+            "type": "object",
+            "properties": {
+              "tabId": {
+                "type": "integer",
+                "optional": true,
+                "description": "Specify the tab to get the enabledness from. If no tab is specified, the non-tab-specific enabledness is returned."
+              }
+            }
+          }
+        ]
+      },
+      {
         "name": "openPopup",
         "type": "function",
         "requireUserInput": true,
         "description": "Opens the extension popup window in the active window.",
         "async": true,
         "parameters": []
       }
     ],
--- a/browser/components/extensions/schemas/page_action.json
+++ b/browser/components/extensions/schemas/page_action.json
@@ -92,16 +92,34 @@
             "type": "function",
             "name": "callback",
             "optional": true,
             "parameters": []
           }
         ]
       },
       {
+        "name": "isShown",
+        "type": "function",
+        "description": "Checks whether the page action is shown.",
+        "async": true,
+        "parameters": [
+          {
+            "name": "details",
+            "type": "object",
+            "properties": {
+              "tabId": {
+                "type": "integer",
+                "description": "Specify the tab to get the shownness from."
+              }
+            }
+          }
+        ]
+      },
+      {
         "name": "setTitle",
         "type": "function",
         "description": "Sets the title of the page action. This is displayed in a tooltip over the page action.",
         "parameters": [
           {
             "name": "details",
             "type": "object",
             "properties": {
--- a/browser/components/extensions/schemas/sidebar_action.json
+++ b/browser/components/extensions/schemas/sidebar_action.json
@@ -192,12 +192,32 @@
       },
       {
         "name": "close",
         "type": "function",
         "requireUserInput": true,
         "description": "Closes the extension sidebar in the active window if the sidebar belongs to the extension.",
         "async": true,
         "parameters": []
+      },
+      {
+        "name": "isOpen",
+        "type": "function",
+        "description": "Checks whether the sidebar action is open.",
+        "async": true,
+        "parameters": [
+          {
+            "name": "details",
+            "type": "object",
+            "properties": {
+              "windowId": {
+                "type": "integer",
+                "minimum": -2,
+                "optional": true,
+                "description": "Specify the window to get the openness from."
+              }
+            }
+          }
+        ]
       }
     ]
   }
 ]
--- a/browser/components/extensions/schemas/tabs.json
+++ b/browser/components/extensions/schemas/tabs.json
@@ -932,16 +932,37 @@
             "name": "tabId",
             "minimum": 0,
             "optional": true,
             "description": "Defaults to the active tab of the $(topic:current-window)[current window]."
           }
         ]
       },
       {
+        "name": "captureTab",
+        "type": "function",
+        "description": "Captures the visible area of a specified tab. You must have $(topic:declare_permissions)[&lt;all_urls&gt;] permission to use this method.",
+        "permissions": ["<all_urls>"],
+        "async": true,
+        "parameters": [
+          {
+            "type": "integer",
+            "name": "tabId",
+            "minimum": 0,
+            "optional": true,
+            "description": "The tab to capture. Defaults to the active tab of the current window."
+          },
+          {
+            "$ref": "extensionTypes.ImageDetails",
+            "name": "options",
+            "optional": true
+          }
+        ]
+      },
+      {
         "name": "captureVisibleTab",
         "type": "function",
         "description": "Captures the visible area of the currently active tab in the specified window. You must have $(topic:declare_permissions)[&lt;all_urls&gt;] permission to use this method.",
         "permissions": ["<all_urls>"],
         "async": "callback",
         "parameters": [
           {
             "type": "integer",
--- a/browser/components/extensions/test/browser/browser-common.ini
+++ b/browser/components/extensions/test/browser/browser-common.ini
@@ -130,16 +130,17 @@ skip-if = (os == 'win' && ccov) # Bug 14
 [browser_ext_sidebarAction_contextMenu.js]
 [browser_ext_sidebarAction_tabs.js]
 [browser_ext_sidebarAction_windows.js]
 [browser_ext_simple.js]
 [browser_ext_slow_script.js]
 skip-if = !e10s || debug || asan
 [browser_ext_tab_runtimeConnect.js]
 [browser_ext_tabs_audio.js]
+[browser_ext_tabs_captureTab.js]
 [browser_ext_tabs_captureVisibleTab.js]
 [browser_ext_tabs_create.js]
 skip-if = os == "linux" && debug && bits == 32 # Bug 1350189
 [browser_ext_tabs_create_invalid_url.js]
 [browser_ext_tabs_detectLanguage.js]
 [browser_ext_tabs_discard.js]
 skip-if = !e10s
 [browser_ext_tabs_discarded.js]
--- a/browser/components/extensions/test/browser/browser_ext_browserAction_context.js
+++ b/browser/components/extensions/test/browser/browser_ext_browserAction_context.js
@@ -16,16 +16,20 @@ async function runTests(options) {
       let badge = await browser.browserAction.getBadgeText({tabId});
       browser.test.assertEq(expecting.badge, badge,
                             "expected value from getBadge");
 
       let badgeBackgroundColor = await browser.browserAction.getBadgeBackgroundColor({tabId});
       browser.test.assertEq(String(expecting.badgeBackgroundColor),
                             String(badgeBackgroundColor),
                             "expected value from getBadgeBackgroundColor");
+
+      let enabled = await browser.browserAction.isEnabled({tabId});
+      browser.test.assertEq(!expecting.disabled, enabled,
+                            "expected value from isEnabled");
     }
 
     let expectDefaults = expecting => {
       return checkDetails(expecting);
     };
 
     let tabs = [];
     let tests = getTests(tabs, expectDefaults);
@@ -280,17 +284,17 @@ add_task(async function testTabSwitchCon
 
           await expectDefaults(details[4]);
           expect(details[4]);
         },
         async expect => {
           browser.test.log("Switch back to tab 2. Expect former value, unaffected by changes to defaults in previous step.");
           await browser.tabs.update(tabs[1], {active: true});
 
-          await expectDefaults(details[3]);
+          await expectDefaults(details[4]);
           expect(details[2]);
         },
         expect => {
           browser.test.log("Navigate to a new page. Expect defaults.");
 
           browser.tabs.onUpdated.addListener(function listener(tabId, changed) {
             if (tabId == tabs[1] && changed.url) {
               browser.tabs.onUpdated.removeListener(listener);
--- a/browser/components/extensions/test/browser/browser_ext_sidebarAction.js
+++ b/browser/components/extensions/test/browser/browser_ext_sidebarAction.js
@@ -27,28 +27,38 @@ let extData = {
     "sidebar.js": function() {
       window.onload = () => {
         browser.test.sendMessage("sidebar");
       };
     },
   },
 
   background: function() {
-    browser.test.onMessage.addListener(msg => {
+    browser.test.onMessage.addListener(async ({msg, data}) => {
       if (msg === "set-panel") {
-        browser.sidebarAction.setPanel({panel: ""}).then(() => {
+        await browser.sidebarAction.setPanel({panel: ""}).then(() => {
           browser.test.notifyFail("empty panel settable");
         }).catch(() => {
           browser.test.notifyPass("unable to set empty panel");
         });
+      } else if (msg === "isOpen") {
+        let {arg = {}, result} = data;
+        let isOpen = await browser.sidebarAction.isOpen(arg);
+        browser.test.assertEq(result, isOpen, "expected value from isOpen");
       }
+      browser.test.sendMessage("done");
     });
   },
 };
 
+async function sendMessage(ext, msg, data = undefined) {
+  ext.sendMessage({msg, data});
+  await ext.awaitMessage("done");
+}
+
 add_task(async function sidebar_initial_install() {
   ok(document.getElementById("sidebar-box").hidden, "sidebar box is not visible");
   let extension = ExtensionTestUtils.loadExtension(extData);
   await extension.startup();
   // Test sidebar is opened on install
   await extension.awaitMessage("sidebar");
   ok(!document.getElementById("sidebar-box").hidden, "sidebar box is visible");
 
@@ -80,12 +90,68 @@ add_task(async function sidebar_two_side
 });
 
 add_task(async function sidebar_empty_panel() {
   let extension = ExtensionTestUtils.loadExtension(extData);
   await extension.startup();
   // Test sidebar is opened on install
   await extension.awaitMessage("sidebar");
   ok(!document.getElementById("sidebar-box").hidden, "sidebar box is visible in first window");
-  extension.sendMessage("set-panel");
+  await sendMessage(extension, "set-panel");
   await extension.awaitFinish();
   await extension.unload();
 });
+
+add_task(async function sidebar_isOpen() {
+  info("Load extension1");
+  let extension1 = ExtensionTestUtils.loadExtension(extData);
+  await extension1.startup();
+
+  info("Test extension1's sidebar is opened on install");
+  await extension1.awaitMessage("sidebar");
+  await sendMessage(extension1, "isOpen", {result: true});
+  let sidebar1ID = SidebarUI.currentID;
+
+  info("Load extension2");
+  let extension2 = ExtensionTestUtils.loadExtension(extData);
+  await extension2.startup();
+
+  info("Test extension2's sidebar is opened on install");
+  await extension2.awaitMessage("sidebar");
+  await sendMessage(extension1, "isOpen", {result: false});
+  await sendMessage(extension2, "isOpen", {result: true});
+
+  info("Switch back to extension1's sidebar");
+  SidebarUI.show(sidebar1ID);
+  await extension1.awaitMessage("sidebar");
+  await sendMessage(extension1, "isOpen", {result: true});
+  await sendMessage(extension2, "isOpen", {result: false});
+
+  info("Test passing a windowId parameter");
+  let windowId = window.getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
+  let WINDOW_ID_CURRENT = -2;
+  await sendMessage(extension1, "isOpen", {arg: {windowId}, result: true});
+  await sendMessage(extension2, "isOpen", {arg: {windowId}, result: false});
+  await sendMessage(extension1, "isOpen", {arg: {windowId: WINDOW_ID_CURRENT}, result: true});
+  await sendMessage(extension2, "isOpen", {arg: {windowId: WINDOW_ID_CURRENT}, result: false});
+
+  info("Open a new window");
+  let newWin = open();
+
+  info("The new window has no sidebar");
+  await sendMessage(extension1, "isOpen", {result: false});
+  await sendMessage(extension2, "isOpen", {result: false});
+
+  info("But the original window still does");
+  await sendMessage(extension1, "isOpen", {arg: {windowId}, result: true});
+  await sendMessage(extension2, "isOpen", {arg: {windowId}, result: false});
+
+  info("Close the new window");
+  newWin.close();
+
+  info("Close the sidebar in the original window");
+  SidebarUI.hide();
+  await sendMessage(extension1, "isOpen", {result: false});
+  await sendMessage(extension2, "isOpen", {result: false});
+
+  await extension1.unload();
+  await extension2.unload();
+});
copy from browser/components/extensions/test/browser/browser_ext_tabs_captureVisibleTab.js
copy to browser/components/extensions/test/browser/browser_ext_tabs_captureTab.js
--- a/browser/components/extensions/test/browser/browser_ext_tabs_captureVisibleTab.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_captureTab.js
@@ -28,20 +28,20 @@ async function runTest(options) {
 
   async function background(options) {
     browser.test.log(`Test color ${options.color} at fullZoom=${options.fullZoom}`);
 
     try {
       let [tab] = await browser.tabs.query({currentWindow: true, active: true});
 
       let [jpeg, png, ...pngs] = await Promise.all([
-        browser.tabs.captureVisibleTab(tab.windowId, {format: "jpeg", quality: 95}),
-        browser.tabs.captureVisibleTab(tab.windowId, {format: "png", quality: 95}),
-        browser.tabs.captureVisibleTab(tab.windowId, {quality: 95}),
-        browser.tabs.captureVisibleTab(tab.windowId),
+        browser.tabs.captureTab(tab.id, {format: "jpeg", quality: 95}),
+        browser.tabs.captureTab(tab.id, {format: "png", quality: 95}),
+        browser.tabs.captureTab(tab.id, {quality: 95}),
+        browser.tabs.captureTab(tab.id),
       ]);
 
       browser.test.assertTrue(pngs.every(url => url == png), "All PNGs are identical");
 
       browser.test.assertTrue(jpeg.startsWith("data:image/jpeg;base64,"), "jpeg is JPEG");
       browser.test.assertTrue(png.startsWith("data:image/png;base64,"), "png is PNG");
 
       let promises = [jpeg, png].map(url => new Promise(resolve => {
@@ -95,61 +95,61 @@ async function runTest(options) {
             browser.test.assertTrue(Math.abs(color[0] - imageData[0]) <= SLOP, `${format} image color.red is correct at (${x}, ${y})`);
             browser.test.assertTrue(Math.abs(color[1] - imageData[1]) <= SLOP, `${format} image color.green is correct at (${x}, ${y})`);
             browser.test.assertTrue(Math.abs(color[2] - imageData[2]) <= SLOP, `${format} image color.blue is correct at (${x}, ${y})`);
             browser.test.assertEq(255, imageData[3], `${format} image color.alpha is correct at (${x}, ${y})`);
           }
         }
       }
 
-      browser.test.notifyPass("captureVisibleTab");
+      browser.test.notifyPass("captureTab");
     } catch (e) {
       browser.test.fail(`Error: ${e} :: ${e.stack}`);
-      browser.test.notifyFail("captureVisibleTab");
+      browser.test.notifyFail("captureTab");
     }
   }
 
   let extension = ExtensionTestUtils.loadExtension({
     manifest: {
       "permissions": ["<all_urls>"],
     },
 
     background: `(${background})(${JSON.stringify(options)})`,
   });
 
   await extension.startup();
 
-  await extension.awaitFinish("captureVisibleTab");
+  await extension.awaitFinish("captureTab");
 
   await extension.unload();
 
   await BrowserTestUtils.removeTab(tab);
 }
 
-add_task(async function testCaptureVisibleTab() {
+add_task(async function testCaptureTab() {
   await runTest({color: [0, 0, 0], fullZoom: 1});
 
   await runTest({color: [0, 0, 0], fullZoom: 2});
 
   await runTest({color: [0, 0, 0], fullZoom: 0.5});
 
   await runTest({color: [255, 255, 255], fullZoom: 1});
 });
 
-add_task(async function testCaptureVisibleTabPermissions() {
+add_task(async function testCaptureTabPermissions() {
   let extension = ExtensionTestUtils.loadExtension({
     manifest: {
       "permissions": ["tabs"],
     },
 
     background() {
-      browser.test.assertEq(undefined, browser.tabs.captureVisibleTab,
-                            'Extension without "<all_urls>" permission should not have access to captureVisibleTab');
-      browser.test.notifyPass("captureVisibleTabPermissions");
+      browser.test.assertEq(undefined, browser.tabs.captureTab,
+                            'Extension without "<all_urls>" permission should not have access to captureTab');
+      browser.test.notifyPass("captureTabPermissions");
     },
   });
 
   await extension.startup();
 
-  await extension.awaitFinish("captureVisibleTabPermissions");
+  await extension.awaitFinish("captureTabPermissions");
 
   await extension.unload();
 });
--- a/browser/components/extensions/test/browser/head_pageAction.js
+++ b/browser/components/extensions/test/browser/head_pageAction.js
@@ -29,44 +29,47 @@ async function runTests(options) {
       let [tab] = await browser.tabs.query({active: true, currentWindow: true});
       let tabId = tab.id;
 
       browser.test.log(`Get details: tab={id: ${tabId}, url: ${JSON.stringify(tab.url)}}`);
 
       return {
         title: await browser.pageAction.getTitle({tabId}),
         popup: await browser.pageAction.getPopup({tabId}),
+        isShown: await browser.pageAction.isShown({tabId}),
       };
     }
 
 
     // Runs the next test in the `tests` array, checks the results,
     // and passes control back to the outer test scope.
     function nextTest() {
       let test = tests.shift();
 
       test(async expecting => {
         function finish() {
           // Check that the actual icon has the expected values, then
           // run the next test.
           browser.test.sendMessage("nextTest", expecting, tests.length);
         }
 
+        // Check that the API returns the expected values, and then
+        // run the next test.
+        let details = await getDetails();
         if (expecting) {
-          // Check that the API returns the expected values, and then
-          // run the next test.
-          let details = await getDetails();
-
           browser.test.assertEq(expecting.title, details.title,
                                 "expected value from getTitle");
 
           browser.test.assertEq(expecting.popup, details.popup,
                                 "expected value from getPopup");
         }
 
+        browser.test.assertEq(!!expecting, details.isShown,
+                              "expected value from isShown");
+
         finish();
       });
     }
 
     async function runTests() {
       tabs = [];
       tests = getTests(tabs);
 
rename from browser/config/mozconfigs/win32/debug-searchfox
rename to browser/config/mozconfigs/win64/debug-searchfox
--- a/browser/config/mozconfigs/win32/debug-searchfox
+++ b/browser/config/mozconfigs/win64/debug-searchfox
@@ -1,17 +1,18 @@
 MOZ_AUTOMATION_BUILD_SYMBOLS=0
 MOZ_AUTOMATION_PACKAGE_TESTS=0
 MOZ_AUTOMATION_L10N_CHECK=0
 
 . "$topsrcdir/build/mozconfig.win-common"
 . "$topsrcdir/browser/config/mozconfigs/common"
+. "$topsrcdir/browser/config/mozconfigs/win64/common-win64"
 
 ac_add_options --enable-optimize
 ac_add_options --enable-debug
 
 ac_add_options --enable-clang-plugin
 ac_add_options --enable-mozsearch-plugin
 
-. $topsrcdir/build/win32/mozconfig.vs-latest
+. $topsrcdir/build/win64/mozconfig.vs-latest
 
 . "$topsrcdir/build/mozconfig.common.override"
 . "$topsrcdir/build/mozconfig.clang-cl"
--- a/browser/extensions/formautofill/ProfileStorage.jsm
+++ b/browser/extensions/formautofill/ProfileStorage.jsm
@@ -371,17 +371,20 @@ class AutofillRecords {
       let sync = this._getSyncMetaData(recordToSave, true);
       sync.changeCounter = 0;
     }
 
     this._data.push(recordToSave);
 
     this._store.saveSoon();
 
-    Services.obs.notifyObservers({wrappedJSObject: {sourceSync}}, "formautofill-storage-changed", "add");
+    Services.obs.notifyObservers({wrappedJSObject: {
+      sourceSync,
+      collectionName: this._collectionName,
+    }}, "formautofill-storage-changed", "add");
     return recordToSave.guid;
   }
 
   _generateGUID() {
     let guid;
     while (!guid || this._findByGUID(guid)) {
       guid = gUUIDGenerator.generateUUID().toString()
                            .replace(/[{}-]/g, "").substring(0, 12);
@@ -444,19 +447,20 @@ class AutofillRecords {
       syncMetadata.changeCounter += 1;
     }
 
     this._computeFields(recordFound);
     this._data[recordFoundIndex] = recordFound;
 
     this._store.saveSoon();
 
-    let str = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
-    str.data = guid;
-    Services.obs.notifyObservers(str, "formautofill-storage-changed", "update");
+    Services.obs.notifyObservers({wrappedJSObject: {
+      guid,
+      collectionName: this._collectionName,
+    }}, "formautofill-storage-changed", "update");
   }
 
   /**
    * Notifies the storage of the use of the specified record, so we can update
    * the metadata accordingly. This does not bump the Sync change counter, since
    * we don't sync `timesUsed` or `timeLastUsed`.
    *
    * @param  {string} guid
@@ -514,17 +518,20 @@ class AutofillRecords {
       } else {
         // If there's no sync meta-data, this record has never been synced, so
         // we can delete it.
         this._data.splice(index, 1);
       }
     }
 
     this._store.saveSoon();
-    Services.obs.notifyObservers({wrappedJSObject: {sourceSync}}, "formautofill-storage-changed", "remove");
+    Services.obs.notifyObservers({wrappedJSObject: {
+      sourceSync,
+      collectionName: this._collectionName,
+    }}, "formautofill-storage-changed", "remove");
   }
 
   /**
    * Returns the record with the specified GUID.
    *
    * @param   {string} guid
    *          Indicates which record to retrieve.
    * @param   {boolean} [options.rawData = false]
@@ -833,16 +840,17 @@ class AutofillRecords {
           keepSyncMetadata: false,
         });
       }
     }
 
     this._store.saveSoon();
     Services.obs.notifyObservers({wrappedJSObject: {
       sourceSync: true,
+      collectionName: this._collectionName,
     }}, "formautofill-storage-changed", "reconcile");
 
     return {forkedGUID};
   }
 
   _removeSyncedRecord(guid) {
     let index = this._findIndexByGUID(guid, {includeDeleted: true});
     if (index == -1) {
--- a/browser/extensions/formautofill/test/browser/browser.ini
+++ b/browser/extensions/formautofill/test/browser/browser.ini
@@ -10,16 +10,15 @@ support-files =
 [browser_autocomplete_footer.js]
 [browser_autocomplete_marked_back_forward.js]
 [browser_autocomplete_marked_detached_tab.js]
 [browser_check_installed.js]
 [browser_creditCard_doorhanger.js]
 [browser_dropdown_layout.js]
 [browser_editAddressDialog.js]
 [browser_editCreditCardDialog.js]
-skip-if = true # Bug 1427510
 [browser_first_time_use_doorhanger.js]
 [browser_insecure_form.js]
 [browser_manageAddressesDialog.js]
 [browser_manageCreditCardsDialog.js]
 [browser_privacyPreferences.js]
 [browser_submission_in_private_mode.js]
 [browser_update_doorhanger.js]
--- a/browser/extensions/formautofill/test/browser/browser_creditCard_doorhanger.js
+++ b/browser/extensions/formautofill/test/browser/browser_creditCard_doorhanger.js
@@ -132,17 +132,17 @@ add_task(async function test_submit_chan
         let name = form.querySelector("#cc-name");
 
         name.focus();
         await new Promise(resolve => setTimeout(resolve, 1000));
         name.setUserInput("");
 
         form.querySelector("#cc-number").setUserInput("1234567812345678");
         form.querySelector("#cc-exp-month").setUserInput("4");
-        form.querySelector("#cc-exp-year").setUserInput("2017");
+        form.querySelector("#cc-exp-year").setUserInput(new Date().getFullYear());
         // Wait 1000ms before submission to make sure the input value applied
         await new Promise(resolve => setTimeout(resolve, 1000));
         form.querySelector("input[type=submit]").click();
       });
 
       await promiseShown;
       await clickDoorhangerButton(MAIN_BUTTON);
     }
@@ -170,17 +170,17 @@ add_task(async function test_submit_dupl
       await ContentTask.spawn(browser, null, async function() {
         let form = content.document.getElementById("form");
         let name = form.querySelector("#cc-name");
         name.focus();
 
         name.setUserInput("John Doe");
         form.querySelector("#cc-number").setUserInput("1234567812345678");
         form.querySelector("#cc-exp-month").setUserInput("4");
-        form.querySelector("#cc-exp-year").setUserInput("2017");
+        form.querySelector("#cc-exp-year").setUserInput(new Date().getFullYear());
 
         // Wait 1000ms before submission to make sure the input value applied
         await new Promise(resolve => setTimeout(resolve, 1000));
         form.querySelector("input[type=submit]").click();
       });
 
       await sleep(1000);
       is(PopupNotifications.panel.state, "closed", "Doorhanger is hidden");
@@ -207,31 +207,31 @@ add_task(async function test_submit_unno
         let form = content.document.getElementById("form");
         let name = form.querySelector("#cc-name");
         name.focus();
 
         name.setUserInput("John Doe");
         form.querySelector("#cc-number").setUserInput("1234567812345678");
         form.querySelector("#cc-exp-month").setUserInput("4");
         // Set unnormalized year
-        form.querySelector("#cc-exp-year").setUserInput("17");
+        form.querySelector("#cc-exp-year").setUserInput(new Date().getFullYear().toString().substr(2, 2));
 
         // Wait 1000ms before submission to make sure the input value applied
         await new Promise(resolve => setTimeout(resolve, 1000));
         form.querySelector("input[type=submit]").click();
       });
 
       await sleep(1000);
       is(PopupNotifications.panel.state, "closed", "Doorhanger is hidden");
     }
   );
 
   creditCards = await getCreditCards();
   is(creditCards.length, 1, "Still 1 credit card in storage");
-  is(creditCards[0]["cc-exp-year"], "2017", "Verify the expiry year field");
+  is(creditCards[0]["cc-exp-year"], new Date().getFullYear(), "Verify the expiry year field");
   await removeAllRecords();
 });
 
 add_task(async function test_submit_creditCard_never_save() {
   await SpecialPowers.pushPrefEnv({
     "set": [
       [CREDITCARDS_USED_STATUS_PREF, 0],
     ],
--- a/browser/extensions/formautofill/test/browser/browser_editCreditCardDialog.js
+++ b/browser/extensions/formautofill/test/browser/browser_editCreditCardDialog.js
@@ -57,16 +57,51 @@ add_task(async function test_saveCreditC
     if (fieldName === "cc-number") {
       fieldValue = "*".repeat(fieldValue.length - 4) + fieldValue.substr(-4);
     }
     is(creditCards[0][fieldName], fieldValue, "check " + fieldName);
   }
   ok(creditCards[0]["cc-number-encrypted"], "cc-number-encrypted exists");
 });
 
+add_task(async function test_saveCreditCardWithMaxYear() {
+  await new Promise(resolve => {
+    let win = window.openDialog(EDIT_CREDIT_CARD_DIALOG_URL);
+    win.addEventListener("load", () => {
+      win.addEventListener("unload", () => {
+        ok(true, "Edit credit card dialog is closed");
+        resolve();
+      }, {once: true});
+      EventUtils.synthesizeKey("VK_TAB", {}, win);
+      EventUtils.synthesizeKey(TEST_CREDIT_CARD_2["cc-number"], {}, win);
+      EventUtils.synthesizeKey("VK_TAB", {}, win);
+      EventUtils.synthesizeKey(TEST_CREDIT_CARD_2["cc-name"], {}, win);
+      EventUtils.synthesizeKey("VK_TAB", {}, win);
+      EventUtils.synthesizeKey(TEST_CREDIT_CARD_2["cc-exp-month"].toString(), {}, win);
+      EventUtils.synthesizeKey("VK_TAB", {}, win);
+      EventUtils.synthesizeKey(TEST_CREDIT_CARD_2["cc-exp-year"].toString(), {}, win);
+      EventUtils.synthesizeKey("VK_TAB", {}, win);
+      EventUtils.synthesizeKey("VK_TAB", {}, win);
+      info("saving credit card");
+      EventUtils.synthesizeKey("VK_RETURN", {}, win);
+    }, {once: true});
+  });
+  let creditCards = await getCreditCards();
+
+  is(creditCards.length, 2, "Two credit card is in storage");
+  for (let [fieldName, fieldValue] of Object.entries(TEST_CREDIT_CARD_2)) {
+    if (fieldName === "cc-number") {
+      fieldValue = "*".repeat(fieldValue.length - 4) + fieldValue.substr(-4);
+    }
+    is(creditCards[1][fieldName], fieldValue, "check " + fieldName);
+  }
+  ok(creditCards[1]["cc-number-encrypted"], "cc-number-encrypted exists");
+  await removeCreditCards([creditCards[1].guid]);
+});
+
 add_task(async function test_editCreditCard() {
   let creditCards = await getCreditCards();
   is(creditCards.length, 1, "only one credit card is in storage");
   await new Promise(resolve => {
     let win = window.openDialog(EDIT_CREDIT_CARD_DIALOG_URL, null, null, creditCards[0]);
     win.addEventListener("FormReady", () => {
       win.addEventListener("unload", () => {
         ok(true, "Edit credit card dialog is closed");
@@ -87,17 +122,17 @@ add_task(async function test_editCreditC
 
   creditCards = await getCreditCards();
   is(creditCards.length, 0, "Credit card storage is empty");
 });
 
 add_task(async function test_addInvalidCreditCard() {
   await new Promise(resolve => {
     let win = window.openDialog(EDIT_CREDIT_CARD_DIALOG_URL);
-    win.addEventListener("FormReady", () => {
+    win.addEventListener("load", () => {
       const unloadHandler = () => ok(false, "Edit credit card dialog shouldn't be closed");
       win.addEventListener("unload", unloadHandler);
 
       EventUtils.synthesizeKey("VK_TAB", {}, win);
       EventUtils.synthesizeKey("test", {}, win);
       win.document.querySelector("#save").click();
 
       is(win.document.querySelector("form").checkValidity(), false, "cc-number is invalid");
--- a/browser/extensions/formautofill/test/browser/head.js
+++ b/browser/extensions/formautofill/test/browser/head.js
@@ -95,24 +95,24 @@ const TEST_ADDRESS_DE_1 = {
   tel: "+4930983333000",
   email: "timbl@w3.org",
 };
 
 const TEST_CREDIT_CARD_1 = {
   "cc-name": "John Doe",
   "cc-number": "1234567812345678",
   "cc-exp-month": 4,
-  "cc-exp-year": 2017,
+  "cc-exp-year": new Date().getFullYear(),
 };
 
 const TEST_CREDIT_CARD_2 = {
   "cc-name": "Timothy Berners-Lee",
   "cc-number": "1111222233334444",
   "cc-exp-month": 12,
-  "cc-exp-year": 2022,
+  "cc-exp-year": new Date().getFullYear() + 10,
 };
 
 const TEST_CREDIT_CARD_3 = {
   "cc-number": "9999888877776666",
   "cc-exp-month": 1,
   "cc-exp-year": 2000,
 };
 
--- a/browser/extensions/formautofill/test/unit/head.js
+++ b/browser/extensions/formautofill/test/unit/head.js
@@ -63,18 +63,22 @@ async function initProfileStorage(fileNa
   let path = getTempFile(fileName).path;
   let profileStorage = new ProfileStorage(path);
   await profileStorage.initialize();
 
   if (!records || !Array.isArray(records)) {
     return profileStorage;
   }
 
-  let onChanged = TestUtils.topicObserved("formautofill-storage-changed",
-                                          (subject, data) => data == "add");
+  let onChanged = TestUtils.topicObserved(
+    "formautofill-storage-changed",
+    (subject, data) =>
+      data == "add" &&
+      subject.wrappedJSObject.collectionName == collectionName
+  );
   for (let record of records) {
     Assert.ok(profileStorage[collectionName].add(record));
     await onChanged;
   }
   await profileStorage._saveImmediately();
   return profileStorage;
 }
 
--- a/browser/extensions/formautofill/test/unit/test_addressRecords.js
+++ b/browser/extensions/formautofill/test/unit/test_addressRecords.js
@@ -1,15 +1,16 @@
 /**
  * Tests ProfileStorage object with addresses records.
  */
 
 "use strict";
 
 const TEST_STORE_FILE_NAME = "test-profile.json";
+const COLLECTION_NAME = "addresses";
 
 const TEST_ADDRESS_1 = {
   "given-name": "Timothy",
   "additional-name": "John",
   "family-name": "Berners-Lee",
   organization: "World Wide Web Consortium",
   "street-address": "32 Vassar Street\nMIT Room 32-G524",
   "address-level2": "Cambridge",
@@ -373,17 +374,19 @@ add_task(async function test_update() {
 
   let addresses = profileStorage.addresses.getAll();
   let guid = addresses[1].guid;
   let timeLastModified = addresses[1].timeLastModified;
 
   let onChanged = TestUtils.topicObserved(
     "formautofill-storage-changed",
     (subject, data) =>
-      data == "update" && subject.QueryInterface(Ci.nsISupportsString).data == guid
+      data == "update" &&
+      subject.wrappedJSObject.guid == guid &&
+      subject.wrappedJSObject.collectionName == COLLECTION_NAME
   );
 
   Assert.notEqual(addresses[1].country, undefined);
 
   profileStorage.addresses.update(guid, TEST_ADDRESS_3);
   await onChanged;
   await profileStorage._saveImmediately();
 
@@ -486,18 +489,22 @@ add_task(async function test_notifyUsed(
 
 add_task(async function test_remove() {
   let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME,
                                                 [TEST_ADDRESS_1, TEST_ADDRESS_2]);
 
   let addresses = profileStorage.addresses.getAll();
   let guid = addresses[1].guid;
 
-  let onChanged = TestUtils.topicObserved("formautofill-storage-changed",
-                                          (subject, data) => data == "remove");
+  let onChanged = TestUtils.topicObserved(
+    "formautofill-storage-changed",
+    (subject, data) =>
+      data == "remove" &&
+      subject.wrappedJSObject.collectionName == COLLECTION_NAME
+  );
 
   Assert.equal(addresses.length, 2);
 
   profileStorage.addresses.remove(guid);
   await onChanged;
 
   addresses = profileStorage.addresses.getAll();
 
@@ -514,17 +521,19 @@ MERGE_TESTCASES.forEach((testcase) => {
     let addresses = profileStorage.addresses.getAll();
     let guid = addresses[0].guid;
     let timeLastModified = addresses[0].timeLastModified;
 
     // Merge address and verify the guid in notifyObservers subject
     let onMerged = TestUtils.topicObserved(
       "formautofill-storage-changed",
       (subject, data) =>
-        data == "update" && subject.QueryInterface(Ci.nsISupportsString).data == guid
+        data == "update" &&
+        subject.wrappedJSObject.guid == guid &&
+        subject.wrappedJSObject.collectionName == COLLECTION_NAME
     );
 
     // Force to create sync metadata.
     profileStorage.addresses.pullSyncChanges();
     Assert.equal(getSyncChangeCounter(profileStorage.addresses, guid), 1);
 
     Assert.ok(profileStorage.addresses.mergeIfPossible(guid,
                                                        testcase.addressToMerge,
--- a/browser/extensions/formautofill/test/unit/test_creditCardRecords.js
+++ b/browser/extensions/formautofill/test/unit/test_creditCardRecords.js
@@ -2,16 +2,17 @@
  * Tests ProfileStorage object with creditCards records.
  */
 
 "use strict";
 
 const {ProfileStorage} = Cu.import("resource://formautofill/ProfileStorage.jsm", {});
 
 const TEST_STORE_FILE_NAME = "test-credit-card.json";
+const COLLECTION_NAME = "creditCards";
 
 const TEST_CREDIT_CARD_1 = {
   "cc-name": "John Doe",
   "cc-number": "1234567812345678",
   "cc-exp-month": 4,
   "cc-exp-year": 2017,
 };
 
@@ -143,18 +144,22 @@ const MERGE_TESTCASES = [
     },
   },
 ];
 
 let prepareTestCreditCards = async function(path) {
   let profileStorage = new ProfileStorage(path);
   await profileStorage.initialize();
 
-  let onChanged = TestUtils.topicObserved("formautofill-storage-changed",
-                                          (subject, data) => data == "add");
+  let onChanged = TestUtils.topicObserved(
+    "formautofill-storage-changed",
+    (subject, data) =>
+      data == "add" &&
+      subject.wrappedJSObject.collectionName == COLLECTION_NAME
+  );
   Assert.ok(profileStorage.creditCards.add(TEST_CREDIT_CARD_1));
   await onChanged;
   Assert.ok(profileStorage.creditCards.add(TEST_CREDIT_CARD_2));
   await onChanged;
   await profileStorage._saveImmediately();
 };
 
 let reCCNumber = /^(\*+)(.{4})$/;
@@ -290,18 +295,22 @@ add_task(async function test_update() {
 
   let profileStorage = new ProfileStorage(path);
   await profileStorage.initialize();
 
   let creditCards = profileStorage.creditCards.getAll();
   let guid = creditCards[1].guid;
   let timeLastModified = creditCards[1].timeLastModified;
 
-  let onChanged = TestUtils.topicObserved("formautofill-storage-changed",
-                                          (subject, data) => data == "update");
+  let onChanged = TestUtils.topicObserved(
+    "formautofill-storage-changed",
+    (subject, data) =>
+      data == "update" &&
+      subject.wrappedJSObject.collectionName == COLLECTION_NAME
+  );
 
   Assert.notEqual(creditCards[1]["cc-name"], undefined);
   profileStorage.creditCards.update(guid, TEST_CREDIT_CARD_3);
   await onChanged;
   await profileStorage._saveImmediately();
 
   profileStorage = new ProfileStorage(path);
   await profileStorage.initialize();
@@ -416,18 +425,22 @@ add_task(async function test_remove() {
   await prepareTestCreditCards(path);
 
   let profileStorage = new ProfileStorage(path);
   await profileStorage.initialize();
 
   let creditCards = profileStorage.creditCards.getAll();
   let guid = creditCards[1].guid;
 
-  let onChanged = TestUtils.topicObserved("formautofill-storage-changed",
-                                          (subject, data) => data == "remove");
+  let onChanged = TestUtils.topicObserved(
+    "formautofill-storage-changed",
+    (subject, data) =>
+      data == "remove" &&
+      subject.wrappedJSObject.collectionName == COLLECTION_NAME
+  );
 
   Assert.equal(creditCards.length, 2);
 
   profileStorage.creditCards.remove(guid);
   await onChanged;
   await profileStorage._saveImmediately();
 
   profileStorage = new ProfileStorage(path);
@@ -448,17 +461,19 @@ MERGE_TESTCASES.forEach((testcase) => {
                                                   "creditCards");
     let creditCards = profileStorage.creditCards.getAll();
     let guid = creditCards[0].guid;
     let timeLastModified = creditCards[0].timeLastModified;
     // Merge creditCard and verify the guid in notifyObservers subject
     let onMerged = TestUtils.topicObserved(
       "formautofill-storage-changed",
       (subject, data) =>
-        data == "update" && subject.QueryInterface(Ci.nsISupportsString).data == guid
+        data == "update" &&
+        subject.wrappedJSObject.guid == guid &&
+        subject.wrappedJSObject.collectionName == COLLECTION_NAME
     );
     // Force to create sync metadata.
     profileStorage.creditCards.pullSyncChanges();
     Assert.equal(getSyncChangeCounter(profileStorage.creditCards, guid), 1);
     Assert.ok(profileStorage.creditCards.mergeIfPossible(guid, testcase.creditCardToMerge));
     if (!testcase.noNeedToUpdate) {
       await onMerged;
     }
--- a/browser/extensions/formautofill/test/unit/test_reconcile.js
+++ b/browser/extensions/formautofill/test/unit/test_reconcile.js
@@ -1006,17 +1006,24 @@ add_task(async function test_reconcile_t
       for (let updatedRecord of test.local) {
         profileStorage[collectionName].update(test.parent.guid, updatedRecord);
       }
 
       let localRecord = profileStorage[collectionName].get(test.parent.guid, {
         rawData: true,
       });
 
+      let onReconciled = TestUtils.topicObserved(
+        "formautofill-storage-changed",
+        (subject, data) =>
+          data == "reconcile" &&
+          subject.wrappedJSObject.collectionName == collectionName
+      );
       let {forkedGUID} = profileStorage[collectionName].reconcile(test.remote);
+      await onReconciled;
       let reconciledRecord = profileStorage[collectionName].get(test.parent.guid, {
         rawData: true,
       });
       if (forkedGUID) {
         let forkedRecord = profileStorage[collectionName].get(forkedGUID, {
           rawData: true,
         });
 
--- a/browser/modules/ContextMenu.jsm
+++ b/browser/modules/ContextMenu.jsm
@@ -687,17 +687,17 @@ class ContextMenu {
           HAVE_CURRENT_DATA: context.target.HAVE_CURRENT_DATA,
         });
       }
     }
 
     context.target = cleanTarget;
 
     if (context.link) {
-      context.link = { href: context.link.href };
+      context.link = { href: context.linkURL };
     }
 
     delete context.linkURI;
   }
 
   _setContext(aEvent) {
     this.context = Object.create(null);
     const context = this.context;
--- a/browser/modules/PermissionUI.jsm
+++ b/browser/modules/PermissionUI.jsm
@@ -456,26 +456,30 @@ GeolocationPermissionPrompt.prototype = 
     return "geolocation";
   },
 
   get anchorID() {
     return "geo-notification-icon";
   },
 
   get message() {
-    let message;
+    let message = {};
     if (this.principal.URI.schemeIs("file")) {
-      message = gBrowserBundle.GetStringFromName("geolocation.shareWithFile3");
+      message.start = gBrowserBundle.GetStringFromName("geolocation.shareWithFile3");
     } else {
-      let hostPort = "<>";
+      let header = gBrowserBundle.formatStringFromName("geolocation.shareWithSite3",
+                                                    ["<>"], 1);
+      header = header.split("<>");
+      message.end = header[1];
+      message.start = header[0];
+
+      message.host = "<>";
       try {
-        hostPort = this.principal.URI.hostPort;
+        message.host = this.principal.URI.hostPort;
       } catch (ex) { }
-      message = gBrowserBundle.formatStringFromName("geolocation.shareWithSite3",
-                                                    [hostPort], 1);
     }
     return message;
   },
 
   get promptActions() {
     // We collect Telemetry data on Geolocation prompts and how users
     // respond to them. The probe keys are a bit verbose, so let's alias them.
     const SHARE_LOCATION =
@@ -554,22 +558,30 @@ DesktopNotificationPermissionPrompt.prot
     return "web-notifications";
   },
 
   get anchorID() {
     return "web-notifications-notification-icon";
   },
 
   get message() {
-    let hostPort = "<>";
+    let message = {};
+
+    message.host = "<>";
     try {
-      hostPort = this.principal.URI.hostPort;
+      message.host = this.principal.URI.hostPort;
     } catch (ex) { }
-    return gBrowserBundle.formatStringFromName("webNotifications.receiveFromSite2",
-                                               [hostPort], 1);
+
+    let header = gBrowserBundle.formatStringFromName("webNotifications.receiveFromSite2",
+                                                    ["<>"], 1);
+    header = header.split("<>");
+    message.end = header[1];
+    message.start = header[0];
+
+    return message;
   },
 
   get promptActions() {
     let actions = [
       {
         label: gBrowserBundle.GetStringFromName("webNotifications.allow"),
         accessKey:
           gBrowserBundle.GetStringFromName("webNotifications.allow.accesskey"),
@@ -625,35 +637,44 @@ PersistentStoragePermissionPrompt.protot
     if (checkbox.show) {
       checkbox.checked = true;
       checkbox.label = gBrowserBundle.GetStringFromName("persistentStorage.remember");
     }
     let learnMoreURL =
       Services.urlFormatter.formatURLPref("app.support.baseURL") + "storage-permissions";
     return {
       checkbox,
-      learnMoreURL
+      learnMoreURL,
+      displayURI: false
     };
   },
 
   get notificationID() {
     return "persistent-storage";
   },
 
   get anchorID() {
     return "persistent-storage-notification-icon";
   },
 
   get message() {
-    let hostPort = "<>";
+    let message = {};
+
+    message.host = "<>";
     try {
-      hostPort = this.principal.URI.hostPort;
+      message.host = this.principal.URI.hostPort;
     } catch (ex) {}
-    return gBrowserBundle.formatStringFromName(
-      "persistentStorage.allowWithSite", [hostPort], 1);
+
+    let header = gBrowserBundle.formatStringFromName("persistentStorage.allowWithSite",
+                                                    ["<>"], 1);
+    header = header.split("<>");
+    message.end = header[1];
+    message.start = header[0];
+
+    return message;
   },
 
   get promptActions() {
     return [
       {
         label: gBrowserBundle.GetStringFromName("persistentStorage.allow"),
         accessKey:
           gBrowserBundle.GetStringFromName("persistentStorage.allow.accesskey"),
--- a/browser/modules/webrtcUI.jsm
+++ b/browser/modules/webrtcUI.jsm
@@ -370,17 +370,18 @@ function prompt(aBrowser, aRequest) {
 
   let uri;
   try {
     // This fails for principals that serialize to "null", e.g. file URIs.
     uri = Services.io.newURI(aRequest.origin);
   } catch (e) {
     uri = Services.io.newURI(aRequest.documentURI);
   }
-  let host = getHost(uri);
+  let message = {};
+  message.host = getHost(uri);
   let chromeDoc = aBrowser.ownerDocument;
   let stringBundle = chromeDoc.defaultView.gNavigatorBundle;
 
   // Mind the order, because for simplicity we're iterating over the list using
   // "includes()". This allows the rotation of string identifiers. We list the
   // full identifiers here so they can be cross-referenced more easily.
   let joinedRequestTypes = requestTypes.join("And");
   let stringId = [
@@ -391,17 +392,20 @@ function prompt(aBrowser, aRequest) {
     "getUserMedia.shareAudioCapture2.message",
     // Combinations of the above request types last.
     "getUserMedia.shareCameraAndMicrophone2.message",
     "getUserMedia.shareCameraAndAudioCapture2.message",
     "getUserMedia.shareScreenAndMicrophone3.message",
     "getUserMedia.shareScreenAndAudioCapture3.message",
   ].find(id => id.includes(joinedRequestTypes));
 
-  let message = stringBundle.getFormattedString(stringId, [host]);
+  let header = stringBundle.getFormattedString(stringId, ["<>"], 1);
+  header = header.split("<>");
+  message.end = header[1];
+  message.start = header[0];
 
   let notification; // Used by action callbacks.
   let mainAction = {
     label: stringBundle.getString("getUserMedia.allow.label"),
     accessKey: stringBundle.getString("getUserMedia.allow.accesskey"),
     // The real callback will be set during the "showing" event. The
     // empty function here is so that PopupNotifications.show doesn't
     // reject the action.
--- a/browser/themes/shared/sidebar.inc.css
+++ b/browser/themes/shared/sidebar.inc.css
@@ -91,17 +91,17 @@
 #sidebar-switcher-target.active:-moz-lwtheme {
   background: hsla(240, 5%, 5%, 0.15);
 }
 
 #sidebarMenu-popup .subviewbutton {
   min-width: 190px;
 }
 
-#sidebar-extensions:empty + toolbarseparator {
+toolbarseparator + #sidebar-extensions-separator {
   display: none;
 }
 
 #sidebarMenu-popup > .subviewbutton[checked="true"] {
   list-style-image: none;
   background: url(chrome://browser/skin/check.svg) no-repeat transparent;
   background-size: 11px 11px;
 }
--- a/browser/themes/windows/browser-aero.css
+++ b/browser/themes/windows/browser-aero.css
@@ -333,22 +333,23 @@
     background-color: rgba(255,255,255,.5);
     color: black;
     border-radius: 4px;
   }
 
   /* Artificially draw window borders that are covered by lwtheme, see bug 591930.
    * We use a different border for win8, and this is not necessary on win10+ */
   #main-window[sizemode="normal"] > #tab-view-deck > #browser-panel:-moz-lwtheme {
-    border-top: 2px solid;
-    -moz-border-top-colors: @glassActiveBorderColor@ rgba(255,255,255,.6);
+    border-top: 1px solid @glassActiveBorderColor@;
+    padding-top: 1px;
+    box-shadow: 0 1px 0 rgba(255,255,255,.6) inset;
   }
 
   #main-window[sizemode="normal"] > #tab-view-deck > #browser-panel:-moz-lwtheme:-moz-window-inactive {
-    -moz-border-top-colors: @glassInactiveBorderColor@ rgba(255,255,255,.6);
+    border-top-color: @glassInactiveBorderColor@;
   }
 }
 
 /* Aero Basic */
 @media (-moz-windows-compositor: 0) {
   @media (-moz-windows-default-theme) {
     #main-window {
       background-color: rgb(185,209,234);
--- a/browser/themes/windows/compacttheme.css
+++ b/browser/themes/windows/compacttheme.css
@@ -149,16 +149,18 @@
 
 /* Restored windows get an artificial border on windows, because the lwtheme background
  * overlaps the regular window border. That isn't the case for us, so we avoid painting
  * over the native border with our custom borders: */
 #browser-panel {
   /* These are !important to avoid specificity-wars with the selectors that add borders here. */
   background-image: none !important;
   border-top: none !important;
+  box-shadow: none !important;
+  padding-top: 0 !important;
 }
 
 @media (-moz-os-version: windows-win10) {
   .titlebar-button:-moz-lwtheme {
     -moz-context-properties: stroke;
     stroke: currentColor;
   }
   #titlebar-min:-moz-lwtheme {
--- a/browser/tools/mozscreenshots/mozscreenshots/extension/TestRunner.jsm
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/TestRunner.jsm
@@ -274,16 +274,32 @@ this.TestRunner = {
       } else {
         bounds = bounds.union(rect);
       }
     }
 
     return {bounds, rects};
   },
 
+  _do_skip(reason, combo, config, func) {
+    const { todo } = reason;
+    if (todo) {
+      this.mochitestScope.todo(
+        false,
+        `Skipped configuration ` +
+        `[ ${combo.map((e) => e.name).join(", ")} ] for failure in ` +
+        `${config.name}.${func}: ${todo}`);
+    } else {
+      this.mochitestScope.info(
+        `\tSkipped configuration ` +
+        `[ ${combo.map((e) => e.name).join(", ")} ] ` +
+        `for "${reason}" in  ${config.name}.${func}`);
+    }
+  },
+
   async _performCombo(combo) {
     let paddedComboIndex = padLeft(this.currentComboIndex + 1, String(this.combos.length).length);
     this.mochitestScope.info(
       `Combination ${paddedComboIndex}/${this.combos.length}: ${this._comboName(combo).substring(1)}`
     );
 
     // Notice that this does need to be a closure, not a function, as otherwise
     // "this" gets replaced and we lose access to this.mochitestScope.
@@ -293,30 +309,34 @@ this.TestRunner = {
       let applyPromise = Promise.resolve(config.applyConfig());
       let timeoutPromise = new Promise((resolve, reject) => {
         setTimeout(reject, APPLY_CONFIG_TIMEOUT_MS, "Timed out");
       });
 
       this.mochitestScope.info("called " + config.name);
       // Add a default timeout of 500ms to avoid conflicts when configurations
       // try to apply at the same time. e.g WindowSize and TabsInTitlebar
-      return Promise.race([applyPromise, timeoutPromise]).then(() => {
+      return Promise.race([applyPromise, timeoutPromise]).then(result => {
         return new Promise((resolve) => {
-          setTimeout(resolve, 500);
+          setTimeout(() => resolve(result), 500);
         });
       });
     };
 
     try {
       // First go through and actually apply all of the configs
       for (let i = 0; i < combo.length; i++) {
         let config = combo[i];
         if (!this._lastCombo || config !== this._lastCombo[i]) {
           this.mochitestScope.info(`promising ${config.name}`);
-          await changeConfig(config);
+          const reason = await changeConfig(config);
+          if (reason) {
+            this._do_skip(reason, combo, config, "applyConfig");
+            return;
+          }
         }
       }
 
       // Update the lastCombo since it's now been applied regardless of whether it's accepted below.
       this.mochitestScope.info("fulfilled all applyConfig so setting lastCombo.");
       this._lastCombo = combo;
 
       // Then ask configs if the current setup is valid. We can't can do this in
@@ -325,28 +345,32 @@ this.TestRunner = {
       for (let i = 0; i < combo.length; i++) {
         let config = combo[i];
         // A configuration can specify an optional verifyConfig method to indicate
         // if the current config is valid for a screenshot. This gets called even
         // if the this config was used in the lastCombo since another config may
         // have invalidated it.
         if (config.verifyConfig) {
           this.mochitestScope.info(`checking if the combo is valid with ${config.name}`);
-          await config.verifyConfig();
+          const reason = await config.verifyConfig();
+          if (reason) {
+            this._do_skip(reason, combo, config, "applyConfig");
+            return;
+          }
         }
       }
     } catch (ex) {
-      this.mochitestScope.info(`\tskipped configuration [ ${combo.map((e) => e.name).join(", ")} ]`);
-      this.mochitestScope.info(`\treason: ${ex.toString()}`);
-      // Don't set lastCombo here so that we properly know which configurations
-      // need to be applied since the last screenshot
-
-      // Return so we don't take a screenshot.
+      this.mochitestScope.ok(false, `Unexpected exception in [ ${combo.map(({ name }) => name).join(", ")} ]: ${ex.toString()}`);
+      this.mochitestScope.info(`\t${ex}`);
+      if (ex.stack) {
+        this.mochitestScope.info(`\t${ex.stack}`);
+      }
       return;
     }
+    this.mochitestScope.info(`Configured UI for [ ${combo.map(({ name }) => name).join(", ")} ] successfully`);
 
     // Collect selectors from combo configs for cropping region
     let windowType;
     const finalSelectors = [];
     for (const obj of combo) {
       if (!windowType) {
         windowType = obj.windowType;
       } else if (windowType !== obj.windowType) {
--- a/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/AppMenu.jsm
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/AppMenu.jsm
@@ -30,57 +30,57 @@ this.AppMenu = {
         let promise = browserWindow.PanelUI.show();
         browserWindow.PanelUI.showMainView();
         return promise;
       },
     },
 
     appMenuHistorySubview: {
       selectors: ["#appMenu-popup"],
-      applyConfig() {
+      async applyConfig() {
         // History has a footer
         if (isCustomizing()) {
-          return Promise.reject("Can't show subviews while customizing");
+          return "Can't show subviews while customizing";
         }
         let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
-        let promise = browserWindow.PanelUI.show();
-        return promise.then(() => {
-          browserWindow.PanelUI.showMainView();
-          browserWindow.document.getElementById("history-panelmenu").click();
-        });
+        await browserWindow.PanelUI.show();
+        browserWindow.PanelUI.showMainView();
+        browserWindow.document.getElementById("history-panelmenu").click();
+
+        return undefined;
       },
 
       verifyConfig: verifyConfigHelper,
     },
 
     appMenuHelpSubview: {
       selectors: ["#appMenu-popup"],
-      applyConfig() {
+      async applyConfig() {
         if (isCustomizing()) {
-          return Promise.reject("Can't show subviews while customizing");
+          return "Can't show subviews while customizing";
         }
         let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
-        let promise = browserWindow.PanelUI.show();
-        return promise.then(() => {
-          browserWindow.PanelUI.showMainView();
-          browserWindow.document.getElementById("PanelUI-help").click();
-        });
+        await browserWindow.PanelUI.show();
+        browserWindow.PanelUI.showMainView();
+        browserWindow.document.getElementById("PanelUI-help").click();
+
+        return undefined;
       },
 
       verifyConfig: verifyConfigHelper,
     },
 
   },
 };
 
 function verifyConfigHelper() {
   if (isCustomizing()) {
-    return Promise.reject("AppMenu verifyConfigHelper");
+    return "navigator:browser has the customizing attribute";
   }
-  return Promise.resolve("AppMenu verifyConfigHelper");
+  return undefined;
 }
 
 function isCustomizing() {
   let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
   if (browserWindow.document.documentElement.hasAttribute("customizing")) {
     return true;
   }
   return false;
--- a/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Buttons.jsm
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Buttons.jsm
@@ -33,37 +33,37 @@ this.Buttons = {
     },
 
     menuPanelButtons: {
       selectors: ["#widget-overflow"],
       applyConfig: async () => {
         CustomizableUI.addWidgetToArea("screenshot-widget", CustomizableUI.AREA_FIXED_OVERFLOW_PANEL);
       },
 
-      verifyConfig() {
+      async verifyConfig() {
         let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
         if (browserWindow.PanelUI.panel.state == "closed") {
-          return Promise.reject("The button isn't shown when the panel isn't open.");
+          return "The button isn't shown when the panel isn't open.";
         }
-        return Promise.resolve("menuPanelButtons.verifyConfig");
+        return undefined;
       },
     },
 
     custPaletteButtons: {
       selectors: ["#customization-palette"],
       applyConfig: async () => {
         CustomizableUI.removeWidgetFromArea("screenshot-widget");
       },
 
-      verifyConfig() {
+      async verifyConfig() {
         let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
         if (browserWindow.document.documentElement.getAttribute("customizing") != "true") {
-          return Promise.reject("The button isn't shown when we're not in customize mode.");
+          return "The button isn't shown when we're not in customize mode.";
         }
-        return Promise.resolve("custPaletteButtons.verifyConfig");
+        return undefined;
       },
     },
   },
 };
 
 function createWidget() {
   let id = "screenshot-widget";
   let spec = {
--- a/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/ControlCenter.jsm
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/ControlCenter.jsm
@@ -50,17 +50,17 @@ this.ControlCenter = {
         let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
         let gBrowser = browserWindow.gBrowser;
         BrowserTestUtils.loadURI(gBrowser.selectedBrowser, channel.file.path);
         await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
         await openIdentityPopup();
       },
 
       async verifyConfig() {
-        return Promise.reject("Bug 1373563: intermittent controlCenter_localFile on Taskcluster");
+        return { todo: "Bug 1373563: intermittent controlCenter_localFile on Taskcluster" };
       },
     },
 
     http: {
       selectors: ["#identity-popup"],
       async applyConfig() {
         await loadPage(HTTP_PAGE);
         await openIdentityPopup();
--- a/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/PermissionPrompts.jsm
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/PermissionPrompts.jsm
@@ -107,18 +107,20 @@ this.PermissionPrompts = {
         let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
         let notification = browserWindow.document.getElementById("addon-install-confirmation-notification");
 
         await closeLastTab();
         await clickOn("#addons");
 
         // We want to skip the progress-notification, so we wait for
         // the install-confirmation screen to be "not hidden" = shown.
-        await BrowserTestUtils.waitForCondition(() => !notification.hasAttribute("hidden"),
-                                                "addon install confirmation did not show", 200);
+        return BrowserTestUtils.waitForCondition(() => !notification.hasAttribute("hidden"),
+                                                "addon install confirmation did not show", 200).catch((msg) => {
+                                                  return Promise.resolve({todo: msg});
+                                                });
       },
     },
   },
 };
 
 async function closeLastTab() {
   if (!lastTab) {
     return;
--- a/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Preferences.jsm
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Preferences.jsm
@@ -31,30 +31,38 @@ this.Preferences = {
 
     for (let [primary, customFn] of panes) {
       let configName = primary.replace(/^pane/, "prefs");
       if (customFn) {
         configName += "-" + customFn.name;
       }
       this.configurations[configName] = {};
       this.configurations[configName].selectors = ["#browser"];
-      this.configurations[configName].applyConfig = prefHelper.bind(null, primary, customFn);
+      if (primary == "panePrivacy" && customFn) {
+        this.configurations[configName].applyConfig = async () => {
+          return {todo: `${configName} times out on the try server`};
+        };
+      } else {
+        this.configurations[configName].applyConfig = prefHelper.bind(null, primary, customFn);
+      }
     }
   },
 
   configurations: {},
 };
 
 let prefHelper = async function(primary, customFn = null) {
   let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
   let selectedBrowser = browserWindow.gBrowser.selectedBrowser;
 
   // close any dialog that might still be open
   await ContentTask.spawn(selectedBrowser, null, async function() {
-    if (!content.window.gSubDialog) {
+    // Check that gSubDialog is defined on the content window
+    // and that there is an open dialog to close
+    if (!content.window.gSubDialog || !content.window.gSubDialog._topDialog) {
       return;
     }
     content.window.gSubDialog.close();
   });
 
   let readyPromise = null;
   if (selectedBrowser.currentURI.specIgnoringRef == "about:preferences") {
     if (selectedBrowser.currentURI.spec == "about:preferences#" + primary.replace(/^pane/, "")) {
@@ -68,19 +76,21 @@ let prefHelper = async function(primary,
   }
 
   browserWindow.openPreferences(primary, {origin: "mozscreenshots"});
 
   await readyPromise;
 
   if (customFn) {
     let customPaintPromise = paintPromise(browserWindow);
-    await customFn(selectedBrowser);
+    let result = await customFn(selectedBrowser);
     await customPaintPromise;
+    return result;
   }
+  return undefined;
 };
 
 function paintPromise(browserWindow) {
   return new Promise((resolve) => {
     browserWindow.addEventListener("MozAfterPaint", function() {
       resolve();
     }, {once: true});
   });
@@ -94,18 +104,23 @@ async function browsingGroup(aBrowser) {
 
 async function cacheGroup(aBrowser) {
   await ContentTask.spawn(aBrowser, null, async function() {
     content.document.getElementById("cacheGroup").scrollIntoView();
   });
 }
 
 async function DNTDialog(aBrowser) {
-  await ContentTask.spawn(aBrowser, null, async function() {
-    content.document.getElementById("doNotTrackSettings").click();
+  return ContentTask.spawn(aBrowser, null, async function() {
+    const button = content.document.getElementById("doNotTrackSettings");
+    if (!button) {
+      return {todo: "The dialog may have exited before we could click the button"};
+    }
+    button.click();
+    return undefined;
   });
 }
 
 async function connectionDialog(aBrowser) {
   await ContentTask.spawn(aBrowser, null, async function() {
     content.document.getElementById("connectionSettings").click();
   });
 }
--- a/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Tabs.jsm
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Tabs.jsm
@@ -48,17 +48,17 @@ this.Tabs = {
         tab = browserWindow.gBrowser.addTab("about:privatebrowsing");
         browserWindow.gBrowser.pinTab(tab);
         tab = browserWindow.gBrowser.addTab("about:home");
         browserWindow.gBrowser.pinTab(tab);
         browserWindow.gBrowser.selectTabAtIndex(5);
         hoverTab(browserWindow.gBrowser.tabs[2]);
         // also hover the new tab button
         let newTabButton = browserWindow.document.getAnonymousElementByAttribute(browserWindow.
-                           gBrowser.tabContainer, "class", "tabs-newtab-button");
+                           gBrowser.tabContainer, "anonid", "tabs-newtab-button");
         hoverTab(newTabButton);
         browserWindow.gBrowser.tabs[browserWindow.gBrowser.tabs.length - 1].
                       setAttribute("beforehovered", true);
 
         await new Promise((resolve, reject) => {
           setTimeout(resolve, 3000);
         });
         await allTabTitlesDisplayed(browserWindow);
@@ -129,16 +129,17 @@ this.Tabs = {
 
 /* helpers */
 
 async function allTabTitlesDisplayed(browserWindow) {
   let specToTitleMap = {
     "about:home": "New Tab",
     "about:newtab": "New Tab",
     "about:addons": "Add-ons Manager",
+    "about:privatebrowsing": "Open a private window?"
   };
   specToTitleMap[PREFS_TAB] = "browser/skin/settings.svg";
   specToTitleMap[CUST_TAB] = "browser/skin/customize.svg";
   specToTitleMap[DEFAULT_FAVICON_TAB] = "No favicon";
 
   let tabTitlePromises = [];
   for (let tab of browserWindow.gBrowser.tabs) {
     function tabTitleLoaded(spec) {
--- a/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/TabsInTitlebar.jsm
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/TabsInTitlebar.jsm
@@ -16,17 +16,17 @@ this.TabsInTitlebar = {
 
   init(libDir) {},
 
   configurations: {
     tabsInTitlebar: {
       selectors: ["#navigator-toolbox"],
       async applyConfig() {
         if (Services.appinfo.OS == "Linux") {
-          return Promise.reject("TabsInTitlebar isn't supported on Linux");
+          return "TabsInTitlebar isn't supported on Linux";
         }
         Services.prefs.setBoolPref(PREF_TABS_IN_TITLEBAR, true);
         return undefined;
       },
     },
 
     tabsOutsideTitlebar: {
       selectors: ["#navigator-toolbox"].concat(Services.appinfo.OS == "Linux" ? [] : ["#titlebar"]),
--- a/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Toolbars.jsm
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Toolbars.jsm
@@ -31,17 +31,17 @@ this.Toolbars = {
         let personalToolbar = browserWindow.document.getElementById("PersonalToolbar");
         browserWindow.setToolbarVisibility(personalToolbar, true);
         toggleMenubarIfNecessary(true);
       },
 
       async verifyConfig() {
         let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
         if (browserWindow.fullScreen) {
-          return Promise.reject("The bookmark toolbar and menubar are not shown in fullscreen.");
+          return "The bookmark toolbar and menubar are not shown in fullscreen.";
         }
         return undefined;
       },
     },
 
   },
 };
 
--- a/browser/tools/mozscreenshots/primaryUI/browser_primaryUI.js
+++ b/browser/tools/mozscreenshots/primaryUI/browser_primaryUI.js
@@ -6,11 +6,15 @@
 
 "use strict";
 
 add_task(async function capture() {
   if (!shouldCapture()) {
     return;
   }
 
+  if (AppConstants.platform == "macosx") {
+    // Bug 1425394 - Generate output so mozprocess knows we're still alive for the long session.
+    SimpleTest.requestCompleteLog();
+  }
   let sets = ["TabsInTitlebar", "Tabs", "WindowSize", "Toolbars", "LightweightThemes", "UIDensities"];
   await TestRunner.start(sets, "primaryUI");
 });
new file mode 100644
--- /dev/null
+++ b/build/debian-packages/make-wheezy.diff
@@ -0,0 +1,13 @@
+diff -Nru make-dfsg-4.0/debian/changelog make-dfsg-4.0/debian/changelog
+--- make-dfsg-4.0/debian/changelog	2015-01-18 03:30:55.000000000 +0900
++++ make-dfsg-4.0/debian/changelog	2018-01-13 14:06:23.000000000 +0900
+@@ -1,3 +1,9 @@
++make-dfsg (4.0-8.1.deb7moz1) wheezy; urgency=medium
++
++  * Mozilla backport for wheezy.
++
++ -- Mike Hommey <glandium@debian.org>  Sat, 13 Jan 2018 14:06:23 +0900
++
+ make-dfsg (4.0-8.1) unstable; urgency=medium
+ 
+   * Non-maintainer upload.
--- a/build/macosx/cross-mozconfig.common
+++ b/build/macosx/cross-mozconfig.common
@@ -26,17 +26,17 @@ FLAGS="-target x86_64-apple-darwin11 -B 
 
 export CC="$topsrcdir/clang/bin/clang $FLAGS"
 export CXX="$topsrcdir/clang/bin/clang++ $FLAGS"
 export CPP="$topsrcdir/clang/bin/clang $FLAGS -E"
 export LLVMCONFIG=$topsrcdir/clang/bin/llvm-config
 export LDFLAGS="-Wl,-syslibroot,$CROSS_SYSROOT -Wl,-dead_strip"
 export BINDGEN_CFLAGS="$FLAGS"
 export TOOLCHAIN_PREFIX=$CROSS_CCTOOLS_PATH/bin/x86_64-apple-darwin11-
-export DSYMUTIL=$topsrcdir/clang/bin/llvm-dsymutil
+export DSYMUTIL=$topsrcdir/llvm-dsymutil/bin/llvm-dsymutil
 export MKFSHFS=$topsrcdir/hfsplus-tools/newfs_hfs
 export DMG_TOOL=$topsrcdir/dmg/dmg
 export HFS_TOOL=$topsrcdir/dmg/hfsplus
 
 export HOST_CC="$topsrcdir/clang/bin/clang"
 export HOST_CXX="$topsrcdir/clang/bin/clang++"
 export HOST_CPP="$topsrcdir/clang/bin/clang -E"
 export HOST_CFLAGS="-g"
--- a/devtools/client/debugger/new/README.mozilla
+++ b/devtools/client/debugger/new/README.mozilla
@@ -1,13 +1,13 @@
 This is the debugger.html project output.
 See https://github.com/devtools-html/debugger.html
 
-Version 8.0
-commit https://github.com/devtools-html/debugger.html/commit/9be8e9d9e7a70730bc02e50ae019028f1f06b14e
-comparison https://github.com/devtools-html/debugger.html/compare/release-7...release-8
+Version 9.0
+commit: https://github.com/devtools-html/debugger.html/commit/0de8d3f673ee0f0030d666f1827380e17bef8036
+comparison: https://github.com/devtools-html/debugger.html/compare/release-8...release-9
 
 Packages:
 - babel-plugin-transform-es2015-modules-commonjs @6.26.0
 - babel-preset-react @6.24.1
 - react @15.6.2
 - react-dom @15.6.2
 - webpack @3.10.0
--- a/devtools/client/debugger/new/debugger.css
+++ b/devtools/client/debugger/new/debugger.css
@@ -1563,44 +1563,48 @@ html[dir="rtl"] .managed-tree .tree .nod
   padding: 0.5em;
   user-select: none;
   font-size: 12px;
 }
 
 .outline-list {
   list-style-type: none;
   width: 100%;
-  padding: 10px;
+  padding: 10px 0px;
   margin: 0;
 }
 
 .outline-list__class-list {
   list-style: none;
   margin: 0;
   padding: 0;
 }
 
 .outline-list h2 {
   font-weight: normal;
   font-size: 1em;
-  margin: 10px 0;
+  margin: 10px 0 10px 10px;
   color: var(--theme-body-color);
 }
 
 .outline-list__element {
   padding-bottom: 0.5rem;
   padding-right: 0.5rem;
   padding-top: 0.2rem;
   cursor: default;
   white-space: nowrap;
 }
 
 .outline-list__element:hover {
   background: var(--theme-toolbar-background-hover);
 }
+
+.outline-list__element .function {
+  padding-left: 10px;
+}
 /* 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/>. */
 
 .function-signature {
   align-self: center;
 }
 
@@ -2844,26 +2848,50 @@ html .breakpoints-list .breakpoint.pause
 
 .breakpoint:hover .close {
   visibility: visible;
 }
 /* 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/>. */
 
+.expression-input-form {
+  width: 100%;
+}
+
 .input-expression {
   width: 100%;
-  margin: 0px;
+  margin: 0;
   border: 1px;
   background-color: var(--theme-sidebar-background);
   font-size: 12px;
-  padding: 0px 20px;
+  padding: 0.5em 2.16em;
   color: var(--theme-body-color);
 }
 
+@keyframes shake {
+  0%,
+  100% {
+    transform: translateX(0);
+  }
+  20%,
+  60% {
+    transform: translateX(-10px);
+  }
+  40%,
+  80% {
+    transform: translateX(10px);
+  }
+}
+
+.input-expression.error {
+  border: 1px solid red;
+  animation: 150ms cubic-bezier(0.07, 0.95, 0, 1) shake;
+}
+
 .input-expression::placeholder {
   text-align: center;
   font-style: italic;
   color: var(--theme-comment-alt);
   opacity: 1;
 }
 
 .input-expression:focus {
@@ -2872,17 +2900,16 @@ html .breakpoints-list .breakpoint.pause
 }
 
 .expressions-list {
   /* TODO: add normalize */
   margin: 0;
   padding: 0;
 }
 .expression-input-container {
-  padding: 0.5em;
   display: flex;
 }
 
 .expression-container {
   border: 1px;
   padding: 0.25em 1em 0.25em 0.5em;
   width: 100%;
   color: var(--theme-body-color);
@@ -3362,25 +3389,28 @@ img.resume {
 html[dir="rtl"] .dropdown {
   right: calc((var(--width) - 11px) * (-1));
 }
 
 .dropdown-block {
   padding: 0px 2px;
   position: relative;
   align-self: center;
+  height: 100%;
 }
 
 .dropdown-button {
   color: var(--theme-content-color3);
   background: none;
   border: none;
   padding: 0;
   font-weight: 100;
   font-size: 14px;
+  height: 100%;
+  width: 24px;
 }
 
 .dropdown li {
   transition: all 0.25s ease;
   padding: 2px 10px 10px 5px;
   overflow: hidden;
   height: 30px;
   text-overflow: ellipsis;
@@ -3391,16 +3421,17 @@ html[dir="rtl"] .dropdown {
   background-color: var(--search-overlays-semitransparent);
 }
 
 .dropdown-icon {
   width: var(--icon-size);
   height: var(--icon-size);
   margin-right: 5px;
   vertical-align: middle;
+  display: inline-block;
 }
 
 .dropdown-icon.prettyPrint {
   mask: url("chrome://devtools/skin/images/debugger/prettyPrint.svg") no-repeat;
   mask-size: 100%;
   background: var(--theme-highlight-blue);
 }
 
--- a/devtools/client/debugger/new/debugger.js
+++ b/devtools/client/debugger/new/debugger.js
@@ -10240,19 +10240,19 @@ if (isDevelopment()) {
   pref("devtools.debugger.features.wasm", true);
   pref("devtools.debugger.features.shortcuts", true);
   pref("devtools.debugger.features.root", true);
   pref("devtools.debugger.features.column-breakpoints", false);
   pref("devtools.debugger.features.chrome-scopes", false);
   pref("devtools.debugger.features.map-scopes", true);
   pref("devtools.debugger.features.breakpoints-dropdown", true);
   pref("devtools.debugger.features.remove-command-bar-options", true);
-  pref("devtools.debugger.features.code-coverage", true);
-  pref("devtools.debugger.features.event-listeners", true);
-  pref("devtools.debugger.features.code-folding", true);
+  pref("devtools.debugger.features.code-coverage", false);
+  pref("devtools.debugger.features.event-listeners", false);
+  pref("devtools.debugger.features.code-folding", false);
   pref("devtools.debugger.features.outline", true);
   pref("devtools.debugger.features.column-breakpoints", true);
 }
 
 const prefs = new PrefsHelper("devtools", {
   autoPrettyPrint: ["Bool", "debugger.auto-pretty-print"],
   clientSourceMapsEnabled: ["Bool", "source-map.client-service.enabled"],
   pauseOnExceptions: ["Bool", "debugger.pause-on-exceptions"],
@@ -10286,17 +10286,18 @@ const features = new PrefsHelper("devtoo
   columnBreakpoints: ["Bool", "column-breakpoints"],
   chromeScopes: ["Bool", "chrome-scopes"],
   mapScopes: ["Bool", "map-scopes"],
   breakpointsDropdown: ["Bool", "breakpoints-dropdown"],
   removeCommandBarOptions: ["Bool", "remove-command-bar-options"],
   workers: ["Bool", "workers"],
   codeCoverage: ["Bool", "code-coverage"],
   eventListeners: ["Bool", "event-listeners"],
-  outline: ["Bool", "outline"]
+  outline: ["Bool", "outline"],
+  codeFolding: ["Bool", "code-folding"]
 });
 /* harmony export (immutable) */ __webpack_exports__["features"] = features;
 
 
 if (prefs.debuggerPrefsSchemaVersion !== prefsSchemaVersion) {
   // clear pending Breakpoints
   prefs.pendingBreakpoints = {};
   prefs.debuggerPrefsSchemaVersion = prefsSchemaVersion;
@@ -14131,17 +14132,17 @@ module.exports = "<!-- This Source Code 
 /* 955 */,
 /* 956 */,
 /* 957 */,
 /* 958 */,
 /* 959 */,
 /* 960 */
 /***/ (function(module, exports) {
 
-module.exports = "# This Source Code Form is subject to the terms of the Mozilla Public\n# License, v. 2.0. If a copy of the MPL was not distributed with this\n# file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n# LOCALIZATION NOTE These strings are used inside the Debugger\n# which is available from the Web Developer sub-menu -> 'Debugger'.\n# The correct localization of this file might be to keep it in\n# English, or another language commonly spoken among web developers.\n# You want to make that choice consistent across the developer tools.\n# A good criteria is the language in which you'd find the best\n# documentation on web development on the web.\n\n# LOCALIZATION NOTE (collapsePanes): This is the tooltip for the button\n# that collapses the left and right panes in the debugger UI.\ncollapsePanes=Collapse panes\n\n# LOCALIZATION NOTE (copySource): This is the text that appears in the\n# context menu to copy the selected source of file open.\ncopySource=Copy\ncopySource.accesskey=y\n\n# LOCALIZATION NOTE (copySourceUri2): This is the text that appears in the\n# context menu to copy the source URI of file open.\ncopySourceUri2=Copy source URI\ncopySourceUri2.accesskey=u\n\n# LOCALIZATION NOTE (setDirectoryRoot): This is the text that appears in the\n# context menu to set a directory as root directory\nsetDirectoryRoot.label=Set directory root\nsetDirectoryRoot.accesskey=r\n\n# LOCALIZATION NOTE (copyFunction): This is the text that appears in the\n# context menu to copy the function the user selected\ncopyFunction.label=Copy function\ncopyFunction.accesskey=F\n\n# LOCALIZATION NOTE (copyStackTrace): This is the text that appears in the\n# context menu to copy the stack trace methods, file names and row number.\ncopyStackTrace=Copy stack trace\ncopyStackTrace.accesskey=c\n\n# LOCALIZATION NOTE (expandPanes): This is the tooltip for the button\n# that expands the left and right panes in the debugger UI.\nexpandPanes=Expand panes\n\n# LOCALIZATION NOTE (pauseButtonTooltip): The tooltip that is displayed for the pause\n# button when the debugger is in a running state.\npauseButtonTooltip=Pause %S\n\n# LOCALIZATION NOTE (pausePendingButtonTooltip): The tooltip that is displayed for\n# the pause button after it's been clicked but before the next JavaScript to run.\npausePendingButtonTooltip=Waiting for next execution\n\n# LOCALIZATION NOTE (resumeButtonTooltip): The label that is displayed on the pause\n# button when the debugger is in a paused state.\nresumeButtonTooltip=Resume %S\n\n# LOCALIZATION NOTE (stepOverTooltip): The label that is displayed on the\n# button that steps over a function call.\nstepOverTooltip=Step over %S\n\n# LOCALIZATION NOTE (stepInTooltip): The label that is displayed on the\n# button that steps into a function call.\nstepInTooltip=Step in %S\n\n# LOCALIZATION NOTE (stepOutTooltip): The label that is displayed on the\n# button that steps out of a function call.\nstepOutTooltip=Step out %S\n\n# LOCALIZATION NOTE (pauseButtonItem): The label that is displayed for the dropdown pause\n# list item when the debugger is in a running state.\npauseButtonItem=Pause on Next Statement\n\n# LOCALIZATION NOTE (ignoreExceptionsItem): The pause on exceptions button description\n# when the debugger will not pause on exceptions.\nignoreExceptionsItem=Ignore exceptions\n\n# LOCALIZATION NOTE (pauseOnUncaughtExceptionsItem): The pause on exceptions dropdown\n# item shown when a user is adding a new breakpoint.\npauseOnUncaughtExceptionsItem=Pause on uncaught exceptions\n\n# LOCALIZATION NOTE (pauseOnExceptionsItem): The pause on exceptions button description\n# when the debugger will pause on all exceptions.\npauseOnExceptionsItem=Pause on all exceptions\n\n# LOCALIZATION NOTE (workersHeader): The text to display in the events\n# header.\nworkersHeader=Workers\n\n# LOCALIZATION NOTE (noWorkersText): The text to display in the workers list\n# when there are no workers.\nnoWorkersText=This page has no workers.\n\n# LOCALIZATION NOTE (noSourcesText): The text to display in the sources list\n# when there are no sources.\nnoSourcesText=This page has no sources.\n\n# LOCALIZATION NOTE (noEventListenersText): The text to display in the events tab\n# when there are no events.\nnoEventListenersText=No event listeners to display.\n\n# LOCALIZATION NOTE (eventListenersHeader): The text to display in the events\n# header.\neventListenersHeader=Event listeners\n\n# LOCALIZATION NOTE (noStackFramesText): The text to display in the call stack tab\n# when there are no stack frames.\nnoStackFramesText=No stack frames to display\n\n# LOCALIZATION NOTE (eventCheckboxTooltip): The tooltip text to display when\n# the user hovers over the checkbox used to toggle an event breakpoint.\neventCheckboxTooltip=Toggle breaking on this event\n\n# LOCALIZATION NOTE (eventOnSelector): The text to display in the events tab\n# for every event item, between the event type and event selector.\neventOnSelector=on\n\n# LOCALIZATION NOTE (eventInSource): The text to display in the events tab\n# for every event item, between the event selector and listener's owner source.\neventInSource=in\n\n# LOCALIZATION NOTE (eventNodes): The text to display in the events tab when\n# an event is listened on more than one target node.\neventNodes=%S nodes\n\n# LOCALIZATION NOTE (eventNative): The text to display in the events tab when\n# a listener is added from plugins, thus getting translated to native code.\neventNative=[native code]\n\n# LOCALIZATION NOTE (*Events): The text to display in the events tab for\n# each group of sub-level event entries.\nanimationEvents=Animation\naudioEvents=Audio\nbatteryEvents=Battery\nclipboardEvents=Clipboard\ncompositionEvents=Composition\ndeviceEvents=Device\ndisplayEvents=Display\ndragAndDropEvents=Drag and Drop\ngamepadEvents=Gamepad\nindexedDBEvents=IndexedDB\ninteractionEvents=Interaction\nkeyboardEvents=Keyboard\nmediaEvents=HTML5 Media\nmouseEvents=Mouse\nmutationEvents=Mutation\nnavigationEvents=Navigation\npointerLockEvents=Pointer Lock\nsensorEvents=Sensor\nstorageEvents=Storage\ntimeEvents=Time\ntouchEvents=Touch\notherEvents=Other\n\n# LOCALIZATION NOTE (blackboxCheckboxTooltip2): The tooltip text to display when\n# the user hovers over the checkbox used to toggle blackboxing its associated\n# source.\nblackboxCheckboxTooltip2=Toggle blackboxing\n\n# LOCALIZATION NOTE (sources.search.key2): Key shortcut to open the search for\n# searching all the source files the debugger has seen.\nsources.search.key2=CmdOrCtrl+P\n\n# LOCALIZATION NOTE (sources.search.alt.key): A second key shortcut to open the\n# search for searching all the source files the debugger has seen.\nsources.search.alt.key=CmdOrCtrl+O\n\n# LOCALIZATION NOTE (projectTextSearch.key): A key shortcut to open the\n# full project text search for searching all the files the debugger has seen.\nprojectTextSearch.key=CmdOrCtrl+Shift+F\n\n# LOCALIZATION NOTE (functionSearch.key): A key shortcut to open the\n# modal for searching functions in a file.\nfunctionSearch.key=CmdOrCtrl+Shift+O\n\n# LOCALIZATION NOTE (toggleBreakpoint.key): A key shortcut to toggle\n# breakpoints.\ntoggleBreakpoint.key=CmdOrCtrl+B\n\n# LOCALIZATION NOTE (toggleCondPanel.key): A key shortcut to toggle\n# the conditional breakpoint panel.\ntoggleCondPanel.key=CmdOrCtrl+Shift+B\n\n# LOCALIZATION NOTE (stepOut.key): A key shortcut to\n# step out.\nstepOut.key=Shift+F11\n\n# LOCALIZATION NOTE (shortcuts.header.editor): Sections header in\n# the shortcuts modal for keyboard shortcuts related to editing.\nshortcuts.header.editor=Editor\n\n# LOCALIZATION NOTE (shortcuts.header.stepping): Sections header in\n# the shortcuts modal for keyboard shortcuts related to stepping.\nshortcuts.header.stepping=Stepping\n\n# LOCALIZATION NOTE (shortcuts.header.search): Sections header in\n# the shortcuts modal for keyboard shortcuts related to search.\nshortcuts.header.search=Search\n\n# LOCALIZATION NOTE (projectTextSearch.placeholder): A placeholder shown\n# when searching across all of the files in a project.\nprojectTextSearch.placeholder=Find in files…\n\n# LOCALIZATION NOTE (projectTextSearch.noResults): The center pane Text Search\n# message when the query did not match any text of all files in a project.\nprojectTextSearch.noResults=No results found\n\n# LOCALIZATION NOTE (sources.noSourcesAvailable): Text shown when the debugger\n# does not have any sources.\nsources.noSourcesAvailable=This page has no sources\n\n# LOCALIZATION NOTE (sourceSearch.search.key2): Key shortcut to open the search\n# for searching within a the currently opened files in the editor\nsourceSearch.search.key2=CmdOrCtrl+F\n\n# LOCALIZATION NOTE (sourceSearch.search.placeholder): placeholder text in\n# the source search input bar\nsourceSearch.search.placeholder=Search in file…\n\n# LOCALIZATION NOTE (sourceSearch.search.again.key2): Key shortcut to highlight\n# the next occurrence of the last search triggered from a source search\nsourceSearch.search.again.key2=CmdOrCtrl+G\n\n# LOCALIZATION NOTE (sourceSearch.search.againPrev.key2): Key shortcut to highlight\n# the previous occurrence of the last search triggered from a source search\nsourceSearch.search.againPrev.key2=CmdOrCtrl+Shift+G\n\n# LOCALIZATION NOTE (sourceSearch.resultsSummary1): Shows a summary of\n# the number of matches for autocomplete\nsourceSearch.resultsSummary1=%d results\n\n# LOCALIZATION NOTE (noMatchingStringsText): The text to display in the\n# global search results when there are no matching strings after filtering.\nnoMatchingStringsText=No matches found\n\n# LOCALIZATION NOTE (emptySearchText): This is the text that appears in the\n# filter text box when it is empty and the scripts container is selected.\nemptySearchText=Search scripts (%S)\n\n# LOCALIZATION NOTE (emptyVariablesFilterText): This is the text that\n# appears in the filter text box for the variables view container.\nemptyVariablesFilterText=Filter variables\n\n# LOCALIZATION NOTE (emptyPropertiesFilterText): This is the text that\n# appears in the filter text box for the editor's variables view bubble.\nemptyPropertiesFilterText=Filter properties\n\n# LOCALIZATION NOTE (searchPanelFilter): This is the text that appears in the\n# filter panel popup for the filter scripts operation.\nsearchPanelFilter=Filter scripts (%S)\n\n# LOCALIZATION NOTE (searchPanelGlobal): This is the text that appears in the\n# filter panel popup for the global search operation.\nsearchPanelGlobal=Search in all files (%S)\n\n# LOCALIZATION NOTE (searchPanelFunction): This is the text that appears in the\n# filter panel popup for the function search operation.\nsearchPanelFunction=Search for function definition (%S)\n\n# LOCALIZATION NOTE (searchPanelToken): This is the text that appears in the\n# filter panel popup for the token search operation.\nsearchPanelToken=Find in this file (%S)\n\n# LOCALIZATION NOTE (searchPanelGoToLine): This is the text that appears in the\n# filter panel popup for the line search operation.\nsearchPanelGoToLine=Go to line (%S)\n\n# LOCALIZATION NOTE (searchPanelVariable): This is the text that appears in the\n# filter panel popup for the variables search operation.\nsearchPanelVariable=Filter variables (%S)\n\n# LOCALIZATION NOTE (breakpointMenuItem): The text for all the elements that\n# are displayed in the breakpoints menu item popup.\nbreakpointMenuItem.setConditional=Configure conditional breakpoint\nbreakpointMenuItem.enableSelf2.label=Enable\nbreakpointMenuItem.enableSelf2.accesskey=E\nbreakpointMenuItem.disableSelf2.label=Disable\nbreakpointMenuItem.disableSelf2.accesskey=D\nbreakpointMenuItem.deleteSelf2.label=Remove\nbreakpointMenuItem.deleteSelf2.accesskey=R\nbreakpointMenuItem.enableOthers2.label=Enable others\nbreakpointMenuItem.enableOthers2.accesskey=o\nbreakpointMenuItem.disableOthers2.label=Disable others\nbreakpointMenuItem.disableOthers2.accesskey=s\nbreakpointMenuItem.deleteOthers2.label=Remove others\nbreakpointMenuItem.deleteOthers2.accesskey=h\nbreakpointMenuItem.enableAll2.label=Enable all\nbreakpointMenuItem.enableAll2.accesskey=b\nbreakpointMenuItem.disableAll2.label=Disable all\nbreakpointMenuItem.disableAll2.accesskey=k\nbreakpointMenuItem.deleteAll2.label=Remove all\nbreakpointMenuItem.deleteAll2.accesskey=a\nbreakpointMenuItem.removeCondition2.label=Remove condition\nbreakpointMenuItem.removeCondition2.accesskey=c\nbreakpointMenuItem.addCondition2.label=Add condition\nbreakpointMenuItem.addCondition2.accesskey=A\nbreakpointMenuItem.editCondition2.label=Edit condition\nbreakpointMenuItem.editCondition2.accesskey=n\nbreakpointMenuItem.enableSelf=Enable breakpoint\nbreakpointMenuItem.enableSelf.accesskey=E\nbreakpointMenuItem.disableSelf=Disable breakpoint\nbreakpointMenuItem.disableSelf.accesskey=D\nbreakpointMenuItem.deleteSelf=Remove breakpoint\nbreakpointMenuItem.deleteSelf.accesskey=R\nbreakpointMenuItem.enableOthers=Enable others\nbreakpointMenuItem.enableOthers.accesskey=o\nbreakpointMenuItem.disableOthers=Disable others\nbreakpointMenuItem.disableOthers.accesskey=s\nbreakpointMenuItem.deleteOthers=Remove others\nbreakpointMenuItem.deleteOthers.accesskey=h\nbreakpointMenuItem.enableAll=Enable all breakpoints\nbreakpointMenuItem.enableAll.accesskey=b\nbreakpointMenuItem.disableAll=Disable all breakpoints\nbreakpointMenuItem.disableAll.accesskey=k\nbreakpointMenuItem.deleteAll=Remove all breakpoints\nbreakpointMenuItem.deleteAll.accesskey=a\nbreakpointMenuItem.removeCondition.label=Remove breakpoint condition\nbreakpointMenuItem.removeCondition.accesskey=c\nbreakpointMenuItem.editCondition.label=Edit breakpoint condition\nbreakpointMenuItem.editCondition.accesskey=n\n\n# LOCALIZATION NOTE (breakpoints.header): Breakpoints right sidebar pane header.\nbreakpoints.header=Breakpoints\n\n# LOCALIZATION NOTE (breakpoints.none): The text that appears when there are\n# no breakpoints present\nbreakpoints.none=No breakpoints\n\n# LOCALIZATION NOTE (breakpoints.enable): The text that may appear as a tooltip\n# when hovering over the 'disable breakpoints' switch button in right sidebar\nbreakpoints.enable=Enable breakpoints\n\n# LOCALIZATION NOTE (breakpoints.disable): The text that may appear as a tooltip\n# when hovering over the 'disable breakpoints' switch button in right sidebar\nbreakpoints.disable=Disable breakpoints\n\n# LOCALIZATION NOTE (breakpoints.removeBreakpointTooltip): The tooltip that is displayed\n# for remove breakpoint button in right sidebar\nbreakpoints.removeBreakpointTooltip=Remove breakpoint\n\n# LOCALIZATION NOTE (callStack.header): Call Stack right sidebar pane header.\ncallStack.header=Call stack\n\n# LOCALIZATION NOTE (callStack.notPaused): Call Stack right sidebar pane\n# message when not paused.\ncallStack.notPaused=Not paused\n\n# LOCALIZATION NOTE (callStack.collapse): Call Stack right sidebar pane\n# message to hide some of the frames that are shown.\ncallStack.collapse=Collapse rows\n\n# LOCALIZATION NOTE (callStack.expand): Call Stack right sidebar pane\n# message to show more of the frames.\ncallStack.expand=Expand rows\n\n# LOCALIZATION NOTE (editor.searchResults): Editor Search bar message\n# for the summarizing the selected search result. e.g. 5 of 10 results.\neditor.searchResults=%d of %d results\n\n# LOCALIZATION NOTE (editor.singleResult): Copy shown when there is one result.\neditor.singleResult=1 result\n\n# LOCALIZATION NOTE (editor.noResults): Editor Search bar message\n# for when no results found.\neditor.noResults=No results\n\n# LOCALIZATION NOTE (editor.searchResults.nextResult): Editor Search bar\n# tooltip for traversing to the Next Result\neditor.searchResults.nextResult=Next result\n\n# LOCALIZATION NOTE (editor.searchResults.prevResult): Editor Search bar\n# tooltip for traversing to the Previous Result\neditor.searchResults.prevResult=Previous result\n\n# LOCALIZATION NOTE (editor.searchTypeToggleTitle): Search bar title for\n# toggling search type buttons(function search, variable search)\neditor.searchTypeToggleTitle=Search for:\n\n# LOCALIZATION NOTE (editor.continueToHere.label): Editor gutter context\n# menu item for jumping to a new paused location\neditor.continueToHere.label=Continue to here\neditor.continueToHere.accesskey=H\n\n# LOCALIZATION NOTE (editor.addBreakpoint): Editor gutter context menu item\n# for adding a breakpoint on a line.\neditor.addBreakpoint=Add breakpoint\n\n# LOCALIZATION NOTE (editor.disableBreakpoint): Editor gutter context menu item\n# for disabling a breakpoint on a line.\neditor.disableBreakpoint=Disable breakpoint\neditor.disableBreakpoint.accesskey=D\n\n# LOCALIZATION NOTE (editor.enableBreakpoint): Editor gutter context menu item\n# for enabling a breakpoint on a line.\neditor.enableBreakpoint=Enable breakpoint\n\n# LOCALIZATION NOTE (editor.removeBreakpoint): Editor gutter context menu item\n# for removing a breakpoint on a line.\neditor.removeBreakpoint=Remove breakpoint\n\n# LOCALIZATION NOTE (editor.editBreakpoint): Editor gutter context menu item\n# for setting a breakpoint condition on a line.\neditor.editBreakpoint=Edit breakpoint\n\n# LOCALIZATION NOTE (editor.addConditionalBreakpoint): Editor gutter context\n# menu item for adding a breakpoint condition on a line.\neditor.addConditionalBreakpoint=Add conditional breakpoint\neditor.addConditionalBreakpoint.accesskey=c\n\n# LOCALIZATION NOTE (editor.conditionalPanel.placeholder): Placeholder text for\n# input element inside ConditionalPanel component\neditor.conditionalPanel.placeholder=This breakpoint will pause when the expression is true\n\n# LOCALIZATION NOTE (editor.conditionalPanel.close): Tooltip text for\n# close button inside ConditionalPanel component\neditor.conditionalPanel.close=Cancel edit breakpoint and close\n\n# LOCALIZATION NOTE (editor.jumpToMappedLocation1): Context menu item\n# for navigating to a source mapped location\neditor.jumpToMappedLocation1=Jump to %S location\neditor.jumpToMappedLocation1.accesskey=m\n\n# LOCALIZATION NOTE (framework.disableGrouping): This is the text that appears in the\n# context menu to disable framework grouping.\nframework.disableGrouping=Disable framework grouping\nframework.disableGrouping.accesskey=u\n\n# LOCALIZATION NOTE (framework.enableGrouping): This is the text that appears in the\n# context menu to enable framework grouping.\nframework.enableGrouping=Enable framework grouping\nframework.enableGrouping.accesskey=u\n\n# LOCALIZATION NOTE (generated): Source Map term for a server source location\ngenerated=generated\n\n# LOCALIZATION NOTE (original): Source Map term for a debugger UI source location\noriginal=original\n\n# LOCALIZATION NOTE (expressions.placeholder): Placeholder text for expression\n# input element\nexpressions.placeholder=Add watch expression\nexpressions.label=Add watch expression\nexpressions.accesskey=e\n\n# LOCALIZATION NOTE (sourceTabs.closeTab): Editor source tab context menu item\n# for closing the selected tab below the mouse.\nsourceTabs.closeTab=Close tab\nsourceTabs.closeTab.accesskey=c\n\n# LOCALIZATION NOTE (sourceTabs.closeOtherTabs): Editor source tab context menu item\n# for closing the other tabs.\nsourceTabs.closeOtherTabs=Close other tabs\nsourceTabs.closeOtherTabs.accesskey=o\n\n# LOCALIZATION NOTE (sourceTabs.closeTabsToEnd): Editor source tab context menu item\n# for closing the tabs to the end (the right for LTR languages) of the selected tab.\nsourceTabs.closeTabsToEnd=Close tabs to the right\nsourceTabs.closeTabsToEnd.accesskey=e\n\n# LOCALIZATION NOTE (sourceTabs.closeAllTabs): Editor source tab context menu item\n# for closing all tabs.\nsourceTabs.closeAllTabs=Close all tabs\nsourceTabs.closeAllTabs.accesskey=a\n\n# LOCALIZATION NOTE (sourceTabs.revealInTree): Editor source tab context menu item\n# for revealing source in tree.\nsourceTabs.revealInTree=Reveal in tree\nsourceTabs.revealInTree.accesskey=r\n\n# LOCALIZATION NOTE (sourceTabs.prettyPrint): Editor source tab context menu item\n# for pretty printing the source.\nsourceTabs.prettyPrint=Pretty print source\nsourceTabs.prettyPrint.accesskey=p\n\n# LOCALIZATION NOTE (sourceFooter.blackbox): Tooltip text associated\n# with the blackbox button\nsourceFooter.blackbox=Blackbox source\nsourceFooter.blackbox.accesskey=B\n\n# LOCALIZATION NOTE (sourceFooter.unblackbox): Tooltip text associated\n# with the blackbox button\nsourceFooter.unblackbox=Unblackbox source\nsourceFooter.unblackbox.accesskey=b\n\n# LOCALIZATION NOTE (sourceFooter.blackboxed): Text associated\n# with a blackboxed source\nsourceFooter.blackboxed=Blackboxed source\n\n# LOCALIZATION NOTE (sourceFooter.mappedSource): Text associated\n# with a mapped source. %S is replaced by the source map origin.\nsourceFooter.mappedSource=(From %S)\n\n# LOCALIZATION NOTE (sourceFooter.mappedSourceTooltip): Tooltip text associated\n# with a mapped source. %S is replaced by the source map origin.\nsourceFooter.mappedSourceTooltip=(Source mapped from %S)\n\n# LOCALIZATION NOTE (sourceFooter.codeCoverage): Text associated\n# with a code coverage button\nsourceFooter.codeCoverage=Code coverage\n\n# LOCALIZATION NOTE (sourceTabs.closeTabButtonTooltip): The tooltip that is displayed\n# for close tab button in source tabs.\nsourceTabs.closeTabButtonTooltip=Close tab\n\n# LOCALIZATION NOTE (scopes.header): Scopes right sidebar pane header.\nscopes.header=Scopes\n\n# LOCALIZATION NOTE (scopes.notAvailable): Scopes right sidebar pane message\n# for when the debugger is paused, but there isn't pause data.\nscopes.notAvailable=Scopes unavailable\n\n# LOCALIZATION NOTE (scopes.notPaused): Scopes right sidebar pane message\n# for when the debugger is not paused.\nscopes.notPaused=Not paused\n\n# LOCALIZATION NOTE (scopes.block): Refers to a block of code in\n# the scopes pane when the debugger is paused.\nscopes.block=Block\n\n# LOCALIZATION NOTE (sources.header): Sources left sidebar header\nsources.header=Sources\n\n# LOCALIZATION NOTE (outline.header): Outline left sidebar header\noutline.header=Outline\n\n# LOCALIZATION NOTE (outline.noFunctions): Outline text when there are no functions to display\noutline.noFunctions=No functions\n\n# LOCALIZATION NOTE (sources.search): Sources left sidebar prompt\n# e.g. Cmd+P to search. On a mac, we use the command unicode character.\n# On windows, it's ctrl.\nsources.search=%S to search\n\n# LOCALIZATION NOTE (watchExpressions.header): Watch Expressions right sidebar\n# pane header.\nwatchExpressions.header=Watch expressions\n\n# LOCALIZATION NOTE (watchExpressions.refreshButton): Watch Expressions header\n# button for refreshing the expressions.\nwatchExpressions.refreshButton=Refresh\n\n# LOCALIZATION NOTE (welcome.search): The center pane welcome panel's\n# search prompt. e.g. cmd+p to search for files. On windows, it's ctrl, on\n# a mac we use the unicode character.\nwelcome.search=%S to search for sources\n\n# LOCALIZATION NOTE (welcome.findInFiles): The center pane welcome panel's\n# search prompt. e.g. cmd+f to search for files. On windows, it's ctrl+shift+f, on\n# a mac we use the unicode character.\nwelcome.findInFiles=%S to find in files\n\n# LOCALIZATION NOTE (welcome.searchFunction): Label displayed in the welcome\n# panel. %S is replaced by the keyboard shortcut to search for functions.\nwelcome.searchFunction=%S to search for functions in file\n\n# LOCALIZATION NOTE (sourceSearch.search): The center pane Source Search\n# prompt for searching for files.\nsourceSearch.search=Search sources…\n\n# LOCALIZATION NOTE (sourceSearch.noResults2): The center pane Source Search\n# message when the query did not match any of the sources.\nsourceSearch.noResults2=No results found\n\n# LOCALIZATION NOTE (ignoreExceptions): The pause on exceptions button tooltip\n# when the debugger will not pause on exceptions.\nignoreExceptions=Ignore exceptions. Click to pause on uncaught exceptions\n\n# LOCALIZATION NOTE (pauseOnUncaughtExceptions): The pause on exceptions button\n# tooltip when the debugger will pause on uncaught exceptions.\npauseOnUncaughtExceptions=Pause on uncaught exceptions. Click to pause on all exceptions\n\n# LOCALIZATION NOTE (pauseOnExceptions): The pause on exceptions button tooltip\n# when the debugger will pause on all exceptions.\npauseOnExceptions=Pause on all exceptions. Click to ignore exceptions\n\n# LOCALIZATION NOTE (loadingText): The text that is displayed in the script\n# editor when the loading process has started but there is no file to display\n# yet.\nloadingText=Loading\\u2026\n\n# LOCALIZATION NOTE (errorLoadingText3): The text that is displayed in the debugger\n# viewer when there is an error loading a file\nerrorLoadingText3=Error loading this URI: %S\n\n# LOCALIZATION NOTE (addWatchExpressionText): The text that is displayed in the\n# watch expressions list to add a new item.\naddWatchExpressionText=Add watch expression\n\n# LOCALIZATION NOTE (addWatchExpressionButton): The button that is displayed in the\n# variables view popup.\naddWatchExpressionButton=Watch\n\n# LOCALIZATION NOTE (emptyVariablesText): The text that is displayed in the\n# variables pane when there are no variables to display.\nemptyVariablesText=No variables to display\n\n# LOCALIZATION NOTE (scopeLabel): The text that is displayed in the variables\n# pane as a header for each variable scope (e.g. \"Global scope, \"With scope\",\n# etc.).\nscopeLabel=%S scope\n\n# LOCALIZATION NOTE (watchExpressionsScopeLabel): The name of the watch\n# expressions scope. This text is displayed in the variables pane as a header for\n# the watch expressions scope.\nwatchExpressionsScopeLabel=Watch expressions\n\n# LOCALIZATION NOTE (globalScopeLabel): The name of the global scope. This text\n# is added to scopeLabel and displayed in the variables pane as a header for\n# the global scope.\nglobalScopeLabel=Global\n\n# LOCALIZATION NOTE (variablesViewErrorStacktrace): This is the text that is\n# shown before the stack trace in an error.\nvariablesViewErrorStacktrace=Stack trace:\n\n# LOCALIZATION NOTE (variablesViewMoreObjects): the text that is displayed\n# when you have an object preview that does not show all of the elements. At the end of the list\n# you see \"N more...\" in the web console output.\n# This is a semi-colon list of plural forms.\n# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals\n# #1 number of remaining items in the object\n# example: 3 more…\nvariablesViewMoreObjects=#1 more…;#1 more…\n\n# LOCALIZATION NOTE (variablesEditableNameTooltip): The text that is displayed\n# in the variables list on an item with an editable name.\nvariablesEditableNameTooltip=Double click to edit\n\n# LOCALIZATION NOTE (variablesEditableValueTooltip): The text that is displayed\n# in the variables list on an item with an editable value.\nvariablesEditableValueTooltip=Click to change value\n\n# LOCALIZATION NOTE (variablesCloseButtonTooltip): The text that is displayed\n# in the variables list on an item which can be removed.\nvariablesCloseButtonTooltip=Click to remove\n\n# LOCALIZATION NOTE (variablesEditButtonTooltip): The text that is displayed\n# in the variables list on a getter or setter which can be edited.\nvariablesEditButtonTooltip=Click to set value\n\n# LOCALIZATION NOTE (variablesDomNodeValueTooltip): The text that is displayed\n# in a tooltip on the \"open in inspector\" button in the the variables list for a\n# DOMNode item.\nvariablesDomNodeValueTooltip=Click to select the node in the inspector\n\n# LOCALIZATION NOTE (configurable|...|Tooltip): The text that is displayed\n# in the variables list on certain variables or properties as tooltips.\n# Expanations of what these represent can be found at the following links:\n# https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty\n# https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/isExtensible\n# https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/isFrozen\n# https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/isSealed\n# It's probably best to keep these in English.\nconfigurableTooltip=configurable\nenumerableTooltip=enumerable\nwritableTooltip=writable\nfrozenTooltip=frozen\nsealedTooltip=sealed\nextensibleTooltip=extensible\noverriddenTooltip=overridden\nWebIDLTooltip=WebIDL\n\n# LOCALIZATION NOTE (variablesSeparatorLabel): The text that is displayed\n# in the variables list as a separator between the name and value.\nvariablesSeparatorLabel=:\n\n# LOCALIZATION NOTE (watchExpressionsSeparatorLabel2): The text that is displayed\n# in the watch expressions list as a separator between the code and evaluation.\nwatchExpressionsSeparatorLabel2=\\u0020→\n\n# LOCALIZATION NOTE (functionSearchSeparatorLabel): The text that is displayed\n# in the functions search panel as a separator between function's inferred name\n# and its real name (if available).\nfunctionSearchSeparatorLabel=←\n\n# LOCALIZATION NOTE(gotoLineModal.placeholder): The placeholder\n# text displayed when the user searches for specific lines in a file\ngotoLineModal.placeholder=Go to line…\ngotoLineModal.key=CmdOrCtrl+Shift+;\ngotoLineModal.title=Go to a line number in a file\n\n# LOCALIZATION NOTE(symbolSearch.search.functionsPlaceholder): The placeholder\n# text displayed when the user searches for functions in a file\nsymbolSearch.search.functionsPlaceholder=Search functions…\nsymbolSearch.search.functionsPlaceholder.title=Search for a function in a file\n\n# LOCALIZATION NOTE(symbolSearch.search.variablesPlaceholder): The placeholder\n# text displayed when the user searches for variables in a file\nsymbolSearch.search.variablesPlaceholder=Search variables…\nsymbolSearch.search.variablesPlaceholder.title=Search for a variable in a file\n\n# LOCALIZATION NOTE(symbolSearch.search.key2): The Key Shortcut for\n# searching for a function or variable\nsymbolSearch.search.key2=CmdOrCtrl+Shift+O\n\n# LOCALIZATION NOTE(symbolSearch.searchModifier.modifiersLabel): A label\n# preceding the group of modifiers\nsymbolSearch.searchModifier.modifiersLabel=Modifiers:\n\n# LOCALIZATION NOTE(symbolSearch.searchModifier.regex): A search option\n# when searching text in a file\nsymbolSearch.searchModifier.regex=Regex\n\n# LOCALIZATION NOTE(symbolSearch.searchModifier.caseSensitive): A search option\n# when searching text in a file\nsymbolSearch.searchModifier.caseSensitive=Case sensitive\n\n# LOCALIZATION NOTE(symbolSearch.searchModifier.wholeWord): A search option\n# when searching text in a file\nsymbolSearch.searchModifier.wholeWord=Whole word\n\n# LOCALIZATION NOTE (resumptionOrderPanelTitle): This is the text that appears\n# as a description in the notification panel popup, when multiple debuggers are\n# open in separate tabs and the user tries to resume them in the wrong order.\n# The substitution parameter is the URL of the last paused window that must be\n# resumed first.\nresumptionOrderPanelTitle=There are one or more paused debuggers. Please resume the most-recently paused debugger first at: %S\n\nvariablesViewOptimizedOut=(optimized away)\nvariablesViewUninitialized=(uninitialized)\nvariablesViewMissingArgs=(unavailable)\n\nanonymousSourcesLabel=Anonymous sources\n\nexperimental=This is an experimental feature\n\n# LOCALIZATION NOTE (whyPaused.debuggerStatement): The text that is displayed\n# in a info block explaining how the debugger is currently paused due to a `debugger`\n# statement in the code\nwhyPaused.debuggerStatement=Paused on debugger statement\n\n# LOCALIZATION NOTE (whyPaused.breakpoint): The text that is displayed\n# in a info block explaining how the debugger is currently paused on a breakpoint\nwhyPaused.breakpoint=Paused on breakpoint\n\n# LOCALIZATION NOTE (whyPaused.exception): The text that is displayed\n# in a info block explaining how the debugger is currently paused on an exception\nwhyPaused.exception=Paused on exception\n\n# LOCALIZATION NOTE (whyPaused.resumeLimit): The text that is displayed\n# in a info block explaining how the debugger is currently paused while stepping\n# in or out of the stack\nwhyPaused.resumeLimit=Paused while stepping\n\n# LOCALIZATION NOTE (whyPaused.pauseOnDOMEvents): The text that is displayed\n# in a info block explaining how the debugger is currently paused on a\n# dom event\nwhyPaused.pauseOnDOMEvents=Paused on event listener\n\n# LOCALIZATION NOTE (whyPaused.breakpointConditionThrown): The text that is displayed\n# in an info block when evaluating a conditional breakpoint throws an error\nwhyPaused.breakpointConditionThrown=Error with conditional breakpoint\n\n# LOCALIZATION NOTE (whyPaused.xhr): The text that is displayed\n# in a info block explaining how the debugger is currently paused on an\n# xml http request\nwhyPaused.xhr=Paused on XMLHttpRequest\n\n# LOCALIZATION NOTE (whyPaused.promiseRejection): The text that is displayed\n# in a info block explaining how the debugger is currently paused on a\n# promise rejection\nwhyPaused.promiseRejection=Paused on promise rejection\n\n# LOCALIZATION NOTE (whyPaused.assert): The text that is displayed\n# in a info block explaining how the debugger is currently paused on an\n# assert\nwhyPaused.assert=Paused on assertion\n\n# LOCALIZATION NOTE (whyPaused.debugCommand): The text that is displayed\n# in a info block explaining how the debugger is currently paused on a\n# debugger statement\nwhyPaused.debugCommand=Paused on debugged function\n\n# LOCALIZATION NOTE (whyPaused.other): The text that is displayed\n# in a info block explaining how the debugger is currently paused on an event\n# listener breakpoint set\nwhyPaused.other=Debugger paused\n\n# LOCALIZATION NOTE (ctrl): The text that is used for documenting\n# keyboard shortcuts that use the control key\nctrl=Ctrl\n\n# LOCALIZATION NOTE (anonymous): The text that is displayed when the\n# display name is null.\nanonymous=(anonymous)\n\n# LOCALIZATION NOTE (shortcuts.toggleBreakpoint): text describing\n# keyboard shortcut action for toggling breakpoint\nshortcuts.toggleBreakpoint=Toggle Breakpoint\nshortcuts.toggleBreakpoint.accesskey=B\n\n# LOCALIZATION NOTE (shortcuts.toggleCondPanel): text describing\n# keyboard shortcut action for toggling conditional panel keyboard\nshortcuts.toggleCondPanel=Toggle Conditional Panel\n\n# LOCALIZATION NOTE (shortcuts.pauseOrResume): text describing\n# keyboard shortcut action for pause of resume\nshortcuts.pauseOrResume=Pause/Resume\n\n# LOCALIZATION NOTE (shortcuts.stepOver): text describing\n# keyboard shortcut action for stepping over\nshortcuts.stepOver=Step Over\n\n# LOCALIZATION NOTE (shortcuts.stepIn): text describing\n# keyboard shortcut action for stepping in\nshortcuts.stepIn=Step In\n\n# LOCALIZATION NOTE (shortcuts.stepOut): text describing\n# keyboard shortcut action for stepping out\nshortcuts.stepOut=Step Out\n\n# LOCALIZATION NOTE (shortcuts.fileSearch): text describing\n# keyboard shortcut action for source file search\nshortcuts.fileSearch=Source File Search\n\n# LOCALIZATION NOTE (shortcuts.searchAgain): text describing\n# keyboard shortcut action for searching again\nshortcuts.searchAgain=Search Again\n\n# LOCALIZATION NOTE (shortcuts.projectSearch): text describing\n# keyboard shortcut action for full project search\nshortcuts.projectSearch=Full Project Search\n\n# LOCALIZATION NOTE (shortcuts.functionSearch): text describing\n# keyboard shortcut action for function search\nshortcuts.functionSearch=Function Search\n\n# LOCALIZATION NOTE (shortcuts.buttonName): text describing\n# keyboard shortcut button text\nshortcuts.buttonName=Keyboard shortcuts\n"
+module.exports = "# This Source Code Form is subject to the terms of the Mozilla Public\n# License, v. 2.0. If a copy of the MPL was not distributed with this\n# file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n# LOCALIZATION NOTE These strings are used inside the Debugger\n# which is available from the Web Developer sub-menu -> 'Debugger'.\n# The correct localization of this file might be to keep it in\n# English, or another language commonly spoken among web developers.\n# You want to make that choice consistent across the developer tools.\n# A good criteria is the language in which you'd find the best\n# documentation on web development on the web.\n\n# LOCALIZATION NOTE (collapsePanes): This is the tooltip for the button\n# that collapses the left and right panes in the debugger UI.\ncollapsePanes=Collapse panes\n\n# LOCALIZATION NOTE (copySource): This is the text that appears in the\n# context menu to copy the selected source of file open.\ncopySource=Copy\ncopySource.accesskey=y\n\n# LOCALIZATION NOTE (copySourceUri2): This is the text that appears in the\n# context menu to copy the source URI of file open.\ncopySourceUri2=Copy source URI\ncopySourceUri2.accesskey=u\n\n# LOCALIZATION NOTE (setDirectoryRoot): This is the text that appears in the\n# context menu to set a directory as root directory\nsetDirectoryRoot.label=Set directory root\nsetDirectoryRoot.accesskey=r\n\n# LOCALIZATION NOTE (copyFunction): This is the text that appears in the\n# context menu to copy the function the user selected\ncopyFunction.label=Copy function\ncopyFunction.accesskey=F\n\n# LOCALIZATION NOTE (copyStackTrace): This is the text that appears in the\n# context menu to copy the stack trace methods, file names and row number.\ncopyStackTrace=Copy stack trace\ncopyStackTrace.accesskey=c\n\n# LOCALIZATION NOTE (expandPanes): This is the tooltip for the button\n# that expands the left and right panes in the debugger UI.\nexpandPanes=Expand panes\n\n# LOCALIZATION NOTE (pauseButtonTooltip): The tooltip that is displayed for the pause\n# button when the debugger is in a running state.\npauseButtonTooltip=Pause %S\n\n# LOCALIZATION NOTE (pausePendingButtonTooltip): The tooltip that is displayed for\n# the pause button after it's been clicked but before the next JavaScript to run.\npausePendingButtonTooltip=Waiting for next execution\n\n# LOCALIZATION NOTE (resumeButtonTooltip): The label that is displayed on the pause\n# button when the debugger is in a paused state.\nresumeButtonTooltip=Resume %S\n\n# LOCALIZATION NOTE (stepOverTooltip): The label that is displayed on the\n# button that steps over a function call.\nstepOverTooltip=Step over %S\n\n# LOCALIZATION NOTE (stepInTooltip): The label that is displayed on the\n# button that steps into a function call.\nstepInTooltip=Step in %S\n\n# LOCALIZATION NOTE (stepOutTooltip): The label that is displayed on the\n# button that steps out of a function call.\nstepOutTooltip=Step out %S\n\n# LOCALIZATION NOTE (pauseButtonItem): The label that is displayed for the dropdown pause\n# list item when the debugger is in a running state.\npauseButtonItem=Pause on Next Statement\n\n# LOCALIZATION NOTE (ignoreExceptionsItem): The pause on exceptions button description\n# when the debugger will not pause on exceptions.\nignoreExceptionsItem=Ignore exceptions\n\n# LOCALIZATION NOTE (pauseOnUncaughtExceptionsItem): The pause on exceptions dropdown\n# item shown when a user is adding a new breakpoint.\npauseOnUncaughtExceptionsItem=Pause on uncaught exceptions\n\n# LOCALIZATION NOTE (pauseOnExceptionsItem): The pause on exceptions button description\n# when the debugger will pause on all exceptions.\npauseOnExceptionsItem=Pause on all exceptions\n\n# LOCALIZATION NOTE (workersHeader): The text to display in the events\n# header.\nworkersHeader=Workers\n\n# LOCALIZATION NOTE (noWorkersText): The text to display in the workers list\n# when there are no workers.\nnoWorkersText=This page has no workers.\n\n# LOCALIZATION NOTE (noSourcesText): The text to display in the sources list\n# when there are no sources.\nnoSourcesText=This page has no sources.\n\n# LOCALIZATION NOTE (noEventListenersText): The text to display in the events tab\n# when there are no events.\nnoEventListenersText=No event listeners to display.\n\n# LOCALIZATION NOTE (eventListenersHeader): The text to display in the events\n# header.\neventListenersHeader=Event listeners\n\n# LOCALIZATION NOTE (noStackFramesText): The text to display in the call stack tab\n# when there are no stack frames.\nnoStackFramesText=No stack frames to display\n\n# LOCALIZATION NOTE (eventCheckboxTooltip): The tooltip text to display when\n# the user hovers over the checkbox used to toggle an event breakpoint.\neventCheckboxTooltip=Toggle breaking on this event\n\n# LOCALIZATION NOTE (eventOnSelector): The text to display in the events tab\n# for every event item, between the event type and event selector.\neventOnSelector=on\n\n# LOCALIZATION NOTE (eventInSource): The text to display in the events tab\n# for every event item, between the event selector and listener's owner source.\neventInSource=in\n\n# LOCALIZATION NOTE (eventNodes): The text to display in the events tab when\n# an event is listened on more than one target node.\neventNodes=%S nodes\n\n# LOCALIZATION NOTE (eventNative): The text to display in the events tab when\n# a listener is added from plugins, thus getting translated to native code.\neventNative=[native code]\n\n# LOCALIZATION NOTE (*Events): The text to display in the events tab for\n# each group of sub-level event entries.\nanimationEvents=Animation\naudioEvents=Audio\nbatteryEvents=Battery\nclipboardEvents=Clipboard\ncompositionEvents=Composition\ndeviceEvents=Device\ndisplayEvents=Display\ndragAndDropEvents=Drag and Drop\ngamepadEvents=Gamepad\nindexedDBEvents=IndexedDB\ninteractionEvents=Interaction\nkeyboardEvents=Keyboard\nmediaEvents=HTML5 Media\nmouseEvents=Mouse\nmutationEvents=Mutation\nnavigationEvents=Navigation\npointerLockEvents=Pointer Lock\nsensorEvents=Sensor\nstorageEvents=Storage\ntimeEvents=Time\ntouchEvents=Touch\notherEvents=Other\n\n# LOCALIZATION NOTE (blackboxCheckboxTooltip2): The tooltip text to display when\n# the user hovers over the checkbox used to toggle blackboxing its associated\n# source.\nblackboxCheckboxTooltip2=Toggle blackboxing\n\n# LOCALIZATION NOTE (sources.search.key2): Key shortcut to open the search for\n# searching all the source files the debugger has seen.\nsources.search.key2=CmdOrCtrl+P\n\n# LOCALIZATION NOTE (sources.search.alt.key): A second key shortcut to open the\n# search for searching all the source files the debugger has seen.\nsources.search.alt.key=CmdOrCtrl+O\n\n# LOCALIZATION NOTE (projectTextSearch.key): A key shortcut to open the\n# full project text search for searching all the files the debugger has seen.\nprojectTextSearch.key=CmdOrCtrl+Shift+F\n\n# LOCALIZATION NOTE (functionSearch.key): A key shortcut to open the\n# modal for searching functions in a file.\nfunctionSearch.key=CmdOrCtrl+Shift+O\n\n# LOCALIZATION NOTE (toggleBreakpoint.key): A key shortcut to toggle\n# breakpoints.\ntoggleBreakpoint.key=CmdOrCtrl+B\n\n# LOCALIZATION NOTE (toggleCondPanel.key): A key shortcut to toggle\n# the conditional breakpoint panel.\ntoggleCondPanel.key=CmdOrCtrl+Shift+B\n\n# LOCALIZATION NOTE (stepOut.key): A key shortcut to\n# step out.\nstepOut.key=Shift+F11\n\n# LOCALIZATION NOTE (shortcuts.header.editor): Sections header in\n# the shortcuts modal for keyboard shortcuts related to editing.\nshortcuts.header.editor=Editor\n\n# LOCALIZATION NOTE (shortcuts.header.stepping): Sections header in\n# the shortcuts modal for keyboard shortcuts related to stepping.\nshortcuts.header.stepping=Stepping\n\n# LOCALIZATION NOTE (shortcuts.header.search): Sections header in\n# the shortcuts modal for keyboard shortcuts related to search.\nshortcuts.header.search=Search\n\n# LOCALIZATION NOTE (projectTextSearch.placeholder): A placeholder shown\n# when searching across all of the files in a project.\nprojectTextSearch.placeholder=Find in files…\n\n# LOCALIZATION NOTE (projectTextSearch.noResults): The center pane Text Search\n# message when the query did not match any text of all files in a project.\nprojectTextSearch.noResults=No results found\n\n# LOCALIZATION NOTE (sources.noSourcesAvailable): Text shown when the debugger\n# does not have any sources.\nsources.noSourcesAvailable=This page has no sources\n\n# LOCALIZATION NOTE (sourceSearch.search.key2): Key shortcut to open the search\n# for searching within a the currently opened files in the editor\nsourceSearch.search.key2=CmdOrCtrl+F\n\n# LOCALIZATION NOTE (sourceSearch.search.placeholder): placeholder text in\n# the source search input bar\nsourceSearch.search.placeholder=Search in file…\n\n# LOCALIZATION NOTE (sourceSearch.search.again.key2): Key shortcut to highlight\n# the next occurrence of the last search triggered from a source search\nsourceSearch.search.again.key2=CmdOrCtrl+G\n\n# LOCALIZATION NOTE (sourceSearch.search.againPrev.key2): Key shortcut to highlight\n# the previous occurrence of the last search triggered from a source search\nsourceSearch.search.againPrev.key2=CmdOrCtrl+Shift+G\n\n# LOCALIZATION NOTE (sourceSearch.resultsSummary1): Shows a summary of\n# the number of matches for autocomplete\nsourceSearch.resultsSummary1=%d results\n\n# LOCALIZATION NOTE (noMatchingStringsText): The text to display in the\n# global search results when there are no matching strings after filtering.\nnoMatchingStringsText=No matches found\n\n# LOCALIZATION NOTE (emptySearchText): This is the text that appears in the\n# filter text box when it is empty and the scripts container is selected.\nemptySearchText=Search scripts (%S)\n\n# LOCALIZATION NOTE (emptyVariablesFilterText): This is the text that\n# appears in the filter text box for the variables view container.\nemptyVariablesFilterText=Filter variables\n\n# LOCALIZATION NOTE (emptyPropertiesFilterText): This is the text that\n# appears in the filter text box for the editor's variables view bubble.\nemptyPropertiesFilterText=Filter properties\n\n# LOCALIZATION NOTE (searchPanelFilter): This is the text that appears in the\n# filter panel popup for the filter scripts operation.\nsearchPanelFilter=Filter scripts (%S)\n\n# LOCALIZATION NOTE (searchPanelGlobal): This is the text that appears in the\n# filter panel popup for the global search operation.\nsearchPanelGlobal=Search in all files (%S)\n\n# LOCALIZATION NOTE (searchPanelFunction): This is the text that appears in the\n# filter panel popup for the function search operation.\nsearchPanelFunction=Search for function definition (%S)\n\n# LOCALIZATION NOTE (searchPanelToken): This is the text that appears in the\n# filter panel popup for the token search operation.\nsearchPanelToken=Find in this file (%S)\n\n# LOCALIZATION NOTE (searchPanelGoToLine): This is the text that appears in the\n# filter panel popup for the line search operation.\nsearchPanelGoToLine=Go to line (%S)\n\n# LOCALIZATION NOTE (searchPanelVariable): This is the text that appears in the\n# filter panel popup for the variables search operation.\nsearchPanelVariable=Filter variables (%S)\n\n# LOCALIZATION NOTE (breakpointMenuItem): The text for all the elements that\n# are displayed in the breakpoints menu item popup.\nbreakpointMenuItem.setConditional=Configure conditional breakpoint\nbreakpointMenuItem.enableSelf2.label=Enable\nbreakpointMenuItem.enableSelf2.accesskey=E\nbreakpointMenuItem.disableSelf2.label=Disable\nbreakpointMenuItem.disableSelf2.accesskey=D\nbreakpointMenuItem.deleteSelf2.label=Remove\nbreakpointMenuItem.deleteSelf2.accesskey=R\nbreakpointMenuItem.enableOthers2.label=Enable others\nbreakpointMenuItem.enableOthers2.accesskey=o\nbreakpointMenuItem.disableOthers2.label=Disable others\nbreakpointMenuItem.disableOthers2.accesskey=s\nbreakpointMenuItem.deleteOthers2.label=Remove others\nbreakpointMenuItem.deleteOthers2.accesskey=h\nbreakpointMenuItem.enableAll2.label=Enable all\nbreakpointMenuItem.enableAll2.accesskey=b\nbreakpointMenuItem.disableAll2.label=Disable all\nbreakpointMenuItem.disableAll2.accesskey=k\nbreakpointMenuItem.deleteAll2.label=Remove all\nbreakpointMenuItem.deleteAll2.accesskey=a\nbreakpointMenuItem.removeCondition2.label=Remove condition\nbreakpointMenuItem.removeCondition2.accesskey=c\nbreakpointMenuItem.addCondition2.label=Add condition\nbreakpointMenuItem.addCondition2.accesskey=A\nbreakpointMenuItem.editCondition2.label=Edit condition\nbreakpointMenuItem.editCondition2.accesskey=n\nbreakpointMenuItem.enableSelf=Enable breakpoint\nbreakpointMenuItem.enableSelf.accesskey=E\nbreakpointMenuItem.disableSelf=Disable breakpoint\nbreakpointMenuItem.disableSelf.accesskey=D\nbreakpointMenuItem.deleteSelf=Remove breakpoint\nbreakpointMenuItem.deleteSelf.accesskey=R\nbreakpointMenuItem.enableOthers=Enable others\nbreakpointMenuItem.enableOthers.accesskey=o\nbreakpointMenuItem.disableOthers=Disable others\nbreakpointMenuItem.disableOthers.accesskey=s\nbreakpointMenuItem.deleteOthers=Remove others\nbreakpointMenuItem.deleteOthers.accesskey=h\nbreakpointMenuItem.enableAll=Enable all breakpoints\nbreakpointMenuItem.enableAll.accesskey=b\nbreakpointMenuItem.disableAll=Disable all breakpoints\nbreakpointMenuItem.disableAll.accesskey=k\nbreakpointMenuItem.deleteAll=Remove all breakpoints\nbreakpointMenuItem.deleteAll.accesskey=a\nbreakpointMenuItem.removeCondition.label=Remove breakpoint condition\nbreakpointMenuItem.removeCondition.accesskey=c\nbreakpointMenuItem.editCondition.label=Edit breakpoint condition\nbreakpointMenuItem.editCondition.accesskey=n\n\n# LOCALIZATION NOTE (breakpoints.header): Breakpoints right sidebar pane header.\nbreakpoints.header=Breakpoints\n\n# LOCALIZATION NOTE (breakpoints.none): The text that appears when there are\n# no breakpoints present\nbreakpoints.none=No breakpoints\n\n# LOCALIZATION NOTE (breakpoints.enable): The text that may appear as a tooltip\n# when hovering over the 'disable breakpoints' switch button in right sidebar\nbreakpoints.enable=Enable breakpoints\n\n# LOCALIZATION NOTE (breakpoints.disable): The text that may appear as a tooltip\n# when hovering over the 'disable breakpoints' switch button in right sidebar\nbreakpoints.disable=Disable breakpoints\n\n# LOCALIZATION NOTE (breakpoints.removeBreakpointTooltip): The tooltip that is displayed\n# for remove breakpoint button in right sidebar\nbreakpoints.removeBreakpointTooltip=Remove breakpoint\n\n# LOCALIZATION NOTE (callStack.header): Call Stack right sidebar pane header.\ncallStack.header=Call stack\n\n# LOCALIZATION NOTE (callStack.notPaused): Call Stack right sidebar pane\n# message when not paused.\ncallStack.notPaused=Not paused\n\n# LOCALIZATION NOTE (callStack.collapse): Call Stack right sidebar pane\n# message to hide some of the frames that are shown.\ncallStack.collapse=Collapse rows\n\n# LOCALIZATION NOTE (callStack.expand): Call Stack right sidebar pane\n# message to show more of the frames.\ncallStack.expand=Expand rows\n\n# LOCALIZATION NOTE (editor.searchResults): Editor Search bar message\n# for the summarizing the selected search result. e.g. 5 of 10 results.\neditor.searchResults=%d of %d results\n\n# LOCALIZATION NOTE (editor.singleResult): Copy shown when there is one result.\neditor.singleResult=1 result\n\n# LOCALIZATION NOTE (editor.noResults): Editor Search bar message\n# for when no results found.\neditor.noResults=No results\n\n# LOCALIZATION NOTE (editor.searchResults.nextResult): Editor Search bar\n# tooltip for traversing to the Next Result\neditor.searchResults.nextResult=Next result\n\n# LOCALIZATION NOTE (editor.searchResults.prevResult): Editor Search bar\n# tooltip for traversing to the Previous Result\neditor.searchResults.prevResult=Previous result\n\n# LOCALIZATION NOTE (editor.searchTypeToggleTitle): Search bar title for\n# toggling search type buttons(function search, variable search)\neditor.searchTypeToggleTitle=Search for:\n\n# LOCALIZATION NOTE (editor.continueToHere.label): Editor gutter context\n# menu item for jumping to a new paused location\neditor.continueToHere.label=Continue to here\neditor.continueToHere.accesskey=H\n\n# LOCALIZATION NOTE (editor.addBreakpoint): Editor gutter context menu item\n# for adding a breakpoint on a line.\neditor.addBreakpoint=Add breakpoint\n\n# LOCALIZATION NOTE (editor.disableBreakpoint): Editor gutter context menu item\n# for disabling a breakpoint on a line.\neditor.disableBreakpoint=Disable breakpoint\neditor.disableBreakpoint.accesskey=D\n\n# LOCALIZATION NOTE (editor.enableBreakpoint): Editor gutter context menu item\n# for enabling a breakpoint on a line.\neditor.enableBreakpoint=Enable breakpoint\n\n# LOCALIZATION NOTE (editor.removeBreakpoint): Editor gutter context menu item\n# for removing a breakpoint on a line.\neditor.removeBreakpoint=Remove breakpoint\n\n# LOCALIZATION NOTE (editor.editBreakpoint): Editor gutter context menu item\n# for setting a breakpoint condition on a line.\neditor.editBreakpoint=Edit breakpoint\n\n# LOCALIZATION NOTE (editor.addConditionalBreakpoint): Editor gutter context\n# menu item for adding a breakpoint condition on a line.\neditor.addConditionalBreakpoint=Add conditional breakpoint\neditor.addConditionalBreakpoint.accesskey=c\n\n# LOCALIZATION NOTE (editor.conditionalPanel.placeholder): Placeholder text for\n# input element inside ConditionalPanel component\neditor.conditionalPanel.placeholder=This breakpoint will pause when the expression is true\n\n# LOCALIZATION NOTE (editor.conditionalPanel.close): Tooltip text for\n# close button inside ConditionalPanel component\neditor.conditionalPanel.close=Cancel edit breakpoint and close\n\n# LOCALIZATION NOTE (editor.jumpToMappedLocation1): Context menu item\n# for navigating to a source mapped location\neditor.jumpToMappedLocation1=Jump to %S location\neditor.jumpToMappedLocation1.accesskey=m\n\n# LOCALIZATION NOTE (framework.disableGrouping): This is the text that appears in the\n# context menu to disable framework grouping.\nframework.disableGrouping=Disable framework grouping\nframework.disableGrouping.accesskey=u\n\n# LOCALIZATION NOTE (framework.enableGrouping): This is the text that appears in the\n# context menu to enable framework grouping.\nframework.enableGrouping=Enable framework grouping\nframework.enableGrouping.accesskey=u\n\n# LOCALIZATION NOTE (generated): Source Map term for a server source location\ngenerated=generated\n\n# LOCALIZATION NOTE (original): Source Map term for a debugger UI source location\noriginal=original\n\n# LOCALIZATION NOTE (expressions.placeholder): Placeholder text for expression\n# input element\nexpressions.placeholder=Add watch expression\n# LOCALIZATION NOTE (expressions.errorMsg): Error text for expression\n# input element\nexpressions.errorMsg=Invalid expression…\nexpressions.label=Add watch expression\nexpressions.accesskey=e\n\n# LOCALIZATION NOTE (sourceTabs.closeTab): Editor source tab context menu item\n# for closing the selected tab below the mouse.\nsourceTabs.closeTab=Close tab\nsourceTabs.closeTab.accesskey=c\n\n# LOCALIZATION NOTE (sourceTabs.closeOtherTabs): Editor source tab context menu item\n# for closing the other tabs.\nsourceTabs.closeOtherTabs=Close other tabs\nsourceTabs.closeOtherTabs.accesskey=o\n\n# LOCALIZATION NOTE (sourceTabs.closeTabsToEnd): Editor source tab context menu item\n# for closing the tabs to the end (the right for LTR languages) of the selected tab.\nsourceTabs.closeTabsToEnd=Close tabs to the right\nsourceTabs.closeTabsToEnd.accesskey=e\n\n# LOCALIZATION NOTE (sourceTabs.closeAllTabs): Editor source tab context menu item\n# for closing all tabs.\nsourceTabs.closeAllTabs=Close all tabs\nsourceTabs.closeAllTabs.accesskey=a\n\n# LOCALIZATION NOTE (sourceTabs.revealInTree): Editor source tab context menu item\n# for revealing source in tree.\nsourceTabs.revealInTree=Reveal in tree\nsourceTabs.revealInTree.accesskey=r\n\n# LOCALIZATION NOTE (sourceTabs.prettyPrint): Editor source tab context menu item\n# for pretty printing the source.\nsourceTabs.prettyPrint=Pretty print source\nsourceTabs.prettyPrint.accesskey=p\n\n# LOCALIZATION NOTE (sourceFooter.blackbox): Tooltip text associated\n# with the blackbox button\nsourceFooter.blackbox=Blackbox source\nsourceFooter.blackbox.accesskey=B\n\n# LOCALIZATION NOTE (sourceFooter.unblackbox): Tooltip text associated\n# with the blackbox button\nsourceFooter.unblackbox=Unblackbox source\nsourceFooter.unblackbox.accesskey=b\n\n# LOCALIZATION NOTE (sourceFooter.blackboxed): Text associated\n# with a blackboxed source\nsourceFooter.blackboxed=Blackboxed source\n\n# LOCALIZATION NOTE (sourceFooter.mappedSource): Text associated\n# with a mapped source. %S is replaced by the source map origin.\nsourceFooter.mappedSource=(From %S)\n\n# LOCALIZATION NOTE (sourceFooter.mappedSourceTooltip): Tooltip text associated\n# with a mapped source. %S is replaced by the source map origin.\nsourceFooter.mappedSourceTooltip=(Source mapped from %S)\n\n# LOCALIZATION NOTE (sourceFooter.codeCoverage): Text associated\n# with a code coverage button\nsourceFooter.codeCoverage=Code coverage\n\n# LOCALIZATION NOTE (sourceTabs.closeTabButtonTooltip): The tooltip that is displayed\n# for close tab button in source tabs.\nsourceTabs.closeTabButtonTooltip=Close tab\n\n# LOCALIZATION NOTE (scopes.header): Scopes right sidebar pane header.\nscopes.header=Scopes\n\n# LOCALIZATION NOTE (scopes.notAvailable): Scopes right sidebar pane message\n# for when the debugger is paused, but there isn't pause data.\nscopes.notAvailable=Scopes unavailable\n\n# LOCALIZATION NOTE (scopes.notPaused): Scopes right sidebar pane message\n# for when the debugger is not paused.\nscopes.notPaused=Not paused\n\n# LOCALIZATION NOTE (scopes.block): Refers to a block of code in\n# the scopes pane when the debugger is paused.\nscopes.block=Block\n\n# LOCALIZATION NOTE (sources.header): Sources left sidebar header\nsources.header=Sources\n\n# LOCALIZATION NOTE (outline.header): Outline left sidebar header\noutline.header=Outline\n\n# LOCALIZATION NOTE (outline.noFunctions): Outline text when there are no functions to display\noutline.noFunctions=No functions\n\n# LOCALIZATION NOTE (sources.search): Sources left sidebar prompt\n# e.g. Cmd+P to search. On a mac, we use the command unicode character.\n# On windows, it's ctrl.\nsources.search=%S to search\n\n# LOCALIZATION NOTE (watchExpressions.header): Watch Expressions right sidebar\n# pane header.\nwatchExpressions.header=Watch expressions\n\n# LOCALIZATION NOTE (watchExpressions.refreshButton): Watch Expressions header\n# button for refreshing the expressions.\nwatchExpressions.refreshButton=Refresh\n\n# LOCALIZATION NOTE (welcome.search): The center pane welcome panel's\n# search prompt. e.g. cmd+p to search for files. On windows, it's ctrl, on\n# a mac we use the unicode character.\nwelcome.search=%S to search for sources\n\n# LOCALIZATION NOTE (welcome.findInFiles): The center pane welcome panel's\n# search prompt. e.g. cmd+f to search for files. On windows, it's ctrl+shift+f, on\n# a mac we use the unicode character.\nwelcome.findInFiles=%S to find in files\n\n# LOCALIZATION NOTE (welcome.searchFunction): Label displayed in the welcome\n# panel. %S is replaced by the keyboard shortcut to search for functions.\nwelcome.searchFunction=%S to search for functions in file\n\n# LOCALIZATION NOTE (sourceSearch.search): The center pane Source Search\n# prompt for searching for files.\nsourceSearch.search=Search sources…\n\n# LOCALIZATION NOTE (sourceSearch.noResults2): The center pane Source Search\n# message when the query did not match any of the sources.\nsourceSearch.noResults2=No results found\n\n# LOCALIZATION NOTE (ignoreExceptions): The pause on exceptions button tooltip\n# when the debugger will not pause on exceptions.\nignoreExceptions=Ignore exceptions. Click to pause on uncaught exceptions\n\n# LOCALIZATION NOTE (pauseOnUncaughtExceptions): The pause on exceptions button\n# tooltip when the debugger will pause on uncaught exceptions.\npauseOnUncaughtExceptions=Pause on uncaught exceptions. Click to pause on all exceptions\n\n# LOCALIZATION NOTE (pauseOnExceptions): The pause on exceptions button tooltip\n# when the debugger will pause on all exceptions.\npauseOnExceptions=Pause on all exceptions. Click to ignore exceptions\n\n# LOCALIZATION NOTE (loadingText): The text that is displayed in the script\n# editor when the loading process has started but there is no file to display\n# yet.\nloadingText=Loading\\u2026\n\n# LOCALIZATION NOTE (errorLoadingText3): The text that is displayed in the debugger\n# viewer when there is an error loading a file\nerrorLoadingText3=Error loading this URI: %S\n\n# LOCALIZATION NOTE (addWatchExpressionText): The text that is displayed in the\n# watch expressions list to add a new item.\naddWatchExpressionText=Add watch expression\n\n# LOCALIZATION NOTE (addWatchExpressionButton): The button that is displayed in the\n# variables view popup.\naddWatchExpressionButton=Watch\n\n# LOCALIZATION NOTE (emptyVariablesText): The text that is displayed in the\n# variables pane when there are no variables to display.\nemptyVariablesText=No variables to display\n\n# LOCALIZATION NOTE (scopeLabel): The text that is displayed in the variables\n# pane as a header for each variable scope (e.g. \"Global scope, \"With scope\",\n# etc.).\nscopeLabel=%S scope\n\n# LOCALIZATION NOTE (watchExpressionsScopeLabel): The name of the watch\n# expressions scope. This text is displayed in the variables pane as a header for\n# the watch expressions scope.\nwatchExpressionsScopeLabel=Watch expressions\n\n# LOCALIZATION NOTE (globalScopeLabel): The name of the global scope. This text\n# is added to scopeLabel and displayed in the variables pane as a header for\n# the global scope.\nglobalScopeLabel=Global\n\n# LOCALIZATION NOTE (variablesViewErrorStacktrace): This is the text that is\n# shown before the stack trace in an error.\nvariablesViewErrorStacktrace=Stack trace:\n\n# LOCALIZATION NOTE (variablesViewMoreObjects): the text that is displayed\n# when you have an object preview that does not show all of the elements. At the end of the list\n# you see \"N more...\" in the web console output.\n# This is a semi-colon list of plural forms.\n# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals\n# #1 number of remaining items in the object\n# example: 3 more…\nvariablesViewMoreObjects=#1 more…;#1 more…\n\n# LOCALIZATION NOTE (variablesEditableNameTooltip): The text that is displayed\n# in the variables list on an item with an editable name.\nvariablesEditableNameTooltip=Double click to edit\n\n# LOCALIZATION NOTE (variablesEditableValueTooltip): The text that is displayed\n# in the variables list on an item with an editable value.\nvariablesEditableValueTooltip=Click to change value\n\n# LOCALIZATION NOTE (variablesCloseButtonTooltip): The text that is displayed\n# in the variables list on an item which can be removed.\nvariablesCloseButtonTooltip=Click to remove\n\n# LOCALIZATION NOTE (variablesEditButtonTooltip): The text that is displayed\n# in the variables list on a getter or setter which can be edited.\nvariablesEditButtonTooltip=Click to set value\n\n# LOCALIZATION NOTE (variablesDomNodeValueTooltip): The text that is displayed\n# in a tooltip on the \"open in inspector\" button in the the variables list for a\n# DOMNode item.\nvariablesDomNodeValueTooltip=Click to select the node in the inspector\n\n# LOCALIZATION NOTE (configurable|...|Tooltip): The text that is displayed\n# in the variables list on certain variables or properties as tooltips.\n# Expanations of what these represent can be found at the following links:\n# https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty\n# https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/isExtensible\n# https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/isFrozen\n# https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/isSealed\n# It's probably best to keep these in English.\nconfigurableTooltip=configurable\nenumerableTooltip=enumerable\nwritableTooltip=writable\nfrozenTooltip=frozen\nsealedTooltip=sealed\nextensibleTooltip=extensible\noverriddenTooltip=overridden\nWebIDLTooltip=WebIDL\n\n# LOCALIZATION NOTE (variablesSeparatorLabel): The text that is displayed\n# in the variables list as a separator between the name and value.\nvariablesSeparatorLabel=:\n\n# LOCALIZATION NOTE (watchExpressionsSeparatorLabel2): The text that is displayed\n# in the watch expressions list as a separator between the code and evaluation.\nwatchExpressionsSeparatorLabel2=\\u0020→\n\n# LOCALIZATION NOTE (functionSearchSeparatorLabel): The text that is displayed\n# in the functions search panel as a separator between function's inferred name\n# and its real name (if available).\nfunctionSearchSeparatorLabel=←\n\n# LOCALIZATION NOTE(gotoLineModal.placeholder): The placeholder\n# text displayed when the user searches for specific lines in a file\ngotoLineModal.placeholder=Go to line…\ngotoLineModal.key=CmdOrCtrl+Shift+;\ngotoLineModal.title=Go to a line number in a file\n\n# LOCALIZATION NOTE(symbolSearch.search.functionsPlaceholder): The placeholder\n# text displayed when the user searches for functions in a file\nsymbolSearch.search.functionsPlaceholder=Search functions…\nsymbolSearch.search.functionsPlaceholder.title=Search for a function in a file\n\n# LOCALIZATION NOTE(symbolSearch.search.variablesPlaceholder): The placeholder\n# text displayed when the user searches for variables in a file\nsymbolSearch.search.variablesPlaceholder=Search variables…\nsymbolSearch.search.variablesPlaceholder.title=Search for a variable in a file\n\n# LOCALIZATION NOTE(symbolSearch.search.key2): The Key Shortcut for\n# searching for a function or variable\nsymbolSearch.search.key2=CmdOrCtrl+Shift+O\n\n# LOCALIZATION NOTE(symbolSearch.searchModifier.modifiersLabel): A label\n# preceding the group of modifiers\nsymbolSearch.searchModifier.modifiersLabel=Modifiers:\n\n# LOCALIZATION NOTE(symbolSearch.searchModifier.regex): A search option\n# when searching text in a file\nsymbolSearch.searchModifier.regex=Regex\n\n# LOCALIZATION NOTE(symbolSearch.searchModifier.caseSensitive): A search option\n# when searching text in a file\nsymbolSearch.searchModifier.caseSensitive=Case sensitive\n\n# LOCALIZATION NOTE(symbolSearch.searchModifier.wholeWord): A search option\n# when searching text in a file\nsymbolSearch.searchModifier.wholeWord=Whole word\n\n# LOCALIZATION NOTE (resumptionOrderPanelTitle): This is the text that appears\n# as a description in the notification panel popup, when multiple debuggers are\n# open in separate tabs and the user tries to resume them in the wrong order.\n# The substitution parameter is the URL of the last paused window that must be\n# resumed first.\nresumptionOrderPanelTitle=There are one or more paused debuggers. Please resume the most-recently paused debugger first at: %S\n\nvariablesViewOptimizedOut=(optimized away)\nvariablesViewUninitialized=(uninitialized)\nvariablesViewMissingArgs=(unavailable)\n\nanonymousSourcesLabel=Anonymous sources\n\nexperimental=This is an experimental feature\n\n# LOCALIZATION NOTE (whyPaused.debuggerStatement): The text that is displayed\n# in a info block explaining how the debugger is currently paused due to a `debugger`\n# statement in the code\nwhyPaused.debuggerStatement=Paused on debugger statement\n\n# LOCALIZATION NOTE (whyPaused.breakpoint): The text that is displayed\n# in a info block explaining how the debugger is currently paused on a breakpoint\nwhyPaused.breakpoint=Paused on breakpoint\n\n# LOCALIZATION NOTE (whyPaused.exception): The text that is displayed\n# in a info block explaining how the debugger is currently paused on an exception\nwhyPaused.exception=Paused on exception\n\n# LOCALIZATION NOTE (whyPaused.resumeLimit): The text that is displayed\n# in a info block explaining how the debugger is currently paused while stepping\n# in or out of the stack\nwhyPaused.resumeLimit=Paused while stepping\n\n# LOCALIZATION NOTE (whyPaused.pauseOnDOMEvents): The text that is displayed\n# in a info block explaining how the debugger is currently paused on a\n# dom event\nwhyPaused.pauseOnDOMEvents=Paused on event listener\n\n# LOCALIZATION NOTE (whyPaused.breakpointConditionThrown): The text that is displayed\n# in an info block when evaluating a conditional breakpoint throws an error\nwhyPaused.breakpointConditionThrown=Error with conditional breakpoint\n\n# LOCALIZATION NOTE (whyPaused.xhr): The text that is displayed\n# in a info block explaining how the debugger is currently paused on an\n# xml http request\nwhyPaused.xhr=Paused on XMLHttpRequest\n\n# LOCALIZATION NOTE (whyPaused.promiseRejection): The text that is displayed\n# in a info block explaining how the debugger is currently paused on a\n# promise rejection\nwhyPaused.promiseRejection=Paused on promise rejection\n\n# LOCALIZATION NOTE (whyPaused.assert): The text that is displayed\n# in a info block explaining how the debugger is currently paused on an\n# assert\nwhyPaused.assert=Paused on assertion\n\n# LOCALIZATION NOTE (whyPaused.debugCommand): The text that is displayed\n# in a info block explaining how the debugger is currently paused on a\n# debugger statement\nwhyPaused.debugCommand=Paused on debugged function\n\n# LOCALIZATION NOTE (whyPaused.other): The text that is displayed\n# in a info block explaining how the debugger is currently paused on an event\n# listener breakpoint set\nwhyPaused.other=Debugger paused\n\n# LOCALIZATION NOTE (ctrl): The text that is used for documenting\n# keyboard shortcuts that use the control key\nctrl=Ctrl\n\n# LOCALIZATION NOTE (anonymous): The text that is displayed when the\n# display name is null.\nanonymous=(anonymous)\n\n# LOCALIZATION NOTE (shortcuts.toggleBreakpoint): text describing\n# keyboard shortcut action for toggling breakpoint\nshortcuts.toggleBreakpoint=Toggle Breakpoint\nshortcuts.toggleBreakpoint.accesskey=B\n\n# LOCALIZATION NOTE (shortcuts.toggleCondPanel): text describing\n# keyboard shortcut action for toggling conditional panel keyboard\nshortcuts.toggleCondPanel=Toggle Conditional Panel\n\n# LOCALIZATION NOTE (shortcuts.pauseOrResume): text describing\n# keyboard shortcut action for pause of resume\nshortcuts.pauseOrResume=Pause/Resume\n\n# LOCALIZATION NOTE (shortcuts.stepOver): text describing\n# keyboard shortcut action for stepping over\nshortcuts.stepOver=Step Over\n\n# LOCALIZATION NOTE (shortcuts.stepIn): text describing\n# keyboard shortcut action for stepping in\nshortcuts.stepIn=Step In\n\n# LOCALIZATION NOTE (shortcuts.stepOut): text describing\n# keyboard shortcut action for stepping out\nshortcuts.stepOut=Step Out\n\n# LOCALIZATION NOTE (shortcuts.fileSearch): text describing\n# keyboard shortcut action for source file search\nshortcuts.fileSearch=Source File Search\n\n# LOCALIZATION NOTE (shortcuts.searchAgain): text describing\n# keyboard shortcut action for searching again\nshortcuts.searchAgain=Search Again\n\n# LOCALIZATION NOTE (shortcuts.projectSearch): text describing\n# keyboard shortcut action for full project search\nshortcuts.projectSearch=Full Project Search\n\n# LOCALIZATION NOTE (shortcuts.functionSearch): text describing\n# keyboard shortcut action for function search\nshortcuts.functionSearch=Function Search\n\n# LOCALIZATION NOTE (shortcuts.buttonName): text describing\n# keyboard shortcut button text\nshortcuts.buttonName=Keyboard shortcuts\n"
 
 /***/ }),
 /* 961 */,
 /* 962 */,
 /* 963 */,
 /* 964 */,
 /* 965 */
 /***/ (function(module, exports) {
@@ -21330,16 +21331,17 @@ async function getGeneratedLocation(stat
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.addExpression = addExpression;
+exports.clearExpressionError = clearExpressionError;
 exports.updateExpression = updateExpression;
 exports.deleteExpression = deleteExpression;
 exports.evaluateExpressions = evaluateExpressions;
 exports.getMappedExpression = getMappedExpression;
 
 var _selectors = __webpack_require__(1352);
 
 var _promise = __webpack_require__(1653);
@@ -21368,38 +21370,44 @@ function addExpression(input) {
       return;
     }
 
     const expression = (0, _selectors.getExpression)(getState(), input);
     if (expression) {
       return dispatch(evaluateExpression(expression));
     }
 
-    dispatch({
-      type: "ADD_EXPRESSION",
-      input
-    });
+    const expressionError = await parser.hasSyntaxError(input);
+    dispatch({ type: "ADD_EXPRESSION", input, expressionError });
 
     const newExpression = (0, _selectors.getExpression)(getState(), input);
-    dispatch(evaluateExpression(newExpression));
+    if (newExpression) {
+      return dispatch(evaluateExpression(newExpression));
+    }
   };
 } /* 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/>. */
 
+function clearExpressionError() {
+  return { type: "CLEAR_EXPRESSION_ERROR" };
+}
+
 function updateExpression(input, expression) {
-  return ({ dispatch, getState }) => {
+  return async ({ dispatch, getState }) => {
     if (!input || input == expression.input) {
       return;
     }
 
+    const expressionError = await parser.hasSyntaxError(input);
     dispatch({
       type: "UPDATE_EXPRESSION",
       expression,
-      input: input
+      input: expressionError ? expression.input : input,
+      expressionError
     });
 
     dispatch(evaluateExpressions());
   };
 }
 
 /**
  *
@@ -21435,25 +21443,16 @@ function evaluateExpressions() {
 function evaluateExpression(expression) {
   return async function ({ dispatch, getState, client, sourceMaps }) {
     if (!expression.input) {
       console.warn("Expressions should not be empty");
       return;
     }
 
     let input = expression.input;
-    const error = await parser.hasSyntaxError(input);
-    if (error) {
-      return dispatch({
-        type: "EVALUATE_EXPRESSION",
-        input: expression.input,
-        value: { input: expression.input, result: error }
-      });
-    }
-
     const frame = (0, _selectors.getSelectedFrame)(getState());
 
     if (frame) {
       const { location, generatedLocation } = frame;
       const source = (0, _selectors.getSource)(getState(), location.sourceId);
       const sourceId = source.get("id");
 
       if (!(0, _devtoolsSourceMap.isGeneratedId)(sourceId)) {
@@ -23057,17 +23056,17 @@ async function findScopeByName(source, n
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
-exports.getExpressions = exports.State = undefined;
+exports.getExpressionError = exports.getExpressions = exports.State = undefined;
 exports.getExpression = getExpression;
 
 var _makeRecord = __webpack_require__(1361);
 
 var _makeRecord2 = _interopRequireDefault(_makeRecord);
 
 var _immutable = __webpack_require__(146);
 
@@ -23075,49 +23074,55 @@ var _lodash = __webpack_require__(2);
 
 var _reselect = __webpack_require__(993);
 
 var _prefs = __webpack_require__(226);
 
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 const State = exports.State = (0, _makeRecord2.default)({
-  expressions: (0, _immutable.List)(restoreExpressions())
+  expressions: (0, _immutable.List)(restoreExpressions()),
+  expressionError: false
 }); /* 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/>. */
 
 /**
  * Expressions reducer
  * @module reducers/expressions
  */
 
 function update(state = State(), action) {
   switch (action.type) {
     case "ADD_EXPRESSION":
+      if (action.expressionError) {
+        return state.set("expressionError", !!action.expressionError);
+      }
       return appendToList(state, ["expressions"], {
         input: action.input,
         value: null,
         updating: true
       });
     case "UPDATE_EXPRESSION":
       const key = action.expression.input;
       return updateItemInList(state, ["expressions"], key, {
         input: action.input,
         value: null,
         updating: true
-      });
+      }).set("expressionError", !!action.expressionError);
     case "EVALUATE_EXPRESSION":
       return updateItemInList(state, ["expressions"], action.input, {
         input: action.input,
         value: action.value,
         updating: false
       });
     case "DELETE_EXPRESSION":
       return deleteExpression(state, action.input);
+    case "CLEAR_EXPRESSION_ERROR":
+      return state.set("expressionError", false);
   }
 
   return state;
 }
 
 function restoreExpressions() {
   const exprs = _prefs.prefs.expressions;
   if (exprs.length == 0) {
@@ -23160,16 +23165,18 @@ function deleteExpression(state, input) 
 const getExpressionsWrapper = state => state.expressions;
 
 const getExpressions = exports.getExpressions = (0, _reselect.createSelector)(getExpressionsWrapper, expressions => expressions.get("expressions"));
 
 function getExpression(state, input) {
   return getExpressions(state).find(exp => exp.input == input);
 }
 
+const getExpressionError = exports.getExpressionError = (0, _reselect.createSelector)(getExpressionsWrapper, expressions => expressions.get("expressionError"));
+
 exports.default = update;
 
 /***/ }),
 /* 1418 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
@@ -30388,17 +30395,17 @@ async function paused(_, packet) {
     return;
   }
 
   // Eagerly fetch the frames
   const response = await threadClient.getFrames(0, CALL_STACK_PAGE_SIZE);
 
   if (why.type != "alreadyPaused") {
     const pause = (0, _create.createPause)(packet, response);
-    _sourceQueue2.default.flush();
+    await _sourceQueue2.default.flush();
     actions.paused(pause);
   }
 }
 
 function resumed(_, packet) {
   // NOTE: the client suppresses resumed events while interrupted
   // to prevent unintentional behavior.
   // see [client docs](../README.md#interrupted) for more information.
@@ -31937,23 +31944,23 @@ function willNavigate(_, event) {
   return async function ({ dispatch, getState, client, sourceMaps }) {
     await sourceMaps.clearSourceMaps();
     (0, _wasm.clearWasmStates)();
     (0, _editor.clearDocuments)();
     (0, _parser.clearSymbols)();
     (0, _parser.clearASTs)();
     (0, _parser.clearScopes)();
     (0, _parser.clearSources)();
-    _sourceQueue2.default.clear();
-
     dispatch(navigate(event.url));
   };
 }
 
 function navigate(url) {
+  _sourceQueue2.default.clear();
+
   return {
     type: "NAVIGATE",
     url
   };
 }
 
 function connect(url) {
   return async function ({ dispatch }) {
@@ -32998,23 +33005,17 @@ class TextSearch extends _react.Componen
         getChildren: file => file.matches || [],
         itemHeight: 24,
         autoExpand: 1,
         autoExpandDepth: 1,
         getParent: item => null,
         getPath: getFilePath,
         renderItem: renderItem
       });
-    } else if (status === _projectTextSearch.statusType.fetching) {
-      return _react2.default.createElement(
-        "div",
-        { className: "no-result-msg absolute-center" },
-        "Loading..."
-      );
-    } else if (this.props.query && !results.length) {
+    } else if (this.props.query && !results.length || status === _projectTextSearch.statusType.fetching) {
       return _react2.default.createElement(
         "div",
         { className: "no-result-msg absolute-center" },
         L10N.getStr("projectTextSearch.noResults")
       );
     }
   }
 
@@ -40909,111 +40910,132 @@ Object.defineProperty(exports, "__esModu
 });
 
 var _react = __webpack_require__(0);
 
 var _react2 = _interopRequireDefault(_react);
 
 var _reactRedux = __webpack_require__(1189);
 
-var _redux = __webpack_require__(3);
+var _classnames = __webpack_require__(175);
+
+var _classnames2 = _interopRequireDefault(_classnames);
+
+var _devtoolsReps = __webpack_require__(1408);
 
 var _actions = __webpack_require__(1354);
 
 var _actions2 = _interopRequireDefault(_actions);
 
 var _selectors = __webpack_require__(1352);
 
 var _expressions = __webpack_require__(1437);
 
 var _Close = __webpack_require__(1374);
 
 var _Close2 = _interopRequireDefault(_Close);
 
-var _devtoolsReps = __webpack_require__(1408);
-
 __webpack_require__(1335);
 
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 class Expressions extends _react.PureComponent {
 
-  constructor(...args) {
-    super(...args);
-
-    this.state = {
-      editing: null
-    };
-
+  constructor(props) {
+    super(props);
+
+    this.clear = () => {
+      this.setState(() => {
+        this.props.clearExpressionError();
+        return { editing: false, editIndex: -1, inputValue: "" };
+      });
+    };
+
+    this.handleChange = e => {
+      this.setState({ inputValue: e.target.value });
+    };
+
+    this.handleKeyDown = e => {
+      if (e.key === "Escape") {
+        this.clear();
+      }
+    };
+
+    this.handleExistingSubmit = async (e, expression) => {
+      e.preventDefault();
+      e.stopPropagation();
+      this.props.updateExpression(this.state.inputValue, expression);
+    };
+
+    this.handleNewSubmit = async e => {
+      e.preventDefault();
+      e.stopPropagation();
+      this.props.addExpression(this.state.inputValue);
+      this.setState({ editing: false, editIndex: -1, inputValue: "" });
+    };
+
+    this.state = { editing: false, editIndex: -1, inputValue: "" };
     this.renderExpression = this.renderExpression.bind(this);
   }
 
   componentDidMount() {
     const { expressions, evaluateExpressions } = this.props;
     if (expressions.size > 0) {
       evaluateExpressions();
     }
   }
 
+  componentWillReceiveProps(nextProps) {
+    if (this.state.editing && !nextProps.expressionError) {
+      this.clear();
+    }
+  }
+
   shouldComponentUpdate(nextProps, nextState) {
-    const { editing } = this.state;
-    const { expressions, loadedObjects } = this.props;
-    return expressions !== nextProps.expressions || loadedObjects !== nextProps.loadedObjects || editing !== nextState.editing;
-  }
-
-  editExpression(expression, { depth }) {
+    const { editing, inputValue } = this.state;
+    const { expressions, expressionError, loadedObjects } = this.props;
+    return expressions !== nextProps.expressions || expressionError !== nextProps.expressionError || loadedObjects !== nextProps.loadedObjects || editing !== nextState.editing || inputValue !== nextState.inputValue;
+  }
+
+  componentDidUpdate() {
+    if (this._input) {
+      const input = this._input;
+      input.setSelectionRange(input.value.length + 1, input.value.length + 1);
+      input.focus();
+    }
+  }
+
+  editExpression(expression, index, { depth }) {
     if (depth > 0) {
       return;
     }
-
-    this.setState({ editing: expression.input });
+    this.setState({
+      inputValue: expression.input,
+      editing: true,
+      editIndex: index
+    });
   }
 
   deleteExpression(e, expression) {
     e.stopPropagation();
     const { deleteExpression } = this.props;
     deleteExpression(expression);
   }
 
-  inputKeyPress(e, expression) {
-    if (e.key !== "Enter") {
-      return;
-    }
-
-    const value = e.target.value;
-    if (value == "") {
-      return;
-    }
-
-    this.setState({ editing: null });
-    e.target.value = "";
-    this.props.updateExpression(value, expression);
-  }
-
-  renderExpressionEditInput(expression) {
-    return _react2.default.createElement(
-      "span",
-      { className: "expression-input-container", key: expression.input },
-      _react2.default.createElement("input", {
-        className: "input-expression",
-        type: "text",
-        onKeyPress: e => this.inputKeyPress(e, expression),
-        onBlur: () => this.setState({ editing: null }),
-        defaultValue: expression.input,
-        ref: c => this._input = c
-      })
-    );
-  }
-
-  renderExpression(expression) {
-    const { loadObjectProperties, loadedObjects, openLink } = this.props;
-    const { editing } = this.state;
+  renderExpression(expression, index) {
+    const {
+      expressionError,
+      loadObjectProperties,
+      loadedObjects,
+      openLink
+    } = this.props;
+    const { editing, editIndex } = this.state;
     const { input, updating } = expression;
-
-    if (editing == input) {
+    const isEditingExpr = editing && editIndex === index;
+    if (isEditingExpr || isEditingExpr && expressionError) {
       return this.renderExpressionEditInput(expression);
     }
 
     if (updating) {
       return;
     }
 
     const { value } = (0, _expressions.getValue)(expression);
@@ -41030,17 +41052,17 @@ class Expressions extends _react.PureCom
       _react2.default.createElement(
         "div",
         { className: "expression-content" },
         _react2.default.createElement(_devtoolsReps.ObjectInspector, {
           roots: [root],
           autoExpandDepth: 0,
           disableWrap: true,
           disabledFocus: true,
-          onDoubleClick: (items, options) => this.editExpression(expression, options),
+          onDoubleClick: (items, options) => this.editExpression(expression, index, options),
           openLink: openLink,
           getObjectProperties: id => loadedObjects[id],
           loadObjectProperties: loadObjectProperties
           // TODO: See https://github.com/devtools-html/debugger.html/issues/3555.
           , getObjectEntries: actor => {},
           loadObjectEntries: grip => {}
         }),
         _react2.default.createElement(
@@ -41049,48 +41071,65 @@ class Expressions extends _react.PureCom
           _react2.default.createElement(_Close2.default, {
             handleClick: e => this.deleteExpression(e, expression)
           })
         )
       )
     );
   }
 
-  componentDidUpdate() {
-    if (this._input) {
-      this._input.focus();
-    }
-  }
-
   renderNewExpressionInput() {
-    const onKeyPress = e => {
-      if (e.key !== "Enter") {
-        return;
-      }
-
-      const value = e.target.value;
-      if (value == "") {
-        return;
-      }
-
-      e.stopPropagation();
-      e.target.value = "";
-      this.props.addExpression(value);
-    };
-
+    const { expressionError } = this.props;
+    const { editing, inputValue } = this.state;
+    const error = editing === false && expressionError === true;
+    const placeholder = error ? L10N.getStr("expressions.errorMsg") : L10N.getStr("expressions.placeholder");
     return _react2.default.createElement(
       "li",
       { className: "expression-input-container" },
-      _react2.default.createElement("input", {
-        className: "input-expression",
-        type: "text",
-        placeholder: L10N.getStr("expressions.placeholder"),
-        onBlur: e => e.target.value = "",
-        onKeyPress: onKeyPress
-      })
+      _react2.default.createElement(
+        "form",
+        { className: "expression-input-form", onSubmit: this.handleNewSubmit },
+        _react2.default.createElement("input", {
+          className: (0, _classnames2.default)("input-expression", { error }),
+          type: "text",
+          placeholder: placeholder,
+          onChange: this.handleChange,
+          onBlur: this.clear,
+          onKeyDown: this.handleKeyDown,
+          value: !editing ? inputValue : ""
+        }),
+        _react2.default.createElement("input", { type: "submit", style: { display: "none" } })
+      )
+    );
+  }
+
+  renderExpressionEditInput(expression) {
+    const { expressionError } = this.props;
+    const { inputValue, editing } = this.state;
+    const error = editing === true && expressionError === true;
+    return _react2.default.createElement(
+      "span",
+      { className: "expression-input-container", key: expression.input },
+      _react2.default.createElement(
+        "form",
+        {
+          className: "expression-input-form",
+          onSubmit: e => this.handleExistingSubmit(e, expression)
+        },
+        _react2.default.createElement("input", {
+          className: (0, _classnames2.default)("input-expression", { error }),
+          type: "text",
+          onChange: this.handleChange,
+          onBlur: this.clear,
+          onKeyDown: this.handleKeyDown,
+          value: editing ? inputValue : expression.input,
+          ref: c => this._input = c
+        }),
+        _react2.default.createElement("input", { type: "submit", style: { display: "none" } })
+      )
     );
   }
 
   render() {
     const { expressions } = this.props;
     return _react2.default.createElement(
       "ul",
       { className: "pane expressions-list" },
@@ -41099,18 +41138,19 @@ class Expressions extends _react.PureCom
     );
   }
 } /* 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/>. */
 
 exports.default = (0, _reactRedux.connect)(state => ({
   expressions: (0, _selectors.getExpressions)(state),
+  expressionError: (0, _selectors.getExpressionError)(state),
   loadedObjects: (0, _selectors.getLoadedObjects)(state)
-}), dispatch => (0, _redux.bindActionCreators)(_actions2.default, dispatch))(Expressions);
+}), _actions2.default)(Expressions);
 
 /***/ }),
 /* 1602 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
@@ -48666,28 +48706,27 @@ function getScope(scope, selectedFrame, 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 
 var _lodash = __webpack_require__(2);
 
 let newSources;
 let createSource;
+let supportsWasm = false;
 let queuedSources;
-let supportsWasm = false;
-
-const queue = (0, _lodash.throttle)(() => {
-  if (!newSources || !createSource) {
-    return;
-  }
-  newSources(queuedSources.map(source => {
-    return createSource(source, { supportsWasm });
-  }));
+
+async function dispatchNewSources() {
+  const sources = queuedSources;
   queuedSources = [];
-}, 100);
+
+  await newSources(sources.map(source => createSource(source, { supportsWasm })));
+}
+
+const queue = (0, _lodash.throttle)(dispatchNewSources, 100);
 
 exports.default = {
   initialize: options => {
     newSources = options.actions.newSources;
     createSource = options.createSource;
     supportsWasm = options.supportsWasm;
     queuedSources = [];
   },
@@ -49700,35 +49739,35 @@ Object.defineProperty(exports, "__esModu
   value: true
 });
 exports.createEditor = createEditor;
 
 var _sourceEditor = __webpack_require__(197);
 
 var _sourceEditor2 = _interopRequireDefault(_sourceEditor);
 
-var _devtoolsConfig = __webpack_require__(1355);
+var _prefs = __webpack_require__(226);
 
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 /* 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/>. */
 
 function createEditor() {
   const gutters = ["breakpoints", "hit-markers", "CodeMirror-linenumbers"];
 
-  if ((0, _devtoolsConfig.isEnabled)("codeFolding")) {
+  if (_prefs.features.codeFolding) {
     gutters.push("CodeMirror-foldgutter");
   }
 
   return new _sourceEditor2.default({
     mode: "javascript",
-    foldGutter: (0, _devtoolsConfig.isEnabled)("codeFolding"),
-    enableCodeFolding: (0, _devtoolsConfig.isEnabled)("codeFolding"),
+    foldGutter: _prefs.features.codeFolding,
+    enableCodeFolding: _prefs.features.codeFolding,
     readOnly: true,
     lineNumbers: true,
     theme: "mozilla",
     styleActiveLine: false,
     lineWrapping: false,
     matchBrackets: true,
     showAnnotationRuler: true,
     gutters,
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps-reloading.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps-reloading.js
@@ -22,24 +22,28 @@ add_task(async function() {
   // should not move anywhere.
   await addBreakpoint(dbg, entrySrc, 13);
   is(getBreakpoints(getState()).size, 1, "One breakpoint exists");
   ok(
     getBreakpoint(getState(), { sourceId: entrySrc.id, line: 13 }),
     "Breakpoint has correct line"
   );
 
+  await addBreakpoint(dbg, entrySrc, 5);
   await addBreakpoint(dbg, entrySrc, 15);
   await disableBreakpoint(dbg, entrySrc, 15);
 
   // Test reloading the debugger
   await reload(dbg, "opts.js");
   await waitForDispatch(dbg, "LOAD_SOURCE_TEXT");
 
-  is(getBreakpoints(getState()).size, 2, "One breakpoint exists");
+  await waitForPaused(dbg);
+  assertPausedLocation(dbg);
+
+  is(getBreakpoints(getState()).size, 3, "Three breakpoints exist");
 
   ok(
     getBreakpoint(getState(), { sourceId: entrySrc.id, line: 13 }),
     "Breakpoint has correct line"
   );
 
   ok(
     getBreakpoint(getState(), {
--- a/devtools/client/framework/toolbox.js
+++ b/devtools/client/framework/toolbox.js
@@ -174,16 +174,30 @@ function Toolbox(target, selectedTool, h
 
   this.on("ready", this._showDevEditionPromo);
 
   gDevTools.on("tool-registered", this._toolRegistered);
   gDevTools.on("tool-unregistered", this._toolUnregistered);
 
   this.on("picker-started", this._onPickerStarted);
   this.on("picker-stopped", this._onPickerStopped);
+
+  /**
+   * Get text direction for the current locale direction.
+   *
+   * `getComputedStyle` forces a synchronous reflow, so use a lazy getter in order to
+   * call it only once.
+   */
+  loader.lazyGetter(this, "direction", () => {
+    // Get the direction from browser.xul document
+    let top = this.win.top;
+    let topDocEl = top.document.documentElement;
+    let isRtl = top.getComputedStyle(topDocEl).direction === "rtl";
+    return isRtl ? "rtl" : "ltr";
+  });
 }
 exports.Toolbox = Toolbox;
 
 /**
  * The toolbox can be 'hosted' either embedded in a browser window
  * or in a separate window.
  */
 Toolbox.HostType = {
@@ -1735,20 +1749,17 @@ Toolbox.prototype = {
     if (!docEl || docEl.namespaceURI !== HTML_NS) {
       // Bail out if the content window or document is not ready or if the document is not
       // HTML.
       return;
     }
 
     if (docEl.hasAttribute("dir")) {
       // Set the dir attribute value only if dir is already present on the document.
-      let top = this.win.top;
-      let topDocEl = top.document.documentElement;
-      let isRtl = top.getComputedStyle(topDocEl).direction === "rtl";
-      docEl.setAttribute("dir", isRtl ? "rtl" : "ltr");
+      docEl.setAttribute("dir", this.direction);
     }
   },
 
   /**
    * Mark all in collection as unselected; and id as selected
    * @param {string} collection
    *        DOM collection of items
    * @param {string} id
--- a/devtools/client/inspector/breadcrumbs.js
+++ b/devtools/client/inspector/breadcrumbs.js
@@ -68,17 +68,17 @@ ArrowScrollBox.prototype = {
     this.inner.addEventListener("underflow", this.onUnderflow);
     this.inner.addEventListener("overflow", this.onOverflow);
   },
 
   /**
    * Determine whether the current text directionality is RTL
    */
   isRtl: function () {
-    return this.win.getComputedStyle(this.container).direction === "rtl";
+    return this.doc.dir === "rtl";
   },
 
   /**
    * Scroll to the specified element using the current scroll behavior
    * @param {Element} element element to scroll
    * @param {String} block desired alignment of element after scrolling
    */
   scrollToElement: function (element, block) {
--- a/devtools/client/inspector/markup/test/browser_markup_anonymous_03.js
+++ b/devtools/client/inspector/markup/test/browser_markup_anonymous_03.js
@@ -5,17 +5,17 @@
 "use strict";
 
 // Test shadow DOM content in the markupview.
 // Note that many features are not yet enabled, but basic listing
 // of elements should be working.
 const TEST_URL = URL_ROOT + "doc_markup_anonymous.html";
 
 add_task(function* () {
-  Services.prefs.setBoolPref("dom.webcomponents.enabled", true);
+  Services.prefs.setBoolPref("dom.webcomponents.shadowdom.enabled", true);
 
   let {inspector} = yield openInspectorForURL(TEST_URL);
 
   let shadow = yield getNodeFront("#shadow", inspector.markup);
   let children = yield inspector.walker.children(shadow);
 
   is(shadow.numChildren, 3, "Children of the shadow root are counted");
   is(children.nodes.length, 3, "Children returned from walker");
--- a/devtools/client/inspector/markup/test/head.js
+++ b/devtools/client/inspector/markup/test/head.js
@@ -30,17 +30,17 @@ registerCleanupFunction(() => {
 // Services.prefs.setBoolPref("devtools.dump.emit", true);
 
 // Clear preferences that may be set during the course of tests.
 registerCleanupFunction(() => {
   Services.prefs.clearUserPref("devtools.dump.emit");
   Services.prefs.clearUserPref("devtools.inspector.htmlPanelOpen");
   Services.prefs.clearUserPref("devtools.inspector.sidebarOpen");
   Services.prefs.clearUserPref("devtools.markup.pagesize");
-  Services.prefs.clearUserPref("dom.webcomponents.enabled");
+  Services.prefs.clearUserPref("dom.webcomponents.shadowdom.enabled");
   Services.prefs.clearUserPref("devtools.inspector.showAllAnonymousContent");
 });
 
 /**
  * Some tests may need to import one or more of the test helper scripts.
  * A test helper script is simply a js file that contains common test code that
  * is either not common-enough to be in head.js, or that is located in a
  * separate directory.
--- a/devtools/client/locales/en-US/debugger.properties
+++ b/devtools/client/locales/en-US/debugger.properties
@@ -434,16 +434,19 @@ framework.enableGrouping.accesskey=u
 generated=generated
 
 # LOCALIZATION NOTE (original): Source Map term for a debugger UI source location
 original=original
 
 # LOCALIZATION NOTE (expressions.placeholder): Placeholder text for expression
 # input element
 expressions.placeholder=Add watch expression
+# LOCALIZATION NOTE (expressions.errorMsg): Error text for expression
+# input element
+expressions.errorMsg=Invalid expression…
 expressions.label=Add watch expression
 expressions.accesskey=e
 
 # LOCALIZATION NOTE (sourceTabs.closeTab): Editor source tab context menu item
 # for closing the selected tab below the mouse.
 sourceTabs.closeTab=Close tab
 sourceTabs.closeTab.accesskey=c
 
--- a/devtools/client/netmonitor/src/components/RequestListColumnWaterfall.js
+++ b/devtools/client/netmonitor/src/components/RequestListColumnWaterfall.js
@@ -2,130 +2,148 @@
  * 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 { Component } = require("devtools/client/shared/vendor/react");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+
 const { L10N } = require("../utils/l10n");
-const { propertiesEqual } = require("../utils/request-utils");
+const {
+  fetchNetworkUpdatePacket,
+  propertiesEqual,
+} = require("../utils/request-utils");
 
 const { div } = dom;
 
 const UPDATED_WATERFALL_PROPS = [
   "eventTimings",
   "fromCache",
   "fromServiceWorker",
   "totalTime",
 ];
 // List of properties of the timing info we want to create boxes for
 const TIMING_KEYS = ["blocked", "dns", "connect", "ssl", "send", "wait", "receive"];
 
 class RequestListColumnWaterfall extends Component {
   static get propTypes() {
     return {
+      connector: PropTypes.object.isRequired,
       firstRequestStartedMillis: PropTypes.number.isRequired,
       item: PropTypes.object.isRequired,
       onWaterfallMouseDown: PropTypes.func.isRequired,
     };
   }
 
+  componentDidMount() {
+    let { connector, item } = this.props;
+    fetchNetworkUpdatePacket(connector.requestData, item, ["eventTimings"]);
+  }
+
+  componentWillReceiveProps(nextProps) {
+    let { connector, item } = nextProps;
+    fetchNetworkUpdatePacket(connector.requestData, item, ["eventTimings"]);
+  }
+
   shouldComponentUpdate(nextProps) {
     return !propertiesEqual(UPDATED_WATERFALL_PROPS, this.props.item, nextProps.item) ||
       this.props.firstRequestStartedMillis !== nextProps.firstRequestStartedMillis;
   }
 
+  timingTooltip() {
+    let { eventTimings, fromCache, fromServiceWorker, totalTime } = this.props.item;
+    let tooltip = [];
+
+    if (fromCache || fromServiceWorker) {
+      return tooltip;
+    }
+
+    if (eventTimings) {
+      for (let key of TIMING_KEYS) {
+        let width = eventTimings.timings[key];
+
+        if (width > 0) {
+          tooltip.push(L10N.getFormatStr("netmonitor.waterfall.tooltip." + key, width));
+        }
+      }
+    }
+
+    if (typeof totalTime === "number") {
+      tooltip.push(L10N.getFormatStr("netmonitor.waterfall.tooltip.total", totalTime));
+    }
+
+    return tooltip.join(L10N.getStr("netmonitor.waterfall.tooltip.separator"));
+  }
+
+  timingBoxes() {
+    let { eventTimings, fromCache, fromServiceWorker, totalTime } = this.props.item;
+    let boxes = [];
+
+    if (fromCache || fromServiceWorker) {
+      return boxes;
+    }
+
+    if (eventTimings) {
+      // Add a set of boxes representing timing information.
+      for (let key of TIMING_KEYS) {
+        let width = eventTimings.timings[key];
+
+        // Don't render anything if it surely won't be visible.
+        // One millisecond == one unscaled pixel.
+        if (width > 0) {
+          boxes.push(
+            div({
+              key,
+              className: `requests-list-timings-box ${key}`,
+              style: { width },
+            })
+          );
+        }
+      }
+    }
+
+    if (typeof totalTime === "number") {
+      let title = L10N.getFormatStr("networkMenu.totalMS", totalTime);
+      boxes.push(
+        div({
+          key: "total",
+          className: "requests-list-timings-total",
+          title,
+        }, title)
+      );
+    }
+
+    return boxes;
+  }
+
   render() {
-    let { firstRequestStartedMillis, item, onWaterfallMouseDown } = this.props;
-    const boxes = timingBoxes(item);
+    let {
+      firstRequestStartedMillis,
+      item,
+      onWaterfallMouseDown,
+    } = this.props;
 
     return (
       div({
         className: "requests-list-column requests-list-waterfall",
-        onMouseOver: function ({target}) {
+        onMouseOver: ({ target }) => {
           if (!target.title) {
-            target.title = timingTooltip(item);
+            target.title = this.timingTooltip();
           }
         }
       },
         div({
           className: "requests-list-timings",
           style: {
             paddingInlineStart: `${item.startedMillis - firstRequestStartedMillis}px`,
           },
           onMouseDown: onWaterfallMouseDown,
         },
-          boxes,
+          this.timingBoxes(),
         )
       )
     );
   }
 }
 
-function timingTooltip(item) {
-  let { eventTimings, fromCache, fromServiceWorker, totalTime } = item;
-  let tooltip = [];
-
-  if (fromCache || fromServiceWorker) {
-    return tooltip;
-  }
-
-  if (eventTimings) {
-    for (let key of TIMING_KEYS) {
-      let width = eventTimings.timings[key];
-
-      if (width > 0) {
-        tooltip.push(L10N.getFormatStr("netmonitor.waterfall.tooltip." + key, width));
-      }
-    }
-  }
-
-  if (typeof totalTime === "number") {
-    tooltip.push(L10N.getFormatStr("netmonitor.waterfall.tooltip.total", totalTime));
-  }
-
-  return tooltip.join(L10N.getStr("netmonitor.waterfall.tooltip.separator"));
-}
-
-function timingBoxes(item) {
-  let { eventTimings, fromCache, fromServiceWorker, totalTime } = item;
-  let boxes = [];
-
-  if (fromCache || fromServiceWorker) {
-    return boxes;
-  }
-
-  if (eventTimings) {
-    // Add a set of boxes representing timing information.
-    for (let key of TIMING_KEYS) {
-      let width = eventTimings.timings[key];
-
-      // Don't render anything if it surely won't be visible.
-      // One millisecond == one unscaled pixel.
-      if (width > 0) {
-        boxes.push(
-          div({
-            key,
-            className: `requests-list-timings-box ${key}`,
-            style: { width },
-          })
-        );
-      }
-    }
-  }
-
-  if (typeof totalTime === "number") {
-    let title = L10N.getFormatStr("networkMenu.totalMS", totalTime);
-    boxes.push(
-      div({
-        key: "total",
-        className: "requests-list-timings-total",
-        title,
-      }, title)
-    );
-  }
-
-  return boxes;
-}
-
 module.exports = RequestListColumnWaterfall;
--- a/devtools/client/netmonitor/src/components/RequestListHeader.js
+++ b/devtools/client/netmonitor/src/components/RequestListHeader.js
@@ -39,16 +39,18 @@ class RequestListHeader extends Componen
     };
   }
 
   constructor(props) {
     super(props);
     this.onContextMenu = this.onContextMenu.bind(this);
     this.drawBackground = this.drawBackground.bind(this);
     this.resizeWaterfall = this.resizeWaterfall.bind(this);
+    this.waterfallDivisionLabels = this.waterfallDivisionLabels.bind(this);
+    this.waterfallLabel = this.waterfallLabel.bind(this);
   }
 
   componentWillMount() {
     const { resetColumns, toggleColumn } = this.props;
     this.contextMenu = new RequestListHeaderContextMenu({
       resetColumns,
       toggleColumn,
     });
@@ -93,16 +95,79 @@ class RequestListHeader extends Componen
       // Measure its width and update the 'waterfallWidth' property in the store.
       // The 'waterfallWidth' will be further updated on every window resize.
       window.cancelIdleCallback(this._resizeTimerId);
       this._resizeTimerId = window.requestIdleCallback(() =>
         this.props.resizeWaterfall(waterfallHeader.getBoundingClientRect().width));
     }
   }
 
+  /**
+   * Build the waterfall header - timing tick marks with the right spacing
+   */
+  waterfallDivisionLabels(waterfallWidth, scale) {
+    let labels = [];
+
+    // Build new millisecond tick labels...
+    let timingStep = REQUESTS_WATERFALL.HEADER_TICKS_MULTIPLE;
+    let scaledStep = scale * timingStep;
+
+    // Ignore any divisions that would end up being too close to each other.
+    while (scaledStep < REQUESTS_WATERFALL.HEADER_TICKS_SPACING_MIN) {
+      scaledStep *= 2;
+    }
+
+    // Insert one label for each division on the current scale.
+    for (let x = 0; x < waterfallWidth; x += scaledStep) {
+      let millisecondTime = x / scale;
+      let divisionScale = "millisecond";
+
+      // If the division is greater than 1 minute.
+      if (millisecondTime > 60000) {
+        divisionScale = "minute";
+      } else if (millisecondTime > 1000) {
+        // If the division is greater than 1 second.
+        divisionScale = "second";
+      }
+
+      let width = (x + scaledStep | 0) - (x | 0);
+      // Adjust the first marker for the borders
+      if (x == 0) {
+        width -= 2;
+      }
+      // Last marker doesn't need a width specified at all
+      if (x + scaledStep >= waterfallWidth) {
+        width = undefined;
+      }
+
+      labels.push(div(
+        {
+          key: labels.length,
+          className: "requests-list-timings-division",
+          "data-division-scale": divisionScale,
+          style: { width }
+        },
+        getFormattedTime(millisecondTime)
+      ));
+    }
+
+    return labels;
+  }
+
+  waterfallLabel(waterfallWidth, scale, label) {
+    let className = "button-text requests-list-waterfall-label-wrapper";
+
+    if (waterfallWidth !== null && scale !== null) {
+      label = this.waterfallDivisionLabels(waterfallWidth, scale);
+      className += " requests-list-waterfall-visible";
+    }
+
+    return div({ className }, label);
+  }
+
   render() {
     let { columns, scale, sort, sortBy, waterfallWidth } = this.props;
 
     return (
       div({ className: "devtools-toolbar requests-list-headers-wrapper" },
         div({
           className: "devtools-toolbar requests-list-headers",
           onContextMenu: this.onContextMenu
@@ -134,92 +199,29 @@ class RequestListHeader extends Componen
                 button({
                   id: `requests-list-${name}-button`,
                   className: `requests-list-header-button`,
                   "data-sorted": sorted,
                   title: sortedTitle ? `${label} (${sortedTitle})` : label,
                   onClick: () => sortBy(name),
                 },
                   name === "waterfall"
-                    ? WaterfallLabel(waterfallWidth, scale, label)
+                    ? this.waterfallLabel(waterfallWidth, scale, label)
                     : div({ className: "button-text" }, label),
                   div({ className: "button-icon" })
                 )
               )
             );
           })
         )
       )
     );
   }
 }
 
-/**
- * Build the waterfall header - timing tick marks with the right spacing
- */
-function waterfallDivisionLabels(waterfallWidth, scale) {
-  let labels = [];
-
-  // Build new millisecond tick labels...
-  let timingStep = REQUESTS_WATERFALL.HEADER_TICKS_MULTIPLE;
-  let scaledStep = scale * timingStep;
-
-  // Ignore any divisions that would end up being too close to each other.
-  while (scaledStep < REQUESTS_WATERFALL.HEADER_TICKS_SPACING_MIN) {
-    scaledStep *= 2;
-  }
-
-  // Insert one label for each division on the current scale.
-  for (let x = 0; x < waterfallWidth; x += scaledStep) {
-    let millisecondTime = x / scale;
-    let divisionScale = "millisecond";
-
-    // If the division is greater than 1 minute.
-    if (millisecondTime > 60000) {
-      divisionScale = "minute";
-    } else if (millisecondTime > 1000) {
-      // If the division is greater than 1 second.
-      divisionScale = "second";
-    }
-
-    let width = (x + scaledStep | 0) - (x | 0);
-    // Adjust the first marker for the borders
-    if (x == 0) {
-      width -= 2;
-    }
-    // Last marker doesn't need a width specified at all
-    if (x + scaledStep >= waterfallWidth) {
-      width = undefined;
-    }
-
-    labels.push(div(
-      {
-        key: labels.length,
-        className: "requests-list-timings-division",
-        "data-division-scale": divisionScale,
-        style: { width }
-      },
-      getFormattedTime(millisecondTime)
-    ));
-  }
-
-  return labels;
-}
-
-function WaterfallLabel(waterfallWidth, scale, label) {
-  let className = "button-text requests-list-waterfall-label-wrapper";
-
-  if (waterfallWidth !== null && scale !== null) {
-    label = waterfallDivisionLabels(waterfallWidth, scale);
-    className += " requests-list-waterfall-visible";
-  }
-
-  return div({ className }, label);
-}
-
 module.exports = connect(
   (state) => ({
     columns: state.ui.columns,
     firstRequestStartedMillis: state.requests.firstStartedMillis,
     scale: getWaterfallScale(state),
     sort: state.sort,
     timingMarkers: state.timingMarkers,
     waterfallWidth: state.ui.waterfallWidth,
--- a/devtools/client/netmonitor/src/components/RequestListItem.js
+++ b/devtools/client/netmonitor/src/components/RequestListItem.js
@@ -249,17 +249,20 @@ class RequestListItem extends Component 
           RequestListColumnEndTime({ item, firstRequestStartedMillis }),
         columns.responseTime &&
           RequestListColumnResponseTime({ item, firstRequestStartedMillis }),
         columns.duration && RequestListColumnDuration({ item }),
         columns.latency && RequestListColumnLatency({ item }),
         ...RESPONSE_HEADERS.filter(header => columns[header]).map(
           header => RequestListColumnResponseHeader({ item, header }),
         ),
-        columns.waterfall &&
-          RequestListColumnWaterfall({ item, firstRequestStartedMillis,
-                                       onWaterfallMouseDown }),
+        columns.waterfall && RequestListColumnWaterfall({
+          connector,
+          firstRequestStartedMillis,
+          item,
+          onWaterfallMouseDown,
+        }),
       )
     );
   }
 }
 
 module.exports = RequestListItem;
--- a/devtools/client/netmonitor/src/components/StatisticsPanel.js
+++ b/devtools/client/netmonitor/src/components/StatisticsPanel.js
@@ -62,24 +62,30 @@ class StatisticsPanel extends Component 
 
   componentWillMount() {
     this.mdnLinkContainerNodes = new Map();
   }
 
   componentDidMount() {
     let { requests, connector } = this.props;
     requests.forEach((request) => {
-      fetchNetworkUpdatePacket(connector.requestData, request, ["responseHeaders"]);
+      fetchNetworkUpdatePacket(connector.requestData, request, [
+        "eventTimings",
+        "responseHeaders",
+      ]);
     });
   }
 
   componentWillReceiveProps(nextProps) {
     let { requests, connector } = nextProps;
     requests.forEach((request) => {
-      fetchNetworkUpdatePacket(connector.requestData, request, ["responseHeaders"]);
+      fetchNetworkUpdatePacket(connector.requestData, request, [
+        "eventTimings",
+        "responseHeaders",
+      ]);
     });
   }
 
   componentDidUpdate(prevProps) {
     MediaQueryList.addListener(this.onLayoutChange);
 
     const { requests } = this.props;
     let ready = requests && requests.length && requests.every((req) =>
--- a/devtools/client/netmonitor/src/components/TabboxPanel.js
+++ b/devtools/client/netmonitor/src/components/TabboxPanel.js
@@ -85,17 +85,20 @@ function TabboxPanel({
         title: RESPONSE_TITLE,
       },
         ResponsePanel({ request, openLink, connector }),
       ),
       TabPanel({
         id: PANELS.TIMINGS,
         title: TIMINGS_TITLE,
       },
-        TimingsPanel({ request }),
+        TimingsPanel({
+          connector,
+          request,
+        }),
       ),
       request.cause && request.cause.stacktraceAvailable &&
       TabPanel({
         id: PANELS.STACK_TRACE,
         title: STACK_TRACE_TITLE,
       },
         StackTracePanel({ connector, openLink, request, sourceMapService }),
       ),
--- a/devtools/client/netmonitor/src/components/TimingsPanel.js
+++ b/devtools/client/netmonitor/src/components/TimingsPanel.js
@@ -1,80 +1,96 @@
 /* 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 { Component } = require("devtools/client/shared/vendor/react");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const { L10N } = require("../utils/l10n");
 const { getNetMonitorTimingsURL } = require("../utils/mdn-utils");
+const { fetchNetworkUpdatePacket } = require("../utils/request-utils");
 
 // Components
 const MDNLink = require("./MdnLink");
 
 const { div, span } = dom;
 const types = ["blocked", "dns", "connect", "ssl", "send", "wait", "receive"];
 const TIMINGS_END_PADDING = "80px";
 
 /*
  * Timings panel component
  * Display timeline bars that shows the total wait time for various stages
  */
-function TimingsPanel({ request }) {
-  if (!request.eventTimings) {
-    return null;
+class TimingsPanel extends Component {
+  static get propTypes() {
+    return {
+      connector: PropTypes.object.isRequired,
+      request: PropTypes.object.isRequired,
+    };
+  }
+
+  componentDidMount() {
+    let { connector, request } = this.props;
+    fetchNetworkUpdatePacket(connector.requestData, request, ["eventTimings"]);
+  }
+
+  componentWillReceiveProps(nextProps) {
+    let { connector, request } = nextProps;
+    fetchNetworkUpdatePacket(connector.requestData, request, ["eventTimings"]);
   }
 
-  const { timings, totalTime, offsets } = request.eventTimings;
-  const timelines = types.map((type, idx) => {
-    // Determine the relative offset for each timings box. For example, the
-    // offset of third timings box will be 0 + blocked offset + dns offset
+  render() {
+    const { eventTimings } = this.props.request;
+    if (!eventTimings) {
+      return null;
+    }
 
-    const offsetScale = offsets[type] / totalTime || 0;
-    const timelineScale = timings[type] / totalTime || 0;
+    const { timings, totalTime, offsets } = eventTimings;
+    const timelines = types.map((type, idx) => {
+      // Determine the relative offset for each timings box. For example, the
+      // offset of third timings box will be 0 + blocked offset + dns offset
+
+      const offsetScale = offsets[type] / totalTime || 0;
+      const timelineScale = timings[type] / totalTime || 0;
 
-    return div({
-      key: type,
-      id: `timings-summary-${type}`,
-      className: "tabpanel-summary-container timings-container",
-    },
-      span({ className: "tabpanel-summary-label timings-label" },
-        L10N.getStr(`netmonitor.timings.${type}`)
-      ),
-      div({ className: "requests-list-timings-container" },
-        span({
-          className: "requests-list-timings-offset",
-          style: {
-            width: `calc(${offsetScale} * (100% - ${TIMINGS_END_PADDING})`,
-          },
+      return div({
+        key: type,
+        id: `timings-summary-${type}`,
+        className: "tabpanel-summary-container timings-container",
+      },
+        span({ className: "tabpanel-summary-label timings-label" },
+          L10N.getStr(`netmonitor.timings.${type}`)
+        ),
+        div({ className: "requests-list-timings-container" },
+          span({
+            className: "requests-list-timings-offset",
+            style: {
+              width: `calc(${offsetScale} * (100% - ${TIMINGS_END_PADDING})`,
+            },
+          }),
+          span({
+            className: `requests-list-timings-box ${type}`,
+            style: {
+              width: `calc(${timelineScale} * (100% - ${TIMINGS_END_PADDING}))`,
+            },
+          }),
+          span({ className: "requests-list-timings-total" },
+            L10N.getFormatStr("networkMenu.totalMS", timings[type])
+          )
+        ),
+      );
+    });
+
+    return (
+      div({ className: "panel-container" },
+        timelines,
+        MDNLink({
+          url: getNetMonitorTimingsURL(),
         }),
-        span({
-          className: `requests-list-timings-box ${type}`,
-          style: {
-            width: `calc(${timelineScale} * (100% - ${TIMINGS_END_PADDING}))`,
-          },
-        }),
-        span({ className: "requests-list-timings-total" },
-          L10N.getFormatStr("networkMenu.totalMS", timings[type])
-        )
-      ),
+      )
     );
-  });
-
-  return (
-    div({ className: "panel-container" },
-      timelines,
-      MDNLink({
-        url: getNetMonitorTimingsURL(),
-      }),
-    )
-  );
+  }
 }
 
-TimingsPanel.displayName = "TimingsPanel";
-
-TimingsPanel.propTypes = {
-  request: PropTypes.object.isRequired,
-};
-
 module.exports = TimingsPanel;
--- a/devtools/client/netmonitor/src/connector/firefox-data-provider.js
+++ b/devtools/client/netmonitor/src/connector/firefox-data-provider.js
@@ -308,17 +308,17 @@ class FirefoxDataProvider {
 
   /**
    * The "networkEventUpdate" message type handler.
    *
    * @param {string} type message type
    * @param {object} packet the message received from the server.
    * @param {object} networkInfo the network request information.
    */
-  async onNetworkEventUpdate(type, data) {
+  onNetworkEventUpdate(type, data) {
     let { packet, networkInfo } = data;
     let { actor } = networkInfo;
     let { updateType } = packet;
 
     switch (updateType) {
       case "securityInfo":
         this.pushRequestToQueue(actor, { securityState: networkInfo.securityInfo });
         break;
@@ -340,20 +340,19 @@ class FirefoxDataProvider {
           mimeType: networkInfo.response.content.mimeType,
         });
         break;
       case "eventTimings":
         // Total time doesn't have to be always set e.g. net provider enhancer
         // in Console panel is using this method to fetch data when network log
         // is expanded. So, make sure to not push undefined into the payload queue
         // (it could overwrite an existing value).
-        if (typeof networkInfo.totalTime != "undefined") {
+        if (typeof networkInfo.totalTime !== "undefined") {
           this.pushRequestToQueue(actor, { totalTime: networkInfo.totalTime });
         }
-        await this._requestData(actor, updateType);
         break;
     }
 
     // This available field helps knowing when/if updateType property is arrived
     // and can be requested via `requestData`
     this.pushRequestToQueue(actor, { [`${updateType}Available`]: true });
 
     this.onPayloadDataReceived(actor);
--- a/devtools/client/netmonitor/src/constants.js
+++ b/devtools/client/netmonitor/src/constants.js
@@ -114,16 +114,17 @@ const UPDATE_PROPS = [
   "securityState",
   "securityInfo",
   "securityInfoAvailable",
   "mimeType",
   "contentSize",
   "transferredSize",
   "totalTime",
   "eventTimings",
+  "eventTimingsAvailable",
   "headersSize",
   "customQueryValue",
   "requestHeaders",
   "requestHeadersAvailable",
   "requestHeadersFromUploadStream",
   "requestCookies",
   "requestCookiesAvailable",
   "requestPostData",
--- a/devtools/client/netmonitor/src/har/har-builder.js
+++ b/devtools/client/netmonitor/src/har/har-builder.js
@@ -115,20 +115,25 @@ HarBuilder.prototype = {
   buildEntry: async function (log, file) {
     let page = this.getPage(log, file);
 
     let entry = {};
     entry.pageref = page.id;
     entry.startedDateTime = dateToJSON(new Date(file.startedMillis));
     entry.time = file.endedMillis - file.startedMillis;
 
+    let eventTimings = file.eventTimings;
+    if (!eventTimings && this._options.requestData) {
+      eventTimings = await this._options.requestData(file.id, "eventTimings");
+    }
+
     entry.request = await this.buildRequest(file);
     entry.response = await this.buildResponse(file);
     entry.cache = this.buildCache(file);
-    entry.timings = file.eventTimings ? file.eventTimings.timings : {};
+    entry.timings = eventTimings ? eventTimings.timings : {};
 
     if (file.remoteAddress) {
       entry.serverIPAddress = file.remoteAddress;
     }
 
     if (file.remotePort) {
       entry.connection = file.remotePort + "";
     }
--- a/devtools/client/netmonitor/src/selectors/ui.js
+++ b/devtools/client/netmonitor/src/selectors/ui.js
@@ -1,34 +1,38 @@
 /* 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 { createSelector } = require("devtools/client/shared/vendor/reselect");
 const { REQUESTS_WATERFALL } = require("../constants");
 const { getDisplayedRequests } = require("./requests");
 
+const EPSILON = 0.001;
+
 function isNetworkDetailsToggleButtonDisabled(state) {
   return getDisplayedRequests(state).length == 0;
 }
 
-const EPSILON = 0.001;
+const getWaterfallScale = createSelector(
+  state => state.requests,
+  state => state.timingMarkers,
+  state => state.ui,
+  (requests, timingMarkers, ui) => {
+    if (requests.firstStartedMillis === +Infinity || ui.waterfallWidth === null) {
+      return null;
+    }
 
-function getWaterfallScale(state) {
-  const { requests, timingMarkers, ui } = state;
-
-  if (requests.firstStartedMillis === +Infinity || ui.waterfallWidth === null) {
-    return null;
+    const lastEventMillis = Math.max(requests.lastEndedMillis,
+                                     timingMarkers.firstDocumentDOMContentLoadedTimestamp,
+                                     timingMarkers.firstDocumentLoadTimestamp);
+    const longestWidth = lastEventMillis - requests.firstStartedMillis;
+    return Math.min(Math.max(
+      (ui.waterfallWidth - REQUESTS_WATERFALL.LABEL_WIDTH) / longestWidth, EPSILON), 1);
   }
-
-  const lastEventMillis = Math.max(requests.lastEndedMillis,
-                                   timingMarkers.firstDocumentDOMContentLoadedTimestamp,
-                                   timingMarkers.firstDocumentLoadTimestamp);
-  const longestWidth = lastEventMillis - requests.firstStartedMillis;
-  return Math.min(Math.max(
-    (ui.waterfallWidth - REQUESTS_WATERFALL.LABEL_WIDTH) / longestWidth, EPSILON), 1);
-}
+);
 
 module.exports = {
   isNetworkDetailsToggleButtonDisabled,
   getWaterfallScale,
 };
--- a/devtools/client/netmonitor/src/widgets/WaterfallBackground.js
+++ b/devtools/client/netmonitor/src/widgets/WaterfallBackground.js
@@ -78,18 +78,17 @@ class WaterfallBackground {
       scaledStep = state.scale * timingStep;
       if (scaledStep < REQUESTS_WATERFALL.BACKGROUND_TICKS_SPACING_MIN) {
         timingStep <<= 1;
         continue;
       }
       optimalTickIntervalFound = true;
     }
 
-    const isRTL = document.defaultView
-      .getComputedStyle(document.documentElement).direction === "rtl";
+    const isRTL = document.dir === "rtl";
     const [r, g, b] = REQUESTS_WATERFALL.BACKGROUND_TICKS_COLOR_RGB;
     let alphaComponent = REQUESTS_WATERFALL.BACKGROUND_TICKS_OPACITY_MIN;
 
     function drawPixelAt(offset, color) {
       let position = (isRTL ? canvasWidth - offset : offset - 1) | 0;
       let [rc, gc, bc, ac] = color;
       view32bit[position] = (ac << 24) | (bc << 16) | (gc << 8) | rc;
     }
--- a/devtools/client/preferences/devtools.js
+++ b/devtools/client/preferences/devtools.js
@@ -77,16 +77,19 @@ pref("devtools.new-animationinspector.en
 
 // Grid highlighter preferences
 pref("devtools.gridinspector.gridOutlineMaxColumns", 50);
 pref("devtools.gridinspector.gridOutlineMaxRows", 50);
 pref("devtools.gridinspector.showGridAreas", false);
 pref("devtools.gridinspector.showGridLineNumbers", false);
 pref("devtools.gridinspector.showInfiniteLines", false);
 
+// Common highlighter preferences
+pref("devtools.highlighter.writingModeAdjust", false);
+
 // Whether or not the box model panel is opened in the computed view
 pref("devtools.computed.boxmodel.opened", true);
 // Whether or not the box model panel is opened in the layout view
 pref("devtools.layout.boxmodel.opened", true);
 // Whether or not the flexbox panel is opened in the layout view
 pref("devtools.layout.flexbox.opened", true);
 // Whether or not the grid inspector panel is opened in the layout view
 pref("devtools.layout.grid.opened", true);
--- a/devtools/client/responsive.html/actions/devices.js
+++ b/devtools/client/responsive.html/actions/devices.js
@@ -69,19 +69,19 @@ function updatePreferredDevices(devices)
 module.exports = {
 
   // This function is only exported for testing purposes
   _loadPreferredDevices: loadPreferredDevices,
 
   updatePreferredDevices: updatePreferredDevices,
 
   addCustomDevice(device) {
-    return function* (dispatch) {
+    return async function (dispatch) {
       // Add custom device to device storage
-      yield addDevice(device, "custom");
+      await addDevice(device, "custom");
       dispatch({
         type: ADD_DEVICE,
         device,
         deviceType: "custom",
       });
     };
   },
 
@@ -96,27 +96,27 @@ module.exports = {
   addDeviceType(deviceType) {
     return {
       type: ADD_DEVICE_TYPE,
       deviceType,
     };
   },
 
   removeCustomDevice(device) {
-    return function* (dispatch, getState) {
+    return async function (dispatch, getState) {
       // Check if the custom device is currently associated with any viewports
       let { viewports } = getState();
       for (let viewport of viewports) {
         if (viewport.device == device.name) {
           dispatch(removeDeviceAssociation(viewport.id));
         }
       }
 
       // Remove custom device from device storage
-      yield removeDevice(device, "custom");
+      await removeDevice(device, "custom");
       dispatch({
         type: REMOVE_DEVICE,
         device,
         deviceType: "custom",
       });
     };
   },
 
@@ -125,23 +125,23 @@ module.exports = {
       type: UPDATE_DEVICE_DISPLAYED,
       device,
       deviceType,
       displayed,
     };
   },
 
   loadDevices() {
-    return function* (dispatch) {
+    return async function (dispatch) {
       dispatch({ type: LOAD_DEVICE_LIST_START });
       let preferredDevices = loadPreferredDevices();
       let devices;
 
       try {
-        devices = yield getDevices();
+        devices = await getDevices();
       } catch (e) {
         console.error("Could not load device list: " + e);
         dispatch({ type: LOAD_DEVICE_LIST_ERROR });
         return;
       }
 
       for (let type of devices.TYPES) {
         dispatch(module.exports.addDeviceType(type));
--- a/devtools/client/responsive.html/actions/screenshot.js
+++ b/devtools/client/responsive.html/actions/screenshot.js
@@ -8,17 +8,16 @@
 
 const {
   TAKE_SCREENSHOT_START,
   TAKE_SCREENSHOT_END,
 } = require("./index");
 
 const { getFormatStr } = require("../utils/l10n");
 const { getToplevelWindow } = require("../utils/window");
-const { Task: { spawn } } = require("devtools/shared/task");
 const e10s = require("../utils/e10s");
 const Services = require("Services");
 
 const CAMERA_AUDIO_URL = "resource://devtools/client/themes/audio/shutter.wav";
 
 const animationFrame = () => new Promise(resolve => {
   window.requestAnimationFrame(resolve);
 });
@@ -36,50 +35,48 @@ function getFileName() {
 
 function createScreenshotFor(node) {
   let mm = node.frameLoader.messageManager;
 
   return e10s.request(mm, "RequestScreenshot");
 }
 
 function saveToFile(data, filename) {
-  return spawn(function* () {
-    const chromeWindow = getToplevelWindow(window);
-    const chromeDocument = chromeWindow.document;
+  const chromeWindow = getToplevelWindow(window);
+  const chromeDocument = chromeWindow.document;
 
-    // append .png extension to filename if it doesn't exist
-    filename = filename.replace(/\.png$|$/i, ".png");
+  // append .png extension to filename if it doesn't exist
+  filename = filename.replace(/\.png$|$/i, ".png");
 
-    chromeWindow.saveURL(data, filename, null,
-                         true, true,
-                         chromeDocument.documentURIObject, chromeDocument);
-  });
+  chromeWindow.saveURL(data, filename, null,
+                        true, true,
+                        chromeDocument.documentURIObject, chromeDocument);
 }
 
 function simulateCameraEffects(node) {
   if (Services.prefs.getBoolPref("devtools.screenshot.audio.enabled")) {
     let cameraAudio = new window.Audio(CAMERA_AUDIO_URL);
     cameraAudio.play();
   }
   node.animate({ opacity: [ 0, 1 ] }, 500);
 }
 
 module.exports = {
 
   takeScreenshot() {
-    return function* (dispatch, getState) {
-      yield dispatch({ type: TAKE_SCREENSHOT_START });
+    return async function (dispatch, getState) {
+      await dispatch({ type: TAKE_SCREENSHOT_START });
 
       // Waiting the next repaint, to ensure the react components
       // can be properly render after the action dispatched above
-      yield animationFrame();
+      await animationFrame();
 
       let iframe = document.querySelector("iframe");
-      let data = yield createScreenshotFor(iframe);
+      let data = await createScreenshotFor(iframe);
 
       simulateCameraEffects(iframe);
 
-      yield saveToFile(data, getFileName());
+      saveToFile(data, getFileName());
 
       dispatch({ type: TAKE_SCREENSHOT_END });
     };
   }
 };
--- a/devtools/client/responsive.html/browser/swap.js
+++ b/devtools/client/responsive.html/browser/swap.js
@@ -1,16 +1,15 @@
 /* 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 { Ci } = require("chrome");
-const { Task } = require("devtools/shared/task");
 const { tunnelToInnerBrowser } = require("./tunnel");
 
 function debug(msg) {
   // console.log(`RDM swap: ${msg}`);
 }
 
 /**
  * Swap page content from an existing tab into a new browser within a container
@@ -87,17 +86,17 @@ function swapToInnerBrowser({ tab, conta
     if (otherBrowser.frameLoader.tabParent.tabId != contentTabId) {
       // Bug 1408602: Try to unwind to save tab content from being lost.
       throw new Error("Swapping tab content between browsers failed.");
     }
   };
 
   return {
 
-    start: Task.async(function* () {
+    async start() {
       tab.isResponsiveDesignMode = true;
 
       // Hide the browser content temporarily while things move around to avoid displaying
       // strange intermediate states.
       tab.linkedBrowser.style.visibility = "hidden";
 
       // Freeze navigation temporarily to avoid "blinking" in the location bar.
       freezeNavigationState(tab);
@@ -145,20 +144,20 @@ function swapToInnerBrowser({ tab, conta
       // after the frame is set lazily, so it's unclear how to know that work
       // has finished.
       debug("Set container docShell active");
       containerBrowser.docShellIsActive = true;
 
       // 3. Create the initial viewport inside the tool UI.
       // The calling application will use container page loaded into the tab to
       // do whatever it needs to create the inner browser.
-      debug("Yield to container tab loaded");
-      yield tabLoaded(containerTab);
-      debug("Yield to get inner browser");
-      innerBrowser = yield getInnerBrowser(containerBrowser);
+      debug("Wait until container tab loaded");
+      await tabLoaded(containerTab);
+      debug("Wait until inner browser available");
+      innerBrowser = await getInnerBrowser(containerBrowser);
       addXULBrowserDecorations(innerBrowser);
       if (innerBrowser.isRemoteBrowser != tab.linkedBrowser.isRemoteBrowser) {
         throw new Error("The inner browser's remoteness must match the " +
                         "original tab.");
       }
 
       // 4. Swap tab content from the regular browser tab to the browser within
       //    the viewport in the tool UI, preserving all state via
@@ -178,18 +177,18 @@ function swapToInnerBrowser({ tab, conta
       //    tool via `swapBrowsersAndCloseOther`.
       debug("Swap tool UI to original tab");
       swapBrowsersAndCloseOtherSilently(tab, containerTab);
 
       // 7. Start a tunnel from the tool tab's browser to the viewport browser
       //    so that some browser UI functions, like navigation, are connected to
       //    the content in the viewport, instead of the tool page.
       tunnel = tunnelToInnerBrowser(tab.linkedBrowser, innerBrowser);
-      debug("Yield to tunnel start");
-      yield tunnel.start();
+      debug("Wait until tunnel start");
+      await tunnel.start();
 
       // Swapping browsers disconnects the find bar UI from the browser.
       // If the find bar has been initialized, reconnect it.
       if (gBrowser.isFindBarInitialized(tab)) {
         let findBar = gBrowser.getFindBar(tab);
         findBar.browser = tab.linkedBrowser;
         if (!findBar.hidden) {
           // Force the find bar to activate again, restoring the search string.
@@ -199,17 +198,17 @@ function swapToInnerBrowser({ tab, conta
 
       // Force the browser UI to match the new state of the tab and browser.
       thawNavigationState(tab);
       gBrowser.setTabTitle(tab);
       gBrowser.updateCurrentBrowser(true);
 
       // Show the browser content again now that the move is done.
       tab.linkedBrowser.style.visibility = "";
-    }),
+    },
 
     stop() {
       // Hide the browser content temporarily while things move around to avoid displaying
       // strange intermediate states.
       tab.linkedBrowser.style.visibility = "hidden";
 
       // 1. Stop the tunnel between outer and inner browsers.
       tunnel.stop();
--- a/devtools/client/responsive.html/browser/tunnel.js
+++ b/devtools/client/responsive.html/browser/tunnel.js
@@ -1,17 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { Ci, Cu } = require("chrome");
 const Services = require("Services");
-const { Task } = require("devtools/shared/task");
 const { BrowserElementWebNavigation } = require("./web-navigation");
 const { getStack } = require("devtools/shared/platform/stack");
 
 // A symbol used to hold onto the frame loader from the outer browser while tunneling.
 const FRAME_LOADER = Symbol("devtools/responsive/frame-loader");
 // Export for use in tests.
 exports.OUTER_FRAME_LOADER_SYMBOL = FRAME_LOADER;
 
@@ -90,17 +89,17 @@ const PROPERTIES_FROM_BROWSER_WINDOW = [
  */
 function tunnelToInnerBrowser(outer, inner) {
   let browserWindow = outer.ownerDocument.defaultView;
   let gBrowser = browserWindow.gBrowser;
   let mmTunnel;
 
   return {
 
-    start: Task.async(function* () {
+    async start() {
       if (outer.isRemoteBrowser) {
         throw new Error("The outer browser must be non-remote.");
       }
       if (!inner.isRemoteBrowser) {
         throw new Error("The inner browser must be remote.");
       }
 
       // Various browser methods access the `frameLoader` property, including:
@@ -229,17 +228,17 @@ function tunnelToInnerBrowser(outer, inn
           },
           configurable: true,
           enumerable: true,
         });
       }
 
       // Add mozbrowser event handlers
       inner.addEventListener("mozbrowseropenwindow", this);
-    }),
+    },
 
     handleEvent(event) {
       if (event.type != "mozbrowseropenwindow") {
         return;
       }
 
       // Minimal support for <a target/> and window.open() which just ensures we at
       // least open them somewhere (in a new tab).  The following things are ignored:
--- a/devtools/client/responsive.html/commands.js
+++ b/devtools/client/responsive.html/commands.js
@@ -87,15 +87,15 @@ exports.items = [
         type: "number",
         description: l10n.lookup("resizePageArgHeightDesc"),
       },
     ],
     exec: resize
   }
 ];
 
-function* resize(args, context) {
+async function resize(args, context) {
   let browserWindow = context.environment.chromeWindow;
-  yield ResponsiveUIManager.handleGcliCommand(browserWindow,
+  await ResponsiveUIManager.handleGcliCommand(browserWindow,
                                               browserWindow.gBrowser.selectedTab,
                                               this.name,
                                               args);
 }
--- a/devtools/client/responsive.html/components/Browser.js
+++ b/devtools/client/responsive.html/components/Browser.js
@@ -114,17 +114,17 @@ class Browser extends PureComponent {
     await ready;
 
     let browserWindow = getToplevelWindow(window);
     let requiresFloatingScrollbars =
       !browserWindow.matchMedia("(-moz-overlay-scrollbars)").matches;
 
     await e10s.request(mm, "Start", {
       requiresFloatingScrollbars,
-      // Tests expect events on resize to yield on various size changes
+      // Tests expect events on resize to wait for various size changes
       notifyOnResize: flags.testing,
     });
   }
 
   async stopFrameScript() {
     let { onContentResize } = this;
     let browser = this.refs.browserContainer.querySelector("iframe.browser");
     let mm = browser.frameLoader.messageManager;
--- a/devtools/client/responsive.html/index.js
+++ b/devtools/client/responsive.html/index.js
@@ -8,17 +8,16 @@
 
 const { utils: Cu } = Components;
 const { BrowserLoader } =
   Cu.import("resource://devtools/client/shared/browser-loader.js", {});
 const { require } = BrowserLoader({
   baseURI: "resource://devtools/client/responsive.html/",
   window
 });
-const { Task } = require("devtools/shared/task");
 const Telemetry = require("devtools/client/shared/telemetry");
 const { loadAgentSheet } = require("./utils/css");
 
 const { createFactory, createElement } =
   require("devtools/client/shared/vendor/react");
 const ReactDOM = require("devtools/client/shared/vendor/react-dom");
 const { Provider } = require("devtools/client/shared/vendor/react-redux");
 
@@ -34,29 +33,29 @@ const { loadDevices } = require("./actio
 window.require = require;
 
 let bootstrap = {
 
   telemetry: new Telemetry(),
 
   store: null,
 
-  init: Task.async(function* () {
+  async init() {
     // Load a special UA stylesheet to reset certain styles such as dropdown
     // lists.
     loadAgentSheet(
       window,
       "resource://devtools/client/responsive.html/responsive-ua.css"
     );
     this.telemetry.toolOpened("responsive");
     let store = this.store = Store();
     let provider = createElement(Provider, { store }, App());
     ReactDOM.render(provider, document.querySelector("#root"));
     message.post(window, "init:done");
-  }),
+  },
 
   destroy() {
     this.store = null;
     this.telemetry.toolClosed("responsive");
     this.telemetry = null;
   },
 
   /**
--- a/devtools/client/responsive.html/manager.js
+++ b/devtools/client/responsive.html/manager.js
@@ -1,17 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { Ci } = require("chrome");
 const promise = require("promise");
-const { Task } = require("devtools/shared/task");
 const EventEmitter = require("devtools/shared/old-event-emitter");
 
 const TOOL_URL = "chrome://devtools/content/responsive.html/index.xhtml";
 
 loader.lazyRequireGetter(this, "DebuggerClient", "devtools/shared/client/debugger-client", true);
 loader.lazyRequireGetter(this, "DebuggerServer", "devtools/server/main", true);
 loader.lazyRequireGetter(this, "TargetFactory", "devtools/client/framework/target", true);
 loader.lazyRequireGetter(this, "gDevTools", "devtools/client/framework/devtools", true);
@@ -70,70 +69,70 @@ const ResponsiveUIManager = exports.Resp
    *        The browser tab.
    * @param options
    *        Other options associated with opening.  Currently includes:
    *        - `command`: Whether initiated via GCLI command bar or toolbox button
    * @return Promise
    *         Resolved to the ResponsiveUI instance for this tab when opening is
    *         complete.
    */
-  openIfNeeded: Task.async(function* (window, tab, options) {
+  async openIfNeeded(window, tab, options) {
     if (!tab.linkedBrowser.isRemoteBrowser) {
       this.showRemoteOnlyNotification(window, tab, options);
       return promise.reject(new Error("RDM only available for remote tabs."));
     }
     // Remove this once we support this case in bug 1306975.
     if (tab.linkedBrowser.hasAttribute("usercontextid")) {
       this.showNoContainerTabsNotification(window, tab, options);
       return promise.reject(new Error("RDM not available for container tabs."));
     }
     if (!this.isActiveForTab(tab)) {
       this.initMenuCheckListenerFor(window);
 
       let ui = new ResponsiveUI(window, tab);
       this.activeTabs.set(tab, ui);
-      yield this.setMenuCheckFor(tab, window);
-      yield ui.inited;
+      await this.setMenuCheckFor(tab, window);
+      await ui.inited;
       this.emit("on", { tab });
     }
 
     return this.getResponsiveUIForTab(tab);
-  }),
+  },
 
   /**
    * Closes the responsive UI, if not already closed.
    *
    * @param window
    *        The main browser chrome window.
    * @param tab
    *        The browser tab.
    * @param options
    *        Other options associated with closing.  Currently includes:
    *        - `command`: Whether initiated via GCLI command bar or toolbox button
    *        - `reason`: String detailing the specific cause for closing
    * @return Promise
    *         Resolved (with no value) when closing is complete.
    */
-  closeIfNeeded: Task.async(function* (window, tab, options) {
+  async closeIfNeeded(window, tab, options) {
     if (this.isActiveForTab(tab)) {
       let ui = this.activeTabs.get(tab);
-      let destroyed = yield ui.destroy(options);
+      let destroyed = await ui.destroy(options);
       if (!destroyed) {
         // Already in the process of destroying, abort.
         return;
       }
       this.activeTabs.delete(tab);
 
       if (!this.isActiveForWindow(window)) {
         this.removeMenuCheckListenerFor(window);
       }
       this.emit("off", { tab });
-      yield this.setMenuCheckFor(tab, window);
+      await this.setMenuCheckFor(tab, window);
     }
-  }),
+  },
 
   /**
    * Returns true if responsive UI is active for a given tab.
    *
    * @param tab
    *        The browser tab.
    * @return boolean
    */
@@ -208,24 +207,24 @@ const ResponsiveUIManager = exports.Resp
 
   removeMenuCheckListenerFor(window) {
     if (window && window.gBrowser && window.gBrowser.tabContainer) {
       let { tabContainer } = window.gBrowser;
       tabContainer.removeEventListener("TabSelect", this.handleMenuCheck);
     }
   },
 
-  setMenuCheckFor: Task.async(function* (tab, window = tab.ownerGlobal) {
-    yield startup(window);
+  async setMenuCheckFor(tab, window = tab.ownerGlobal) {
+    await startup(window);
 
     let menu = window.document.getElementById("menu_responsiveUI");
     if (menu) {
       menu.setAttribute("checked", this.isActiveForTab(tab));
     }
-  }),
+  },
 
   showRemoteOnlyNotification(window, tab, options) {
     this.showErrorNotification(window, tab, options, getStr("responsive.remoteOnly"));
   },
 
   showNoContainerTabsNotification(window, tab, options) {
     this.showErrorNotification(window, tab, options,
                                getStr("responsive.noContainerTabs"));
@@ -315,59 +314,59 @@ ResponsiveUI.prototype = {
 
   /**
    * Open RDM while preserving the state of the page.  We use `swapFrameLoaders`
    * to ensure all in-page state is preserved, just like when you move a tab to
    * a new window.
    *
    * For more details, see /devtools/docs/responsive-design-mode.md.
    */
-  init: Task.async(function* () {
+  async init() {
     debug("Init start");
 
     let ui = this;
 
     // Watch for tab close and window close so we can clean up RDM synchronously
     this.tab.addEventListener("TabClose", this);
     this.browserWindow.addEventListener("unload", this);
 
     // Swap page content from the current tab into a viewport within RDM
     debug("Create browser swapper");
     this.swap = swapToInnerBrowser({
       tab: this.tab,
       containerURL: TOOL_URL,
-      getInnerBrowser: Task.async(function* (containerBrowser) {
+      async getInnerBrowser(containerBrowser) {
         let toolWindow = ui.toolWindow = containerBrowser.contentWindow;
         toolWindow.addEventListener("message", ui);
-        debug("Yield to init from inner");
-        yield message.request(toolWindow, "init");
+        debug("Wait until init from inner");
+        await message.request(toolWindow, "init");
         toolWindow.addInitialViewport("about:blank");
-        debug("Yield to browser mounted");
-        yield message.wait(toolWindow, "browser-mounted");
+        debug("Wait until browser mounted");
+        await message.wait(toolWindow, "browser-mounted");
         return ui.getViewportBrowser();
-      })
+      }
     });
-    debug("Yield to swap start");
-    yield this.swap.start();
+    debug("Wait until swap start");
+    await this.swap.start();
 
     this.tab.addEventListener("BeforeTabRemotenessChange", this);
 
     // Notify the inner browser to start the frame script
-    debug("Yield to start frame script");
-    yield message.request(this.toolWindow, "start-frame-script");
+    debug("Wait until start frame script");
+    await message.request(this.toolWindow, "start-frame-script");
 
     // Get the protocol ready to speak with emulation actor
-    debug("Yield to RDP server connect");
-    yield this.connectToServer();
+    debug("Wait until RDP server connect");
+    await this.connectToServer();
 
     // Non-blocking message to tool UI to start any delayed init activities
     message.post(this.toolWindow, "post-init");
 
     debug("Init done");
-  }),
+  },
 
   /**
    * Close RDM and restore page content back into a regular tab.
    *
    * @param object
    *        Destroy options, which currently includes a `reason` string.
    * @return boolean
    *         Whether this call is actually destroying.  False means destruction
@@ -376,17 +375,17 @@ ResponsiveUI.prototype = {
   async destroy(options) {
     if (this.destroying) {
       return false;
     }
     this.destroying = true;
 
     // If our tab is about to be closed, there's not enough time to exit
     // gracefully, but that shouldn't be a problem since the tab will go away.
-    // So, skip any yielding when we're about to close the tab.
+    // So, skip any waiting when we're about to close the tab.
     let isWindowClosing = options && options.reason === "unload";
     let isTabContentDestroying =
       isWindowClosing || (options && (options.reason === "TabClose" ||
                                       options.reason === "BeforeTabRemotenessChange"));
 
     // Ensure init has finished before starting destroy
     if (!isTabContentDestroying) {
       await this.inited;
@@ -437,24 +436,24 @@ ResponsiveUI.prototype = {
       swap.stop();
     }
 
     this.destroyed = true;
 
     return true;
   },
 
-  connectToServer: Task.async(function* () {
+  async connectToServer() {
     DebuggerServer.init();
     DebuggerServer.registerAllActors();
     this.client = new DebuggerClient(DebuggerServer.connectPipe());
-    yield this.client.connect();
-    let { tab } = yield this.client.getTab();
+    await this.client.connect();
+    let { tab } = await this.client.getTab();
     this.emulationFront = EmulationFront(this.client, tab);
-  }),
+  },
 
   handleEvent(event) {
     let { browserWindow, tab } = this;
 
     switch (event.type) {
       case "message":
         this.handleMessage(event);
         break;
@@ -493,35 +492,35 @@ ResponsiveUI.prototype = {
         this.onExit();
         break;
       case "remove-device-association":
         this.onRemoveDeviceAssociation(event);
         break;
     }
   },
 
-  onChangeDevice: Task.async(function* (event) {
+  async onChangeDevice(event) {
     let { userAgent, pixelRatio, touch } = event.data.device;
     // Bug 1428799: Should we reload on UA change as well?
-    yield this.updateUserAgent(userAgent);
-    yield this.updateDPPX(pixelRatio);
-    let reloadNeeded = yield this.updateTouchSimulation(touch);
+    await this.updateUserAgent(userAgent);
+    await this.updateDPPX(pixelRatio);
+    let reloadNeeded = await this.updateTouchSimulation(touch);
     if (reloadNeeded) {
       this.getViewportBrowser().reload();
     }
     // Used by tests
     this.emit("device-changed");
-  }),
+  },
 
-  onChangeNetworkThrottling: Task.async(function* (event) {
+  async onChangeNetworkThrottling(event) {
     let { enabled, profile } = event.data;
-    yield this.updateNetworkThrottling(enabled, profile);
+    await this.updateNetworkThrottling(enabled, profile);
     // Used by tests
     this.emit("network-throttling-changed");
-  }),
+  },
 
   onChangePixelRatio(event) {
     let { pixelRatio } = event.data;
     this.updateDPPX(pixelRatio);
   },
 
   async onChangeTouchSimulation(event) {
     let { enabled } = event.data;
@@ -541,65 +540,65 @@ ResponsiveUI.prototype = {
     });
   },
 
   onExit() {
     let { browserWindow, tab } = this;
     ResponsiveUIManager.closeIfNeeded(browserWindow, tab);
   },
 
-  onRemoveDeviceAssociation: Task.async(function* (event) {
+  async onRemoveDeviceAssociation(event) {
     // Bug 1428799: Should we reload on UA change as well?
-    yield this.updateUserAgent();
-    yield this.updateDPPX();
-    let reloadNeeded = yield this.updateTouchSimulation();
+    await this.updateUserAgent();
+    await this.updateDPPX();
+    let reloadNeeded = await this.updateTouchSimulation();
     if (reloadNeeded) {
       this.getViewportBrowser().reload();
     }
     // Used by tests
     this.emit("device-association-removed");
-  }),
+  },
 
   /**
    * Set or clear the emulated device pixel ratio.
    *
    * @return boolean
    *         Whether a reload is needed to apply the change.
    *         (This is always immediate, so it's always false.)
    */
-  updateDPPX: Task.async(function* (dppx) {
+  async updateDPPX(dppx) {
     if (!dppx) {
-      yield this.emulationFront.clearDPPXOverride();
+      await this.emulationFront.clearDPPXOverride();
       return false;
     }
-    yield this.emulationFront.setDPPXOverride(dppx);
+    await this.emulationFront.setDPPXOverride(dppx);
     return false;
-  }),
+  },
 
   /**
    * Set or clear network throttling.
    *
    * @return boolean
    *         Whether a reload is needed to apply the change.
    *         (This is always immediate, so it's always false.)
    */
-  updateNetworkThrottling: Task.async(function* (enabled, profile) {
+  async updateNetworkThrottling(enabled, profile) {
     if (!enabled) {
-      yield this.emulationFront.clearNetworkThrottling();
+      await this.emulationFront.clearNetworkThrottling();
       return false;
     }
     let data = throttlingProfiles.find(({ id }) => id == profile);
     let { download, upload, latency } = data;
-    yield this.emulationFront.setNetworkThrottling({
+    await this.emulationFront.setNetworkThrottling({
       downloadThroughput: download,
       uploadThroughput: upload,
       latency,
     });
     return false;
-  }),
+  },
 
   /**
    * Set or clear the emulated user agent.
    *
    * @return boolean
    *         Whether a reload is needed to apply the change.
    */
   updateUserAgent(userAgent) {
@@ -629,20 +628,20 @@ ResponsiveUI.prototype = {
    */
   getViewportSize() {
     return this.toolWindow.getViewportSize();
   },
 
   /**
    * Helper for tests, GCLI, etc. Assumes a single viewport for now.
    */
-  setViewportSize: Task.async(function* (size) {
-    yield this.inited;
+  async setViewportSize(size) {
+    await this.inited;
     this.toolWindow.setViewportSize(size);
-  }),
+  },
 
   /**
    * Helper for tests/reloading the viewport. Assumes a single viewport for now.
    */
   getViewportBrowser() {
     return this.toolWindow.getViewportBrowser();
   },
 
--- a/devtools/client/responsive.html/test/browser/browser_cmd_click.js
+++ b/devtools/client/responsive.html/test/browser/browser_cmd_click.js
@@ -5,25 +5,25 @@
 
 // Ensure Cmd/Ctrl-clicking link opens a new tab
 
 const TAB_URL = "http://example.com/";
 const TEST_URL =
   `data:text/html,<a href="${TAB_URL}">Click me</a>`
   .replace(/ /g, "%20");
 
-addRDMTask(TEST_URL, function* ({ ui }) {
+addRDMTask(TEST_URL, async function ({ ui }) {
   let store = ui.toolWindow.store;
 
   // Wait until the viewport has been added
-  yield waitUntilState(store, state => state.viewports.length == 1);
+  await waitUntilState(store, state => state.viewports.length == 1);
 
   // Cmd-click the link and wait for a new tab
-  yield waitForFrameLoad(ui, TEST_URL);
+  await waitForFrameLoad(ui, TEST_URL);
   let newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser, TAB_URL);
   BrowserTestUtils.synthesizeMouseAtCenter("a", {
     ctrlKey: true,
     metaKey: true,
   }, ui.getViewportBrowser());
-  let newTab = yield newTabPromise;
+  let newTab = await newTabPromise;
   ok(newTab, "New tab opened from link");
-  yield removeTab(newTab);
+  await removeTab(newTab);
 });
--- a/devtools/client/responsive.html/test/browser/browser_device_change.js
+++ b/devtools/client/responsive.html/test/browser/browser_device_change.js
@@ -23,60 +23,60 @@ const testDevice = {
   "firefoxOS": true,
   "os": "custom",
   "featured": true,
 };
 
 // Add the new device to the list
 addDeviceForTest(testDevice);
 
-addRDMTask(TEST_URL, function* ({ ui }) {
+addRDMTask(TEST_URL, async function ({ ui }) {
   let { store } = ui.toolWindow;
 
   // Wait until the viewport has been added and the device list has been loaded
-  yield waitUntilState(store, state => state.viewports.length == 1
+  await waitUntilState(store, state => state.viewports.length == 1
     && state.devices.listState == Types.deviceListState.LOADED);
 
   // Test defaults
   testViewportDimensions(ui, 320, 480);
   info("Should have default UA at the start of the test");
-  yield testUserAgent(ui, DEFAULT_UA);
-  yield testDevicePixelRatio(ui, DEFAULT_DPPX);
-  yield testTouchEventsOverride(ui, false);
+  await testUserAgent(ui, DEFAULT_UA);
+  await testDevicePixelRatio(ui, DEFAULT_DPPX);
+  await testTouchEventsOverride(ui, false);
   testViewportDeviceSelectLabel(ui, "no device selected");
 
   // Test device with custom properties
   let reloaded = waitForViewportLoad(ui);
-  yield selectDevice(ui, "Fake Phone RDM Test");
-  yield reloaded;
-  yield waitForViewportResizeTo(ui, testDevice.width, testDevice.height);
+  await selectDevice(ui, "Fake Phone RDM Test");
+  await reloaded;
+  await waitForViewportResizeTo(ui, testDevice.width, testDevice.height);
   info("Should have device UA now that device is applied");
-  yield testUserAgent(ui, testDevice.userAgent);
-  yield testDevicePixelRatio(ui, testDevice.pixelRatio);
-  yield testTouchEventsOverride(ui, true);
+  await testUserAgent(ui, testDevice.userAgent);
+  await testDevicePixelRatio(ui, testDevice.pixelRatio);
+  await testTouchEventsOverride(ui, true);
 
   // Test resetting device when resizing viewport
   let deviceRemoved = once(ui, "device-association-removed");
   reloaded = waitForViewportLoad(ui);
-  yield testViewportResize(ui, ".viewport-vertical-resize-handle",
+  await testViewportResize(ui, ".viewport-vertical-resize-handle",
     [-10, -10], [testDevice.width, testDevice.height - 10], [0, -10], ui);
-  yield Promise.all([ deviceRemoved, reloaded ]);
+  await Promise.all([ deviceRemoved, reloaded ]);
   info("Should have default UA after resizing viewport");
-  yield testUserAgent(ui, DEFAULT_UA);
-  yield testDevicePixelRatio(ui, DEFAULT_DPPX);
-  yield testTouchEventsOverride(ui, false);
+  await testUserAgent(ui, DEFAULT_UA);
+  await testDevicePixelRatio(ui, DEFAULT_DPPX);
+  await testTouchEventsOverride(ui, false);
   testViewportDeviceSelectLabel(ui, "no device selected");
 
   // Test device with generic properties
-  yield selectDevice(ui, "Laptop (1366 x 768)");
-  yield waitForViewportResizeTo(ui, 1366, 768);
+  await selectDevice(ui, "Laptop (1366 x 768)");
+  await waitForViewportResizeTo(ui, 1366, 768);
   info("Should have default UA when using device without specific UA");
-  yield testUserAgent(ui, DEFAULT_UA);
-  yield testDevicePixelRatio(ui, 1);
-  yield testTouchEventsOverride(ui, false);
+  await testUserAgent(ui, DEFAULT_UA);
+  await testDevicePixelRatio(ui, 1);
+  await testTouchEventsOverride(ui, false);
 });
 
 add_task(async function () {
   const tab = await addTab(TEST_URL);
   const { ui } = await openRDM(tab);
 
   let { store } = ui.toolWindow;
 
@@ -108,18 +108,12 @@ function testViewportDimensions(ui, w, h
   let viewport = ui.toolWindow.document.querySelector(".viewport-content");
 
   is(ui.toolWindow.getComputedStyle(viewport).getPropertyValue("width"),
      `${w}px`, `Viewport should have width of ${w}px`);
   is(ui.toolWindow.getComputedStyle(viewport).getPropertyValue("height"),
      `${h}px`, `Viewport should have height of ${h}px`);
 }
 
-function* testDevicePixelRatio(ui, expected) {
-  let dppx = yield getViewportDevicePixelRatio(ui);
+async function testDevicePixelRatio(ui, expected) {
+  let dppx = await getViewportDevicePixelRatio(ui);
   is(dppx, expected, `devicePixelRatio should be set to ${expected}`);
 }
-
-function* getViewportDevicePixelRatio(ui) {
-  return yield ContentTask.spawn(ui.getViewportBrowser(), {}, function* () {
-    return content.devicePixelRatio;
-  });
-}
--- a/devtools/client/responsive.html/test/browser/browser_device_custom.js
+++ b/devtools/client/responsive.html/test/browser/browser_device_custom.js
@@ -21,22 +21,22 @@ const unicodeDevice = {
   pixelRatio: 1.5,
   userAgent: "Mozilla/5.0 (Mobile; rv:39.0) Gecko/39.0 Firefox/39.0",
   touch: true,
 };
 
 const TEST_URL = "data:text/html;charset=utf-8,";
 const Types = require("devtools/client/responsive.html/types");
 
-addRDMTask(TEST_URL, function* ({ ui }) {
+addRDMTask(TEST_URL, async function ({ ui }) {
   let { toolWindow } = ui;
   let { store, document } = toolWindow;
 
   // Wait until the viewport has been added and the device list has been loaded
-  yield waitUntilState(store, state => state.viewports.length == 1
+  await waitUntilState(store, state => state.viewports.length == 1
     && state.devices.listState == Types.deviceListState.LOADED);
 
   let deviceSelector = document.querySelector(".viewport-device-selector");
   let submitButton = document.querySelector("#device-submit-button");
 
   openDeviceModal(ui);
 
   info("Reveal device adder form, check that defaults match the viewport");
@@ -47,44 +47,44 @@ addRDMTask(TEST_URL, function* ({ ui }) 
     width: 320,
     height: 480,
     pixelRatio: window.devicePixelRatio,
     userAgent: navigator.userAgent,
     touch: false,
   });
 
   info("Fill out device adder form and save");
-  yield addDeviceInModal(ui, device);
+  await addDeviceInModal(ui, device);
 
   info("Verify device defaults to enabled in modal");
   let deviceCb = [...document.querySelectorAll(".device-input-checkbox")].find(cb => {
     return cb.value == device.name;
   });
   ok(deviceCb, "Custom device checkbox added to modal");
   ok(deviceCb.checked, "Custom device enabled");
   submitButton.click();
 
   info("Look for custom device in device selector");
   let selectorOption = [...deviceSelector.options].find(opt => opt.value == device.name);
   ok(selectorOption, "Custom device option added to device selector");
 });
 
-addRDMTask(TEST_URL, function* ({ ui }) {
+addRDMTask(TEST_URL, async function ({ ui }) {
   let { toolWindow } = ui;
   let { store, document } = toolWindow;
 
   // Wait until the viewport has been added and the device list has been loaded
-  yield waitUntilState(store, state => state.viewports.length == 1
+  await waitUntilState(store, state => state.viewports.length == 1
     && state.devices.listState == Types.deviceListState.LOADED);
 
   let deviceSelector = document.querySelector(".viewport-device-selector");
   let submitButton = document.querySelector("#device-submit-button");
 
   info("Select existing device from the selector");
-  yield selectDevice(ui, "Test Device");
+  await selectDevice(ui, "Test Device");
 
   openDeviceModal(ui);
 
   info("Reveal device adder form, check that defaults are based on selected device");
   let adderShow = document.querySelector("#device-adder-show");
   adderShow.click();
   testDeviceAdder(ui, Object.assign({}, device, {
     name: "Test Device (Custom)",
@@ -92,69 +92,69 @@ addRDMTask(TEST_URL, function* ({ ui }) 
 
   info("Remove previously added custom device");
   let deviceRemoveButton = document.querySelector(".device-remove-button");
   let removed = Promise.all([
     waitUntilState(store, state => state.devices.custom.length == 0),
     once(ui, "device-association-removed")
   ]);
   deviceRemoveButton.click();
-  yield removed;
+  await removed;
   submitButton.click();
 
   info("Ensure custom device was removed from device selector");
-  yield waitUntilState(store, state => state.viewports[0].device == "");
+  await waitUntilState(store, state => state.viewports[0].device == "");
   is(deviceSelector.value, "", "Device selector reset to no device");
   let selectorOption = [...deviceSelector.options].find(opt => opt.value == device.name);
   ok(!selectorOption, "Custom device option removed from device selector");
 
   info("Ensure device properties like UA have been reset");
-  yield testUserAgent(ui, navigator.userAgent);
+  await testUserAgent(ui, navigator.userAgent);
 });
 
-addRDMTask(TEST_URL, function* ({ ui }) {
+addRDMTask(TEST_URL, async function ({ ui }) {
   let { toolWindow } = ui;
   let { store, document } = toolWindow;
 
   // Wait until the viewport has been added and the device list has been loaded
-  yield waitUntilState(store, state => state.viewports.length == 1
+  await waitUntilState(store, state => state.viewports.length == 1
     && state.devices.listState == Types.deviceListState.LOADED);
 
   let deviceSelector = document.querySelector(".viewport-device-selector");
   let submitButton = document.querySelector("#device-submit-button");
 
   openDeviceModal(ui);
 
   info("Reveal device adder form");
   let adderShow = document.querySelector("#device-adder-show");
   adderShow.click();
 
   info("Fill out device adder form by setting details to unicode device and save");
-  yield addDeviceInModal(ui, unicodeDevice);
+  await addDeviceInModal(ui, unicodeDevice);
 
   info("Verify unicode device defaults to enabled in modal");
   let deviceCb = [...document.querySelectorAll(".device-input-checkbox")].find(cb => {
     return cb.value == unicodeDevice.name;
   });
   ok(deviceCb, "Custom unicode device checkbox added to modal");
   ok(deviceCb.checked, "Custom unicode device enabled");
   submitButton.click();
 
   info("Look for custom unicode device in device selector");
   let selectorOption = [...deviceSelector.options].find(opt =>
     opt.value == unicodeDevice.name);
   ok(selectorOption, "Custom unicode device option added to device selector");
 });
 
-addRDMTask(TEST_URL, function* ({ ui }) {
+addRDMTask(TEST_URL, async function ({ ui }) {
   let { toolWindow } = ui;
   let { store, document } = toolWindow;
 
   // Wait until the viewport has been added and the device list has been loaded
-  yield waitUntilState(store, state => state.viewports.length == 1
+  await waitUntilState(store, state => state.viewports.length == 1
     && state.devices.listState == Types.deviceListState.LOADED);
 
   let deviceSelector = document.querySelector(".viewport-device-selector");
 
   // Check if the unicode custom device is present in the list of device options since
   // we want to ensure that unicode device names are not forgotten after restarting RDM
   // see bug 1379687
   info("Look for custom unicode device in device selector");
--- a/devtools/client/responsive.html/test/browser/browser_device_custom_remove.js
+++ b/devtools/client/responsive.html/test/browser/browser_device_custom_remove.js
@@ -19,44 +19,44 @@ const device = {
 const device1 = Object.assign({}, device, {
   name: "Test Device 1",
 });
 
 const device2 = Object.assign({}, device, {
   name: "Test Device 2",
 });
 
-addRDMTask(TEST_URL, function* ({ ui }) {
+addRDMTask(TEST_URL, async function ({ ui }) {
   let { toolWindow } = ui;
   let { store, document } = toolWindow;
 
   info("Verify that remove buttons affect the correct device");
 
   // Wait until the viewport has been added and the device list has been loaded
-  yield waitUntilState(store, state => state.viewports.length == 1
+  await waitUntilState(store, state => state.viewports.length == 1
     && state.devices.listState == Types.deviceListState.LOADED);
 
   let deviceSelector = document.querySelector(".viewport-device-selector");
   let submitButton = document.querySelector("#device-submit-button");
 
   openDeviceModal(ui);
 
   info("Reveal device adder form");
   let adderShow = document.querySelector("#device-adder-show");
   adderShow.click();
 
   info("Add test device 1");
-  yield addDeviceInModal(ui, device1);
+  await addDeviceInModal(ui, device1);
 
   info("Reveal device adder form");
   adderShow = document.querySelector("#device-adder-show");
   adderShow.click();
 
   info("Add test device 2");
-  yield addDeviceInModal(ui, device2);
+  await addDeviceInModal(ui, device2);
 
   info("Verify all custom devices default to enabled in modal");
   let deviceCbs =
     [...document.querySelectorAll(".device-type-custom .device-input-checkbox")];
   is(deviceCbs.length, 2, "Both devices have a checkbox in modal");
   for (let cb of deviceCbs) {
     ok(cb.checked, "Custom device enabled");
   }
@@ -72,34 +72,34 @@ addRDMTask(TEST_URL, function* ({ ui }) 
 
   openDeviceModal(ui);
 
   info("Remove device 2");
   let deviceRemoveButtons = [...document.querySelectorAll(".device-remove-button")];
   is(deviceRemoveButtons.length, 2, "Both devices have a remove button in modal");
   let removed = waitUntilState(store, state => state.devices.custom.length == 1);
   deviceRemoveButtons[1].click();
-  yield removed;
+  await removed;
   submitButton.click();
 
   info("Ensure device 1 is still in device selector");
   deviceOption1 = [...deviceSelector.options].find(opt => opt.value == device1.name);
   ok(deviceOption1, "Test device 1 option exists");
 
   info("Ensure device 2 is no longer in device selector");
   deviceOption2 = [...deviceSelector.options].find(opt => opt.value == device2.name);
   ok(!deviceOption2, "Test device 2 option removed");
 });
 
-addRDMTask(TEST_URL, function* ({ ui }) {
+addRDMTask(TEST_URL, async function ({ ui }) {
   let { toolWindow } = ui;
   let { store, document } = toolWindow;
 
   // Wait until the viewport has been added and the device list has been loaded
-  yield waitUntilState(store, state => state.viewports.length == 1
+  await waitUntilState(store, state => state.viewports.length == 1
     && state.devices.listState == Types.deviceListState.LOADED);
 
   let deviceSelector = document.querySelector(".viewport-device-selector");
 
   info("Ensure device 1 is still in device selector");
   let deviceOption1 = [...deviceSelector.options].find(opt => opt.value == device1.name);
   ok(deviceOption1, "Test device 1 option exists");
 
--- a/devtools/client/responsive.html/test/browser/browser_device_modal_error.js
+++ b/devtools/client/responsive.html/test/browser/browser_device_modal_error.js
@@ -5,29 +5,29 @@ http://creativecommons.org/publicdomain/
 
 // Test to check that RDM can handle properly an error in the device list
 
 const TEST_URL = "data:text/html;charset=utf-8,";
 const Types = require("devtools/client/responsive.html/types");
 const { getStr } = require("devtools/client/responsive.html/utils/l10n");
 
 // Set a wrong URL for the device list file
-add_task(function* () {
-  yield SpecialPowers.pushPrefEnv({
+add_task(async function () {
+  await SpecialPowers.pushPrefEnv({
     set: [["devtools.devices.url", TEST_URI_ROOT + "wrong_devices_file.json"]],
   });
 });
 
-addRDMTask(TEST_URL, function* ({ ui }) {
+addRDMTask(TEST_URL, async function ({ ui }) {
   let { store, document } = ui.toolWindow;
   let select = document.querySelector(".viewport-device-selector");
 
   // Wait until the viewport has been added and the device list state indicates
   // an error
-  yield waitUntilState(store, state => state.viewports.length == 1
+  await waitUntilState(store, state => state.viewports.length == 1
     && state.devices.listState == Types.deviceListState.ERROR);
 
   // The device selector placeholder should be set accordingly
   let placeholder = select.options[select.selectedIndex].innerHTML;
   ok(placeholder == getStr("responsive.deviceListError"),
     "Device selector indicates an error");
 
   // The device selector should be disabled
--- a/devtools/client/responsive.html/test/browser/browser_device_modal_exit.js
+++ b/devtools/client/responsive.html/test/browser/browser_device_modal_exit.js
@@ -3,23 +3,23 @@ http://creativecommons.org/publicdomain/
 
 "use strict";
 
 // Test submitting display device changes on the device modal
 
 const TEST_URL = "data:text/html;charset=utf-8,";
 const Types = require("devtools/client/responsive.html/types");
 
-addRDMTask(TEST_URL, function* ({ ui }) {
+addRDMTask(TEST_URL, async function ({ ui }) {
   let { store, document } = ui.toolWindow;
   let modal = document.querySelector("#device-modal-wrapper");
   let closeButton = document.querySelector("#device-close-button");
 
   // Wait until the viewport has been added and the device list has been loaded
-  yield waitUntilState(store, state => state.viewports.length == 1
+  await waitUntilState(store, state => state.viewports.length == 1
     && state.devices.listState == Types.deviceListState.LOADED);
 
   openDeviceModal(ui);
 
   let preferredDevicesBefore = _loadPreferredDevices();
 
   info("Check the first unchecked device and exit the modal.");
   let uncheckedCb = [...document.querySelectorAll(".device-input-checkbox")]
--- a/devtools/client/responsive.html/test/browser/browser_device_modal_submit.js
+++ b/devtools/client/responsive.html/test/browser/browser_device_modal_submit.js
@@ -16,33 +16,33 @@ const addedDevice = {
   "firefoxOS": false,
   "os": "custom",
   "featured": true,
 };
 
 const TEST_URL = "data:text/html;charset=utf-8,";
 const Types = require("devtools/client/responsive.html/types");
 
-addRDMTask(TEST_URL, function* ({ ui }) {
+addRDMTask(TEST_URL, async function ({ ui }) {
   let { store, document } = ui.toolWindow;
   let modal = document.querySelector("#device-modal-wrapper");
   let select = document.querySelector(".viewport-device-selector");
   let submitButton = document.querySelector("#device-submit-button");
 
   // Wait until the viewport has been added and the device list has been loaded
-  yield waitUntilState(store, state => state.viewports.length == 1
+  await waitUntilState(store, state => state.viewports.length == 1
     && state.devices.listState == Types.deviceListState.LOADED);
 
   openDeviceModal(ui);
 
   info("Checking displayed device checkboxes are checked in the device modal.");
   let checkedCbs = [...document.querySelectorAll(".device-input-checkbox")]
     .filter(cb => cb.checked);
 
-  let remoteList = yield getDevices();
+  let remoteList = await getDevices();
 
   let featuredCount = remoteList.TYPES.reduce((total, type) => {
     return total + remoteList[type].reduce((subtotal, device) => {
       return subtotal + ((device.os != "fxos" && device.featured) ? 1 : 0);
     }, 0);
   }, 0);
 
   is(featuredCount, checkedCbs.length,
@@ -105,27 +105,27 @@ addRDMTask(TEST_URL, function* ({ ui }) 
   ok([...document.querySelectorAll(".device-input-checkbox")]
     .filter(cb => !cb.checked && cb.value === checkedVal)[0],
     checkedVal + " is unchecked in the device modal.");
 
   // Let's add a dummy device to simulate featured flag changes for next test
   addDeviceForTest(addedDevice);
 });
 
-addRDMTask(TEST_URL, function* ({ ui }) {
+addRDMTask(TEST_URL, async function ({ ui }) {
   let { store, document } = ui.toolWindow;
   let select = document.querySelector(".viewport-device-selector");
 
   // Wait until the viewport has been added and the device list has been loaded
-  yield waitUntilState(store, state => state.viewports.length == 1
+  await waitUntilState(store, state => state.viewports.length == 1
     && state.devices.listState == Types.deviceListState.LOADED);
 
   openDeviceModal(ui);
 
-  let remoteList = yield getDevices();
+  let remoteList = await getDevices();
   let featuredCount = remoteList.TYPES.reduce((total, type) => {
     return total + remoteList[type].reduce((subtotal, device) => {
       return subtotal + ((device.os != "fxos" && device.featured) ? 1 : 0);
     }, 0);
   }, 0);
   let preferredDevices = _loadPreferredDevices();
 
   // Tests to prove that reloading the RDM didn't break our device list
--- a/devtools/client/responsive.html/test/browser/browser_device_pixel_ratio_change.js
+++ b/devtools/client/responsive.html/test/browser/browser_device_pixel_ratio_change.js
@@ -19,88 +19,88 @@ const testDevice = {
   "firefoxOS": true,
   "os": "custom",
   "featured": true,
 };
 
 // Add the new device to the list
 addDeviceForTest(testDevice);
 
-addRDMTask(TEST_URL, function* ({ ui, manager }) {
-  yield waitStartup(ui);
+addRDMTask(TEST_URL, async function ({ ui, manager }) {
+  await waitStartup(ui);
 
-  yield testDefaults(ui);
-  yield testChangingDevice(ui);
-  yield testResetWhenResizingViewport(ui);
-  yield testChangingDevicePixelRatio(ui);
+  await testDefaults(ui);
+  await testChangingDevice(ui);
+  await testResetWhenResizingViewport(ui);
+  await testChangingDevicePixelRatio(ui);
 });
 
-function* waitStartup(ui) {
+async function waitStartup(ui) {
   let { store } = ui.toolWindow;
 
   // Wait until the viewport has been added and the device list has been loaded
-  yield waitUntilState(store, state => state.viewports.length == 1
+  await waitUntilState(store, state => state.viewports.length == 1
     && state.devices.listState == Types.deviceListState.LOADED);
 }
 
-function* testDefaults(ui) {
+async function testDefaults(ui) {
   info("Test Defaults");
 
-  yield testDevicePixelRatio(ui, window.devicePixelRatio);
+  await testDevicePixelRatio(ui, window.devicePixelRatio);
   testViewportDevicePixelRatioSelect(ui, {
     value: window.devicePixelRatio,
     disabled: false,
   });
   testViewportDeviceSelectLabel(ui, "no device selected");
 }
 
-function* testChangingDevice(ui) {
+async function testChangingDevice(ui) {
   info("Test Changing Device");
 
   let waitPixelRatioChange = onceDevicePixelRatioChange(ui);
 
-  yield selectDevice(ui, testDevice.name);
-  yield waitForViewportResizeTo(ui, testDevice.width, testDevice.height);
-  yield waitPixelRatioChange;
-  yield testDevicePixelRatio(ui, testDevice.pixelRatio);
+  await selectDevice(ui, testDevice.name);
+  await waitForViewportResizeTo(ui, testDevice.width, testDevice.height);
+  await waitPixelRatioChange;
+  await testDevicePixelRatio(ui, testDevice.pixelRatio);
   testViewportDevicePixelRatioSelect(ui, {
     value: testDevice.pixelRatio,
     disabled: true,
   });
   testViewportDeviceSelectLabel(ui, testDevice.name);
 }
 
-function* testResetWhenResizingViewport(ui) {
+async function testResetWhenResizingViewport(ui) {
   info("Test reset when resizing the viewport");
 
   let waitPixelRatioChange = onceDevicePixelRatioChange(ui);
 
   let deviceRemoved = once(ui, "device-association-removed");
-  yield testViewportResize(ui, ".viewport-vertical-resize-handle",
+  await testViewportResize(ui, ".viewport-vertical-resize-handle",
     [-10, -10], [testDevice.width, testDevice.height - 10], [0, -10], ui);
-  yield deviceRemoved;
+  await deviceRemoved;
 
-  yield waitPixelRatioChange;
-  yield testDevicePixelRatio(ui, window.devicePixelRatio);
+  await waitPixelRatioChange;
+  await testDevicePixelRatio(ui, window.devicePixelRatio);
 
   testViewportDevicePixelRatioSelect(ui, {
     value: window.devicePixelRatio,
     disabled: false,
   });
   testViewportDeviceSelectLabel(ui, "no device selected");
 }
 
-function* testChangingDevicePixelRatio(ui) {
+async function testChangingDevicePixelRatio(ui) {
   info("Test changing device pixel ratio");
 
   let waitPixelRatioChange = onceDevicePixelRatioChange(ui);
 
-  yield selectDevicePixelRatio(ui, VIEWPORT_DPPX);
-  yield waitPixelRatioChange;
-  yield testDevicePixelRatio(ui, VIEWPORT_DPPX);
+  await selectDevicePixelRatio(ui, VIEWPORT_DPPX);
+  await waitPixelRatioChange;
+  await testDevicePixelRatio(ui, VIEWPORT_DPPX);
   testViewportDevicePixelRatioSelect(ui, {
     value: VIEWPORT_DPPX,
     disabled: false,
   });
   testViewportDeviceSelectLabel(ui, "no device selected");
 }
 
 function testViewportDevicePixelRatioSelect(ui, expected) {
@@ -109,31 +109,25 @@ function testViewportDevicePixelRatioSel
   let select =
     ui.toolWindow.document.querySelector("#global-device-pixel-ratio-selector");
   is(select.value, expected.value,
      `DevicePixelRatio Select value should be: ${expected.value}`);
   is(select.disabled, expected.disabled,
     `DevicePixelRatio Select should be ${expected.disabled ? "disabled" : "enabled"}.`);
 }
 
-function* testDevicePixelRatio(ui, expected) {
+async function testDevicePixelRatio(ui, expected) {
   info("Test device pixel ratio");
 
-  let dppx = yield getViewportDevicePixelRatio(ui);
+  let dppx = await getViewportDevicePixelRatio(ui);
   is(dppx, expected, `devicePixelRatio should be: ${expected}`);
 }
 
-function* getViewportDevicePixelRatio(ui) {
-  return yield ContentTask.spawn(ui.getViewportBrowser(), {}, function* () {
-    return content.devicePixelRatio;
-  });
-}
-
 function onceDevicePixelRatioChange(ui) {
-  return ContentTask.spawn(ui.getViewportBrowser(), {}, function* () {
+  return ContentTask.spawn(ui.getViewportBrowser(), {}, async function () {
     info(`Listening for a pixel ratio change (current: ${content.devicePixelRatio}dppx)`);
 
     let pixelRatio = content.devicePixelRatio;
     let mql = content.matchMedia(`(resolution: ${pixelRatio}dppx)`);
 
     return new Promise(resolve => {
       const onWindowCreated = () => {
         if (pixelRatio !== content.devicePixelRatio) {
--- a/devtools/client/responsive.html/test/browser/browser_device_width.js
+++ b/devtools/client/responsive.html/test/browser/browser_device_width.js
@@ -1,104 +1,104 @@
 /* Any copyright is dedicated to the Public Domain.
 http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 const TEST_URL = "data:text/html;charset=utf-8,";
 
-addRDMTask(TEST_URL, function* ({ ui, manager }) {
+addRDMTask(TEST_URL, async function ({ ui, manager }) {
   ok(ui, "An instance of the RDM should be attached to the tab.");
-  yield setViewportSize(ui, manager, 110, 500);
+  await setViewportSize(ui, manager, 110, 500);
 
   info("Checking initial width/height properties.");
-  yield doInitialChecks(ui);
+  await doInitialChecks(ui);
 
   info("Changing the RDM size");
-  yield setViewportSize(ui, manager, 90, 500);
+  await setViewportSize(ui, manager, 90, 500);
 
   info("Checking for screen props");
-  yield checkScreenProps(ui);
+  await checkScreenProps(ui);
 
   info("Changing the RDM size using input keys");
-  yield setViewportSizeWithInputKeys(ui);
+  await setViewportSizeWithInputKeys(ui);
 
   info("Setting docShell.deviceSizeIsPageSize to false");
-  yield ContentTask.spawn(ui.getViewportBrowser(), {}, function* () {
+  await ContentTask.spawn(ui.getViewportBrowser(), {}, async function () {
     let docShell = content.QueryInterface(Ci.nsIInterfaceRequestor)
                           .getInterface(Ci.nsIWebNavigation)
                           .QueryInterface(Ci.nsIDocShell);
     docShell.deviceSizeIsPageSize = false;
   });
 
   info("Checking for screen props once again.");
-  yield checkScreenProps2(ui);
+  await checkScreenProps2(ui);
 });
 
-function* setViewportSizeWithInputKeys(ui) {
+async function setViewportSizeWithInputKeys(ui) {
   let width = 320, height = 500;
   let resized = waitForViewportResizeTo(ui, width, height);
   ui.setViewportSize({ width, height });
-  yield resized;
+  await resized;
 
   let dimensions = ui.toolWindow.document.querySelectorAll(".viewport-dimension-input");
 
   // Increase width value to 420 by using the Up arrow key
   resized = waitForViewportResizeTo(ui, 420, height);
   dimensions[0].focus();
   for (let i = 1; i <= 100; i++) {
     EventUtils.synthesizeKey("KEY_ArrowUp", { code: "ArrowUp" });
   }
-  yield resized;
+  await resized;
 
   // Resetting width value back to 320 using `Shift + Down` arrow
   resized = waitForViewportResizeTo(ui, width, height);
   dimensions[0].focus();
   for (let i = 1; i <= 10; i++) {
     EventUtils.synthesizeKey("KEY_ArrowDown", { shiftKey: true, code: "ArrowDown" });
   }
-  yield resized;
+  await resized;
 
   // Increase height value to 600 by using `PageUp + Shift` key
   resized = waitForViewportResizeTo(ui, width, 600);
   dimensions[1].focus();
   EventUtils.synthesizeKey("VK_PAGE_UP", { shiftKey: true });
-  yield resized;
+  await resized;
 
   // Resetting height value back to 500 by using `PageDown + Shift` key
   resized = waitForViewportResizeTo(ui, width, height);
   dimensions[1].focus();
   EventUtils.synthesizeKey("VK_PAGE_DOWN", { shiftKey: true });
-  yield resized;
+  await resized;
 }
 
-function* doInitialChecks(ui) {
-  let { innerWidth, matchesMedia } = yield grabContentInfo(ui);
+async function doInitialChecks(ui) {
+  let { innerWidth, matchesMedia } = await grabContentInfo(ui);
   is(innerWidth, 110, "initial width should be 110px");
   ok(!matchesMedia, "media query shouldn't match.");
 }
 
-function* checkScreenProps(ui) {
-  let { matchesMedia, screen } = yield grabContentInfo(ui);
+async function checkScreenProps(ui) {
+  let { matchesMedia, screen } = await grabContentInfo(ui);
   ok(matchesMedia, "media query should match");
   isnot(window.screen.width, screen.width,
         "screen.width should not be the size of the screen.");
   is(screen.width, 90, "screen.width should be the page width");
   is(screen.height, 500, "screen.height should be the page height");
 }
 
-function* checkScreenProps2(ui) {
-  let { matchesMedia, screen } = yield grabContentInfo(ui);
+async function checkScreenProps2(ui) {
+  let { matchesMedia, screen } = await grabContentInfo(ui);
   ok(!matchesMedia, "media query should be re-evaluated.");
   is(window.screen.width, screen.width,
      "screen.width should be the size of the screen.");
 }
 
 function grabContentInfo(ui) {
-  return ContentTask.spawn(ui.getViewportBrowser(), {}, function* () {
+  return ContentTask.spawn(ui.getViewportBrowser(), {}, async function () {
     return {
       screen: {
         width: content.screen.width,
         height: content.screen.height
       },
       innerWidth: content.innerWidth,
       matchesMedia: content.matchMedia("(max-device-width:100px)").matches
     };
--- a/devtools/client/responsive.html/test/browser/browser_exit_button.js
+++ b/devtools/client/responsive.html/test/browser/browser_exit_button.js
@@ -1,71 +1,71 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 const TEST_URL = "data:text/html;charset=utf-8,";
 
 // Test global exit button
-addRDMTask(TEST_URL, function* (...args) {
-  yield testExitButton(...args);
+addRDMTask(TEST_URL, async function (...args) {
+  await testExitButton(...args);
 });
 
 // Test global exit button on detached tab.
 // See Bug 1262806
-add_task(function* () {
-  let tab = yield addTab(TEST_URL);
-  let { ui, manager } = yield openRDM(tab);
+add_task(async function () {
+  let tab = await addTab(TEST_URL);
+  let { ui, manager } = await openRDM(tab);
 
-  yield waitBootstrap(ui);
+  await waitBootstrap(ui);
 
   let waitTabIsDetached = Promise.all([
     once(tab, "TabClose"),
     once(tab.linkedBrowser, "SwapDocShells")
   ]);
 
   // Detach the tab with RDM open.
   let newWindow = gBrowser.replaceTabWithWindow(tab);
 
   // Wait until the tab is detached and the new window is fully initialized.
-  yield waitTabIsDetached;
-  yield newWindow.delayedStartupPromise;
+  await waitTabIsDetached;
+  await newWindow.delayedStartupPromise;
 
   // Get the new tab instance.
   tab = newWindow.gBrowser.tabs[0];
 
   // Detaching a tab closes RDM.
   ok(!manager.isActiveForTab(tab),
     "Responsive Design Mode is not active for the tab");
 
   // Reopen the RDM and test the exit button again.
-  yield testExitButton(yield openRDM(tab));
-  yield BrowserTestUtils.closeWindow(newWindow);
+  await testExitButton(await openRDM(tab));
+  await BrowserTestUtils.closeWindow(newWindow);
 });
 
-function* waitBootstrap(ui) {
+async function waitBootstrap(ui) {
   let { toolWindow, tab } = ui;
   let { store } = toolWindow;
   let url = String(tab.linkedBrowser.currentURI.spec);
 
   // Wait until the viewport has been added.
-  yield waitUntilState(store, state => state.viewports.length == 1);
+  await waitUntilState(store, state => state.viewports.length == 1);
 
   // Wait until the document has been loaded.
-  yield waitForFrameLoad(ui, url);
+  await waitForFrameLoad(ui, url);
 }
 
-function* testExitButton({ui, manager}) {
-  yield waitBootstrap(ui);
+async function testExitButton({ui, manager}) {
+  await waitBootstrap(ui);
 
   let exitButton = ui.toolWindow.document.getElementById("global-exit-button");
 
   ok(manager.isActiveForTab(ui.tab),
     "Responsive Design Mode active for the tab");
 
   exitButton.click();
 
-  yield once(manager, "off");
+  await once(manager, "off");
 
   ok(!manager.isActiveForTab(ui.tab),
     "Responsive Design Mode is not active for the tab");
 }
--- a/devtools/client/responsive.html/test/browser/browser_frame_script_active.js
+++ b/devtools/client/responsive.html/test/browser/browser_frame_script_active.js
@@ -3,44 +3,44 @@
 
 "use strict";
 
 // Verify frame script is active when expected.
 
 const e10s = require("devtools/client/responsive.html/utils/e10s");
 
 const TEST_URL = "http://example.com/";
-add_task(function* () {
-  let tab = yield addTab(TEST_URL);
+add_task(async function () {
+  let tab = await addTab(TEST_URL);
 
-  let { ui } = yield openRDM(tab);
+  let { ui } = await openRDM(tab);
 
   let mm = ui.getViewportBrowser().messageManager;
-  let { active } = yield e10s.request(mm, "IsActive");
+  let { active } = await e10s.request(mm, "IsActive");
   is(active, true, "Frame script is active");
 
-  yield closeRDM(tab);
+  await closeRDM(tab);
 
   // Must re-get the messageManager on each run since it changes when RDM opens
   // or closes due to the design of swapFrameLoaders.  Also, we only have access
   // to a valid `ui` instance while RDM is open.
   mm = tab.linkedBrowser.messageManager;
-  ({ active } = yield e10s.request(mm, "IsActive"));
+  ({ active } = await e10s.request(mm, "IsActive"));
   is(active, false, "Frame script is active");
 
   // Try another round as well to be sure there is no state saved anywhere
-  ({ ui } = yield openRDM(tab));
+  ({ ui } = await openRDM(tab));
 
   mm = ui.getViewportBrowser().messageManager;
-  ({ active } = yield e10s.request(mm, "IsActive"));
+  ({ active } = await e10s.request(mm, "IsActive"));
   is(active, true, "Frame script is active");
 
-  yield closeRDM(tab);
+  await closeRDM(tab);
 
   // Must re-get the messageManager on each run since it changes when RDM opens
   // or closes due to the design of swapFrameLoaders.  Also, we only have access
   // to a valid `ui` instance while RDM is open.
   mm = tab.linkedBrowser.messageManager;
-  ({ active } = yield e10s.request(mm, "IsActive"));
+  ({ active } = await e10s.request(mm, "IsActive"));
   is(active, false, "Frame script is active");
 
-  yield removeTab(tab);
+  await removeTab(tab);
 });
--- a/devtools/client/responsive.html/test/browser/browser_hide_container.js
+++ b/devtools/client/responsive.html/test/browser/browser_hide_container.js
@@ -25,40 +25,40 @@ function flushContainerTabState(tab) {
   // During this test, we actually expect this to hang because the container tab
   // doesn't have the right epoch value to reply to the flush correctly.
   return new Promise(resolve => {
     TabStateFlusher.flush(outerBrowser).then(resolve);
     waitForTime(10000).then(resolve);
   });
 }
 
-add_task(function* () {
+add_task(async function () {
   // Load test URL
-  let tab = yield addTab(TEST_URL);
+  let tab = await addTab(TEST_URL);
   let browser = tab.linkedBrowser;
 
   // Check session history state
-  let history = yield getSessionHistory(browser);
+  let history = await getSessionHistory(browser);
   is(history.index - 1, 0, "At page 0 in history");
   is(history.entries.length, 1, "1 page in history");
   is(history.entries[0].url, TEST_URL, "Page 0 URL matches");
 
   // Open RDM
-  yield openRDM(tab);
+  await openRDM(tab);
 
   // Checking session history directly in content does show the container URL
   // that we're trying to hide...
-  history = yield getSessionHistory(browser);
+  history = await getSessionHistory(browser);
   is(history.index - 1, 0, "At page 0 in history");
   is(history.entries.length, 1, "1 page in history");
   is(history.entries[0].url, CONTAINER_URL, "Page 0 URL matches");
 
   // However, checking the recorded tab state for the outer browser shows the
   // container URL has been ignored correctly.
-  yield flushContainerTabState(tab);
+  await flushContainerTabState(tab);
   let tabState = JSON.parse(SessionStore.getTabState(tab));
   is(tabState.index - 1, 0, "At page 0 in history");
   is(tabState.entries.length, 1, "1 page in history");
   is(tabState.entries[0].url, TEST_URL, "Page 0 URL matches");
 
-  yield closeRDM(tab);
-  yield removeTab(tab);
+  await closeRDM(tab);
+  await removeTab(tab);
 });
--- a/devtools/client/responsive.html/test/browser/browser_menu_item_01.js
+++ b/devtools/client/responsive.html/test/browser/browser_menu_item_01.js
@@ -21,42 +21,42 @@ const activateTab = (tab) => new Promise
   gBrowser.selectedTab = tab;
 });
 
 const isMenuChecked = () => {
   let menu = document.getElementById("menu_responsiveUI");
   return menu.getAttribute("checked") === "true";
 };
 
-add_task(function* () {
-  yield startup(window);
+add_task(async function () {
+  await startup(window);
 
   ok(!isMenuChecked(),
     "RDM menu item is unchecked by default");
 
-  const tab = yield addTab(TEST_URL);
+  const tab = await addTab(TEST_URL);
 
   ok(!isMenuChecked(),
     "RDM menu item is unchecked for new tab");
 
-  yield openRDM(tab);
+  await openRDM(tab);
 
   ok(isMenuChecked(),
     "RDM menu item is checked with RDM open");
 
-  const tab2 = yield addTab(TEST_URL);
+  const tab2 = await addTab(TEST_URL);
 
   ok(!isMenuChecked(),
     "RDM menu item is unchecked for new tab");
 
-  yield activateTab(tab);
+  await activateTab(tab);
 
   ok(isMenuChecked(),
     "RDM menu item is checked for the tab where RDM is open");
 
-  yield closeRDM(tab);
+  await closeRDM(tab);
 
   ok(!isMenuChecked(),
     "RDM menu item is unchecked after RDM is closed");
 
-  yield removeTab(tab);
-  yield removeTab(tab2);
+  await removeTab(tab);
+  await removeTab(tab2);
 });
--- a/devtools/client/responsive.html/test/browser/browser_menu_item_02.js
+++ b/devtools/client/responsive.html/test/browser/browser_menu_item_02.js
@@ -7,41 +7,41 @@
 
 const TEST_URL = "data:text/html;charset=utf-8,";
 
 const isMenuCheckedFor = ({document}) => {
   let menu = document.getElementById("menu_responsiveUI");
   return menu.getAttribute("checked") === "true";
 };
 
-add_task(function* () {
-  const window1 = yield BrowserTestUtils.openNewBrowserWindow();
+add_task(async function () {
+  const window1 = await BrowserTestUtils.openNewBrowserWindow();
   let { gBrowser } = window1;
 
-  yield BrowserTestUtils.withNewTab({ gBrowser, url: TEST_URL },
-    function* (browser) {
+  await BrowserTestUtils.withNewTab({ gBrowser, url: TEST_URL },
+    async function (browser) {
       let tab = gBrowser.getTabForBrowser(browser);
 
       is(window1, Services.wm.getMostRecentWindow("navigator:browser"),
         "The new window is the active one");
 
       ok(!isMenuCheckedFor(window1),
         "RDM menu item is unchecked by default");
 
-      yield openRDM(tab);
+      await openRDM(tab);
 
       ok(isMenuCheckedFor(window1),
         "RDM menu item is checked with RDM open");
 
-      yield closeRDM(tab);
+      await closeRDM(tab);
 
       ok(!isMenuCheckedFor(window1),
         "RDM menu item is unchecked with RDM closed");
     });
 
-  yield BrowserTestUtils.closeWindow(window1);
+  await BrowserTestUtils.closeWindow(window1);
 
   is(window, Services.wm.getMostRecentWindow("navigator:browser"),
     "The original window is the active one");
 
   ok(!isMenuCheckedFor(window),
     "RDM menu item is unchecked");
 });
--- a/devtools/client/responsive.html/test/browser/browser_mouse_resize.js
+++ b/devtools/client/responsive.html/test/browser/browser_mouse_resize.js
@@ -1,27 +1,27 @@
 /* Any copyright is dedicated to the Public Domain.
 http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 const TEST_URL = "data:text/html;charset=utf-8,";
 
-addRDMTask(TEST_URL, function* ({ ui, manager }) {
+addRDMTask(TEST_URL, async function ({ ui, manager }) {
   let store = ui.toolWindow.store;
 
   // Wait until the viewport has been added
-  yield waitUntilState(store, state => state.viewports.length == 1);
+  await waitUntilState(store, state => state.viewports.length == 1);
 
-  yield setViewportSize(ui, manager, 300, 300);
+  await setViewportSize(ui, manager, 300, 300);
 
   // Do horizontal + vertical resize
-  yield testViewportResize(ui, ".viewport-resize-handle",
+  await testViewportResize(ui, ".viewport-resize-handle",
     [10, 10], [320, 310], [10, 10]);
 
   // Do horizontal resize
-  yield testViewportResize(ui, ".viewport-horizontal-resize-handle",
+  await testViewportResize(ui, ".viewport-horizontal-resize-handle",
     [-10, 10], [300, 310], [-10, 0]);
 
   // Do vertical resize
-  yield testViewportResize(ui, ".viewport-vertical-resize-handle",
+  await testViewportResize(ui, ".viewport-vertical-resize-handle",
     [-10, -10], [300, 300], [0, -10], ui);
 });
--- a/devtools/client/responsive.html/test/browser/browser_navigation.js
+++ b/devtools/client/responsive.html/test/browser/browser_navigation.js
@@ -5,61 +5,61 @@
 
 // Test the primary browser navigation UI to verify it's connected to the viewport.
 
 const DUMMY_1_URL = "http://example.com/";
 const TEST_URL = `${URL_ROOT}doc_page_state.html`;
 const DUMMY_2_URL = "http://example.com/browser/";
 const DUMMY_3_URL = "http://example.com/browser/devtools/";
 
-add_task(function* () {
+add_task(async function () {
   // Load up a sequence of pages:
   // 0. DUMMY_1_URL
   // 1. TEST_URL
   // 2. DUMMY_2_URL
-  let tab = yield addTab(DUMMY_1_URL);
+  let tab = await addTab(DUMMY_1_URL);
   let browser = tab.linkedBrowser;
-  yield load(browser, TEST_URL);
-  yield load(browser, DUMMY_2_URL);
+  await load(browser, TEST_URL);
+  await load(browser, DUMMY_2_URL);
 
   // Check session history state
-  let history = yield getSessionHistory(browser);
+  let history = await getSessionHistory(browser);
   is(history.index - 1, 2, "At page 2 in history");
   is(history.entries.length, 3, "3 pages in history");
   is(history.entries[0].url, DUMMY_1_URL, "Page 0 URL matches");
   is(history.entries[1].url, TEST_URL, "Page 1 URL matches");
   is(history.entries[2].url, DUMMY_2_URL, "Page 2 URL matches");
 
   // Go back one so we're at the test page
-  yield back(browser);
+  await back(browser);
 
   // Check session history state
-  history = yield getSessionHistory(browser);
+  history = await getSessionHistory(browser);
   is(history.index - 1, 1, "At page 1 in history");
   is(history.entries.length, 3, "3 pages in history");
   is(history.entries[0].url, DUMMY_1_URL, "Page 0 URL matches");
   is(history.entries[1].url, TEST_URL, "Page 1 URL matches");
   is(history.entries[2].url, DUMMY_2_URL, "Page 2 URL matches");
 
-  yield openRDM(tab);
+  await openRDM(tab);
 
   ok(browser.webNavigation.canGoBack, "Going back is allowed");
   ok(browser.webNavigation.canGoForward, "Going forward is allowed");
   is(browser.documentURI.spec, TEST_URL, "documentURI matches page 1");
   is(browser.contentTitle, "Page State Test", "contentTitle matches page 1");
 
-  yield forward(browser);
+  await forward(browser);
 
   ok(browser.webNavigation.canGoBack, "Going back is allowed");
   ok(!browser.webNavigation.canGoForward, "Going forward is not allowed");
   is(browser.documentURI.spec, DUMMY_2_URL, "documentURI matches page 2");
   is(browser.contentTitle, "mochitest index /browser/", "contentTitle matches page 2");
 
-  yield back(browser);
-  yield back(browser);
+  await back(browser);
+  await back(browser);
 
   ok(!browser.webNavigation.canGoBack, "Going back is not allowed");
   ok(browser.webNavigation.canGoForward, "Going forward is allowed");
   is(browser.documentURI.spec, DUMMY_1_URL, "documentURI matches page 0");
   is(browser.contentTitle, "mochitest index /", "contentTitle matches page 0");
 
   let receivedStatusChanges = new Promise(resolve => {
     let statusChangesSeen = 0;
@@ -71,28 +71,28 @@ add_task(function* () {
           gBrowser.removeProgressListener(progressListener);
           ok(true, `${statusChangesExpected} status changes while loading`);
           resolve();
         }
       }
     };
     gBrowser.addProgressListener(progressListener);
   });
-  yield load(browser, DUMMY_3_URL);
-  yield receivedStatusChanges;
+  await load(browser, DUMMY_3_URL);
+  await receivedStatusChanges;
 
   ok(browser.webNavigation.canGoBack, "Going back is allowed");
   ok(!browser.webNavigation.canGoForward, "Going forward is not allowed");
   is(browser.documentURI.spec, DUMMY_3_URL, "documentURI matches page 3");
   is(browser.contentTitle, "mochitest index /browser/devtools/",
      "contentTitle matches page 3");
 
-  yield closeRDM(tab);
+  await closeRDM(tab);
 
   // Check session history state
-  history = yield getSessionHistory(browser);
+  history = await getSessionHistory(browser);
   is(history.index - 1, 1, "At page 1 in history");
   is(history.entries.length, 2, "2 pages in history");
   is(history.entries[0].url, DUMMY_1_URL, "Page 0 URL matches");
   is(history.entries[1].url, DUMMY_3_URL, "Page 1 URL matches");
 
-  yield removeTab(tab);
+  await removeTab(tab);
 });
--- a/devtools/client/responsive.html/test/browser/browser_network_throttling.js
+++ b/devtools/client/responsive.html/test/browser/browser_network_throttling.js
@@ -3,54 +3,54 @@ http://creativecommons.org/publicdomain/
 
 "use strict";
 
 const throttlingProfiles = require("devtools/client/shared/network-throttling-profiles");
 
 // Tests changing network throttling
 const TEST_URL = "data:text/html;charset=utf-8,Network throttling test";
 
-addRDMTask(TEST_URL, function* ({ ui, manager }) {
+addRDMTask(TEST_URL, async function ({ ui, manager }) {
   let { store } = ui.toolWindow;
 
   // Wait until the viewport has been added
-  yield waitUntilState(store, state => state.viewports.length == 1);
+  await waitUntilState(store, state => state.viewports.length == 1);
 
   // Test defaults
   testNetworkThrottlingSelectorLabel(ui, "No throttling");
-  yield testNetworkThrottlingState(ui, null);
+  await testNetworkThrottlingState(ui, null);
 
   // Test a fast profile
-  yield testThrottlingProfile(ui, "Wi-Fi");
+  await testThrottlingProfile(ui, "Wi-Fi");
 
   // Test a slower profile
-  yield testThrottlingProfile(ui, "Regular 3G");
+  await testThrottlingProfile(ui, "Regular 3G");
 
   // Test switching back to no throttling
-  yield selectNetworkThrottling(ui, "No throttling");
+  await selectNetworkThrottling(ui, "No throttling");
   testNetworkThrottlingSelectorLabel(ui, "No throttling");
-  yield testNetworkThrottlingState(ui, null);
+  await testNetworkThrottlingState(ui, null);
 });
 
 function testNetworkThrottlingSelectorLabel(ui, expected) {
   let selector = "#global-network-throttling-selector";
   let select = ui.toolWindow.document.querySelector(selector);
   is(select.selectedOptions[0].textContent, expected,
     `Select label should be changed to ${expected}`);
 }
 
-var testNetworkThrottlingState = Task.async(function* (ui, expected) {
-  let state = yield ui.emulationFront.getNetworkThrottling();
+var testNetworkThrottlingState = async function (ui, expected) {
+  let state = await ui.emulationFront.getNetworkThrottling();
   Assert.deepEqual(state, expected, "Network throttling state should be " +
                                     JSON.stringify(expected, null, 2));
-});
+};
 
-var testThrottlingProfile = Task.async(function* (ui, profile) {
-  yield selectNetworkThrottling(ui, profile);
+var testThrottlingProfile = async function (ui, profile) {
+  await selectNetworkThrottling(ui, profile);
   testNetworkThrottlingSelectorLabel(ui, profile);
   let data = throttlingProfiles.find(({ id }) => id == profile);
   let { download, upload, latency } = data;
-  yield testNetworkThrottlingState(ui, {
+  await testNetworkThrottlingState(ui, {
     downloadThroughput: download,
     uploadThroughput: upload,
     latency,
   });
-});
+};
--- a/devtools/client/responsive.html/test/browser/browser_page_state.js
+++ b/devtools/client/responsive.html/test/browser/browser_page_state.js
@@ -5,72 +5,72 @@
 
 // Test page state to ensure page is not reloaded and session history is not
 // modified.
 
 const DUMMY_1_URL = "http://example.com/";
 const TEST_URL = `${URL_ROOT}doc_page_state.html`;
 const DUMMY_2_URL = "http://example.com/browser/";
 
-add_task(function* () {
+add_task(async function () {
   // Load up a sequence of pages:
   // 0. DUMMY_1_URL
   // 1. TEST_URL
   // 2. DUMMY_2_URL
-  let tab = yield addTab(DUMMY_1_URL);
+  let tab = await addTab(DUMMY_1_URL);
   let browser = tab.linkedBrowser;
-  yield load(browser, TEST_URL);
-  yield load(browser, DUMMY_2_URL);
+  await load(browser, TEST_URL);
+  await load(browser, DUMMY_2_URL);
 
   // Check session history state
-  let history = yield getSessionHistory(browser);
+  let history = await getSessionHistory(browser);
   is(history.index - 1, 2, "At page 2 in history");
   is(history.entries.length, 3, "3 pages in history");
   is(history.entries[0].url, DUMMY_1_URL, "Page 0 URL matches");
   is(history.entries[1].url, TEST_URL, "Page 1 URL matches");
   is(history.entries[2].url, DUMMY_2_URL, "Page 2 URL matches");
 
   // Go back one so we're at the test page
-  yield back(browser);
+  await back(browser);
 
   // Check session history state
-  history = yield getSessionHistory(browser);
+  history = await getSessionHistory(browser);
   is(history.index - 1, 1, "At page 1 in history");
   is(history.entries.length, 3, "3 pages in history");
   is(history.entries[0].url, DUMMY_1_URL, "Page 0 URL matches");
   is(history.entries[1].url, TEST_URL, "Page 1 URL matches");
   is(history.entries[2].url, DUMMY_2_URL, "Page 2 URL matches");
 
   // Click on content to set an altered state that would be lost on reload
-  yield BrowserTestUtils.synthesizeMouseAtCenter("body", {}, browser);
+  await BrowserTestUtils.synthesizeMouseAtCenter("body", {}, browser);
 
-  let { ui } = yield openRDM(tab);
+  let { ui } = await openRDM(tab);
 
   // Check color inside the viewport
-  let color = yield spawnViewportTask(ui, {}, function* () {
+  let color = await spawnViewportTask(ui, {}, function () {
     // eslint-disable-next-line mozilla/no-cpows-in-tests
     return content.getComputedStyle(content.document.body)
                   .getPropertyValue("background-color");
   });
   is(color, "rgb(0, 128, 0)",
      "Content is still modified from click in viewport");
 
-  yield closeRDM(tab);
+  await closeRDM(tab);
 
   // Check color back in the browser tab
-  color = yield ContentTask.spawn(browser, {}, function* () {
+  color = await ContentTask.spawn(browser, {}, async function () {
     // eslint-disable-next-line mozilla/no-cpows-in-tests
     return content.getComputedStyle(content.document.body)
                   .getPropertyValue("background-color");
   });
   is(color, "rgb(0, 128, 0)",
      "Content is still modified from click in browser tab");
 
   // Check session history state
-  history = yield getSessionHistory(browser);
+  history = await getSessionHistory(browser);
   is(history.index - 1, 1, "At page 1 in history");
   is(history.entries.length, 3, "3 pages in history");
   is(history.entries[0].url, DUMMY_1_URL, "Page 0 URL matches");
   is(history.entries[1].url, TEST_URL, "Page 1 URL matches");
   is(history.entries[2].url, DUMMY_2_URL, "Page 2 URL matches");
 
-  yield removeTab(tab);
+  await removeTab(tab);
 });
--- a/devtools/client/responsive.html/test/browser/browser_permission_doorhanger.js
+++ b/devtools/client/responsive.html/test/browser/browser_permission_doorhanger.js
@@ -15,39 +15,39 @@ function waitForGeolocationPrompt(win, b
       if (notification) {
         win.PopupNotifications.panel.removeEventListener("popupshown", popupShown);
         resolve();
       }
     });
   });
 }
 
-add_task(function* () {
-  let tab = yield addTab(DUMMY_URL);
+add_task(async function () {
+  let tab = await addTab(DUMMY_URL);
   let browser = tab.linkedBrowser;
   let win = browser.ownerGlobal;
 
   let waitPromptPromise = waitForGeolocationPrompt(win, browser);
 
   // Checks if a geolocation permission doorhanger appears when openning a page
   // requesting geolocation
-  yield load(browser, TEST_SURL);
-  yield waitPromptPromise;
+  await load(browser, TEST_SURL);
+  await waitPromptPromise;
 
   ok(true, "Permission doorhanger appeared without RDM enabled");
 
   // Lets switch back to the dummy website and enable RDM
-  yield load(browser, DUMMY_URL);
-  let { ui } = yield openRDM(tab);
+  await load(browser, DUMMY_URL);
+  let { ui } = await openRDM(tab);
   let newBrowser = ui.getViewportBrowser();
 
   waitPromptPromise = waitForGeolocationPrompt(win, newBrowser);
 
   // Checks if the doorhanger appeared again when reloading the geolocation
   // page inside RDM
-  yield load(browser, TEST_SURL);
-  yield waitPromptPromise;
+  await load(browser, TEST_SURL);
+  await waitPromptPromise;
 
   ok(true, "Permission doorhanger appeared inside RDM");
 
-  yield closeRDM(tab);
-  yield removeTab(tab);
+  await closeRDM(tab);
+  await removeTab(tab);
 });
--- a/devtools/client/responsive.html/test/browser/browser_resize_cmd.js
+++ b/devtools/client/responsive.html/test/browser/browser_resize_cmd.js
@@ -1,110 +1,110 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 /* global ResponsiveUIManager */
 /* eslint key-spacing: 0 */
 
-add_task(function* () {
+add_task(async function () {
   let manager = ResponsiveUIManager;
   let done;
 
   function isOpen() {
     return ResponsiveUIManager.isActiveForTab(gBrowser.selectedTab);
   }
 
   const TEST_URL = "data:text/html;charset=utf-8,hi";
-  yield helpers.addTabWithToolbar(TEST_URL, (options) => {
+  await helpers.addTabWithToolbar(TEST_URL, (options) => {
     return helpers.audit(options, [
       {
         setup() {
           done = once(manager, "on");
           return helpers.setInput(options, "resize toggle");
         },
         check: {
           input:  "resize toggle",
           hints:               "",
           markup: "VVVVVVVVVVVVV",
           status: "VALID"
         },
         exec: {
           output: ""
         },
-        post: Task.async(function* () {
-          yield done;
+        async post() {
+          await done;
           ok(isOpen(), "responsive mode is open");
-        }),
+        },
       },
       {
         setup() {
           done = once(manager, "off");
           return helpers.setInput(options, "resize toggle");
         },
         check: {
           input:  "resize toggle",
           hints:               "",
           markup: "VVVVVVVVVVVVV",
           status: "VALID"
         },
         exec: {
           output: ""
         },
-        post: Task.async(function* () {
-          yield done;
+        async post() {
+          await done;
           ok(!isOpen(), "responsive mode is closed");
-        }),
+        },
       },
     ]);
   });
-  yield helpers.addTabWithToolbar(TEST_URL, (options) => {
+  await helpers.addTabWithToolbar(TEST_URL, (options) => {
     return helpers.audit(options, [
       {
         setup() {
           done = once(manager, "on");
           return helpers.setInput(options, "resize on");
         },
         check: {
           input:  "resize on",
           hints:           "",
           markup: "VVVVVVVVV",
           status: "VALID"
         },
         exec: {
           output: ""
         },
-        post: Task.async(function* () {
-          yield done;
+        async post() {
+          await done;
           ok(isOpen(), "responsive mode is open");
-        }),
+        },
       },
       {
         setup() {
           done = once(manager, "off");
           return helpers.setInput(options, "resize off");
         },
         check: {
           input:  "resize off",
           hints:            "",
           markup: "VVVVVVVVVV",
           status: "VALID"
         },
         exec: {
           output: ""
         },
-        post: Task.async(function* () {
-          yield done;
+        async post() {
+          await done;
           ok(!isOpen(), "responsive mode is closed");
-        }),
+        },
       },
     ]);
   });
-  yield helpers.addTabWithToolbar(TEST_URL, (options) => {
+  await helpers.addTabWithToolbar(TEST_URL, (options) => {
     return helpers.audit(options, [
       {
         setup() {
           done = once(manager, "on");
           return helpers.setInput(options, "resize to 400 400");
         },
         check: {
           input:  "resize to 400 400",
@@ -114,35 +114,35 @@ add_task(function* () {
           args: {
             width: { value: 400 },
             height: { value: 400 },
           }
         },
         exec: {
           output: ""
         },
-        post: Task.async(function* () {
-          yield done;
+        async post() {
+          await done;
           ok(isOpen(), "responsive mode is open");
-        }),
+        },
       },
       {
         setup() {
           done = once(manager, "off");
           return helpers.setInput(options, "resize off");
         },
         check: {
           input:  "resize off",
           hints:            "",
           markup: "VVVVVVVVVV",
           status: "VALID"
         },
         exec: {
           output: ""
         },
-        post: Task.async(function* () {
-          yield done;
+        async post() {
+          await done;
           ok(!isOpen(), "responsive mode is closed");
-        }),
+        },
       },
     ]);
   });
 });
--- a/devtools/client/responsive.html/test/browser/browser_screenshot_button.js
+++ b/devtools/client/responsive.html/test/browser/browser_screenshot_button.js
@@ -4,56 +4,56 @@
 "use strict";
 
 // Test global exit button
 
 const TEST_URL = "data:text/html;charset=utf-8,";
 
 const { OS } = require("resource://gre/modules/osfile.jsm");
 
-function* waitUntilScreenshot() {
-  return new Promise(Task.async(function* (resolve) {
+function waitUntilScreenshot() {
+  return new Promise(async function (resolve) {
     let { Downloads } = require("resource://gre/modules/Downloads.jsm");
-    let list = yield Downloads.getList(Downloads.ALL);
+    let list = await Downloads.getList(Downloads.ALL);
 
     let view = {
       onDownloadAdded: download => {
         download.whenSucceeded().then(() => {
           resolve(download.target.path);
           list.removeView(view);
         });
       }
     };
 
-    yield list.addView(view);
-  }));
+    await list.addView(view);
+  });
 }
 
-addRDMTask(TEST_URL, function* ({ ui: {toolWindow} }) {
+addRDMTask(TEST_URL, async function ({ ui: {toolWindow} }) {
   let { store, document } = toolWindow;
 
   // Wait until the viewport has been added
-  yield waitUntilState(store, state => state.viewports.length == 1);
+  await waitUntilState(store, state => state.viewports.length == 1);
 
   info("Click the screenshot button");
   let screenshotButton = document.getElementById("global-screenshot-button");
   screenshotButton.click();
 
   let whenScreenshotSucceeded = waitUntilScreenshot();
 
-  let filePath = yield whenScreenshotSucceeded;
+  let filePath = await whenScreenshotSucceeded;
   let image = new Image();
   image.src = OS.Path.toFileURI(filePath);
 
-  yield once(image, "load");
+  await once(image, "load");
 
   // We have only one viewport at the moment
   let viewport = store.getState().viewports[0];
   let ratio = window.devicePixelRatio;
 
   is(image.width, viewport.width * ratio,
     "screenshot width has the expected width");
 
   is(image.height, viewport.height * ratio,
     "screenshot width has the expected height");
 
-  yield OS.File.remove(filePath);
+  await OS.File.remove(filePath);
 });
--- a/devtools/client/responsive.html/test/browser/browser_tab_close.js
+++ b/devtools/client/responsive.html/test/browser/browser_tab_close.js
@@ -2,42 +2,42 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // Verify RDM closes synchronously when tabs are closed.
 
 const TEST_URL = "http://example.com/";
 
-add_task(function* () {
-  let tab = yield addTab(TEST_URL);
+add_task(async function () {
+  let tab = await addTab(TEST_URL);
 
-  let { ui } = yield openRDM(tab);
+  let { ui } = await openRDM(tab);
   let clientClosed = waitForClientClose(ui);
 
   closeRDM(tab, {
     reason: "TabClose",
   });
 
   // This flag is set at the end of `ResponsiveUI.destroy`.  If it is true
-  // without yielding on `closeRDM` above, then we must have closed
+  // without waiting for `closeRDM` above, then we must have closed
   // synchronously.
   is(ui.destroyed, true, "RDM closed synchronously");
 
-  yield clientClosed;
-  yield removeTab(tab);
+  await clientClosed;
+  await removeTab(tab);
 });
 
-add_task(function* () {
-  let tab = yield addTab(TEST_URL);
+add_task(async function () {
+  let tab = await addTab(TEST_URL);
 
-  let { ui } = yield openRDM(tab);
+  let { ui } = await openRDM(tab);
   let clientClosed = waitForClientClose(ui);
 
-  yield removeTab(tab);
+  await removeTab(tab);
 
   // This flag is set at the end of `ResponsiveUI.destroy`.  If it is true without
-  // yielding on `closeRDM` itself and only removing the tab, then we must have closed
+  // waiting for `closeRDM` itself and only removing the tab, then we must have closed
   // synchronously in response to tab closing.
   is(ui.destroyed, true, "RDM closed synchronously");
 
-  yield clientClosed;
+  await clientClosed;
 });
--- a/devtools/client/responsive.html/test/browser/browser_tab_remoteness_change.js
+++ b/devtools/client/responsive.html/test/browser/browser_tab_remoteness_change.js
@@ -2,44 +2,44 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // Verify RDM closes synchronously when tabs change remoteness.
 
 const TEST_URL = "http://example.com/";
 
-add_task(function* () {
-  let tab = yield addTab(TEST_URL);
+add_task(async function () {
+  let tab = await addTab(TEST_URL);
 
-  let { ui } = yield openRDM(tab);
+  let { ui } = await openRDM(tab);
   let clientClosed = waitForClientClose(ui);
 
   closeRDM(tab, {
     reason: "BeforeTabRemotenessChange",
   });
 
   // This flag is set at the end of `ResponsiveUI.destroy`.  If it is true
-  // without yielding on `closeRDM` above, then we must have closed
+  // without waiting for `closeRDM` above, then we must have closed
   // synchronously.
   is(ui.destroyed, true, "RDM closed synchronously");
 
-  yield clientClosed;
-  yield removeTab(tab);
+  await clientClosed;
+  await removeTab(tab);
 });
 
-add_task(function* () {
-  let tab = yield addTab(TEST_URL);
+add_task(async function () {
+  let tab = await addTab(TEST_URL);
 
-  let { ui } = yield openRDM(tab);
+  let { ui } = await openRDM(tab);
   let clientClosed = waitForClientClose(ui);
 
   // Load URL that requires the main process, forcing a remoteness flip
-  yield load(tab.linkedBrowser, "about:robots");
+  await load(tab.linkedBrowser, "about:robots");
 
   // This flag is set at the end of `ResponsiveUI.destroy`.  If it is true without
-  // yielding on `closeRDM` itself and only removing the tab, then we must have closed
+  // waiting for `closeRDM` itself and only removing the tab, then we must have closed
   // synchronously in response to tab closing.
   is(ui.destroyed, true, "RDM closed synchronously");
 
-  yield clientClosed;
-  yield removeTab(tab);
+  await clientClosed;
+  await removeTab(tab);
 });
--- a/devtools/client/responsive.html/test/browser/browser_target_blank.js
+++ b/devtools/client/responsive.html/test/browser/browser_target_blank.js
@@ -5,24 +5,24 @@
 
 // Ensure target="_blank" link opens a new tab
 
 const TAB_URL = "http://example.com/";
 const TEST_URL =
   `data:text/html,<a href="${TAB_URL}" target="_blank">Click me</a>`
   .replace(/ /g, "%20");
 
-addRDMTask(TEST_URL, function* ({ ui }) {
+addRDMTask(TEST_URL, async function ({ ui }) {
   let store = ui.toolWindow.store;
 
   // Wait until the viewport has been added
-  yield waitUntilState(store, state => state.viewports.length == 1);
+  await waitUntilState(store, state => state.viewports.length == 1);
 
   // Click the target="_blank" link and wait for a new tab
-  yield waitForFrameLoad(ui, TEST_URL);
+  await waitForFrameLoad(ui, TEST_URL);
   let newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser, TAB_URL);
-  spawnViewportTask(ui, {}, function* () {
+  spawnViewportTask(ui, {}, function () {
     content.document.querySelector("a").click(); // eslint-disable-line
   });
-  let newTab = yield newTabPromise;
+  let newTab = await newTabPromise;
   ok(newTab, "New tab opened from link");
-  yield removeTab(newTab);
+  await removeTab(newTab);
 });
--- a/devtools/client/responsive.html/test/browser/browser_toolbox_computed_view.js
+++ b/devtools/client/responsive.html/test/browser/browser_toolbox_computed_view.js
@@ -13,47 +13,47 @@ const TEST_URI = "data:text/html;charset
                  "} " +
                  "@media screen and (max-width: 200px) {" +
                  "  div { " +
                  "    width: 100px;" +
                  "  }" +
                  "};" +
                  "</style><div></div></html>";
 
-addRDMTask(TEST_URI, function* ({ ui, manager }) {
+addRDMTask(TEST_URI, async function ({ ui, manager }) {
   info("Open the responsive design mode and set its size to 500x500 to start");
-  yield setViewportSize(ui, manager, 500, 500);
+  await setViewportSize(ui, manager, 500, 500);
 
   info("Open the inspector, computed-view and select the test node");
-  let { inspector, view } = yield openComputedView();
-  yield selectNode("div", inspector);
+  let { inspector, view } = await openComputedView();
+  await selectNode("div", inspector);
 
   info("Try shrinking the viewport and checking the applied styles");
-  yield testShrink(view, inspector, ui, manager);
+  await testShrink(view, inspector, ui, manager);
 
   info("Try growing the viewport and checking the applied styles");
-  yield testGrow(view, inspector, ui, manager);
+  await testGrow(view, inspector, ui, manager);
 
-  yield closeToolbox();
+  await closeToolbox();
 });
 
-function* testShrink(computedView, inspector, ui, manager) {
+async function testShrink(computedView, inspector, ui, manager) {
   is(computedWidth(computedView), "500px", "Should show 500px initially.");
 
   let onRefresh = inspector.once("computed-view-refreshed");
-  yield setViewportSize(ui, manager, 100, 100);
-  yield onRefresh;
+  await setViewportSize(ui, manager, 100, 100);
+  await onRefresh;
 
   is(computedWidth(computedView), "100px", "Should be 100px after shrinking.");
 }
 
-function* testGrow(computedView, inspector, ui, manager) {
+async function testGrow(computedView, inspector, ui, manager) {
   let onRefresh = inspector.once("computed-view-refreshed");
-  yield setViewportSize(ui, manager, 500, 500);
-  yield onRefresh;
+  await setViewportSize(ui, manager, 500, 500);
+  await onRefresh;
 
   is(computedWidth(computedView), "500px", "Should be 500px after growing.");
 }
 
 function computedWidth(computedView) {
   for (let prop of computedView.propertyViews) {
     if (prop.name === "width") {
       return prop.valueNode.textContent;
--- a/devtools/client/responsive.html/test/browser/browser_toolbox_rule_view.js
+++ b/devtools/client/responsive.html/test/browser/browser_toolbox_rule_view.js
@@ -13,62 +13,62 @@ const TEST_URI = "data:text/html;charset
                  "} " +
                  "@media screen and (max-width: 200px) {" +
                  "  div { " +
                  "    width: 100px;" +
                  "  }" +
                  "};" +
                  "</style><div></div></html>";
 
-addRDMTask(TEST_URI, function* ({ ui, manager }) {
+addRDMTask(TEST_URI, async function ({ ui, manager }) {
   info("Open the responsive design mode and set its size to 500x500 to start");
-  yield setViewportSize(ui, manager, 500, 500);
+  await setViewportSize(ui, manager, 500, 500);
 
   info("Open the inspector, rule-view and select the test node");
-  let { inspector, view } = yield openRuleView();
-  yield selectNode("div", inspector);
+  let { inspector, view } = await openRuleView();
+  await selectNode("div", inspector);
 
   info("Try shrinking the viewport and checking the applied styles");
-  yield testShrink(view, ui, manager);
+  await testShrink(view, ui, manager);
 
   info("Try growing the viewport and checking the applied styles");
-  yield testGrow(view, ui, manager);
+  await testGrow(view, ui, manager);
 
   info("Check that ESC still opens the split console");
-  yield testEscapeOpensSplitConsole(inspector);
+  await testEscapeOpensSplitConsole(inspector);
 
-  yield closeToolbox();
+  await closeToolbox();
 });
 
-function* testShrink(ruleView, ui, manager) {
+async function testShrink(ruleView, ui, manager) {
   is(numberOfRules(ruleView), 2, "Should have two rules initially.");
 
   info("Resize to 100x100 and wait for the rule-view to update");
   let onRefresh = ruleView.once("ruleview-refreshed");
-  yield setViewportSize(ui, manager, 100, 100);
-  yield onRefresh;
+  await setViewportSize(ui, manager, 100, 100);
+  await onRefresh;
 
   is(numberOfRules(ruleView), 3, "Should have three rules after shrinking.");
 }
 
-function* testGrow(ruleView, ui, manager) {
+async function testGrow(ruleView, ui, manager) {
   info("Resize to 500x500 and wait for the rule-view to update");
   let onRefresh = ruleView.once("ruleview-refreshed");
-  yield setViewportSize(ui, manager, 500, 500);
-  yield onRefresh;
+  await setViewportSize(ui, manager, 500, 500);
+  await onRefresh;
 
   is(numberOfRules(ruleView), 2, "Should have two rules after growing.");
 }
 
-function* testEscapeOpensSplitConsole(inspector) {
+async function testEscapeOpensSplitConsole(inspector) {
   ok(!inspector._toolbox._splitConsole, "Console is not split.");
 
   info("Press escape");
   let onSplit = inspector._toolbox.once("split-console");
   EventUtils.synthesizeKey("VK_ESCAPE", {});
-  yield onSplit;
+  await onSplit;
 
   ok(inspector._toolbox._splitConsole, "Console is split after pressing ESC.");
 }
 
 function numberOfRules(ruleView) {
   return ruleView.element.querySelectorAll(".ruleview-code").length;
 }
--- a/devtools/client/responsive.html/test/browser/browser_toolbox_swap_browsers.js
+++ b/devtools/client/responsive.html/test/browser/browser_toolbox_swap_browsers.js
@@ -4,119 +4,119 @@
 "use strict";
 
 // Verify that toolbox remains open when opening and closing RDM.
 
 const TEST_URL = "http://example.com/";
 
 function getServerConnections(browser) {
   ok(browser.isRemoteBrowser, "Content browser is remote");
-  return ContentTask.spawn(browser, {}, function* () {
+  return ContentTask.spawn(browser, {}, async function () {
     const Cu = Components.utils;
     const { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
     const { DebuggerServer } = require("devtools/server/main");
     if (!DebuggerServer._connections) {
       return 0;
     }
     return Object.getOwnPropertyNames(DebuggerServer._connections);
   });
 }
 
-let checkServerConnectionCount = Task.async(function* (browser, expected, msg) {
-  let conns = yield getServerConnections(browser);
+let checkServerConnectionCount = async function (browser, expected, msg) {
+  let conns = await getServerConnections(browser);
   is(conns.length || 0, expected, "Server connection count: " + msg);
-});
+};
 
-let checkToolbox = Task.async(function* (tab, location) {
+let checkToolbox = async function (tab, location) {
   let target = TargetFactory.forTab(tab);
   ok(!!gDevTools.getToolbox(target), `Toolbox exists ${location}`);
-});
+};
 
-add_task(function* () {
-  let tab = yield addTab(TEST_URL);
+add_task(async function () {
+  let tab = await addTab(TEST_URL);
 
   let tabsInDifferentProcesses = E10S_MULTI_ENABLED &&
     (gBrowser.tabs[0].linkedBrowser.frameLoader.childID !=
      gBrowser.tabs[1].linkedBrowser.frameLoader.childID);
 
   info("Open toolbox outside RDM");
   {
     // 0: No DevTools connections yet
-    yield checkServerConnectionCount(tab.linkedBrowser, 0,
+    await checkServerConnectionCount(tab.linkedBrowser, 0,
       "0: No DevTools connections yet");
-    let { toolbox } = yield openInspector();
+    let { toolbox } = await openInspector();
     if (tabsInDifferentProcesses) {
       // 1: Two tabs open, but only one per content process
-      yield checkServerConnectionCount(tab.linkedBrowser, 1,
+      await checkServerConnectionCount(tab.linkedBrowser, 1,
         "1: Two tabs open, but only one per content process");
     } else {
       // 2: One for each tab (starting tab plus the one we opened)
-      yield checkServerConnectionCount(tab.linkedBrowser, 2,
+      await checkServerConnectionCount(tab.linkedBrowser, 2,
         "2: One for each tab (starting tab plus the one we opened)");
     }
-    yield checkToolbox(tab, "outside RDM");
-    let { ui } = yield openRDM(tab);
+    await checkToolbox(tab, "outside RDM");
+    let { ui } = await openRDM(tab);
     if (tabsInDifferentProcesses) {
       // 2: RDM UI adds an extra connection, 1 + 1 = 2
-      yield checkServerConnectionCount(ui.getViewportBrowser(), 2,
+      await checkServerConnectionCount(ui.getViewportBrowser(), 2,
         "2: RDM UI uses an extra connection");
     } else {
       // 3: RDM UI adds an extra connection, 2 + 1 = 3
-      yield checkServerConnectionCount(ui.getViewportBrowser(), 3,
+      await checkServerConnectionCount(ui.getViewportBrowser(), 3,
         "3: RDM UI uses an extra connection");
     }
-    yield checkToolbox(tab, "after opening RDM");
-    yield closeRDM(tab);
+    await checkToolbox(tab, "after opening RDM");
+    await closeRDM(tab);
     if (tabsInDifferentProcesses) {
       // 1: RDM UI closed, return to previous connection count
-      yield checkServerConnectionCount(tab.linkedBrowser, 1,
+      await checkServerConnectionCount(tab.linkedBrowser, 1,
         "1: RDM UI closed, return to previous connection count");
     } else {
       // 2: RDM UI closed, return to previous connection count
-      yield checkServerConnectionCount(tab.linkedBrowser, 2,
+      await checkServerConnectionCount(tab.linkedBrowser, 2,
         "2: RDM UI closed, return to previous connection count");
     }
-    yield checkToolbox(tab, tab.linkedBrowser, "after closing RDM");
-    yield toolbox.destroy();
+    await checkToolbox(tab, tab.linkedBrowser, "after closing RDM");
+    await toolbox.destroy();
     // 0: All DevTools usage closed
-    yield checkServerConnectionCount(tab.linkedBrowser, 0,
+    await checkServerConnectionCount(tab.linkedBrowser, 0,
       "0: All DevTools usage closed");
   }
 
   info("Open toolbox inside RDM");
   {
     // 0: No DevTools connections yet
-    yield checkServerConnectionCount(tab.linkedBrowser, 0,
+    await checkServerConnectionCount(tab.linkedBrowser, 0,
       "0: No DevTools connections yet");
-    let { ui } = yield openRDM(tab);
+    let { ui } = await openRDM(tab);
     // 1: RDM UI uses an extra connection
-    yield checkServerConnectionCount(ui.getViewportBrowser(), 1,
+    await checkServerConnectionCount(ui.getViewportBrowser(), 1,
       "1: RDM UI uses an extra connection");
-    let { toolbox } = yield openInspector();
+    let { toolbox } = await openInspector();
     if (tabsInDifferentProcesses) {
       // 2: Two tabs open, but only one per content process
-      yield checkServerConnectionCount(ui.getViewportBrowser(), 2,
+      await checkServerConnectionCount(ui.getViewportBrowser(), 2,
         "2: Two tabs open, but only one per content process");
     } else {
       // 3: One for each tab (starting tab plus the one we opened)
-      yield checkServerConnectionCount(ui.getViewportBrowser(), 3,
+      await checkServerConnectionCount(ui.getViewportBrowser(), 3,
         "3: One for each tab (starting tab plus the one we opened)");
     }
-    yield checkToolbox(tab, ui.getViewportBrowser(), "inside RDM");
-    yield closeRDM(tab);
+    await checkToolbox(tab, ui.getViewportBrowser(), "inside RDM");
+    await closeRDM(tab);
     if (tabsInDifferentProcesses) {
       // 1: RDM UI closed, one less connection
-      yield checkServerConnectionCount(tab.linkedBrowser, 1,
+      await checkServerConnectionCount(tab.linkedBrowser, 1,
         "1: RDM UI closed, one less connection");
     } else {
       // 2: RDM UI closed, one less connection
-      yield checkServerConnectionCount(tab.linkedBrowser, 2,
+      await checkServerConnectionCount(tab.linkedBrowser, 2,
         "2: RDM UI closed, one less connection");
     }
-    yield checkToolbox(tab, tab.linkedBrowser, "after closing RDM");
-    yield toolbox.destroy();
+    await checkToolbox(tab, tab.linkedBrowser, "after closing RDM");
+    await toolbox.destroy();
     // 0: All DevTools usage closed
-    yield checkServerConnectionCount(tab.linkedBrowser, 0,
+    await checkServerConnectionCount(tab.linkedBrowser, 0,
       "0: All DevTools usage closed");
   }
 
-  yield removeTab(tab);
+  await removeTab(tab);
 });
--- a/devtools/client/responsive.html/test/browser/browser_touch_device.js
+++ b/devtools/client/responsive.html/test/browser/browser_touch_device.js
@@ -17,72 +17,72 @@ const testDevice = {
   "firefoxOS": true,
   "os": "custom",
   "featured": true,
 };
 
 // Add the new device to the list
 addDeviceForTest(testDevice);
 
-addRDMTask(TEST_URL, function* ({ ui, manager }) {
-  yield waitStartup(ui);
+addRDMTask(TEST_URL, async function ({ ui, manager }) {
+  await waitStartup(ui);
 
-  yield testDefaults(ui);
-  yield testChangingDevice(ui);
-  yield testResizingViewport(ui, true, false);
-  yield testEnableTouchSimulation(ui);
-  yield testResizingViewport(ui, false, true);
-  yield testDisableTouchSimulation(ui);
+  await testDefaults(ui);
+  await testChangingDevice(ui);
+  await testResizingViewport(ui, true, false);
+  await testEnableTouchSimulation(ui);
+  await testResizingViewport(ui, false, true);
+  await testDisableTouchSimulation(ui);
 });
 
-function* waitStartup(ui) {
+async function waitStartup(ui) {
   let { store } = ui.toolWindow;
 
   // Wait until the viewport has been added and the device list has been loaded
-  yield waitUntilState(store, state => state.viewports.length == 1
+  await waitUntilState(store, state => state.viewports.length == 1
     && state.devices.listState == Types.deviceListState.LOADED);
 }
 
-function* testDefaults(ui) {
+async function testDefaults(ui) {
   info("Test Defaults");
 
-  yield testTouchEventsOverride(ui, false);
+  await testTouchEventsOverride(ui, false);
   testViewportDeviceSelectLabel(ui, "no device selected");
 }
 
-function* testChangingDevice(ui) {
+async function testChangingDevice(ui) {
   info("Test Changing Device");
 
-  yield selectDevice(ui, testDevice.name);
-  yield waitForViewportResizeTo(ui, testDevice.width, testDevice.height);
-  yield testTouchEventsOverride(ui, true);
+  await selectDevice(ui, testDevice.name);
+  await waitForViewportResizeTo(ui, testDevice.width, testDevice.height);
+  await testTouchEventsOverride(ui, true);
   testViewportDeviceSelectLabel(ui, testDevice.name);
 }
 
-function* testResizingViewport(ui, device, touch) {
+async function testResizingViewport(ui, device, touch) {
   info(`Test resizing the viewport, device ${device}, touch ${touch}`);
 
   let deviceRemoved;
   if (device) {
     deviceRemoved = once(ui, "device-association-removed");
   }
-  yield testViewportResize(ui, ".viewport-vertical-resize-handle",
+  await testViewportResize(ui, ".viewport-vertical-resize-handle",
     [-10, -10], [testDevice.width, testDevice.height - 10], [0, -10], ui);
   if (device) {
-    yield deviceRemoved;
+    await deviceRemoved;
   }
-  yield testTouchEventsOverride(ui, touch);
+  await testTouchEventsOverride(ui, touch);
   testViewportDeviceSelectLabel(ui, "no device selected");
 }
 
-function* testEnableTouchSimulation(ui) {
+async function testEnableTouchSimulation(ui) {
   info("Test enabling touch simulation via button");
 
-  yield toggleTouchSimulation(ui);
-  yield testTouchEventsOverride(ui, true);
+  await toggleTouchSimulation(ui);
+  await testTouchEventsOverride(ui, true);
 }
 
-function* testDisableTouchSimulation(ui) {
+async function testDisableTouchSimulation(ui) {
   info("Test disabling touch simulation via button");
 
-  yield toggleTouchSimulation(ui);
-  yield testTouchEventsOverride(ui, false);
+  await toggleTouchSimulation(ui);
+  await testTouchEventsOverride(ui, false);
 }
--- a/devtools/client/responsive.html/test/browser/browser_touch_simulation.js
+++ b/devtools/client/responsive.html/test/browser/browser_touch_simulation.js
@@ -3,161 +3,161 @@
 
 "use strict";
 
 // Test global touch simulation button
 
 const TEST_URL = `${URL_ROOT}touch.html`;
 const PREF_DOM_META_VIEWPORT_ENABLED = "dom.meta-viewport.enabled";
 
-addRDMTask(TEST_URL, function* ({ ui }) {
-  yield injectEventUtilsInContentTask(ui.getViewportBrowser());
+addRDMTask(TEST_URL, async function ({ ui }) {
+  await injectEventUtilsInContentTask(ui.getViewportBrowser());
 
-  yield waitBootstrap(ui);
-  yield testWithNoTouch(ui);
-  yield toggleTouchSimulation(ui);
-  yield testWithTouch(ui);
-  yield testWithMetaViewportEnabled(ui);
-  yield testWithMetaViewportDisabled(ui);
+  await waitBootstrap(ui);
+  await testWithNoTouch(ui);
+  await toggleTouchSimulation(ui);
+  await testWithTouch(ui);
+  await testWithMetaViewportEnabled(ui);
+  await testWithMetaViewportDisabled(ui);
   testTouchButton(ui);
 });
 
-function* testWithNoTouch(ui) {
-  yield ContentTask.spawn(ui.getViewportBrowser(), {}, function* () {
+async function testWithNoTouch(ui) {
+  await ContentTask.spawn(ui.getViewportBrowser(), {}, async function () {
     let div = content.document.querySelector("div");
     let x = 0, y = 0;
 
     info("testWithNoTouch: Initial test parameter and mouse mouse outside div");
     x = -1; y = -1;
-    yield EventUtils.synthesizeMouse(div, x, y,
+    await EventUtils.synthesizeMouse(div, x, y,
           { type: "mousemove", isSynthesized: false }, content);
     div.style.transform = "none";
     div.style.backgroundColor = "";
 
     info("testWithNoTouch: Move mouse into the div element");
-    yield EventUtils.synthesizeMouseAtCenter(div,
+    await EventUtils.synthesizeMouseAtCenter(div,
           { type: "mousemove", isSynthesized: false }, content);
     is(div.style.backgroundColor, "red", "mouseenter or mouseover should work");
 
     info("testWithNoTouch: Drag the div element");
-    yield EventUtils.synthesizeMouseAtCenter(div,
+    await EventUtils.synthesizeMouseAtCenter(div,
           { type: "mousedown", isSynthesized: false }, content);
     x = 100; y = 100;
-    yield EventUtils.synthesizeMouse(div, x, y,
+    await EventUtils.synthesizeMouse(div, x, y,
           { type: "mousemove", isSynthesized: false }, content);
     is(div.style.transform, "none", "touchmove shouldn't work");
-    yield EventUtils.synthesizeMouse(div, x, y,
+    await EventUtils.synthesizeMouse(div, x, y,
           { type: "mouseup", isSynthesized: false }, content);
 
     info("testWithNoTouch: Move mouse out of the div element");
     x = -1; y = -1;
-    yield EventUtils.synthesizeMouse(div, x, y,
+    await EventUtils.synthesizeMouse(div, x, y,
           { type: "mousemove", isSynthesized: false }, content);
     is(div.style.backgroundColor, "blue", "mouseout or mouseleave should work");
 
     info("testWithNoTouch: Click the div element");
-    yield EventUtils.synthesizeClick(div);
+    await EventUtils.synthesizeClick(div);
     is(div.dataset.isDelay, "false",
       "300ms delay between touch events and mouse events should not work");
   });
 }
 
-function* testWithTouch(ui) {
-  yield ContentTask.spawn(ui.getViewportBrowser(), {}, function* () {
+async function testWithTouch(ui) {
+  await ContentTask.spawn(ui.getViewportBrowser(), {}, async function () {
     let div = content.document.querySelector("div");
     let x = 0, y = 0;
 
     info("testWithTouch: Initial test parameter and mouse mouse outside div");
     x = -1; y = -1;
-    yield EventUtils.synthesizeMouse(div, x, y,
+    await EventUtils.synthesizeMouse(div, x, y,
           { type: "mousemove", isSynthesized: false }, content);
     div.style.transform = "none";
     div.style.backgroundColor = "";
 
     info("testWithTouch: Move mouse into the div element");
-    yield EventUtils.synthesizeMouseAtCenter(div,
+    await EventUtils.synthesizeMouseAtCenter(div,
           { type: "mousemove", isSynthesized: false }, content);
     isnot(div.style.backgroundColor, "red",
       "mouseenter or mouseover should not work");
 
     info("testWithTouch: Drag the div element");
-    yield EventUtils.synthesizeMouseAtCenter(div,
+    await EventUtils.synthesizeMouseAtCenter(div,
           { type: "mousedown", isSynthesized: false }, content);
     x = 100; y = 100;
-    yield EventUtils.synthesizeMouse(div, x, y,
+    await EventUtils.synthesizeMouse(div, x, y,
           { type: "mousemove", isSynthesized: false }, content);
     isnot(div.style.transform, "none", "touchmove should work");
-    yield EventUtils.synthesizeMouse(div, x, y,
+    await EventUtils.synthesizeMouse(div, x, y,
           { type: "mouseup", isSynthesized: false }, content);
 
     info("testWithTouch: Move mouse out of the div element");
     x = -1; y = -1;
-    yield EventUtils.synthesizeMouse(div, x, y,
+    await EventUtils.synthesizeMouse(div, x, y,
           { type: "mousemove", isSynthesized: false }, content);
     isnot(div.style.backgroundColor, "blue",
       "mouseout or mouseleave should not work");
   });
 }
 
-function* testWithMetaViewportEnabled(ui) {
-  yield SpecialPowers.pushPrefEnv({set: [[PREF_DOM_META_VIEWPORT_ENABLED, true]]});
+async function testWithMetaViewportEnabled(ui) {
+  await SpecialPowers.pushPrefEnv({set: [[PREF_DOM_META_VIEWPORT_ENABLED, true]]});
 
-  yield ContentTask.spawn(ui.getViewportBrowser(), {}, function* () {
+  await ContentTask.spawn(ui.getViewportBrowser(), {}, async function () {
     let { synthesizeClick } = EventUtils;
 
     let meta = content.document.querySelector("meta[name=viewport]");
     let div = content.document.querySelector("div");
     div.dataset.isDelay = "false";
 
     info("testWithMetaViewportEnabled: " +
          "click the div element with <meta name='viewport'>");
     meta.content = "";
-    yield synthesizeClick(div);
+    await synthesizeClick(div);
     is(div.dataset.isDelay, "true",
       "300ms delay between touch events and mouse events should work");
 
     info("testWithMetaViewportEnabled: " +
          "click the div element with " +
          "<meta name='viewport' content='user-scalable=no'>");
     meta.content = "user-scalable=no";
-    yield synthesizeClick(div);
+    await synthesizeClick(div);
     is(div.dataset.isDelay, "false",
       "300ms delay between touch events and mouse events should not work");
 
     info("testWithMetaViewportEnabled: " +
          "click the div element with " +
          "<meta name='viewport' content='minimum-scale=maximum-scale'>");
     meta.content = "minimum-scale=maximum-scale";
-    yield synthesizeClick(div);
+    await synthesizeClick(div);
     is(div.dataset.isDelay, "false",
       "300ms delay between touch events and mouse events should not work");
 
     info("testWithMetaViewportEnabled: " +
          "click the div element with " +
          "<meta name='viewport' content='width=device-width'>");
     meta.content = "width=device-width";
-    yield synthesizeClick(div);
+    await synthesizeClick(div);
     is(div.dataset.isDelay, "false",
       "300ms delay between touch events and mouse events should not work");
   });
 }
 
-function* testWithMetaViewportDisabled(ui) {
-  yield SpecialPowers.pushPrefEnv({set: [[PREF_DOM_META_VIEWPORT_ENABLED, false]]});
+async function testWithMetaViewportDisabled(ui) {
+  await SpecialPowers.pushPrefEnv({set: [[PREF_DOM_META_VIEWPORT_ENABLED, false]]});
 
-  yield ContentTask.spawn(ui.getViewportBrowser(), {}, function* () {
+  await ContentTask.spawn(ui.getViewportBrowser(), {}, async function () {
     let { synthesizeClick } = EventUtils;
 
     let meta = content.document.querySelector("meta[name=viewport]");
     let div = content.document.querySelector("div");
     div.dataset.isDelay = "false";
 
     info("testWithMetaViewportDisabled: click the div with <meta name='viewport'>");
     meta.content = "";
-    yield synthesizeClick(div);
+    await synthesizeClick(div);
     is(div.dataset.isDelay, "true",
       "300ms delay between touch events and mouse events should work");
   });
 }
 
 function testTouchButton(ui) {
   let { document } = ui.toolWindow;
   let touchButton = document.querySelector("#global-touch-simulation-button");
@@ -171,14 +171,14 @@ function testTouchButton(ui) {
     "Touch simulation is stopped on click.");
 
   touchButton.click();
 
   ok(touchButton.classList.contains("checked"),
     "Touch simulation is started on click.");
 }
 
-function* waitBootstrap(ui) {
+async function waitBootstrap(ui) {
   let { store } = ui.toolWindow;
 
-  yield waitUntilState(store, state => state.viewports.length == 1);
-  yield waitForFrameLoad(ui, TEST_URL);
+  await waitUntilState(store, state => state.viewports.length == 1);
+  await waitForFrameLoad(ui, TEST_URL);
 }
--- a/devtools/client/responsive.html/test/browser/browser_viewport_basics.js
+++ b/devtools/client/responsive.html/test/browser/browser_viewport_basics.js
@@ -2,29 +2,29 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // Test viewports basics after opening, like size and location
 
 const TEST_URL = "http://example.org/";
 
-addRDMTask(TEST_URL, function* ({ ui }) {
+addRDMTask(TEST_URL, async function ({ ui }) {
   let store = ui.toolWindow.store;
 
   // Wait until the viewport has been added
-  yield waitUntilState(store, state => state.viewports.length == 1);
+  await waitUntilState(store, state => state.viewports.length == 1);
 
   // A single viewport of default size appeared
   let viewport = ui.toolWindow.document.querySelector(".viewport-content");
 
   is(ui.toolWindow.getComputedStyle(viewport).getPropertyValue("width"),
      "320px", "Viewport has default width");
   is(ui.toolWindow.getComputedStyle(viewport).getPropertyValue("height"),
      "480px", "Viewport has default height");
 
   // Browser's location should match original tab
-  yield waitForFrameLoad(ui, TEST_URL);
-  let location = yield spawnViewportTask(ui, {}, function* () {
+  await waitForFrameLoad(ui, TEST_URL);
+  let location = await spawnViewportTask(ui, {}, function () {
     return content.location.href; // eslint-disable-line
   });
   is(location, TEST_URL, "Viewport location matches");
 });
--- a/devtools/client/responsive.html/test/browser/browser_window_close.js
+++ b/devtools/client/responsive.html/test/browser/browser_window_close.js
@@ -1,25 +1,25 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
-add_task(function* () {
+add_task(async function () {
   let newWindowPromise = BrowserTestUtils.waitForNewWindow();
   window.open("data:text/html;charset=utf-8,", "_blank");
-  let newWindow = yield newWindowPromise;
+  let newWindow = await newWindowPromise;
 
   newWindow.focus();
-  yield BrowserTestUtils.browserLoaded(newWindow.gBrowser.selectedBrowser);
+  await BrowserTestUtils.browserLoaded(newWindow.gBrowser.selectedBrowser);
 
   let tab = newWindow.gBrowser.selectedTab;
-  yield openRDM(tab);
+  await openRDM(tab);
 
   // Close the window on a tab with an active responsive design UI and
   // wait for the UI to gracefully shutdown.  This has leaked the window
   // in the past.
   ok(ResponsiveUIManager.isActiveForTab(tab),
      "ResponsiveUI should be active for tab when the window is closed");
   let offPromise = once(ResponsiveUIManager, "off");
-  yield BrowserTestUtils.closeWindow(newWindow);
-  yield offPromise;
+  await BrowserTestUtils.closeWindow(newWindow);
+  await offPromise;
 });
--- a/devtools/client/responsive.html/test/browser/head.js
+++ b/devtools/client/responsive.html/test/browser/head.js
@@ -60,82 +60,82 @@ registerCleanupFunction(async () => {
   await removeLocalDevices();
 });
 
 loader.lazyRequireGetter(this, "ResponsiveUIManager", "devtools/client/responsive.html/manager", true);
 
 /**
  * Open responsive design mode for the given tab.
  */
-var openRDM = Task.async(function* (tab) {
+var openRDM = async function (tab) {
   info("Opening responsive design mode");
   let manager = ResponsiveUIManager;
-  let ui = yield manager.openIfNeeded(tab.ownerGlobal, tab);
+  let ui = await manager.openIfNeeded(tab.ownerGlobal, tab);
   info("Responsive design mode opened");
   return { ui, manager };
-});
+};
 
 /**
  * Close responsive design mode for the given tab.
  */
-var closeRDM = Task.async(function* (tab, options) {
+var closeRDM = async function (tab, options) {
   info("Closing responsive design mode");
   let manager = ResponsiveUIManager;
-  yield manager.closeIfNeeded(tab.ownerGlobal, tab, options);
+  await manager.closeIfNeeded(tab.ownerGlobal, tab, options);
   info("Responsive design mode closed");
-});
+};
 
 /**
  * Adds a new test task that adds a tab with the given URL, opens responsive
  * design mode, runs the given generator, closes responsive design mode, and
  * removes the tab.
  *
  * Example usage:
  *
- *   addRDMTask(TEST_URL, function*({ ui, manager }) {
+ *   addRDMTask(TEST_URL, async function ({ ui, manager }) {
  *     // Your tests go here...
  *   });
  */
-function addRDMTask(url, generator) {
-  add_task(function* () {
-    const tab = yield addTab(url);
-    const results = yield openRDM(tab);
+function addRDMTask(url, task) {
+  add_task(async function () {
+    const tab = await addTab(url);
+    const results = await openRDM(tab);
 
     try {
-      yield* generator(results);
+      await task(results);
     } catch (err) {
       ok(false, "Got an error: " + DevToolsUtils.safeErrorString(err));
     }
 
-    yield closeRDM(tab);
-    yield removeTab(tab);
+    await closeRDM(tab);
+    await removeTab(tab);
   });
 }
 
 function spawnViewportTask(ui, args, task) {
   return ContentTask.spawn(ui.getViewportBrowser(), args, task);
 }
 
 function waitForFrameLoad(ui, targetURL) {
-  return spawnViewportTask(ui, { targetURL }, function* (args) {
+  return spawnViewportTask(ui, { targetURL }, async function (args) {
     if ((content.document.readyState == "complete" ||
          content.document.readyState == "interactive") &&
         content.location.href == args.targetURL) {
       return;
     }
-    yield ContentTaskUtils.waitForEvent(this, "DOMContentLoaded");
+    await ContentTaskUtils.waitForEvent(this, "DOMContentLoaded");
   });
 }
 
 function waitForViewportResizeTo(ui, width, height) {
-  return new Promise(Task.async(function* (resolve) {
+  return new Promise(async function (resolve) {
     let isSizeMatching = (data) => data.width == width && data.height == height;
 
     // If the viewport has already the expected size, we resolve the promise immediately.
-    let size = yield getContentSize(ui);
+    let size = await getContentSize(ui);
     if (isSizeMatching(size)) {
       resolve();
       return;
     }
 
     // Otherwise, we'll listen to both content's resize event and browser's load end;
     // since a racing condition can happen, where the content's listener is added after
     // the resize, because the content's document was reloaded; therefore the test would
@@ -147,38 +147,44 @@ function waitForViewportResizeTo(ui, wid
         return;
       }
       ui.off("content-resize", onResize);
       browser.removeEventListener("mozbrowserloadend", onBrowserLoadEnd);
       info(`Got content-resize to ${width} x ${height}`);
       resolve();
     };
 
-    let onBrowserLoadEnd = Task.async(function* () {
-      let data = yield getContentSize(ui);
+    let onBrowserLoadEnd = async function () {
+      let data = await getContentSize(ui);
       onResize(undefined, data);
-    });
+    };
 
     info(`Waiting for content-resize to ${width} x ${height}`);
     ui.on("content-resize", onResize);
     browser.addEventListener("mozbrowserloadend",
       onBrowserLoadEnd, { once: true });
-  }));
+  });
 }
 
-var setViewportSize = Task.async(function* (ui, manager, width, height) {
+var setViewportSize = async function (ui, manager, width, height) {
   let size = ui.getViewportSize();
   info(`Current size: ${size.width} x ${size.height}, ` +
        `set to: ${width} x ${height}`);
   if (size.width != width || size.height != height) {
     let resized = waitForViewportResizeTo(ui, width, height);
     ui.setViewportSize({ width, height });
-    yield resized;
+    await resized;
   }
-});
+};
+
+function getViewportDevicePixelRatio(ui) {
+  return ContentTask.spawn(ui.getViewportBrowser(), {}, async function () {
+    return content.devicePixelRatio;
+  });
+}
 
 function getElRect(selector, win) {
   let el = win.document.querySelector(selector);
   return el.getBoundingClientRect();
 }
 
 /**
  * Drag an element identified by 'selector' by [x,y] amount. Returns
@@ -201,22 +207,22 @@ function dragElementBy(selector, x, y, w
 
   // mousemove and mouseup are regular DOM listeners
   EventUtils.synthesizeMouseAtPoint(...endPoint, { type: "mousemove" }, win);
   EventUtils.synthesizeMouseAtPoint(...endPoint, { type: "mouseup" }, win);
 
   return rect;
 }
 
-function* testViewportResize(ui, selector, moveBy,
+async function testViewportResize(ui, selector, moveBy,
                              expectedViewportSize, expectedHandleMove) {
   let win = ui.toolWindow;
   let resized = waitForViewportResizeTo(ui, ...expectedViewportSize);
   let startRect = dragElementBy(selector, ...moveBy, win);
-  yield resized;
+  await resized;
 
   let endRect = getElRect(selector, win);
   is(endRect.left - startRect.left, expectedHandleMove[0],
     `The x move of ${selector} is as expected`);
   is(endRect.top - startRect.top, expectedHandleMove[1],
     `The y move of ${selector} is as expected`);
 }
 
@@ -264,17 +270,17 @@ const selectDevicePixelRatio = (ui, valu
   changeSelectValue(ui, "#global-device-pixel-ratio-selector", value);
 
 const selectNetworkThrottling = (ui, value) => Promise.all([
   once(ui, "network-throttling-changed"),
   changeSelectValue(ui, "#global-network-throttling-selector", value)
 ]);
 
 function getSessionHistory(browser) {
-  return ContentTask.spawn(browser, {}, function* () {
+  return ContentTask.spawn(browser, {}, async function () {
     /* eslint-disable no-undef */
     let { utils: Cu } = Components;
     const { SessionHistory } =
       Cu.import("resource://gre/modules/sessionstore/SessionHistory.jsm", {});
     return SessionHistory.collect(docShell);
     /* eslint-enable no-undef */
   });
 }
@@ -333,50 +339,50 @@ function addDeviceForTest(device) {
 }
 
 async function waitForClientClose(ui) {
   info("Waiting for RDM debugger client to close");
   await ui.client.addOneTimeListener("closed");
   info("RDM's debugger client is now closed");
 }
 
-function* testTouchEventsOverride(ui, expected) {
+async function testTouchEventsOverride(ui, expected) {
   let { document } = ui.toolWindow;
   let touchButton = document.querySelector("#global-touch-simulation-button");
 
-  let flag = yield ui.emulationFront.getTouchEventsOverride();
+  let flag = await ui.emulationFront.getTouchEventsOverride();
   is(flag === Ci.nsIDocShell.TOUCHEVENTS_OVERRIDE_ENABLED, expected,
     `Touch events override should be ${expected ? "enabled" : "disabled"}`);
   is(touchButton.classList.contains("checked"), expected,
     `Touch simulation button should be ${expected ? "" : "in"}active.`);
 }
 
 function testViewportDeviceSelectLabel(ui, expected) {
   info("Test viewport's device select label");
 
   let select = ui.toolWindow.document.querySelector(".viewport-device-selector");
   is(select.selectedOptions[0].textContent, expected,
      `Device Select value should be: ${expected}`);
 }
 
-function* toggleTouchSimulation(ui) {
+async function toggleTouchSimulation(ui) {
   let { document } = ui.toolWindow;
   let touchButton = document.querySelector("#global-touch-simulation-button");
   let changed = once(ui, "touch-simulation-changed");
   let loaded = waitForViewportLoad(ui);
   touchButton.click();
-  yield Promise.all([ changed, loaded ]);
+  await Promise.all([ changed, loaded ]);
 }
 
 function testUserAgent(ui, expected) {
   testUserAgentFromBrowser(ui.getViewportBrowser(), expected);
 }
 
 async function testUserAgentFromBrowser(browser, expected) {
-  let ua = await ContentTask.spawn(browser, {}, function* () {
+  let ua = await ContentTask.spawn(browser, {}, async function () {
     return content.navigator.userAgent;
   });
   is(ua, expected, `UA should be set to ${expected}`);
 }
 
 /**
  * Assuming the device modal is open and the device adder form is shown, this helper
  * function adds `device` via the form, saves it, and waits for it to appear in the store.
--- a/devtools/client/responsive.html/test/unit/head.js
+++ b/devtools/client/responsive.html/test/unit/head.js
@@ -4,17 +4,16 @@
 "use strict";
 
 /* eslint no-unused-vars: [2, {"vars": "local"}] */
 
 const { utils: Cu } = Components;
 const { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
 
 const promise = require("promise");
-const { Task } = require("devtools/shared/task");
 const Store = require("devtools/client/responsive.html/store");
 
 const DevToolsUtils = require("devtools/shared/DevToolsUtils");
 
 const flags = require("devtools/shared/flags");
 flags.testing = true;
 registerCleanupFunction(() => {
   flags.testing = false;
--- a/devtools/client/responsive.html/test/unit/test_add_device.js
+++ b/devtools/client/responsive.html/test/unit/test_add_device.js
@@ -5,17 +5,17 @@
 
 // Test adding a new device.
 
 const {
   addDevice,
   addDeviceType,
 } = require("devtools/client/responsive.html/actions/devices");
 
-add_task(function* () {
+add_task(async function () {
   let store = Store();
   const { getState, dispatch } = store;
 
   let device = {
     "name": "Firefox OS Flame",
     "width": 320,
     "height": 570,
     "pixelRatio": 1.5,
--- a/devtools/client/responsive.html/test/unit/test_add_device_type.js
+++ b/devtools/client/responsive.html/test/unit/test_add_device_type.js
@@ -3,17 +3,17 @@
 
 "use strict";
 
 // Test adding a new device type.
 
 const { addDeviceType } =
   require("devtools/client/responsive.html/actions/devices");
 
-add_task(function* () {
+add_task(async function () {
   let store = Store();
   const { getState, dispatch } = store;
 
   dispatch(addDeviceType("phones"));
 
   equal(getState().devices.types.length, 1, "Correct number of device types");
   equal(getState().devices.phones.length, 0,
     "Defaults to an empty array of phones");
--- a/devtools/client/responsive.html/test/unit/test_add_viewport.js
+++ b/devtools/client/responsive.html/test/unit/test_add_viewport.js
@@ -3,17 +3,17 @@
 
 "use strict";
 
 // Test adding viewports to the page.
 
 const { addViewport } =
   require("devtools/client/responsive.html/actions/viewports");
 
-add_task(function* () {
+add_task(async function () {
   let store = Store();
   const { getState, dispatch } = store;
 
   equal(getState().viewports.length, 0, "Defaults to no viewpots at startup");
 
   dispatch(addViewport());
   equal(getState().viewports.length, 1, "One viewport total");
 
--- a/devtools/client/responsive.html/test/unit/test_change_device.js
+++ b/devtools/client/responsive.html/test/unit/test_change_device.js
@@ -9,17 +9,17 @@ const {
   addDevice,
   addDeviceType,
 } = require("devtools/client/responsive.html/actions/devices");
 const {
   addViewport,
   changeDevice,
 } = require("devtools/client/responsive.html/actions/viewports");
 
-add_task(function* () {
+add_task(async function () {
   let store = Store();
   const { getState, dispatch } = store;
 
   dispatch(addDeviceType("phones"));
   dispatch(addDevice({
     "name": "Firefox OS Flame",
     "width": 320,
     "height": 570,
--- a/devtools/client/responsive.html/test/unit/test_change_display_pixel_ratio.js
+++ b/devtools/client/responsive.html/test/unit/test_change_display_pixel_ratio.js
@@ -4,17 +4,17 @@
 "use strict";
 
 // Test changing the display pixel ratio.
 
 const { changeDisplayPixelRatio } =
   require("devtools/client/responsive.html/actions/display-pixel-ratio");
 const NEW_PIXEL_RATIO = 5.5;
 
-add_task(function* () {
+add_task(async function () {
   let store = Store();
   const { getState, dispatch } = store;
 
   equal(getState().displayPixelRatio, 0,
         "Defaults to 0 at startup");
 
   dispatch(changeDisplayPixelRatio(NEW_PIXEL_RATIO));
   equal(getState().displayPixelRatio, NEW_PIXEL_RATIO,
--- a/devtools/client/responsive.html/test/unit/test_change_location.js
+++ b/devtools/client/responsive.html/test/unit/test_change_location.js
@@ -5,17 +5,17 @@
 
 // Test changing the location of the displayed page.
 
 const { changeLocation } =
   require("devtools/client/responsive.html/actions/location");
 
 const TEST_URL = "http://example.com";
 
-add_task(function* () {
+add_task(async function () {
   let store = Store();
   const { getState, dispatch } = store;
 
   equal(getState().location, "about:blank",
         "Defaults to about:blank at startup");
 
   dispatch(changeLocation(TEST_URL));
   equal(getState().location, TEST_URL, "Location changed to TEST_URL");
--- a/devtools/client/responsive.html/test/unit/test_change_network_throttling.js
+++ b/devtools/client/responsive.html/test/unit/test_change_network_throttling.js
@@ -4,17 +4,17 @@
 "use strict";
 
 // Test changing the network throttling state
 
 const {
   changeNetworkThrottling,
 } = require("devtools/client/responsive.html/actions/network-throttling");
 
-add_task(function* () {
+add_task(async function () {
   let store = Store();
   const { getState, dispatch } = store;
 
   ok(!getState().networkThrottling.enabled,
     "Network throttling is disabled by default.");
   equal(getState().networkThrottling.profile, "",
     "Network throttling profile is empty by default.");
 
--- a/devtools/client/responsive.html/test/unit/test_change_pixel_ratio.js
+++ b/devtools/client/responsive.html/test/unit/test_change_pixel_ratio.js
@@ -4,17 +4,17 @@
 "use strict";
 
 // Test changing the viewport pixel ratio.
 
 const { addViewport, changePixelRatio } =
   require("devtools/client/responsive.html/actions/viewports");
 const NEW_PIXEL_RATIO = 5.5;
 
-add_task(function* () {
+add_task(async function () {
   let store = Store();
   const { getState, dispatch } = store;
 
   dispatch(addViewport());
   dispatch(changePixelRatio(0, NEW_PIXEL_RATIO));
 
   let viewport = getState().viewports[0];
   equal(viewport.pixelRatio.value, NEW_PIXEL_RATIO,
--- a/devtools/client/responsive.html/test/unit/test_resize_viewport.js
+++ b/devtools/client/responsive.html/test/unit/test_resize_viewport.js
@@ -3,17 +3,17 @@
 
 "use strict";
 
 // Test resizing the viewport.
 
 const { addViewport, resizeViewport } =
   require("devtools/client/responsive.html/actions/viewports");
 
-add_task(function* () {
+add_task(async function () {
   let store = Store();
   const { getState, dispatch } = store;
 
   dispatch(addViewport());
   dispatch(resizeViewport(0, 500, 500));
 
   let viewport = getState().viewports[0];
   equal(viewport.width, 500, "Resized width of 500");
--- a/devtools/client/responsive.html/test/unit/test_rotate_viewport.js
+++ b/devtools/client/responsive.html/test/unit/test_rotate_viewport.js
@@ -3,17 +3,17 @@
 
 "use strict";
 
 // Test rotating the viewport.
 
 const { addViewport, rotateViewport } =
   require("devtools/client/responsive.html/actions/viewports");
 
-add_task(function* () {
+add_task(async function () {
   let store = Store();
   const { getState, dispatch } = store;
 
   dispatch(addViewport());
 
   let viewport = getState().viewports[0];
   equal(viewport.width, 320, "Default width of 320");
   equal(viewport.height, 480, "Default height of 480");
--- a/devtools/client/responsive.html/test/unit/test_update_device_displayed.js
+++ b/devtools/client/responsive.html/test/unit/test_update_device_displayed.js
@@ -6,17 +6,17 @@
 // Test updating the device `displayed` property
 
 const {
   addDevice,
   addDeviceType,
   updateDeviceDisplayed,
 } = require("devtools/client/responsive.html/actions/devices");
 
-add_task(function* () {
+add_task(async function () {
   let store = Store();
   const { getState, dispatch } = store;
 
   let device = {
     "name": "Firefox OS Flame",
     "width": 320,
     "height": 570,
     "pixelRatio": 1.5,
--- a/devtools/client/responsive.html/test/unit/test_update_touch_simulation_enabled.js
+++ b/devtools/client/responsive.html/test/unit/test_update_touch_simulation_enabled.js
@@ -4,17 +4,17 @@
 "use strict";
 
 // Test updating the touch simulation `enabled` property
 
 const {
   changeTouchSimulation,
 } = require("devtools/client/responsive.html/actions/touch-simulation");
 
-add_task(function* () {
+add_task(async function () {
   let store = Store();
   const { getState, dispatch } = store;
 
   ok(!getState().touchSimulation.enabled,
     "Touch simulation is disabled by default.");
 
   dispatch(changeTouchSimulation(true));
 
--- a/devtools/client/shared/components/splitter/SplitBox.js
+++ b/devtools/client/shared/components/splitter/SplitBox.js
@@ -135,27 +135,24 @@ class SplitBox extends Component {
 
   /**
    * Adjust size of the controlled panel. Depending on the current
    * orientation we either remember the width or height of
    * the splitter box.
    */
   onMove(x, y) {
     const node = ReactDOM.findDOMNode(this);
-    const doc = node.ownerDocument;
-    const win = doc.defaultView;
 
     let size;
     let { endPanelControl } = this.props;
 
     if (this.state.vert) {
       // Switch the control flag in case of RTL. Note that RTL
       // has impact on vertical splitter only.
-      let dir = win.getComputedStyle(doc.documentElement).direction;
-      if (dir == "rtl") {
+      if (document.dir === "rtl") {
         endPanelControl = !endPanelControl;
       }
 
       size = endPanelControl ?
         (node.offsetLeft + node.offsetWidth) - x :
         x - node.offsetLeft;
 
       this.setState({
--- a/devtools/client/webconsole/new-console-output/new-console-output-wrapper.js
+++ b/devtools/client/webconsole/new-console-output/new-console-output-wrapper.js
@@ -216,41 +216,45 @@ NewConsoleOutputWrapper.prototype = {
           sideBar
         ));
       this.body = ReactDOM.render(provider, this.parentNode);
 
       this.jsterm.focus();
     });
   },
 
-  dispatchMessageAdd: function (message, waitForResponse) {
+  dispatchMessageAdd: function (packet, waitForResponse) {
     // Wait for the message to render to resolve with the DOM node.
     // This is just for backwards compatibility with old tests, and should
     // be removed once it's not needed anymore.
     // Can only wait for response if the action contains a valid message.
     let promise;
     // Also, do not expect any update while the panel is in background.
     if (waitForResponse && document.visibilityState === "visible") {
+      const timeStampToMatch = packet.message
+        ? packet.message.timeStamp
+        : packet.timestamp;
+
       promise = new Promise(resolve => {
         let jsterm = this.jsterm;
         jsterm.hud.on("new-messages", function onThisMessage(e, messages) {
           for (let m of messages) {
-            if (m.timeStamp === message.timestamp) {
+            if (m.timeStamp === timeStampToMatch) {
               resolve(m.node);
               jsterm.hud.off("new-messages", onThisMessage);
               return;
             }
           }
         });
       });
     } else {
       promise = Promise.resolve();
     }
 
-    this.batchedMessagesAdd(message);
+    this.batchedMessagesAdd(packet);
     return promise;
   },
 
   dispatchMessagesAdd: function (messages) {
     store.dispatch(actions.messagesAdd(messages));
   },
 
   dispatchMessagesClear: function () {
--- a/devtools/client/webconsole/new-console-output/test/mochitest/browser.ini
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/browser.ini
@@ -373,17 +373,16 @@ skip-if = true #	Bug 1404359
 skip-if = true #	Bug 1405647
 [browser_webconsole_split_focus.js]
 skip-if = true #	Bug 1405648
 [browser_webconsole_split_persist.js]
 skip-if = true #	Bug 1405649
 [browser_webconsole_stacktrace_location_debugger_link.js]
 [browser_webconsole_stacktrace_location_scratchpad_link.js]
 [browser_webconsole_strict_mode_errors.js]
-skip-if = true #	Bug 1406039
 [browser_webconsole_string.js]
 [browser_webconsole_time_methods.js]
 skip-if = true #	Bug 1404877
 [browser_webconsole_timestamps.js]
 [browser_webconsole_trackingprotection_errors.js]
 tags = trackingprotection
 skip-if = true #	Bug 1405650
 # old console skip-if = (os == 'win' && bits == 64) # Bug 1390001
--- a/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_console_group.js
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_console_group.js
@@ -26,63 +26,116 @@ add_task(async function () {
           parameters: message.parameters,
           messageText: message.messageText
         });
         return res;
       }, []);
     info("messages : " + JSON.stringify(messages));
   });
 
+  const onMessagesLogged = waitForMessage(hud, "log-6");
   ContentTask.spawn(gBrowser.selectedBrowser, null, function () {
     content.wrappedJSObject.doLog();
   });
+  await onMessagesLogged;
 
   info("Test a group at root level");
-  let node = await waitFor(() => findMessage(hud, "group-1"));
+  let node = findMessage(hud, "group-1");
   testClass(node, "startGroup");
   testIndent(node, 0);
+  await testGroupToggle({
+    node,
+    store,
+    shouldBeOpen: true,
+    visibleMessageIdsAfterExpand: ["1","2","3","4","6","8","9","12"],
+    visibleMessageIdsAfterCollapse: ["1","8","9","12"],
+  });
 
   info("Test a message in a 1 level deep group");
-  node = await waitFor(() => findMessage(hud, "log-1"), undefined, 200);
+  node = findMessage(hud, "log-1");
   testClass(node, "log");
   testIndent(node, 1);
 
   info("Test a group in a 1 level deep group");
-  node = await waitFor(() => findMessage(hud, "group-2"));
+  node = findMessage(hud, "group-2");
   testClass(node, "startGroup");
   testIndent(node, 1);
+  await testGroupToggle({
+    node,
+    store,
+    shouldBeOpen: true,
+    visibleMessageIdsAfterExpand: ["1","2","3","4","6","8","9","12"],
+    visibleMessageIdsAfterCollapse: ["1","2","3","6","8","9","12"],
+  });
 
   info("Test a message in a 2 level deep group");
-  node = await waitFor(() => findMessage(hud, "log-2"));
+  node = findMessage(hud, "log-2");
   testClass(node, "log");
   testIndent(node, 2);
 
   info("Test a message in a 1 level deep group, after closing a 2 level deep group");
-  node = await waitFor(() => findMessage(hud, "log-3"));
+  node = findMessage(hud, "log-3");
   testClass(node, "log");
   testIndent(node, 1);
 
   info("Test a message at root level, after closing all the groups");
-  node = await waitFor(() => findMessage(hud, "log-4"));
+  node = findMessage(hud, "log-4");
   testClass(node, "log");
   testIndent(node, 0);
 
   info("Test a collapsed group at root level");
-  node = await waitFor(() => findMessage(hud, "group-3"));
+  node = findMessage(hud, "group-3");
   testClass(node, "startGroupCollapsed");
   testIndent(node, 0);
+  await testGroupToggle({
+    node,
+    store,
+    shouldBeOpen: false,
+    visibleMessageIdsAfterExpand: ["1","2","3","4","6","8","9","10","12"],
+    visibleMessageIdsAfterCollapse: ["1","2","3","4","6","8","9","12"]
+  });
+
   info("Test a message at root level, after closing a collapsed group");
-  node = await waitFor(() => findMessage(hud, "log-6"));
+  node = findMessage(hud, "log-6");
   testClass(node, "log");
   testIndent(node, 0);
   let nodes = hud.ui.outputNode.querySelectorAll(".message");
   is(nodes.length, 8, "expected number of messages are displayed");
 });
 
 function testClass(node, className) {
   ok(node.classList.contains(className), `message has the expected "${className}" class`);
 }
 
 function testIndent(node, indent) {
   indent = `${indent * INDENT_WIDTH}px`;
   is(node.querySelector(".indent").style.width, indent,
     "message has the expected level of indentation");
 }
+
+async function testGroupToggle({
+  node,
+  store,
+  shouldBeOpen,
+  visibleMessageIdsAfterExpand,
+  visibleMessageIdsAfterCollapse
+}) {
+  let toggleArrow = node.querySelector(".theme-twisty");
+  const isOpen = node => node.classList.contains("open");
+  const assertVisibleMessageIds = (expanded) => {
+    let visibleMessageIds = store.getState().messages.visibleMessages;
+    expanded ? is(visibleMessageIds.toString(), visibleMessageIdsAfterExpand.toString()) :
+      is(visibleMessageIds.toString(), visibleMessageIdsAfterCollapse.toString());
+  }
+
+  await waitFor(() => isOpen(node) === shouldBeOpen)
+  assertVisibleMessageIds(shouldBeOpen);
+
+  toggleArrow.click();
+  shouldBeOpen = !shouldBeOpen;
+  await waitFor(() => isOpen(node) === shouldBeOpen)
+  assertVisibleMessageIds(shouldBeOpen);
+
+  toggleArrow.click();
+  shouldBeOpen = !shouldBeOpen;
+  await waitFor(() => isOpen(node) === shouldBeOpen)
+  assertVisibleMessageIds(shouldBeOpen);
+}
\ No newline at end of file
--- a/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_strict_mode_errors.js
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_strict_mode_errors.js
@@ -2,82 +2,39 @@
 /* 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/ */
 
 // Check that "use strict" JS errors generate errors, not warnings.
 
 "use strict";
 
-add_task(function* () {
+add_task(async function () {
+  let hud = await openNewTabAndConsole("data:text/html;charset=utf8,empty page");
+
+  loadScriptURI("'use strict';var arguments;");
+  await waitForError(hud,
+    "SyntaxError: 'arguments' can't be defined or assigned to in strict mode code");
+
+  loadScriptURI("'use strict';function f(a, a) {};");
+  await waitForError(hud, "SyntaxError: duplicate formal argument a");
+
+  loadScriptURI("'use strict';var o = {get p() {}};o.p = 1;");
+  await waitForError(hud, 'TypeError: setting getter-only property "p"');
+
+  loadScriptURI("'use strict';v = 1;");
+  await waitForError(hud, "ReferenceError: assignment to undeclared variable v");
+});
+
+async function waitForError(hud, text) {
+  await waitFor(() => findMessage(hud, text, ".message.error"));
+  ok(true, "Received expected error message");
+}
+
+function loadScriptURI(script) {
   // On e10s, the exception is triggered in child process
   // and is ignored by test harness
   if (!Services.appinfo.browserTabsRemoteAutostart) {
     expectUncaughtException();
   }
-  yield loadTab("data:text/html;charset=utf8,<script>'use strict';var arguments;</script>");
-
-  let hud = yield openConsole();
-
-  yield waitForMessages({
-    webconsole: hud,
-    messages: [
-      {
-        text: "SyntaxError: 'arguments' can't be defined or assigned to in strict mode code",
-        category: CATEGORY_JS,
-        severity: SEVERITY_ERROR,
-      },
-    ],
-  });
-
-  if (!Services.appinfo.browserTabsRemoteAutostart) {
-    expectUncaughtException();
-  }
-  BrowserTestUtils.loadURI(gBrowser.selectedBrowser, "data:text/html;charset="
-    + "utf8,<script>'use strict';function f(a, a) {};</script>");
-
-  yield waitForMessages({
-    webconsole: hud,
-    messages: [
-      {
-        text: "SyntaxError: duplicate formal argument a",
-        category: CATEGORY_JS,
-        severity: SEVERITY_ERROR,
-      },
-    ],
-  });
-
-  if (!Services.appinfo.browserTabsRemoteAutostart) {
-    expectUncaughtException();
-  }
-  BrowserTestUtils.loadURI(gBrowser.selectedBrowser, "data:text/html;charset="
-    + "utf8,<script>'use strict';var o = {get p() {}};o.p = 1;</script>");
-
-  yield waitForMessages({
-    webconsole: hud,
-    messages: [
-      {
-        text: 'TypeError: setting getter-only property "p"',
-        category: CATEGORY_JS,
-        severity: SEVERITY_ERROR,
-      },
-    ],
-  });
-
-  if (!Services.appinfo.browserTabsRemoteAutostart) {
-    expectUncaughtException();
-  }
-  BrowserTestUtils.loadURI(gBrowser.selectedBrowser,
-    "data:text/html;charset=utf8,<script>'use strict';v = 1;</script>");
-
-  yield waitForMessages({
-    webconsole: hud,
-    messages: [
-      {
-        text: "ReferenceError: assignment to undeclared variable v",
-        category: CATEGORY_JS,
-        severity: SEVERITY_ERROR,
-      },
-    ],
-  });
-
-  hud = null;
-});
+  let uri = "data:text/html;charset=utf8,<script>" + script + "</script>";
+  BrowserTestUtils.loadURI(gBrowser.selectedBrowser, uri);
+}
--- a/devtools/client/webide/content/runtimedetails.js
+++ b/devtools/client/webide/content/runtimedetails.js
@@ -135,17 +135,17 @@ function EnableCertApps() {
   let device = AppManager.selectedRuntime.device;
   // TODO: Remove `network.disable.ipc.security` once bug 1125916 is fixed.
   device.shell(
     "stop b2g && " +
     "cd /data/b2g/mozilla/*.default/ && " +
     "echo 'user_pref(\"devtools.debugger.forbid-certified-apps\", false);' >> prefs.js && " +
     "echo 'user_pref(\"dom.apps.developer_mode\", true);' >> prefs.js && " +
     "echo 'user_pref(\"network.disable.ipc.security\", true);' >> prefs.js && " +
-    "echo 'user_pref(\"dom.webcomponents.enabled\", true);' >> prefs.js && " +
+    "echo 'user_pref(\"dom.webcomponents.shadowdom.enabled\", true);' >> prefs.js && " +
     "start b2g"
   );
 }
 
 function RootADB() {
   let device = AppManager.selectedRuntime.device;
   device.summonRoot().then(CheckLockState, console.error);
 }
--- a/devtools/server/actors/highlighters/css-grid.js
+++ b/devtools/server/actors/highlighters/css-grid.js
@@ -1460,18 +1460,18 @@ class CssGridHighlighter extends AutoRef
     // It also clear the <canvas>'s drawing context.
     updateCanvasElement(this.canvas, this._canvasPosition, this.win.devicePixelRatio);
 
     // Clear the grid area highlights.
     this.clearGridAreas();
     this.clearGridCell();
 
     // Update the current matrix used in our canvas' rendering.
-    let { currentMatrix, hasNodeTransformations } = getCurrentMatrix(this.currentNode,
-      this.win);
+    let { currentMatrix, hasNodeTransformations } =
+      getCurrentMatrix(this.currentNode, this.win);
     this.currentMatrix = currentMatrix;
     this.hasNodeTransformations = hasNodeTransformations;
 
     // Start drawing the grid fragments.
     for (let i = 0; i < this.gridData.length; i++) {
       this.renderFragment(this.gridData[i]);
     }
 
--- a/devtools/server/actors/highlighters/utils/canvas.js
+++ b/devtools/server/actors/highlighters/utils/canvas.js
@@ -1,20 +1,25 @@
 /* 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 Services = require("Services");
+const DevToolsUtils = require("devtools/shared/DevToolsUtils");
+
 const {
   apply,
   getNodeTransformationMatrix,
   identity,
   isIdentity,
   multiply,
+  reflectAboutY,
+  rotate,
   scale,
   translate,
 } = require("devtools/shared/layout/dom-matrix-2d");
 const { getViewportDimensions } = require("devtools/shared/layout/utils");
 
 // A set of utility functions for highlighters that render their content to a <canvas>
 // element.
 
@@ -33,16 +38,21 @@ const { getViewportDimensions } = requir
 // the displayport API instead.
 //
 // Using a fixed value should also solve bug 1348293.
 const CANVAS_SIZE = 4096;
 
 // The default color used for the canvas' font, fill and stroke colors.
 const DEFAULT_COLOR = "#9400FF";
 
+// Boolean pref to enable adjustment for writing mode and RTL content.
+DevToolsUtils.defineLazyGetter(this, "WRITING_MODE_ADJUST_ENABLED", () => {
+  return Services.prefs.getBoolPref("devtools.highlighter.writingModeAdjust");
+});
+
 /**
  * Draws a rect to the context given and applies a transformation matrix if passed.
  * The coordinates are the start and end points of the rectangle's diagonal.
  *
  * @param  {CanvasRenderingContext2D} ctx
  *         The 2D canvas context.
  * @param  {Number} x1
  *         The x-axis coordinate of the rectangle's diagonal start point.
@@ -258,16 +268,18 @@ function getBoundsFromPoints(points) {
  * following transformations, in this order:
  *   1. The scale given by the display pixel ratio.
  *   2. The translation to the top left corner of the element.
  *   3. The scale given by the current zoom.
  *   4. The translation given by the top and left padding of the element.
  *   5. Any CSS transformation applied directly to the element (only 2D
  *      transformation; the 3D transformation are flattened, see `dom-matrix-2d` module
  *      for further details.)
+ *   6. Rotate, translate, and reflect as needed to match the writing mode and text
+ *      direction of the element.
  *
  *  The transformations of the element's ancestors are not currently computed (see
  *  bug 1355675).
  *
  * @param  {Element} element
  *         The current element.
  * @param  {Window} window
  *         The window object.
@@ -285,32 +297,40 @@ function getCurrentMatrix(element, windo
   let borderTop = parseFloat(computedStyle.borderTopWidth);
   let borderLeft = parseFloat(computedStyle.borderLeftWidth);
 
   let nodeMatrix = getNodeTransformationMatrix(element, window.document.documentElement);
 
   let currentMatrix = identity();
   let hasNodeTransformations = false;
 
-  // First, we scale based on the device pixel ratio.
+  // Scale based on the device pixel ratio.
   currentMatrix = multiply(currentMatrix, scale(window.devicePixelRatio));
 
-  // Then, we apply the current node's transformation matrix, relative to the
-  // inspected window's root element, but only if it's not a identity matrix.
+  // Apply the current node's transformation matrix, relative to the inspected window's
+  // root element, but only if it's not a identity matrix.
   if (isIdentity(nodeMatrix)) {
     hasNodeTransformations = false;
   } else {
     currentMatrix = multiply(currentMatrix, nodeMatrix);
     hasNodeTransformations = true;
   }
 
-  // Finally, we translate the origin based on the node's padding and border values.
+  // Translate the origin based on the node's padding and border values.
   currentMatrix = multiply(currentMatrix,
     translate(paddingLeft + borderLeft, paddingTop + borderTop));
 
+  if (WRITING_MODE_ADJUST_ENABLED) {
+    // Adjust as needed to match the writing mode and text direction of the element.
+    let writingModeMatrix = getWritingModeMatrix(element, computedStyle);
+    if (!isIdentity(writingModeMatrix)) {
+      currentMatrix = multiply(currentMatrix, writingModeMatrix);
+    }
+  }
+
   return { currentMatrix, hasNodeTransformations };
 }
 
 /**
  * Given an array of four points, returns a string represent a path description.
  *
  * @param  {Array} points
  *         An array with 4 pointer objects {x, y} representing the box quads.
@@ -350,16 +370,82 @@ function getPointsFromDiagonal(x1, y1, x
   ].map(point => {
     let transformedPoint = apply(matrix, point);
 
     return { x: transformedPoint[0], y: transformedPoint[1] };
   });
 }
 
 /**
+ * Returns the matrix to rotate, translate, and reflect (if needed) from the element's
+ * top-left origin into the actual writing mode and text direction applied to the element.
+ *
+ * @param  {Element} element
+ *         The current element.
+ * @param  {CSSStyleDeclaration} computedStyle
+ *         The computed style for the element.
+ * @return {Array}
+ *         The matrix with adjustments for writing mode and text direction, if any.
+ */
+function getWritingModeMatrix(element, computedStyle) {
+  let currentMatrix = identity();
+  let { direction, writingMode } = computedStyle;
+
+  switch (writingMode) {
+    case "horizontal-tb":
+      // This is the initial value.  No further adjustment needed.
+      break;
+    case "vertical-rl":
+      currentMatrix = multiply(
+        translate(element.offsetWidth, 0),
+        rotate(-Math.PI / 2)
+      );
+      break;
+    case "vertical-lr":
+      currentMatrix = multiply(
+        reflectAboutY(),
+        rotate(-Math.PI / 2)
+      );
+      break;
+    case "sideways-rl":
+      currentMatrix = multiply(
+        translate(element.offsetWidth, 0),
+        rotate(-Math.PI / 2)
+      );
+      break;
+    case "sideways-lr":
+      currentMatrix = multiply(
+        rotate(Math.PI / 2),
+        translate(-element.offsetHeight, 0)
+      );
+      break;
+    default:
+      console.error(`Unexpected writing-mode: ${writingMode}`);
+  }
+
+  switch (direction) {
+    case "ltr":
+      // This is the initial value.  No further adjustment needed.
+      break;
+    case "rtl":
+      let rowLength = element.offsetWidth;
+      if (writingMode != "horizontal-tb") {
+        rowLength = element.offsetHeight;
+      }
+      currentMatrix = multiply(currentMatrix, translate(rowLength, 0));
+      currentMatrix = multiply(currentMatrix, reflectAboutY());
+      break;
+    default:
+      console.error(`Unexpected direction: ${direction}`);
+  }
+
+  return currentMatrix;
+}
+
+/**
  * Updates the <canvas> element's style in accordance with the current window's
  * device pixel ratio, and the position calculated in `getCanvasPosition`. It also
  * clears the drawing context. This is called on canvas update after a scroll event where
  * `getCanvasPosition` updates the new canvasPosition.
  *
  * @param  {Canvas} canvas
  *         The <canvas> element.
  * @param  {Object} canvasPosition
--- a/devtools/server/tests/mochitest/test_inspector-anonymous.html
+++ b/devtools/server/tests/mochitest/test_inspector-anonymous.html
@@ -20,17 +20,17 @@ window.onload = function () {
     require("devtools/server/actors/inspector");
   const nodeFilterConstants =
     require("devtools/shared/dom-node-filter-constants");
   const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
   const isStylo = SpecialPowers.DOMWindowUtils.isStyledByServo;
 
   SpecialPowers.pushPrefEnv({"set": [
-    ["dom.webcomponents.enabled", true]
+    ["dom.webcomponents.shadowdom.enabled", true]
   ]});
   SimpleTest.waitForExplicitFinish();
 
   let gWalker = null;
   let gInspectee = null;
 
   addTest(function setup() {
     info("Setting up inspector and walker actors.");
--- a/devtools/shared/css/generated/properties-db.js
+++ b/devtools/shared/css/generated/properties-db.js
@@ -8524,16 +8524,17 @@ exports.CSS_PROPERTIES = {
       "-moz-left",
       "-moz-right",
       "center",
       "end",
       "inherit",
       "initial",
       "justify",
       "left",
+      "match-parent",
       "right",
       "start",
       "unset"
     ]
   },
   "text-align-last": {
     "isInherited": true,
     "subproperties": [
--- a/devtools/shared/layout/dom-matrix-2d.js
+++ b/devtools/shared/layout/dom-matrix-2d.js
@@ -40,16 +40,30 @@ exports.scale = scale;
 const translate = (tx = 0, ty = tx) => [
   1, 0, tx,
   0, 1, ty,
   0, 0, 1
 ];
 exports.translate = translate;
 
 /**
+ * Returns a matrix that reflects about the Y axis.  For example, the point (x1, y1) would
+ * become (-x1, y1).
+ *
+ * @return {Array}
+ *         The new matrix.
+ */
+const reflectAboutY = () => [
+  -1, 0, 0,
+  0,  1, 0,
+  0,  0, 1,
+];
+exports.reflectAboutY = reflectAboutY;
+
+/**
  * Returns a matrix for the rotation given.
  * Calling `rotate()` or `rotate(0)` returns a new identity matrix.
  *
  * @param {Number} [angle = 0]
  *        The angle, in radians, for which to return a corresponding rotation matrix.
  *        If unspecified, it will equal `0`.
  * @return {Array}
  *         The new matrix.
--- a/dom/animation/KeyframeEffectReadOnly.cpp
+++ b/dom/animation/KeyframeEffectReadOnly.cpp
@@ -1759,16 +1759,25 @@ KeyframeEffectReadOnly::CreateStyleConte
 
 template<typename StyleType>
 void
 KeyframeEffectReadOnly::CalculateCumulativeChangeHint(StyleType* aStyleContext)
 {
   mCumulativeChangeHint = nsChangeHint(0);
 
   for (const AnimationProperty& property : mProperties) {
+    // For opacity property we don't produce any change hints that are not
+    // included in nsChangeHint_Hints_CanIgnoreIfNotVisible so we can throttle
+    // opacity animations regardless of the change they produce.  This
+    // optimization is particularly important since it allows us to throttle
+    // opacity animations with missing 0%/100% keyframes.
+    if (property.mProperty == eCSSProperty_opacity) {
+      continue;
+    }
+
     for (const AnimationPropertySegment& segment : property.mSegments) {
       // In case composite operation is not 'replace' or value is null,
       // we can't throttle animations which will not cause any layout changes
       // on invisible elements because we can't calculate the change hint for
       // such properties until we compose it.
       if (!segment.HasReplaceableValues()) {
         mCumulativeChangeHint = ~nsChangeHint_Hints_CanIgnoreIfNotVisible;
         return;
--- a/dom/animation/test/mozilla/file_restyles.html
+++ b/dom/animation/test/mozilla/file_restyles.html
@@ -20,16 +20,19 @@ SimpleTest.finish = function finish() {
 <script src="/tests/SimpleTest/paint_listener.js"></script>
 <script src="../testcommon.js"></script>
 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
 <style>
 @keyframes opacity {
   from { opacity: 1; }
   to { opacity: 0; }
 }
+@keyframes opacity-without-end-value {
+  from { opacity: 0; }
+}
 @keyframes background-color {
   from { background-color: red; }
   to { background-color: blue; }
 }
 @keyframes rotate {
   from { transform: rotate(0deg); }
   to { transform: rotate(360deg); }
 }
@@ -127,18 +130,16 @@ function tweakExpectedRestyleCount(aAnim
   }
   return aExpectedRestyleCount;
 }
 
 var omtaEnabled = isOMTAEnabled();
 
 var isAndroid = !!navigator.userAgent.includes("Android");
 var isServo = isStyledByServo();
-var offscreenThrottlingEnabled =
-  SpecialPowers.getBoolPref('dom.animations.offscreen-throttling');
 var hasConformantPromiseHandling;
 
 function add_task_if_omta_enabled(test) {
   if (!omtaEnabled) {
     info(test.name + " is skipped because OMTA is disabled");
     return;
   }
   add_task(test);
@@ -316,58 +317,46 @@ waitForAllPaints(() => {
 
     is(markers.length, 0,
        'Finished animations should never cause restyles when mouse is moved ' +
        'on the animations');
     await ensureElementRemoval(div);
   });
 
   add_task_if_omta_enabled(async function no_restyling_compositor_animations_out_of_view_element() {
-    if (!offscreenThrottlingEnabled) {
-      return;
-    }
-
     var div = addDiv(null,
       { style: 'animation: opacity 100s; transform: translateY(-400px);' });
     var animation = div.getAnimations()[0];
 
     await animation.ready;
     ok(!SpecialPowers.wrap(animation).isRunningOnCompositor);
 
     var markers = await observeStyling(5);
 
     is(markers.length, 0,
        'Animations running on the compositor in an out-of-view element ' +
        'should never cause restyles');
     await ensureElementRemoval(div);
   });
 
   add_task(async function no_restyling_main_thread_animations_out_of_view_element() {
-    if (!offscreenThrottlingEnabled) {
-      return;
-    }
-
     var div = addDiv(null,
       { style: 'animation: background-color 100s; transform: translateY(-400px);' });
     var animation = div.getAnimations()[0];
 
     await animation.ready;
     var markers = await observeStyling(5);
 
     is(markers.length, 0,
        'Animations running on the main-thread in an out-of-view element ' +
        'should never cause restyles');
     await ensureElementRemoval(div);
   });
 
   add_task_if_omta_enabled(async function no_restyling_compositor_animations_in_scrolled_out_element() {
-    if (!offscreenThrottlingEnabled) {
-      return;
-    }
-
     var parentElement = addDiv(null,
       { style: 'overflow-y: scroll; height: 20px;' });
     var div = addDiv(null,
       { style: 'animation: opacity 100s; position: relative; top: 100px;' });
     parentElement.appendChild(div);
     var animation = div.getAnimations()[0];
 
     await animation.ready;
@@ -377,25 +366,42 @@ waitForAllPaints(() => {
     is(markers.length, 0,
        'Animations running on the compositor for elements ' +
        'which are scrolled out should never cause restyles');
 
     await ensureElementRemoval(parentElement);
   });
 
   add_task(
+    async function no_restyling_missing_keyframe_opacity_animations_on_scrolled_out_element() {
+      var parentElement = addDiv(null,
+        { style: 'overflow-y: scroll; height: 20px;' });
+      var div = addDiv(null,
+        { style: 'animation: opacity-without-end-value 100s; ' +
+                 'position: relative; top: 100px;' });
+      parentElement.appendChild(div);
+      var animation = div.getAnimations()[0];
+      await animation.ready;
+
+      var markers = await observeStyling(5);
+
+      is(markers.length, 0,
+         'Opacity animations on scrolled out elements should never cause ' +
+         'restyles even if the animation has missing keyframes');
+
+      await ensureElementRemoval(parentElement);
+    }
+  );
+
+  add_task(
     async function restyling_transform_animations_in_scrolled_out_element() {
       if (hasConformantPromiseHandling) {
         return;
       }
 
-      if (!offscreenThrottlingEnabled) {
-        return;
-      }
-
       // Skip this test on Android since this test have been failing
       // intermittently.
       // Bug 1413817: We should audit this test still fails once we have the
       // conformant Promise micro task.
       if (isAndroid) {
         return;
       }
 
@@ -437,20 +443,16 @@ waitForAllPaints(() => {
   );
 
   add_task(
     async function restyling_transform_animations_in_scrolled_out_element() {
       if (!hasConformantPromiseHandling) {
         return;
       }
 
-      if (!offscreenThrottlingEnabled) {
-        return;
-      }
-
       await SpecialPowers.pushPrefEnv({ set: [["ui.showHideScrollbars", 1]] });
 
       // Make sure we start from the state right after requestAnimationFrame.
       await waitForFrame();
 
       var parentElement = addDiv(null,
         { style: 'overflow-y: scroll; height: 20px;' });
       var div = addDiv(null,
@@ -486,20 +488,16 @@ waitForAllPaints(() => {
          'should be unthrottled after around 200ms have elapsed. now: ' +
          now + ' start time: ' + timeAtStart);
 
       await ensureElementRemoval(parentElement);
     }
   );
 
   add_task(async function restyling_main_thread_animations_in_scrolled_out_element() {
-    if (!offscreenThrottlingEnabled) {
-      return;
-    }
-
     var parentElement = addDiv(null,
       { style: 'overflow-y: scroll; height: 20px;' });
     var div = addDiv(null,
       { style: 'animation: background-color 100s; position: relative; top: 20px;' });
     parentElement.appendChild(div);
     var animation = div.getAnimations()[0];
 
     await animation.ready;
@@ -519,20 +517,16 @@ waitForAllPaints(() => {
        'Animations running on the main-thread which were in scrolled out ' +
        'elements should update restyling soon after the element moved in ' +
        'view by scrolling');
 
     await ensureElementRemoval(parentElement);
   });
 
   add_task(async function restyling_main_thread_animations_in_nested_scrolled_out_element() {
-    if (!offscreenThrottlingEnabled) {
-      return;
-    }
-
     var grandParent = addDiv(null,
       { style: 'overflow-y: scroll; height: 20px;' });
     var parentElement = addDiv(null,
       { style: 'overflow-y: scroll; height: 100px;' });
     var div = addDiv(null,
       { style: 'animation: background-color 100s; ' +
                'position: relative; ' +
                'top: 20px;' }); // This element is in-view in the parent, but
@@ -573,20 +567,16 @@ waitForAllPaints(() => {
 
     todo_is(markers.length, 0,
             'Bug 1237454: Animations running on the compositor in ' +
             'visibility hidden element should never cause restyles');
     await ensureElementRemoval(div);
   });
 
   add_task(async function restyling_main_thread_animations_move_out_of_view_by_scrolling() {
-    if (!offscreenThrottlingEnabled) {
-      return;
-    }
-
     var parentElement = addDiv(null,
       { style: 'overflow-y: scroll; height: 200px;' });
     var div = addDiv(null,
       { style: 'animation: background-color 100s;' });
     var pad = addDiv(null,
       { style: 'height: 400px;' });
     parentElement.appendChild(div);
     parentElement.appendChild(pad);
@@ -604,20 +594,16 @@ waitForAllPaints(() => {
     ok(markers.length >= 0,
        'Animations running on the main-thread which are in scrolled out ' +
        'elements should throttle restyling');
 
     await ensureElementRemoval(parentElement);
   });
 
   add_task(async function restyling_main_thread_animations_moved_in_view_by_resizing() {
-    if (!offscreenThrottlingEnabled) {
-      return;
-    }
-
     var parentElement = addDiv(null,
       { style: 'overflow-y: scroll; height: 20px;' });
     var div = addDiv(null,
       { style: 'animation: background-color 100s; position: relative; top: 100px;' });
     parentElement.appendChild(div);
     var animation = div.getAnimations()[0];
 
     await animation.ready;
@@ -988,45 +974,75 @@ waitForAllPaints(() => {
          '!important rule begins running on the compositor even if the ' +
          '!important rule had been dropped before the target element was ' +
          'removed');
 
       await ensureElementRemoval(div);
     }
   );
 
-  // Tests that additive animations don't throttle at all.
+  add_task(
+    async function no_throttling_additive_animations_out_of_view_element() {
+      var div = addDiv(null, { style: 'transform: translateY(-400px);' });
+      var animation =
+        div.animate([{ visibility: 'visible' }],
+                    { duration: 100 * MS_PER_SEC, composite: 'add' });
+
+      await animation.ready;
+
+      const expectedRestyleCount = tweakExpectedRestyleCount(animation, 5);
+      var markers = await observeStyling(5);
+
+      is(markers.length, expectedRestyleCount,
+         'Additive animation has no keyframe whose offset is 0 or 1 in an ' +
+         'out-of-view element should not be throttled');
+      await ensureElementRemoval(div);
+    }
+  );
+
+  // Tests that missing keyframes animations don't throttle at all.
   add_task(async function no_throttling_animations_out_of_view_element() {
-    if (!offscreenThrottlingEnabled ||
-        !SpecialPowers.getBoolPref('dom.animations-api.core.enabled')) {
-      return;
-    }
-
     var div = addDiv(null, { style: 'transform: translateY(-400px);' });
     var animation =
       div.animate([{ visibility: 'visible' }], 100 * MS_PER_SEC);
 
     await animation.ready;
 
     const expectedRestyleCount = tweakExpectedRestyleCount(animation, 5);
     var markers = await observeStyling(5);
 
     is(markers.length, expectedRestyleCount,
        'Discrete animation has has no keyframe whose offset is 0 or 1 in an ' +
        'out-of-view element should not be throttled');
     await ensureElementRemoval(div);
   });
 
+  // Tests that missing keyframes animation on scrolled out element that the
+  // animation is not able to be throttled.
+  add_task(
+    async function no_throttling_missing_keyframe_animations_out_of_view_element() {
+      var div =
+        addDiv(null, { style: 'transform: translateY(-400px);' +
+                              'visibility: collapse;' });
+      var animation =
+        div.animate([{ visibility: 'visible' }], 100 * MS_PER_SEC);
+      await animation.ready;
+
+      const expectedRestyleCount = tweakExpectedRestyleCount(animation, 5);
+      var markers = await observeStyling(5);
+      is(markers.length, expectedRestyleCount,
+         'visibility animation has no keyframe whose offset is 0 or 1 in an ' +
+         'out-of-view element and produces change hint other than paint-only ' +
+         'change hint should not be throttled');
+      await ensureElementRemoval(div);
+    }
+  );
+
   // Counter part of the above test.
   add_task(async function no_restyling_discrete_animations_out_of_view_element() {
-    if (!offscreenThrottlingEnabled ||
-        !SpecialPowers.getBoolPref('dom.animations-api.core.enabled')) {
-      return;
-    }
-
     var div = addDiv(null, { style: 'transform: translateY(-400px);' });
     var animation =
       div.animate({ visibility: ['visible', 'hidden'] }, 100 * MS_PER_SEC);
 
     await animation.ready;
 
     var markers = await observeStyling(5);
 
@@ -1071,20 +1087,16 @@ waitForAllPaints(() => {
     is(markers.length, expectedRestyleCount,
        'CSS animations on an in-view svg element with post-transform should ' +
        'not be throttled.');
 
     await ensureElementRemoval(div);
   });
 
   add_task(async function throttling_animations_out_of_view_svg() {
-    if (!offscreenThrottlingEnabled) {
-      return;
-    }
-
     var div = addDiv(null, { style: 'overflow: scroll;' +
                                     'height: 100px; width: 100px;' });
     var svg = addSVGElement(div, 'svg', { viewBox: '-10 -10 0.1 0.1',
                                           width: '50px',
                                           height: '50px' });
     var rect = addSVGElement(svg, 'rect', { width: '10',
                                             height: '10',
                                             fill: 'red' });
@@ -1116,20 +1128,16 @@ waitForAllPaints(() => {
     is(markers.length, expectedRestyleCount,
        'CSS animation on an in-view element with pre-transform should not ' +
        'be throttled.');
 
     await ensureElementRemoval(scrollDiv);
   });
 
   add_task(async function throttling_animations_out_of_view_css_transform() {
-    if (!offscreenThrottlingEnabled) {
-      return;
-    }
-
     var scrollDiv = addDiv(null, { style: 'overflow: scroll;' +
                                           'height: 100px; width: 100px;' });
     var targetDiv = addDiv(null,
                            { style: 'animation: background-color 100s;' +
                                     'transform: translate(100px, 100px);' });
     scrollDiv.appendChild(targetDiv);
 
     var animation = targetDiv.getAnimations()[0];
@@ -1140,20 +1148,16 @@ waitForAllPaints(() => {
        'CSS animation on an out-of-view element with pre-transform should be ' +
        'throttled.');
 
     await ensureElementRemoval(scrollDiv);
   });
 
   add_task(
     async function throttling_animations_in_out_of_view_position_absolute_element() {
-      if (!offscreenThrottlingEnabled) {
-        return;
-      }
-
       var parentDiv = addDiv(null,
                              { style: 'position: absolute; top: -1000px;' });
       var targetDiv = addDiv(null,
                              { style: 'animation: background-color 100s;' });
       parentDiv.appendChild(targetDiv);
 
       var animation = targetDiv.getAnimations()[0];
       await animation.ready;
@@ -1164,20 +1168,16 @@ waitForAllPaints(() => {
          'be throttled');
 
       await ensureElementRemoval(parentDiv);
     }
   );
 
   add_task(
     async function throttling_animations_on_out_of_view_position_absolute_element() {
-      if (!offscreenThrottlingEnabled) {
-        return;
-      }
-
       var div = addDiv(null,
                        { style: 'animation: background-color 100s; ' +
                                 'position: absolute; top: -1000px;' });
 
       var animation = div.getAnimations()[0];
       await animation.ready;
 
       var markers = await observeStyling(5);
@@ -1186,20 +1186,16 @@ waitForAllPaints(() => {
          'be throttled');
 
       await ensureElementRemoval(div);
     }
   );
 
   add_task(
     async function throttling_animations_in_out_of_view_position_fixed_element() {
-      if (!offscreenThrottlingEnabled) {
-        return;
-      }
-
       var parentDiv = addDiv(null,
                              { style: 'position: fixed; top: -1000px;' });
       var targetDiv = addDiv(null,
                              { style: 'animation: background-color 100s;' });
       parentDiv.appendChild(targetDiv);
 
       var animation = targetDiv.getAnimations()[0];
       await animation.ready;
@@ -1210,20 +1206,16 @@ waitForAllPaints(() => {
          'throttled');
 
       await ensureElementRemoval(parentDiv);
     }
   );
 
   add_task(
     async function throttling_animations_on_out_of_view_position_fixed_element() {
-      if (!offscreenThrottlingEnabled) {
-        return;
-      }
-
       var div = addDiv(null,
                        { style: 'animation: background-color 100s; ' +
                                 'position: fixed; top: -1000px;' });
 
       var animation = div.getAnimations()[0];
       await animation.ready;
 
       var markers = await observeStyling(5);
--- a/dom/base/ChildIterator.cpp
+++ b/dom/base/ChildIterator.cpp
@@ -20,17 +20,17 @@ namespace dom {
 ExplicitChildIterator::ExplicitChildIterator(const nsIContent* aParent,
                                              bool aStartAtBeginning)
   : mParent(aParent),
     mChild(nullptr),
     mDefaultChild(nullptr),
     mIsFirst(aStartAtBeginning),
     mIndexInInserted(0)
 {
-  mParentAsSlot = nsDocument::IsWebComponentsEnabled(mParent) ?
+  mParentAsSlot = nsDocument::IsShadowDOMEnabled(mParent) ?
     HTMLSlotElement::FromContent(mParent) : nullptr;
 }
 
 nsIContent*
 ExplicitChildIterator::GetNextChild()
 {
   // If we're already in the inserted-children array, look there first
   if (mIndexInInserted) {
--- a/dom/base/DocumentOrShadowRoot.cpp
+++ b/dom/base/DocumentOrShadowRoot.cpp
@@ -111,17 +111,17 @@ DocumentOrShadowRoot::GetRetargetedFocus
                                            getter_AddRefs(focusedWindow));
     // be safe and make sure the element is from this document
     if (focusedContent && focusedContent->OwnerDoc() == AsNode().OwnerDoc()) {
       if (focusedContent->ChromeOnlyAccess()) {
         focusedContent = focusedContent->FindFirstNonChromeOnlyAccessContent();
       }
 
       if (focusedContent) {
-        if (!nsDocument::IsWebComponentsEnabled(focusedContent)) {
+        if (!nsDocument::IsShadowDOMEnabled(focusedContent)) {
           return focusedContent->AsElement();
         }
 
         if (nsIContent* retarget = Retarget(focusedContent)) {
           return retarget->AsElement();
         }
       }
     }
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -1175,16 +1175,18 @@ FragmentOrElement::RemoveChildAt_Depreca
   if (oldKid) {
     doRemoveChildAt(aIndex, aNotify, oldKid, mAttrsAndChildren);
   }
 }
 
 void
 FragmentOrElement::RemoveChildNode(nsIContent* aKid, bool aNotify)
 {
+  // Let's keep the node alive.
+  nsCOMPtr<nsIContent> kungFuDeathGrip = aKid;
   doRemoveChildAt(IndexOf(aKid), aNotify, aKid, mAttrsAndChildren);
 }
 
 void
 FragmentOrElement::GetTextContentInternal(nsAString& aTextContent,
                                           OOMReporter& aError)
 {
   if (!nsContentUtils::GetNodeTextContent(this, true, aTextContent, fallible)) {
@@ -2302,20 +2304,19 @@ FragmentOrElement::SetInnerHTMLInternal(
   mozAutoSubtreeModified subtree(doc, nullptr);
 
   target->FireNodeRemovedForChildren();
 
   // Needed when innerHTML is used in combination with contenteditable
   mozAutoDocUpdate updateBatch(doc, UPDATE_CONTENT_MODEL, true);
 
   // Remove childnodes.
-  uint32_t childCount = target->GetChildCount();
   nsAutoMutationBatch mb(target, true, false);
-  for (uint32_t i = 0; i < childCount; ++i) {
-    target->RemoveChildAt_Deprecated(0, true);
+  while (target->HasChildren()) {
+    target->RemoveChildNode(target->GetFirstChild(), true);
   }
   mb.RemovalDone();
 
   nsAutoScriptLoaderDisabler sld(doc);
 
   nsAtom* contextLocalName = NodeInfo()->NameAtom();
   int32_t contextNameSpaceID = GetNameSpaceID();
 
--- a/dom/base/crashtests/1324463.html
+++ b/dom/base/crashtests/1324463.html
@@ -1,12 +1,12 @@
 <!DOCTYPE html>
 <html>
 <script>
-// requires: user_pref("dom.webcomponents.enabled", true);
+// requires: user_pref("dom.webcomponents.shadowdom.enabled", true);
 addEventListener("DOMContentLoaded", function(){
   let o_0 = document.createElement("span").createShadowRoot();
   let o_1 = document.createElementNS("http://www.mozilla.org/xbl", "binding");
   let o_2 = document.createElementNS("http://www.mozilla.org/xbl", "children");
   let o_3 = document.createTextNode("");
   o_0.appendChild(o_1);
   o_1.appendChild(o_2);
   o_2.appendChild(o_3);
--- a/dom/base/crashtests/1422931.html
+++ b/dom/base/crashtests/1422931.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
 <html>
 <body>
-<!-- Testing slot element with "dom.webcomponents.enabled" set to false -->
+<!-- Testing slot element with "dom.webcomponents.shadowdom.enabled" set to false -->
 <slot><div></div></slot>
 </html>
--- a/dom/base/crashtests/crashtests.list
+++ b/dom/base/crashtests/crashtests.list
@@ -189,27 +189,27 @@ load 852381.html
 load 863950.html
 load 864448.html
 load 886213.html
 load 898906.html
 load 930250.html
 load 942979.html
 load 973401.html
 load 978646.html
-pref(dom.webcomponents.enabled,true) load 1024428-1.html
+pref(dom.webcomponents.shadowdom.enabled,true) load 1024428-1.html
 load 1026714.html
-pref(dom.webcomponents.enabled,true) load 1027461-1.html
-pref(dom.webcomponents.enabled,true) load 1029710.html
+pref(dom.webcomponents.shadowdom.enabled,true) load 1027461-1.html
+pref(dom.webcomponents.shadowdom.enabled,true) load 1029710.html
 load 1154598.xhtml
 load 1157995.html
 load 1158412.html
 load 1181619.html
 load 1230422.html
 load 1251361.html
-pref(dom.webcomponents.enabled,true) load 1281715.html
+pref(dom.webcomponents.shadowdom.enabled,true) load 1281715.html
 load 1304437.html
 pref(dom.IntersectionObserver.enabled,true) load 1324209.html
 load 1324500.html
 pref(dom.IntersectionObserver.enabled,true) load 1326194-1.html
 pref(dom.IntersectionObserver.enabled,true) load 1326194-2.html
 pref(dom.IntersectionObserver.enabled,true) load 1332939.html
 pref(dom.webcomponents.customelements.enabled,true) load 1341693.html
 load 1352453.html
@@ -228,15 +228,15 @@ load 1383478.html
 load 1383780.html
 pref(clipboard.autocopy,true) load 1385272-1.html
 load 1393806.html
 load 1396466.html
 load 1400701.html
 load 1403377.html
 load 1405771.html
 load 1406109-1.html
-pref(dom.webcomponents.enabled,true) load 1324463.html
+pref(dom.webcomponents.shadowdom.enabled,true) load 1324463.html
 pref(dom.webcomponents.customelements.enabled,true) load 1413815.html
 load 1411473.html
-pref(dom.webcomponents.enabled,false) load 1422931.html
-pref(dom.webcomponents.enabled,true) load 1419799.html
+pref(dom.webcomponents.shadowdom.enabled,false) load 1422931.html
+pref(dom.webcomponents.shadowdom.enabled,true) load 1419799.html
 skip-if(!browserIsRemote) pref(dom.webcomponents.customelements.enabled,true) pref(dom.disable_open_during_load,false) load 1419902.html # skip on non e10s loads, Bug 1419902
-pref(dom.webcomponents.enabled,true) load 1428053.html
+pref(dom.webcomponents.shadowdom.enabled,true) load 1428053.html
--- a/dom/base/nsContentCreatorFunctions.h
+++ b/dom/base/nsContentCreatorFunctions.h
@@ -37,17 +37,17 @@ NS_NewElement(mozilla::dom::Element** aR
 nsresult
 NS_NewXMLElement(mozilla::dom::Element** aResult,
                  already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
 
 nsresult
 NS_NewHTMLElement(mozilla::dom::Element** aResult,
                   already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
                   mozilla::dom::FromParser aFromParser,
-                  const nsAString* aIs = nullptr,
+                  nsAtom* aIsAtom = nullptr,
                   mozilla::dom::CustomElementDefinition* aDefinition = nullptr);
 
 // First argument should be nsHTMLTag, but that adds dependency to parser
 // for a bunch of files.
 already_AddRefed<nsGenericHTMLElement>
 CreateHTMLElement(uint32_t aNodeType,
                   already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
                   mozilla::dom::FromParser aFromParser);
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -288,17 +288,17 @@ bool nsContentUtils::sIsFullScreenApiEna
 bool nsContentUtils::sIsUnprefixedFullscreenApiEnabled = false;