Merge mozilla-central to mozilla-inbound
authorDorel Luca <dluca@mozilla.com>
Mon, 04 Jun 2018 21:48:29 +0300
changeset 475458 425c5899aa74427a1b34e2e6610b220d1a0cf960
parent 475457 4c50952c3e8c379a3fd09517fbd656f35e99d165 (current diff)
parent 475396 d8f180ab74921fd07a66d6868914a48e5f9ea797 (diff)
child 475459 d697c464a22e78d59704362149da19c97ead74ec
push id9374
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:43:20 +0000
treeherdermozilla-beta@160e085dfb0b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone62.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to mozilla-inbound
devtools/client/inspector/animation/test/browser_animation_keyframes-graph_computed-value-path.js
dom/clients/manager/ClientInfo.cpp
dom/clients/manager/ClientManagerService.cpp
dom/geolocation/nsGeolocation.cpp
dom/ipc/ContentParent.cpp
dom/serviceworkers/ServiceWorkerManager.cpp
js/src/gc/GC.cpp
js/src/vm/JSScript.cpp
layout/style/nsTransitionManager.cpp
netwerk/protocol/http/HttpChannelChild.cpp
services/common/remote-settings.js
services/common/tests/unit/test_remote_settings.js
services/common/tests/unit/test_remote_settings_jexl_filters.js
services/common/tests/unit/test_remote_settings_poll.js
third_party/python/hglib/LICENSE
third_party/python/hglib/hglib/__init__.py
third_party/python/hglib/hglib/client.py
third_party/python/hglib/hglib/context.py
third_party/python/hglib/hglib/error.py
third_party/python/hglib/hglib/merge.py
third_party/python/hglib/hglib/templates.py
third_party/python/hglib/hglib/util.py
third_party/python/hglib/setup.py
--- a/Pipfile
+++ b/Pipfile
@@ -7,11 +7,12 @@ name = "pypi"
 
 [packages]
 pipenv = "==2018.5.18"
 virtualenv = "==15.2.0"
 six = "==1.10.0"
 attrs = "==18.1.0"
 pytest = "==3.2.5"
 jsmin = "==2.1.0"
+python-hglib = "==2.4"
 
 [requires]
 python_version = "2.7"
--- a/Pipfile.lock
+++ b/Pipfile.lock
@@ -1,12 +1,12 @@
 {
     "_meta": {
         "hash": {
-            "sha256": "706dd858cb4e07dbccf7f3e6f129ac5b50c9906bcd6083e4fb09e9869b379d5e"
+            "sha256": "695978bb529a1cffb6f329519ce6fe68adbee73d9f05595dbefb2b9d0ebe4177"
         },
         "pipfile-spec": 6,
         "requires": {
             "python_version": "2.7"
         },
         "sources": [
             {
                 "name": "pypi",
@@ -56,16 +56,23 @@
         "pytest": {
             "hashes": [
                 "sha256:241d7e7798d79192a123ceaf64c602b4d233eacf6d6e42ae27caa97f498b7dc6",
                 "sha256:6d5bd4f7113b444c55a3bbb5c738a3dd80d43563d063fc42dcb0aaefbdd78b81"
             ],
             "index": "pypi",
             "version": "==3.2.5"
         },
+        "python-hglib": {
+            "hashes": [
+                "sha256:693d6ed92a6566e78802c7a03c256cda33d08c63ad3f00fcfa11379b184b9462"
+            ],
+            "index": "pypi",
+            "version": "==2.4"
+        },
         "six": {
             "hashes": [
                 "sha256:0ff78c403d9bccf5a425a6d31a12aa6b47f1c21ca4dc2573a7e2f32a97335eb1",
                 "sha256:105f8d68616f8248e24bf0e9372ef04d3cc10104f1980f54d57b2ce73a5ad56a"
             ],
             "index": "pypi",
             "version": "==1.10.0"
         },
--- a/accessible/ipc/other/ProxyAccessible.cpp
+++ b/accessible/ipc/other/ProxyAccessible.cpp
@@ -73,17 +73,17 @@ ProxyAccessible::RelationByType(Relation
                                      &targetIDs);
 
   size_t targetCount = targetIDs.Length();
   nsTArray<ProxyAccessible*> targets(targetCount);
   for (size_t i = 0; i < targetCount; i++)
     if (ProxyAccessible* proxy = mDoc->GetAccessible(targetIDs[i]))
       targets.AppendElement(proxy);
 
-  return std::move(targets);
+  return targets;
 }
 
 void
 ProxyAccessible::Relations(nsTArray<RelationType>* aTypes,
                            nsTArray<nsTArray<ProxyAccessible*>>* aTargetSets)
   const
 {
   nsTArray<RelationTargets> ipcRelations;
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -754,16 +754,17 @@ BrowserGlue.prototype = {
       description: gBrowserBundle.GetStringFromName("darkTheme.description"),
       iconURL: "resource:///chrome/browser/content/browser/defaultthemes/dark.icon.svg",
       textcolor: "white",
       accentcolor: "black",
       popup: "#4a4a4f",
       popup_text: "rgb(249, 249, 250)",
       popup_border: "#27272b",
       toolbar_field_text: "rgb(249, 249, 250)",
+      toolbar_field_border: "rgba(249, 249, 250, 0.2)",
       author: vendorShortName,
     });
 
     Normandy.init();
 
     // Initialize the default l10n resource sources for L10nRegistry.
     let locales = Services.locale.getPackagedLocales();
     const appSource = new FileSource("app", locales, "resource://app/localization/{locale}/");
--- a/browser/components/preferences/in-content/privacy.js
+++ b/browser/components/preferences/in-content/privacy.js
@@ -1001,17 +1001,17 @@ var gPrivacyPane = {
     document.getElementById("autoplayMediaPolicyButton").disabled = autoPlayEnabled;
   },
 
   /**
    * Show the controls for the new media autoplay behaviour behind a pref for now
    */
   updateAutoplayMediaControlsVisibility() {
     document.getElementById("autoplayMediaBox").hidden =
-      !Services.prefs.getBoolPref("media.autoplay.enabled.user-gestures-needed");
+      !Services.prefs.getBoolPref("media.autoplay.enabled.user-gestures-needed", false);
   },
 
   /**
    * Displays the autoplay exceptions dialog where specific site autoplay preferences
    * can be set.
    */
   showAutoplayMediaExceptions() {
     var params = {
--- a/browser/config/mozconfigs/linux64/code-coverage
+++ b/browser/config/mozconfigs/linux64/code-coverage
@@ -1,8 +1,10 @@
+MOZ_AUTOMATION_L10N_CHECK=0
+
 . "$topsrcdir/browser/config/mozconfigs/linux64/nightly"
 
 TOOLTOOL_DIR=${TOOLTOOL_DIR:-$topsrcdir}
 
 ac_add_options --disable-install-strip
 ac_add_options --disable-elf-hack
 ac_add_options --disable-sandbox
 ac_add_options --disable-profiling
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -294,16 +294,17 @@
 @RESPATH@/components/nsPrompter.js
 @RESPATH@/components/SyncComponents.manifest
 @RESPATH@/components/Weave.js
 @RESPATH@/components/FxAccountsComponents.manifest
 @RESPATH@/components/FxAccountsPush.js
 @RESPATH@/components/CaptivePortalDetectComponents.manifest
 @RESPATH@/components/captivedetect.js
 @RESPATH@/components/servicesComponents.manifest
+@RESPATH@/components/servicesSettings.manifest
 @RESPATH@/components/cryptoComponents.manifest
 @RESPATH@/components/TelemetryStartup.js
 @RESPATH@/components/TelemetryStartup.manifest
 @RESPATH@/components/XULStore.js
 @RESPATH@/components/XULStore.manifest
 @RESPATH@/components/recording-cmdline.js
 @RESPATH@/components/recording-cmdline.manifest
 @RESPATH@/components/htmlMenuBuilder.js
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -45,17 +45,21 @@
   --toolbar-bgimage: none;
 
   --toolbox-border-bottom-color: rgba(0,0,0,.3);
 
   --panel-separator-color: hsla(210,4%,10%,.14);
 }
 
 :root[lwt-popup-brighttext] {
-  --panel-separator-color: hsla(0,0%,80%,.25);
+  --panel-separator-color: rgba(249,249,250,.2);
+
+  --arrowpanel-dimmed: rgba(249,249,250,.1);
+  --arrowpanel-dimmed-further: rgba(249,249,250,.15);
+  --arrowpanel-dimmed-even-further: rgba(249,249,250,.2);
 }
 
 #menubar-items {
   -moz-box-orient: vertical; /* for flex hack */
 }
 
 #main-menubar {
   -moz-box-flex: 1; /* make menu items expand to fill toolbar height */
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -36,17 +36,21 @@
 :root:-moz-lwtheme {
   --toolbar-bgcolor: rgba(255,255,255,.4);
   --toolbar-bgimage: none;
 
   --toolbox-border-bottom-color: rgba(0,0,0,.3);
 }
 
 :root[lwt-popup-brighttext] {
-  --panel-separator-color: hsla(0,0%,80%,.25);
+  --panel-separator-color: rgba(249,249,250,.2);
+
+  --arrowpanel-dimmed: rgba(249,249,250,.1);
+  --arrowpanel-dimmed-further: rgba(249,249,250,.15);
+  --arrowpanel-dimmed-even-further: rgba(249,249,250,.2);
 }
 
 #navigator-toolbox {
   --tabs-border-color: rgba(0,0,0,.3);
 }
 
 #tabbrowser-tabs {
   --tab-line-color: #0a84ff;
--- a/browser/themes/shared/compacttheme.inc.css
+++ b/browser/themes/shared/compacttheme.inc.css
@@ -25,16 +25,21 @@
   --chrome-nav-bar-controls-border-color: hsla(240, 5%, 5%, .3);
   --chrome-selection-color: #fff;
   --chrome-selection-background-color: #5675B9;
 
   /* Url and search bars */
   --lwt-toolbar-field-background-color: rgb(71, 71, 73);
   --lwt-toolbar-field-color: var(--chrome-color);
   --urlbar-separator-color: #5F6670;
+
+  /* !important to override LightweightThemeManager.addBuiltInTheme in
+     nsBrowserGlue.js */
+  --autocomplete-popup-background: #2A2A2E !important;
+  --autocomplete-popup-highlight-background: #0060DF;
 }
 
 :root:-moz-lwtheme-darktext {
   --lwt-toolbar-field-background-color: #fff;
 
   --chrome-background-color: #E3E4E6;
   --chrome-color: #18191a;
   --chrome-secondary-background-color: #f5f6f7;
--- a/browser/themes/shared/searchbar.inc.css
+++ b/browser/themes/shared/searchbar.inc.css
@@ -47,16 +47,20 @@
   font-weight: normal;
   background-color: var(--arrowpanel-dimmed);
   border-top: 1px solid var(--panel-separator-color);
   margin: 0;
   padding: 3px 6px;
   color: var(--panel-disabled-color);
 }
 
+:root[lwt-popup-brighttext] .search-panel-header {
+  color: var(--autocomplete-popup-color);
+}
+
 .search-panel-header > label {
   margin-top: 2px !important;
   margin-bottom: 1px !important;
 }
 
 .search-panel-current-input > label {
   margin: 2px 0 !important;
 }
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -67,17 +67,21 @@
   --toolbar-bgimage: none;
 
   --toolbox-border-bottom-color: rgba(0,0,0,.3);
 
   --panel-separator-color: hsla(210,4%,10%,.14);
 }
 
 :root[lwt-popup-brighttext] {
-  --panel-separator-color: hsla(0,0%,80%,.25);
+  --panel-separator-color: rgba(249,249,250,.2);
+
+  --arrowpanel-dimmed: rgba(249,249,250,.1);
+  --arrowpanel-dimmed-further: rgba(249,249,250,.15);
+  --arrowpanel-dimmed-even-further: rgba(249,249,250,.2);
 }
 
 #navigator-toolbox:-moz-lwtheme {
   --tabs-border-color: rgba(0,0,0,.3);
 }
 
 #menubar-items {
   -moz-box-orient: vertical; /* for flex hack */
--- a/build/moz.configure/warnings.configure
+++ b/build/moz.configure/warnings.configure
@@ -81,22 +81,16 @@ check_and_add_gcc_warning('-Wstring-conv
 
 # we inline 'new' and 'delete' in mozalloc
 check_and_add_gcc_warning('-Wno-inline-new-delete', cxx_compiler)
 
 # Prevent the following GCC warnings from being treated as errors:
 # too many false positives
 check_and_add_gcc_warning('-Wno-error=maybe-uninitialized')
 
-# Turned on by -Wall, but needs changes to be turned into an error
-# (bug 1465060).
-check_and_add_gcc_warning('-Wno-error=pessimizing-move')
-# This one is probably easier, it's only triggered by tests.
-check_and_add_gcc_warning('-Wno-error=self-move')
-
 # we don't want our builds held hostage when a platform-specific API
 # becomes deprecated.
 check_and_add_gcc_warning('-Wno-error=deprecated-declarations')
 
 # false positives depending on optimization
 check_and_add_gcc_warning('-Wno-error=array-bounds')
 
 # can't get rid of those PGO warnings
--- a/build/unix/build-binutils/build-binutils.sh
+++ b/build/unix/build-binutils/build-binutils.sh
@@ -1,26 +1,26 @@
 #!/bin/bash
 
-binutils_version=2.25.1
+binutils_version=2.28.1
 make_flags='-j12'
 
 root_dir="$1"
 if [ -z "$root_dir" -o ! -d "$root_dir" ]; then
   root_dir=$(mktemp -d)
 fi
 cd $root_dir
 
 if test -z $TMPDIR; then
   TMPDIR=/tmp/
 fi
 
 # Download the source of the specified version of binutils
-wget -c --progress=dot:mega -P $TMPDIR ftp://ftp.gnu.org/gnu/binutils/binutils-${binutils_version}.tar.bz2 || exit 1
-tar xjf $TMPDIR/binutils-${binutils_version}.tar.bz2
+wget -c --progress=dot:mega -P $TMPDIR ftp://ftp.gnu.org/gnu/binutils/binutils-${binutils_version}.tar.xz || exit 1
+tar xJf $TMPDIR/binutils-${binutils_version}.tar.xz
 
 # Build binutils
 mkdir binutils-objdir
 cd binutils-objdir
 
 ../binutils-$binutils_version/configure --prefix /tools/binutils/ --enable-gold --enable-plugins --disable-nls || exit 1
 make $make_flags || exit 1
 make install $make_flags DESTDIR=$root_dir || exit 1
new file mode 100644
--- /dev/null
+++ b/build/unix/stdc++compat/hide_std.ld
@@ -0,0 +1,5 @@
+hidden {
+  local:
+    # std::thread::_M_start_thread(...)
+    _ZNSt6thread15_M_start_thread*;
+};
--- a/build/unix/stdc++compat/moz.build
+++ b/build/unix/stdc++compat/moz.build
@@ -18,8 +18,10 @@ FORCE_STATIC_LIB = True
 
 NO_PGO = True
 
 DisableStlWrapping()
 COMPILE_FLAGS['CLANG_PLUGIN'] = []
 
 DEFINES['MOZ_LIBSTDCXX_VERSION'] = CONFIG['MOZ_LIBSTDCXX_TARGET_VERSION']
 HOST_DEFINES['MOZ_LIBSTDCXX_VERSION'] = CONFIG['MOZ_LIBSTDCXX_HOST_VERSION']
+
+OS_LIBS += ['-Wl,--version-script,%s/hide_std.ld' % SRCDIR]
--- a/build/virtualenv_packages.txt
+++ b/build/virtualenv_packages.txt
@@ -9,17 +9,17 @@ mozilla.pth:python/l10n
 mozilla.pth:third_party/python/attrs/src
 mozilla.pth:third_party/python/blessings
 mozilla.pth:third_party/python/compare-locales
 mozilla.pth:third_party/python/configobj
 mozilla.pth:third_party/python/cram
 mozilla.pth:third_party/python/dlmanager
 mozilla.pth:third_party/python/fluent
 mozilla.pth:third_party/python/futures
-mozilla.pth:third_party/python/hglib
+mozilla.pth:third_party/python/python-hglib
 mozilla.pth:third_party/python/jsmin
 optional:setup.py:third_party/python/psutil:build_ext:--inplace
 mozilla.pth:third_party/python/psutil
 mozilla.pth:third_party/python/pylru
 mozilla.pth:third_party/python/which
 mozilla.pth:third_party/python/pystache
 mozilla.pth:third_party/python/pyyaml/lib
 mozilla.pth:third_party/python/requests
--- a/devtools/client/inspector/animation/animation.js
+++ b/devtools/client/inspector/animation/animation.js
@@ -181,16 +181,33 @@ class AnimationInspector {
     return this.inspector.store.getState().animations;
   }
 
   addAnimationsCurrentTimeListener(listener) {
     this.animationsCurrentTimeListeners.push(listener);
   }
 
   /**
+   * This function calls AnimationsFront.setCurrentTimes with considering the createdTime
+   * which was introduced bug 1454392.
+   *
+   * @param {Number} currentTime
+   */
+  async doSetCurrentTimes(currentTime) {
+    const { animations, timeScale } = this.state;
+
+    // If currentTime is not defined in timeScale (which happens when connected
+    // to server older than FF62), set currentTime as it is. See bug 1454392.
+    currentTime = typeof timeScale.currentTime === "undefined"
+                    ? currentTime : currentTime + timeScale.minStartTime;
+    await this.animationsFront.setCurrentTimes(animations, currentTime, true,
+                                               { relativeToCreatedTime: true });
+  }
+
+  /**
    * Return a map of animated property from given animation actor.
    *
    * @param {Object} animation
    * @return {Map} A map of animated property
    *         key: {String} Animated property name
    *         value: {Array} Array of keyframe object
    *         Also, the keyframe object is consisted as following.
    *         {
@@ -381,27 +398,21 @@ class AnimationInspector {
   async setAnimationsCurrentTime(currentTime, shouldRefresh) {
     this.stopAnimationsCurrentTimeTimer();
     this.onAnimationsCurrentTimeUpdated(currentTime);
 
     if (!shouldRefresh && this.isCurrentTimeSet) {
       return;
     }
 
-    const { animations, timeScale } = this.state;
+    const { animations } = this.state;
     this.isCurrentTimeSet = true;
-    // If currentTime is not defined in timeScale (which happens when connected
-    // to server older than FF62), set currentTime as it is. See bug 1454392.
-    currentTime =
-      typeof timeScale.currentTime === "undefined"
-        ? currentTime : currentTime + timeScale.minStartTime;
 
     try {
-      await this.animationsFront.setCurrentTimes(animations, currentTime, true,
-                                                 { relativeToCreatedTime: true });
+      await this.doSetCurrentTimes(currentTime);
       await this.updateAnimations(animations);
     } catch (e) {
       // Expected if we've already been destroyed or other node have been selected
       // in the meantime.
       console.error(e);
       return;
     }
 
@@ -440,18 +451,17 @@ class AnimationInspector {
         await this.inspector.target.actorHasMethod("animations", "pauseSome");
     }
 
     const { animations, timeScale } = this.state;
 
     try {
       if (doPlay && animations.every(animation =>
                       timeScale.getEndTime(animation) <= animation.state.currentTime)) {
-        await this.animationsFront.setCurrentTimes(animations, 0, true,
-                                                   { relativeToCreatedTime: true });
+        await this.doSetCurrentTimes(0);
       }
 
       // If the server does not support pauseSome/playSome function, (which happens
       // when connected to server older than FF62), use pauseAll/playAll instead.
       // See bug 1456857.
       if (this.hasPausePlaySome) {
         if (doPlay) {
           await this.animationsFront.playSome(animations);
--- a/devtools/client/inspector/animation/components/AnimationTarget.js
+++ b/devtools/client/inspector/animation/components/AnimationTarget.js
@@ -129,20 +129,34 @@ class AnimationTarget extends Component 
       },
       Rep(
         {
           defaultRep: ElementNode,
           mode: MODE.TINY,
           inspectIconTitle: getInspectorStr("inspector.nodePreview.highlightNodeLabel"),
           object: translateNodeFrontToGrip(nodeFront),
           onDOMNodeClick: () => this.select(),
-          onDOMNodeMouseOut: () => onHideBoxModelHighlighter(),
-          onDOMNodeMouseOver: () => this.highlight(),
+          onDOMNodeMouseOut: () => {
+            if (!isHighlighted) {
+              onHideBoxModelHighlighter();
+            }
+          },
+          onDOMNodeMouseOver: () => {
+            if (!isHighlighted) {
+              this.highlight();
+            }
+          },
           onInspectIconClick: (_, e) => {
             e.stopPropagation();
+
+            if (!isHighlighted) {
+              // At first, hide highlighter which was created by onDOMNodeMouseOver.
+              onHideBoxModelHighlighter();
+            }
+
             setHighlightedNode(isHighlighted ? null : nodeFront);
           }
         }
       )
     );
   }
 }
 
--- a/devtools/client/inspector/animation/test/browser.ini
+++ b/devtools/client/inspector/animation/test/browser.ini
@@ -31,17 +31,18 @@ support-files =
 [browser_animation_animation-target_select.js]
 [browser_animation_animation-timeline-tick.js]
 [browser_animation_css-transition-with-playstate-idle.js]
 [browser_animation_current-time-label.js]
 [browser_animation_current-time-scrubber.js]
 [browser_animation_current-time-scrubber_each-different-creation-time-animations.js]
 [browser_animation_empty_on_invalid_nodes.js]
 [browser_animation_inspector_exists.js]
-[browser_animation_keyframes-graph_computed-value-path.js]
+[browser_animation_keyframes-graph_computed-value-path-01.js]
+[browser_animation_keyframes-graph_computed-value-path-02.js]
 [browser_animation_keyframes-graph_computed-value-path_easing-hint.js]
 skip-if = (os == "win") || (os == "linux") #1461899
 [browser_animation_keyframes-graph_keyframe-marker.js]
 [browser_animation_keyframes-progress-bar.js]
 [browser_animation_keyframes-progress-bar_after-resuming.js]
 [browser_animation_logic_auto-stop.js]
 [browser_animation_logic_avoid-updating-during-hiding.js]
 [browser_animation_logic_created-time.js]
--- a/devtools/client/inspector/animation/test/browser_animation_animation-target_highlight.js
+++ b/devtools/client/inspector/animation/test/browser_animation_animation-target_highlight.js
@@ -3,66 +3,94 @@
 
 "use strict";
 
 // Test for following highlighting related.
 // * highlight when mouse over on a target node
 // * unhighlight when mouse out from the above element
 // * lock highlighting when click on the inspect icon in animation target component
 // * add 'highlighting' class to animation target component during locking
+// * mouseover locked target node
 // * unlock highlighting when click on the above icon
 // * lock highlighting when click on the other inspect icon
 // * if the locked node has multi animations,
 //   the class will add to those animation target as well
 
 add_task(async function() {
   await addTab(URL_ROOT + "doc_simple_animation.html");
   await removeAnimatedElementsExcept([".animated", ".multi"]);
-  const { animationInspector, panel, toolbox } = await openAnimationInspector();
+  const {
+    animationInspector,
+    inspector,
+    panel,
+    toolbox,
+  } = await openAnimationInspector();
 
   info("Check highlighting when mouse over on a target node");
-  let onHighlight = toolbox.once("node-highlight");
+  const onHighlight = toolbox.once("node-highlight");
   mouseOverOnTargetNode(animationInspector, panel, 0);
   let nodeFront = await onHighlight;
   assertNodeFront(nodeFront, "DIV", "ball animated");
 
   info("Check unhighlighting when mouse out on a target node");
   const onUnhighlight = toolbox.once("node-unhighlight");
   mouseOutOnTargetNode(animationInspector, panel, 0);
   await onUnhighlight;
   ok(true, "Unhighlighted the targe node");
 
   info("Check node is highlighted when the inspect icon is clicked");
-  onHighlight = toolbox.once("node-highlight");
+  let onHighlighterShown = inspector.highlighters.once("box-model-highlighter-shown");
   await clickOnInspectIcon(animationInspector, panel, 0);
-  nodeFront = await onHighlight;
+  nodeFront = await onHighlighterShown;
   assertNodeFront(nodeFront, "DIV", "ball animated");
   ok(panel.querySelectorAll(".animation-target")[0].classList.contains("highlighting"),
     "The highlighted animation target element should have 'highlighting' class");
 
   info("Check if the animation target is still highlighted on mouse out");
   mouseOutOnTargetNode(animationInspector, panel, 0);
   await wait(500);
   ok(panel.querySelectorAll(".animation-target")[0].classList.contains("highlighting"),
     "The highlighted element still should have 'highlighting' class");
 
+  info("Check no highlight event occur by mouse over locked target");
+  let highlightEventCount = 0;
+  const highlightEventCounter = () => {
+    highlightEventCount += 1;
+  };
+  toolbox.on("node-highlight", highlightEventCounter);
+  mouseOverOnTargetNode(animationInspector, panel, 0);
+  await wait(500);
+  is(highlightEventCount, 0, "Highlight event should not occur");
+  toolbox.off("node-highlight", highlightEventCounter);
+
   info("Highlighting another animation target");
-  onHighlight = toolbox.once("node-highlight");
+  onHighlighterShown = inspector.highlighters.once("box-model-highlighter-shown");
   await clickOnInspectIcon(animationInspector, panel, 1);
-  nodeFront = await onHighlight;
+  nodeFront = await onHighlighterShown;
   assertNodeFront(nodeFront, "DIV", "ball multi");
 
   info("Check the highlighted state of the animation targets");
   const animationTargetEls = panel.querySelectorAll(".animation-target");
   ok(!animationTargetEls[0].classList.contains("highlighting"),
     "The animation target[0] should not have 'highlighting' class");
   ok(animationTargetEls[1].classList.contains("highlighting"),
     "The animation target[1] should have 'highlighting' class");
   ok(animationTargetEls[2].classList.contains("highlighting"),
     "The animation target[2] should have 'highlighting' class");
+
+  info("Hide highlighter");
+  const onHighlighterHidden = inspector.highlighters.once("box-model-highlighter-hidden");
+  await clickOnInspectIcon(animationInspector, panel, 1);
+  await onHighlighterHidden;
+
+  info("Check the highlighted state of the animation targets");
+  ok(!animationTargetEls[1].classList.contains("highlighting"),
+    "The animation target[1] should not have 'highlighting' class");
+  ok(!animationTargetEls[2].classList.contains("highlighting"),
+    "The animation target[2] should not have 'highlighting' class");
 });
 
 function assertNodeFront(nodeFront, tagName, classValue) {
   is(nodeFront.tagName, "DIV",
      "The highlighted node has the correct tagName");
   is(nodeFront.attributes[0].name, "class",
      "The highlighted node has the correct attributes");
   is(nodeFront.attributes[0].value, classValue,
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/test/browser_animation_keyframes-graph_computed-value-path-01.js
@@ -0,0 +1,341 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test for following ComputedValuePath component:
+// * element existence
+// * path segments
+// * fill color by animation type
+// * stop color if the animation type is color
+
+requestLongerTimeout(2);
+
+const TEST_DATA = [
+  {
+    targetClass: "multi-types",
+    properties: [
+      {
+        name: "background-color",
+        computedValuePathClass: "color-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 0, y: 100 },
+          { x: 1000, y: 100 },
+        ],
+        expectedStopColors: [
+          { offset: 0, color: "rgb(255, 0, 0)" },
+          { offset: 1, color: "rgb(0, 255, 0)" },
+        ]
+      },
+      {
+        name: "background-repeat",
+        computedValuePathClass: "discrete-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 499.999, y: 0 },
+          { x: 500, y: 100 },
+          { x: 1000, y: 100 },
+        ],
+      },
+      {
+        name: "font-size",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 500, y: 50 },
+          { x: 1000, y: 100 },
+        ],
+      },
+      {
+        name: "margin-left",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 500, y: 50 },
+          { x: 1000, y: 100 },
+        ],
+      },
+      {
+        name: "opacity",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 500, y: 50 },
+          { x: 1000, y: 100 },
+        ],
+      },
+      {
+        name: "text-align",
+        computedValuePathClass: "discrete-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 499.999, y: 0 },
+          { x: 500, y: 100 },
+          { x: 1000, y: 100 },
+        ],
+      },
+      {
+        name: "transform",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 500, y: 50 },
+          { x: 1000, y: 100 },
+        ],
+      },
+    ],
+  },
+  {
+    targetClass: "multi-types-reverse",
+    properties: [
+      {
+        name: "background-color",
+        computedValuePathClass: "color-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 0, y: 100 },
+          { x: 1000, y: 100 },
+        ],
+        expectedStopColors: [
+          { offset: 0, color: "rgb(0, 255, 0)" },
+          { offset: 1, color: "rgb(255, 0, 0)" },
+        ]
+      },
+      {
+        name: "background-repeat",
+        computedValuePathClass: "discrete-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 499.999, y: 0 },
+          { x: 500, y: 100 },
+          { x: 1000, y: 100 },
+        ],
+      },
+      {
+        name: "font-size",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 100 },
+          { x: 500, y: 50 },
+          { x: 1000, y: 0 },
+        ],
+      },
+      {
+        name: "margin-left",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 100 },
+          { x: 500, y: 50 },
+          { x: 1000, y: 0 },
+        ],
+      },
+      {
+        name: "opacity",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 100 },
+          { x: 500, y: 50 },
+          { x: 1000, y: 0 },
+        ],
+      },
+      {
+        name: "text-align",
+        computedValuePathClass: "discrete-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 499.999, y: 0 },
+          { x: 500, y: 100 },
+          { x: 1000, y: 100 },
+        ],
+      },
+      {
+        name: "transform",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 100 },
+          { x: 500, y: 50 },
+          { x: 1000, y: 0 },
+        ],
+      },
+    ],
+  },
+  {
+    targetClass: "middle-keyframe",
+    properties: [
+      {
+        name: "background-color",
+        computedValuePathClass: "color-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 0, y: 100 },
+          { x: 500, y: 100 },
+          { x: 1000, y: 100 },
+        ],
+        expectedStopColors: [
+          { offset: 0, color: "rgb(255, 0, 0)" },
+          { offset: 0.5, color: "rgb(0, 0, 255)" },
+          { offset: 1, color: "rgb(0, 255, 0)" },
+        ]
+      },
+      {
+        name: "background-repeat",
+        computedValuePathClass: "discrete-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 249.999, y: 0 },
+          { x: 250, y: 100 },
+          { x: 749.999, y: 100 },
+          { x: 750, y: 0 },
+          { x: 1000, y: 0 },
+        ],
+      },
+      {
+        name: "font-size",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 250, y: 50 },
+          { x: 500, y: 100 },
+          { x: 750, y: 50 },
+          { x: 1000, y: 0 },
+        ],
+      },
+      {
+        name: "margin-left",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 250, y: 50 },
+          { x: 500, y: 100 },
+          { x: 750, y: 50 },
+          { x: 1000, y: 0 },
+        ],
+      },
+      {
+        name: "opacity",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 250, y: 50 },
+          { x: 500, y: 100 },
+          { x: 750, y: 50 },
+          { x: 1000, y: 0 },
+        ],
+      },
+      {
+        name: "text-align",
+        computedValuePathClass: "discrete-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 249.999, y: 0 },
+          { x: 250, y: 100 },
+          { x: 749.999, y: 100 },
+          { x: 750, y: 0 },
+          { x: 1000, y: 0 },
+        ],
+      },
+      {
+        name: "transform",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 250, y: 50 },
+          { x: 500, y: 100 },
+          { x: 750, y: 50 },
+          { x: 1000, y: 0 },
+        ],
+      },
+    ],
+  },
+  {
+    targetClass: "steps-keyframe",
+    properties: [
+      {
+        name: "background-color",
+        computedValuePathClass: "color-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 0, y: 100 },
+          { x: 500, y: 100 },
+          { x: 1000, y: 100 },
+        ],
+        expectedStopColors: [
+          { offset: 0, color: "rgb(255, 0, 0)" },
+          { offset: 0.499, color: "rgb(255, 0, 0)" },
+          { offset: 0.5, color: "rgb(128, 128, 0)" },
+          { offset: 0.999, color: "rgb(128, 128, 0)" },
+          { offset: 1, color: "rgb(0, 255, 0)" },
+        ]
+      },
+      {
+        name: "background-repeat",
+        computedValuePathClass: "discrete-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 499.999, y: 0 },
+          { x: 500, y: 100 },
+          { x: 1000, y: 100 },
+        ],
+      },
+      {
+        name: "font-size",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 500, y: 0 },
+          { x: 500, y: 50 },
+          { x: 1000, y: 50 },
+          { x: 1000, y: 100 },
+        ],
+      },
+      {
+        name: "margin-left",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 499.999, y: 0 },
+          { x: 500, y: 50 },
+          { x: 999.999, y: 50 },
+          { x: 1000, y: 100 },
+        ],
+      },
+      {
+        name: "opacity",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 499.999, y: 0 },
+          { x: 500, y: 50 },
+          { x: 999.999, y: 50 },
+          { x: 1000, y: 100 },
+        ],
+      },
+      {
+        name: "text-align",
+        computedValuePathClass: "discrete-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 499.999, y: 0 },
+          { x: 500, y: 100 },
+          { x: 1000, y: 100 },
+        ],
+      },
+      {
+        name: "transform",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 500, y: 0 },
+          { x: 500, y: 50 },
+          { x: 1000, y: 50 },
+          { x: 1000, y: 100 },
+        ],
+      },
+    ],
+  },
+];
+
+add_task(async function() {
+  await testKeyframesGraphComputedValuePath(TEST_DATA);
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/test/browser_animation_keyframes-graph_computed-value-path-02.js
@@ -0,0 +1,91 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test for following ComputedValuePath component:
+// * element existence
+// * path segments
+
+requestLongerTimeout(2);
+
+const TEST_DATA = [
+  {
+    targetClass: "steps-effect",
+    properties: [
+      {
+        name: "opacity",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 250, y: 25 },
+          { x: 500, y: 50 },
+          { x: 750, y: 75 },
+          { x: 1000, y: 100 },
+        ],
+      },
+    ],
+  },
+  {
+    targetClass: "frames-keyframe",
+    properties: [
+      {
+        name: "opacity",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 199, y: 0 },
+          { x: 200, y: 25 },
+          { x: 399, y: 25 },
+          { x: 400, y: 50 },
+          { x: 599, y: 50 },
+          { x: 600, y: 75 },
+          { x: 799, y: 75 },
+          { x: 800, y: 100 },
+          { x: 1000, y: 100 },
+        ],
+      },
+    ],
+  },
+  {
+    targetClass: "narrow-offsets",
+    properties: [
+      {
+        name: "opacity",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 100, y: 100 },
+          { x: 110, y: 100 },
+          { x: 114.9, y: 100 },
+          { x: 115, y: 50 },
+          { x: 129.9, y: 50 },
+          { x: 130, y: 0 },
+          { x: 1000, y: 100 },
+        ],
+      },
+    ],
+  },
+  {
+    targetClass: "duplicate-offsets",
+    properties: [
+      {
+        name: "opacity",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 100 },
+          { x: 250, y: 100 },
+          { x: 499, y: 100 },
+          { x: 500, y: 100 },
+          { x: 500, y: 0 },
+          { x: 750, y: 50 },
+          { x: 1000, y: 100 },
+        ],
+      },
+    ],
+  },
+];
+
+add_task(async function() {
+  await testKeyframesGraphComputedValuePath(TEST_DATA);
+});
deleted file mode 100644
--- a/devtools/client/inspector/animation/test/browser_animation_keyframes-graph_computed-value-path.js
+++ /dev/null
@@ -1,463 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-// Test for following ComputedValuePath component:
-// * element existence
-// * path segments
-// * fill color by animation type
-// * stop color if the animation type is color
-
-requestLongerTimeout(2);
-
-const TEST_DATA = [
-  {
-    targetClass: "multi-types",
-    properties: [
-      {
-        name: "background-color",
-        computedValuePathClass: "color-path",
-        expectedPathSegments: [
-          { x: 0, y: 0 },
-          { x: 0, y: 100 },
-          { x: 1000, y: 100 },
-        ],
-        expectedStopColors: [
-          { offset: 0, color: "rgb(255, 0, 0)" },
-          { offset: 1, color: "rgb(0, 255, 0)" },
-        ]
-      },
-      {
-        name: "background-repeat",
-        computedValuePathClass: "discrete-path",
-        expectedPathSegments: [
-          { x: 0, y: 0 },
-          { x: 499.999, y: 0 },
-          { x: 500, y: 100 },
-          { x: 1000, y: 100 },
-        ],
-      },
-      {
-        name: "font-size",
-        computedValuePathClass: "distance-path",
-        expectedPathSegments: [
-          { x: 0, y: 0 },
-          { x: 500, y: 50 },
-          { x: 1000, y: 100 },
-        ],
-      },
-      {
-        name: "margin-left",
-        computedValuePathClass: "distance-path",
-        expectedPathSegments: [
-          { x: 0, y: 0 },
-          { x: 500, y: 50 },
-          { x: 1000, y: 100 },
-        ],
-      },
-      {
-        name: "opacity",
-        computedValuePathClass: "distance-path",
-        expectedPathSegments: [
-          { x: 0, y: 0 },
-          { x: 500, y: 50 },
-          { x: 1000, y: 100 },
-        ],
-      },
-      {
-        name: "text-align",
-        computedValuePathClass: "discrete-path",
-        expectedPathSegments: [
-          { x: 0, y: 0 },
-          { x: 499.999, y: 0 },
-          { x: 500, y: 100 },
-          { x: 1000, y: 100 },
-        ],
-      },
-      {
-        name: "transform",
-        computedValuePathClass: "distance-path",
-        expectedPathSegments: [
-          { x: 0, y: 0 },
-          { x: 500, y: 50 },
-          { x: 1000, y: 100 },
-        ],
-      },
-    ],
-  },
-  {
-    targetClass: "multi-types-reverse",
-    properties: [
-      {
-        name: "background-color",
-        computedValuePathClass: "color-path",
-        expectedPathSegments: [
-          { x: 0, y: 0 },
-          { x: 0, y: 100 },
-          { x: 1000, y: 100 },
-        ],
-        expectedStopColors: [
-          { offset: 0, color: "rgb(0, 255, 0)" },
-          { offset: 1, color: "rgb(255, 0, 0)" },
-        ]
-      },
-      {
-        name: "background-repeat",
-        computedValuePathClass: "discrete-path",
-        expectedPathSegments: [
-          { x: 0, y: 0 },
-          { x: 499.999, y: 0 },
-          { x: 500, y: 100 },
-          { x: 1000, y: 100 },
-        ],
-      },
-      {
-        name: "font-size",
-        computedValuePathClass: "distance-path",
-        expectedPathSegments: [
-          { x: 0, y: 100 },
-          { x: 500, y: 50 },
-          { x: 1000, y: 0 },
-        ],
-      },
-      {
-        name: "margin-left",
-        computedValuePathClass: "distance-path",
-        expectedPathSegments: [
-          { x: 0, y: 100 },
-          { x: 500, y: 50 },
-          { x: 1000, y: 0 },
-        ],
-      },
-      {
-        name: "opacity",
-        computedValuePathClass: "distance-path",
-        expectedPathSegments: [
-          { x: 0, y: 100 },
-          { x: 500, y: 50 },
-          { x: 1000, y: 0 },
-        ],
-      },
-      {
-        name: "text-align",
-        computedValuePathClass: "discrete-path",
-        expectedPathSegments: [
-          { x: 0, y: 0 },
-          { x: 499.999, y: 0 },
-          { x: 500, y: 100 },
-          { x: 1000, y: 100 },
-        ],
-      },
-      {
-        name: "transform",
-        computedValuePathClass: "distance-path",
-        expectedPathSegments: [
-          { x: 0, y: 100 },
-          { x: 500, y: 50 },
-          { x: 1000, y: 0 },
-        ],
-      },
-    ],
-  },
-  {
-    targetClass: "middle-keyframe",
-    properties: [
-      {
-        name: "background-color",
-        computedValuePathClass: "color-path",
-        expectedPathSegments: [
-          { x: 0, y: 0 },
-          { x: 0, y: 100 },
-          { x: 500, y: 100 },
-          { x: 1000, y: 100 },
-        ],
-        expectedStopColors: [
-          { offset: 0, color: "rgb(255, 0, 0)" },
-          { offset: 0.5, color: "rgb(0, 0, 255)" },
-          { offset: 1, color: "rgb(0, 255, 0)" },
-        ]
-      },
-      {
-        name: "background-repeat",
-        computedValuePathClass: "discrete-path",
-        expectedPathSegments: [
-          { x: 0, y: 0 },
-          { x: 249.999, y: 0 },
-          { x: 250, y: 100 },
-          { x: 749.999, y: 100 },
-          { x: 750, y: 0 },
-          { x: 1000, y: 0 },
-        ],
-      },
-      {
-        name: "font-size",
-        computedValuePathClass: "distance-path",
-        expectedPathSegments: [
-          { x: 0, y: 0 },
-          { x: 250, y: 50 },
-          { x: 500, y: 100 },
-          { x: 750, y: 50 },
-          { x: 1000, y: 0 },
-        ],
-      },
-      {
-        name: "margin-left",
-        computedValuePathClass: "distance-path",
-        expectedPathSegments: [
-          { x: 0, y: 0 },
-          { x: 250, y: 50 },
-          { x: 500, y: 100 },
-          { x: 750, y: 50 },
-          { x: 1000, y: 0 },
-        ],
-      },
-      {
-        name: "opacity",
-        computedValuePathClass: "distance-path",
-        expectedPathSegments: [
-          { x: 0, y: 0 },
-          { x: 250, y: 50 },
-          { x: 500, y: 100 },
-          { x: 750, y: 50 },
-          { x: 1000, y: 0 },
-        ],
-      },
-      {
-        name: "text-align",
-        computedValuePathClass: "discrete-path",
-        expectedPathSegments: [
-          { x: 0, y: 0 },
-          { x: 249.999, y: 0 },
-          { x: 250, y: 100 },
-          { x: 749.999, y: 100 },
-          { x: 750, y: 0 },
-          { x: 1000, y: 0 },
-        ],
-      },
-      {
-        name: "transform",
-        computedValuePathClass: "distance-path",
-        expectedPathSegments: [
-          { x: 0, y: 0 },
-          { x: 250, y: 50 },
-          { x: 500, y: 100 },
-          { x: 750, y: 50 },
-          { x: 1000, y: 0 },
-        ],
-      },
-    ],
-  },
-  {
-    targetClass: "steps-keyframe",
-    properties: [
-      {
-        name: "background-color",
-        computedValuePathClass: "color-path",
-        expectedPathSegments: [
-          { x: 0, y: 0 },
-          { x: 0, y: 100 },
-          { x: 500, y: 100 },
-          { x: 1000, y: 100 },
-        ],
-        expectedStopColors: [
-          { offset: 0, color: "rgb(255, 0, 0)" },
-          { offset: 0.499, color: "rgb(255, 0, 0)" },
-          { offset: 0.5, color: "rgb(128, 128, 0)" },
-          { offset: 0.999, color: "rgb(128, 128, 0)" },
-          { offset: 1, color: "rgb(0, 255, 0)" },
-        ]
-      },
-      {
-        name: "background-repeat",
-        computedValuePathClass: "discrete-path",
-        expectedPathSegments: [
-          { x: 0, y: 0 },
-          { x: 499.999, y: 0 },
-          { x: 500, y: 100 },
-          { x: 1000, y: 100 },
-        ],
-      },
-      {
-        name: "font-size",
-        computedValuePathClass: "distance-path",
-        expectedPathSegments: [
-          { x: 0, y: 0 },
-          { x: 500, y: 0 },
-          { x: 500, y: 50 },
-          { x: 1000, y: 50 },
-          { x: 1000, y: 100 },
-        ],
-      },
-      {
-        name: "margin-left",
-        computedValuePathClass: "distance-path",
-        expectedPathSegments: [
-          { x: 0, y: 0 },
-          { x: 499.999, y: 0 },
-          { x: 500, y: 50 },
-          { x: 999.999, y: 50 },
-          { x: 1000, y: 100 },
-        ],
-      },
-      {
-        name: "opacity",
-        computedValuePathClass: "distance-path",
-        expectedPathSegments: [
-          { x: 0, y: 0 },
-          { x: 499.999, y: 0 },
-          { x: 500, y: 50 },
-          { x: 999.999, y: 50 },
-          { x: 1000, y: 100 },
-        ],
-      },
-      {
-        name: "text-align",
-        computedValuePathClass: "discrete-path",
-        expectedPathSegments: [
-          { x: 0, y: 0 },
-          { x: 499.999, y: 0 },
-          { x: 500, y: 100 },
-          { x: 1000, y: 100 },
-        ],
-      },
-      {
-        name: "transform",
-        computedValuePathClass: "distance-path",
-        expectedPathSegments: [
-          { x: 0, y: 0 },
-          { x: 500, y: 0 },
-          { x: 500, y: 50 },
-          { x: 1000, y: 50 },
-          { x: 1000, y: 100 },
-        ],
-      },
-    ],
-  },
-  {
-    targetClass: "steps-effect",
-    properties: [
-      {
-        name: "opacity",
-        computedValuePathClass: "distance-path",
-        expectedPathSegments: [
-          { x: 0, y: 0 },
-          { x: 250, y: 25 },
-          { x: 500, y: 50 },
-          { x: 750, y: 75 },
-          { x: 1000, y: 100 },
-        ],
-      },
-    ],
-  },
-  {
-    targetClass: "frames-keyframe",
-    properties: [
-      {
-        name: "opacity",
-        computedValuePathClass: "distance-path",
-        expectedPathSegments: [
-          { x: 0, y: 0 },
-          { x: 199, y: 0 },
-          { x: 200, y: 25 },
-          { x: 399, y: 25 },
-          { x: 400, y: 50 },
-          { x: 599, y: 50 },
-          { x: 600, y: 75 },
-          { x: 799, y: 75 },
-          { x: 800, y: 100 },
-          { x: 1000, y: 100 },
-        ],
-      },
-    ],
-  },
-  {
-    targetClass: "narrow-offsets",
-    properties: [
-      {
-        name: "opacity",
-        computedValuePathClass: "distance-path",
-        expectedPathSegments: [
-          { x: 0, y: 0 },
-          { x: 100, y: 100 },
-          { x: 110, y: 100 },
-          { x: 114.9, y: 100 },
-          { x: 115, y: 50 },
-          { x: 129.9, y: 50 },
-          { x: 130, y: 0 },
-          { x: 1000, y: 100 },
-        ],
-      },
-    ],
-  },
-  {
-    targetClass: "duplicate-offsets",
-    properties: [
-      {
-        name: "opacity",
-        computedValuePathClass: "distance-path",
-        expectedPathSegments: [
-          { x: 0, y: 100 },
-          { x: 250, y: 100 },
-          { x: 499, y: 100 },
-          { x: 500, y: 100 },
-          { x: 500, y: 0 },
-          { x: 750, y: 50 },
-          { x: 1000, y: 100 },
-        ],
-      },
-    ],
-  },
-];
-
-add_task(async function() {
-  await addTab(URL_ROOT + "doc_multi_keyframes.html");
-  const { animationInspector, panel } = await openAnimationInspector();
-
-  for (const { properties, targetClass } of TEST_DATA) {
-    info(`Checking keyframes graph for ${ targetClass }`);
-    await clickOnAnimationByTargetSelector(animationInspector,
-                                           panel, `.${ targetClass }`);
-
-    for (const property of properties) {
-      const {
-        name,
-        computedValuePathClass,
-        expectedPathSegments,
-        expectedStopColors,
-      } = property;
-
-      const testTarget = `${ name } in ${ targetClass }`;
-      info(`Checking keyframes graph for ${ testTarget }`);
-      info(`Checking keyframes graph path existence for ${ testTarget }`);
-      const keyframesGraphPathEl = panel.querySelector(`.${ name }`);
-      ok(keyframesGraphPathEl,
-        `The keyframes graph path element of ${ testTarget } should be existence`);
-
-      info(`Checking computed value path existence for ${ testTarget }`);
-      const computedValuePathEl =
-        keyframesGraphPathEl.querySelector(`.${ computedValuePathClass }`);
-      ok(computedValuePathEl,
-        `The computed value path element of ${ testTarget } should be existence`);
-
-      info(`Checking path segments for ${ testTarget }`);
-      const pathEl = computedValuePathEl.querySelector("path");
-      ok(pathEl, `The <path> element of ${ testTarget } should be existence`);
-      assertPathSegments(pathEl, true, expectedPathSegments);
-
-      if (!expectedStopColors) {
-        continue;
-      }
-
-      info(`Checking linearGradient for ${ testTarget }`);
-      const linearGradientEl = computedValuePathEl.querySelector("linearGradient");
-      ok(linearGradientEl,
-        `The <linearGradientEl> element of ${ testTarget } should be existence`);
-
-      for (const expectedStopColor of expectedStopColors) {
-        const { offset, color } = expectedStopColor;
-        assertLinearGradient(linearGradientEl, offset, color);
-      }
-    }
-  }
-});
--- a/devtools/client/inspector/animation/test/browser_animation_pause-resume-button_end-time.js
+++ b/devtools/client/inspector/animation/test/browser_animation_pause-resume-button_end-time.js
@@ -21,27 +21,35 @@ add_task(async function() {
                   ["running", "finished", "finished"]);
   await clickOnCurrentTimeScrubberController(animationInspector, panel, 0);
 
   info("Check animations state after resuming without infinite animation");
   info("Remove infinite animation");
   await setClassAttribute(animationInspector, ".animated", "ball still");
   info("Make the current time of animation to be over its end time");
   await clickOnCurrentTimeScrubberController(animationInspector, panel, 1);
+  await clickOnPlaybackRateSelector(animationInspector, panel, 10);
   info("Resume animations");
   await clickOnPauseResumeButton(animationInspector, panel);
   assertPlayState(animationInspector.state.animations, ["running", "running"]);
   assertCurrentTimeLessThanDuration(animationInspector.state.animations);
+  assertScrubberPosition(panel);
 });
 
 function assertPlayState(animations, expectedState) {
   animations.forEach((animation, index) => {
     is(animation.state.playState, expectedState[index],
        `The playState of animation [${ index }] should be ${ expectedState[index] }`);
   });
 }
 
 function assertCurrentTimeLessThanDuration(animations) {
   animations.forEach((animation, index) => {
     ok(animation.state.currentTime < animation.state.duration,
-       "The current time of animation[${ index }] should be less than its duration");
+       `The current time of animation[${ index }] should be less than its duration`);
   });
 }
+
+function assertScrubberPosition(panel) {
+  const scrubberEl = panel.querySelector(".current-time-scrubber");
+  const translateX = parseFloat(scrubberEl.style.transform.match(/-?\d+(\.\d+)?/)[0]);
+  ok(translateX >= 0, "The translateX of scrubber position should be zero or more");
+}
--- a/devtools/client/inspector/animation/test/head.js
+++ b/devtools/client/inspector/animation/test/head.js
@@ -756,8 +756,66 @@ function findStopElement(linearGradientE
   for (const stopEl of linearGradientEl.querySelectorAll("stop")) {
     if (offset <= parseFloat(stopEl.getAttribute("offset"))) {
       return stopEl;
     }
   }
 
   return null;
 }
+
+/**
+ * Do test for keyframes-graph_computed-value-path-1/2.
+ *
+ * @param {Array} testData
+ */
+async function testKeyframesGraphComputedValuePath(testData) {
+  await addTab(URL_ROOT + "doc_multi_keyframes.html");
+  await removeAnimatedElementsExcept(testData.map(t => `.${ t.targetClass }`));
+  const { animationInspector, panel } = await openAnimationInspector();
+
+  for (const { properties, targetClass } of testData) {
+    info(`Checking keyframes graph for ${ targetClass }`);
+    await clickOnAnimationByTargetSelector(animationInspector,
+                                           panel, `.${ targetClass }`);
+
+    for (const property of properties) {
+      const {
+        name,
+        computedValuePathClass,
+        expectedPathSegments,
+        expectedStopColors,
+      } = property;
+
+      const testTarget = `${ name } in ${ targetClass }`;
+      info(`Checking keyframes graph for ${ testTarget }`);
+      info(`Checking keyframes graph path existence for ${ testTarget }`);
+      const keyframesGraphPathEl = panel.querySelector(`.${ name }`);
+      ok(keyframesGraphPathEl,
+         `The keyframes graph path element of ${ testTarget } should be existence`);
+
+      info(`Checking computed value path existence for ${ testTarget }`);
+      const computedValuePathEl =
+        keyframesGraphPathEl.querySelector(`.${ computedValuePathClass }`);
+      ok(computedValuePathEl,
+         `The computed value path element of ${ testTarget } should be existence`);
+
+      info(`Checking path segments for ${ testTarget }`);
+      const pathEl = computedValuePathEl.querySelector("path");
+      ok(pathEl, `The <path> element of ${ testTarget } should be existence`);
+      assertPathSegments(pathEl, true, expectedPathSegments);
+
+      if (!expectedStopColors) {
+        continue;
+      }
+
+      info(`Checking linearGradient for ${ testTarget }`);
+      const linearGradientEl = computedValuePathEl.querySelector("linearGradient");
+      ok(linearGradientEl,
+         `The <linearGradientEl> element of ${ testTarget } should be existence`);
+
+      for (const expectedStopColor of expectedStopColors) {
+        const { offset, color } = expectedStopColor;
+        assertLinearGradient(linearGradientEl, offset, color);
+      }
+    }
+  }
+}
--- a/devtools/client/inspector/shared/highlighters-overlay.js
+++ b/devtools/client/inspector/shared/highlighters-overlay.js
@@ -438,28 +438,31 @@ class HighlightersOverlay {
     }
 
     const isShown = await highlighter.show(node, options);
     if (!isShown) {
       return;
     }
 
     this.boxModelHighlighterShown = node;
+    this.emit("box-model-highlighter-shown", node);
   }
 
   /**
    * Hide the box model highlighter.
    */
   async hideBoxModelHighlighter() {
     if (!this.boxModelHighlighterShown || !this.highlighters.BoxModelHighlighter) {
       return;
     }
 
     await this.highlighters.BoxModelHighlighter.hide();
+    const node = this.boxModelHighlighterShown;
     this.boxModelHighlighterShown = null;
+    this.emit("box-model-highlighter-hidden", node);
   }
 
   /**
    * Toggle the geometry editor highlighter for the given element.
    *
    * @param {NodeFront} node
    *        The NodeFront of the element to highlight.
    */
--- a/devtools/client/locales/en-US/performance.properties
+++ b/devtools/client/locales/en-US/performance.properties
@@ -58,23 +58,23 @@ graphs.ms=ms
 # AS SHORT AS POSSIBLE so it doesn't obstruct important parts of the graph.
 graphs.memory=MB
 
 # LOCALIZATION NOTE (category.*):
 # These strings are displayed in the categories graph of the Performance Tools,
 # as the legend for each block in every bar. These labels should be kept
 # AS SHORT AS POSSIBLE so they don't obstruct important parts of the graph.
 category.other=Gecko
-category.css=Styles
+category.layout=Layout
 category.js=JIT
 category.gc=GC
 category.network=Network
 category.graphics=Graphics
-category.storage=Storage
-category.events=Input & Events
+category.dom=DOM
+category.idle=Idle
 category.tools=Tools
 
 # LOCALIZATION NOTE (table.bytes):
 # This string is displayed in the call tree after bytesize units.
 # %S represents the value in bytes.
 table.bytes=%S B
 
 # LOCALIZATION NOTE (table.ms2):
--- a/devtools/client/locales/jar.mn
+++ b/devtools/client/locales/jar.mn
@@ -1,13 +1,13 @@
 #filter substitution
 # 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/.
 
 [localization] @AB_CD@.jar:
-    devtools (en-US/**/*.ftl)
+    devtools (%*.ftl)
 
 @AB_CD@.jar:
 %   locale devtools @AB_CD@ %locale/@AB_CD@/devtools/client/
     locale/@AB_CD@/devtools/client/ (%*.properties)
     locale/@AB_CD@/devtools/client/ (%*.dtd)
 
--- a/devtools/client/performance/modules/categories.js
+++ b/devtools/client/performance/modules/categories.js
@@ -2,26 +2,30 @@
  * 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 { L10N } = require("devtools/client/performance/modules/global");
 
 /**
  * Details about each label stack frame category.
- * @see CATEGORY_MAPPINGS.
+ * To be kept in sync with the js::ProfilingStackFrame::Category in ProfilingStack.h
  */
 const CATEGORIES = [{
+  color: "#d99b28",
+  abbrev: "idle",
+  label: L10N.getStr("category.idle")
+}, {
   color: "#5e88b0",
   abbrev: "other",
   label: L10N.getStr("category.other")
 }, {
   color: "#46afe3",
-  abbrev: "css",
-  label: L10N.getStr("category.css")
+  abbrev: "layout",
+  label: L10N.getStr("category.layout")
 }, {
   color: "#d96629",
   abbrev: "js",
   label: L10N.getStr("category.js")
 }, {
   color: "#eb5368",
   abbrev: "gc",
   label: L10N.getStr("category.gc")
@@ -30,99 +34,40 @@ const CATEGORIES = [{
   abbrev: "network",
   label: L10N.getStr("category.network")
 }, {
   color: "#70bf53",
   abbrev: "graphics",
   label: L10N.getStr("category.graphics")
 }, {
   color: "#8fa1b2",
-  abbrev: "storage",
-  label: L10N.getStr("category.storage")
+  abbrev: "dom",
+  label: L10N.getStr("category.dom")
 }, {
-  color: "#d99b28",
-  abbrev: "events",
-  label: L10N.getStr("category.events")
-}, {
+  // The devtools-only "tools" category which gets computed by
+  // computeIsContentAndCategory and is not part of the category list in
+  // ProfilingStack.h.
   color: "#8fa1b2",
   abbrev: "tools",
   label: L10N.getStr("category.tools")
 }];
 
 /**
- * Mapping from category bitmasks in the profiler data to additional details.
- * To be kept in sync with the js::ProfilingStackFrame::Category in ProfilingStack.h
+ * Get the numeric index for the given category abbreviation.
+ * See `CATEGORIES` above.
  */
-const CATEGORY_MAPPINGS = {
-  // js::ProfilingStackFrame::Category::OTHER
-  "16": CATEGORIES[0],
-  // js::ProfilingStackFrame::Category::CSS
-  "32": CATEGORIES[1],
-  // js::ProfilingStackFrame::Category::JS
-  "64": CATEGORIES[2],
-  // js::ProfilingStackFrame::Category::GC
-  "128": CATEGORIES[3],
-  // js::ProfilingStackFrame::Category::CC
-  "256": CATEGORIES[3],
-  // js::ProfilingStackFrame::Category::NETWORK
-  "512": CATEGORIES[4],
-  // js::ProfilingStackFrame::Category::GRAPHICS
-  "1024": CATEGORIES[5],
-  // js::ProfilingStackFrame::Category::STORAGE
-  "2048": CATEGORIES[6],
-  // js::ProfilingStackFrame::Category::EVENTS
-  "4096": CATEGORIES[7],
-  // non-bitmasks for specially-assigned categories
-  "9000": CATEGORIES[8],
-};
-
-/**
- * Get the numeric bitmask (or set of masks) for the given category
- * abbreviation. See `CATEGORIES` and `CATEGORY_MAPPINGS` above.
- *
- * CATEGORY_MASK can be called with just a name if it is expected that the
- * category is mapped to by exactly one bitmask. If the category is mapped
- * to by multiple masks, CATEGORY_MASK for that name must be called with
- * an additional argument specifying the desired id (in ascending order).
- */
-const [CATEGORY_MASK, CATEGORY_MASK_LIST] = (() => {
-  const bitmasksForCategory = {};
-  const all = Object.keys(CATEGORY_MAPPINGS);
-
-  for (const category of CATEGORIES) {
-    bitmasksForCategory[category.abbrev] = all
-      .filter(mask => CATEGORY_MAPPINGS[mask] == category)
-      .map(mask => +mask)
-      .sort();
+const CATEGORY_INDEX = (() => {
+  const indexForCategory = {};
+  for (let categoryIndex = 0; categoryIndex < CATEGORIES.length; categoryIndex++) {
+    const category = CATEGORIES[categoryIndex];
+    indexForCategory[category.abbrev] = categoryIndex;
   }
 
-  return [
-    function(name, index) {
-      if (!(name in bitmasksForCategory)) {
-        throw new Error(`Category abbreviation "${name}" does not exist.`);
-      }
-      if (arguments.length == 1) {
-        if (bitmasksForCategory[name].length != 1) {
-          throw new Error(`Expected exactly one category number for "${name}".`);
-        } else {
-          return bitmasksForCategory[name][0];
-        }
-      } else {
-        if (index > bitmasksForCategory[name].length) {
-          throw new Error(`Index "${index}" too high for category "${name}".`);
-        }
-        return bitmasksForCategory[name][index - 1];
-      }
-    },
-
-    function(name) {
-      if (!(name in bitmasksForCategory)) {
-        throw new Error(`Category abbreviation "${name}" does not exist.`);
-      }
-      return bitmasksForCategory[name];
+  return function(name) {
+    if (!(name in indexForCategory)) {
+      throw new Error(`Category abbreviation "${name}" does not exist.`);
     }
-  ];
+    return indexForCategory[name];
+  };
 })();
 
 exports.CATEGORIES = CATEGORIES;
-exports.CATEGORY_MAPPINGS = CATEGORY_MAPPINGS;
-exports.CATEGORY_MASK = CATEGORY_MASK;
-exports.CATEGORY_MASK_LIST = CATEGORY_MASK_LIST;
+exports.CATEGORY_INDEX = CATEGORY_INDEX;
--- a/devtools/client/performance/modules/logic/frame-utils.js
+++ b/devtools/client/performance/modules/logic/frame-utils.js
@@ -4,17 +4,17 @@
 "use strict";
 
 const global = require("devtools/client/performance/modules/global");
 const demangle = require("devtools/client/shared/demangle");
 const { assert } = require("devtools/shared/DevToolsUtils");
 const { isChromeScheme, isContentScheme, isWASM, parseURL } =
   require("devtools/client/shared/source-utils");
 
-const { CATEGORY_MASK, CATEGORY_MAPPINGS } = require("devtools/client/performance/modules/categories");
+const { CATEGORY_INDEX, CATEGORIES } = require("devtools/client/performance/modules/categories");
 
 // Character codes used in various parsing helper functions.
 const CHAR_CODE_R = "r".charCodeAt(0);
 const CHAR_CODE_0 = "0".charCodeAt(0);
 const CHAR_CODE_9 = "9".charCodeAt(0);
 const CHAR_CODE_CAP_Z = "Z".charCodeAt(0);
 
 const CHAR_CODE_LPAREN = "(".charCodeAt(0);
@@ -185,17 +185,17 @@ function parseLocation(location, fallbac
 
 /**
  * Sets the properties of `isContent` and `category` on a frame.
  *
  * @param {InflatedFrame} frame
  */
 function computeIsContentAndCategory(frame) {
   // Only C++ stack frames have associated category information.
-  if (frame.category) {
+  if (frame.category !== null && frame.category !== undefined) {
     return;
   }
 
   const location = frame.location;
 
   // There are 3 variants of location strings in the profiler (with optional
   // column numbers):
   //   1) "name (resource:line)"
@@ -229,28 +229,28 @@ function computeIsContentAndCategory(fra
   }
 
   if (schemeStartIndex !== 0) {
     for (let j = schemeStartIndex; j < location.length; j++) {
       if (location.charCodeAt(j) === CHAR_CODE_R &&
           isChromeScheme(location, j) &&
           (location.includes("resource://devtools") ||
            location.includes("resource://devtools"))) {
-        frame.category = CATEGORY_MASK("tools");
+        frame.category = CATEGORY_INDEX("tools");
         return;
       }
     }
   }
 
   if (location === "EnterJIT") {
-    frame.category = CATEGORY_MASK("js");
+    frame.category = CATEGORY_INDEX("js");
     return;
   }
 
-  frame.category = CATEGORY_MASK("other");
+  frame.category = CATEGORY_INDEX("other");
 }
 
 /**
  * Get caches to cache inflated frames and computed frame keys of a frame
  * table.
  *
  * @param object framesTable
  * @return object
@@ -388,17 +388,20 @@ function getFrameInfo(node, options) {
       data.functionName = global.L10N.getStr("table.root");
     } else {
       data = parseLocation(node.location, node.line, node.column);
       data.hasOptimizations = node.hasOptimizations();
       data.isContent = node.isContent;
       data.isMetaCategory = node.isMetaCategory;
     }
     data.samples = node.youngestFrameSamples;
-    data.categoryData = CATEGORY_MAPPINGS[node.category] || {};
+    const hasCategory = node.category !== null && node.category !== undefined;
+    data.categoryData = hasCategory
+      ? (CATEGORIES[node.category] || CATEGORIES[CATEGORY_INDEX("other")])
+      : {};
     data.nodeType = node.nodeType;
 
     // Frame name (function location or some meta information)
     if (data.isMetaCategory) {
       data.name = data.categoryData.label;
     } else if (shouldDemangle(data.functionName)) {
       data.name = demangle(data.functionName);
     } else {
--- a/devtools/client/performance/test/browser_perf-tree-view-02.js
+++ b/devtools/client/performance/test/browser_perf-tree-view-02.js
@@ -119,17 +119,17 @@ add_task(function() {
   is($fun(".call-tree-url", $$(".call-tree-item")[2]).textContent.trim(), "baz",
     "The .A.B node's function cell displays the correct url.");
   ok($fun(".call-tree-url", $$(".call-tree-item")[2]).getAttribute("tooltiptext").includes("http://foo/bar/baz"),
     "The .A.B node's function cell displays the correct url tooltiptext.");
   is($fun(".call-tree-line", $$(".call-tree-item")[2]).textContent.trim(), ":34",
     "The .A.B node's function cell displays the correct line.");
   is($fun(".call-tree-host", $$(".call-tree-item")[2]).textContent.trim(), "foo",
     "The .A.B node's function cell displays the correct host.");
-  is($fun(".call-tree-category", $$(".call-tree-item")[2]).textContent.trim(), "Styles",
+  is($fun(".call-tree-category", $$(".call-tree-item")[2]).textContent.trim(), "Layout",
     "The .A.B node's function cell displays the correct category.");
 
   is($$dur(3).textContent.trim(), "5 ms",
     "The .A.E node's duration cell displays the correct value.");
   is($$per(3).textContent.trim(), "25%",
     "The .A.E node's percentage cell displays the correct value.");
   is($$sam(3).textContent.trim(), "0",
     "The .A.E node's samples cell displays the correct value.");
--- a/devtools/client/performance/test/browser_perf-tree-view-08.js
+++ b/devtools/client/performance/test/browser_perf-tree-view-08.js
@@ -4,17 +4,17 @@
 
 /**
  * Tests that the profiler's tree view renders generalized platform data
  * when `contentOnly` is on correctly.
  */
 
 const { ThreadNode } = require("devtools/client/performance/modules/logic/tree-model");
 const { CallView } = require("devtools/client/performance/modules/widgets/tree-view");
-const { CATEGORY_MASK } = require("devtools/client/performance/modules/categories");
+const { CATEGORY_INDEX } = require("devtools/client/performance/modules/categories");
 const RecordingUtils = require("devtools/shared/performance/recording-utils");
 
 add_task(function() {
   const threadNode = new ThreadNode(gProfile.threads[0], { startTime: 0, endTime: 20,
                                                            contentOnly: true });
 
   // Don't display the synthesized (root) and the real (root) node twice.
   threadNode.calls = threadNode.calls[0].calls;
@@ -84,26 +84,26 @@ const gProfile = RecordingUtils.deflateP
       ]
     }, {
       time: 1 + 1 + 2,
       frames: [
         { location: "(root)" },
         { location: "http://content/A" },
         { location: "http://content/E" },
         { location: "http://content/F" },
-        { location: "platform_JS", category: CATEGORY_MASK("js") },
+        { location: "platform_JS", category: CATEGORY_INDEX("js") },
       ]
     }, {
       time: 1 + 1 + 2 + 3,
       frames: [
         { location: "(root)" },
-        { location: "platform_JS2", category: CATEGORY_MASK("js") },
+        { location: "platform_JS2", category: CATEGORY_INDEX("js") },
       ]
     }, {
       time: 1 + 1 + 2 + 3 + 5,
       frames: [
         { location: "(root)" },
         { location: "http://content/A" },
-        { location: "platform_GC", category: CATEGORY_MASK("gc", 1) },
+        { location: "platform_GC", category: CATEGORY_INDEX("gc") },
       ]
     }]
   }]
 });
--- a/devtools/client/performance/test/helpers/synth-utils.js
+++ b/devtools/client/performance/test/helpers/synth-utils.js
@@ -1,53 +1,53 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 "use strict";
 
 /**
  * Generates a generalized profile with some samples.
  */
 exports.synthesizeProfile = () => {
-  const { CATEGORY_MASK } = require("devtools/client/performance/modules/categories");
+  const { CATEGORY_INDEX } = require("devtools/client/performance/modules/categories");
   const RecordingUtils = require("devtools/shared/performance/recording-utils");
 
   return RecordingUtils.deflateProfile({
     meta: { version: 2 },
     threads: [{
       samples: [{
         time: 1,
         frames: [
-          { category: CATEGORY_MASK("other"), location: "(root)" },
-          { category: CATEGORY_MASK("other"), location: "A (http://foo/bar/baz:12)" },
-          { category: CATEGORY_MASK("css"), location: "B (http://foo/bar/baz:34)" },
-          { category: CATEGORY_MASK("js"), location: "C (http://foo/bar/baz:56)" }
+          { category: CATEGORY_INDEX("other"), location: "(root)" },
+          { category: CATEGORY_INDEX("other"), location: "A (http://foo/bar/baz:12)" },
+          { category: CATEGORY_INDEX("layout"), location: "B (http://foo/bar/baz:34)" },
+          { category: CATEGORY_INDEX("js"), location: "C (http://foo/bar/baz:56)" }
         ]
       }, {
         time: 1 + 1,
         frames: [
-          { category: CATEGORY_MASK("other"), location: "(root)" },
-          { category: CATEGORY_MASK("other"), location: "A (http://foo/bar/baz:12)" },
-          { category: CATEGORY_MASK("css"), location: "B (http://foo/bar/baz:34)" },
-          { category: CATEGORY_MASK("gc", 1), location: "D (http://foo/bar/baz:78:9)" }
+          { category: CATEGORY_INDEX("other"), location: "(root)" },
+          { category: CATEGORY_INDEX("other"), location: "A (http://foo/bar/baz:12)" },
+          { category: CATEGORY_INDEX("layout"), location: "B (http://foo/bar/baz:34)" },
+          { category: CATEGORY_INDEX("gc"), location: "D (http://foo/bar/baz:78:9)" }
         ]
       }, {
         time: 1 + 1 + 2,
         frames: [
-          { category: CATEGORY_MASK("other"), location: "(root)" },
-          { category: CATEGORY_MASK("other"), location: "A (http://foo/bar/baz:12)" },
-          { category: CATEGORY_MASK("css"), location: "B (http://foo/bar/baz:34)" },
-          { category: CATEGORY_MASK("gc", 1), location: "D (http://foo/bar/baz:78:9)" }
+          { category: CATEGORY_INDEX("other"), location: "(root)" },
+          { category: CATEGORY_INDEX("other"), location: "A (http://foo/bar/baz:12)" },
+          { category: CATEGORY_INDEX("layout"), location: "B (http://foo/bar/baz:34)" },
+          { category: CATEGORY_INDEX("gc"), location: "D (http://foo/bar/baz:78:9)" }
         ]
       }, {
         time: 1 + 1 + 2 + 3,
         frames: [
-          { category: CATEGORY_MASK("other"), location: "(root)" },
-          { category: CATEGORY_MASK("other"), location: "A (http://foo/bar/baz:12)" },
-          { category: CATEGORY_MASK("gc", 2), location: "E (http://foo/bar/baz:90)" },
-          { category: CATEGORY_MASK("network"), location: "F (http://foo/bar/baz:99)" }
+          { category: CATEGORY_INDEX("other"), location: "(root)" },
+          { category: CATEGORY_INDEX("other"), location: "A (http://foo/bar/baz:12)" },
+          { category: CATEGORY_INDEX("gc"), location: "E (http://foo/bar/baz:90)" },
+          { category: CATEGORY_INDEX("network"), location: "F (http://foo/bar/baz:99)" }
         ]
       }]
     }]
   });
 };
 
 /**
  * Generates a simple implementation for a tree class.
--- a/devtools/client/performance/test/unit/test_profiler-categories.js
+++ b/devtools/client/performance/test/unit/test_profiler-categories.js
@@ -2,32 +2,24 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 "use strict";
 
 /**
  * Tests if the profiler categories are mapped correctly.
  */
 
 add_task(function() {
-  const { CATEGORIES, CATEGORY_MAPPINGS } = require("devtools/client/performance/modules/categories");
+  const { CATEGORIES } = require("devtools/client/performance/modules/categories");
   const { L10N } = require("devtools/client/performance/modules/global");
   const count = CATEGORIES.length;
 
   ok(count,
     "Should have a non-empty list of categories available.");
 
   ok(CATEGORIES.some(e => e.color),
     "All categories have an associated color.");
 
   ok(CATEGORIES.every(e => e.label),
     "All categories have an associated label.");
 
   ok(CATEGORIES.every(e => e.label === L10N.getStr("category." + e.abbrev)),
     "All categories have a correctly localized label.");
-
-  ok(Object.keys(CATEGORY_MAPPINGS).every(e => (Number(e) >= 9000 && Number(e) <= 9999) ||
-                                                Number.isInteger(Math.log2(e))),
-    "All bitmask mappings keys are powers of 2, or between 9000-9999 for special " +
-    "categories.");
-
-  ok(Object.keys(CATEGORY_MAPPINGS).every(e => CATEGORIES.includes(CATEGORY_MAPPINGS[e])),
-    "All bitmask mappings point to a category.");
 });
--- a/devtools/client/performance/test/unit/test_tree-model-07.js
+++ b/devtools/client/performance/test/unit/test_tree-model-07.js
@@ -1,17 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 "use strict";
 
 /**
  * Tests that when displaying only content nodes, platform nodes are generalized.
  */
 
-var { CATEGORY_MASK } = require("devtools/client/performance/modules/categories");
+var { CATEGORY_INDEX } = require("devtools/client/performance/modules/categories");
 
 add_task(function test() {
   const { ThreadNode } = require("devtools/client/performance/modules/logic/tree-model");
   const url = (n) => `http://content/${n}`;
 
   // Create a root node from a given samples array.
 
   const root = getFrameNodePath(new ThreadNode(gThread, { startTime: 5, endTime: 30,
@@ -30,32 +30,39 @@ add_task(function test() {
    *       - F
    *         - (JS)
    */
 
   // Test the root node.
 
   equal(root.calls.length, 2, "root has 2 children");
   ok(getFrameNodePath(root, url("A")), "root has content child");
-  ok(getFrameNodePath(root, "64"), "root has platform generalized child");
-  equal(getFrameNodePath(root, "64").calls.length, 0,
+  ok(getFrameNodePath(root, `${CATEGORY_INDEX("js")}`),
+     "root has platform generalized child");
+  equal(getFrameNodePath(root, `${CATEGORY_INDEX("js")}`).calls.length, 0,
         "platform generalized child is a leaf.");
 
-  ok(getFrameNodePath(root, `${url("A")} > 128`),
+  ok(getFrameNodePath(root, `${url("A")} > ${CATEGORY_INDEX("gc")}`),
      "A has platform generalized child of another type");
-  equal(getFrameNodePath(root, `${url("A")} > 128`).calls.length, 0,
+  equal(getFrameNodePath(root, `${url("A")} > ${CATEGORY_INDEX("gc")}`).calls.length, 0,
         "second generalized type is a leaf.");
 
-  ok(getFrameNodePath(root, `${url("A")} > ${url("E")} > ${url("F")} > 64`),
+  ok(getFrameNodePath(
+       root,
+       `${url("A")} > ${url("E")} > ${url("F")} > ${CATEGORY_INDEX("js")}`
+     ),
      "a second leaf of the first generalized type exists deep in the tree.");
-  ok(getFrameNodePath(root, `${url("A")} > 128`),
+  ok(getFrameNodePath(root, `${url("A")} > ${CATEGORY_INDEX("gc")}`),
      "A has platform generalized child of another type");
 
-  equal(getFrameNodePath(root, "64").category,
-     getFrameNodePath(root, `${url("A")} > ${url("E")} > ${url("F")} > 64`).category,
+  equal(getFrameNodePath(root, `${CATEGORY_INDEX("js")}`).category,
+     getFrameNodePath(
+       root,
+       `${url("A")} > ${url("E")} > ${url("F")} > ${CATEGORY_INDEX("js")}`
+     ).category,
      "generalized frames of same type are duplicated in top-down view");
 });
 
 var gThread = synthesizeProfileForTest([{
   time: 5,
   frames: [
     { location: "(root)" },
     { location: "http://content/A" },
@@ -63,35 +70,35 @@ var gThread = synthesizeProfileForTest([
     { location: "http://content/C" }
   ]
 }, {
   time: 5 + 6,
   frames: [
     { location: "(root)" },
     { location: "http://content/A" },
     { location: "http://content/B" },
-    { location: "contentY", category: CATEGORY_MASK("css") },
+    { location: "contentY", category: CATEGORY_INDEX("layout") },
     { location: "http://content/D" }
   ]
 }, {
   time: 5 + 6 + 7,
   frames: [
     { location: "(root)" },
     { location: "http://content/A" },
-    { location: "contentY", category: CATEGORY_MASK("css") },
+    { location: "contentY", category: CATEGORY_INDEX("layout") },
     { location: "http://content/E" },
     { location: "http://content/F" },
-    { location: "contentY", category: CATEGORY_MASK("js") },
+    { location: "contentY", category: CATEGORY_INDEX("js") },
   ]
 }, {
   time: 5 + 20,
   frames: [
     { location: "(root)" },
-    { location: "contentX", category: CATEGORY_MASK("js") },
+    { location: "contentX", category: CATEGORY_INDEX("js") },
   ]
 }, {
   time: 5 + 25,
   frames: [
     { location: "(root)" },
     { location: "http://content/A" },
-    { location: "contentZ", category: CATEGORY_MASK("gc", 1) },
+    { location: "contentZ", category: CATEGORY_INDEX("gc") },
   ]
 }]);
--- a/devtools/client/performance/test/unit/test_tree-model-08.js
+++ b/devtools/client/performance/test/unit/test_tree-model-08.js
@@ -4,17 +4,17 @@
 
 /**
  * Verifies if FrameNodes retain and parse their data appropriately.
  */
 
 add_task(function test() {
   const FrameUtils = require("devtools/client/performance/modules/logic/frame-utils");
   const { FrameNode } = require("devtools/client/performance/modules/logic/tree-model");
-  const { CATEGORY_MASK } = require("devtools/client/performance/modules/categories");
+  const { CATEGORY_INDEX } = require("devtools/client/performance/modules/categories");
   const compute = frame => {
     FrameUtils.computeIsContentAndCategory(frame);
     return frame;
   };
 
   const frames = [
     new FrameNode("hello/<.world (http://foo/bar.js:123:987)", compute({
       location: "hello/<.world (http://foo/bar.js:123:987)",
@@ -34,17 +34,17 @@ add_task(function test() {
     }), false),
     new FrameNode("hello/<.world (resource://foo.js -> http://bar/baz.js:123:987)", compute({
       location: "hello/<.world (resource://foo.js -> http://bar/baz.js:123:987)",
       line: 456,
     }), false),
     new FrameNode("Foo::Bar::Baz", compute({
       location: "Foo::Bar::Baz",
       line: 456,
-      category: CATEGORY_MASK("other"),
+      category: CATEGORY_INDEX("other"),
     }), false),
     new FrameNode("EnterJIT", compute({
       location: "EnterJIT",
     }), false),
     new FrameNode("chrome://browser/content/content.js", compute({
       location: "chrome://browser/content/content.js",
       line: 456,
       column: 123
--- a/devtools/client/performance/test/unit/test_tree-model-09.js
+++ b/devtools/client/performance/test/unit/test_tree-model-09.js
@@ -1,16 +1,18 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 "use strict";
 
 /**
  * Tests that when displaying only content nodes, platform nodes are generalized.
  */
 
+var { CATEGORY_INDEX } = require("devtools/client/performance/modules/categories");
+
 add_task(function test() {
   const { ThreadNode } = require("devtools/client/performance/modules/logic/tree-model");
   const url = (n) => `http://content/${n}`;
 
   // Create a root node from a given samples array.
 
   const root = getFrameNodePath(new ThreadNode(gThread, { startTime: 5, endTime: 25,
                                                           contentOnly: true }), "(root)");
@@ -27,26 +29,29 @@ add_task(function test() {
    *       - F
    *         - (Tools)
    */
 
   // Test the root node.
 
   equal(root.calls.length, 2, "root has 2 children");
   ok(getFrameNodePath(root, url("A")), "root has content child");
-  ok(getFrameNodePath(root, "9000"),
+  ok(getFrameNodePath(root, `${CATEGORY_INDEX("tools")}`),
     "root has platform generalized child from Chrome JS");
-  equal(getFrameNodePath(root, "9000").calls.length, 0,
+  equal(getFrameNodePath(root, `${CATEGORY_INDEX("tools")}`).calls.length, 0,
     "platform generalized child is a leaf.");
 
-  ok(getFrameNodePath(root, `${url("A")} > ${url("E")} > ${url("F")} > 9000`),
+  ok(getFrameNodePath(root,
+       `${url("A")} > ${url("E")} > ${url("F")} > ${CATEGORY_INDEX("tools")}`),
      "a second leaf of the generalized Chrome JS exists.");
 
-  equal(getFrameNodePath(root, "9000").category,
-     getFrameNodePath(root, `${url("A")} > ${url("E")} > ${url("F")} > 9000`).category,
+  equal(getFrameNodePath(root, `${CATEGORY_INDEX("tools")}`).category,
+     getFrameNodePath(root,
+       `${url("A")} > ${url("E")} > ${url("F")} > ${CATEGORY_INDEX("tools")}`
+     ).category,
      "generalized frames of same type are duplicated in top-down view");
 });
 
 var gThread = synthesizeProfileForTest([{
   time: 5,
   frames: [
     { location: "(root)" },
     { location: "http://content/A" },
--- a/devtools/client/scratchpad/test/browser_scratchpad_wrong_window_focus.js
+++ b/devtools/client/scratchpad/test/browser_scratchpad_wrong_window_focus.js
@@ -24,17 +24,17 @@ function test() {
       const sw = gScratchpadWindow;
       const {require} = ChromeUtils.import("resource://devtools/shared/Loader.jsm", {});
       const {TargetFactory} = require("devtools/client/framework/target");
 
       openScratchpad(function() {
         const target = TargetFactory.forTab(gBrowser.selectedTab);
         gDevTools.showToolbox(target, "webconsole").then((toolbox) => {
           const hud = toolbox.getCurrentPanel().hud;
-          hud.jsterm.clearOutput(true);
+          hud.ui.clearOutput(true);
           testFocus(sw, hud);
         });
       });
     });
   });
 
   gBrowser.loadURI("data:text/html;charset=utf8,<p>test window focus for Scratchpad.");
 }
--- a/devtools/client/shared/webpack/shims/jsterm-stub.js
+++ b/devtools/client/shared/webpack/shims/jsterm-stub.js
@@ -17,17 +17,16 @@ function JSTerm(webConsoleFrame) {
 JSTerm.prototype = {
   SELECTED_FRAME: -1,
 
   get webConsoleClient() {
     return this.hud.webConsoleClient;
   },
 
   openVariablesView() { },
-  clearOutput() { },
 
   init() {
     this.doc = this.hud.window.document;
     this.root = this.doc.createElement("div");
     this.root.className = "jsterm-input-container";
     this.inputNode = this.doc.createElement("input");
     this.inputNode.className = "jsterm-input-node jsterm-input-node-html";
     this.root.appendChild(this.inputNode);
--- a/devtools/client/shared/widgets/FlameGraph.js
+++ b/devtools/client/shared/widgets/FlameGraph.js
@@ -8,17 +8,19 @@ const { ELLIPSIS } = require("devtools/s
 
 loader.lazyRequireGetter(this, "defer", "devtools/shared/defer");
 loader.lazyRequireGetter(this, "EventEmitter",
   "devtools/shared/event-emitter");
 
 loader.lazyRequireGetter(this, "getColor",
   "devtools/client/shared/theme", true);
 
-loader.lazyRequireGetter(this, "CATEGORY_MAPPINGS",
+loader.lazyRequireGetter(this, "CATEGORIES",
+  "devtools/client/performance/modules/categories", true);
+loader.lazyRequireGetter(this, "CATEGORY_INDEX",
   "devtools/client/performance/modules/categories", true);
 loader.lazyRequireGetter(this, "FrameUtils",
   "devtools/client/performance/modules/logic/frame-utils");
 loader.lazyRequireGetter(this, "demangle",
   "devtools/client/shared/demangle");
 
 loader.lazyRequireGetter(this, "AbstractCanvasGraph",
   "devtools/client/shared/widgets/Graphs", true);
@@ -1287,17 +1289,18 @@ var FlameGraphUtils = {
         mutableFrameKeyOptions.isLeaf = stackDepth === 0;
         let frameKey = inflatedFrame.getFrameKey(mutableFrameKeyOptions);
 
         // If not skipping the frame, add it to the current level. The (root)
         // node isn't useful for flame graphs.
         if (frameKey !== "" && frameKey !== "(root)") {
           // If the frame is a meta category, use the category label.
           if (mutableFrameKeyOptions.isMetaCategoryOut) {
-            frameKey = CATEGORY_MAPPINGS[frameKey].label;
+            const category = CATEGORIES[frameKey] || CATEGORIES[CATEGORY_INDEX("other")];
+            frameKey = category.label;
           }
 
           sampleFrames[stackDepth] = inflatedFrame;
           sampleFrameKeys[stackDepth] = frameKey;
 
           // If we shouldn't flatten the current frame into the previous one,
           // increment the stack depth.
           if (!flattenRecursion || frameKey !== prevFrameKey) {
--- a/devtools/client/webconsole/components/JSTerm.js
+++ b/devtools/client/webconsole/components/JSTerm.js
@@ -283,17 +283,17 @@ class JSTerm extends Component {
     }
     const result = response.result;
     const helperResult = response.helperResult;
     const helperHasRawOutput = !!(helperResult || {}).rawOutput;
 
     if (helperResult && helperResult.type) {
       switch (helperResult.type) {
         case "clearOutput":
-          this.clearOutput();
+          this.hud.clearOutput();
           break;
         case "clearHistory":
           this.props.clearHistory();
           break;
         case "inspectObject":
           this.inspectObjectActor(helperResult.object);
           break;
         case "error":
@@ -480,50 +480,16 @@ class JSTerm extends Component {
     } else {
       grip = state.frames[frame];
     }
 
     return grip ? grip.actor : null;
   }
 
   /**
-   * Clear the Web Console output.
-   *
-   * This method emits the "messages-cleared" notification.
-   *
-   * @param boolean clearStorage
-   *        True if you want to clear the console messages storage associated to
-   *        this Web Console.
-   */
-  clearOutput(clearStorage) {
-    if (this.hud && this.hud.consoleOutput) {
-      this.hud.consoleOutput.dispatchMessagesClear();
-    }
-
-    this.webConsoleClient.clearNetworkRequests();
-    if (clearStorage) {
-      this.webConsoleClient.clearMessagesCache();
-    }
-    this.focus();
-    this.emit("messages-cleared");
-  }
-
-  /**
-   * Remove all of the private messages from the Web Console output.
-   *
-   * This method emits the "private-messages-cleared" notification.
-   */
-  clearPrivateMessages() {
-    if (this.hud && this.hud.consoleOutput) {
-      this.hud.consoleOutput.dispatchPrivateMessagesClear();
-      this.emit("private-messages-cleared");
-    }
-  }
-
-  /**
    * Updates the size of the input field (command line) to fit its contents.
    *
    * @returns void
    */
   resizeInput() {
     if (this.props.codeMirrorEnabled) {
       return;
     }
--- a/devtools/client/webconsole/console-commands.js
+++ b/devtools/client/webconsole/console-commands.js
@@ -68,18 +68,18 @@ exports.items = [
         return null;
       }
 
       const panel = toolbox.getPanel("webconsole");
       if (panel == null) {
         return null;
       }
 
-      const onceMessagesCleared = panel.hud.jsterm.once("messages-cleared");
-      panel.hud.jsterm.clearOutput();
+      const onceMessagesCleared = panel.hud.once("messages-cleared");
+      panel.hud.ui.clearOutput();
       return onceMessagesCleared;
     }
   },
   {
     item: "command",
     runAt: "client",
     name: "console close",
     description: l10n.lookup("consolecloseDesc"),
--- a/devtools/client/webconsole/test/mochitest/browser_console.js
+++ b/devtools/client/webconsole/test/mochitest/browser_console.js
@@ -39,17 +39,17 @@ add_task(async function() {
   });
 
   await testMessages(hud);
   await testCPOWInspection(hud);
   await resetFilters(hud);
 });
 
 async function testMessages(hud) {
-  hud.jsterm.clearOutput(true);
+  hud.ui.clearOutput(true);
 
   expectUncaughtException();
 
   executeSoon(() => {
     // eslint-disable-next-line no-undef
     foobarException();
   });
 
--- a/devtools/client/webconsole/test/mochitest/browser_console_consolejsm_output.js
+++ b/devtools/client/webconsole/test/mochitest/browser_console_consolejsm_output.js
@@ -14,17 +14,17 @@ add_task(async function testCategoryLogs
 
   const {console} = ChromeUtils.import("resource://gre/modules/Console.jsm", {});
   console.log("bug861338-log-cached");
 
   const hud = await HUDService.toggleBrowserConsole();
 
   await checkMessageExists(hud, "bug861338-log-cached");
 
-  hud.jsterm.clearOutput(true);
+  hud.ui.clearOutput(true);
 
   function testTrace() {
     console.trace();
   }
 
   console.time("foobarTimer");
   const foobar = { bug851231prop: "bug851231value" };
 
@@ -43,17 +43,17 @@ add_task(async function testCategoryLogs
   await checkMessageExists(hud, "bug851231-info");
   await checkMessageExists(hud, "bug851231-warn");
   await checkMessageExists(hud, "bug851231-error");
   await checkMessageExists(hud, "bug851231-debug");
   await checkMessageExists(hud, "XULDocument");
   await checkMessageExists(hud, "console.trace()");
   await checkMessageExists(hud, "foobarTimer");
 
-  hud.jsterm.clearOutput(true);
+  hud.ui.clearOutput(true);
   await HUDService.toggleBrowserConsole();
 });
 
 add_task(async function testFilter() {
   const consoleStorage = Cc["@mozilla.org/consoleAPI-storage;1"];
   const storage = consoleStorage.getService(Ci.nsIConsoleAPIStorage);
   storage.clearEvents();
 
@@ -74,17 +74,17 @@ add_task(async function testFilter() {
   console2.error(shouldBeVisible);
 
   await checkMessageExists(hud, shouldBeVisible);
   // Here we can safely assert that the log message is not visible, since the
   // error message was logged after and is visible.
   await checkMessageHidden(hud, shouldBeHidden);
 
   await resetFilters(hud);
-  hud.jsterm.clearOutput(true);
+  hud.ui.clearOutput(true);
   await HUDService.toggleBrowserConsole();
 });
 
 // Test that console.profile / profileEnd trigger the right events
 add_task(async function testProfile() {
   const consoleStorage = Cc["@mozilla.org/consoleAPI-storage;1"];
   const storage = consoleStorage.getService(Ci.nsIConsoleAPIStorage);
   const { console } = ChromeUtils.import("resource://gre/modules/Console.jsm", {});
--- a/devtools/client/webconsole/test/mochitest/browser_console_webconsole_private_browsing.js
+++ b/devtools/client/webconsole/test/mochitest/browser_console_webconsole_private_browsing.js
@@ -80,17 +80,17 @@ add_task(async function() {
     waitForMessage(hud, PRIVATE_EXCEPTION, ".error");
   logPrivateMessages(privateBrowser.selectedBrowser);
 
   await onBrowserConsolePrivateLogMessage;
   await onBrowserConsolePrivateErrorMessage;
   ok(true, "Messages are displayed as expected");
 
   info("close the private window and check if private messages are removed");
-  const onPrivateMessagesCleared = hud.jsterm.once("private-messages-cleared");
+  const onPrivateMessagesCleared = hud.ui.once("private-messages-cleared");
   privateWindow.BrowserTryToCloseWindow();
   await onPrivateMessagesCleared;
 
   ok(findMessage(hud, NON_PRIVATE_MESSAGE),
     "non-private messages are still shown after private window closed");
   assertNoPrivateMessages(hud);
 
   info("close the browser console");
--- a/devtools/client/webconsole/test/mochitest/browser_jsterm_completion.js
+++ b/devtools/client/webconsole/test/mochitest/browser_jsterm_completion.js
@@ -5,17 +5,17 @@
 
 // Tests that code completion works properly.
 
 "use strict";
 
 const TEST_URI = "data:text/html;charset=utf8,<p>test code completion";
 
 add_task(async function() {
-  const {jsterm} = await openNewTabAndConsole(TEST_URI);
+  const {jsterm, ui} = await openNewTabAndConsole(TEST_URI);
   const input = jsterm.inputNode;
 
   // Test typing 'docu'.
   await jstermSetValueAndComplete(jsterm, "docu");
   is(input.value, "docu", "'docu' completion (input.value)");
   is(jsterm.completeNode.value, "    ment", "'docu' completion (completeNode)");
 
   // Test typing 'docu' and press tab.
@@ -45,17 +45,17 @@ add_task(async function() {
      "'document.getElem' another tab completion");
 
   // Test pressing shift_tab.
   await jstermComplete(jsterm, jsterm.COMPLETE_BACKWARD);
   is(input.value, "document.getElem", "'document.getElem' untab completion");
   is(jsterm.completeNode.value, "                entsByTagNameNS",
      "'document.getElem' completion");
 
-  jsterm.clearOutput();
+  ui.clearOutput();
 
   await jstermSetValueAndComplete(jsterm, "docu");
   is(jsterm.completeNode.value, "    ment", "'docu' completion");
 
   await jsterm.execute();
   is(jsterm.completeNode.value, "", "clear completion on execute()");
 
   // Test multi-line completion works
--- a/devtools/client/webconsole/test/mochitest/browser_jsterm_dollar.js
+++ b/devtools/client/webconsole/test/mochitest/browser_jsterm_dollar.js
@@ -13,19 +13,19 @@ const TEST_URI = "http://example.com/bro
 
 add_task(async function() {
   const hud = await openNewTabAndConsole(TEST_URI);
   await test$(hud);
   await test$$(hud);
 });
 
 async function test$(hud) {
-  hud.jsterm.clearOutput();
+  hud.ui.clearOutput();
   const msg = await hud.jsterm.execute("$(document.body)");
   ok(msg.textContent.includes("<p>"), "jsterm output is correct for $()");
 }
 
 async function test$$(hud) {
-  hud.jsterm.clearOutput();
+  hud.ui.clearOutput();
   hud.jsterm.setInputValue();
   const msg = await hud.jsterm.execute("$$(document)");
   ok(msg.textContent.includes("621644"), "jsterm output is correct for $$()");
 }
--- a/devtools/client/webconsole/test/mochitest/browser_jsterm_error_docs.js
+++ b/devtools/client/webconsole/test/mochitest/browser_jsterm_error_docs.js
@@ -17,17 +17,17 @@ add_task(async function() {
     "JSMSG_BAD_ARRAY_LENGTH": "([]).length = -1",
     "JSMSG_NEGATIVE_REPETITION_COUNT": "'abc'.repeat(-1);",
     "JSMSG_PRECISION_RANGE": "77.1234.toExponential(-1);",
   };
 
   for (const [errorMessageName, expression] of Object.entries(ErrorDocStatements)) {
     const title = ErrorDocs.GetURL({ errorMessageName }).split("?")[0];
 
-    jsterm.clearOutput();
+    hud.ui.clearOutput();
     const onMessage = waitForMessage(hud, "RangeError:");
     jsterm.execute(expression);
     const {node} = await onMessage;
     const learnMoreLink = node.querySelector(".learn-more-link");
     ok(learnMoreLink, `There is a [Learn More] link for "${errorMessageName}" error`);
     is(learnMoreLink.title, title, `The link has the expected "${title}" title`);
   }
 });
--- a/devtools/client/webconsole/test/mochitest/browser_jsterm_helper_help.js
+++ b/devtools/client/webconsole/test/mochitest/browser_jsterm_helper_help.js
@@ -13,17 +13,17 @@ add_task(async function() {
   let openedLinks = 0;
   const oldOpenLink = hud.openLink;
   hud.openLink = (url) => {
     if (url == HELP_URL) {
       openedLinks++;
     }
   };
 
-  jsterm.clearOutput();
+  hud.ui.clearOutput();
   await jsterm.execute("help()");
   await jsterm.execute("help");
   await jsterm.execute("?");
 
   const messages = Array.from(jsterm.outputNode.querySelectorAll(".message"));
   ok(messages.every(msg => msg.classList.contains("command")),
     "There is no results shown for the help commands");
   is(openedLinks, 3, "correct number of pages opened by the help calls");
--- a/devtools/client/webconsole/test/mochitest/browser_jsterm_hide_when_devtools_chrome_enabled_false.js
+++ b/devtools/client/webconsole/test/mochitest/browser_jsterm_hide_when_devtools_chrome_enabled_false.js
@@ -60,17 +60,17 @@ add_task(async function() {
  * currently in use.
  */
 async function getObjectInspector(hud) {
   const { ui, jsterm } = hud;
 
   // Filter out other messages to ensure ours stays visible.
   ui.filterBox.value = "browser_console_hide_jsterm_test";
 
-  jsterm.clearOutput();
+  hud.ui.clearOutput();
   jsterm.execute("new Object({ browser_console_hide_jsterm_test: true })");
 
   const message = await waitFor(
     () => findMessage(hud, "Object { browser_console_hide_jsterm_test: true }")
   );
 
   const objInspector = message.querySelector(".tree");
   return objInspector;
--- a/devtools/client/webconsole/test/mochitest/browser_jsterm_history.js
+++ b/devtools/client/webconsole/test/mochitest/browser_jsterm_history.js
@@ -11,19 +11,19 @@ const TEST_URI = "data:text/html;charset
 const COMMANDS = ["document", "window", "window.location"];
 
 const {
   HISTORY_BACK,
   HISTORY_FORWARD,
 } = require("devtools/client/webconsole/constants");
 
 add_task(async function() {
-  const { jsterm } = await openNewTabAndConsole(TEST_URI);
+  const { jsterm, ui } = await openNewTabAndConsole(TEST_URI);
   const { inputNode } = jsterm;
-  jsterm.clearOutput();
+  ui.clearOutput();
 
   for (const command of COMMANDS) {
     info(`Executing command ${command}`);
     jsterm.setInputValue(command);
     await jsterm.execute();
   }
 
   for (let x = COMMANDS.length - 1; x != -1; x--) {
--- a/devtools/client/webconsole/test/mochitest/browser_jsterm_selfxss.js
+++ b/devtools/client/webconsole/test/mochitest/browser_jsterm_selfxss.js
@@ -14,18 +14,18 @@ XPCOMUtils.defineLazyServiceGetter(
   "nsIClipboardHelper"
 );
 const WebConsoleUtils = require("devtools/client/webconsole/utils").Utils;
 const stringToCopy = "foobazbarBug642615";
 
 add_task(async function() {
   await pushPref("devtools.selfxss.count", 0);
 
-  const {jsterm} = await openNewTabAndConsole(TEST_URI);
-  jsterm.clearOutput();
+  const {jsterm, ui} = await openNewTabAndConsole(TEST_URI);
+  ui.clearOutput();
   ok(!jsterm.completeNode.value, "no completeNode.value");
 
   jsterm.setInputValue("doc");
 
   info("wait for completion value after typing 'docu'");
   let onAutocompleteUpdated = jsterm.once("autocomplete-updated");
   EventUtils.sendString("u");
   await onAutocompleteUpdated;
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_cd_iframe.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_cd_iframe.js
@@ -62,10 +62,10 @@ async function executeWindowTest(hud, if
   hud.jsterm.execute(`document.title`);
   hud.jsterm.execute(`"p: " + document.querySelector("p").textContent`);
   hud.jsterm.execute(`"obj: " + window.foobar`);
 
   const messages = await onMessages;
   ok(messages, `Expected evaluation result messages are shown in ${iframeRole} iframe`);
 
   // Clear the output so we don't pollute the next assertions.
-  hud.jsterm.clearOutput();
+  hud.ui.clearOutput();
 }
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_console_logging_workers_api.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_console_logging_workers_api.js
@@ -15,12 +15,12 @@ add_task(async function() {
   const hud = await openNewTabAndConsole(TEST_URI);
   const message = await waitFor(() => findMessage(hud, "foo-bar-shared-worker"));
   is(
     message.querySelector(".message-body").textContent,
     `foo-bar-shared-worker Object { foo: "bar" }`,
     "log from SharedWorker is displayed as expected"
   );
 
-  const onMessagesCleared = hud.jsterm.once("messages-cleared");
-  hud.jsterm.clearOutput(true);
+  const onMessagesCleared = hud.ui.once("messages-cleared");
+  hud.ui.clearOutput(true);
   await onMessagesCleared;
 });
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_context_menu_copy_entire_message.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_context_menu_copy_entire_message.js
@@ -30,17 +30,17 @@ const TEST_URI = `data:text/html;charset
 
 add_task(async function() {
   const observer = new PrefObserver("");
   let onPrefUpdated = observer.once(PREF_MESSAGE_TIMESTAMP, () => {});
   Services.prefs.setBoolPref(PREF_MESSAGE_TIMESTAMP, true);
   await onPrefUpdated;
 
   const hud = await openNewTabAndConsole(TEST_URI);
-  hud.jsterm.clearOutput();
+  hud.ui.clearOutput();
 
   info("Call the log function defined in the test page");
   await ContentTask.spawn(gBrowser.selectedBrowser, null, () => {
     content.wrappedJSObject.logStuff();
   });
 
   info("Test copy menu item for the simple log");
   let message = await waitFor(() => findMessage(hud, "simple text message"));
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_context_menu_copy_link_location.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_context_menu_copy_link_location.js
@@ -13,17 +13,17 @@ const TEST_URI = "http://example.com/bro
                  Date.now();
 const CONTEXT_MENU_ID = "#console-menu-copy-url";
 
 add_task(async function() {
   // Enable net messages in the console for this test.
   await pushPref("devtools.webconsole.filter.net", true);
 
   const hud = await openNewTabAndConsole(TEST_URI);
-  hud.jsterm.clearOutput();
+  hud.ui.clearOutput();
 
   info("Test Copy URL menu item for text log");
 
   info("Logging a text message in the content window");
   const onLogMessage = waitForMessage(hud, "simple text message");
   await ContentTask.spawn(gBrowser.selectedBrowser, null, () => {
     content.wrappedJSObject.console.log("simple text message");
   });
@@ -31,17 +31,17 @@ add_task(async function() {
   ok(message, "Text log found in the console");
 
   info("Open and check the context menu for the logged text message");
   let menuPopup = await openContextMenu(hud, message.node);
   let copyURLItem = menuPopup.querySelector(CONTEXT_MENU_ID);
   ok(!copyURLItem, "Copy URL menu item is hidden for a simple text message");
 
   await hideContextMenu(hud);
-  hud.jsterm.clearOutput();
+  hud.ui.clearOutput();
 
   info("Test Copy URL menu item for network log");
 
   info("Reload the content window to produce a network log");
   const onNetworkMessage = waitForMessage(hud, "test-console.html");
   await ContentTask.spawn(gBrowser.selectedBrowser, null, () => {
     content.wrappedJSObject.location.reload();
   });
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_context_menu_open_url.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_context_menu_open_url.js
@@ -11,34 +11,34 @@
 const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
                  "test/mochitest/test-console.html";
 
 add_task(async function() {
   // Enable net messages in the console for this test.
   await pushPref("devtools.webconsole.filter.net", true);
 
   const hud = await openNewTabAndConsole(TEST_URI);
-  hud.jsterm.clearOutput();
+  hud.ui.clearOutput();
 
   info("Test Open URL menu item for text log");
 
   info("Logging a text message in the content window");
   await ContentTask.spawn(gBrowser.selectedBrowser, null, () => {
     content.wrappedJSObject.console.log("simple text message");
   });
   let message = await waitFor(() => findMessage(hud, "simple text message"));
   ok(message, "Text log found in the console");
 
   info("Open and check the context menu for the logged text message");
   let menuPopup = await openContextMenu(hud, message);
   let openUrlItem = menuPopup.querySelector("#console-menu-open-url");
   ok(!openUrlItem, "Open URL menu item is not available");
 
   await hideContextMenu(hud);
-  hud.jsterm.clearOutput();
+  hud.ui.clearOutput();
 
   info("Test Open URL menu item for network log");
 
   info("Reload the content window to produce a network log");
   await ContentTask.spawn(gBrowser.selectedBrowser, null, () => {
     content.wrappedJSObject.location.reload();
   });
   message = await waitFor(() => findMessage(hud, "test-console.html"));
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_csp_violation.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_csp_violation.js
@@ -12,16 +12,16 @@ const TEST_URI = "data:text/html;charset
 const TEST_VIOLATION = "https://example.com/browser/devtools/client/webconsole/" +
                        "test/mochitest/test-csp-violation.html";
 const CSP_VIOLATION_MSG = "Content Security Policy: The page\u2019s settings " +
                           "blocked the loading of a resource at " +
                           "http://some.example.com/test.png (\u201cimg-src\u201d).";
 
 add_task(async function() {
   const hud = await openNewTabAndConsole(TEST_URI);
-  hud.jsterm.clearOutput();
+  hud.ui.clearOutput();
 
   const onRepeatedMessage = waitForRepeatedMessage(hud, CSP_VIOLATION_MSG, 2);
   await loadDocument(TEST_VIOLATION);
   await onRepeatedMessage;
 
   ok(true, "Received expected messages");
 });
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_cspro.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_cspro.js
@@ -35,10 +35,10 @@ add_task(async function() {
 
   info("Load a page with CSP warnings.");
   loadDocument(TEST_VIOLATION);
 
   await onCspViolationMessage;
   await onCspReportMessage;
   ok(true, "Confirmed that CSP and CSP-Report-Only log different messages to console");
 
-  hud.jsterm.clearOutput(true);
+  hud.ui.clearOutput(true);
 });
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_execution_scope.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_execution_scope.js
@@ -8,17 +8,17 @@
 "use strict";
 
 const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
                  "test/mochitest/test-console.html";
 
 add_task(async function() {
   const hud = await openNewTabAndConsole(TEST_URI);
   const {jsterm} = hud;
-  jsterm.clearOutput();
+  hud.ui.clearOutput();
 
   const onInputMessage = waitForMessage(hud, "window.location.href;", ".message.command");
   const onEvaluationResultMessage = waitForMessage(hud, TEST_URI, ".message.result");
   jsterm.execute("window.location.href;");
 
   let message = await onInputMessage;
   ok(message, "Input message is displayed with the expected class");
 
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_file_uri.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_file_uri.js
@@ -28,17 +28,17 @@ add_task(async function() {
 
   // Open tab with correct remote type so we don't switch processes when we load
   // the file:// URI, otherwise we won't get the same web console.
   const remoteType = E10SUtils.getRemoteTypeForURI(uri.spec,
                                                  gMultiProcessBrowser);
   const { browser } = await loadTab("about:blank", remoteType);
 
   hud = await openConsole();
-  hud.jsterm.clearOutput();
+  hud.ui.clearOutput();
 
   const loaded = loadBrowser(browser);
   BrowserTestUtils.loadURI(gBrowser.selectedBrowser, uri.spec);
   await loaded;
 
   await testMessages();
 
   Services.prefs.clearUserPref(PREF);
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_highlighter_console_helper.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_highlighter_console_helper.js
@@ -43,24 +43,24 @@ add_task(async function() {
 
   await onPickerStopped;
   await onInspectorUpdated;
 
   info("Picker mode stopped, <h1> selected, now switching to the console");
   const hud = await openConsole();
   const {jsterm} = hud;
 
-  jsterm.clearOutput();
+  hud.ui.clearOutput();
 
   const onEvaluationResult = waitForMessage(hud, "<h1>");
   jsterm.execute("$0");
   await onEvaluationResult;
   ok(true, "correct output for $0");
 
-  jsterm.clearOutput();
+  hud.ui.clearOutput();
 
   const newH1Content = "newH1Content";
   const onAssignmentResult = waitForMessage(hud, "<h1>");
   jsterm.execute(`$0.textContent = "${newH1Content}";$0`);
   await onAssignmentResult;
 
   ok(true, "correct output for $0 after setting $0.textContent");
   const {textContent} = await testActor.getNodeInfo("h1");
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_hpkp_invalid-headers.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_hpkp_invalid-headers.js
@@ -87,17 +87,17 @@ add_task(async function() {
     name: "Non-built-in root error displayed successfully",
     text: "Public-Key-Pins: The certificate used by the site was not issued " +
           "by a certificate in the default root certificate store. To " +
           "prevent accidental breakage, the specified header was ignored."
   }, hud);
 });
 
 async function navigateAndCheckForWarningMessage({name, text, url}, hud) {
-  hud.jsterm.clearOutput(true);
+  hud.ui.clearOutput(true);
 
   const onMessage = waitForMessage(hud, text, ".message.warning");
   BrowserTestUtils.loadURI(gBrowser.selectedBrowser, url);
   const {node} = await onMessage;
   ok(node, name);
 
   const learnMoreNode = node.querySelector(".learn-more-link");
   ok(learnMoreNode, `There is a "Learn more" link`);
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_hsts_invalid-headers.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_hsts_invalid-headers.js
@@ -53,17 +53,17 @@ add_task(async function() {
     url: SJS_URL + "?multipleMaxAge",
     name: "Multiple max-age error displayed successfully",
     text: "Strict-Transport-Security: The site specified a header that " +
           "included multiple \u2018max-age\u2019 directives."
   }, hud);
 });
 
 async function navigateAndCheckWarningMessage({url, name, text}, hud) {
-  hud.jsterm.clearOutput(true);
+  hud.ui.clearOutput(true);
 
   const onMessage = waitForMessage(hud, text, ".message.warning");
   BrowserTestUtils.loadURI(gBrowser.selectedBrowser, url);
   const {node} = await onMessage;
   ok(node, name);
 
   const learnMoreNode = node.querySelector(".learn-more-link");
   ok(learnMoreNode, `There is a "Learn more" link`);
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_input_focus.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_input_focus.js
@@ -15,17 +15,17 @@ const TEST_URI =
 
 add_task(async function() {
   const hud = await openNewTabAndConsole(TEST_URI);
 
   const inputNode = hud.jsterm.inputNode;
   info("Focus after console is opened");
   ok(hasFocus(inputNode), "input node is focused after console is opened");
 
-  hud.jsterm.clearOutput();
+  hud.ui.clearOutput();
   ok(hasFocus(inputNode), "input node is focused after output is cleared");
 
   info("Focus during message logging");
   ContentTask.spawn(gBrowser.selectedBrowser, {}, function() {
     content.wrappedJSObject.console.log("console message 2");
   });
   const msg = await waitFor(() => findMessage(hud, "console message 2"));
   ok(hasFocus(inputNode, "input node is focused, first time"));
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_js_input_expansion.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_js_input_expansion.js
@@ -6,18 +6,18 @@
 // Tests that the input box expands as the user types long lines.
 
 "use strict";
 
 const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
                  "test/mochitest/test-console.html";
 
 add_task(async function() {
-  const { jsterm } = await openNewTabAndConsole(TEST_URI);
-  jsterm.clearOutput();
+  const { jsterm, ui } = await openNewTabAndConsole(TEST_URI);
+  ui.clearOutput();
 
   const { inputNode } = jsterm;
   const getInputHeight = () => inputNode.clientHeight;
 
   info("Get the initial (empty) height of the input");
   const emptyHeight = getInputHeight();
 
   info("Set some multiline text in the input");
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_loglimit.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_loglimit.js
@@ -8,17 +8,17 @@
 // Test that messages are properly updated when the log limit is reached.
 
 const TEST_URI = "data:text/html;charset=utf-8,Web Console test for " +
                  "Old messages are removed after passing devtools.hud.loglimit";
 
 add_task(async function() {
   await pushPref("devtools.hud.loglimit", 140);
   const hud = await openNewTabAndConsole(TEST_URI);
-  hud.jsterm.clearOutput();
+  hud.ui.clearOutput();
 
   let onMessage = waitForMessage(hud, "test message [149]");
   ContentTask.spawn(gBrowser.selectedBrowser, {}, async function() {
     for (let i = 0; i < 150; i++) {
       content.console.log(`test message [${i}]`);
     }
   });
   await onMessage;
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_network_messages_expand.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_network_messages_expand.js
@@ -99,17 +99,17 @@ async function openRequestAfterUpdates(t
 
   await payload;
   await testNetworkMessage(toolbox, messageNode);
 }
 
 async function openRequestBeforeUpdates(target, hud, tab) {
   const toolbox = gDevTools.getToolbox(target);
 
-  hud.jsterm.clearOutput(true);
+  hud.ui.clearOutput(true);
 
   const xhrUrl = TEST_PATH + "sjs_slow-response-test-server.sjs";
   const message = waitForMessage(hud, xhrUrl);
 
   // Fire an XHR POST request.
   ContentTask.spawn(gBrowser.selectedBrowser, null, function() {
     content.wrappedJSObject.testXhrPostSlowResponse();
   });
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_output_order.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_output_order.js
@@ -8,17 +8,17 @@
 
 "use strict";
 
 const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
                  "test/mochitest/test-console.html";
 
 add_task(async function() {
   const hud = await openNewTabAndConsole(TEST_URI);
-  hud.jsterm.clearOutput();
+  hud.ui.clearOutput();
 
   const messages = ["console.log('foo', 'bar');", "foo bar", "undefined"];
   const onMessages = waitForMessages({
     hud,
     messages: messages.map(text => ({text}))
   });
 
   hud.jsterm.execute("console.log('foo', 'bar');");
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_reopen_closed_tab.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_reopen_closed_tab.js
@@ -15,17 +15,17 @@ add_task(async function() {
   // If we persist log, the test might be successful even if only the first
   // error log is shown.
   pushPref("devtools.webconsole.persistlog", false);
 
   info("Open console and refresh tab.");
 
   expectUncaughtExceptionNoE10s();
   let hud = await openNewTabAndConsole(TEST_URI);
-  hud.jsterm.clearOutput();
+  hud.ui.clearOutput();
 
   expectUncaughtExceptionNoE10s();
   await refreshTab();
   await waitForError(hud);
 
   // Close and reopen
   await closeConsole();
 
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_sandbox_update_after_navigation.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_sandbox_update_after_navigation.js
@@ -41,28 +41,28 @@ add_task(async function() {
   onMessages = waitForMessages({
     hud,
     messages: [
       { text: "window.location.href" },
       { text: TEST_URI2 },
     ],
   });
 
-  hud.jsterm.clearOutput();
+  hud.ui.clearOutput();
   hud.jsterm.execute("window.location.href");
 
   info("wait for window.location.href after page navigation");
   await onMessages;
 
   ok(!findMessage(hud, "Permission denied"), "no permission denied errors");
 
   // Navigation clears messages. Wait for that clear to happen before
   // continuing the test or it might destroy messages we wait later on (Bug
   // 1270234).
-  const cleared = hud.jsterm.once("messages-cleared");
+  const cleared = hud.ui.once("messages-cleared");
 
   gBrowser.goBack();
 
   info("Waiting for messages-cleared event due to navigation");
   await cleared;
 
   info("Messages cleared after navigation; checking location");
 
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_script_errordoc_urls.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_script_errordoc_urls.js
@@ -61,10 +61,10 @@ async function testScriptError(hud, test
   // but have the URL in the title attribute.
   const hrefs = new Set();
   for (const link of hud.ui.outputNode.querySelectorAll("a")) {
     hrefs.add(link.title);
   }
 
   ok(hrefs.has(url), `Expected a link to ${url}.`);
 
-  hud.jsterm.clearOutput();
+  hud.ui.clearOutput();
 }
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_select_all.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_select_all.js
@@ -18,17 +18,17 @@ add_task(async function testSelectAll() 
   testBrowserMenuSelectAll(hud);
   await testContextMenuSelectAll(hud);
 });
 
 async function testSelectionWhenMovingBetweenBoxes(hud) {
   const jsterm = hud.jsterm;
 
   // Fill the console with some output.
-  jsterm.clearOutput();
+  hud.ui.clearOutput();
   await jsterm.execute("1 + 2");
   await waitFor(() => findMessage(hud, "3"));
   await jsterm.execute("3 + 4");
   await waitFor(() => findMessage(hud, "7"));
   await jsterm.execute("5 + 6");
   await waitFor(() => findMessage(hud, "11"));
 }
 
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_show_subresource_security_errors.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_show_subresource_security_errors.js
@@ -10,15 +10,15 @@
 const TEST_URI = "data:text/html;charset=utf-8,Web Console subresource STS " +
                  "warning test";
 const TEST_DOC = "https://example.com/browser/devtools/client/webconsole/" +
                  "test/mochitest/test-subresource-security-error.html";
 const SAMPLE_MSG = "specified a header that could not be parsed successfully.";
 
 add_task(async function() {
   const hud = await openNewTabAndConsole(TEST_URI);
-  hud.jsterm.clearOutput();
+  hud.ui.clearOutput();
   await loadDocument(TEST_DOC);
 
   await waitFor(() => findMessage(hud, SAMPLE_MSG, ".message.warn"));
 
   ok(true, "non-toplevel security warning message was displayed");
 });
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_time_methods.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_time_methods.js
@@ -50,17 +50,17 @@ add_task(async function() {
   // We use this await to 'sync' until the message appears, as the console API
   // guarantees us that the smoke signal will be printed after the message for
   // console.time("bTimer") (if there were any)
   await waitFor(() => findMessage(hud2, "smoke signal"));
 
   is(findMessage(hud2, "bTimer started"), null, "No message is printed to "
     + "the console when the timer starts");
 
-  hud2.jsterm.clearOutput();
+  hud2.ui.clearOutput();
 
   // Calling console.time('bTimer') on a page, then navigating to another page
   // and calling console.timeEnd('bTimer') on the new console front-end should
   // result on a warning message: 'Timer "bTimer" does not exist',
   // as the timers in different pages are not related
   await BrowserTestUtils.loadURI(gBrowser.selectedBrowser, TEST_URI4);
 
   const error2 =
--- a/devtools/client/webconsole/test/mochitest/head.js
+++ b/devtools/client/webconsole/test/mochitest/head.js
@@ -41,17 +41,17 @@ registerCleanupFunction(async function()
   // filter prefs has been pushed for the test
   await SpecialPowers.flushPrefEnv();
   Services.prefs.getChildList("devtools.webconsole.filter").forEach(pref => {
     Services.prefs.clearUserPref(pref);
   });
   const browserConsole = HUDService.getBrowserConsole();
   if (browserConsole) {
     if (browserConsole.jsterm) {
-      browserConsole.jsterm.clearOutput(true);
+      browserConsole.jsterm.hud.clearOutput(true);
     }
     await HUDService.toggleBrowserConsole();
   }
 });
 
 /**
  * Add a new tab and open the toolbox in it, and select the webconsole.
  *
--- a/devtools/client/webconsole/webconsole-connection-proxy.js
+++ b/devtools/client/webconsole/webconsole-connection-proxy.js
@@ -382,17 +382,17 @@ WebConsoleConnectionProxy.prototype = {
    * @private
    * @param string type
    *        Message type.
    * @param object packet
    *        The message received from the server.
    */
   _onLastPrivateContextExited: function(type, packet) {
     if (this.webConsoleFrame && packet.from == this._consoleActor) {
-      this.webConsoleFrame.jsterm.clearPrivateMessages();
+      this.webConsoleFrame.clearPrivateMessages();
     }
   },
 
   /**
    * The "navigate" event handlers. We redirect any message to the UI for displaying.
    *
    * @private
    * @param object packet
--- a/devtools/client/webconsole/webconsole-frame.js
+++ b/devtools/client/webconsole/webconsole-frame.js
@@ -118,16 +118,49 @@ WebConsoleFrame.prototype = {
       this.proxy = null;
     } else {
       onDestroy();
     }
 
     return this._destroyer.promise;
   },
 
+  /**
+   * Clear the Web Console output.
+   *
+   * This method emits the "messages-cleared" notification.
+   *
+   * @param boolean clearStorage
+   *        True if you want to clear the console messages storage associated to
+   *        this Web Console.
+   */
+  clearOutput(clearStorage) {
+    if (this.consoleOutput) {
+      this.consoleOutput.dispatchMessagesClear();
+    }
+    this.webConsoleClient.clearNetworkRequests();
+    if (clearStorage) {
+      this.webConsoleClient.clearMessagesCache();
+    }
+    this.jsterm.focus();
+    this.emit("messages-cleared");
+  },
+
+  /**
+   * Remove all of the private messages from the Web Console output.
+   *
+   * This method emits the "private-messages-cleared" notification.
+   */
+  clearPrivateMessages() {
+    if (this.consoleOutput) {
+      this.consoleOutput.dispatchPrivateMessagesClear();
+      this.emit("private-messages-cleared");
+    }
+  },
+
   _onUpdateListeners() {
 
   },
 
   logWarningAboutReplacedAPI() {
     this.owner.target.logWarningInPage(l10n.getStr("ConsoleAPIDisabled"),
       "ConsoleAPIDisabled");
   },
@@ -233,17 +266,17 @@ WebConsoleFrame.prototype = {
 
     let clearShortcut;
     if (AppConstants.platform === "macosx") {
       clearShortcut = l10n.getStr("webconsole.clear.keyOSX");
     } else {
       clearShortcut = l10n.getStr("webconsole.clear.key");
     }
 
-    shortcuts.on(clearShortcut, () => this.jsterm.clearOutput(true));
+    shortcuts.on(clearShortcut, () => this.clearOutput(true));
 
     if (this.isBrowserConsole) {
       // Make sure keyboard shortcuts work immediately after opening
       // the Browser Console (Bug 1461366).
       this.window.focus();
 
       shortcuts.on(l10n.getStr("webconsole.close.key"),
                    this.window.top.close.bind(this.window.top));
@@ -333,17 +366,17 @@ WebConsoleFrame.prototype = {
   },
 
   handleTabWillNavigate: function(packet) {
     if (this.persistLog) {
       // Add a _type to hit convertCachedPacket.
       packet._type = true;
       this.consoleOutput.dispatchMessageAdd(packet);
     } else {
-      this.jsterm.clearOutput(false);
+      this.clearOutput(false);
     }
 
     if (packet.url) {
       this.onLocationChange(packet.url, packet.title);
     }
   }
 };
 
--- a/devtools/shared/heapsnapshot/DeserializedNode.cpp
+++ b/devtools/shared/heapsnapshot/DeserializedNode.cpp
@@ -82,18 +82,18 @@ class DeserializedEdgeRange : public Edg
   void settle() {
     if (i >= node->edges.length()) {
       front_ = nullptr;
       return;
     }
 
     auto& edge = node->edges[i];
     auto referent = node->getEdgeReferent(edge);
-    currentEdge = std::move(Edge(edge.name ? NS_strdup(edge.name) : nullptr,
-                                     referent));
+    currentEdge = Edge(edge.name
+                ? NS_strdup(edge.name) : nullptr, referent);
     front_ = &currentEdge;
   }
 
 public:
   explicit DeserializedEdgeRange(DeserializedNode& node)
     : node(&node)
     , i(0)
   {
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -2860,17 +2860,17 @@ nsDocShell::MaybeCreateInitialClientSour
 }
 
 Maybe<ClientInfo>
 nsDocShell::GetInitialClientInfo() const
 {
   if (mInitialClientSource) {
     Maybe<ClientInfo> result;
     result.emplace(mInitialClientSource->Info());
-    return std::move(result);
+    return result;
   }
 
   nsGlobalWindowInner* innerWindow =
     mScriptGlobal ? mScriptGlobal->GetCurrentInnerWindowInternal() : nullptr;
   nsIDocument* doc = innerWindow ? innerWindow->GetExtantDoc() : nullptr;
 
   if (!doc || !doc->IsInitialDocument()) {
     return Maybe<ClientInfo>();
@@ -14062,20 +14062,20 @@ nsDocShell::NotifyJSRunToCompletionStart
                                          const uint32_t aLineNumber,
                                          JS::Handle<JS::Value> aAsyncStack,
                                          const char* aAsyncCause)
 {
   // If first start, mark interval start.
   if (mJSRunToCompletionDepth == 0) {
     RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
     if (timelines && timelines->HasConsumer(this)) {
-      timelines->AddMarkerForDocShell(this, std::move(
+      timelines->AddMarkerForDocShell(this,
         mozilla::MakeUnique<JavascriptTimelineMarker>(
           aReason, aFunctionName, aFilename, aLineNumber, MarkerTracingType::START,
-          aAsyncStack, aAsyncCause)));
+          aAsyncStack, aAsyncCause));
     }
   }
 
   mJSRunToCompletionDepth++;
 }
 
 void
 nsDocShell::NotifyJSRunToCompletionStop()
--- a/docshell/base/timeline/AutoRestyleTimelineMarker.cpp
+++ b/docshell/base/timeline/AutoRestyleTimelineMarker.cpp
@@ -27,34 +27,34 @@ AutoRestyleTimelineMarker::AutoRestyleTi
   }
 
   RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
   if (!timelines || !timelines->HasConsumer(aDocShell)) {
     return;
   }
 
   mDocShell = aDocShell;
-  timelines->AddMarkerForDocShell(mDocShell, std::move(
+  timelines->AddMarkerForDocShell(mDocShell,
     MakeUnique<RestyleTimelineMarker>(
       mIsAnimationOnly,
-      MarkerTracingType::START)));
+      MarkerTracingType::START));
 }
 
 AutoRestyleTimelineMarker::~AutoRestyleTimelineMarker()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (!mDocShell) {
     return;
   }
 
   RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
   if (!timelines || !timelines->HasConsumer(mDocShell)) {
     return;
   }
 
-  timelines->AddMarkerForDocShell(mDocShell, std::move(
+  timelines->AddMarkerForDocShell(mDocShell,
     MakeUnique<RestyleTimelineMarker>(
       mIsAnimationOnly,
-      MarkerTracingType::END)));
+      MarkerTracingType::END));
 }
 
 } // namespace mozilla
--- a/docshell/base/timeline/TimelineConsumers.cpp
+++ b/docshell/base/timeline/TimelineConsumers.cpp
@@ -180,30 +180,30 @@ TimelineConsumers::IsEmpty()
 void
 TimelineConsumers::AddMarkerForDocShell(nsDocShell* aDocShell,
                                         const char* aName,
                                         MarkerTracingType aTracingType,
                                         MarkerStackRequest aStackRequest)
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (HasConsumer(aDocShell)) {
-    aDocShell->mObserved->AddMarker(std::move(MakeUnique<TimelineMarker>(aName, aTracingType, aStackRequest)));
+    aDocShell->mObserved->AddMarker(MakeUnique<TimelineMarker>(aName, aTracingType, aStackRequest));
   }
 }
 
 void
 TimelineConsumers::AddMarkerForDocShell(nsDocShell* aDocShell,
                                         const char* aName,
                                         const TimeStamp& aTime,
                                         MarkerTracingType aTracingType,
                                         MarkerStackRequest aStackRequest)
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (HasConsumer(aDocShell)) {
-    aDocShell->mObserved->AddMarker(std::move(MakeUnique<TimelineMarker>(aName, aTime, aTracingType, aStackRequest)));
+    aDocShell->mObserved->AddMarker(MakeUnique<TimelineMarker>(aName, aTime, aTracingType, aStackRequest));
   }
 }
 
 void
 TimelineConsumers::AddMarkerForDocShell(nsDocShell* aDocShell,
                                         UniquePtr<AbstractTimelineMarker>&& aMarker)
 {
   MOZ_ASSERT(NS_IsMainThread());
--- a/dom/animation/EffectSet.h
+++ b/dom/animation/EffectSet.h
@@ -85,17 +85,17 @@ public:
   // This allows us to avoid exposing mEffects directly and saves the
   // caller from having to dereference hashtable iterators using
   // the rather complicated: iter.Get()->GetKey().
   class Iterator
   {
   public:
     explicit Iterator(EffectSet& aEffectSet)
       : mEffectSet(aEffectSet)
-      , mHashIterator(std::move(aEffectSet.mEffects.Iter()))
+      , mHashIterator(aEffectSet.mEffects.Iter())
       , mIsEndIterator(false)
     {
 #ifdef DEBUG
       mEffectSet.mActiveIterators++;
 #endif
     }
 
     Iterator(Iterator&& aOther)
--- a/dom/base/BodyUtil.cpp
+++ b/dom/base/BodyUtil.cpp
@@ -291,16 +291,20 @@ public:
   FormDataParser(const nsACString& aMimeType, const nsACString& aData, nsIGlobalObject* aParent)
     : mMimeType(aMimeType), mData(aData), mState(START_PART), mParentObject(aParent)
   {
   }
 
   bool
   Parse()
   {
+    if (mData.IsEmpty()) {
+      return false;
+    }
+
     // Determine boundary from mimetype.
     const char* boundaryId = nullptr;
     boundaryId = strstr(mMimeType.BeginWriting(), "boundary");
     if (!boundaryId) {
       return false;
     }
 
     boundaryId = strchr(boundaryId, '=');
@@ -382,17 +386,17 @@ public:
           mState = START_PART;
           break;
 
         default:
           MOZ_CRASH("Invalid case");
       }
     }
 
-    NS_NOTREACHED("Should never reach here.");
+    MOZ_ASSERT_UNREACHABLE("Should never reach here.");
     return false;
   }
 
   already_AddRefed<FormData> GetFormData()
   {
     return mFormData.forget();
   }
 };
--- a/dom/base/CustomElementRegistry.cpp
+++ b/dom/base/CustomElementRegistry.cpp
@@ -488,17 +488,17 @@ CustomElementRegistry::CreateCustomEleme
 
   if (aArgs) {
     callback->SetArgs(*aArgs);
   }
 
   if (aAdoptedCallbackArgs) {
     callback->SetAdoptedCallbackArgs(*aAdoptedCallbackArgs);
   }
-  return std::move(callback);
+  return callback;
 }
 
 /* static */ void
 CustomElementRegistry::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType,
                                                 Element* aCustomElement,
                                                 LifecycleCallbackArgs* aArgs,
                                                 LifecycleAdoptedCallbackArgs* aAdoptedCallbackArgs,
                                                 CustomElementDefinition* aDefinition)
--- a/dom/base/nsContentPermissionHelper.cpp
+++ b/dom/base/nsContentPermissionHelper.cpp
@@ -427,17 +427,17 @@ nsContentPermissionUtils::GetContentPerm
 {
   nsTArray<PContentPermissionRequestParent*> parentArray;
   for (auto& it : ContentPermissionRequestParentMap()) {
     if (it.second == aTabId) {
       parentArray.AppendElement(it.first);
     }
   }
 
-  return std::move(parentArray);
+  return parentArray;
 }
 
 /* static */ void
 nsContentPermissionUtils::NotifyRemoveContentPermissionRequestParent(
   PContentPermissionRequestParent* aParent)
 {
   auto it = ContentPermissionRequestParentMap().find(aParent);
   MOZ_ASSERT(it != ContentPermissionRequestParentMap().end());
@@ -450,17 +450,17 @@ nsContentPermissionUtils::GetContentPerm
 {
   nsTArray<PContentPermissionRequestChild*> childArray;
   for (auto& it : ContentPermissionRequestChildMap()) {
     if (it.second == aTabId) {
       childArray.AppendElement(it.first);
     }
   }
 
-  return std::move(childArray);
+  return childArray;
 }
 
 /* static */ void
 nsContentPermissionUtils::NotifyRemoveContentPermissionRequestChild(
   PContentPermissionRequestChild* aChild)
 {
   auto it = ContentPermissionRequestChildMap().find(aChild);
   MOZ_ASSERT(it != ContentPermissionRequestChildMap().end());
--- a/dom/base/nsContentSink.cpp
+++ b/dom/base/nsContentSink.cpp
@@ -1230,16 +1230,19 @@ void
 nsContentSink::ScrollToRef()
 {
   mDocument->ScrollToRef();
 }
 
 void
 nsContentSink::StartLayout(bool aIgnorePendingSheets)
 {
+  AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("nsContentSink::StartLayout", LAYOUT,
+                                        mDocumentURI->GetSpecOrDefault());
+
   if (mLayoutStarted) {
     // Nothing to do here
     return;
   }
 
   mDeferredLayoutStart = true;
 
   if (!aIgnorePendingSheets && WaitForPendingSheets()) {
--- a/dom/base/nsDOMDataChannel.cpp
+++ b/dom/base/nsDOMDataChannel.cpp
@@ -131,16 +131,28 @@ nsDOMDataChannel::Id() const
 
 // XXX should be GetType()?  Open question for the spec
 bool
 nsDOMDataChannel::Reliable() const
 {
   return mDataChannel->GetType() == mozilla::DataChannelConnection::RELIABLE;
 }
 
+mozilla::dom::Nullable<uint16_t>
+nsDOMDataChannel::GetMaxPacketLifeTime() const
+{
+  return mDataChannel->GetMaxPacketLifeTime();
+}
+
+mozilla::dom::Nullable<uint16_t>
+nsDOMDataChannel::GetMaxRetransmits() const
+{
+  return mDataChannel->GetMaxRetransmits();
+}
+
 bool
 nsDOMDataChannel::Ordered() const
 {
   return mDataChannel->GetOrdered();
 }
 
 RTCDataChannelState
 nsDOMDataChannel::ReadyState() const
--- a/dom/base/nsDOMDataChannel.h
+++ b/dom/base/nsDOMDataChannel.h
@@ -50,16 +50,18 @@ public:
   {
     return GetOwner();
   }
 
   // WebIDL
   void GetLabel(nsAString& aLabel);
   void GetProtocol(nsAString& aProtocol);
   bool Reliable() const;
+  mozilla::dom::Nullable<uint16_t> GetMaxPacketLifeTime() const;
+  mozilla::dom::Nullable<uint16_t> GetMaxRetransmits() const;
   mozilla::dom::RTCDataChannelState ReadyState() const;
   uint32_t BufferedAmount() const;
   uint32_t BufferedAmountLowThreshold() const;
   void SetBufferedAmountLowThreshold(uint32_t aThreshold);
   IMPL_EVENT_HANDLER(open)
   IMPL_EVENT_HANDLER(error)
   IMPL_EVENT_HANDLER(close)
   void Close();
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -715,17 +715,17 @@ nsDOMWindowUtils::SendMouseEventToWindow
                                          float aPressure,
                                          unsigned short aInputSourceArg,
                                          bool aIsDOMEventSynthesized,
                                          bool aIsWidgetEventSynthesized,
                                          int32_t aButtons,
                                          uint32_t aIdentifier,
                                          uint8_t aOptionalArgCount)
 {
-  AUTO_PROFILER_LABEL("nsDOMWindowUtils::SendMouseEventToWindow", EVENTS);
+  AUTO_PROFILER_LABEL("nsDOMWindowUtils::SendMouseEventToWindow", OTHER);
 
   return SendMouseEventCommon(aType, aX, aY, aButton, aClickCount, aModifiers,
                               aIgnoreRootScrollFrame, aPressure,
                               aInputSourceArg,
                               aOptionalArgCount >= 7 ?
                                 aIdentifier : DEFAULT_MOUSE_POINTER_ID,
                               true, nullptr,
                               aOptionalArgCount >= 4 ?
@@ -1234,17 +1234,17 @@ nsDOMWindowUtils::GetWidgetForElement(El
   }
 
   return nullptr;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::GarbageCollect(nsICycleCollectorListener *aListener)
 {
-  AUTO_PROFILER_LABEL("nsDOMWindowUtils::GarbageCollect", GC);
+  AUTO_PROFILER_LABEL("nsDOMWindowUtils::GarbageCollect", GCCC);
 
   nsJSContext::GarbageCollectNow(JS::gcreason::DOM_UTILS);
   nsJSContext::CycleCollectNow(aListener);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -5560,39 +5560,39 @@ nsIDocument::GetAnonRootIfInAnonymousCon
   return nullptr;
 }
 
 Maybe<ClientInfo>
 nsIDocument::GetClientInfo() const
 {
   nsPIDOMWindowInner* inner = GetInnerWindow();
   if (inner) {
-    return std::move(inner->GetClientInfo());
-  }
-  return std::move(Maybe<ClientInfo>());
+    return inner->GetClientInfo();
+  }
+  return Maybe<ClientInfo>();
 }
 
 Maybe<ClientState>
 nsIDocument::GetClientState() const
 {
   nsPIDOMWindowInner* inner = GetInnerWindow();
   if (inner) {
-    return std::move(inner->GetClientState());
-  }
-  return std::move(Maybe<ClientState>());
+    return inner->GetClientState();
+  }
+  return Maybe<ClientState>();
 }
 
 Maybe<ServiceWorkerDescriptor>
 nsIDocument::GetController() const
 {
   nsPIDOMWindowInner* inner = GetInnerWindow();
   if (inner) {
-    return std::move(inner->GetController());
-  }
-  return std::move(Maybe<ServiceWorkerDescriptor>());
+    return inner->GetController();
+  }
+  return Maybe<ServiceWorkerDescriptor>();
 }
 
 //
 // nsIDocument interface
 //
 DocumentType*
 nsIDocument::GetDoctype() const
 {
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -916,17 +916,17 @@ nsFrameLoader::MarginsChanged(uint32_t a
     // a different style
     presContext->RebuildAllStyleData(nsChangeHint(0), eRestyle_Subtree);
 }
 
 bool
 nsFrameLoader::ShowRemoteFrame(const ScreenIntSize& size,
                                nsSubDocumentFrame *aFrame)
 {
-  AUTO_PROFILER_LABEL("nsFrameLoader::ShowRemoteFrame", GRAPHICS);
+  AUTO_PROFILER_LABEL("nsFrameLoader::ShowRemoteFrame", OTHER);
   NS_ASSERTION(IsRemoteFrame(), "ShowRemote only makes sense on remote frames.");
 
   if (!mRemoteBrowser && !TryRemoteBrowser()) {
     NS_ERROR("Couldn't create child process.");
     return false;
   }
 
   // FIXME/bug 589337: Show()/Hide() is pretty expensive for
--- a/dom/base/nsFrameMessageManager.cpp
+++ b/dom/base/nsFrameMessageManager.cpp
@@ -504,17 +504,17 @@ nsFrameMessageManager::SendMessage(JSCon
                                    ErrorResult& aError)
 {
   NS_ASSERTION(!IsGlobal(), "Should not call SendSyncMessage in chrome");
   NS_ASSERTION(!IsBroadcaster(), "Should not call SendSyncMessage in chrome");
   NS_ASSERTION(!GetParentManager(),
                "Should not have parent manager in content!");
 
   AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING(
-    "nsFrameMessageManager::SendMessage", EVENTS, aMessageName);
+    "nsFrameMessageManager::SendMessage", OTHER, aMessageName);
 
   if (sSendingSyncMessage && aIsSync) {
     // No kind of blocking send should be issued on top of a sync message.
     aError.Throw(NS_ERROR_UNEXPECTED);
     return;
   }
 
   StructuredCloneData data;
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -2315,35 +2315,35 @@ void
 nsPIDOMWindowInner::SyncStateFromParentWindow()
 {
   nsGlobalWindowInner::Cast(this)->SyncStateFromParentWindow();
 }
 
 Maybe<ClientInfo>
 nsPIDOMWindowInner::GetClientInfo() const
 {
-  return std::move(nsGlobalWindowInner::Cast(this)->GetClientInfo());
+  return nsGlobalWindowInner::Cast(this)->GetClientInfo();
 }
 
 Maybe<ClientState>
 nsPIDOMWindowInner::GetClientState() const
 {
-  return std::move(nsGlobalWindowInner::Cast(this)->GetClientState());
+  return nsGlobalWindowInner::Cast(this)->GetClientState();
 }
 
 Maybe<ServiceWorkerDescriptor>
 nsPIDOMWindowInner::GetController() const
 {
-  return std::move(nsGlobalWindowInner::Cast(this)->GetController());
+  return nsGlobalWindowInner::Cast(this)->GetController();
 }
 
 RefPtr<mozilla::dom::ServiceWorker>
 nsPIDOMWindowInner::GetOrCreateServiceWorker(const mozilla::dom::ServiceWorkerDescriptor& aDescriptor)
 {
-  return std::move(nsGlobalWindowInner::Cast(this)->GetOrCreateServiceWorker(aDescriptor));
+  return nsGlobalWindowInner::Cast(this)->GetOrCreateServiceWorker(aDescriptor);
 }
 
 void
 nsPIDOMWindowInner::NoteCalledRegisterForServiceWorkerScope(const nsACString& aScope)
 {
   nsGlobalWindowInner::Cast(this)->NoteCalledRegisterForServiceWorkerScope(aScope);
 }
 
@@ -5493,17 +5493,17 @@ nsGlobalWindowInner::ShowSlowScriptDialo
   auto getString = [&] (const char* name,
                         nsContentUtils::PropertiesFile propFile = nsContentUtils::eDOM_PROPERTIES) {
     nsAutoString result;
     nsresult rv = nsContentUtils::GetLocalizedString(
       propFile, name, result);
 
     // GetStringFromName can return NS_OK and still give nullptr string
     failed = failed || NS_FAILED(rv) || result.IsEmpty();
-    return std::move(result);
+    return result;
   };
 
   bool isAddonScript = !aAddonId.IsEmpty();
   bool showDebugButton = debugCallback && !isAddonScript;
 
   // Get localizable strings
 
   nsAutoString title, checkboxMsg, debugButton, msg;
@@ -6324,43 +6324,43 @@ nsGlobalWindowInner::CallOnChildren(Meth
 Maybe<ClientInfo>
 nsGlobalWindowInner::GetClientInfo() const
 {
   MOZ_ASSERT(NS_IsMainThread());
   Maybe<ClientInfo> clientInfo;
   if (mClientSource) {
     clientInfo.emplace(mClientSource->Info());
   }
-  return std::move(clientInfo);
+  return clientInfo;
 }
 
 Maybe<ClientState>
 nsGlobalWindowInner::GetClientState() const
 {
   MOZ_ASSERT(NS_IsMainThread());
   Maybe<ClientState> clientState;
   if (mClientSource) {
     ClientState state;
     nsresult rv = mClientSource->SnapshotState(&state);
     if (NS_SUCCEEDED(rv)) {
       clientState.emplace(state);
     }
   }
-  return std::move(clientState);
+  return clientState;
 }
 
 Maybe<ServiceWorkerDescriptor>
 nsGlobalWindowInner::GetController() const
 {
   MOZ_ASSERT(NS_IsMainThread());
   Maybe<ServiceWorkerDescriptor> controller;
   if (mClientSource) {
     controller = mClientSource->GetController();
   }
-  return std::move(controller);
+  return controller;
 }
 
 RefPtr<ServiceWorker>
 nsGlobalWindowInner::GetOrCreateServiceWorker(const ServiceWorkerDescriptor& aDescriptor)
 {
   MOZ_ASSERT(NS_IsMainThread());
   RefPtr<ServiceWorker> ref;
   ForEachEventTargetObject([&] (DOMEventTargetHelper* aTarget, bool* aDoneOut) {
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -1173,17 +1173,17 @@ FullGCTimerFired(nsITimer* aTimer, void*
 
 //static
 void
 nsJSContext::GarbageCollectNow(JS::gcreason::Reason aReason,
                                IsIncremental aIncremental,
                                IsShrinking aShrinking,
                                int64_t aSliceMillis)
 {
-  AUTO_PROFILER_LABEL_DYNAMIC_CSTR("nsJSContext::GarbageCollectNow", GC,
+  AUTO_PROFILER_LABEL_DYNAMIC_CSTR("nsJSContext::GarbageCollectNow", GCCC,
                                    JS::gcreason::ExplainReason(aReason));
 
   MOZ_ASSERT_IF(aSliceMillis, aIncremental == IncrementalGC);
 
   KillGCTimer();
 
   // Reset sPendingLoadCount in case the timer that fired was a
   // timer we scheduled due to a normal GC timer firing while
@@ -1226,17 +1226,17 @@ nsJSContext::GarbageCollectNow(JS::gcrea
   } else {
     JS::NonIncrementalGC(cx, gckind, aReason);
   }
 }
 
 static void
 FinishAnyIncrementalGC()
 {
-  AUTO_PROFILER_LABEL("FinishAnyIncrementalGC", GC);
+  AUTO_PROFILER_LABEL("FinishAnyIncrementalGC", GCCC);
 
   if (sCCLockedOut) {
     AutoJSAPI jsapi;
     jsapi.Init();
 
     // We're in the middle of an incremental GC, so finish it.
     JS::PrepareForIncrementalGC(jsapi.cx());
     JS::FinishIncrementalGC(jsapi.cx(), JS::gcreason::CC_FORCED);
@@ -1477,34 +1477,34 @@ CycleCollectorStats::RunForgetSkippable(
 //static
 void
 nsJSContext::CycleCollectNow(nsICycleCollectorListener *aListener)
 {
   if (!NS_IsMainThread()) {
     return;
   }
 
-  AUTO_PROFILER_LABEL("nsJSContext::CycleCollectNow", CC);
+  AUTO_PROFILER_LABEL("nsJSContext::CycleCollectNow", GCCC);
 
   gCCStats.PrepareForCycleCollectionSlice(TimeStamp());
   nsCycleCollector_collect(aListener);
   gCCStats.FinishCycleCollectionSlice();
 }
 
 //static
 void
 nsJSContext::RunCycleCollectorSlice(TimeStamp aDeadline)
 {
   if (!NS_IsMainThread()) {
     return;
   }
 
   AUTO_PROFILER_TRACING("CC", aDeadline.IsNull() ? "CCSlice" : "IdleCCSlice");
 
-  AUTO_PROFILER_LABEL("nsJSContext::RunCycleCollectorSlice", CC);
+  AUTO_PROFILER_LABEL("nsJSContext::RunCycleCollectorSlice", GCCC);
 
   gCCStats.PrepareForCycleCollectionSlice(aDeadline);
 
   // Decide how long we want to budget for this slice. By default,
   // use an unlimited budget.
   js::SliceBudget budget = js::SliceBudget::unlimited();
 
   if (sIncrementalCC) {
@@ -1552,17 +1552,17 @@ nsJSContext::RunCycleCollectorSlice(Time
 //static
 void
 nsJSContext::RunCycleCollectorWorkSlice(int64_t aWorkBudget)
 {
   if (!NS_IsMainThread()) {
     return;
   }
 
-  AUTO_PROFILER_LABEL("nsJSContext::RunCycleCollectorWorkSlice", CC);
+  AUTO_PROFILER_LABEL("nsJSContext::RunCycleCollectorWorkSlice", GCCC);
 
   gCCStats.PrepareForCycleCollectionSlice();
 
   js::SliceBudget budget = js::SliceBudget(js::WorkBudget(aWorkBudget));
   nsCycleCollector_collectSlice(budget);
 
   gCCStats.FinishCycleCollectionSlice();
 }
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -1574,17 +1574,17 @@ class CGAbstractMethod(CGThing):
             decorators.append('static')
         decorators.append(self.returnType)
         maybeNewline = " " if self.inline else "\n"
         return ' '.join(decorators) + maybeNewline
 
     def _auto_profiler_label(self):
         profiler_label_and_jscontext = self.profiler_label_and_jscontext()
         if profiler_label_and_jscontext:
-            return 'AUTO_PROFILER_LABEL_FAST("%s", OTHER, %s);' % profiler_label_and_jscontext
+            return 'AUTO_PROFILER_LABEL_FAST("%s", DOM, %s);' % profiler_label_and_jscontext
         return None
 
     def declare(self):
         if self.inline:
             return self._define(True)
         return "%s%s%s(%s);\n" % (self._template(), self._decorators(), self.name, self._argstring(True))
 
     def indent_body(self, body):
--- a/dom/canvas/ImageBitmap.cpp
+++ b/dom/canvas/ImageBitmap.cpp
@@ -799,17 +799,17 @@ ImageBitmap::ToCloneData() const
   UniquePtr<ImageBitmapCloneData> result(new ImageBitmapCloneData());
   result->mPictureRect = mPictureRect;
   result->mAlphaType = mAlphaType;
   result->mIsCroppingAreaOutSideOfSourceImage = mIsCroppingAreaOutSideOfSourceImage;
   RefPtr<SourceSurface> surface = mData->GetAsSourceSurface();
   result->mSurface = surface->GetDataSurface();
   MOZ_ASSERT(result->mSurface);
 
-  return std::move(result);
+  return result;
 }
 
 /* static */ already_AddRefed<ImageBitmap>
 ImageBitmap::CreateFromCloneData(nsIGlobalObject* aGlobal,
                                  ImageBitmapCloneData* aData)
 {
   RefPtr<layers::Image> data = CreateImageFromSurface(aData->mSurface);
 
--- a/dom/canvas/WebGLFormats.cpp
+++ b/dom/canvas/WebGLFormats.cpp
@@ -822,17 +822,17 @@ FormatUsageAuthority::CreateForWebGL1(gl
     ptr->AllowRBFormat(LOCAL_GL_DEPTH_STENCIL,
                        ptr->GetUsage(EffectiveFormat::DEPTH24_STENCIL8));
 
     ////////////////////////////////////////////////////////////////////////////
 
     if (!AddUnsizedFormats(ptr, gl))
         return nullptr;
 
-    return std::move(ret);
+    return ret;
 }
 
 UniquePtr<FormatUsageAuthority>
 FormatUsageAuthority::CreateForWebGL2(gl::GLContext* gl)
 {
     UniquePtr<FormatUsageAuthority> ret(new FormatUsageAuthority);
     const auto ptr = ret.get();
 
@@ -1057,17 +1057,17 @@ FormatUsageAuthority::CreateForWebGL2(gl
         AddSimpleUnsized(ptr, LOCAL_GL_RGB , LOCAL_GL_FLOAT, EffectiveFormat::RGB32F );
 
         AddSimpleUnsized(ptr, LOCAL_GL_RGBA, LOCAL_GL_HALF_FLOAT_OES, EffectiveFormat::RGBA16F);
         AddSimpleUnsized(ptr, LOCAL_GL_RGB , LOCAL_GL_HALF_FLOAT_OES, EffectiveFormat::RGB16F );
     }
 
     ////////////////////////////////////
 
-    return std::move(ret);
+    return ret;
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
 
 void
 FormatUsageAuthority::AddTexUnpack(FormatUsageInfo* usage, const PackingInfo& pi,
                                    const DriverUnpackInfo& dui)
 {
--- a/dom/canvas/WebGLTextureUpload.cpp
+++ b/dom/canvas/WebGLTextureUpload.cpp
@@ -222,17 +222,17 @@ FromPboOffset(WebGLContext* webgl, const
                                              isClientData, ptr, availBufferBytes);
 }
 
 static UniquePtr<webgl::TexUnpackBlob>
 FromImageBitmap(WebGLContext* webgl, const char* funcName, TexImageTarget target,
                 uint32_t width, uint32_t height, uint32_t depth,
                 const dom::ImageBitmap& imageBitmap)
 {
-    UniquePtr<dom::ImageBitmapCloneData> cloneData = std::move(imageBitmap.ToCloneData());
+    UniquePtr<dom::ImageBitmapCloneData> cloneData = imageBitmap.ToCloneData();
     if (!cloneData) {
       return nullptr;
     }
 
     const RefPtr<gfx::DataSourceSurface> surf = cloneData->mSurface;
 
     if (!width) {
         width = surf->GetSize().width;
@@ -455,17 +455,17 @@ ValidateTexOrSubImage(WebGLContext* webg
     if (!ValidateViewType(webgl, funcName, pi.type, src))
         return nullptr;
 
     auto blob = webgl->From(funcName, target, rawWidth, rawHeight, rawDepth, border, src,
                             scopedArr);
     if (!blob || !blob->Validate(webgl, funcName, pi))
         return nullptr;
 
-    return std::move(blob);
+    return blob;
 }
 
 void
 WebGLTexture::TexImage(const char* funcName, TexImageTarget target, GLint level,
                        GLenum internalFormat, GLsizei width, GLsizei height,
                        GLsizei depth, GLint border, const webgl::PackingInfo& pi,
                        const TexImageSource& src)
 {
--- a/dom/clients/manager/ClientHandle.cpp
+++ b/dom/clients/manager/ClientHandle.cpp
@@ -198,13 +198,13 @@ ClientHandle::OnDetach()
   if (!mDetachPromise) {
     mDetachPromise = new GenericPromise::Private(__func__);
     if (IsShutdown()) {
       mDetachPromise->Resolve(true, __func__);
     }
   }
 
   RefPtr<GenericPromise> ref(mDetachPromise);
-  return std::move(ref);
+  return ref;
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/clients/manager/ClientInfo.cpp
+++ b/dom/clients/manager/ClientInfo.cpp
@@ -146,13 +146,13 @@ ClientInfo::IsPrivateBrowsing() const
   }
 }
 
 nsCOMPtr<nsIPrincipal>
 ClientInfo::GetPrincipal() const
 {
   MOZ_ASSERT(NS_IsMainThread());
   nsCOMPtr<nsIPrincipal> ref = PrincipalInfoToPrincipal(PrincipalInfo());
-  return std::move(ref);
+  return ref;
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/clients/manager/ClientManager.cpp
+++ b/dom/clients/manager/ClientManager.cpp
@@ -131,30 +131,30 @@ ClientManager::CreateSourceInternal(Clie
   if (NS_WARN_IF(NS_FAILED(rv))) {
     // If we can't even get a UUID, at least make sure not to use a garbage
     // value.  Instead return a shutdown ClientSource with a zero'd id.
     // This should be exceptionally rare, if it happens at all.
     id.Clear();
     ClientSourceConstructorArgs args(id, aType, aPrincipal, TimeStamp::Now());
     UniquePtr<ClientSource> source(new ClientSource(this, aEventTarget, args));
     source->Shutdown();
-    return std::move(source);
+    return source;
   }
 
   ClientSourceConstructorArgs args(id, aType, aPrincipal, TimeStamp::Now());
   UniquePtr<ClientSource> source(new ClientSource(this, aEventTarget, args));
 
   if (IsShutdown()) {
     source->Shutdown();
-    return std::move(source);
+    return source;
   }
 
   source->Activate(GetActor());
 
-  return std::move(source);
+  return source;
 }
 
 already_AddRefed<ClientHandle>
 ClientManager::CreateHandleInternal(const ClientInfo& aClientInfo,
                                     nsISerialEventTarget* aSerialEventTarget)
 {
   NS_ASSERT_OWNINGTHREAD(ClientManager);
   MOZ_DIAGNOSTIC_ASSERT(aSerialEventTarget);
--- a/dom/clients/manager/ClientManagerService.cpp
+++ b/dom/clients/manager/ClientManagerService.cpp
@@ -435,18 +435,18 @@ ClientManagerService::MatchAll(const Cli
 
       if(controller.ref().Id() != swd.Id() ||
          controller.ref().Scope() != swd.Scope()) {
         continue;
       }
     }
 
     promiseList->AddPromise(
-      source->StartOp(std::move(ClientGetInfoAndStateArgs(source->Info().Id(),
-                                                     source->Info().PrincipalInfo()))));
+      source->StartOp(ClientGetInfoAndStateArgs(source->Info().Id(),
+                                                source->Info().PrincipalInfo())));
   }
 
   // Maybe finish the promise now in case we didn't find any matching clients.
   promiseList->MaybeFinish();
 
   return promiseList->GetResultPromise();
 }
 
--- a/dom/console/Console.cpp
+++ b/dom/console/Console.cpp
@@ -2882,36 +2882,36 @@ Console::MonotonicTimer(JSContext* aCx, 
         return false;
       }
 
       nsAutoJSString key;
       if (!key.init(aCx, jsString)) {
         return false;
       }
 
-      timelines->AddMarkerForDocShell(docShell, std::move(
-        MakeUnique<TimestampTimelineMarker>(key)));
+      timelines->AddMarkerForDocShell(docShell,
+        MakeUnique<TimestampTimelineMarker>(key));
     }
     // For `console.time(foo)` and `console.timeEnd(foo)`.
     else if (isTimelineRecording && aData.Length() == 1) {
       JS::Rooted<JS::Value> value(aCx, aData[0]);
       JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, value));
       if (!jsString) {
         return false;
       }
 
       nsAutoJSString key;
       if (!key.init(aCx, jsString)) {
         return false;
       }
 
-      timelines->AddMarkerForDocShell(docShell, std::move(
+      timelines->AddMarkerForDocShell(docShell,
         MakeUnique<ConsoleTimelineMarker>(
           key, aMethodName == MethodTime ? MarkerTracingType::START
-                                         : MarkerTracingType::END)));
+                                         : MarkerTracingType::END));
     }
 
     return true;
   }
 
   if (NS_IsMainThread()) {
     *aTimeStamp = (TimeStamp::Now() - mCreationTimeStamp).ToMilliseconds();
     return true;
--- a/dom/events/DataTransferItemList.cpp
+++ b/dom/events/DataTransferItemList.cpp
@@ -87,17 +87,16 @@ DataTransferItemList::Remove(uint32_t aI
                              ErrorResult& aRv)
 {
   if (mDataTransfer->IsReadOnly()) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 
   if (aIndex >= Length()) {
-    aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     return;
   }
 
   ClearDataHelper(mItems[aIndex], aIndex, -1, aSubjectPrincipal, aRv);
 }
 
 DataTransferItem*
 DataTransferItemList::IndexedGetter(uint32_t aIndex, bool& aFound) const
@@ -356,20 +355,18 @@ DataTransferItemList::SetDataWithPrincip
                         || !subsumes))) {
           aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
           return nullptr;
         }
         item->SetPrincipal(aPrincipal);
 
         DataTransferItem::eKind oldKind = item->Kind();
         item->SetData(aData);
-        if (oldKind != item->Kind()) {
-          // Types list may have changed, even if aIndex == 0.
-          mDataTransfer->TypesListMayHaveChanged();
-        }
+
+        mDataTransfer->TypesListMayHaveChanged();
 
         if (aIndex != 0) {
           // If the item changes from being a file to not a file or vice-versa,
           // its presence in the mItems array may need to change.
           if (item->Kind() == DataTransferItem::KIND_FILE &&
               oldKind != DataTransferItem::KIND_FILE) {
             // not file => file
             mItems.AppendElement(item);
--- a/dom/events/EventDispatcher.cpp
+++ b/dom/events/EventDispatcher.cpp
@@ -789,17 +789,17 @@ ShouldClearTargets(WidgetEvent* aEvent)
 EventDispatcher::Dispatch(nsISupports* aTarget,
                           nsPresContext* aPresContext,
                           WidgetEvent* aEvent,
                           Event* aDOMEvent,
                           nsEventStatus* aEventStatus,
                           EventDispatchingCallback* aCallback,
                           nsTArray<EventTarget*>* aTargets)
 {
-  AUTO_PROFILER_LABEL("EventDispatcher::Dispatch", EVENTS);
+  AUTO_PROFILER_LABEL("EventDispatcher::Dispatch", OTHER);
 
   NS_ASSERTION(aEvent, "Trying to dispatch without WidgetEvent!");
   NS_ENSURE_TRUE(!aEvent->mFlags.mIsBeingDispatched,
                  NS_ERROR_DOM_INVALID_STATE_ERR);
   NS_ASSERTION(!aTargets || !aEvent->mMessage, "Wrong parameters!");
 
   // If we're dispatching an already created DOMEvent object, make
   // sure it is initialized!
--- a/dom/events/EventListenerManager.cpp
+++ b/dom/events/EventListenerManager.cpp
@@ -1240,19 +1240,19 @@ EventListenerManager::HandleEventInterna
                 listener->mListenerType != Listener::eNativeListener) {
               docShell = nsContentUtils::GetDocShellForEventTarget(mTarget);
               if (docShell) {
                 if (timelines && timelines->HasConsumer(docShell)) {
                   needsEndEventMarker = true;
                   nsAutoString typeStr;
                   (*aDOMEvent)->GetType(typeStr);
                   uint16_t phase = (*aDOMEvent)->EventPhase();
-                  timelines->AddMarkerForDocShell(docShell, std::move(
+                  timelines->AddMarkerForDocShell(docShell,
                     MakeUnique<EventTimelineMarker>(
-                      typeStr, phase, MarkerTracingType::START)));
+                      typeStr, phase, MarkerTracingType::START));
                 }
               }
             }
 
             aEvent->mFlags.mInPassiveListener = listener->mFlags.mPassive;
             Maybe<Listener> listenerHolder;
             if (listener->mFlags.mOnce) {
               // Move the listener to the stack before handling the event.
@@ -1268,17 +1268,17 @@ EventListenerManager::HandleEventInterna
             if (profiler_is_active()) {
               // Add a profiler label and a profiler marker for the actual
               // dispatch of the event.
               // This is a very hot code path, so we need to make sure not to
               // do this extra work when we're not profiling.
               nsAutoString typeStr;
               (*aDOMEvent)->GetType(typeStr);
               AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING(
-                "EventListenerManager::HandleEventInternal", EVENTS, typeStr);
+                "EventListenerManager::HandleEventInternal", OTHER, typeStr);
 
               uint16_t phase = (*aDOMEvent)->EventPhase();
               profiler_add_marker(
                 "DOMEvent",
                 MakeUnique<DOMEventMarkerPayload>(typeStr, phase,
                                                   aEvent->mTimeStamp,
                                                   "DOMEvent",
                                                   TRACING_INTERVAL_START));
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -4177,17 +4177,17 @@ EventStateManager::StopHandlingUserInput
 static void
 CreateMouseOrPointerWidgetEvent(WidgetMouseEvent* aMouseEvent,
                                 EventMessage aMessage,
                                 nsIContent* aRelatedContent,
                                 nsAutoPtr<WidgetMouseEvent>& aNewEvent)
 {
   WidgetPointerEvent* sourcePointer = aMouseEvent->AsPointerEvent();
   if (sourcePointer) {
-    AUTO_PROFILER_LABEL("CreateMouseOrPointerWidgetEvent", EVENTS);
+    AUTO_PROFILER_LABEL("CreateMouseOrPointerWidgetEvent", OTHER);
 
     nsAutoPtr<WidgetPointerEvent> newPointerEvent;
     newPointerEvent =
       new WidgetPointerEvent(aMouseEvent->IsTrusted(), aMessage,
                              aMouseEvent->mWidget);
     newPointerEvent->mIsPrimary = sourcePointer->mIsPrimary;
     newPointerEvent->mWidth = sourcePointer->mWidth;
     newPointerEvent->mHeight = sourcePointer->mHeight;
--- a/dom/file/uri/BlobURLProtocolHandler.cpp
+++ b/dom/file/uri/BlobURLProtocolHandler.cpp
@@ -541,17 +541,17 @@ private:
   {
     nsCOMPtr<nsIAsyncShutdownService> svc = services::GetAsyncShutdown();
     NS_ENSURE_TRUE(!!svc, nullptr);
 
     nsCOMPtr<nsIAsyncShutdownClient> phase;
     nsresult rv = svc->GetXpcomWillShutdown(getter_AddRefs(phase));
     NS_ENSURE_SUCCESS(rv, nullptr);
 
-    return std::move(phase);
+    return phase;
   }
 
   nsCString mURI;
   bool mBroadcastToOtherProcesses;
 
   nsCOMPtr<nsITimer> mTimer;
 };
 
--- a/dom/indexedDB/ActorsChild.cpp
+++ b/dom/indexedDB/ActorsChild.cpp
@@ -726,17 +726,17 @@ DispatchErrorEvent(IDBRequest* aRequest,
                    IDBTransaction* aTransaction = nullptr,
                    Event* aEvent = nullptr)
 {
   MOZ_ASSERT(aRequest);
   aRequest->AssertIsOnOwningThread();
   MOZ_ASSERT(NS_FAILED(aErrorCode));
   MOZ_ASSERT(NS_ERROR_GET_MODULE(aErrorCode) == NS_ERROR_MODULE_DOM_INDEXEDDB);
 
-  AUTO_PROFILER_LABEL("IndexedDB:DispatchErrorEvent", STORAGE);
+  AUTO_PROFILER_LABEL("IndexedDB:DispatchErrorEvent", DOM);
 
   RefPtr<IDBRequest> request = aRequest;
   RefPtr<IDBTransaction> transaction = aTransaction;
 
   request->SetError(aErrorCode);
 
   RefPtr<Event> errorEvent;
   if (!aEvent) {
@@ -799,17 +799,17 @@ DispatchErrorEvent(IDBRequest* aRequest,
 }
 
 void
 DispatchSuccessEvent(ResultHelper* aResultHelper,
                      Event* aEvent = nullptr)
 {
   MOZ_ASSERT(aResultHelper);
 
-  AUTO_PROFILER_LABEL("IndexedDB:DispatchSuccessEvent", STORAGE);
+  AUTO_PROFILER_LABEL("IndexedDB:DispatchSuccessEvent", DOM);
 
   RefPtr<IDBRequest> request = aResultHelper->Request();
   MOZ_ASSERT(request);
   request->AssertIsOnOwningThread();
 
   RefPtr<IDBTransaction> transaction = aResultHelper->Transaction();
 
   if (transaction && transaction->IsAborted()) {
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -757,17 +757,17 @@ MakeCompressedIndexDataValues(
                              UniqueFreePtr<uint8_t>& aCompressedIndexDataValues,
                              uint32_t* aCompressedIndexDataValuesLength)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(!IsOnBackgroundThread());
   MOZ_ASSERT(!aCompressedIndexDataValues);
   MOZ_ASSERT(aCompressedIndexDataValuesLength);
 
-  AUTO_PROFILER_LABEL("MakeCompressedIndexDataValues", STORAGE);
+  AUTO_PROFILER_LABEL("MakeCompressedIndexDataValues", DOM);
 
   const uint32_t arrayLength = aIndexValues.Length();
   if (!arrayLength) {
     *aCompressedIndexDataValuesLength = 0;
     return NS_OK;
   }
 
   // First calculate the size of the final buffer.
@@ -849,17 +849,17 @@ ReadCompressedIndexDataValuesFromBlob(co
                                       nsTArray<IndexDataValue>& aIndexValues)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(!IsOnBackgroundThread());
   MOZ_ASSERT(aBlobData);
   MOZ_ASSERT(aBlobDataLength);
   MOZ_ASSERT(aIndexValues.IsEmpty());
 
-  AUTO_PROFILER_LABEL("ReadCompressedIndexDataValuesFromBlob", STORAGE);
+  AUTO_PROFILER_LABEL("ReadCompressedIndexDataValuesFromBlob", DOM);
 
   if (uintptr_t(aBlobData) > UINTPTR_MAX - aBlobDataLength) {
     IDB_REPORT_INTERNAL_ERR();
     return NS_ERROR_FILE_CORRUPTED;
   }
 
   const uint8_t* blobDataIter = aBlobData;
   const uint8_t* blobDataEnd = aBlobData + aBlobDataLength;
@@ -990,17 +990,17 @@ ReadCompressedIndexDataValues(mozIStorag
 }
 
 nsresult
 CreateFileTables(mozIStorageConnection* aConnection)
 {
   AssertIsOnIOThread();
   MOZ_ASSERT(aConnection);
 
-  AUTO_PROFILER_LABEL("CreateFileTables", STORAGE);
+  AUTO_PROFILER_LABEL("CreateFileTables", DOM);
 
   // Table `file`
   nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "CREATE TABLE file ("
       "id INTEGER PRIMARY KEY, "
       "refcount INTEGER NOT NULL"
     ");"
   ));
@@ -1062,17 +1062,17 @@ CreateFileTables(mozIStorageConnection* 
 }
 
 nsresult
 CreateTables(mozIStorageConnection* aConnection)
 {
   AssertIsOnIOThread();
   MOZ_ASSERT(aConnection);
 
-  AUTO_PROFILER_LABEL("CreateTables", STORAGE);
+  AUTO_PROFILER_LABEL("CreateTables", DOM);
 
   // Table `database`
 
   // There are two reasons for having the origin column.
   // First, we can ensure that we don't have collisions in the origin hash we
   // use for the path because when we open the db we can make sure that the
   // origins exactly match. Second, chrome code crawling through the idb
   // directory can figure out the origin of every db without having to
@@ -1210,17 +1210,17 @@ CreateTables(mozIStorageConnection* aCon
 }
 
 nsresult
 UpgradeSchemaFrom4To5(mozIStorageConnection* aConnection)
 {
   AssertIsOnIOThread();
   MOZ_ASSERT(aConnection);
 
-  AUTO_PROFILER_LABEL("UpgradeSchemaFrom4To5", STORAGE);
+  AUTO_PROFILER_LABEL("UpgradeSchemaFrom4To5", DOM);
 
   nsresult rv;
 
   // All we changed is the type of the version column, so lets try to
   // convert that to an integer, and if we fail, set it to 0.
   nsCOMPtr<mozIStorageStatement> stmt;
   rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
     "SELECT name, version, dataVersion "
@@ -1327,17 +1327,17 @@ UpgradeSchemaFrom4To5(mozIStorageConnect
 }
 
 nsresult
 UpgradeSchemaFrom5To6(mozIStorageConnection* aConnection)
 {
   AssertIsOnIOThread();
   MOZ_ASSERT(aConnection);
 
-  AUTO_PROFILER_LABEL("UpgradeSchemaFrom5To6", STORAGE);
+  AUTO_PROFILER_LABEL("UpgradeSchemaFrom5To6", DOM);
 
   // First, drop all the indexes we're no longer going to use.
   nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "DROP INDEX key_index;"
   ));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
@@ -1775,17 +1775,17 @@ UpgradeSchemaFrom5To6(mozIStorageConnect
 }
 
 nsresult
 UpgradeSchemaFrom6To7(mozIStorageConnection* aConnection)
 {
   AssertIsOnIOThread();
   MOZ_ASSERT(aConnection);
 
-  AUTO_PROFILER_LABEL("UpgradeSchemaFrom6To7", STORAGE);
+  AUTO_PROFILER_LABEL("UpgradeSchemaFrom6To7", DOM);
 
   nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "CREATE TEMPORARY TABLE temp_upgrade ("
       "id, "
       "name, "
       "key_path, "
       "auto_increment"
     ");"
@@ -1848,17 +1848,17 @@ UpgradeSchemaFrom6To7(mozIStorageConnect
 }
 
 nsresult
 UpgradeSchemaFrom7To8(mozIStorageConnection* aConnection)
 {
   AssertIsOnIOThread();
   MOZ_ASSERT(aConnection);
 
-  AUTO_PROFILER_LABEL("UpgradeSchemaFrom7To8", STORAGE);
+  AUTO_PROFILER_LABEL("UpgradeSchemaFrom7To8", DOM);
 
   nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "CREATE TEMPORARY TABLE temp_upgrade ("
       "id, "
       "object_store_id, "
       "name, "
       "key_path, "
       "unique_index, "
@@ -1941,17 +1941,17 @@ private:
 
   NS_IMETHOD
   OnFunctionCall(mozIStorageValueArray* aArguments,
                  nsIVariant** aResult) override
   {
     MOZ_ASSERT(aArguments);
     MOZ_ASSERT(aResult);
 
-    AUTO_PROFILER_LABEL("CompressDataBlobsFunction::OnFunctionCall", STORAGE);
+    AUTO_PROFILER_LABEL("CompressDataBlobsFunction::OnFunctionCall", DOM);
 
     uint32_t argc;
     nsresult rv = aArguments->GetNumEntries(&argc);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     if (argc != 1) {
@@ -2000,17 +2000,17 @@ private:
 };
 
 nsresult
 UpgradeSchemaFrom8To9_0(mozIStorageConnection* aConnection)
 {
   AssertIsOnIOThread();
   MOZ_ASSERT(aConnection);
 
-  AUTO_PROFILER_LABEL("UpgradeSchemaFrom8To9_0", STORAGE);
+  AUTO_PROFILER_LABEL("UpgradeSchemaFrom8To9_0", DOM);
 
   // We no longer use the dataVersion column.
   nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "UPDATE database SET dataVersion = 0;"
   ));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
@@ -2053,17 +2053,17 @@ UpgradeSchemaFrom8To9_0(mozIStorageConne
 }
 
 nsresult
 UpgradeSchemaFrom9_0To10_0(mozIStorageConnection* aConnection)
 {
   AssertIsOnIOThread();
   MOZ_ASSERT(aConnection);
 
-  AUTO_PROFILER_LABEL("UpgradeSchemaFrom9_0To10_0", STORAGE);
+  AUTO_PROFILER_LABEL("UpgradeSchemaFrom9_0To10_0", DOM);
 
   nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "ALTER TABLE object_data ADD COLUMN file_ids TEXT;"
   ));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
@@ -2088,17 +2088,17 @@ UpgradeSchemaFrom9_0To10_0(mozIStorageCo
 }
 
 nsresult
 UpgradeSchemaFrom10_0To11_0(mozIStorageConnection* aConnection)
 {
   AssertIsOnIOThread();
   MOZ_ASSERT(aConnection);
 
-  AUTO_PROFILER_LABEL("UpgradeSchemaFrom10_0To11_0", STORAGE);
+  AUTO_PROFILER_LABEL("UpgradeSchemaFrom10_0To11_0", DOM);
 
   nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "CREATE TEMPORARY TABLE temp_upgrade ("
       "id, "
       "object_store_id, "
       "name, "
       "key_path, "
       "unique_index, "
@@ -2266,17 +2266,17 @@ private:
 
   NS_IMETHOD
   OnFunctionCall(mozIStorageValueArray* aArguments,
                  nsIVariant** aResult) override
   {
     MOZ_ASSERT(aArguments);
     MOZ_ASSERT(aResult);
 
-    AUTO_PROFILER_LABEL("EncodeKeysFunction::OnFunctionCall", STORAGE);
+    AUTO_PROFILER_LABEL("EncodeKeysFunction::OnFunctionCall", DOM);
 
     uint32_t argc;
     nsresult rv = aArguments->GetNumEntries(&argc);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     if (argc != 1) {
@@ -2317,17 +2317,17 @@ private:
 };
 
 nsresult
 UpgradeSchemaFrom11_0To12_0(mozIStorageConnection* aConnection)
 {
   AssertIsOnIOThread();
   MOZ_ASSERT(aConnection);
 
-  AUTO_PROFILER_LABEL("UpgradeSchemaFrom11_0To12_0", STORAGE);
+  AUTO_PROFILER_LABEL("UpgradeSchemaFrom11_0To12_0", DOM);
 
   NS_NAMED_LITERAL_CSTRING(encoderName, "encode");
 
   nsCOMPtr<mozIStorageFunction> encoder = new EncodeKeysFunction();
 
   nsresult rv = aConnection->CreateFunction(encoderName, 1, encoder);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
@@ -2586,17 +2586,17 @@ UpgradeSchemaFrom11_0To12_0(mozIStorageC
 
 nsresult
 UpgradeSchemaFrom12_0To13_0(mozIStorageConnection* aConnection,
                             bool* aVacuumNeeded)
 {
   AssertIsOnIOThread();
   MOZ_ASSERT(aConnection);
 
-  AUTO_PROFILER_LABEL("UpgradeSchemaFrom12_0To13_0", STORAGE);
+  AUTO_PROFILER_LABEL("UpgradeSchemaFrom12_0To13_0", DOM);
 
   nsresult rv;
 
 #ifdef IDB_MOBILE
   int32_t defaultPageSize;
   rv = aConnection->GetDefaultPageSize(&defaultPageSize);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
@@ -3572,29 +3572,29 @@ UpgradeSchemaFrom17_0To18_0Helper::DoUpg
 
 nsresult
 UpgradeSchemaFrom17_0To18_0(mozIStorageConnection* aConnection,
                             const nsACString& aOrigin)
 {
   MOZ_ASSERT(aConnection);
   MOZ_ASSERT(!aOrigin.IsEmpty());
 
-  AUTO_PROFILER_LABEL("UpgradeSchemaFrom17_0To18_0", STORAGE);
+  AUTO_PROFILER_LABEL("UpgradeSchemaFrom17_0To18_0", DOM);
 
   return UpgradeSchemaFrom17_0To18_0Helper::DoUpgrade(aConnection, aOrigin);
 }
 
 nsresult
 UpgradeSchemaFrom18_0To19_0(mozIStorageConnection* aConnection)
 {
   AssertIsOnIOThread();
   MOZ_ASSERT(aConnection);
 
   nsresult rv;
-  AUTO_PROFILER_LABEL("UpgradeSchemaFrom18_0To19_0", STORAGE);
+  AUTO_PROFILER_LABEL("UpgradeSchemaFrom18_0To19_0", DOM);
 
   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "ALTER TABLE object_store_index "
     "ADD COLUMN locale TEXT;"
   ));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
@@ -3683,17 +3683,17 @@ private:
 
 nsresult
 UpgradeSchemaFrom19_0To20_0(nsIFile* aFMDirectory,
                             mozIStorageConnection* aConnection)
 {
   AssertIsOnIOThread();
   MOZ_ASSERT(aConnection);
 
-  AUTO_PROFILER_LABEL("UpgradeSchemaFrom19_0To20_0", STORAGE);
+  AUTO_PROFILER_LABEL("UpgradeSchemaFrom19_0To20_0", DOM);
 
   nsCOMPtr<mozIStorageStatement> stmt;
   nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
     "SELECT count(*) "
     "FROM object_data "
     "WHERE file_ids IS NOT NULL"
   ), getter_AddRefs(stmt));
   if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -3899,17 +3899,17 @@ UpgradeIndexDataValuesFunction::ReadOldC
 NS_IMETHODIMP
 UpgradeIndexDataValuesFunction::OnFunctionCall(mozIStorageValueArray* aArguments,
                                                nsIVariant** aResult)
 {
   MOZ_ASSERT(aArguments);
   MOZ_ASSERT(aResult);
 
   AUTO_PROFILER_LABEL(
-    "UpgradeIndexDataValuesFunction::OnFunctionCall", STORAGE);
+    "UpgradeIndexDataValuesFunction::OnFunctionCall", DOM);
 
   uint32_t argc;
   nsresult rv = aArguments->GetNumEntries(&argc);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   if (argc != 1) {
@@ -3958,17 +3958,17 @@ UpgradeSchemaFrom20_0To21_0(mozIStorageC
 {
   // This should have been part of the 18 to 19 upgrade, where we changed the
   // layout of the index_data_values blobs but didn't upgrade the existing data.
   // See bug 1202788.
 
   AssertIsOnIOThread();
   MOZ_ASSERT(aConnection);
 
-  AUTO_PROFILER_LABEL("UpgradeSchemaFrom20_0To21_0", STORAGE);
+  AUTO_PROFILER_LABEL("UpgradeSchemaFrom20_0To21_0", DOM);
 
   RefPtr<UpgradeIndexDataValuesFunction> function =
     new UpgradeIndexDataValuesFunction();
 
   NS_NAMED_LITERAL_CSTRING(functionName, "upgrade_idv");
 
   nsresult rv = aConnection->CreateFunction(functionName, 1, function);
   if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -4013,17 +4013,17 @@ UpgradeSchemaFrom21_0To22_0(mozIStorageC
 nsresult
 UpgradeSchemaFrom22_0To23_0(mozIStorageConnection* aConnection,
                             const nsACString& aOrigin)
 {
   AssertIsOnIOThread();
   MOZ_ASSERT(aConnection);
   MOZ_ASSERT(!aOrigin.IsEmpty());
 
-  AUTO_PROFILER_LABEL("UpgradeSchemaFrom22_0To23_0", STORAGE);
+  AUTO_PROFILER_LABEL("UpgradeSchemaFrom22_0To23_0", DOM);
 
   nsCOMPtr<mozIStorageStatement> stmt;
   nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
     "UPDATE database "
       "SET origin = :origin;"
   ), getter_AddRefs(stmt));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
@@ -4087,17 +4087,17 @@ private:
   NS_IMETHOD
   OnFunctionCall(mozIStorageValueArray* aArguments,
                  nsIVariant** aResult) override
   {
     MOZ_ASSERT(aArguments);
     MOZ_ASSERT(aResult);
 
     AUTO_PROFILER_LABEL(
-      "StripObsoleteOriginAttributesFunction::OnFunctionCall", STORAGE);
+      "StripObsoleteOriginAttributesFunction::OnFunctionCall", DOM);
 
 #ifdef DEBUG
   {
     uint32_t argCount;
     MOZ_ALWAYS_SUCCEEDS(aArguments->GetNumEntries(&argCount));
     MOZ_ASSERT(argCount == 1);
 
     int32_t type;
@@ -4134,17 +4134,17 @@ private:
 };
 
 nsresult
 UpgradeSchemaFrom25_0To26_0(mozIStorageConnection* aConnection)
 {
   AssertIsOnIOThread();
   MOZ_ASSERT(aConnection);
 
-  AUTO_PROFILER_LABEL("UpgradeSchemaFrom25_0To26_0", STORAGE);
+  AUTO_PROFILER_LABEL("UpgradeSchemaFrom25_0To26_0", DOM);
 
   NS_NAMED_LITERAL_CSTRING(functionName, "strip_obsolete_attributes");
 
   nsCOMPtr<mozIStorageFunction> stripObsoleteAttributes =
     new StripObsoleteOriginAttributesFunction();
 
   nsresult rv = aConnection->CreateFunction(functionName,
                                             /* aNumArguments */ 1,
@@ -4477,17 +4477,17 @@ CreateStorageConnection(nsIFile* aDBFile
                         uint32_t aTelemetryId,
                         mozIStorageConnection** aConnection)
 {
   AssertIsOnIOThread();
   MOZ_ASSERT(aDBFile);
   MOZ_ASSERT(aFMDirectory);
   MOZ_ASSERT(aConnection);
 
-  AUTO_PROFILER_LABEL("CreateStorageConnection", STORAGE);
+  AUTO_PROFILER_LABEL("CreateStorageConnection", DOM);
 
   nsresult rv;
   bool exists;
 
   if (IndexedDatabaseManager::InLowDiskSpaceMode()) {
     rv = aDBFile->Exists(&exists);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
@@ -4942,17 +4942,17 @@ GetStorageConnection(nsIFile* aDatabaseF
                      uint32_t aTelemetryId,
                      mozIStorageConnection** aConnection)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(!IsOnBackgroundThread());
   MOZ_ASSERT(aDatabaseFile);
   MOZ_ASSERT(aConnection);
 
-  AUTO_PROFILER_LABEL("GetStorageConnection", STORAGE);
+  AUTO_PROFILER_LABEL("GetStorageConnection", DOM);
 
   bool exists;
   nsresult rv = aDatabaseFile->Exists(&exists);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   if (NS_WARN_IF(!exists)) {
@@ -10520,17 +10520,17 @@ nsresult
 DatabaseConnection::GetCachedStatement(const nsACString& aQuery,
                                        CachedStatement* aCachedStatement)
 {
   AssertIsOnConnectionThread();
   MOZ_ASSERT(!aQuery.IsEmpty());
   MOZ_ASSERT(aCachedStatement);
   MOZ_ASSERT(mStorageConnection);
 
-  AUTO_PROFILER_LABEL("DatabaseConnection::GetCachedStatement", STORAGE);
+  AUTO_PROFILER_LABEL("DatabaseConnection::GetCachedStatement", DOM);
 
   nsCOMPtr<mozIStorageStatement> stmt;
 
   if (!mCachedStatements.Get(aQuery, getter_AddRefs(stmt))) {
     nsresult rv =
       mStorageConnection->CreateStatement(aQuery, getter_AddRefs(stmt));
     if (NS_FAILED(rv)) {
 #ifdef DEBUG
@@ -10557,17 +10557,17 @@ DatabaseConnection::GetCachedStatement(c
 nsresult
 DatabaseConnection::BeginWriteTransaction()
 {
   AssertIsOnConnectionThread();
   MOZ_ASSERT(mStorageConnection);
   MOZ_ASSERT(mInReadTransaction);
   MOZ_ASSERT(!mInWriteTransaction);
 
-  AUTO_PROFILER_LABEL("DatabaseConnection::BeginWriteTransaction", STORAGE);
+  AUTO_PROFILER_LABEL("DatabaseConnection::BeginWriteTransaction", DOM);
 
   // Release our read locks.
   CachedStatement rollbackStmt;
   nsresult rv =
     GetCachedStatement(NS_LITERAL_CSTRING("ROLLBACK;"), &rollbackStmt);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
@@ -10634,17 +10634,17 @@ DatabaseConnection::BeginWriteTransactio
 nsresult
 DatabaseConnection::CommitWriteTransaction()
 {
   AssertIsOnConnectionThread();
   MOZ_ASSERT(mStorageConnection);
   MOZ_ASSERT(!mInReadTransaction);
   MOZ_ASSERT(mInWriteTransaction);
 
-  AUTO_PROFILER_LABEL("DatabaseConnection::CommitWriteTransaction", STORAGE);
+  AUTO_PROFILER_LABEL("DatabaseConnection::CommitWriteTransaction", DOM);
 
   CachedStatement stmt;
   nsresult rv = GetCachedStatement(NS_LITERAL_CSTRING("COMMIT;"), &stmt);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   rv = stmt->Execute();
@@ -10658,17 +10658,17 @@ DatabaseConnection::CommitWriteTransacti
 
 void
 DatabaseConnection::RollbackWriteTransaction()
 {
   AssertIsOnConnectionThread();
   MOZ_ASSERT(!mInReadTransaction);
   MOZ_ASSERT(mStorageConnection);
 
-  AUTO_PROFILER_LABEL("DatabaseConnection::RollbackWriteTransaction", STORAGE);
+  AUTO_PROFILER_LABEL("DatabaseConnection::RollbackWriteTransaction", DOM);
 
   if (!mInWriteTransaction) {
     return;
   }
 
   DatabaseConnection::CachedStatement stmt;
   nsresult rv = GetCachedStatement(NS_LITERAL_CSTRING("ROLLBACK;"), &stmt);
   if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -10685,17 +10685,17 @@ DatabaseConnection::RollbackWriteTransac
 void
 DatabaseConnection::FinishWriteTransaction()
 {
   AssertIsOnConnectionThread();
   MOZ_ASSERT(mStorageConnection);
   MOZ_ASSERT(!mInReadTransaction);
   MOZ_ASSERT(!mInWriteTransaction);
 
-  AUTO_PROFILER_LABEL("DatabaseConnection::FinishWriteTransaction", STORAGE);
+  AUTO_PROFILER_LABEL("DatabaseConnection::FinishWriteTransaction", DOM);
 
   if (mUpdateRefcountFunction) {
     mUpdateRefcountFunction->Reset();
   }
 
   CachedStatement stmt;
   nsresult rv = GetCachedStatement(NS_LITERAL_CSTRING("BEGIN;"), &stmt);
   if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -10713,17 +10713,17 @@ DatabaseConnection::FinishWriteTransacti
 nsresult
 DatabaseConnection::StartSavepoint()
 {
   AssertIsOnConnectionThread();
   MOZ_ASSERT(mStorageConnection);
   MOZ_ASSERT(mUpdateRefcountFunction);
   MOZ_ASSERT(mInWriteTransaction);
 
-  AUTO_PROFILER_LABEL("DatabaseConnection::StartSavepoint", STORAGE);
+  AUTO_PROFILER_LABEL("DatabaseConnection::StartSavepoint", DOM);
 
   CachedStatement stmt;
   nsresult rv = GetCachedStatement(NS_LITERAL_CSTRING(SAVEPOINT_CLAUSE), &stmt);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   rv = stmt->Execute();
@@ -10744,17 +10744,17 @@ DatabaseConnection::StartSavepoint()
 nsresult
 DatabaseConnection::ReleaseSavepoint()
 {
   AssertIsOnConnectionThread();
   MOZ_ASSERT(mStorageConnection);
   MOZ_ASSERT(mUpdateRefcountFunction);
   MOZ_ASSERT(mInWriteTransaction);
 
-  AUTO_PROFILER_LABEL("DatabaseConnection::ReleaseSavepoint", STORAGE);
+  AUTO_PROFILER_LABEL("DatabaseConnection::ReleaseSavepoint", DOM);
 
   CachedStatement stmt;
   nsresult rv = GetCachedStatement(
     NS_LITERAL_CSTRING("RELEASE " SAVEPOINT_CLAUSE),
     &stmt);
   if (NS_SUCCEEDED(rv)) {
     rv = stmt->Execute();
     if (NS_SUCCEEDED(rv)) {
@@ -10773,17 +10773,17 @@ DatabaseConnection::ReleaseSavepoint()
 nsresult
 DatabaseConnection::RollbackSavepoint()
 {
   AssertIsOnConnectionThread();
   MOZ_ASSERT(mStorageConnection);
   MOZ_ASSERT(mUpdateRefcountFunction);
   MOZ_ASSERT(mInWriteTransaction);
 
-  AUTO_PROFILER_LABEL("DatabaseConnection::RollbackSavepoint", STORAGE);
+  AUTO_PROFILER_LABEL("DatabaseConnection::RollbackSavepoint", DOM);
 
 #ifdef DEBUG
   MOZ_ASSERT(mDEBUGSavepointCount);
   mDEBUGSavepointCount--;
 #endif
 
   mUpdateRefcountFunction->RollbackSavepoint();
 
@@ -10804,17 +10804,17 @@ DatabaseConnection::RollbackSavepoint()
 
 nsresult
 DatabaseConnection::CheckpointInternal(CheckpointMode aMode)
 {
   AssertIsOnConnectionThread();
   MOZ_ASSERT(!mInReadTransaction);
   MOZ_ASSERT(!mInWriteTransaction);
 
-  AUTO_PROFILER_LABEL("DatabaseConnection::CheckpointInternal", STORAGE);
+  AUTO_PROFILER_LABEL("DatabaseConnection::CheckpointInternal", DOM);
 
   nsAutoCString stmtString;
   stmtString.AssignLiteral("PRAGMA wal_checkpoint(");
 
   switch (aMode) {
     case CheckpointMode::Full:
       // Ensures that the database is completely checkpointed and flushed to
       // disk.
@@ -10854,17 +10854,17 @@ DatabaseConnection::CheckpointInternal(C
 
 void
 DatabaseConnection::DoIdleProcessing(bool aNeedsCheckpoint)
 {
   AssertIsOnConnectionThread();
   MOZ_ASSERT(mInReadTransaction);
   MOZ_ASSERT(!mInWriteTransaction);
 
-  AUTO_PROFILER_LABEL("DatabaseConnection::DoIdleProcessing", STORAGE);
+  AUTO_PROFILER_LABEL("DatabaseConnection::DoIdleProcessing", DOM);
 
   DatabaseConnection::CachedStatement freelistStmt;
   uint32_t freelistCount;
   nsresult rv = GetFreelistCount(freelistStmt, &freelistCount);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     freelistCount = 0;
   }
 
@@ -10933,17 +10933,17 @@ DatabaseConnection::ReclaimFreePagesWhil
   AssertIsOnConnectionThread();
   MOZ_ASSERT(aFreelistStatement);
   MOZ_ASSERT(aRollbackStatement);
   MOZ_ASSERT(aFreelistCount);
   MOZ_ASSERT(aFreedSomePages);
   MOZ_ASSERT(!mInReadTransaction);
   MOZ_ASSERT(!mInWriteTransaction);
 
-  AUTO_PROFILER_LABEL("DatabaseConnection::ReclaimFreePagesWhileIdle", STORAGE);
+  AUTO_PROFILER_LABEL("DatabaseConnection::ReclaimFreePagesWhileIdle", DOM);
 
   // Make sure we don't keep working if anything else needs this thread.
   nsIThread* currentThread = NS_GetCurrentThread();
   MOZ_ASSERT(currentThread);
 
   if (NS_HasPendingEvents(currentThread)) {
     *aFreedSomePages = false;
     return NS_OK;
@@ -11045,17 +11045,17 @@ DatabaseConnection::ReclaimFreePagesWhil
 
 nsresult
 DatabaseConnection::GetFreelistCount(CachedStatement& aCachedStatement,
                                      uint32_t* aFreelistCount)
 {
   AssertIsOnConnectionThread();
   MOZ_ASSERT(aFreelistCount);
 
-  AUTO_PROFILER_LABEL("DatabaseConnection::GetFreelistCount", STORAGE);
+  AUTO_PROFILER_LABEL("DatabaseConnection::GetFreelistCount", DOM);
 
   nsresult rv;
 
   if (!aCachedStatement) {
     rv = GetCachedStatement(NS_LITERAL_CSTRING("PRAGMA freelist_count;"),
                             &aCachedStatement);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
@@ -11089,17 +11089,17 @@ DatabaseConnection::GetFreelistCount(Cac
 void
 DatabaseConnection::Close()
 {
   AssertIsOnConnectionThread();
   MOZ_ASSERT(mStorageConnection);
   MOZ_ASSERT(!mDEBUGSavepointCount);
   MOZ_ASSERT(!mInWriteTransaction);
 
-  AUTO_PROFILER_LABEL("DatabaseConnection::Close", STORAGE);
+  AUTO_PROFILER_LABEL("DatabaseConnection::Close", DOM);
 
   if (mUpdateRefcountFunction) {
     MOZ_ALWAYS_SUCCEEDS(
       mStorageConnection->RemoveFunction(
         NS_LITERAL_CSTRING("update_refcount")));
     mUpdateRefcountFunction = nullptr;
   }
 
@@ -11374,17 +11374,17 @@ UpdateRefcountFunction::UpdateRefcountFu
 
 nsresult
 DatabaseConnection::
 UpdateRefcountFunction::WillCommit()
 {
   MOZ_ASSERT(mConnection);
   mConnection->AssertIsOnConnectionThread();
 
-  AUTO_PROFILER_LABEL("DatabaseConnection::UpdateRefcountFunction::WillCommit", STORAGE);
+  AUTO_PROFILER_LABEL("DatabaseConnection::UpdateRefcountFunction::WillCommit", DOM);
 
   DatabaseUpdateFunction function(this);
   for (auto iter = mFileInfoEntries.ConstIter(); !iter.Done(); iter.Next()) {
     auto key = iter.Key();
     FileInfoEntry* value = iter.Data();
     MOZ_ASSERT(value);
 
     if (value->mDelta && !function.Update(key, value->mDelta)) {
@@ -11408,17 +11408,17 @@ UpdateRefcountFunction::WillCommit()
 void
 DatabaseConnection::
 UpdateRefcountFunction::DidCommit()
 {
   MOZ_ASSERT(mConnection);
   mConnection->AssertIsOnConnectionThread();
 
   AUTO_PROFILER_LABEL(
-    "DatabaseConnection::UpdateRefcountFunction::DidCommit", STORAGE);
+    "DatabaseConnection::UpdateRefcountFunction::DidCommit", DOM);
 
   for (auto iter = mFileInfoEntries.ConstIter(); !iter.Done(); iter.Next()) {
     FileInfoEntry* value = iter.Data();
 
     MOZ_ASSERT(value);
 
     if (value->mDelta) {
       value->mFileInfo->UpdateDBRefs(value->mDelta);
@@ -11433,17 +11433,17 @@ UpdateRefcountFunction::DidCommit()
 void
 DatabaseConnection::
 UpdateRefcountFunction::DidAbort()
 {
   MOZ_ASSERT(mConnection);
   mConnection->AssertIsOnConnectionThread();
 
   AUTO_PROFILER_LABEL(
-    "DatabaseConnection::UpdateRefcountFunction::DidAbort", STORAGE);
+    "DatabaseConnection::UpdateRefcountFunction::DidAbort", DOM);
 
   if (NS_FAILED(RemoveJournals(mJournalsToRemoveAfterAbort))) {
     NS_WARNING("RemoveJournals failed!");
   }
 }
 
 void
 DatabaseConnection::
@@ -11594,17 +11594,17 @@ UpdateRefcountFunction::ProcessValue(moz
                                      int32_t aIndex,
                                      UpdateType aUpdateType)
 {
   MOZ_ASSERT(mConnection);
   mConnection->AssertIsOnConnectionThread();
   MOZ_ASSERT(aValues);
 
   AUTO_PROFILER_LABEL(
-    "DatabaseConnection::UpdateRefcountFunction::ProcessValue", STORAGE);
+    "DatabaseConnection::UpdateRefcountFunction::ProcessValue", DOM);
 
   int32_t type;
   nsresult rv = aValues->GetTypeOfIndex(aIndex, &type);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   if (type == mozIStorageValueArray::VALUE_TYPE_NULL) {
@@ -11663,17 +11663,17 @@ UpdateRefcountFunction::ProcessValue(moz
 nsresult
 DatabaseConnection::
 UpdateRefcountFunction::CreateJournals()
 {
   MOZ_ASSERT(mConnection);
   mConnection->AssertIsOnConnectionThread();
 
   AUTO_PROFILER_LABEL(
-    "DatabaseConnection::UpdateRefcountFunction::CreateJournals", STORAGE);
+    "DatabaseConnection::UpdateRefcountFunction::CreateJournals", DOM);
 
   nsCOMPtr<nsIFile> journalDirectory = mFileManager->GetJournalDirectory();
   if (NS_WARN_IF(!journalDirectory)) {
     return NS_ERROR_FAILURE;
   }
 
   for (uint32_t i = 0; i < mJournalsToCreateBeforeCommit.Length(); i++) {
     int64_t id = mJournalsToCreateBeforeCommit[i];
@@ -11698,17 +11698,17 @@ UpdateRefcountFunction::CreateJournals()
 nsresult
 DatabaseConnection::
 UpdateRefcountFunction::RemoveJournals(const nsTArray<int64_t>& aJournals)
 {
   MOZ_ASSERT(mConnection);
   mConnection->AssertIsOnConnectionThread();
 
   AUTO_PROFILER_LABEL(
-    "DatabaseConnection::UpdateRefcountFunction::RemoveJournals", STORAGE);
+    "DatabaseConnection::UpdateRefcountFunction::RemoveJournals", DOM);
 
   nsCOMPtr<nsIFile> journalDirectory = mFileManager->GetJournalDirectory();
   if (NS_WARN_IF(!journalDirectory)) {
     return NS_ERROR_FAILURE;
   }
 
   for (uint32_t index = 0; index < aJournals.Length(); index++) {
     nsCOMPtr<nsIFile> file =
@@ -11732,17 +11732,17 @@ NS_IMETHODIMP
 DatabaseConnection::
 UpdateRefcountFunction::OnFunctionCall(mozIStorageValueArray* aValues,
                                        nsIVariant** _retval)
 {
   MOZ_ASSERT(aValues);
   MOZ_ASSERT(_retval);
 
   AUTO_PROFILER_LABEL(
-    "DatabaseConnection::UpdateRefcountFunction::OnFunctionCall", STORAGE);
+    "DatabaseConnection::UpdateRefcountFunction::OnFunctionCall", DOM);
 
   uint32_t numEntries;
   nsresult rv = aValues->GetNumEntries(&numEntries);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   MOZ_ASSERT(numEntries == 2);
@@ -11792,17 +11792,17 @@ DatabaseConnection::UpdateRefcountFuncti
 DatabaseUpdateFunction::UpdateInternal(int64_t aId,
                                        int32_t aDelta)
 {
   MOZ_ASSERT(mFunction);
 
   AUTO_PROFILER_LABEL(
     "DatabaseConnection::UpdateRefcountFunction::"
     "DatabaseUpdateFunction::UpdateInternal",
-    STORAGE);
+    DOM);
 
   DatabaseConnection* connection = mFunction->mConnection;
   MOZ_ASSERT(connection);
   connection->AssertIsOnConnectionThread();
 
   MOZ_ASSERT(connection->GetStorageConnection());
 
   nsresult rv;
@@ -11939,17 +11939,17 @@ ConnectionPool::~ConnectionPool()
 }
 
 // static
 void
 ConnectionPool::IdleTimerCallback(nsITimer* aTimer, void* aClosure)
 {
   MOZ_ASSERT(aTimer);
 
-  AUTO_PROFILER_LABEL("ConnectionPool::IdleTimerCallback", STORAGE);
+  AUTO_PROFILER_LABEL("ConnectionPool::IdleTimerCallback", DOM);
 
   auto* self = static_cast<ConnectionPool*>(aClosure);
   MOZ_ASSERT(self);
   MOZ_ASSERT(self->mIdleTimer);
   MOZ_ASSERT(SameCOMIdentity(self->mIdleTimer, aTimer));
   MOZ_ASSERT(!self->mTargetIdleTime.IsNull());
   MOZ_ASSERT_IF(self->mIdleDatabases.IsEmpty(), !self->mIdleThreads.IsEmpty());
   MOZ_ASSERT_IF(self->mIdleThreads.IsEmpty(), !self->mIdleDatabases.IsEmpty());
@@ -12003,17 +12003,17 @@ ConnectionPool::IdleTimerCallback(nsITim
 nsresult
 ConnectionPool::GetOrCreateConnection(const Database* aDatabase,
                                       DatabaseConnection** aConnection)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(!IsOnBackgroundThread());
   MOZ_ASSERT(aDatabase);
 
-  AUTO_PROFILER_LABEL("ConnectionPool::GetOrCreateConnection", STORAGE);
+  AUTO_PROFILER_LABEL("ConnectionPool::GetOrCreateConnection", DOM);
 
   DatabaseInfo* dbInfo;
   {
     MutexAutoLock lock(mDatabasesMutex);
 
     dbInfo = mDatabases.Get(aDatabase->Id());
   }
 
@@ -12068,17 +12068,17 @@ ConnectionPool::Start(const nsID& aBackg
                       bool aIsWriteTransaction,
                       TransactionDatabaseOperationBase* aTransactionOp)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(!aDatabaseId.IsEmpty());
   MOZ_ASSERT(mNextTransactionId < UINT64_MAX);
   MOZ_ASSERT(!mShutdownRequested);
 
-  AUTO_PROFILER_LABEL("ConnectionPool::Start", STORAGE);
+  AUTO_PROFILER_LABEL("ConnectionPool::Start", DOM);
 
   const uint64_t transactionId = ++mNextTransactionId;
 
   DatabaseInfo* dbInfo = mDatabases.Get(aDatabaseId);
 
   const bool databaseInfoIsNew = !dbInfo;
 
   if (databaseInfoIsNew) {
@@ -12163,17 +12163,17 @@ ConnectionPool::Start(const nsID& aBackg
 }
 
 void
 ConnectionPool::Dispatch(uint64_t aTransactionId, nsIRunnable* aRunnable)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aRunnable);
 
-  AUTO_PROFILER_LABEL("ConnectionPool::Dispatch", STORAGE);
+  AUTO_PROFILER_LABEL("ConnectionPool::Dispatch", DOM);
 
   TransactionInfo* transactionInfo = mTransactions.Get(aTransactionId);
   MOZ_ASSERT(transactionInfo);
   MOZ_ASSERT(!transactionInfo->mFinished);
 
   if (transactionInfo->mRunning) {
     DatabaseInfo* dbInfo = transactionInfo->mDatabaseInfo;
     MOZ_ASSERT(dbInfo);
@@ -12196,17 +12196,17 @@ ConnectionPool::Finish(uint64_t aTransac
   AssertIsOnOwningThread();
 
 #ifdef DEBUG
   TransactionInfo* transactionInfo = mTransactions.Get(aTransactionId);
   MOZ_ASSERT(transactionInfo);
   MOZ_ASSERT(!transactionInfo->mFinished);
 #endif
 
-  AUTO_PROFILER_LABEL("ConnectionPool::Finish", STORAGE);
+  AUTO_PROFILER_LABEL("ConnectionPool::Finish", DOM);
 
   RefPtr<FinishCallbackWrapper> wrapper =
     new FinishCallbackWrapper(this, aTransactionId, aCallback);
 
   Dispatch(aTransactionId, wrapper);
 
 #ifdef DEBUG
   MOZ_ASSERT(!transactionInfo->mFinished);
@@ -12217,17 +12217,17 @@ ConnectionPool::Finish(uint64_t aTransac
 void
 ConnectionPool::WaitForDatabasesToComplete(nsTArray<nsCString>&& aDatabaseIds,
                                            nsIRunnable* aCallback)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(!aDatabaseIds.IsEmpty());
   MOZ_ASSERT(aCallback);
 
-  AUTO_PROFILER_LABEL("ConnectionPool::WaitForDatabasesToComplete", STORAGE);
+  AUTO_PROFILER_LABEL("ConnectionPool::WaitForDatabasesToComplete", DOM);
 
   bool mayRunCallbackImmediately = true;
 
   for (uint32_t index = 0, count = aDatabaseIds.Length();
        index < count;
        index++) {
     const nsCString& databaseId = aDatabaseIds[index];
     MOZ_ASSERT(!databaseId.IsEmpty());
@@ -12249,17 +12249,17 @@ ConnectionPool::WaitForDatabasesToComple
 
 void
 ConnectionPool::Shutdown()
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(!mShutdownRequested);
   MOZ_ASSERT(!mShutdownComplete);
 
-  AUTO_PROFILER_LABEL("ConnectionPool::Shutdown", STORAGE);
+  AUTO_PROFILER_LABEL("ConnectionPool::Shutdown", DOM);
 
   mShutdownRequested = true;
 
   CancelIdleTimer();
   MOZ_ASSERT(mTargetIdleTime.IsNull());
 
   mIdleTimer = nullptr;
 
@@ -12284,17 +12284,17 @@ ConnectionPool::Cleanup()
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mShutdownRequested);
   MOZ_ASSERT(!mShutdownComplete);
   MOZ_ASSERT(!mDatabases.Count());
   MOZ_ASSERT(!mTransactions.Count());
   MOZ_ASSERT(mIdleThreads.IsEmpty());
 
-  AUTO_PROFILER_LABEL("ConnectionPool::Cleanup", STORAGE);
+  AUTO_PROFILER_LABEL("ConnectionPool::Cleanup", DOM);
 
   if (!mCompleteCallbacks.IsEmpty()) {
     // Run all callbacks manually now.
     for (uint32_t count = mCompleteCallbacks.Length(), index = 0;
          index < count;
          index++) {
       nsAutoPtr<DatabasesCompleteCallback> completeCallback(
         mCompleteCallbacks[index].forget());
@@ -12317,17 +12317,17 @@ ConnectionPool::Cleanup()
 }
 
 void
 ConnectionPool::AdjustIdleTimer()
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mIdleTimer);
 
-  AUTO_PROFILER_LABEL("ConnectionPool::AdjustIdleTimer", STORAGE);
+  AUTO_PROFILER_LABEL("ConnectionPool::AdjustIdleTimer", DOM);
 
   // Figure out the next time at which we should release idle resources. This
   // includes both databases and threads.
   TimeStamp newTargetIdleTime;
   MOZ_ASSERT(newTargetIdleTime.IsNull());
 
   if (!mIdleDatabases.IsEmpty()) {
     newTargetIdleTime = mIdleDatabases[0].mIdleTime;
@@ -12417,17 +12417,17 @@ ConnectionPool::ShutdownThread(ThreadInf
 }
 
 void
 ConnectionPool::CloseIdleDatabases()
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mShutdownRequested);
 
-  AUTO_PROFILER_LABEL("ConnectionPool::CloseIdleDatabases", STORAGE);
+  AUTO_PROFILER_LABEL("ConnectionPool::CloseIdleDatabases", DOM);
 
   if (!mIdleDatabases.IsEmpty()) {
     for (IdleDatabaseInfo& idleInfo : mIdleDatabases) {
       CloseDatabase(idleInfo.mDatabaseInfo);
     }
     mIdleDatabases.Clear();
   }
 
@@ -12441,17 +12441,17 @@ ConnectionPool::CloseIdleDatabases()
 }
 
 void
 ConnectionPool::ShutdownIdleThreads()
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mShutdownRequested);
 
-  AUTO_PROFILER_LABEL("ConnectionPool::ShutdownIdleThreads", STORAGE);
+  AUTO_PROFILER_LABEL("ConnectionPool::ShutdownIdleThreads", DOM);
 
   if (!mIdleThreads.IsEmpty()) {
     for (uint32_t threadCount = mIdleThreads.Length(), threadIndex = 0;
          threadIndex < threadCount;
          threadIndex++) {
       ShutdownThread(mIdleThreads[threadIndex].mThreadInfo);
     }
     mIdleThreads.Clear();
@@ -12460,17 +12460,17 @@ ConnectionPool::ShutdownIdleThreads()
 
 bool
 ConnectionPool::ScheduleTransaction(TransactionInfo* aTransactionInfo,
                                     bool aFromQueuedTransactions)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aTransactionInfo);
 
-  AUTO_PROFILER_LABEL("ConnectionPool::ScheduleTransaction", STORAGE);
+  AUTO_PROFILER_LABEL("ConnectionPool::ScheduleTransaction", DOM);
 
   DatabaseInfo* dbInfo = aTransactionInfo->mDatabaseInfo;
   MOZ_ASSERT(dbInfo);
 
   dbInfo->mIdle = false;
 
   if (dbInfo->mClosing) {
     MOZ_ASSERT(!mIdleDatabases.Contains(dbInfo));
@@ -12591,17 +12591,17 @@ ConnectionPool::ScheduleTransaction(Tran
   return true;
 }
 
 void
 ConnectionPool::NoteFinishedTransaction(uint64_t aTransactionId)
 {
   AssertIsOnOwningThread();
 
-  AUTO_PROFILER_LABEL("ConnectionPool::NoteFinishedTransaction", STORAGE);
+  AUTO_PROFILER_LABEL("ConnectionPool::NoteFinishedTransaction", DOM);
 
   TransactionInfo* transactionInfo = mTransactions.Get(aTransactionId);
   MOZ_ASSERT(transactionInfo);
   MOZ_ASSERT(transactionInfo->mRunning);
   MOZ_ASSERT(transactionInfo->mFinished);
 
   transactionInfo->mRunning = false;
 
@@ -12677,17 +12677,17 @@ void
 ConnectionPool::ScheduleQueuedTransactions(ThreadInfo& aThreadInfo)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aThreadInfo.mThread);
   MOZ_ASSERT(aThreadInfo.mRunnable);
   MOZ_ASSERT(!mQueuedTransactions.IsEmpty());
   MOZ_ASSERT(!mIdleThreads.Contains(aThreadInfo));
 
-  AUTO_PROFILER_LABEL("ConnectionPool::ScheduleQueuedTransactions", STORAGE);
+  AUTO_PROFILER_LABEL("ConnectionPool::ScheduleQueuedTransactions", DOM);
 
   mIdleThreads.InsertElementSorted(aThreadInfo);
 
   aThreadInfo.mRunnable = nullptr;
   aThreadInfo.mThread = nullptr;
 
   uint32_t index = 0;
   for (uint32_t count = mQueuedTransactions.Length(); index < count; index++) {
@@ -12709,17 +12709,17 @@ ConnectionPool::NoteIdleDatabase(Databas
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aDatabaseInfo);
   MOZ_ASSERT(!aDatabaseInfo->TotalTransactionCount());
   MOZ_ASSERT(aDatabaseInfo->mThreadInfo.mThread);
   MOZ_ASSERT(aDatabaseInfo->mThreadInfo.mRunnable);
   MOZ_ASSERT(!mIdleDatabases.Contains(aDatabaseInfo));
 
-  AUTO_PROFILER_LABEL("ConnectionPool::NoteIdleDatabase", STORAGE);
+  AUTO_PROFILER_LABEL("ConnectionPool::NoteIdleDatabase", DOM);
 
   const bool otherDatabasesWaiting = !mQueuedTransactions.IsEmpty();
 
   if (mShutdownRequested ||
       otherDatabasesWaiting ||
       aDatabaseInfo->mCloseOnIdle) {
     // Make sure we close the connection if we're shutting down or giving the
     // thread to another database.
@@ -12746,17 +12746,17 @@ ConnectionPool::NoteIdleDatabase(Databas
 void
 ConnectionPool::NoteClosedDatabase(DatabaseInfo* aDatabaseInfo)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aDatabaseInfo);
   MOZ_ASSERT(aDatabaseInfo->mClosing);
   MOZ_ASSERT(!mIdleDatabases.Contains(aDatabaseInfo));
 
-  AUTO_PROFILER_LABEL("ConnectionPool::NoteClosedDatabase", STORAGE);
+  AUTO_PROFILER_LABEL("ConnectionPool::NoteClosedDatabase", DOM);
 
   aDatabaseInfo->mClosing = false;
 
   // Figure out what to do with this database's thread. It may have already been
   // given to another database, in which case there's nothing to do here.
   // Otherwise we prioritize the thread as follows:
   //   1. Databases that haven't had an opportunity to run at all are highest
   //      priority. Those live in the |mQueuedTransactions| list.
@@ -12850,17 +12850,17 @@ ConnectionPool::NoteClosedDatabase(Datab
 bool
 ConnectionPool::MaybeFireCallback(DatabasesCompleteCallback* aCallback)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aCallback);
   MOZ_ASSERT(!aCallback->mDatabaseIds.IsEmpty());
   MOZ_ASSERT(aCallback->mCallback);
 
-  AUTO_PROFILER_LABEL("ConnectionPool::MaybeFireCallback", STORAGE);
+  AUTO_PROFILER_LABEL("ConnectionPool::MaybeFireCallback", DOM);
 
   for (uint32_t count = aCallback->mDatabaseIds.Length(), index = 0;
        index < count;
        index++) {
     const nsCString& databaseId = aCallback->mDatabaseIds[index];
     MOZ_ASSERT(!databaseId.IsEmpty());
 
     if (mDatabases.Get(databaseId)) {
@@ -12921,17 +12921,17 @@ ConnectionPool::CloseDatabase(DatabaseIn
 }
 
 bool
 ConnectionPool::CloseDatabaseWhenIdleInternal(const nsACString& aDatabaseId)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(!aDatabaseId.IsEmpty());
 
-  AUTO_PROFILER_LABEL("ConnectionPool::CloseDatabaseWhenIdleInternal", STORAGE);
+  AUTO_PROFILER_LABEL("ConnectionPool::CloseDatabaseWhenIdleInternal", DOM);
 
   if (DatabaseInfo* dbInfo = mDatabases.Get(aDatabaseId)) {
     if (mIdleDatabases.RemoveElement(dbInfo) ||
         mDatabasesPerformingIdleMaintenance.RemoveElement(dbInfo)) {
       CloseDatabase(dbInfo);
       AdjustIdleTimer();
     } else {
       dbInfo->mCloseOnIdle = true;
@@ -12998,17 +12998,17 @@ IdleConnectionRunnable::Run()
 }
 
 NS_IMETHODIMP
 ConnectionPool::
 CloseConnectionRunnable::Run()
 {
   MOZ_ASSERT(mDatabaseInfo);
 
-  AUTO_PROFILER_LABEL("ConnectionPool::CloseConnectionRunnable::Run", STORAGE);
+  AUTO_PROFILER_LABEL("ConnectionPool::CloseConnectionRunnable::Run", DOM);
 
   if (mOwningEventTarget) {
     MOZ_ASSERT(mDatabaseInfo->mClosing);
 
     nsCOMPtr<nsIEventTarget> owningThread;
     mOwningEventTarget.swap(owningThread);
 
     // The connection could be null if EnsureConnection() didn't run or was not
@@ -13127,17 +13127,17 @@ FinishCallbackWrapper::~FinishCallbackWr
 nsresult
 ConnectionPool::
 FinishCallbackWrapper::Run()
 {
   MOZ_ASSERT(mConnectionPool);
   MOZ_ASSERT(mCallback);
   MOZ_ASSERT(mOwningEventTarget);
 
-  AUTO_PROFILER_LABEL("ConnectionPool::FinishCallbackWrapper::Run", STORAGE);
+  AUTO_PROFILER_LABEL("ConnectionPool::FinishCallbackWrapper::Run", DOM);
 
   if (!mHasRunOnce) {
     MOZ_ASSERT(!IsOnBackgroundThread());
 
     mHasRunOnce = true;
 
     Unused << mCallback->Run();
 
@@ -13191,17 +13191,17 @@ ThreadRunnable::Run()
     mContinueRunning = false;
     return NS_OK;
   }
 
   mFirstRun = false;
 
   {
     // Scope for the profiler label.
-    AUTO_PROFILER_LABEL("ConnectionPool::ThreadRunnable::Run", STORAGE);
+    AUTO_PROFILER_LABEL("ConnectionPool::ThreadRunnable::Run", DOM);
 
     DebugOnly<nsIThread*> currentThread = NS_GetCurrentThread();
     MOZ_ASSERT(currentThread);
 
 #ifdef DEBUG
     if (kDEBUGTransactionThreadPriority !=
           nsISupportsPriority::PRIORITY_NORMAL) {
       NS_WARNING("ConnectionPool thread debugging enabled, priority has been "
@@ -13999,17 +13999,17 @@ Database::Invalidate()
 }
 
 nsresult
 Database::EnsureConnection()
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(!IsOnBackgroundThread());
 
-  AUTO_PROFILER_LABEL("Database::EnsureConnection", STORAGE);
+  AUTO_PROFILER_LABEL("Database::EnsureConnection", DOM);
 
   if (!mConnection || !mConnection->GetStorageConnection()) {
     nsresult rv =
       gConnectionPool->GetOrCreateConnection(this, getter_AddRefs(mConnection));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
@@ -19461,17 +19461,17 @@ NS_IMPL_ISUPPORTS(UpgradeFileIdsFunction
 NS_IMETHODIMP
 UpgradeFileIdsFunction::OnFunctionCall(mozIStorageValueArray* aArguments,
                                        nsIVariant** aResult)
 {
   MOZ_ASSERT(aArguments);
   MOZ_ASSERT(aResult);
   MOZ_ASSERT(mFileManager);
 
-  AUTO_PROFILER_LABEL("UpgradeFileIdsFunction::OnFunctionCall", STORAGE);
+  AUTO_PROFILER_LABEL("UpgradeFileIdsFunction::OnFunctionCall", DOM);
 
   uint32_t argc;
   nsresult rv = aArguments->GetNumEntries(&argc);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   if (argc != 2) {
@@ -19634,17 +19634,17 @@ DatabaseOperationBase::GetStructuredClon
                                                  const nsAString& aFileIds,
                                                  StructuredCloneReadInfo* aInfo)
 {
   MOZ_ASSERT(!IsOnBackgroundThread());
   MOZ_ASSERT(aFileManager);
   MOZ_ASSERT(aInfo);
 
   AUTO_PROFILER_LABEL(
-    "DatabaseOperationBase::GetStructuredCloneReadInfoFromBlob", STORAGE);
+    "DatabaseOperationBase::GetStructuredCloneReadInfoFromBlob", DOM);
 
   const char* compressed = reinterpret_cast<const char*>(aBlobData);
   size_t compressedLength = size_t(aBlobDataLength);
 
   size_t uncompressedLength;
   if (NS_WARN_IF(!snappy::GetUncompressedLength(compressed, compressedLength,
                                                 &uncompressedLength))) {
     return NS_ERROR_FILE_CORRUPTED;
@@ -19688,17 +19688,17 @@ DatabaseOperationBase::GetStructuredClon
                                                  StructuredCloneReadInfo* aInfo)
 {
   MOZ_ASSERT(!IsOnBackgroundThread());
   MOZ_ASSERT(aFileManager);
   MOZ_ASSERT(aInfo);
 
   AUTO_PROFILER_LABEL(
     "DatabaseOperationBase::GetStructuredCloneReadInfoFromExternalBlob",
-    STORAGE);
+    DOM);
 
   nsresult rv;
 
   if (!aFileIds.IsVoid()) {
     rv = DeserializeStructuredCloneFiles(aFileManager,
                                          aFileIds,
                                          aInfo->mFiles,
                                          &aInfo->mHasPreprocessInfo);
@@ -19917,17 +19917,17 @@ DatabaseOperationBase::IndexDataValuesFr
                                   const nsTArray<IndexUpdateInfo>& aUpdateInfos,
                                   const UniqueIndexTable& aUniqueIndexTable,
                                   nsTArray<IndexDataValue>& aIndexValues)
 {
   MOZ_ASSERT(aIndexValues.IsEmpty());
   MOZ_ASSERT_IF(!aUpdateInfos.IsEmpty(), aUniqueIndexTable.Count());
 
   AUTO_PROFILER_LABEL(
-    "DatabaseOperationBase::IndexDataValuesFromUpdateInfos", STORAGE);
+    "DatabaseOperationBase::IndexDataValuesFromUpdateInfos", DOM);
 
   const uint32_t count = aUpdateInfos.Length();
 
   if (!count) {
     return NS_OK;
   }
 
   if (NS_WARN_IF(!aIndexValues.SetCapacity(count, fallible))) {
@@ -19960,17 +19960,17 @@ DatabaseOperationBase::InsertIndexTableR
                              const int64_t aObjectStoreId,
                              const Key& aObjectStoreKey,
                              const FallibleTArray<IndexDataValue>& aIndexValues)
 {
   MOZ_ASSERT(aConnection);
   aConnection->AssertIsOnConnectionThread();
   MOZ_ASSERT(!aObjectStoreKey.IsUnset());
 
-  AUTO_PROFILER_LABEL("DatabaseOperationBase::InsertIndexTableRows", STORAGE);
+  AUTO_PROFILER_LABEL("DatabaseOperationBase::InsertIndexTableRows", DOM);
 
   const uint32_t count = aIndexValues.Length();
   if (!count) {
     return NS_OK;
   }
 
   NS_NAMED_LITERAL_CSTRING(objectStoreIdString, "object_store_id");
   NS_NAMED_LITERAL_CSTRING(objectDataKeyString, "object_data_key");
@@ -20068,17 +20068,17 @@ DatabaseOperationBase::DeleteIndexDataTa
                              const Key& aObjectStoreKey,
                              const FallibleTArray<IndexDataValue>& aIndexValues)
 {
   MOZ_ASSERT(aConnection);
   aConnection->AssertIsOnConnectionThread();
   MOZ_ASSERT(!aObjectStoreKey.IsUnset());
 
   AUTO_PROFILER_LABEL(
-    "DatabaseOperationBase::DeleteIndexDataTableRows", STORAGE);
+    "DatabaseOperationBase::DeleteIndexDataTableRows", DOM);
 
   const uint32_t count = aIndexValues.Length();
   if (!count) {
     return NS_OK;
   }
 
   NS_NAMED_LITERAL_CSTRING(indexIdString, "index_id");
   NS_NAMED_LITERAL_CSTRING(valueString, "value");
@@ -20162,17 +20162,17 @@ DatabaseOperationBase::DeleteObjectStore
       ObjectStoreHasIndexes(aConnection, aObjectStoreId, &hasIndexes)));
     MOZ_ASSERT(hasIndexes,
                "Don't use this slow method if there are no indexes!");
   }
 #endif
 
   AUTO_PROFILER_LABEL(
     "DatabaseOperationBase::DeleteObjectStoreDataTableRowsWithIndexes",
-    STORAGE);
+    DOM);
 
   const bool singleRowOnly =
     aKeyRange.type() == OptionalKeyRange::TSerializedKeyRange &&
     aKeyRange.get_SerializedKeyRange().isOnly();
 
   NS_NAMED_LITERAL_CSTRING(objectStoreIdString, "object_store_id");
   NS_NAMED_LITERAL_CSTRING(keyString, "key");
 
@@ -20302,17 +20302,17 @@ DatabaseOperationBase::UpdateIndexValues
                              const int64_t aObjectStoreId,
                              const Key& aObjectStoreKey,
                              const FallibleTArray<IndexDataValue>& aIndexValues)
 {
   MOZ_ASSERT(aConnection);
   aConnection->AssertIsOnConnectionThread();
   MOZ_ASSERT(!aObjectStoreKey.IsUnset());
 
-  AUTO_PROFILER_LABEL("DatabaseOperationBase::UpdateIndexValues", STORAGE);
+  AUTO_PROFILER_LABEL("DatabaseOperationBase::UpdateIndexValues", DOM);
 
   UniqueFreePtr<uint8_t> indexDataValues;
   uint32_t indexDataValuesLength;
   nsresult rv = MakeCompressedIndexDataValues(aIndexValues,
                                               indexDataValues,
                                               &indexDataValuesLength);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
@@ -21467,17 +21467,17 @@ OpenDatabaseOp::DatabaseOpen()
 }
 
 nsresult
 OpenDatabaseOp::DoDatabaseWork()
 {
   AssertIsOnIOThread();
   MOZ_ASSERT(mState == State::DatabaseWorkOpen);
 
-  AUTO_PROFILER_LABEL("OpenDatabaseOp::DoDatabaseWork", STORAGE);
+  AUTO_PROFILER_LABEL("OpenDatabaseOp::DoDatabaseWork", DOM);
 
   if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonBackgroundThread()) ||
       !OperationMayProceed()) {
     IDB_REPORT_INTERNAL_ERR();
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   const nsString& databaseName = mCommonParams.metadata().name();
@@ -22659,17 +22659,17 @@ VersionChangeOp::DoDatabaseWork(Database
 
   if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonBackgroundThread()) ||
       !OperationMayProceed()) {
     IDB_REPORT_INTERNAL_ERR();
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   AUTO_PROFILER_LABEL(
-    "OpenDatabaseOp::VersionChangeOp::DoDatabaseWork", STORAGE);
+    "OpenDatabaseOp::VersionChangeOp::DoDatabaseWork", DOM);
 
   IDB_LOG_MARK("IndexedDB %s: Parent Transaction[%lld]: "
                  "Beginning database work",
                "IndexedDB %s: P T[%lld]: DB Start",
                IDB_LOG_ID_STRING(mBackgroundChildLoggingId),
                mLoggingSerialNumber);
 
   Transaction()->SetActiveOnConnectionThread();
@@ -22760,17 +22760,17 @@ VersionChangeOp::Cleanup()
 void
 DeleteDatabaseOp::LoadPreviousVersion(nsIFile* aDatabaseFile)
 {
   AssertIsOnIOThread();
   MOZ_ASSERT(aDatabaseFile);
   MOZ_ASSERT(mState == State::DatabaseWorkOpen);
   MOZ_ASSERT(!mPreviousVersion);
 
-  AUTO_PROFILER_LABEL("DeleteDatabaseOp::LoadPreviousVersion", STORAGE);
+  AUTO_PROFILER_LABEL("DeleteDatabaseOp::LoadPreviousVersion", DOM);
 
   nsresult rv;
 
   nsCOMPtr<mozIStorageService> ss =
     do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID, &rv);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
@@ -22847,17 +22847,17 @@ DeleteDatabaseOp::DatabaseOpen()
 }
 
 nsresult
 DeleteDatabaseOp::DoDatabaseWork()
 {
   AssertIsOnIOThread();
   MOZ_ASSERT(mState == State::DatabaseWorkOpen);
 
-  AUTO_PROFILER_LABEL("DeleteDatabaseOp::DoDatabaseWork", STORAGE);
+  AUTO_PROFILER_LABEL("DeleteDatabaseOp::DoDatabaseWork", DOM);
 
   if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonBackgroundThread()) ||
       !OperationMayProceed()) {
     IDB_REPORT_INTERNAL_ERR();
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   const nsString& databaseName = mCommonParams.metadata().name();
@@ -23097,17 +23097,17 @@ VersionChangeOp::DeleteFile(nsIFile* aDi
 {
   AssertIsOnIOThread();
   MOZ_ASSERT(aDirectory);
   MOZ_ASSERT(!aFilename.IsEmpty());
   MOZ_ASSERT_IF(aQuotaManager, mDeleteDatabaseOp->mEnforcingQuota);
 
   MOZ_ASSERT(mDeleteDatabaseOp->mState == State::DatabaseWorkVersionChange);
 
-  AUTO_PROFILER_LABEL("DeleteDatabaseOp::VersionChangeOp::DeleteFile", STORAGE);
+  AUTO_PROFILER_LABEL("DeleteDatabaseOp::VersionChangeOp::DeleteFile", DOM);
 
   nsCOMPtr<nsIFile> file;
   nsresult rv = aDirectory->Clone(getter_AddRefs(file));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   rv = file->Append(aFilename);
@@ -23157,17 +23157,17 @@ VersionChangeOp::DeleteFile(nsIFile* aDi
 nsresult
 DeleteDatabaseOp::
 VersionChangeOp::RunOnIOThread()
 {
   AssertIsOnIOThread();
   MOZ_ASSERT(mDeleteDatabaseOp->mState == State::DatabaseWorkVersionChange);
 
   AUTO_PROFILER_LABEL(
-    "DeleteDatabaseOp::VersionChangeOp::RunOnIOThread", STORAGE);
+    "DeleteDatabaseOp::VersionChangeOp::RunOnIOThread", DOM);
 
   if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonBackgroundThread()) ||
       !OperationMayProceed()) {
     IDB_REPORT_INTERNAL_ERR();
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   const PersistenceType& persistenceType =
@@ -23489,17 +23489,17 @@ void
 TransactionDatabaseOperationBase::RunOnConnectionThread()
 {
   MOZ_ASSERT(!IsOnBackgroundThread());
   MOZ_ASSERT(mInternalState == InternalState::DatabaseWork);
   MOZ_ASSERT(mTransaction);
   MOZ_ASSERT(NS_SUCCEEDED(mResultCode));
 
   AUTO_PROFILER_LABEL(
-    "TransactionDatabaseOperationBase::RunOnConnectionThread", STORAGE);
+    "TransactionDatabaseOperationBase::RunOnConnectionThread", DOM);
 
   // There are several cases where we don't actually have to to any work here.
 
   if (mTransactionIsAborted || mTransaction->IsInvalidatedOnAnyThread()) {
     // This transaction is already set to be aborted or invalidated.
     mResultCode = NS_ERROR_DOM_INDEXEDDB_ABORT_ERR;
   } else if (!OperationMayProceed()) {
     // The operation was canceled in some way, likely because the child process
@@ -23877,17 +23877,17 @@ NS_IMPL_ISUPPORTS_INHERITED0(Transaction
 
 NS_IMETHODIMP
 TransactionBase::
 CommitOp::Run()
 {
   MOZ_ASSERT(mTransaction);
   mTransaction->AssertIsOnConnectionThread();
 
-  AUTO_PROFILER_LABEL("TransactionBase::CommitOp::Run", STORAGE);
+  AUTO_PROFILER_LABEL("TransactionBase::CommitOp::Run", DOM);
 
   IDB_LOG_MARK("IndexedDB %s: Parent Transaction[%lld] Request[%llu]: "
                  "Beginning database work",
                "IndexedDB %s: P T[%lld] R[%llu]: DB Start",
                IDB_LOG_ID_STRING(mBackgroundChildLoggingId),
                mTransaction->LoggingSerialNumber(),
                mLoggingSerialNumber);
 
@@ -23969,17 +23969,17 @@ CommitOp::Run()
 
 void
 TransactionBase::
 CommitOp::TransactionFinishedBeforeUnblock()
 {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(mTransaction);
 
-  AUTO_PROFILER_LABEL("CommitOp::TransactionFinishedBeforeUnblock", STORAGE);
+  AUTO_PROFILER_LABEL("CommitOp::TransactionFinishedBeforeUnblock", DOM);
 
   if (!IsActorDestroyed()) {
     mTransaction->UpdateMetadata(mResultCode);
   }
 }
 
 void
 TransactionBase::
@@ -24134,17 +24134,17 @@ CreateFileOp::CreateMutableFile(MutableF
 }
 
 nsresult
 CreateFileOp::DoDatabaseWork()
 {
   AssertIsOnIOThread();
   MOZ_ASSERT(mState == State::DatabaseWork);
 
-  AUTO_PROFILER_LABEL("CreateFileOp::DoDatabaseWork", STORAGE);
+  AUTO_PROFILER_LABEL("CreateFileOp::DoDatabaseWork", DOM);
 
   if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) {
     NS_WARNING("Refusing to create file because disk space is low!");
     return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
   }
 
   if (NS_WARN_IF(QuotaManager::IsShuttingDown()) || !OperationMayProceed()) {
     IDB_REPORT_INTERNAL_ERR();
@@ -24277,17 +24277,17 @@ VersionChangeTransactionOp::Cleanup()
 }
 
 nsresult
 CreateObjectStoreOp::DoDatabaseWork(DatabaseConnection* aConnection)
 {
   MOZ_ASSERT(aConnection);
   aConnection->AssertIsOnConnectionThread();
 
-  AUTO_PROFILER_LABEL("CreateObjectStoreOp::DoDatabaseWork", STORAGE);
+  AUTO_PROFILER_LABEL("CreateObjectStoreOp::DoDatabaseWork", DOM);
 
   if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) {
     return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
   }
 
 #ifdef DEBUG
   {
     // Make sure that we're not creating an object store with the same name as
@@ -24379,17 +24379,17 @@ CreateObjectStoreOp::DoDatabaseWork(Data
 }
 
 nsresult
 DeleteObjectStoreOp::DoDatabaseWork(DatabaseConnection* aConnection)
 {
   MOZ_ASSERT(aConnection);
   aConnection->AssertIsOnConnectionThread();
 
-  AUTO_PROFILER_LABEL("DeleteObjectStoreOp::DoDatabaseWork", STORAGE);
+  AUTO_PROFILER_LABEL("DeleteObjectStoreOp::DoDatabaseWork", DOM);
 
   NS_NAMED_LITERAL_CSTRING(objectStoreIdString, "object_store_id");
 
 #ifdef DEBUG
   {
     // Make sure |mIsLastObjectStore| is telling the truth.
     DatabaseConnection::CachedStatement stmt;
     MOZ_ALWAYS_SUCCEEDS(
@@ -24600,17 +24600,17 @@ DeleteObjectStoreOp::DoDatabaseWork(Data
 }
 
 nsresult
 RenameObjectStoreOp::DoDatabaseWork(DatabaseConnection* aConnection)
 {
   MOZ_ASSERT(aConnection);
   aConnection->AssertIsOnConnectionThread();
 
-  AUTO_PROFILER_LABEL("RenameObjectStoreOp::DoDatabaseWork", STORAGE);
+  AUTO_PROFILER_LABEL("RenameObjectStoreOp::DoDatabaseWork", DOM);
 
   if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) {
     return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
   }
 
 #ifdef DEBUG
   {
     // Make sure that we're not renaming an object store with the same name as
@@ -24696,17 +24696,17 @@ CreateIndexOp::CreateIndexOp(VersionChan
 nsresult
 CreateIndexOp::InsertDataFromObjectStore(DatabaseConnection* aConnection)
 {
   MOZ_ASSERT(aConnection);
   aConnection->AssertIsOnConnectionThread();
   MOZ_ASSERT(!IndexedDatabaseManager::InLowDiskSpaceMode());
   MOZ_ASSERT(mMaybeUniqueIndexTable);
 
-  AUTO_PROFILER_LABEL("CreateIndexOp::InsertDataFromObjectStore", STORAGE);
+  AUTO_PROFILER_LABEL("CreateIndexOp::InsertDataFromObjectStore", DOM);
 
   nsCOMPtr<mozIStorageConnection> storageConnection =
     aConnection->GetStorageConnection();
   MOZ_ASSERT(storageConnection);
 
   RefPtr<UpdateIndexDataValuesFunction> updateFunction =
     new UpdateIndexDataValuesFunction(this, aConnection);
 
@@ -24786,17 +24786,17 @@ CreateIndexOp::Init(TransactionBase* aTr
 }
 
 nsresult
 CreateIndexOp::DoDatabaseWork(DatabaseConnection* aConnection)
 {
   MOZ_ASSERT(aConnection);
   aConnection->AssertIsOnConnectionThread();
 
-  AUTO_PROFILER_LABEL("CreateIndexOp::DoDatabaseWork", STORAGE);
+  AUTO_PROFILER_LABEL("CreateIndexOp::DoDatabaseWork", DOM);
 
   if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) {
     return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
   }
 
 #ifdef DEBUG
   {
     // Make sure that we're not creating an index with the same name and object
@@ -24928,17 +24928,17 @@ UpdateIndexDataValuesFunction::OnFunctio
 {
   MOZ_ASSERT(aValues);
   MOZ_ASSERT(_retval);
   MOZ_ASSERT(mConnection);
   mConnection->AssertIsOnConnectionThread();
   MOZ_ASSERT(mOp);
 
   AUTO_PROFILER_LABEL(
-    "CreateIndexOp::UpdateIndexDataValuesFunction::OnFunctionCall", STORAGE);
+    "CreateIndexOp::UpdateIndexDataValuesFunction::OnFunctionCall", DOM);
 
 #ifdef DEBUG
   {
     uint32_t argCount;
     MOZ_ALWAYS_SUCCEEDS(aValues->GetNumEntries(&argCount));
     MOZ_ASSERT(argCount == 4); // key, index_data_values, file_ids, data
 
     int32_t valueType;
@@ -25157,17 +25157,17 @@ DeleteIndexOp::RemoveReferencesToIndex(D
 
     bool
     LessThan(const IndexDataValue& aA, const IndexDataValue& aB) const
     {
       return aA.mIndexId < aB.mIndexId;
     };
   };
 
-  AUTO_PROFILER_LABEL("DeleteIndexOp::RemoveReferencesToIndex", STORAGE);
+  AUTO_PROFILER_LABEL("DeleteIndexOp::RemoveReferencesToIndex", DOM);
 
   if (mIsLastIndex) {
     // There is no need to parse the previous entry in the index_data_values
     // column if this is the last index. Simply set it to NULL.
     DatabaseConnection::CachedStatement stmt;
     nsresult rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
       "UPDATE object_data "
         "SET index_data_values = NULL "
@@ -25297,17 +25297,17 @@ DeleteIndexOp::DoDatabaseWork(DatabaseCo
       }
     }
 
     MOZ_ASSERT_IF(mIsLastIndex, foundThisIndex && !foundOtherIndex);
     MOZ_ASSERT_IF(!mIsLastIndex, foundThisIndex && foundOtherIndex);
   }
 #endif
 
-  AUTO_PROFILER_LABEL("DeleteIndexOp::DoDatabaseWork", STORAGE);
+  AUTO_PROFILER_LABEL("DeleteIndexOp::DoDatabaseWork", DOM);
 
   DatabaseConnection::AutoSavepoint autoSave;
   nsresult rv = autoSave.Start(Transaction());
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   DatabaseConnection::CachedStatement selectStmt;
@@ -25554,17 +25554,17 @@ DeleteIndexOp::DoDatabaseWork(DatabaseCo
 }
 
 nsresult
 RenameIndexOp::DoDatabaseWork(DatabaseConnection* aConnection)
 {
   MOZ_ASSERT(aConnection);
   aConnection->AssertIsOnConnectionThread();
 
-  AUTO_PROFILER_LABEL("RenameIndexOp::DoDatabaseWork", STORAGE);
+  AUTO_PROFILER_LABEL("RenameIndexOp::DoDatabaseWork", DOM);
 
   if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) {
     return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
   }
 
 #ifdef DEBUG
   {
     // Make sure that we're not renaming an index with the same name as another
@@ -26054,17 +26054,17 @@ ObjectStoreAddOrPutRequestOp::Init(Trans
 
 nsresult
 ObjectStoreAddOrPutRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
 {
   MOZ_ASSERT(aConnection);
   aConnection->AssertIsOnConnectionThread();
   MOZ_ASSERT(aConnection->GetStorageConnection());
 
-  AUTO_PROFILER_LABEL("ObjectStoreAddOrPutRequestOp::DoDatabaseWork", STORAGE);
+  AUTO_PROFILER_LABEL("ObjectStoreAddOrPutRequestOp::DoDatabaseWork", DOM);
 
   if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) {
     return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
   }
 
   DatabaseConnection::AutoSavepoint autoSave;
   nsresult rv = autoSave.Start(Transaction());
   if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -26550,17 +26550,17 @@ ObjectStoreGetRequestOp::DoDatabaseWork(
 {
   MOZ_ASSERT(aConnection);
   aConnection->AssertIsOnConnectionThread();
   MOZ_ASSERT_IF(!mGetAll,
                 mOptionalKeyRange.type() ==
                   OptionalKeyRange::TSerializedKeyRange);
   MOZ_ASSERT_IF(!mGetAll, mLimit == 1);
 
-  AUTO_PROFILER_LABEL("ObjectStoreGetRequestOp::DoDatabaseWork", STORAGE);
+  AUTO_PROFILER_LABEL("ObjectStoreGetRequestOp::DoDatabaseWork", DOM);
 
   const bool hasKeyRange =
     mOptionalKeyRange.type() == OptionalKeyRange::TSerializedKeyRange;
 
   nsAutoCString keyRangeClause;
   if (hasKeyRange) {
     GetBindingClauseForKeyRange(mOptionalKeyRange.get_SerializedKeyRange(),
                                 NS_LITERAL_CSTRING("key"),
@@ -26764,17 +26764,17 @@ ObjectStoreGetKeyRequestOp::ObjectStoreG
 }
 
 nsresult
 ObjectStoreGetKeyRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
 {
   MOZ_ASSERT(aConnection);
   aConnection->AssertIsOnConnectionThread();
 
-  AUTO_PROFILER_LABEL("ObjectStoreGetKeyRequestOp::DoDatabaseWork", STORAGE);
+  AUTO_PROFILER_LABEL("ObjectStoreGetKeyRequestOp::DoDatabaseWork", DOM);
 
   const bool hasKeyRange =
       mOptionalKeyRange.type() == OptionalKeyRange::TSerializedKeyRange;
 
   nsAutoCString keyRangeClause;
   if (hasKeyRange) {
     GetBindingClauseForKeyRange(mOptionalKeyRange.get_SerializedKeyRange(),
                                 NS_LITERAL_CSTRING("key"),
@@ -26885,17 +26885,17 @@ ObjectStoreDeleteRequestOp::ObjectStoreD
   mObjectStoreMayHaveIndexes = metadata->HasLiveIndexes();
 }
 
 nsresult
 ObjectStoreDeleteRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
 {
   MOZ_ASSERT(aConnection);
   aConnection->AssertIsOnConnectionThread();
-  AUTO_PROFILER_LABEL("ObjectStoreDeleteRequestOp::DoDatabaseWork", STORAGE);
+  AUTO_PROFILER_LABEL("ObjectStoreDeleteRequestOp::DoDatabaseWork", DOM);
 
   DatabaseConnection::AutoSavepoint autoSave;
   nsresult rv = autoSave.Start(Transaction());
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   bool objectStoreHasIndexes;
@@ -26976,17 +26976,17 @@ ObjectStoreClearRequestOp::ObjectStoreCl
 }
 
 nsresult
 ObjectStoreClearRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
 {
   MOZ_ASSERT(aConnection);
   aConnection->AssertIsOnConnectionThread();
 
-  AUTO_PROFILER_LABEL("ObjectStoreClearRequestOp::DoDatabaseWork", STORAGE);
+  AUTO_PROFILER_LABEL("ObjectStoreClearRequestOp::DoDatabaseWork", DOM);
 
   DatabaseConnection::AutoSavepoint autoSave;
   nsresult rv = autoSave.Start(Transaction());
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   bool objectStoreHasIndexes;
@@ -27037,17 +27037,17 @@ ObjectStoreClearRequestOp::DoDatabaseWor
 }
 
 nsresult
 ObjectStoreCountRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
 {
   MOZ_ASSERT(aConnection);
   aConnection->AssertIsOnConnectionThread();
 
-  AUTO_PROFILER_LABEL("ObjectStoreCountRequestOp::DoDatabaseWork", STORAGE);
+  AUTO_PROFILER_LABEL("ObjectStoreCountRequestOp::DoDatabaseWork", DOM);
 
   const bool hasKeyRange =
     mParams.optionalKeyRange().type() == OptionalKeyRange::TSerializedKeyRange;
 
   nsAutoCString keyRangeClause;
   if (hasKeyRange) {
     GetBindingClauseForKeyRange(
       mParams.optionalKeyRange().get_SerializedKeyRange(),
@@ -27200,17 +27200,17 @@ IndexGetRequestOp::DoDatabaseWork(Databa
 {
   MOZ_ASSERT(aConnection);
   aConnection->AssertIsOnConnectionThread();
   MOZ_ASSERT_IF(!mGetAll,
                 mOptionalKeyRange.type() ==
                   OptionalKeyRange::TSerializedKeyRange);
   MOZ_ASSERT_IF(!mGetAll, mLimit == 1);
 
-  AUTO_PROFILER_LABEL("IndexGetRequestOp::DoDatabaseWork", STORAGE);
+  AUTO_PROFILER_LABEL("IndexGetRequestOp::DoDatabaseWork", DOM);
 
   const bool hasKeyRange =
     mOptionalKeyRange.type() == OptionalKeyRange::TSerializedKeyRange;
 
   nsCString indexTable;
   if (mMetadata->mCommonMetadata.unique()) {
     indexTable.AssignLiteral("unique_index_data ");
   }
@@ -27401,17 +27401,17 @@ IndexGetKeyRequestOp::DoDatabaseWork(Dat
 {
   MOZ_ASSERT(aConnection);
   aConnection->AssertIsOnConnectionThread();
   MOZ_ASSERT_IF(!mGetAll,
                 mOptionalKeyRange.type() ==
                   OptionalKeyRange::TSerializedKeyRange);
   MOZ_ASSERT_IF(!mGetAll, mLimit == 1);
 
-  AUTO_PROFILER_LABEL("IndexGetKeyRequestOp::DoDatabaseWork", STORAGE);
+  AUTO_PROFILER_LABEL("IndexGetKeyRequestOp::DoDatabaseWork", DOM);
 
   const bool hasKeyRange =
     mOptionalKeyRange.type() == OptionalKeyRange::TSerializedKeyRange;
 
   nsCString indexTable;
   if (mMetadata->mCommonMetadata.unique()) {
     indexTable.AssignLiteral("unique_index_data ");
   }
@@ -27512,17 +27512,17 @@ IndexGetKeyRequestOp::GetResponse(Reques
 }
 
 nsresult
 IndexCountRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
 {
   MOZ_ASSERT(aConnection);
   aConnection->AssertIsOnConnectionThread();
 
-  AUTO_PROFILER_LABEL("IndexCountRequestOp::DoDatabaseWork", STORAGE);
+  AUTO_PROFILER_LABEL("IndexCountRequestOp::DoDatabaseWork", DOM);
 
   const bool hasKeyRange =
     mParams.optionalKeyRange().type() == OptionalKeyRange::TSerializedKeyRange;
 
   nsCString indexTable;
   if (mMetadata->mCommonMetadata.unique()) {
     indexTable.AssignLiteral("unique_index_data ");
   }
@@ -27798,17 +27798,17 @@ OpenOp::DoObjectStoreDatabaseWork(Databa
 {
   MOZ_ASSERT(aConnection);
   aConnection->AssertIsOnConnectionThread();
   MOZ_ASSERT(mCursor);
   MOZ_ASSERT(mCursor->mType == OpenCursorParams::TObjectStoreOpenCursorParams);
   MOZ_ASSERT(mCursor->mObjectStoreId);
   MOZ_ASSERT(mCursor->mFileManager);
 
-  AUTO_PROFILER_LABEL("Cursor::OpenOp::DoObjectStoreDatabaseWork", STORAGE);
+  AUTO_PROFILER_LABEL("Cursor::OpenOp::DoObjectStoreDatabaseWork", DOM);
 
   const bool usingKeyRange =
     mOptionalKeyRange.type() == OptionalKeyRange::TSerializedKeyRange;
 
   NS_NAMED_LITERAL_CSTRING(keyString, "key");
   NS_NAMED_LITERAL_CSTRING(id, "id");
   NS_NAMED_LITERAL_CSTRING(openLimit, " LIMIT ");
 
@@ -27956,17 +27956,17 @@ OpenOp::DoObjectStoreKeyDatabaseWork(Dat
 {
   MOZ_ASSERT(aConnection);
   aConnection->AssertIsOnConnectionThread();
   MOZ_ASSERT(mCursor);
   MOZ_ASSERT(mCursor->mType ==
                OpenCursorParams::TObjectStoreOpenKeyCursorParams);
   MOZ_ASSERT(mCursor->mObjectStoreId);
 
-  AUTO_PROFILER_LABEL("Cursor::OpenOp::DoObjectStoreKeyDatabaseWork", STORAGE);
+  AUTO_PROFILER_LABEL("Cursor::OpenOp::DoObjectStoreKeyDatabaseWork", DOM);
 
   const bool usingKeyRange =
     mOptionalKeyRange.type() == OptionalKeyRange::TSerializedKeyRange;
 
   NS_NAMED_LITERAL_CSTRING(keyString, "key");
   NS_NAMED_LITERAL_CSTRING(id, "id");
   NS_NAMED_LITERAL_CSTRING(openLimit, " LIMIT ");
 
@@ -28112,17 +28112,17 @@ OpenOp::DoIndexDatabaseWork(DatabaseConn
 {
   MOZ_ASSERT(aConnection);
   aConnection->AssertIsOnConnectionThread();
   MOZ_ASSERT(mCursor);
   MOZ_ASSERT(mCursor->mType == OpenCursorParams::TIndexOpenCursorParams);
   MOZ_ASSERT(mCursor->mObjectStoreId);
   MOZ_ASSERT(mCursor->mIndexId);
 
-  AUTO_PROFILER_LABEL("Cursor::OpenOp::DoIndexDatabaseWork", STORAGE);
+  AUTO_PROFILER_LABEL("Cursor::OpenOp::DoIndexDatabaseWork", DOM);
 
   const bool usingKeyRange =
     mOptionalKeyRange.type() == OptionalKeyRange::TSerializedKeyRange;
 
   nsCString indexTable = mCursor->mUniqueIndex ?
     NS_LITERAL_CSTRING("unique_index_data") :
     NS_LITERAL_CSTRING("index_data");
 
@@ -28359,17 +28359,17 @@ OpenOp::DoIndexKeyDatabaseWork(DatabaseC
 {
   MOZ_ASSERT(aConnection);
   aConnection->AssertIsOnConnectionThread();
   MOZ_ASSERT(mCursor);
   MOZ_ASSERT(mCursor->mType == OpenCursorParams::TIndexOpenKeyCursorParams);
   MOZ_ASSERT(mCursor->mObjectStoreId);
   MOZ_ASSERT(mCursor->mIndexId);
 
-  AUTO_PROFILER_LABEL("Cursor::OpenOp::DoIndexKeyDatabaseWork", STORAGE);
+  AUTO_PROFILER_LABEL("Cursor::OpenOp::DoIndexKeyDatabaseWork", DOM);
 
   const bool usingKeyRange =
     mOptionalKeyRange.type() == OptionalKeyRange::TSerializedKeyRange;
 
   nsCString table = mCursor->mUniqueIndex ?
     NS_LITERAL_CSTRING("unique_index_data") :
     NS_LITERAL_CSTRING("index_data");
 
@@ -28599,17 +28599,17 @@ OpenOp::DoDatabaseWork(DatabaseConnectio
   aConnection->AssertIsOnConnectionThread();
   MOZ_ASSERT(mCursor);
   MOZ_ASSERT(mCursor->mContinueQuery.IsEmpty());
   MOZ_ASSERT(mCursor->mContinueToQuery.IsEmpty());
   MOZ_ASSERT(mCursor->mContinuePrimaryKeyQuery.IsEmpty());
   MOZ_ASSERT(mCursor->mKey.IsUnset());
   MOZ_ASSERT(mCursor->mRangeKey.IsUnset());
 
-  AUTO_PROFILER_LABEL("Cursor::OpenOp::DoDatabaseWork", STORAGE);
+  AUTO_PROFILER_LABEL("Cursor::OpenOp::DoDatabaseWork", DOM);
 
   nsresult rv;
 
   switch (mCursor->mType) {
     case OpenCursorParams::TObjectStoreOpenCursorParams:
       rv = DoObjectStoreDatabaseWork(aConnection);
       break;
 
@@ -28683,17 +28683,17 @@ ContinueOp::DoDatabaseWork(DatabaseConne
 
   MOZ_ASSERT_IF(isIndex &&
                 (mCursor->mDirection == IDBCursor::NEXT ||
                  mCursor->mDirection == IDBCursor::PREV),
                 !mCursor->mContinuePrimaryKeyQuery.IsEmpty());
   MOZ_ASSERT_IF(isIndex, mCursor->mIndexId);
   MOZ_ASSERT_IF(isIndex, !mCursor->mObjectKey.IsUnset());
 
-  AUTO_PROFILER_LABEL("Cursor::ContinueOp::DoDatabaseWork", STORAGE);
+  AUTO_PROFILER_LABEL("Cursor::ContinueOp::DoDatabaseWork", DOM);
 
   // We need to pick a query based on whether or not a key was passed to the
   // continue function. If not we'll grab the the next item in the database that
   // is greater than (or less than, if we're running a PREV cursor) the current
   // key. If a key was passed we'll grab the next item in the database that is
   // greater than (or less than, if we're running a PREV cursor) or equal to the
   // key that was specified.
 
@@ -29470,17 +29470,17 @@ FileHelper::SyncCopy(nsIInputStream* aIn
                      nsIOutputStream* aOutputStream,
                      char* aBuffer,
                      uint32_t aBufferSize)
 {
   MOZ_ASSERT(!IsOnBackgroundThread());
   MOZ_ASSERT(aInputStream);
   MOZ_ASSERT(aOutputStream);
 
-  AUTO_PROFILER_LABEL("FileHelper::SyncCopy", STORAGE);
+  AUTO_PROFILER_LABEL("FileHelper::SyncCopy", DOM);
 
   nsresult rv;
 
   do {
     uint32_t numRead;
     rv = SyncRead(aInputStream, aBuffer, aBufferSize, &numRead);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       break;
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -2515,17 +2515,17 @@ ContentChild::RecvLoadProcessScript(cons
 
 mozilla::ipc::IPCResult
 ContentChild::RecvAsyncMessage(const nsString& aMsg,
                                InfallibleTArray<CpowEntry>&& aCpows,
                                const IPC::Principal& aPrincipal,
                                const ClonedMessageData& aData)
 {
   AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING(
-    "ContentChild::RecvAsyncMessage", EVENTS, aMsg);
+    "ContentChild::RecvAsyncMessage", OTHER, aMsg);
 
   CrossProcessCpowHolder cpows(this, aCpows);
   RefPtr<nsFrameMessageManager> cpm =
     nsFrameMessageManager::GetChildProcessManager();
   if (cpm) {
     StructuredCloneData data;
     ipc::UnpackClonedMessageDataForChild(aData, data);
     cpm->ReceiveMessage(cpm, nullptr, aMsg, false, &data, &cpows, aPrincipal, nullptr,
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -4456,18 +4456,18 @@ ContentParent::RecvNotifyTabDestroying(c
 {
   NotifyTabDestroying(aTabId, aCpId);
   return IPC_OK();
 }
 
 nsTArray<TabContext>
 ContentParent::GetManagedTabContext()
 {
-  return std::move(ContentProcessManager::GetSingleton()->
-          GetTabContextByContentProcess(this->ChildID()));
+  return ContentProcessManager::GetSingleton()->
+    GetTabContextByContentProcess(this->ChildID());
 }
 
 mozilla::docshell::POfflineCacheUpdateParent*
 ContentParent::AllocPOfflineCacheUpdateParent(const URIParams& aManifestURI,
                                               const URIParams& aDocumentURI,
                                               const PrincipalInfo& aLoadingPrincipalInfo,
                                               const bool& aStickDocument)
 {
--- a/dom/ipc/ContentProcessManager.cpp
+++ b/dom/ipc/ContentProcessManager.cpp
@@ -120,26 +120,26 @@ nsTArray<ContentParentId>
 ContentProcessManager::GetAllChildProcessById(const ContentParentId& aParentCpId)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsTArray<ContentParentId> cpIdArray;
   auto iter = mContentParentMap.find(aParentCpId);
   if (NS_WARN_IF(iter == mContentParentMap.end())) {
     ASSERT_UNLESS_FUZZING();
-    return std::move(cpIdArray);
+    return cpIdArray;
   }
 
   for (auto cpIter = iter->second.mChildrenCpId.begin();
        cpIter != iter->second.mChildrenCpId.end();
        ++cpIter) {
     cpIdArray.AppendElement(*cpIter);
   }
 
-  return std::move(cpIdArray);
+  return cpIdArray;
 }
 
 bool
 ContentProcessManager::RegisterRemoteFrame(const TabId& aTabId,
                                            const ContentParentId& aOpenerCpId,
                                            const TabId& aOpenerTabId,
                                            const IPCTabContext& aContext,
                                            const ContentParentId& aChildCpId)
@@ -231,26 +231,26 @@ nsTArray<TabContext>
 ContentProcessManager::GetTabContextByContentProcess(const ContentParentId& aChildCpId)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsTArray<TabContext> tabContextArray;
   auto iter = mContentParentMap.find(aChildCpId);
   if (NS_WARN_IF(iter == mContentParentMap.end())) {
     ASSERT_UNLESS_FUZZING();
-    return std::move(tabContextArray);
+    return tabContextArray;
   }
 
   for (auto remoteFrameIter = iter->second.mRemoteFrames.begin();
        remoteFrameIter != iter->second.mRemoteFrames.end();
        ++remoteFrameIter) {
     tabContextArray.AppendElement(remoteFrameIter->second.mContext);
   }
 
-  return std::move(tabContextArray);
+  return tabContextArray;
 }
 
 bool
 ContentProcessManager::GetRemoteFrameOpenerTabId(const ContentParentId& aChildCpId,
                                                  const TabId& aChildTabId,
                                                  /*out*/ContentParentId* aOpenerCpId,
                                                  /*out*/TabId* aOpenerTabId)
 {
@@ -332,26 +332,26 @@ nsTArray<TabId>
 ContentProcessManager::GetTabParentsByProcessId(const ContentParentId& aChildCpId)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsTArray<TabId> tabIdList;
   auto iter = mContentParentMap.find(aChildCpId);
   if (NS_WARN_IF(iter == mContentParentMap.end())) {
     ASSERT_UNLESS_FUZZING();
-    return std::move(tabIdList);
+    return tabIdList;
   }
 
   for (auto remoteFrameIter = iter->second.mRemoteFrames.begin();
       remoteFrameIter != iter->second.mRemoteFrames.end();
       ++remoteFrameIter) {
     tabIdList.AppendElement(remoteFrameIter->first);
   }
 
-  return std::move(tabIdList);
+  return tabIdList;
 }
 
 uint32_t
 ContentProcessManager::GetTabParentCountByProcessId(const ContentParentId& aChildCpId)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   auto iter = mContentParentMap.find(aChildCpId);
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -2299,17 +2299,17 @@ TabChild::RecvLoadRemoteScript(const nsS
 
 mozilla::ipc::IPCResult
 TabChild::RecvAsyncMessage(const nsString& aMessage,
                            InfallibleTArray<CpowEntry>&& aCpows,
                            const IPC::Principal& aPrincipal,
                            const ClonedMessageData& aData)
 {
   AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING(
-    "TabChild::RecvAsyncMessage", EVENTS, aMessage);
+    "TabChild::RecvAsyncMessage", OTHER, aMessage);
 
   CrossProcessCpowHolder cpows(Manager(), aCpows);
   if (!mTabChildGlobal) {
     return IPC_OK();
   }
 
   RefPtr<nsFrameMessageManager> mm = mTabChildGlobal->GetMessageManager();
 
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -1667,17 +1667,17 @@ TabParent::SendHandleTap(TapType aType,
 mozilla::ipc::IPCResult
 TabParent::RecvSyncMessage(const nsString& aMessage,
                            const ClonedMessageData& aData,
                            InfallibleTArray<CpowEntry>&& aCpows,
                            const IPC::Principal& aPrincipal,
                            nsTArray<StructuredCloneData>* aRetVal)
 {
   AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING(
-    "TabParent::RecvSyncMessage", EVENTS, aMessage);
+    "TabParent::RecvSyncMessage", OTHER, aMessage);
 
   StructuredCloneData data;
   ipc::UnpackClonedMessageDataForParent(aData, data);
 
   CrossProcessCpowHolder cpows(Manager(), aCpows);
   if (!ReceiveMessage(aMessage, true, &data, &cpows, aPrincipal, aRetVal)) {
     return IPC_FAIL_NO_REASON(this);
   }
@@ -1687,17 +1687,17 @@ TabParent::RecvSyncMessage(const nsStrin
 mozilla::ipc::IPCResult
 TabParent::RecvRpcMessage(const nsString& aMessage,
                           const ClonedMessageData& aData,
                           InfallibleTArray<CpowEntry>&& aCpows,
                           const IPC::Principal& aPrincipal,
                           nsTArray<StructuredCloneData>* aRetVal)
 {
   AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING(
-    "TabParent::RecvRpcMessage", EVENTS, aMessage);
+    "TabParent::RecvRpcMessage", OTHER, aMessage);
 
   StructuredCloneData data;
   ipc::UnpackClonedMessageDataForParent(aData, data);
 
   CrossProcessCpowHolder cpows(Manager(), aCpows);
   if (!ReceiveMessage(aMessage, true, &data, &cpows, aPrincipal, aRetVal)) {
     return IPC_FAIL_NO_REASON(this);
   }
@@ -1706,17 +1706,17 @@ TabParent::RecvRpcMessage(const nsString
 
 mozilla::ipc::IPCResult
 TabParent::RecvAsyncMessage(const nsString& aMessage,
                             InfallibleTArray<CpowEntry>&& aCpows,
                             const IPC::Principal& aPrincipal,
                             const ClonedMessageData& aData)
 {
   AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING(
-    "TabParent::RecvAsyncMessage", EVENTS, aMessage);
+    "TabParent::RecvAsyncMessage", OTHER, aMessage);
 
   StructuredCloneData data;
   ipc::UnpackClonedMessageDataForParent(aData, data);
 
   CrossProcessCpowHolder cpows(Manager(), aCpows);
   if (!ReceiveMessage(aMessage, false, &data, &cpows, aPrincipal, nullptr)) {
     return IPC_FAIL_NO_REASON(this);
   }
--- a/dom/ipc/nsIContentChild.cpp
+++ b/dom/ipc/nsIContentChild.cpp
@@ -169,17 +169,17 @@ nsIContentChild::DeallocPFileDescriptorS
 
 mozilla::ipc::IPCResult
 nsIContentChild::RecvAsyncMessage(const nsString& aMsg,
                                   InfallibleTArray<CpowEntry>&& aCpows,
                                   const IPC::Principal& aPrincipal,
                                   const ClonedMessageData& aData)
 {
   AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING(
-    "nsIContentChild::RecvAsyncMessage", EVENTS, aMsg);
+    "nsIContentChild::RecvAsyncMessage", OTHER, aMsg);
 
   CrossProcessCpowHolder cpows(this, aCpows);
   RefPtr<nsFrameMessageManager> cpm = nsFrameMessageManager::GetChildProcessManager();
   if (cpm) {
     ipc::StructuredCloneData data;
     ipc::UnpackClonedMessageDataForChild(aData, data);
 
     cpm->ReceiveMessage(cpm, nullptr, aMsg, false, &data, &cpows, aPrincipal, nullptr,
--- a/dom/ipc/nsIContentParent.cpp
+++ b/dom/ipc/nsIContentParent.cpp
@@ -244,17 +244,17 @@ nsIContentParent::DeallocPIPCBlobInputSt
 mozilla::ipc::IPCResult
 nsIContentParent::RecvSyncMessage(const nsString& aMsg,
                                   const ClonedMessageData& aData,
                                   InfallibleTArray<CpowEntry>&& aCpows,
                                   const IPC::Principal& aPrincipal,
                                   nsTArray<ipc::StructuredCloneData>* aRetvals)
 {
   AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING(
-    "nsIContentParent::RecvSyncMessage", EVENTS, aMsg);
+    "nsIContentParent::RecvSyncMessage", OTHER, aMsg);
 
   CrossProcessCpowHolder cpows(this, aCpows);
   RefPtr<nsFrameMessageManager> ppm = mMessageManager;
   if (ppm) {
     ipc::StructuredCloneData data;
     ipc::UnpackClonedMessageDataForParent(aData, data);
 
     ppm->ReceiveMessage(ppm, nullptr, aMsg, true, &data, &cpows, aPrincipal, aRetvals,
@@ -266,17 +266,17 @@ nsIContentParent::RecvSyncMessage(const 
 mozilla::ipc::IPCResult
 nsIContentParent::RecvRpcMessage(const nsString& aMsg,
                                  const ClonedMessageData& aData,
                                  InfallibleTArray<CpowEntry>&& aCpows,
                                  const IPC::Principal& aPrincipal,
                                  nsTArray<ipc::StructuredCloneData>* aRetvals)
 {
   AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING(
-    "nsIContentParent::RecvRpcMessage", EVENTS, aMsg);
+    "nsIContentParent::RecvRpcMessage", OTHER, aMsg);
 
   CrossProcessCpowHolder cpows(this, aCpows);
   RefPtr<nsFrameMessageManager> ppm = mMessageManager;
   if (ppm) {
     ipc::StructuredCloneData data;
     ipc::UnpackClonedMessageDataForParent(aData, data);
 
     ppm->ReceiveMessage(ppm, nullptr, aMsg, true, &data, &cpows, aPrincipal, aRetvals,
@@ -326,17 +326,17 @@ nsIContentParent::DeallocPParentToChildS
 
 mozilla::ipc::IPCResult
 nsIContentParent::RecvAsyncMessage(const nsString& aMsg,
                                    InfallibleTArray<CpowEntry>&& aCpows,
                                    const IPC::Principal& aPrincipal,
                                    const ClonedMessageData& aData)
 {
   AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING(
-    "nsIContentParent::RecvAsyncMessage", EVENTS, aMsg);
+    "nsIContentParent::RecvAsyncMessage", OTHER, aMsg);
 
   CrossProcessCpowHolder cpows(this, aCpows);
   RefPtr<nsFrameMessageManager> ppm = mMessageManager;
   if (ppm) {
     ipc::StructuredCloneData data;
     ipc::UnpackClonedMessageDataForParent(aData, data);
 
     ppm->ReceiveMessage(ppm, nullptr, aMsg, false, &data, &cpows, aPrincipal, nullptr,
--- a/dom/media/MediaStreamGraph.cpp
+++ b/dom/media/MediaStreamGraph.cpp
@@ -2587,17 +2587,17 @@ MediaStream::SetTrackEnabledImpl(TrackID
     }
   } else {
     for (const DisabledTrack& t : mDisabledTracks) {
       if (aTrackID == t.mTrackID) {
         NS_ERROR("Changing disabled track mode for a track is not allowed");
         return;
       }
     }
-    mDisabledTracks.AppendElement(std::move(DisabledTrack(aTrackID, aMode)));
+    mDisabledTracks.AppendElement(DisabledTrack(aTrackID, aMode));
   }
 }
 
 DisabledTrackMode
 MediaStream::GetDisabledTrackMode(TrackID aTrackID)
 {
   for (const DisabledTrack& t : mDisabledTracks) {
     if (t.mTrackID == aTrackID) {
--- a/dom/media/PeerConnection.js
+++ b/dom/media/PeerConnection.js
@@ -1576,19 +1576,19 @@ class RTCPeerConnection {
     }
     if (maxPacketLifeTime !== undefined && maxRetransmits !== undefined) {
       throw new this._win.DOMException(
           "Both maxPacketLifeTime and maxRetransmits cannot be provided",
           "InvalidParameterError");
     }
     // Must determine the type where we still know if entries are undefined.
     let type;
-    if (maxPacketLifeTime) {
+    if (maxPacketLifeTime !== undefined) {
       type = Ci.IPeerConnection.kDataChannelPartialReliableTimed;
-    } else if (maxRetransmits) {
+    } else if (maxRetransmits !== undefined) {
       type = Ci.IPeerConnection.kDataChannelPartialReliableRexmit;
     } else {
       type = Ci.IPeerConnection.kDataChannelReliable;
     }
     // Synchronous since it doesn't block.
     let dataChannel =
       this._impl.createDataChannel(label, protocol, type, ordered,
                                    maxPacketLifeTime, maxRetransmits,
--- a/dom/media/eme/MediaKeySystemAccess.cpp
+++ b/dom/media/eme/MediaKeySystemAccess.cpp
@@ -759,17 +759,17 @@ GetSupportedCapabilities(
     if (!supportedCapabilities.AppendElement(capabilities, mozilla::fallible)) {
       NS_WARNING("GetSupportedCapabilities: Malloc failure");
       return Sequence<MediaKeySystemMediaCapability>();
     }
 
     // Note: omitting steps 3.13.2, our robustness is not sophisticated enough
     // to require considering all requirements together.
   }
-  return std::move(supportedCapabilities);
+  return supportedCapabilities;
 }
 
 // "Get Supported Configuration and Consent" algorithm, steps 4-7 for
 // distinctive identifier, and steps 8-11 for persistent state. The steps
 // are the same for both requirements/features, so we factor them out into
 // a single function.
 static bool
 CheckRequirement(const MediaKeysRequirement aRequirement,
--- a/dom/media/gmp/ChromiumCDMParent.cpp
+++ b/dom/media/gmp/ChromiumCDMParent.cpp
@@ -1073,17 +1073,17 @@ ChromiumCDMParent::RecvDrainComplete()
 {
   if (mIsShutdown) {
     MOZ_ASSERT(mDecodePromise.IsEmpty());
     return IPC_OK();
   }
 
   MediaDataDecoder::DecodedData samples;
   while (!mReorderQueue.IsEmpty()) {
-    samples.AppendElement(std::move(mReorderQueue.Pop()));
+    samples.AppendElement(mReorderQueue.Pop());
   }
 
   mDecodePromise.ResolveIfExists(std::move(samples), __func__);
   return IPC_OK();
 }
 RefPtr<ShutdownPromise>
 ChromiumCDMParent::ShutdownVideoDecoder()
 {
--- a/dom/media/gmp/GMPParent.cpp
+++ b/dom/media/gmp/GMPParent.cpp
@@ -941,17 +941,17 @@ GMPParent::GetGMPContentParent(UniquePtr
     }
   }
 }
 
 already_AddRefed<GMPContentParent>
 GMPParent::ForgetGMPContentParent()
 {
   MOZ_ASSERT(mGetContentParentPromises.IsEmpty());
-  return std::move(mGMPContentParent.forget());
+  return mGMPContentParent.forget();
 }
 
 bool
 GMPParent::EnsureProcessLoaded(base::ProcessId* aID)
 {
   if (!EnsureProcessLoaded()) {
     return false;
   }
--- a/dom/media/gmp/GMPServiceParent.cpp
+++ b/dom/media/gmp/GMPServiceParent.cpp
@@ -1880,17 +1880,17 @@ GMPServiceParent::ActorDestroy(ActorDest
   // Make sure the IPC channel is closed before destroying mToDelete.
   MonitorAutoLock lock(monitor);
   RefPtr<Runnable> task = NewNonOwningRunnableMethod<Monitor*, bool*>(
     "gmp::GMPServiceParent::CloseTransport",
     this,
     &GMPServiceParent::CloseTransport,
     &monitor,
     &completed);
-  XRE_GetIOMessageLoop()->PostTask(std::move(task.forget()));
+  XRE_GetIOMessageLoop()->PostTask(task.forget());
 
   while (!completed) {
     lock.Wait();
   }
 
   // Dispatch a task to the current thread to ensure we don't delete the
   // GMPServiceParent until the current calling context is finished with
   // the object.
--- a/dom/media/gmp/GMPStorageChild.cpp
+++ b/dom/media/gmp/GMPStorageChild.cpp
@@ -21,17 +21,17 @@
     } \
   } while(false)
 
 static nsTArray<uint8_t>
 ToArray(const uint8_t* aData, uint32_t aDataSize)
 {
   nsTArray<uint8_t> data;
   data.AppendElements(aData, aDataSize);
-  return std::move(data);
+  return data;
 }
 
 namespace mozilla {
 namespace gmp {
 
 GMPRecordImpl::GMPRecordImpl(GMPStorageChild* aOwner,
                              const nsCString& aName,
                              GMPRecordClient* aClient)
--- a/dom/media/ipc/VideoDecoderManagerParent.cpp
+++ b/dom/media/ipc/VideoDecoderManagerParent.cpp
@@ -39,17 +39,17 @@ using namespace gfx;
 SurfaceDescriptorGPUVideo
 VideoDecoderManagerParent::StoreImage(Image* aImage, TextureClient* aTexture)
 {
   SurfaceDescriptorGPUVideo ret;
   aTexture->GPUVideoDesc(&ret);
 
   mImageMap[ret.handle()] = aImage;
   mTextureMap[ret.handle()] = aTexture;
-  return std::move(ret);
+  return ret;
 }
 
 StaticRefPtr<nsIThread> sVideoDecoderManagerThread;
 StaticRefPtr<TaskQueue> sManagerTaskQueue;
 
 class VideoDecoderManagerThreadHolder
 {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VideoDecoderManagerThreadHolder)
--- a/dom/media/platforms/apple/AppleVTDecoder.cpp
+++ b/dom/media/platforms/apple/AppleVTDecoder.cpp
@@ -252,17 +252,17 @@ AppleVTDecoder::ProcessDrain()
   AssertOnTaskQueueThread();
   nsresult rv = WaitForAsynchronousFrames();
   if (NS_FAILED(rv)) {
     LOG("AppleVTDecoder::Drain failed waiting for platform decoder");
   }
   MonitorAutoLock mon(mMonitor);
   DecodedData samples;
   while (!mReorderQueue.IsEmpty()) {
-    samples.AppendElement(std::move(mReorderQueue.Pop()));
+    samples.AppendElement(mReorderQueue.Pop());
   }
   return DecodePromise::CreateAndResolve(std::move(samples), __func__);
 }
 
 AppleVTDecoder::AppleFrameRef*
 AppleVTDecoder::CreateAppleFrameRef(const MediaRawData* aSample)
 {
   MOZ_ASSERT(aSample);
--- a/dom/media/platforms/omx/OmxPlatformLayer.cpp
+++ b/dom/media/platforms/omx/OmxPlatformLayer.cpp
@@ -168,17 +168,17 @@ ConfigForMime(const nsACString& aMimeTyp
                 aMimeType.EqualsLiteral("audio/mpeg")) {
       conf.reset(new OmxMp3Config());
     } else if (aMimeType.EqualsLiteral("audio/3gpp")) {
       conf.reset(new OmxAmrConfig<OmxAmrSampleRate::kNarrowBand>());
     } else if (aMimeType.EqualsLiteral("audio/amr-wb")) {
       conf.reset(new OmxAmrConfig<OmxAmrSampleRate::kWideBand>());
     }
   }
-  return std::move(conf);
+  return conf;
 }
 
 // There should be a better way to calculate it.
 #define MIN_VIDEO_INPUT_BUFFER_SIZE 64 * 1024
 
 class OmxCommonVideoConfig : public OmxVideoConfig
 {
 public:
@@ -226,17 +226,17 @@ template<>
 UniquePtr<OmxVideoConfig>
 ConfigForMime(const nsACString& aMimeType)
 {
   UniquePtr<OmxVideoConfig> conf;
 
   if (OmxPlatformLayer::SupportsMimeType(aMimeType)) {
     conf.reset(new OmxCommonVideoConfig());
   }
-  return std::move(conf);
+  return conf;
 }
 
 OMX_ERRORTYPE
 OmxPlatformLayer::Config()
 {
   MOZ_ASSERT(mInfo);
 
   OMX_PORT_PARAM_TYPE portParam;
--- a/dom/serviceworkers/ServiceWorkerDescriptor.cpp
+++ b/dom/serviceworkers/ServiceWorkerDescriptor.cpp
@@ -98,17 +98,17 @@ ServiceWorkerDescriptor::PrincipalInfo()
   return mData->principalInfo();
 }
 
 nsCOMPtr<nsIPrincipal>
 ServiceWorkerDescriptor::GetPrincipal() const
 {
   AssertIsOnMainThread();
   nsCOMPtr<nsIPrincipal> ref =  PrincipalInfoToPrincipal(mData->principalInfo());
-  return std::move(ref);
+  return ref;
 }
 
 const nsCString&
 ServiceWorkerDescriptor::Scope() const
 {
   return mData->scope();
 }
 
--- a/dom/serviceworkers/ServiceWorkerManager.cpp
+++ b/dom/serviceworkers/ServiceWorkerManager.cpp
@@ -319,51 +319,51 @@ ServiceWorkerManager::StartControllingCl
   const ServiceWorkerDescriptor& active =
     aRegistrationInfo->GetActive()->Descriptor();
 
   auto entry = mControlledClients.LookupForAdd(aClientInfo.Id());
   if (entry) {
     RefPtr<ServiceWorkerRegistrationInfo> old =
       entry.Data()->mRegistrationInfo.forget();
 
-    ref = std::move(entry.Data()->mClientHandle->Control(active));
+    ref = entry.Data()->mClientHandle->Control(active);
     entry.Data()->mRegistrationInfo = aRegistrationInfo;
 
     if (old != aRegistrationInfo) {
       StopControllingRegistration(old);
       aRegistrationInfo->StartControllingClient();
     }
 
     Telemetry::Accumulate(Telemetry::SERVICE_WORKER_CONTROLLED_DOCUMENTS, 1);
 
-    return std::move(ref);
+    return ref;
   }
 
   RefPtr<ClientHandle> clientHandle =
     ClientManager::CreateHandle(aClientInfo,
                                 SystemGroup::EventTargetFor(TaskCategory::Other));
 
-  ref = std::move(clientHandle->Control(active));
+  ref = clientHandle->Control(active);
 
   aRegistrationInfo->StartControllingClient();
 
   entry.OrInsert([&] {
     return new ControlledClientData(clientHandle, aRegistrationInfo);
   });
 
   RefPtr<ServiceWorkerManager> self(this);
   clientHandle->OnDetach()->Then(
     SystemGroup::EventTargetFor(TaskCategory::Other), __func__,
     [self = std::move(self), aClientInfo] {
       self->StopControllingClient(aClientInfo);
     });
 
   Telemetry::Accumulate(Telemetry::SERVICE_WORKER_CONTROLLED_DOCUMENTS, 1);
 
-  return std::move(ref);
+  return ref;
 }
 
 void
 ServiceWorkerManager::StopControllingClient(const ClientInfo& aClientInfo)
 {
   auto entry = mControlledClients.Lookup(aClientInfo.Id());
   if (!entry) {
     return;
--- a/dom/serviceworkers/ServiceWorkerRegistrar.cpp
+++ b/dom/serviceworkers/ServiceWorkerRegistrar.cpp
@@ -1276,17 +1276,17 @@ ServiceWorkerRegistrar::GetShutdownPhase
   // memory), and there's no point in continuing startup. Include as much
   // information as possible in the crash report.
   RELEASE_ASSERT_SUCCEEDED(rv, "async shutdown service");
 
 
   nsCOMPtr<nsIAsyncShutdownClient> client;
   rv = svc->GetProfileBeforeChange(getter_AddRefs(client));
   RELEASE_ASSERT_SUCCEEDED(rv, "profileBeforeChange shutdown blocker");
-  return std::move(client);
+  return client;
 }
 
 #undef RELEASE_ASSERT_SUCCEEDED
 
 void
 ServiceWorkerRegistrar::Shutdown()
 {
   AssertIsOnBackgroundThread();
--- a/dom/serviceworkers/ServiceWorkerRegistrationDescriptor.cpp
+++ b/dom/serviceworkers/ServiceWorkerRegistrationDescriptor.cpp
@@ -22,17 +22,17 @@ ServiceWorkerRegistrationDescriptor::New
   Maybe<IPCServiceWorkerDescriptor> result;
   if (mData->installing().type() != OptionalIPCServiceWorkerDescriptor::Tvoid_t) {
     result.emplace(mData->installing().get_IPCServiceWorkerDescriptor());
   } else if (mData->waiting().type() != OptionalIPCServiceWorkerDescriptor::Tvoid_t) {
     result.emplace(mData->waiting().get_IPCServiceWorkerDescriptor());
   } else if (mData->active().type() != OptionalIPCServiceWorkerDescriptor::Tvoid_t) {
     result.emplace(mData->active().get_IPCServiceWorkerDescriptor());
   }
-  return std::move(result);
+  return result;
 }
 
 ServiceWorkerRegistrationDescriptor::ServiceWorkerRegistrationDescriptor(
                                     uint64_t aId,
                                     nsIPrincipal* aPrincipal,
                                     const nsACString& aScope,
                                     ServiceWorkerUpdateViaCache aUpdateViaCache)
   : mData(MakeUnique<IPCServiceWorkerRegistrationDescriptor>())
@@ -133,17 +133,17 @@ ServiceWorkerRegistrationDescriptor::Pri
   return mData->principalInfo();
 }
 
 nsCOMPtr<nsIPrincipal>
 ServiceWorkerRegistrationDescriptor::GetPrincipal() const
 {
   AssertIsOnMainThread();
   nsCOMPtr<nsIPrincipal> ref =  PrincipalInfoToPrincipal(mData->principalInfo());
-  return std::move(ref);
+  return ref;
 }
 
 const nsCString&
 ServiceWorkerRegistrationDescriptor::Scope() const
 {
   return mData->scope();
 }
 
@@ -152,54 +152,54 @@ ServiceWorkerRegistrationDescriptor::Get
 {
   Maybe<ServiceWorkerDescriptor> result;
 
   if (mData->installing().type() != OptionalIPCServiceWorkerDescriptor::Tvoid_t) {
     result.emplace(ServiceWorkerDescriptor(
       mData->installing().get_IPCServiceWorkerDescriptor()));
   }
 
-  return std::move(result);
+  return result;
 }
 
 Maybe<ServiceWorkerDescriptor>
 ServiceWorkerRegistrationDescriptor::GetWaiting() const
 {
   Maybe<ServiceWorkerDescriptor> result;
 
   if (mData->waiting().type() != OptionalIPCServiceWorkerDescriptor::Tvoid_t) {
     result.emplace(ServiceWorkerDescriptor(
       mData->waiting().get_IPCServiceWorkerDescriptor()));
   }
 
-  return std::move(result);
+  return result;
 }
 
 Maybe<ServiceWorkerDescriptor>
 ServiceWorkerRegistrationDescriptor::GetActive() const
 {
   Maybe<ServiceWorkerDescriptor> result;
 
   if (mData->active().type() != OptionalIPCServiceWorkerDescriptor::Tvoid_t) {
     result.emplace(ServiceWorkerDescriptor(
       mData->active().get_IPCServiceWorkerDescriptor()));
   }
 
-  return std::move(result);
+  return result;
 }
 
 Maybe<ServiceWorkerDescriptor>
 ServiceWorkerRegistrationDescriptor::Newest() const
 {
   Maybe<ServiceWorkerDescriptor> result;
   Maybe<IPCServiceWorkerDescriptor> newest(NewestInternal());
   if (newest.isSome()) {
     result.emplace(ServiceWorkerDescriptor(newest.ref()));
   }
-  return std::move(result);
+  return result;
 }
 
 namespace {
 
 bool
 IsValidWorker(const OptionalIPCServiceWorkerDescriptor& aWorker,
               const nsACString& aScope,
               const mozilla::ipc::ContentPrincipalInfo& aContentPrincipal)
--- a/dom/storage/StorageDBThread.cpp
+++ b/dom/storage/StorageDBThread.cpp
@@ -328,17 +328,17 @@ StorageDBThread::Shutdown()
   mThread = nullptr;
 
   return mStatus;
 }
 
 void
 StorageDBThread::SyncPreload(LocalStorageCacheBridge* aCache, bool aForceSync)
 {
-  AUTO_PROFILER_LABEL("StorageDBThread::SyncPreload", STORAGE);
+  AUTO_PROFILER_LABEL("StorageDBThread::SyncPreload", OTHER);
   if (!aForceSync && aCache->LoadedCount()) {
     // Preload already started for this cache, just wait for it to finish.
     // LoadWait will exit after LoadDone on the cache has been called.
     SetHigherPriority();
     aCache->LoadWait();
     SetDefaultPriority();
     return;
   }
--- a/dom/u2f/U2F.cpp
+++ b/dom/u2f/U2F.cpp
@@ -272,17 +272,17 @@ U2F::Register(const nsAString& aAppId,
                                   adjustedAppId,
                                   challenge,
                                   clientData,
                                   adjustedTimeoutMillis,
                                   excludeList,
                                   null_t() /* no extra info for U2F */);
 
   MOZ_ASSERT(mTransaction.isNothing());
-  mTransaction = Some(U2FTransaction(std::move(AsVariant(callback))));
+  mTransaction = Some(U2FTransaction(AsVariant(callback)));
   mChild->SendRequestRegister(mTransaction.ref().mId, info);
 }
 
 void
 U2F::FinishMakeCredential(const uint64_t& aTransactionId,
                           const WebAuthnMakeCredentialResult& aResult)
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -418,17 +418,17 @@ U2F::Sign(const nsAString& aAppId,
                                 adjustedAppId,
                                 challenge,
                                 clientData,
                                 adjustedTimeoutMillis,
                                 permittedList,
                                 null_t() /* no extra info for U2F */);
 
   MOZ_ASSERT(mTransaction.isNothing());
-  mTransaction = Some(U2FTransaction(std::move(AsVariant(callback))));
+  mTransaction = Some(U2FTransaction(AsVariant(callback)));
   mChild->SendRequestSign(mTransaction.ref().mId, info);
 }
 
 void
 U2F::FinishGetAssertion(const uint64_t& aTransactionId,
                         const WebAuthnGetAssertionResult& aResult)
 {
   MOZ_ASSERT(NS_IsMainThread());
--- a/dom/webidl/RTCDataChannel.webidl
+++ b/dom/webidl/RTCDataChannel.webidl
@@ -13,16 +13,18 @@ enum RTCDataChannelType {
   "arraybuffer",
   "blob"
 };
 
 interface RTCDataChannel : EventTarget
 {
   readonly attribute DOMString label;
   readonly attribute boolean reliable;
+  readonly attribute unsigned short? maxPacketLifeTime;
+  readonly attribute unsigned short? maxRetransmits;
   readonly attribute RTCDataChannelState readyState;
   readonly attribute unsigned long bufferedAmount;
   attribute unsigned long bufferedAmountLowThreshold;
   attribute EventHandler onopen;
   attribute EventHandler onerror;
   attribute EventHandler onclose;
   void close();
   attribute EventHandler onmessage;
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -3492,30 +3492,30 @@ WorkerPrivate::EnsurePerformanceStorage(
 
 Maybe<ClientInfo>
 WorkerPrivate::GetClientInfo() const
 {
   AssertIsOnWorkerThread();
   Maybe<ClientInfo> clientInfo;
   if (!mClientSource) {
     MOZ_DIAGNOSTIC_ASSERT(mStatus >= Terminating);
-    return std::move(clientInfo);
+    return clientInfo;
   }
   clientInfo.emplace(mClientSource->Info());
-  return std::move(clientInfo);
+  return clientInfo;
 }
 
 const ClientState
 WorkerPrivate::GetClientState() const
 {
   AssertIsOnWorkerThread();
   MOZ_DIAGNOSTIC_ASSERT(mClientSource);
   ClientState state;
   mClientSource->SnapshotState(&state);
-  return std::move(state);
+  return state;
 }
 
 const Maybe<ServiceWorkerDescriptor>
 WorkerPrivate::GetController()
 {
   AssertIsOnWorkerThread();
   {
     MutexAutoLock lock(mMutex);
@@ -3815,16 +3815,18 @@ WorkerPrivate::DisableMemoryReporter()
   if (NS_FAILED(UnregisterWeakMemoryReporter(memoryReporter))) {
     NS_WARNING("Failed to unregister memory reporter!");
   }
 }
 
 void
 WorkerPrivate::WaitForWorkerEvents()
 {
+  AUTO_PROFILER_LABEL("WorkerPrivate::WaitForWorkerEvents", IDLE);
+
   AssertIsOnWorkerThread();
   mMutex.AssertCurrentThreadOwns();
 
   // Wait for a worker event.
   mCondVar.Wait();
 }
 
 WorkerPrivate::ProcessAllControlRunnablesResult
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -543,17 +543,17 @@ WorkerGlobalScope::GetClientInfo() const
   return mWorkerPrivate->GetClientInfo();
 }
 
 Maybe<ClientState>
 WorkerGlobalScope::GetClientState() const
 {
   Maybe<ClientState> state;
   state.emplace(mWorkerPrivate->GetClientState());
-  return std::move(state);
+  return state;
 }
 
 Maybe<ServiceWorkerDescriptor>
 WorkerGlobalScope::GetController() const
 {
   return mWorkerPrivate->GetController();
 }
 
--- a/editor/libeditor/HTMLAnonymousNodeEditor.cpp
+++ b/editor/libeditor/HTMLAnonymousNodeEditor.cpp
@@ -225,17 +225,17 @@ HTMLEditor::CreateAnonymousElement(nsAto
   // sort of ok.
   newContent->SetProperty(nsGkAtoms::restylableAnonymousNode,
 			  reinterpret_cast<void*>(true));
 #endif // DEBUG
 
   // display the element
   ps->PostRecreateFramesFor(newContent);
 
-  return std::move(newContent);
+  return newContent;
 }
 
 // Removes event listener and calls DeleteRefToAnonymousNode.
 void
 HTMLEditor::RemoveListenerAndDeleteRef(const nsAString& aEvent,
                                        nsIDOMEventListener* aListener,
                                        bool aUseCapture,
                                        ManualNACPtr aElement,
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -6016,18 +6016,17 @@ HTMLEditRules::CreateStyleForInsertText(
   int32_t offset = firstRange->StartOffset();
 
   RefPtr<Element> rootElement = aDocument.GetRootElement();
   if (NS_WARN_IF(!rootElement)) {
     return NS_ERROR_FAILURE;
   }
 
   // process clearing any styles first
-  UniquePtr<PropItem> item =
-    std::move(HTMLEditorRef().mTypeInState->TakeClearProperty());
+  UniquePtr<PropItem> item = HTMLEditorRef().mTypeInState->TakeClearProperty();
 
   {
     // Transactions may set selection, but we will set selection if necessary.
     AutoTransactionsConserveSelection dontChangeMySelection(&HTMLEditorRef());
 
     while (item && node != rootElement) {
       // XXX If we redesign ClearStyle(), we can use EditorDOMPoint in this
       //     method.
@@ -6035,24 +6034,24 @@ HTMLEditRules::CreateStyleForInsertText(
         HTMLEditorRef().ClearStyle(address_of(node), &offset,
                                    item->tag, item->attr);
       if (NS_WARN_IF(!CanHandleEditAction())) {
         return NS_ERROR_EDITOR_DESTROYED;
       }
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
-      item = std::move(HTMLEditorRef().mTypeInState->TakeClearProperty());
+      item = HTMLEditorRef().mTypeInState->TakeClearProperty();
       weDidSomething = true;
     }
   }
 
   // then process setting any styles
   int32_t relFontSize = HTMLEditorRef().mTypeInState->TakeRelativeFontSize();
-  item = std::move(HTMLEditorRef().mTypeInState->TakeSetProperty());
+  item = HTMLEditorRef().mTypeInState->TakeSetProperty();
 
   if (item || relFontSize) {
     // we have at least one style to add; make a new text node to insert style
     // nodes above.
     if (RefPtr<Text> text = node->GetAsText()) {
       // if we are in a text node, split it
       SplitNodeResult splitTextNodeResult =
         HTMLEditorRef().SplitNodeDeepWithTransaction(
--- a/editor/libeditor/HTMLEditorObjectResizer.cpp
+++ b/editor/libeditor/HTMLEditorObjectResizer.cpp
@@ -140,17 +140,17 @@ HTMLEditor::CreateResizer(int16_t aLocat
     case nsIHTMLObjectResizer::eBottomRight:
       locationStr = kBottomRight;
       break;
   }
 
   nsresult rv =
     ret->SetAttr(kNameSpaceID_None, nsGkAtoms::anonlocation, locationStr, true);
   NS_ENSURE_SUCCESS(rv, nullptr);
-  return std::move(ret);
+  return ret;
 }
 
 ManualNACPtr
 HTMLEditor::CreateShadow(nsIContent& aParentContent,
                          Element& aOriginalObject)
 {
   // let's create an image through the element factory
   RefPtr<nsAtom> name;
--- a/extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineChild.cpp
+++ b/extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineChild.cpp
@@ -34,17 +34,17 @@ RemoteSpellcheckEngineChild::SetCurrentD
   if (!SendSetDictionaryFromList(
          aList,
          reinterpret_cast<intptr_t>(promiseHolder.get()))) {
     return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
   }
   RefPtr<GenericPromise> result = promiseHolder->Ensure(__func__);
   // promiseHolder will removed by receive message
   mResponsePromises.AppendElement(std::move(promiseHolder));
-  return std::move(result);
+  return result;
 }
 
 mozilla::ipc::IPCResult
 RemoteSpellcheckEngineChild::RecvNotifyOfCurrentDictionary(
                                const nsString& aDictionary,
                                const intptr_t& aId)
 {
   MozPromiseHolder<GenericPromise>* promiseHolder =
--- a/gfx/2d/SFNTData.cpp
+++ b/gfx/2d/SFNTData.cpp
@@ -134,25 +134,25 @@ SFNTData::Create(const uint8_t *aFontDat
     const BigEndianUint32* endOfOffsets = offset + numFonts;
     while (offset != endOfOffsets) {
       if (!sfntData->AddFont(aFontData, aDataLength, *offset)) {
         return nullptr;
       }
       ++offset;
     }
 
-    return std::move(sfntData);
+    return sfntData;
   }
 
   UniquePtr<SFNTData> sfntData(new SFNTData);
   if (!sfntData->AddFont(aFontData, aDataLength, 0)) {
     return nullptr;
   }
 
-  return std::move(sfntData);
+  return sfntData;
 }
 
 /* static */
 uint64_t
 SFNTData::GetUniqueKey(const uint8_t *aFontData, uint32_t aDataLength,
                        uint32_t aVarDataSize, const void* aVarData)
 {
   uint64_t hash;
--- a/gfx/gl/GLScreenBuffer.cpp
+++ b/gfx/gl/GLScreenBuffer.cpp
@@ -43,28 +43,28 @@ UniquePtr<GLScreenBuffer>
 GLScreenBuffer::Create(GLContext* gl,
                        const gfx::IntSize& size,
                        const SurfaceCaps& caps)
 {
     UniquePtr<GLScreenBuffer> ret;
     if (caps.antialias &&
         !gl->IsSupported(GLFeature::framebuffer_multisample))
     {
-        return std::move(ret);
+        return ret;
     }
 
     layers::TextureFlags flags = layers::TextureFlags::ORIGIN_BOTTOM_LEFT;
     if (!caps.premultAlpha) {
         flags |= layers::TextureFlags::NON_PREMULTIPLIED;
     }
 
     UniquePtr<SurfaceFactory> factory = MakeUnique<SurfaceFactory_Basic>(gl, caps, flags);
 
     ret.reset( new GLScreenBuffer(gl, caps, std::move(factory)) );
-    return std::move(ret);
+    return ret;
 }
 
 /* static */ UniquePtr<SurfaceFactory>
 GLScreenBuffer::CreateFactory(GLContext* gl,
                               const SurfaceCaps& caps,
                               KnowsCompositor* compositorConnection,
                               const layers::TextureFlags& flags)
 {
@@ -948,17 +948,17 @@ ReadBuffer::Create(GLContext* gl,
     const bool isComplete = gl->IsFramebufferComplete(fb);
     if (needsAcquire) {
         surf->ProducerReadRelease();
     }
 
     if (!isComplete)
         return nullptr;
 
-    return std::move(ret);
+    return ret;
 }
 
 ReadBuffer::~ReadBuffer()
 {
     if (!mGL->MakeCurrent())
         return;
 
     GLuint fb = mFB;
--- a/gfx/gl/MozFramebuffer.cpp
+++ b/gfx/gl/MozFramebuffer.cpp
@@ -129,17 +129,17 @@ MozFramebuffer::CreateWith(GLContext* co
     }
 
     const auto status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
     if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
         MOZ_ASSERT(false);
         return nullptr;
     }
 
-    return std::move(mozFB);
+    return mozFB;
 }
 
 ////////////////////
 
 MozFramebuffer::MozFramebuffer(GLContext* const gl, const gfx::IntSize& size,
                                const uint32_t samples, const bool depthStencil,
                                const GLenum colorTarget, const GLuint colorName)
     : mWeakGL(gl)
--- a/gfx/gl/SharedSurface.cpp
+++ b/gfx/gl/SharedSurface.cpp
@@ -327,17 +327,17 @@ SurfaceFactory::NewTexClient(const gfx::
         if (cur->Surf()->mSize == size) {
             cur->Surf()->WaitForBufferOwnership();
             return cur.forget();
         }
 
         StopRecycling(cur);
     }
 
-    UniquePtr<SharedSurface> surf = std::move(CreateShared(size));
+    UniquePtr<SharedSurface> surf = CreateShared(size);
     if (!surf)
         return nullptr;
 
     RefPtr<layers::SharedSurfaceTextureClient> ret;
     ret = layers::SharedSurfaceTextureClient::Create(std::move(surf), this, mAllocator, mFlags);
 
     StartRecycling(ret);
 
--- a/gfx/gl/SharedSurfaceEGL.cpp
+++ b/gfx/gl/SharedSurfaceEGL.cpp
@@ -25,37 +25,37 @@ SharedSurface_EGLImage::Create(GLContext
 {
     auto* egl = gl::GLLibraryEGL::Get();
     MOZ_ASSERT(egl);
     MOZ_ASSERT(context);
 
     UniquePtr<SharedSurface_EGLImage> ret;
 
     if (!HasExtensions(egl, prodGL)) {
-        return std::move(ret);
+        return ret;
     }
 
     MOZ_ALWAYS_TRUE(prodGL->MakeCurrent());
     GLuint prodTex = CreateTextureForOffscreen(prodGL, formats, size);
     if (!prodTex) {
-        return std::move(ret);
+        return ret;
     }
 
     EGLClientBuffer buffer = reinterpret_cast<EGLClientBuffer>(uintptr_t(prodTex));
     EGLImage image = egl->fCreateImage(egl->Display(), context,
                                        LOCAL_EGL_GL_TEXTURE_2D, buffer,
                                        nullptr);
     if (!image) {
         prodGL->fDeleteTextures(1, &prodTex);
-        return std::move(ret);
+        return ret;
     }
 
     ret.reset( new SharedSurface_EGLImage(prodGL, egl, size, hasAlpha,
                                           formats, prodTex, image) );
-    return std::move(ret);
+    return ret;
 }
 
 bool
 SharedSurface_EGLImage::HasExtensions(GLLibraryEGL* egl, GLContext* gl)
 {
     return egl->HasKHRImageBase() &&
            egl->IsExtensionSupported(GLLibraryEGL::KHR_gl_texture_2D_image) &&
            (gl->IsExtensionSupported(GLContext::OES_EGL_image_external) ||
@@ -173,17 +173,17 @@ SurfaceFactory_EGLImage::Create(GLContex
     typedef SurfaceFactory_EGLImage ptrT;
     UniquePtr<ptrT> ret;
 
     auto* egl = gl::GLLibraryEGL::Get();
     if (SharedSurface_EGLImage::HasExtensions(egl, prodGL)) {
         ret.reset( new ptrT(prodGL, caps, allocator, flags, context) );
     }
 
-    return std::move(ret);
+    return ret;
 }
 
 ////////////////////////////////////////////////////////////////////////
 
 #ifdef MOZ_WIDGET_ANDROID
 
 /*static*/ UniquePtr<SharedSurface_SurfaceTexture>
 SharedSurface_SurfaceTexture::Create(GLContext* prodGL,
@@ -196,22 +196,22 @@ SharedSurface_SurfaceTexture::Create(GLC
 
     UniquePtr<SharedSurface_SurfaceTexture> ret;
 
     AndroidNativeWindow window(surface);
     GLContextEGL* egl = GLContextEGL::Cast(prodGL);
     MOZ_ASSERT(egl);
     EGLSurface eglSurface = egl->CreateCompatibleSurface(window.NativeWindow());
     if (!eglSurface) {
-        return std::move(ret);
+        return ret;
     }
 
     ret.reset(new SharedSurface_SurfaceTexture(prodGL, size, hasAlpha,
                                                formats, surface, eglSurface));
-    return std::move(ret);
+    return ret;
 }
 
 SharedSurface_SurfaceTexture::SharedSurface_SurfaceTexture(GLContext* gl,
                                                            const gfx::IntSize& size,
                                                            bool hasAlpha,
                                                            const GLFormats& formats,
                                                            java::GeckoSurface::Param surface,
                                                            EGLSurface eglSurface)
@@ -288,17 +288,17 @@ SharedSurface_SurfaceTexture::ToSurfaceD
 
 /*static*/ UniquePtr<SurfaceFactory_SurfaceTexture>
 SurfaceFactory_SurfaceTexture::Create(GLContext* prodGL, const SurfaceCaps& caps,
                                       const RefPtr<layers::LayersIPCChannel>& allocator,
                                       const layers::TextureFlags& flags)
 {
     UniquePtr<SurfaceFactory_SurfaceTexture> ret(
         new SurfaceFactory_SurfaceTexture(prodGL, caps, allocator, flags));
-    return std::move(ret);
+    return ret;
 }
 
 UniquePtr<SharedSurface>
 SurfaceFactory_SurfaceTexture::CreateShared(const gfx::IntSize& size)
 {
     bool hasAlpha = mReadCaps.alpha;
 
     jni::Object::LocalRef surface = java::SurfaceAllocator::AcquireSurface(size.width, size.height, true);
--- a/gfx/gl/SharedSurfaceGL.cpp
+++ b/gfx/gl/SharedSurfaceGL.cpp
@@ -28,35 +28,35 @@ SharedSurface_Basic::Create(GLContext* g
 
     GLContext::LocalErrorScope localError(*gl);
     GLuint tex = CreateTextureForOffscreen(gl, formats, size);
 
     GLenum err = localError.GetError();
     MOZ_ASSERT_IF(err != LOCAL_GL_NO_ERROR, err == LOCAL_GL_OUT_OF_MEMORY);
     if (err) {
         gl->fDeleteTextures(1, &tex);
-        return std::move(ret);
+        return ret;
     }
 
     bool ownsTex = true;
     ret.reset( new SharedSurface_Basic(gl, size, hasAlpha, tex, ownsTex) );
-    return std::move(ret);
+    return ret;
 }
 
 
 /*static*/ UniquePtr<SharedSurface_Basic>
 SharedSurface_Basic::Wrap(GLContext* gl,
                           const IntSize& size,
                           bool hasAlpha,
                           GLuint tex)
 {
     bool ownsTex = false;
     UniquePtr<SharedSurface_Basic> ret( new SharedSurface_Basic(gl, size, hasAlpha, tex,
                                                                 ownsTex) );
-    return std::move(ret);
+    return ret;
 }
 
 SharedSurface_Basic::SharedSurface_Basic(GLContext* gl,
                                          const IntSize& size,
                                          bool hasAlpha,
                                          GLuint tex,
                                          bool ownsTex)
     : SharedSurface(SharedSurfaceType::Basic,
@@ -121,22 +121,22 @@ SharedSurface_GLTexture::Create(GLContex
     GLContext::LocalErrorScope localError(*prodGL);
 
     GLuint tex = CreateTextureForOffscreen(prodGL, formats, size);
 
     GLenum err = localError.GetError();
     MOZ_ASSERT_IF(err, err == LOCAL_GL_OUT_OF_MEMORY);
     if (err) {
         prodGL->fDeleteTextures(1, &tex);
-        return std::move(ret);
+        return ret;
     }
 
     ret.reset(new SharedSurface_GLTexture(prodGL, size,
                                           hasAlpha, tex));
-    return std::move(ret);
+    return ret;
 }
 
 SharedSurface_GLTexture::~SharedSurface_GLTexture()
 {
     if (!mGL->MakeCurrent())
         return;
 
     if (mTex) {
--- a/gfx/gl/SharedSurfaceGLX.cpp
+++ b/gfx/gl/SharedSurfaceGLX.cpp
@@ -32,17 +32,17 @@ SharedSurface_GLXDrawable::Create(GLCont
     Screen* screen = XDefaultScreenOfDisplay(display);
     Visual* visual = gfxXlibSurface::FindVisual(screen, gfx::SurfaceFormat::A8R8G8B8_UINT32);
 
     RefPtr<gfxXlibSurface> surf = gfxXlibSurface::Create(screen, visual, size);
     if (!deallocateClient)
         surf->ReleasePixmap();
 
     ret.reset(new SharedSurface_GLXDrawable(prodGL, size, inSameProcess, surf));
-    return std::move(ret);
+    return ret;
 }
 
 
 SharedSurface_GLXDrawable::SharedSurface_GLXDrawable(GLContext* gl,
                                                      const gfx::IntSize& size,
                                                      bool inSameProcess,
                                                      const RefPtr<gfxXlibSurface>& xlibSurface)
     : SharedSurface(SharedSurfaceType::GLXDrawable,
@@ -124,17 +124,17 @@ SurfaceFactory_GLXDrawable::Create(GLCon
                                    const RefPtr<layers::LayersIPCChannel>& allocator,
                                    const layers::TextureFlags& flags)
 {
     MOZ_ASSERT(caps.alpha, "GLX surfaces require an alpha channel!");
 
     typedef SurfaceFactory_GLXDrawable ptrT;
     UniquePtr<ptrT> ret(new ptrT(prodGL, caps, allocator,
                                  flags & ~layers::TextureFlags::ORIGIN_BOTTOM_LEFT));
-    return std::move(ret);
+    return ret;
 }
 
 UniquePtr<SharedSurface>
 SurfaceFactory_GLXDrawable::CreateShared(const gfx::IntSize& size)
 {
     bool deallocateClient = !!(mFlags & layers::TextureFlags::DEALLOCATE_CLIENT);
     return SharedSurface_GLXDrawable::Create(mGL, mCaps, size, deallocateClient,
                                              mAllocator->IsSameProcess());
--- a/gfx/gl/SharedSurfaceIO.cpp
+++ b/gfx/gl/SharedSurfaceIO.cpp
@@ -21,17 +21,17 @@ SharedSurface_IOSurface::Create(const Re
 {
     MOZ_ASSERT(ioSurf);
     MOZ_ASSERT(gl);
 
     auto size = gfx::IntSize::Truncate(ioSurf->GetWidth(), ioSurf->GetHeight());
 
     typedef SharedSurface_IOSurface ptrT;
     UniquePtr<ptrT> ret( new ptrT(ioSurf, gl, size, hasAlpha) );
-    return std::move(ret);
+    return ret;
 }
 
 void
 SharedSurface_IOSurface::ProducerReleaseImpl()
 {
     mGL->MakeCurrent();
     mGL->fFlush();
 }
@@ -214,17 +214,17 @@ SurfaceFactory_IOSurface::Create(GLConte
                                  const RefPtr<layers::LayersIPCChannel>& allocator,
                                  const layers::TextureFlags& flags)
 {
     auto maxDims = gfx::IntSize::Truncate(MacIOSurface::GetMaxWidth(),
                                           MacIOSurface::GetMaxHeight());
 
     typedef SurfaceFactory_IOSurface ptrT;
     UniquePtr<ptrT> ret( new ptrT(gl, caps, allocator, flags, maxDims) );
-    return std::move(ret);
+    return ret;
 }
 
 UniquePtr<SharedSurface>
 SurfaceFactory_IOSurface::CreateShared(const gfx::IntSize& size)
 {
     if (size.width > mMaxDims.width ||
         size.height > mMaxDims.height)
     {
--- a/gfx/layers/AnimationHelper.cpp
+++ b/gfx/layers/AnimationHelper.cpp
@@ -108,17 +108,17 @@ CompositorAnimationStorage::SetAnimatedV
 void
 CompositorAnimationStorage::SetAnimatedValue(uint64_t aId,
                                              gfx::Matrix4x4&& aTransformInDevSpace)
 {
   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   const TransformData dontCare = {};
   SetAnimatedValue(aId,
                    std::move(aTransformInDevSpace),
-                   std::move(gfx::Matrix4x4()),
+                   gfx::Matrix4x4(),
                    dontCare);
 }
 
 void
 CompositorAnimationStorage::SetAnimatedValue(uint64_t aId,
                                              const float& aOpacity)
 {
   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
@@ -576,18 +576,18 @@ AnimationHelper::SetAnimations(
     data->mTiming = TimingParams {
       animation.duration(),
       animation.delay(),
       animation.endDelay(),
       animation.iterations(),
       animation.iterationStart(),
       static_cast<dom::PlaybackDirection>(animation.direction()),
       static_cast<dom::FillMode>(animation.fillMode()),
-      std::move(AnimationUtils::TimingFunctionToComputedTimingFunction(
-           animation.easingFunction()))
+      AnimationUtils::TimingFunctionToComputedTimingFunction(
+           animation.easingFunction())
     };
     InfallibleTArray<Maybe<ComputedTimingFunction>>& functions =
       data->mFunctions;
     InfallibleTArray<RefPtr<RawServoAnimationValue>>& startValues =
       data->mStartValues;
     InfallibleTArray<RefPtr<RawServoAnimationValue>>& endValues =
       data->mEndValues;
 
--- a/gfx/layers/LayerTreeInvalidation.cpp
+++ b/gfx/layers/LayerTreeInvalidation.cpp
@@ -341,17 +341,17 @@ struct ContainerLayerProperties : public
 {
   explicit ContainerLayerProperties(ContainerLayer* aLayer)
     : LayerPropertiesBase(aLayer)
     , mPreXScale(aLayer->GetPreXScale())
     , mPreYScale(aLayer->GetPreYScale())
   {
     for (Layer* child = aLayer->GetFirstChild(); child; child = child->GetNextSibling()) {
       child->CheckCanary();
-      mChildren.AppendElement(std::move(CloneLayerTreePropertiesInternal(child)));
+      mChildren.AppendElement(CloneLayerTreePropertiesInternal(child));
     }
   }
 
 protected:
   ContainerLayerProperties(const ContainerLayerProperties& a) = delete;
   ContainerLayerProperties& operator=(const ContainerLayerProperties& a) = delete;
 
 public:
--- a/gfx/layers/PaintThread.cpp
+++ b/gfx/layers/PaintThread.cpp
@@ -282,16 +282,18 @@ PaintThread::PrepareBuffer(CapturedBuffe
   SyncRunnable::DispatchToThread(sThread, task);
 #endif
 }
 
 void
 PaintThread::AsyncPrepareBuffer(CompositorBridgeChild* aBridge,
                                 CapturedBufferState* aState)
 {
+  AUTO_PROFILER_LABEL("PaintThread::AsyncPrepareBuffer", GRAPHICS);
+
   MOZ_ASSERT(IsOnPaintThread());
   MOZ_ASSERT(aState);
 
   if (!aState->PrepareBuffer()) {
     gfxCriticalNote << "Failed to prepare buffers on the paint thread.";
   }
 
   if (aBridge->NotifyFinishedAsyncWorkerPaint(aState)) {
@@ -333,16 +335,18 @@ PaintThread::PaintContents(CapturedPaint
 #endif
 }
 
 void
 PaintThread::AsyncPaintContents(CompositorBridgeChild* aBridge,
                                 CapturedPaintState* aState,
                                 PrepDrawTargetForPaintingCallback aCallback)
 {
+  AUTO_PROFILER_LABEL("PaintThread::AsyncPaintContents", GRAPHICS);
+
   MOZ_ASSERT(IsOnPaintThread());
   MOZ_ASSERT(aState);
 
   DrawTarget* target = aState->mTargetDual;
   DrawTargetCapture* capture = aState->mCapture;
 
   Matrix oldTransform = target->GetTransform();
   bool oldPermitsSubpixelAA = target->GetPermitSubpixelAA();
@@ -405,16 +409,18 @@ PaintThread::PaintTiledContents(Captured
   SyncRunnable::DispatchToThread(mPaintWorkers, task);
 #endif
 }
 
 void
 PaintThread::AsyncPaintTiledContents(CompositorBridgeChild* aBridge,
                                      CapturedTiledPaintState* aState)
 {
+  AUTO_PROFILER_LABEL("PaintThread::AsyncPaintTiledContents", GRAPHICS);
+  
   MOZ_ASSERT(IsOnPaintWorkerThread());
   MOZ_ASSERT(aState);
 
   for (auto& copy : aState->mCopies) {
     copy.CopyBuffer();
   }
 
   for (auto& clear : aState->mClears) {
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -2604,31 +2604,36 @@ APZCTreeManager::BuildOverscrollHandoffC
 
 void
 APZCTreeManager::SetLongTapEnabled(bool aLongTapEnabled)
 {
   APZThreadUtils::AssertOnControllerThread();
   GestureEventListener::SetLongTapEnabled(aLongTapEnabled);
 }
 
-RefPtr<HitTestingTreeNode>
-APZCTreeManager::FindScrollThumbNode(const AsyncDragMetrics& aDragMetrics)
+void
+APZCTreeManager::FindScrollThumbNode(const AsyncDragMetrics& aDragMetrics,
+                                     HitTestingTreeNodeAutoLock& aOutThumbNode)
 {
   if (!aDragMetrics.mDirection) {
     // The AsyncDragMetrics has not been initialized yet - there will be
     // no matching node, so don't bother searching the tree.
-    return RefPtr<HitTestingTreeNode>();
+    return;
   }
 
   RecursiveMutexAutoLock lock(mTreeLock);
 
-  return DepthFirstSearch<ReverseIterator>(mRootNode.get(),
+  RefPtr<HitTestingTreeNode> result = DepthFirstSearch<ReverseIterator>(
+      mRootNode.get(),
       [&aDragMetrics](HitTestingTreeNode* aNode) {
         return aNode->MatchesScrollDragMetrics(aDragMetrics);
       });
+  if (result) {
+    aOutThumbNode.Initialize(lock, result.forget(), mTreeLock);
+  }
 }
 
 AsyncPanZoomController*
 APZCTreeManager::GetTargetApzcForNode(HitTestingTreeNode* aNode)
 {
   for (const HitTestingTreeNode* n = aNode;
        n && n->GetLayersId() == aNode->GetLayersId();
        n = n->GetParent()) {
--- a/gfx/layers/apz/src/APZCTreeManager.h
+++ b/gfx/layers/apz/src/APZCTreeManager.h
@@ -372,19 +372,20 @@ public:
 
   /**
    * Returns the current dpi value in use.
    */
   float GetDPI() const;
 
   /**
    * Find the hit testing node for the scrollbar thumb that matches these
-   * drag metrics.
+   * drag metrics. Initializes aOutThumbNode with the node, if there is one.
    */
-  RefPtr<HitTestingTreeNode> FindScrollThumbNode(const AsyncDragMetrics& aDragMetrics);
+  void FindScrollThumbNode(const AsyncDragMetrics& aDragMetrics,
+                           HitTestingTreeNodeAutoLock& aOutThumbNode);
 
   /**
    * Sets allowed touch behavior values for current touch-session for specific
    * input block (determined by aInputBlock).
    * Should be invoked by the widget. Each value of the aValues arrays
    * corresponds to the different touch point that is currently active.
    * Must be called after receiving the TOUCH_START event that starts the
    * touch-session.
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -995,18 +995,18 @@ nsEventStatus AsyncPanZoomController::Ha
   }
 
   if (aEvent.mType == MouseInput::MouseType::MOUSE_UP) {
     SetState(NOTHING);
     ScrollSnap();
     return nsEventStatus_eConsumeNoDefault;
   }
 
-  RefPtr<HitTestingTreeNode> node =
-    GetApzcTreeManager()->FindScrollThumbNode(aDragMetrics);
+  HitTestingTreeNodeAutoLock node;
+  GetApzcTreeManager()->FindScrollThumbNode(aDragMetrics, node);
   if (!node) {
     return nsEventStatus_eConsumeNoDefault;
   }
 
   if (aEvent.mType == MouseInput::MouseType::MOUSE_DOWN) {
     SetState(SCROLLBAR_DRAG);
   }
 
--- a/gfx/layers/apz/src/HitTestingTreeNode.cpp
+++ b/gfx/layers/apz/src/HitTestingTreeNode.cpp
@@ -19,17 +19,17 @@ namespace layers {
 
 using gfx::CompositorHitTestInfo;
 
 HitTestingTreeNode::HitTestingTreeNode(AsyncPanZoomController* aApzc,
                                        bool aIsPrimaryHolder,
                                        LayersId aLayersId)
   : mApzc(aApzc)
   , mIsPrimaryApzcHolder(aIsPrimaryHolder)
-  , mLocked(false)
+  , mLockCount(0)
   , mLayersId(aLayersId)
   , mScrollbarAnimationId(0)
   , mFixedPosTarget(FrameMetrics::NULL_SCROLL_ID)
   , mIsBackfaceHidden(false)
   , mOverride(EventRegionsOverride::NoOverride)
 {
   if (mIsPrimaryApzcHolder) {
     MOZ_ASSERT(mApzc);
@@ -69,17 +69,17 @@ HitTestingTreeNode::Destroy()
     }
     mApzc = nullptr;
   }
 }
 
 bool
 HitTestingTreeNode::IsRecyclable(const RecursiveMutexAutoLock& aProofOfTreeLock)
 {
-  return !(IsPrimaryHolder() || mLocked);
+  return !(IsPrimaryHolder() || (mLockCount > 0));
 }
 
 void
 HitTestingTreeNode::SetLastChild(HitTestingTreeNode* aChild)
 {
   mLastChild = aChild;
   if (aChild) {
     aChild->mParent = this;
@@ -405,25 +405,24 @@ HitTestingTreeNode::SetApzcParent(AsyncP
   } else {
     MOZ_ASSERT(GetApzc()->GetParent() == aParent);
   }
 }
 
 void
 HitTestingTreeNode::Lock(const RecursiveMutexAutoLock& aProofOfTreeLock)
 {
-  MOZ_ASSERT(!mLocked);
-  mLocked = true;
+  mLockCount++;
 }
 
 void
 HitTestingTreeNode::Unlock(const RecursiveMutexAutoLock& aProofOfTreeLock)
 {
-  MOZ_ASSERT(mLocked);
-  mLocked = false;
+  MOZ_ASSERT(mLockCount > 0);
+  mLockCount--;
 }
 
 HitTestingTreeNodeAutoLock::HitTestingTreeNodeAutoLock()
   : mTreeMutex(nullptr)
 {
 }
 
 HitTestingTreeNodeAutoLock::~HitTestingTreeNodeAutoLock()
--- a/gfx/layers/apz/src/HitTestingTreeNode.h
+++ b/gfx/layers/apz/src/HitTestingTreeNode.h
@@ -153,17 +153,17 @@ private:
   void SetApzcParent(AsyncPanZoomController* aApzc);
 
   RefPtr<HitTestingTreeNode> mLastChild;
   RefPtr<HitTestingTreeNode> mPrevSibling;
   RefPtr<HitTestingTreeNode> mParent;
 
   RefPtr<AsyncPanZoomController> mApzc;
   bool mIsPrimaryApzcHolder;
-  bool mLocked;
+  int mLockCount;
 
   LayersId mLayersId;
 
   // This is only set to non-zero if WebRender is enabled, and only for HTTNs
   // where IsScrollThumbNode() returns true. It holds the animation id that we
   // use to move the thumb node to reflect async scrolling.
   uint64_t mScrollbarAnimationId;
 
--- a/gfx/layers/apz/test/mochitest/apz_test_utils.js
+++ b/gfx/layers/apz/test/mochitest/apz_test_utils.js
@@ -537,16 +537,41 @@ function hitTest(point) {
   dump("Hit-testing point (" + point.x + ", " + point.y + ")\n");
   utils.sendMouseEvent("MozMouseHittest", point.x, point.y, 0, 0, 0, true, 0, 0, true, true);
   var data = utils.getCompositorAPZTestData();
   ok(data.hitResults.length >= 1, "Expected at least one hit result in the APZTestData");
   var result = data.hitResults[data.hitResults.length - 1];
   return { hitInfo: result.hitResult, scrollId: result.scrollId };
 }
 
+// Returns a canonical stringification of the hitInfo bitfield.
+function hitInfoToString(hitInfo) {
+  var strs = [];
+  for (var flag in APZHitResultFlags) {
+    if ((hitInfo & APZHitResultFlags[flag]) != 0) {
+      strs.push(flag);
+    }
+  }
+  if (strs.length == 0) {
+    return "INVISIBLE";
+  }
+  strs.sort(function(a, b) {
+    return APZHitResultFlags[a] - APZHitResultFlags[b];
+  });
+  return strs.join(" | ");
+}
+
+// Takes an object returned by hitTest, along with the expected values, and
+// asserts that they match. Notably, it uses hitInfoToString to provide a
+// more useful message for the case that the hit info doesn't match
+function checkHitResult(hitResult, expectedHitInfo, expectedScrollId, desc) {
+  is(hitInfoToString(hitResult.hitInfo), hitInfoToString(expectedHitInfo), desc + " hit info");
+  is(hitResult.scrollId, expectedScrollId, desc + " scrollid");
+}
+
 // Symbolic constants used by hitTestScrollbar().
 var ScrollbarTrackLocation = {
     START: 1,
     END: 2
 };
 var LayerState = {
     ACTIVE: 1,
     INACTIVE: 2
@@ -592,61 +617,52 @@ function hitTestScrollbar(params) {
   // The direction flag (APZHitResultFlags.SCROLLBAR_VERTICAL) is added in
   // later, for the vertical test only.
   // The APZHitResultFlags.SCROLLBAR flag will be present regardless of whether
   // the layer is active or inactive because we force layerization of scrollbar
   // tracks. Unfortunately not forcing the layerization results in different
   // behaviour on different platforms which makes testing harder.
   var expectedHitInfo = APZHitResultFlags.VISIBLE | APZHitResultFlags.SCROLLBAR;
   if (params.expectThumb) {
-    // WebRender will hit-test scroll thumbs even inside inactive scrollframes,
-    // because the hit-test is based on display items and we do in fact generate
-    // the display items for the scroll thumb. The user-observed behaviour is
-    // going to be unaffected because the dispatch-to-content flag will also be
-    // set on these thumbs so it's not like APZ will allow async-scrolling them
-    // before the scrollframe has been activated/layerized. In non-WebRender we
-    // do not generate the layers for thumbs on inactive scrollframes, so the
-    // hit test will be accordingly different.
+    // We do not generate the layers for thumbs on inactive scrollframes.
     expectedHitInfo |= APZHitResultFlags.DISPATCH_TO_CONTENT;
-    if (config.isWebRender || params.layerState == LayerState.ACTIVE) {
-        expectedHitInfo |= APZHitResultFlags.SCROLLBAR_THUMB;
+    if (params.layerState == LayerState.ACTIVE) {
+      expectedHitInfo |= APZHitResultFlags.SCROLLBAR_THUMB;
     }
   }
 
   var scrollframeMsg = (params.layerState == LayerState.ACTIVE)
     ? "active scrollframe" : "inactive scrollframe";
 
   // Hit-test the targeted areas, assuming we don't have overlay scrollbars
   // with zero dimensions.
   if (params.directions.vertical && verticalScrollbarWidth > 0) {
     var verticalScrollbarPoint = {
         x: boundingClientRect.right - (verticalScrollbarWidth / 2),
         y: (params.trackLocation == ScrollbarTrackLocation.START)
              ? (boundingClientRect.y + scrollbarArrowButtonHeight + 5)
              : (boundingClientRect.bottom - horizontalScrollbarHeight - scrollbarArrowButtonHeight - 5)
     };
-    var {hitInfo, scrollId} = hitTest(verticalScrollbarPoint);
-    is(hitInfo, expectedHitInfo | APZHitResultFlags.SCROLLBAR_VERTICAL,
-       scrollframeMsg + " - vertical scrollbar hit info");
-    is(scrollId, params.expectedScrollId,
-       scrollframeMsg + " - vertical scrollbar scrollid");
+    checkHitResult(hitTest(verticalScrollbarPoint),
+                   expectedHitInfo | APZHitResultFlags.SCROLLBAR_VERTICAL,
+                   params.expectedScrollId,
+                   scrollframeMsg + " - vertical scrollbar");
   }
 
   if (params.directions.horizontal && horizontalScrollbarHeight > 0) {
     var horizontalScrollbarPoint = {
         x: (params.trackLocation == ScrollbarTrackLocation.START)
              ? (boundingClientRect.x + scrollbarArrowButtonWidth + 5)
              : (boundingClientRect.right - verticalScrollbarWidth - scrollbarArrowButtonWidth - 5),
         y: boundingClientRect.bottom - (horizontalScrollbarHeight / 2),
     };
-    var {hitInfo, scrollId} = hitTest(horizontalScrollbarPoint);
-    is(hitInfo, expectedHitInfo,
-       scrollframeMsg + " - horizontal scrollbar hit info");
-    is(scrollId, params.expectedScrollId,
-       scrollframeMsg + " - horizontal scrollbar scrollid");
+    checkHitResult(hitTest(horizontalScrollbarPoint),
+                   expectedHitInfo,
+                   params.expectedScrollId,
+                   scrollframeMsg + " - horizontal scrollbar");
   }
 }
 
 var ApzCleanup = {
   _cleanups: [],
 
   register: function(func) {
     if (this._cleanups.length == 0) {
--- a/gfx/layers/apz/test/mochitest/helper_hittest_basic.html
+++ b/gfx/layers/apz/test/mochitest/helper_hittest_basic.html
@@ -19,30 +19,28 @@
 
 function* test(testDriver) {
   var config = getHitTestConfig();
   var utils = config.utils;
 
   var scroller = document.getElementById('scroller');
   var apzaware = document.getElementById('apzaware');
 
-  var {hitInfo, scrollId} = hitTest(centerOf(scroller));
-  is(hitInfo, APZHitResultFlags.VISIBLE | APZHitResultFlags.DISPATCH_TO_CONTENT,
-     "inactive scrollframe hit info");
-  is(scrollId, utils.getViewId(document.scrollingElement),
-     "inactive scrollframe scrollid");
+  checkHitResult(hitTest(centerOf(scroller)),
+                 APZHitResultFlags.VISIBLE | APZHitResultFlags.DISPATCH_TO_CONTENT,
+                 utils.getViewId(document.scrollingElement),
+                 "inactive scrollframe");
 
   // The apz-aware div (which has a non-passive wheel listener) is not visible
   // and so the hit-test should just return the root scrollframe area that's
   // covering it
-  var {hitInfo, scrollId} = hitTest(centerOf(apzaware));
-  is(hitInfo, APZHitResultFlags.VISIBLE,
-     "inactive scrollframe - apzaware block hit info");
-  is(scrollId, utils.getViewId(document.scrollingElement),
-     "inactive scrollframe - apzaware block scrollid");
+  checkHitResult(hitTest(centerOf(apzaware)),
+                 APZHitResultFlags.VISIBLE,
+                 utils.getViewId(document.scrollingElement),
+                 "inactive scrollframe - apzaware block");
 
   // Hit test where the scroll thumbs should be.
   hitTestScrollbar({
     element: scroller,
     directions: { vertical: true, horizontal: true },
     expectedScrollId: utils.getViewId(document.scrollingElement),
     trackLocation: ScrollbarTrackLocation.START,
     expectThumb: true,
@@ -62,30 +60,28 @@ function* test(testDriver) {
     // WebRender hit-testing we need to make sure WR has the latest info).
     utils.advanceTimeAndRefresh(16);
     utils.restoreNormalRefresh();
   }
 
   var scrollerViewId = utils.getViewId(scroller);
 
   // Now we again test the middle of the scrollframe, which is now active
-  var {hitInfo, scrollId} = hitTest(centerOf(scroller));
-  is(hitInfo, APZHitResultFlags.VISIBLE,
-     "active scrollframe hit info");
-  is(scrollId, scrollerViewId,
-     "active scrollframe scrollid");
+  checkHitResult(hitTest(centerOf(scroller)),
+                 APZHitResultFlags.VISIBLE,
+                 scrollerViewId,
+                 "active scrollframe");
 
   // Test the apz-aware block
   var apzawarePosition = centerOf(apzaware); // main thread position
   apzawarePosition.y -= scrollY; // APZ position
-  var {hitInfo, scrollId} = hitTest(apzawarePosition);
-  is(hitInfo, APZHitResultFlags.VISIBLE | APZHitResultFlags.DISPATCH_TO_CONTENT,
-     "active scrollframe - apzaware block hit info");
-  is(scrollId, scrollerViewId,
-     "active scrollframe - apzaware block scrollid");
+  checkHitResult(hitTest(apzawarePosition),
+                 APZHitResultFlags.VISIBLE | APZHitResultFlags.DISPATCH_TO_CONTENT,
+                 scrollerViewId,
+                 "active scrollframe - apzaware block");
 
   // Test the scrollbars. Note that this time the vertical scrollthumb is
   // going to be at the bottom of the track. We'll test both the top and the
   // bottom.
 
   // top of scrollbar track
   hitTestScrollbar({
     element: scroller,
--- a/gfx/layers/apz/test/mochitest/helper_hittest_checkerboard.html
+++ b/gfx/layers/apz/test/mochitest/helper_hittest_checkerboard.html
@@ -39,21 +39,20 @@ function* test(testDriver) {
     utils.restoreNormalRefresh();
   }
 
   var scrollerViewId = utils.getViewId(scroller);
 
   // Hit-test the middle of the scrollframe, which is now inside the
   // checkerboarded region, and check that we hit the scrollframe and
   // not its parent.
-  var {hitInfo, scrollId} = hitTest(centerOf(scroller));
-  is(hitInfo, APZHitResultFlags.VISIBLE,
-     "active scrollframe hit info");
-  is(scrollId, scrollerViewId,
-     "active scrollframe scrollid");
+  checkHitResult(hitTest(centerOf(scroller)),
+                 APZHitResultFlags.VISIBLE,
+                 scrollerViewId,
+                 "active scrollframe");
 
   subtestDone();
 }
 
 waitUntilApzStable().then(runContinuation(test));
 
 </script>
 </html>
--- a/gfx/layers/apz/test/mochitest/mochitest.ini
+++ b/gfx/layers/apz/test/mochitest/mochitest.ini
@@ -86,9 +86,9 @@
   skip-if = (toolkit == 'android') || (toolkit == 'cocoa') # wheel events not supported on mobile, and synthesized wheel smooth-scrolling not supported on OS X
 [test_wheel_scroll.html]
   skip-if = (os == 'android') # wheel events not supported on mobile
 [test_wheel_transactions.html]
   skip-if = (toolkit == 'android') || webrender # wheel events not supported on mobile; bug 1429521 for webrender
 [test_group_overrides.html]
   skip-if = (toolkit == 'android') || webrender # wheel events not supported on mobile; bug 1429521 for webrender
 [test_group_hittest.html]
-  skip-if = (toolkit == 'android') || webrender # mouse events not supported on mobile; re-enable on webrender when bug 1391318 is fixed
+  skip-if = (toolkit == 'android') # mouse events not supported on mobile
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -488,16 +488,18 @@ ClientLayerManager::GetCompositorBridgeC
     return CompositorBridgeChild::Get();
   }
   return GetRemoteRenderer();
 }
 
 void
 ClientLayerManager::FlushAsyncPaints()
 {
+  AUTO_PROFILER_LABEL("ClientLayerManager::FlushAsyncPaints", GRAPHICS);
+
   CompositorBridgeChild* cbc = GetCompositorBridgeChild();
   if (cbc) {
     cbc->FlushAsyncPaints();
   }
 }
 
 void
 ClientLayerManager::ScheduleComposite()
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -492,26 +492,32 @@ CompositorBridgeParent::StopAndClearReso
       lts->mParent = nullptr;
     });
     mLayerManager->Destroy();
     mLayerManager = nullptr;
     mCompositionManager = nullptr;
   }
 
   if (mWrBridge) {
+    // Ensure we are not holding the sIndirectLayerTreesLock when destroying
+    // the WebRenderBridgeParent instances because it may block on WR.
+    std::vector<RefPtr<WebRenderBridgeParent>> indirectBridgeParents;
     { // scope lock
       MonitorAutoLock lock(*sIndirectLayerTreesLock);
-      ForEachIndirectLayerTree([] (LayerTreeState* lts, LayersId) -> void {
+      ForEachIndirectLayerTree([&] (LayerTreeState* lts, LayersId) -> void {
         if (lts->mWrBridge) {
-          lts->mWrBridge->Destroy();
-          lts->mWrBridge = nullptr;
+          indirectBridgeParents.emplace_back(lts->mWrBridge.forget());
         }
         lts->mParent = nullptr;
       });
     }
+    for (const RefPtr<WebRenderBridgeParent>& bridge : indirectBridgeParents) {
+      bridge->Destroy();
+    }
+    indirectBridgeParents.clear();
 
     // Ensure we are not holding the sIndirectLayerTreesLock here because we
     // are going to block on WR threads in order to shut it down properly.
     mWrBridge->Destroy();
     mWrBridge = nullptr;
     if (mAsyncImageManager) {
       mAsyncImageManager->Destroy();
       // WebRenderAPI should be already destructed
--- a/gfx/layers/ipc/CompositorVsyncScheduler.cpp
+++ b/gfx/layers/ipc/CompositorVsyncScheduler.cpp
@@ -139,17 +139,17 @@ CompositorVsyncScheduler::PostVRTask(Tim
   MonitorAutoLock lockVR(mCurrentVRListenerTaskMonitor);
   if (mCurrentVRListenerTask == nullptr && VRListenerThreadHolder::Loop()) {
     RefPtr<Runnable> task = NewRunnableMethod<TimeStamp>(
       "layers::CompositorVsyncScheduler::DispatchVREvents",
       this,
       &CompositorVsyncScheduler::DispatchVREvents,
       aTimestamp);
     mCurrentVRListenerTask = task;
-    VRListenerThreadHolder::Loop()->PostDelayedTask(std::move(task.forget()), 0);
+    VRListenerThreadHolder::Loop()->PostDelayedTask(task.forget(), 0);
   }
 }
 
 void
 CompositorVsyncScheduler::ScheduleComposition()
 {
   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   if (!mVsyncObserver) {
--- a/gfx/layers/ipc/UiCompositorControllerParent.cpp
+++ b/gfx/layers/ipc/UiCompositorControllerParent.cpp
@@ -24,17 +24,17 @@ typedef CompositorBridgeParent::LayerTre
 /* static */ RefPtr<UiCompositorControllerParent>
 UiCompositorControllerParent::GetFromRootLayerTreeId(const LayersId& aRootLayerTreeId)
 {
   RefPtr<UiCompositorControllerParent> controller;
   CompositorBridgeParent::CallWithIndirectShadowTree(aRootLayerTreeId,
     [&](LayerTreeState& aState) -> void {
       controller = aState.mUiControllerParent;
     });
-  return std::move(controller);
+  return controller;
 }
 
 /* static */ RefPtr<UiCompositorControllerParent>
 UiCompositorControllerParent::Start(const LayersId& aRootLayerTreeId, Endpoint<PUiCompositorControllerParent>&& aEndpoint)
 {
   RefPtr<UiCompositorControllerParent> parent = new UiCompositorControllerParent(aRootLayerTreeId);
 
   RefPtr<Runnable> task =
--- a/gfx/layers/wr/AsyncImagePipelineManager.cpp
+++ b/gfx/layers/wr/AsyncImagePipelineManager.cpp
@@ -315,28 +315,29 @@ AsyncImagePipelineManager::ApplyAsyncIma
 
     pipeline->mSentDL = true;
     pipeline->mIsChanged = false;
 
     wr::LayoutSize contentSize { pipeline->mScBounds.Width(), pipeline->mScBounds.Height() };
     wr::DisplayListBuilder builder(pipelineId, contentSize);
 
     float opacity = 1.0f;
-    builder.PushStackingContext(wr::ToLayoutRect(pipeline->mScBounds),
-                                nullptr,
-                                nullptr,
-                                &opacity,
-                                pipeline->mScTransform.IsIdentity() ? nullptr : &pipeline->mScTransform,
-                                wr::TransformStyle::Flat,
-                                nullptr,
-                                pipeline->mMixBlendMode,
-                                nsTArray<wr::WrFilterOp>(),
-                                true,
-                                // This is fine to do unconditionally because we only push images here.
-                                wr::GlyphRasterSpace::Screen());
+    Maybe<wr::WrClipId> referenceFrameId = builder.PushStackingContext(
+        wr::ToLayoutRect(pipeline->mScBounds),
+        nullptr,
+        nullptr,
+        &opacity,
+        pipeline->mScTransform.IsIdentity() ? nullptr : &pipeline->mScTransform,
+        wr::TransformStyle::Flat,
+        nullptr,
+        pipeline->mMixBlendMode,
+        nsTArray<wr::WrFilterOp>(),
+        true,
+        // This is fine to do unconditionally because we only push images here.
+        wr::GlyphRasterSpace::Screen());
 
     if (pipeline->mCurrentTexture && !keys.IsEmpty()) {
       LayoutDeviceRect rect(0, 0, pipeline->mCurrentTexture->GetSize().width, pipeline->mCurrentTexture->GetSize().height);
       if (pipeline->mScaleToSize.isSome()) {
         rect = LayoutDeviceRect(0, 0, pipeline->mScaleToSize.value().width, pipeline->mScaleToSize.value().height);
       }
 
       if (pipeline->mUseExternalImage) {
@@ -353,17 +354,17 @@ AsyncImagePipelineManager::ApplyAsyncIma
         builder.PushImage(wr::ToLayoutRect(rect),
                           wr::ToLayoutRect(rect),
                           true,
                           pipeline->mFilter,
                           keys[0]);
       }
     }
 
-    builder.PopStackingContext();
+    builder.PopStackingContext(referenceFrameId.isSome());
 
     wr::BuiltDisplayList dl;
     wr::LayoutSize builderContentSize;
     builder.Finalize(builderContentSize, dl);
     aTxn.SetDisplayList(gfx::Color(0.f, 0.f, 0.f, 0.f),
                         epoch,
                         LayerSize(pipeline->mScBounds.Width(), pipeline->mScBounds.Height()),
                         pipelineId, builderContentSize,
--- a/gfx/layers/wr/StackingContextHelper.cpp
+++ b/gfx/layers/wr/StackingContextHelper.cpp
@@ -80,17 +80,17 @@ StackingContextHelper::StackingContextHe
 
   mAffectsClipPositioning = mReferenceFrameId.isSome() ||
       (aBounds.TopLeft() != LayoutDevicePoint());
 }
 
 StackingContextHelper::~StackingContextHelper()
 {
   if (mBuilder) {
-    mBuilder->PopStackingContext();
+    mBuilder->PopStackingContext(mReferenceFrameId.isSome());
   }
 }
 
 const Maybe<nsDisplayTransform*>&
 StackingContextHelper::GetDeferredTransformItem() const
 {
   return mDeferredTransformItem;
 }
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -1610,16 +1610,24 @@ WebRenderBridgeParent::ClearResources()
     mAnimStorage->ClearById(*iter);
   }
   mActiveAnimations.clear();
   std::queue<CompositorAnimationIdsForEpoch>().swap(mCompositorAnimationsToDelete); // clear queue
 
   if (mWidget) {
     mCompositorScheduler->Destroy();
   }
+
+  // Before tearing down mApi we should make sure the above transaction has been
+  // flushed back to the render backend thread. Otherwise the cleanup messages
+  // that the WebRenderAPI destructor triggers can race ahead of the transaction
+  // (because it goes directly to the RB thread, bypassing the scene builder
+  // thread) and clear caches etc. that are still in use.
+  FlushSceneBuilds();
+
   mAnimStorage = nullptr;
   mCompositorScheduler = nullptr;
   mAsyncImageManager = nullptr;
   mApi = nullptr;
   mCompositorBridge = nullptr;
 }
 
 bool
--- a/gfx/layers/wr/WebRenderCommandBuilder.cpp
+++ b/gfx/layers/wr/WebRenderCommandBuilder.cpp
@@ -1538,17 +1538,17 @@ PaintByLayer(nsDisplayItem* aItem,
              nsDisplayListBuilder* aDisplayListBuilder,
              const RefPtr<BasicLayerManager>& aManager,
              gfxContext* aContext,
              const gfx::Size& aScale,
              const std::function<void()>& aPaintFunc)
 {
   UniquePtr<LayerProperties> props;
   if (aManager->GetRoot()) {
-    props = std::move(LayerProperties::CloneFrom(aManager->GetRoot()));
+    props = LayerProperties::CloneFrom(aManager->GetRoot());
   }
   FrameLayerBuilder* layerBuilder = new FrameLayerBuilder();
   layerBuilder->Init(aDisplayListBuilder, aManager, nullptr, true);
   layerBuilder->DidBeginRetainedLayerTransaction(aManager);
 
   aManager->SetDefaultTarget(aContext);
   aManager->BeginTransactionWithTarget(aContext);
   bool isInvalidated = false;
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -2549,17 +2549,17 @@ gfxFont::Measure(const gfxTextRun *aText
 {
     // If aBoundingBoxType is TIGHT_HINTED_OUTLINE_EXTENTS
     // and the underlying cairo font may be antialiased,
     // we need to create a copy in order to avoid getting cached extents.
     // This is only used by MathML layout at present.
     if (aBoundingBoxType == TIGHT_HINTED_OUTLINE_EXTENTS &&
         mAntialiasOption != kAntialiasNone) {
         if (!mNonAAFont) {
-            mNonAAFont = std::move(CopyWithAntialiasOption(kAntialiasNone));
+            mNonAAFont = CopyWithAntialiasOption(kAntialiasNone);
         }
         // if font subclass doesn't implement CopyWithAntialiasOption(),
         // it will return null and we'll proceed to use the existing font
         if (mNonAAFont) {
             return mNonAAFont->Measure(aTextRun, aStart, aEnd,
                                        TIGHT_HINTED_OUTLINE_EXTENTS,
                                        aRefDrawTarget, aSpacing, aOrientation);
         }
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -1829,17 +1829,17 @@ gfxPlatform::GetBackendPrefs() const
   data.mContentBitmask = BackendTypeBit(BackendType::CAIRO);
 #ifdef USE_SKIA
   data.mCanvasBitmask |= BackendTypeBit(BackendType::SKIA);
   data.mContentBitmask |= BackendTypeBit(BackendType::SKIA);
 #endif
   data.mCanvasDefault = BackendType::CAIRO;
   data.mContentDefault = BackendType::CAIRO;
 
-  return std::move(data);
+  return data;
 }
 
 void
 gfxPlatform::InitBackendPrefs(BackendPrefsData&& aPrefsData)
 {
     mPreferredCanvasBackend = GetCanvasBackendPref(aPrefsData.mCanvasBitmask);
     if (mPreferredCanvasBackend == BackendType::NONE) {
         mPreferredCanvasBackend = aPrefsData.mCanvasDefault;
--- a/gfx/thebes/gfxPlatformMac.cpp
+++ b/gfx/thebes/gfxPlatformMac.cpp
@@ -98,17 +98,17 @@ gfxPlatformMac::GetBackendPrefs() const
 {
   BackendPrefsData data;
 
   data.mCanvasBitmask = BackendTypeBit(BackendType::SKIA);
   data.mContentBitmask = BackendTypeBit(BackendType::SKIA);
   data.mCanvasDefault = BackendType::SKIA;
   data.mContentDefault = BackendType::SKIA;
 
-  return std::move(data);
+  return data;
 }
 
 bool
 gfxPlatformMac::UsesTiling() const
 {
     // The non-tiling ContentClient requires CrossProcessSemaphore which
     // isn't implemented for OSX.
     return true;
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -894,17 +894,17 @@ InvalidateWindowForDeviceReset(HWND aWnd
                  RDW_INVALIDATE|RDW_INTERNALPAINT|RDW_FRAME);
     return TRUE;
 }
 
 void
 gfxWindowsPlatform::SchedulePaintIfDeviceReset()
 {
   AUTO_PROFILER_LABEL("gfxWindowsPlatform::SchedulePaintIfDeviceReset",
-                      GRAPHICS);
+                      OTHER);
 
   DeviceResetReason resetReason = DeviceResetReason::OK;
   if (!DidRenderingDeviceReset(&resetReason)) {
     return;
   }
 
   gfxCriticalNote << "(gfxWindowsPlatform) Detected device reset: " << (int)resetReason;
 
--- a/gfx/webrender/examples/alpha_perf.rs
+++ b/gfx/webrender/examples/alpha_perf.rs
@@ -30,19 +30,17 @@ impl Example for App {
         _document_id: DocumentId,
     ) {
         let bounds = (0, 0).to(1920, 1080);
         let info = LayoutPrimitiveInfo::new(bounds);
 
         builder.push_stacking_context(
             &info,
             None,
-            None,
             TransformStyle::Flat,
-            None,
             MixBlendMode::Normal,
             Vec::new(),
             GlyphRasterSpace::Screen,
         );
 
         for _ in 0 .. self.rect_count {
             builder.push_rect(&info, ColorF::new(1.0, 1.0, 1.0, 0.05));
         }
--- a/gfx/webrender/examples/animation.rs
+++ b/gfx/webrender/examples/animation.rs
@@ -43,22 +43,29 @@ impl Example for App {
         // Create a 200x200 stacking context with an animated transform property.
         let bounds = (0, 0).to(200, 200);
 
         let filters = vec![
             FilterOp::Opacity(PropertyBinding::Binding(self.opacity_key, self.opacity), self.opacity),
         ];
 
         let info = LayoutPrimitiveInfo::new(bounds);
+        let reference_frame_id = builder.push_reference_frame(
+            &info,
+            Some(PropertyBinding::Binding(self.property_key, LayoutTransform::identity())),
+            None,
+        );
+
+        builder.push_clip_id(reference_frame_id);
+
+        let info = LayoutPrimitiveInfo::new(bounds);
         builder.push_stacking_context(
             &info,
             None,
-            Some(PropertyBinding::Binding(self.property_key, LayoutTransform::identity())),
             TransformStyle::Flat,
-            None,
             MixBlendMode::Normal,
             filters,
             GlyphRasterSpace::Screen,
         );
 
         let complex_clip = ComplexClipRegion {
             rect: bounds,
             radii: BorderRadius::uniform(50.0),
@@ -68,16 +75,19 @@ impl Example for App {
         builder.push_clip_id(clip_id);
 
         // Fill it with a white rect
         builder.push_rect(&info, ColorF::new(0.0, 1.0, 0.0, 1.0));
 
         builder.pop_clip_id();
 
         builder.pop_stacking_context();
+
+        builder.pop_clip_id();
+        builder.pop_reference_frame();
     }
 
     fn on_event(&mut self, win_event: winit::WindowEvent, api: &RenderApi, document_id: DocumentId) -> bool {
         match win_event {
             winit::WindowEvent::KeyboardInput {
                 input: winit::KeyboardInput {
                     state: winit::ElementState::Pressed,
                     virtual_keycode: Some(key),
--- a/gfx/webrender/examples/basic.rs
+++ b/gfx/webrender/examples/basic.rs
@@ -188,19 +188,17 @@ impl Example for App {
         _pipeline_id: PipelineId,
         _document_id: DocumentId,
     ) {
         let bounds = LayoutRect::new(LayoutPoint::zero(), builder.content_size());
         let info = LayoutPrimitiveInfo::new(bounds);
         builder.push_stacking_context(
             &info,
             None,
-            None,
             TransformStyle::Flat,
-            None,
             MixBlendMode::Normal,
             Vec::new(),
             GlyphRasterSpace::Screen,
         );
 
         let image_mask_key = api.generate_image_key();
         txn.add_image(
             image_mask_key,
--- a/gfx/webrender/examples/blob.rs
+++ b/gfx/webrender/examples/blob.rs
@@ -246,19 +246,17 @@ impl Example for App {
             None,
         );
 
         let bounds = api::LayoutRect::new(api::LayoutPoint::zero(), builder.content_size());
         let info = api::LayoutPrimitiveInfo::new(bounds);
         builder.push_stacking_context(
             &info,
             None,
-            None,
             api::TransformStyle::Flat,
-            None,
             api::MixBlendMode::Normal,
             Vec::new(),
             api::GlyphRasterSpace::Screen,
         );
 
         let info = api::LayoutPrimitiveInfo::new((30, 30).by(500, 500));
         builder.push_image(
             &info,
--- a/gfx/webrender/examples/document.rs
+++ b/gfx/webrender/examples/document.rs
@@ -64,17 +64,17 @@ impl App {
         ];
 
         for (pipeline_id, layer, color, offset) in init_data {
             let size = DeviceUintSize::new(250, 250);
             let bounds = DeviceUintRect::new(offset, size);
 
             let document_id = api.add_document(size, layer);
             let mut txn = Transaction::new();
-            txn.set_window_parameters(framebuffer_size, bounds, 1.0);
+            txn.set_window_parameters(framebuffer_size, bounds, device_pixel_ratio);
             txn.set_root_pipeline(pipeline_id);
             api.send_transaction(document_id, txn);
 
             self.documents.push(Document {
                 id: document_id,
                 pipeline_id,
                 content_rect: bounds.to_f32() / TypedScale::new(device_pixel_ratio),
                 color,
@@ -109,19 +109,17 @@ impl Example for App {
             let local_rect = LayoutRect::new(
                 LayoutPoint::zero(),
                 doc.content_rect.size,
             );
 
             builder.push_stacking_context(
                 &LayoutPrimitiveInfo::new(doc.content_rect),
                 None,
-                None,
                 TransformStyle::Flat,
-                None,
                 MixBlendMode::Normal,
                 Vec::new(),
                 GlyphRasterSpace::Screen,
             );
             builder.push_rect(
                 &LayoutPrimitiveInfo::new(local_rect),
                 doc.color,
             );
--- a/gfx/webrender/examples/frame_output.rs
+++ b/gfx/webrender/examples/frame_output.rs
@@ -97,19 +97,17 @@ impl App {
         let mut builder = DisplayListBuilder::new(
             document.pipeline_id,
             document.content_rect.size,
         );
 
         builder.push_stacking_context(
             &info,
             None,
-            None,
             TransformStyle::Flat,
-            None,
             MixBlendMode::Normal,
             Vec::new(),
             GlyphRasterSpace::Screen,
         );
 
         builder.push_rect(&info, ColorF::new(1.0, 1.0, 0.0, 1.0));
         builder.pop_stacking_context();
 
@@ -143,19 +141,17 @@ impl Example for App {
                 builder.content_size().width;
             self.init_output_document(api, DeviceUintSize::new(200, 200), device_pixel_ratio);
         }
 
         let info = LayoutPrimitiveInfo::new((100, 100).to(200, 200));
         builder.push_stacking_context(
             &info,
             None,
-            None,
             TransformStyle::Flat,
-            None,
             MixBlendMode::Normal,
             Vec::new(),
             GlyphRasterSpace::Screen,
         );
 
         builder.push_image(
             &info,
             info.rect.size,
--- a/gfx/webrender/examples/iframe.rs
+++ b/gfx/webrender/examples/iframe.rs
@@ -35,19 +35,17 @@ impl Example for App {
 
         let sub_pipeline_id = PipelineId(pipeline_id.0, 42);
         let mut sub_builder = DisplayListBuilder::new(sub_pipeline_id, sub_bounds.size);
 
         let info = LayoutPrimitiveInfo::new(sub_bounds);
         sub_builder.push_stacking_context(
             &info,
             None,
-            None,
             TransformStyle::Flat,
-            None,
             MixBlendMode::Normal,
             Vec::new(),
             GlyphRasterSpace::Screen,
         );
 
         // green rect visible == success
         sub_builder.push_rect(&info, ColorF::new(0.0, 1.0, 0.0, 1.0));
         sub_builder.pop_stacking_context();
@@ -57,30 +55,40 @@ impl Example for App {
             Epoch(0),
             None,
             sub_bounds.size,
             sub_builder.finalize(),
             true,
         );
         api.send_transaction(document_id, txn);
 
+        let info = LayoutPrimitiveInfo::new(sub_bounds);
+        let reference_frame_id = builder.push_reference_frame(
+            &info,
+            Some(PropertyBinding::Binding(PropertyBindingKey::new(42), LayoutTransform::identity())),
+            None,
+        );
+        builder.push_clip_id(reference_frame_id);
+
+
         // And this is for the root pipeline
         builder.push_stacking_context(
             &info,
             None,
-            Some(PropertyBinding::Binding(PropertyBindingKey::new(42), LayoutTransform::identity())),
             TransformStyle::Flat,
-            None,
             MixBlendMode::Normal,
             Vec::new(),
             GlyphRasterSpace::Screen,
         );
         // red rect under the iframe: if this is visible, things have gone wrong
         builder.push_rect(&info, ColorF::new(1.0, 0.0, 0.0, 1.0));
         builder.push_iframe(&info, sub_pipeline_id, false);
         builder.pop_stacking_context();
+
+        builder.pop_clip_id();
+        builder.pop_reference_frame();
     }
 }
 
 fn main() {
     let mut app = App {};
     boilerplate::main_wrapper(&mut app, None);
 }
--- a/gfx/webrender/examples/image_resize.rs
+++ b/gfx/webrender/examples/image_resize.rs
@@ -37,19 +37,17 @@ impl Example for App {
             None,
         );
 
         let bounds = (0, 0).to(512, 512);
         let info = LayoutPrimitiveInfo::new(bounds);
         builder.push_stacking_context(
             &info,
             None,
-            None,
             TransformStyle::Flat,
-            None,
             MixBlendMode::Normal,
             Vec::new(),
             GlyphRasterSpace::Screen,
         );
 
         let image_size = LayoutSize::new(100.0, 100.0);
 
         let info = LayoutPrimitiveInfo::with_clip_rect(
--- a/gfx/webrender/examples/multiwindow.rs
+++ b/gfx/webrender/examples/multiwindow.rs
@@ -175,19 +175,17 @@ impl Window {
         let mut txn = Transaction::new();
         let mut builder = DisplayListBuilder::new(self.pipeline_id, layout_size);
 
         let bounds = LayoutRect::new(LayoutPoint::zero(), builder.content_size());
         let info = LayoutPrimitiveInfo::new(bounds);
         builder.push_stacking_context(
             &info,
             None,
-            None,
             TransformStyle::Flat,
-            None,
             MixBlendMode::Normal,
             Vec::new(),
             GlyphRasterSpace::Screen,
         );
 
         let info = LayoutPrimitiveInfo::new(LayoutRect::new(
             LayoutPoint::new(100.0, 100.0),
             LayoutSize::new(100.0, 200.0)
--- a/gfx/webrender/examples/scrolling.rs
+++ b/gfx/webrender/examples/scrolling.rs
@@ -30,34 +30,30 @@ impl Example for App {
         _document_id: DocumentId,
     ) {
         let info = LayoutPrimitiveInfo::new(
             LayoutRect::new(LayoutPoint::zero(), builder.content_size())
         );
         builder.push_stacking_context(
             &info,
             None,
-            None,
             TransformStyle::Flat,
-            None,
             MixBlendMode::Normal,
             Vec::new(),
             GlyphRasterSpace::Screen,
         );
 
         if true {
             // scrolling and clips stuff
             // let's make a scrollbox
             let scrollbox = (0, 0).to(300, 400);
             builder.push_stacking_context(
                 &LayoutPrimitiveInfo::new((10, 10).by(0, 0)),
                 None,
-                None,
                 TransformStyle::Flat,
-                None,
                 MixBlendMode::Normal,
                 Vec::new(),
                 GlyphRasterSpace::Screen,
             );
             // set the scrolling clip
             let clip_id = builder.define_scroll_frame(
                 None,
                 (0, 0).by(1000, 1000),
--- a/gfx/webrender/examples/texture_cache_stress.rs
+++ b/gfx/webrender/examples/texture_cache_stress.rs
@@ -89,19 +89,17 @@ impl Example for App {
         _pipeline_id: PipelineId,
         _document_id: DocumentId,
     ) {
         let bounds = (0, 0).to(512, 512);
         let info = LayoutPrimitiveInfo::new(bounds);
         builder.push_stacking_context(
             &info,
             None,
-            None,
             TransformStyle::Flat,
-            None,
             MixBlendMode::Normal,
             Vec::new(),
             GlyphRasterSpace::Screen,
         );
 
         let x0 = 50.0;
         let y0 = 50.0;
         let image_size = LayoutSize::new(4.0, 4.0);
--- a/gfx/webrender/examples/yuv.rs
+++ b/gfx/webrender/examples/yuv.rs
@@ -84,19 +84,17 @@ impl Example for App {
         _pipeline_id: PipelineId,
         _document_id: DocumentId,
     ) {
         let bounds = LayoutRect::new(LayoutPoint::zero(), builder.content_size());
         let info = LayoutPrimitiveInfo::new(bounds);
         builder.push_stacking_context(
             &info,
             None,
-            None,
             TransformStyle::Flat,
-            None,
             MixBlendMode::Normal,
             Vec::new(),
             GlyphRasterSpace::Screen,
         );
 
         let yuv_chanel1 = api.generate_image_key();
         let yuv_chanel2 = api.generate_image_key();
         let yuv_chanel2_1 = api.generate_image_key();
--- a/gfx/webrender/res/clip_shared.glsl
+++ b/gfx/webrender/res/clip_shared.glsl
@@ -93,18 +93,8 @@ ClipVertexInfo write_clip_tile_vertex(Re
 
     init_transform_vs(vec4(local_clip_rect.p0, local_clip_rect.p0 + local_clip_rect.size));
 
     ClipVertexInfo vi = ClipVertexInfo(node_pos.xyw, actual_pos, local_clip_rect);
     return vi;
 }
 
 #endif //WR_VERTEX_SHADER
-
-#ifdef WR_FRAGMENT_SHADER
-
-//Note: identical to prim_shared
-float distance_to_line(vec2 p0, vec2 perp_dir, vec2 p) {
-    vec2 dir_to_p0 = p0 - p;
-    return dot(normalize(perp_dir), dir_to_p0);
-}
-
-#endif //WR_FRAGMENT_SHADER
--- a/gfx/webrender/res/cs_border_segment.glsl
+++ b/gfx/webrender/res/cs_border_segment.glsl
@@ -1,46 +1,75 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include shared,prim_shared,ellipse,shared_border
+#include shared,ellipse
 
-flat varying vec4 vColor0;
-flat varying vec4 vColor1;
+// For edges, the colors are the same. For corners, these
+// are the colors of each edge making up the corner.
+flat varying vec4 vColor0[2];
+flat varying vec4 vColor1[2];
+
+// A point + tangent defining the line where the edge
+// transition occurs. Used for corners only.
 flat varying vec4 vColorLine;
-flat varying int vFeatures;
-flat varying vec2 vClipCenter;
+
+// x = segment, y = styles, z = edge axes
+flat varying ivec3 vConfig;
+
+// xy = Local space position of the clip center.
+// zw = Scale the rect origin by this to get the outer
+// corner from the segment rectangle.
+flat varying vec4 vClipCenter_Sign;
+
+// An outer and inner elliptical radii for border
+// corner clipping.
 flat varying vec4 vClipRadii;
-flat varying vec2 vClipSign;
+
+// Reference point for determine edge clip lines.
+flat varying vec4 vEdgeReference;
 
+// Stores widths/2 and widths/3 to save doing this in FS.
+flat varying vec4 vPartialWidths;
+
+// Local space position
 varying vec2 vPos;
 
-#define CLIP_RADII      1
-#define MIX_COLOR       2
+#define SEGMENT_TOP_LEFT        0
+#define SEGMENT_TOP_RIGHT       1
+#define SEGMENT_BOTTOM_RIGHT    2
+#define SEGMENT_BOTTOM_LEFT     3
+#define SEGMENT_LEFT            4
+#define SEGMENT_TOP             5
+#define SEGMENT_RIGHT           6
+#define SEGMENT_BOTTOM          7
+
+// Border styles as defined in webrender_api/types.rs
+#define BORDER_STYLE_NONE         0
+#define BORDER_STYLE_SOLID        1
+#define BORDER_STYLE_DOUBLE       2
+#define BORDER_STYLE_DOTTED       3
+#define BORDER_STYLE_DASHED       4
+#define BORDER_STYLE_HIDDEN       5
+#define BORDER_STYLE_GROOVE       6
+#define BORDER_STYLE_RIDGE        7
+#define BORDER_STYLE_INSET        8
+#define BORDER_STYLE_OUTSET       9
 
 #ifdef WR_VERTEX_SHADER
 
 in vec2 aTaskOrigin;
 in vec4 aRect;
 in vec4 aColor0;
 in vec4 aColor1;
 in int aFlags;
 in vec2 aWidths;
 in vec2 aRadii;
 
-#define SEGMENT_TOP_LEFT        0
-#define SEGMENT_TOP_RIGHT       1
-#define SEGMENT_BOTTOM_RIGHT    2
-#define SEGMENT_BOTTOM_LEFT     3
-#define SEGMENT_LEFT            4
-#define SEGMENT_TOP             5
-#define SEGMENT_RIGHT           6
-#define SEGMENT_BOTTOM          7
-
 vec2 get_outer_corner_scale(int segment) {
     vec2 p;
 
     switch (segment) {
         case SEGMENT_TOP_LEFT:
             p = vec2(0.0, 0.0);
             break;
         case SEGMENT_TOP_RIGHT:
@@ -56,72 +85,257 @@ vec2 get_outer_corner_scale(int segment)
             // Should never get hit
             p = vec2(0.0);
             break;
     }
 
     return p;
 }
 
-void main(void) {
-    vec2 pos = aRect.xy + aRect.zw * aPosition.xy;
+vec4 mod_color(vec4 color, float f) {
+    return vec4(clamp(color.rgb * f, vec3(0.0), vec3(color.a)), color.a);
+}
+
+vec4[2] get_colors_for_side(vec4 color, int style) {
+    vec4 result[2];
+    const vec2 f = vec2(1.3, 0.7);
 
+    switch (style) {
+        case BORDER_STYLE_GROOVE:
+            result[0] = mod_color(color, f.x);
+            result[1] = mod_color(color, f.y);
+            break;
+        case BORDER_STYLE_RIDGE:
+            result[0] = mod_color(color, f.y);
+            result[1] = mod_color(color, f.x);
+            break;
+        default:
+            result[0] = color;
+            result[1] = color;
+            break;
+    }
+
+    return result;
+}
+
+void main(void) {
     int segment = aFlags & 0xff;
-    int style = (aFlags >> 8) & 0xff;
+    int style0 = (aFlags >> 8) & 0xff;
+    int style1 = (aFlags >> 16) & 0xff;
 
     vec2 outer_scale = get_outer_corner_scale(segment);
-    vec2 outer = aRect.xy + outer_scale * aRect.zw;
+    vec2 outer = outer_scale * aRect.zw;
     vec2 clip_sign = 1.0 - 2.0 * outer_scale;
 
-    vColor0 = aColor0;
-    vColor1 = aColor1;
-    vPos = pos;
-
-    vFeatures = 0;
-    vClipSign = clip_sign;
-    vClipCenter = outer + clip_sign * aRadii;
-    vClipRadii = vec4(aRadii, aRadii - aWidths);
-    vColorLine = vec4(0.0);
-
+    // Set some flags used by the FS to determine the
+    // orientation of the two edges in this corner.
+    ivec2 edge_axis;
+    // Derive the positions for the edge clips, which must be handled
+    // differently between corners and edges.
+    vec2 edge_reference;
     switch (segment) {
         case SEGMENT_TOP_LEFT:
+            edge_axis = ivec2(0, 1);
+            edge_reference = outer;
+            break;
         case SEGMENT_TOP_RIGHT:
+            edge_axis = ivec2(1, 0);
+            edge_reference = vec2(outer.x - aWidths.x, outer.y);
+            break;
         case SEGMENT_BOTTOM_RIGHT:
+            edge_axis = ivec2(0, 1);
+            edge_reference = outer - aWidths;
+            break;
         case SEGMENT_BOTTOM_LEFT:
-            vFeatures |= (CLIP_RADII | MIX_COLOR);
-            vColorLine = vec4(outer, aWidths.y * -clip_sign.y, aWidths.x * clip_sign.x);
+            edge_axis = ivec2(1, 0);
+            edge_reference = vec2(outer.x, outer.y - aWidths.y);
+            break;
+        case SEGMENT_TOP:
+        case SEGMENT_BOTTOM:
+            edge_axis = ivec2(1, 1);
+            edge_reference = vec2(0.0);
+            break;
+        case SEGMENT_LEFT:
+        case SEGMENT_RIGHT:
+        default:
+            edge_axis = ivec2(0, 0);
+            edge_reference = vec2(0.0);
             break;
+    }
+
+    vConfig = ivec3(
+        segment,
+        style0 | (style1 << 16),
+        edge_axis.x | (edge_axis.y << 16)
+    );
+    vPartialWidths = vec4(aWidths / 3.0, aWidths / 2.0);
+    vPos = aRect.zw * aPosition.xy;
+
+    vColor0 = get_colors_for_side(aColor0, style0);
+    vColor1 = get_colors_for_side(aColor1, style1);
+    vClipCenter_Sign = vec4(outer + clip_sign * aRadii, clip_sign);
+    vClipRadii = vec4(aRadii, max(aRadii - aWidths, 0.0));
+    vColorLine = vec4(outer, aWidths.y * -clip_sign.y, aWidths.x * clip_sign.x);
+    vEdgeReference = vec4(edge_reference, edge_reference + aWidths);
+
+    gl_Position = uTransform * vec4(aTaskOrigin + aRect.xy + vPos, 0.0, 1.0);
+}
+#endif
+
+#ifdef WR_FRAGMENT_SHADER
+vec4 evaluate_color_for_style_in_corner(
+    vec2 clip_relative_pos,
+    int style,
+    vec4 color[2],
+    vec4 clip_radii,
+    float mix_factor,
+    int segment,
+    float aa_range
+) {
+    switch (style) {
+        case BORDER_STYLE_DOUBLE: {
+            // Get the distances from 0.33 of the radii, and
+            // also 0.67 of the radii. Use these to form a
+            // SDF subtraction which will clip out the inside
+            // third of the rounded edge.
+            float d_radii_a = distance_to_ellipse(
+                clip_relative_pos,
+                clip_radii.xy - vPartialWidths.xy,
+                aa_range
+            );
+            float d_radii_b = distance_to_ellipse(
+                clip_relative_pos,
+                clip_radii.xy - 2.0 * vPartialWidths.xy,
+                aa_range
+            );
+            float d = min(-d_radii_a, d_radii_b);
+            float alpha = distance_aa(aa_range, d);
+            return alpha * color[0];
+        }
+        case BORDER_STYLE_GROOVE:
+        case BORDER_STYLE_RIDGE: {
+            float d = distance_to_ellipse(
+                clip_relative_pos,
+                clip_radii.xy - vPartialWidths.zw,
+                aa_range
+            );
+            float alpha = distance_aa(aa_range, d);
+            float swizzled_factor;
+            switch (segment) {
+                case SEGMENT_TOP_LEFT: swizzled_factor = 0.0; break;
+                case SEGMENT_TOP_RIGHT: swizzled_factor = mix_factor; break;
+                case SEGMENT_BOTTOM_RIGHT: swizzled_factor = 1.0; break;
+                case SEGMENT_BOTTOM_LEFT: swizzled_factor = 1.0 - mix_factor; break;
+                default: swizzled_factor = 0.0; break;
+            };
+            vec4 c0 = mix(color[1], color[0], swizzled_factor);
+            vec4 c1 = mix(color[0], color[1], swizzled_factor);
+            return mix(c0, c1, alpha);
+        }
         default:
             break;
     }
 
-    gl_Position = uTransform * vec4(aTaskOrigin + pos, 0.0, 1.0);
+    return color[0];
 }
-#endif
 
-#ifdef WR_FRAGMENT_SHADER
+vec4 evaluate_color_for_style_in_edge(
+    vec2 pos,
+    int style,
+    vec4 color[2],
+    float aa_range,
+    int edge_axis
+) {
+    switch (style) {
+        case BORDER_STYLE_DOUBLE: {
+            float d0 = -1.0;
+            float d1 = -1.0;
+            if (vPartialWidths[edge_axis] > 1.0) {
+                vec2 ref = vec2(
+                    vEdgeReference[edge_axis] + vPartialWidths[edge_axis],
+                    vEdgeReference[edge_axis+2] - vPartialWidths[edge_axis]
+                );
+                d0 = pos[edge_axis] - ref.x;
+                d1 = ref.y - pos[edge_axis];
+            }
+            float d = min(d0, d1);
+            float alpha = distance_aa(aa_range, d);
+            return alpha * color[0];
+        }
+        case BORDER_STYLE_GROOVE:
+        case BORDER_STYLE_RIDGE: {
+            float ref = vEdgeReference[edge_axis] + vPartialWidths[edge_axis+2];
+            float d = pos[edge_axis] - ref;
+            float alpha = distance_aa(aa_range, d);
+            return mix(color[0], color[1], alpha);
+        }
+        default:
+            break;
+    }
+
+    return color[0];
+}
+
 void main(void) {
     float aa_range = compute_aa_range(vPos);
     float d = -1.0;
+    vec4 color0, color1;
 
-    // Apply color mix
+    int segment = vConfig.x;
+    ivec2 style = ivec2(vConfig.y & 0xffff, vConfig.y >> 16);
+    ivec2 edge_axis = ivec2(vConfig.z & 0xffff, vConfig.z >> 16);
+
     float mix_factor = 0.0;
-    if ((vFeatures & MIX_COLOR) != 0) {
+    if (edge_axis.x != edge_axis.y) {
         float d_line = distance_to_line(vColorLine.xy, vColorLine.zw, vPos);
         mix_factor = distance_aa(aa_range, -d_line);
     }
 
-    // Apply clip radii
-    if ((vFeatures & CLIP_RADII) != 0) {
-        vec2 p = vPos - vClipCenter;
-        if (vClipSign.x * p.x < 0.0 && vClipSign.y * p.y < 0.0) {
-            float d_radii_a = distance_to_ellipse(p, vClipRadii.xy, aa_range);
-            float d_radii_b = distance_to_ellipse(p, vClipRadii.zw, aa_range);
-            float d_radii = max(d_radii_a, -d_radii_b);
-            d = max(d, d_radii);
-        }
+    // Check if inside corner clip-region
+    vec2 clip_relative_pos = vPos - vClipCenter_Sign.xy;
+    bool in_clip_region = all(lessThan(vClipCenter_Sign.zw * clip_relative_pos, vec2(0.0)));
+
+    if (in_clip_region) {
+        float d_radii_a = distance_to_ellipse(clip_relative_pos, vClipRadii.xy, aa_range);
+        float d_radii_b = distance_to_ellipse(clip_relative_pos, vClipRadii.zw, aa_range);
+        float d_radii = max(d_radii_a, -d_radii_b);
+        d = max(d, d_radii);
+
+        color0 = evaluate_color_for_style_in_corner(
+            clip_relative_pos,
+            style.x,
+            vColor0,
+            vClipRadii,
+            mix_factor,
+            segment,
+            aa_range
+        );
+        color1 = evaluate_color_for_style_in_corner(
+            clip_relative_pos,
+            style.y,
+            vColor1,
+            vClipRadii,
+            mix_factor,
+            segment,
+            aa_range
+        );
+    } else {
+        color0 = evaluate_color_for_style_in_edge(
+            vPos,
+            style.x,
+            vColor0,
+            aa_range,
+            edge_axis.x
+        );
+        color1 = evaluate_color_for_style_in_edge(
+            vPos,
+            style.y,
+            vColor1,
+            aa_range,
+            edge_axis.y
+        );
     }
 
     float alpha = distance_aa(aa_range, d);
-    vec4 color = mix(vColor0, vColor1, mix_factor);
+    vec4 color = mix(color0, color1, mix_factor);
     oFragColor = color * alpha;
 }
 #endif
--- a/gfx/webrender/res/prim_shared.glsl
+++ b/gfx/webrender/res/prim_shared.glsl
@@ -20,21 +20,16 @@ uniform sampler2DArray sCacheRGBA8;
 
 // An A8 target for standalone tasks that is available to all passes.
 uniform sampler2DArray sSharedCacheA8;
 
 vec2 clamp_rect(vec2 pt, RectWithSize rect) {
     return clamp(pt, rect.p0, rect.p0 + rect.size);
 }
 
-float distance_to_line(vec2 p0, vec2 perp_dir, vec2 p) {
-    vec2 dir_to_p0 = p0 - p;
-    return dot(normalize(perp_dir), dir_to_p0);
-}
-
 // TODO: convert back to RectWithEndPoint if driver issues are resolved, if ever.
 flat varying vec4 vClipMaskUvBounds;
 varying vec3 vClipMaskUv;
 
 
 #ifdef WR_VERTEX_SHADER
 
 #define VECS_PER_LOCAL_CLIP_RECT    1
--- a/gfx/webrender/res/shared.glsl
+++ b/gfx/webrender/res/shared.glsl
@@ -51,16 +51,71 @@
 
     // Fragment shader outputs
     #ifdef WR_FEATURE_DUAL_SOURCE_BLENDING
         layout(location = 0, index = 0) out vec4 oFragColor;
         layout(location = 0, index = 1) out vec4 oFragBlend;
     #else
         out vec4 oFragColor;
     #endif
+
+    #define EPSILON     0.0001
+
+    float distance_to_line(vec2 p0, vec2 perp_dir, vec2 p) {
+        vec2 dir_to_p0 = p0 - p;
+        return dot(normalize(perp_dir), dir_to_p0);
+    }
+
+    /// Find the appropriate half range to apply the AA approximation over.
+    /// This range represents a coefficient to go from one CSS pixel to half a device pixel.
+    float compute_aa_range(vec2 position) {
+        // The constant factor is chosen to compensate for the fact that length(fw) is equal
+        // to sqrt(2) times the device pixel ratio in the typical case. 0.5/sqrt(2) = 0.35355.
+        //
+        // This coefficient is chosen to ensure that any sample 0.5 pixels or more inside of
+        // the shape has no anti-aliasing applied to it (since pixels are sampled at their center,
+        // such a pixel (axis aligned) is fully inside the border). We need this so that antialiased
+        // curves properly connect with non-antialiased vertical or horizontal lines, among other things.
+        //
+        // Lines over a half-pixel away from the pixel center *can* intersect with the pixel square;
+        // indeed, unless they are horizontal or vertical, they are guaranteed to. However, choosing
+        // a nonzero area for such pixels causes noticeable artifacts at the junction between an anti-
+        // aliased corner and a straight edge.
+        //
+        // We may want to adjust this constant in specific scenarios (for example keep the principled
+        // value for straight edges where we want pixel-perfect equivalence with non antialiased lines
+        // when axis aligned, while selecting a larger and smoother aa range on curves).
+        return 0.35355 * length(fwidth(position));
+    }
+
+    /// Return the blending coefficient for distance antialiasing.
+    ///
+    /// 0.0 means inside the shape, 1.0 means outside.
+    ///
+    /// This cubic polynomial approximates the area of a 1x1 pixel square under a
+    /// line, given the signed Euclidean distance from the center of the square to
+    /// that line. Calculating the *exact* area would require taking into account
+    /// not only this distance but also the angle of the line. However, in
+    /// practice, this complexity is not required, as the area is roughly the same
+    /// regardless of the angle.
+    ///
+    /// The coefficients of this polynomial were determined through least-squares
+    /// regression and are accurate to within 2.16% of the total area of the pixel
+    /// square 95% of the time, with a maximum error of 3.53%.
+    ///
+    /// See the comments in `compute_aa_range()` for more information on the
+    /// cutoff values of -0.5 and 0.5.
+    float distance_aa(float aa_range, float signed_distance) {
+        float dist = 0.5 * signed_distance / aa_range;
+        if (dist <= -0.5 + EPSILON)
+            return 1.0;
+        if (dist >= 0.5 - EPSILON)
+            return 0.0;
+        return 0.5 + dist * (0.8431027 * dist * dist - 1.14453603);
+    }
 #endif
 
 //======================================================================================
 // Shared shader uniforms
 //======================================================================================
 #ifdef WR_FEATURE_TEXTURE_2D
 uniform sampler2D sColor0;
 uniform sampler2D sColor1;
--- a/gfx/webrender/res/shared_border.glsl
+++ b/gfx/webrender/res/shared_border.glsl
@@ -1,26 +1,26 @@
 /* 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/. */
 
-#ifdef WR_VERTEX_SHADER
-
 // Border styles as defined in webrender_api/types.rs
 #define BORDER_STYLE_NONE         0
 #define BORDER_STYLE_SOLID        1
 #define BORDER_STYLE_DOUBLE       2
 #define BORDER_STYLE_DOTTED       3
 #define BORDER_STYLE_DASHED       4
 #define BORDER_STYLE_HIDDEN       5
 #define BORDER_STYLE_GROOVE       6
 #define BORDER_STYLE_RIDGE        7
 #define BORDER_STYLE_INSET        8
 #define BORDER_STYLE_OUTSET       9
 
+#ifdef WR_VERTEX_SHADER
+
 struct Border {
     vec4 style;
     vec4 widths;
     vec4 colors[4];
     vec4 radii[2];
 };
 
 struct BorderCorners {
--- a/gfx/webrender/res/transform.glsl
+++ b/gfx/webrender/res/transform.glsl
@@ -1,74 +1,24 @@
 /* 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/. */
 
-#define EPSILON     0.0001
-
 flat varying vec4 vTransformBounds;
 
 #ifdef WR_VERTEX_SHADER
 
 void init_transform_vs(vec4 local_bounds) {
     vTransformBounds = local_bounds;
 }
 
 #endif //WR_VERTEX_SHADER
 
 #ifdef WR_FRAGMENT_SHADER
 
-/// Find the appropriate half range to apply the AA approximation over.
-/// This range represents a coefficient to go from one CSS pixel to half a device pixel.
-float compute_aa_range(vec2 position) {
-    // The constant factor is chosen to compensate for the fact that length(fw) is equal
-    // to sqrt(2) times the device pixel ratio in the typical case. 0.5/sqrt(2) = 0.35355.
-    //
-    // This coefficient is chosen to ensure that any sample 0.5 pixels or more inside of
-    // the shape has no anti-aliasing applied to it (since pixels are sampled at their center,
-    // such a pixel (axis aligned) is fully inside the border). We need this so that antialiased
-    // curves properly connect with non-antialiased vertical or horizontal lines, among other things.
-    //
-    // Lines over a half-pixel away from the pixel center *can* intersect with the pixel square;
-    // indeed, unless they are horizontal or vertical, they are guaranteed to. However, choosing
-    // a nonzero area for such pixels causes noticeable artifacts at the junction between an anti-
-    // aliased corner and a straight edge.
-    //
-    // We may want to adjust this constant in specific scenarios (for example keep the principled
-    // value for straight edges where we want pixel-perfect equivalence with non antialiased lines
-    // when axis aligned, while selecting a larger and smoother aa range on curves).
-    return 0.35355 * length(fwidth(position));
-}
-
-/// Return the blending coefficient for distance antialiasing.
-///
-/// 0.0 means inside the shape, 1.0 means outside.
-///
-/// This cubic polynomial approximates the area of a 1x1 pixel square under a
-/// line, given the signed Euclidean distance from the center of the square to
-/// that line. Calculating the *exact* area would require taking into account
-/// not only this distance but also the angle of the line. However, in
-/// practice, this complexity is not required, as the area is roughly the same
-/// regardless of the angle.
-///
-/// The coefficients of this polynomial were determined through least-squares
-/// regression and are accurate to within 2.16% of the total area of the pixel
-/// square 95% of the time, with a maximum error of 3.53%.
-///
-/// See the comments in `compute_aa_range()` for more information on the
-/// cutoff values of -0.5 and 0.5.
-float distance_aa(float aa_range, float signed_distance) {
-    float dist = 0.5 * signed_distance / aa_range;
-    if (dist <= -0.5 + EPSILON)
-        return 1.0;
-    if (dist >= 0.5 - EPSILON)
-        return 0.0;
-    return 0.5 + dist * (0.8431027 * dist * dist - 1.14453603);
-}
-
 float signed_distance_rect(vec2 pos, vec2 p0, vec2 p1) {
     vec2 d = max(p0 - pos, pos - p1);
     return length(max(vec2(0.0), d)) + min(0.0, max(d.x, d.y));
 }
 
 float init_transform_fs(vec2 local_pos) {
     // Get signed distance from local rect bounds.
     float d = signed_distance_rect(
--- a/gfx/webrender/src/border.rs
+++ b/gfx/webrender/src/border.rs
@@ -466,26 +466,26 @@ impl<'a> DisplayListFlattener<'a> {
         let top = &border.top;
         let bottom = &border.bottom;
 
         let brush_border_supported = [left, top, right, bottom].iter().all(|edge| {
             match edge.style {
                 BorderStyle::Solid |
                 BorderStyle::Hidden |
                 BorderStyle::None |
+                BorderStyle::Double |
                 BorderStyle::Inset |
+                BorderStyle::Groove |
+                BorderStyle::Ridge |
                 BorderStyle::Outset => {
                     true
                 }
 
-                BorderStyle::Double |
                 BorderStyle::Dotted |
-                BorderStyle::Dashed |
-                BorderStyle::Groove |
-                BorderStyle::Ridge => {
+                BorderStyle::Dashed => {
                     false
                 }
             }
         });
 
         if brush_border_supported {
             let prim = BrushPrimitive::new(
                 BrushKind::Border {
@@ -1011,31 +1011,38 @@ struct DotInfo {
 
 impl DotInfo {
     fn new(arc_pos: f32, diameter: f32) -> DotInfo {
         DotInfo { arc_pos, diameter }
     }
 }
 
 #[derive(Debug)]
+pub struct BorderSegmentInfo {
+    task_rect: DeviceRect,
+    segment: BorderSegment,
+    radius: DeviceSize,
+    widths: DeviceSize,
+}
+
+#[derive(Debug)]
 pub struct BorderRenderTaskInfo {
-    pub instances: Vec<BorderInstance>,
-    pub segments: Vec<BrushSegment>,
+    pub border_segments: Vec<BorderSegmentInfo>,
     pub size: DeviceIntSize,
 }
 
 impl BorderRenderTaskInfo {
     pub fn new(
         rect: &LayoutRect,
         border: &NormalBorder,
         widths: &BorderWidths,
         scale: LayoutToDeviceScale,
+        brush_segments: &mut Vec<BrushSegment>,
     ) -> Self {
-        let mut instances = Vec::new();
-        let mut segments = Vec::new();
+        let mut border_segments = Vec::new();
 
         let dp_width_top = (widths.top * scale.0).ceil();
         let dp_width_bottom = (widths.bottom * scale.0).ceil();
         let dp_width_left = (widths.left * scale.0).ceil();
         let dp_width_right = (widths.right * scale.0).ceil();
 
         let dp_corner_tl = (border.radius.top_left * scale).ceil();
         let dp_corner_tr = (border.radius.top_right * scale).ceil();
@@ -1083,219 +1090,258 @@ impl BorderRenderTaskInfo {
         let width_inner = 16.0;
         let height_inner = 16.0;
 
         let size = DeviceSize::new(
             dp_size_tl.width.max(dp_size_bl.width) + width_inner + dp_size_tr.width.max(dp_size_br.width),
             dp_size_tl.height.max(dp_size_tr.height) + height_inner + dp_size_bl.height.max(dp_size_br.height),
         );
 
-        // These modulate colors are not part of the specification. They
-        // are derived from the Gecko source code and experimentation, and
-        // used to modulate the colors in order to generate colors for
-        // the inset/outset and groove/ridge border styles.
-        let left_color = border.left.border_color(1.0, 2.0 / 3.0, 0.3, 0.7);
-        let top_color = border.top.border_color(1.0, 2.0 / 3.0, 0.3, 0.7);
-        let right_color = border.right.border_color(2.0 / 3.0, 1.0, 0.7, 0.3);
-        let bottom_color = border.bottom.border_color(2.0 / 3.0, 1.0, 0.7, 0.3);
-
         add_edge_segment(
             LayoutRect::from_floats(
                 rect.origin.x,
                 rect.origin.y + local_size_tl.height,
                 rect.origin.x + widths.left,
                 rect.origin.y + rect.size.height - local_size_bl.height,
             ),
             DeviceRect::from_floats(
                 0.0,
                 dp_size_tl.height,
                 dp_width_left,
                 size.height - dp_size_bl.height,
             ),
-            border.left.style,
-            left_color,
+            &border.left,
             BorderSegment::Left,
             EdgeAaSegmentMask::LEFT | EdgeAaSegmentMask::RIGHT,
-            &mut instances,
+            &mut border_segments,
             BrushFlags::SEGMENT_RELATIVE | BrushFlags::SEGMENT_REPEAT_Y,
-            &mut segments,
+            brush_segments,
         );
 
         add_edge_segment(
             LayoutRect::from_floats(
                 rect.origin.x + local_size_tl.width,
                 rect.origin.y,
                 rect.origin.x + rect.size.width - local_size_tr.width,
                 rect.origin.y + widths.top,
             ),
             DeviceRect::from_floats(
                 dp_size_tl.width,
                 0.0,
                 size.width - dp_size_tr.width,
                 dp_width_top,
             ),
-            border.top.style,
-            top_color,
+            &border.top,
             BorderSegment::Top,
             EdgeAaSegmentMask::TOP | EdgeAaSegmentMask::BOTTOM,
-            &mut instances,
+            &mut border_segments,
             BrushFlags::SEGMENT_RELATIVE | BrushFlags::SEGMENT_REPEAT_X,
-            &mut segments,
+            brush_segments,
         );
 
         add_edge_segment(
             LayoutRect::from_floats(
                 rect.origin.x + rect.size.width - widths.right,
                 rect.origin.y + local_size_tr.height,
                 rect.origin.x + rect.size.width,
                 rect.origin.y + rect.size.height - local_size_br.height,
             ),
             DeviceRect::from_floats(
                 size.width - dp_width_right,
                 dp_size_tr.height,
                 size.width,
                 size.height - dp_size_br.height,
             ),
-            border.right.style,
-            right_color,
+            &border.right,
             BorderSegment::Right,
             EdgeAaSegmentMask::RIGHT | EdgeAaSegmentMask::LEFT,
-            &mut instances,
+            &mut border_segments,
             BrushFlags::SEGMENT_RELATIVE | BrushFlags::SEGMENT_REPEAT_Y,
-            &mut segments,
+            brush_segments,
         );
 
         add_edge_segment(
             LayoutRect::from_floats(
                 rect.origin.x + local_size_bl.width,
                 rect.origin.y + rect.size.height - widths.bottom,
                 rect.origin.x + rect.size.width - local_size_br.width,
                 rect.origin.y + rect.size.height,
             ),
             DeviceRect::from_floats(
                 dp_size_bl.width,
                 size.height - dp_width_bottom,
                 size.width - dp_size_br.width,
                 size.height,
             ),
-            border.bottom.style,
-            bottom_color,
+            &border.bottom,
             BorderSegment::Bottom,
             EdgeAaSegmentMask::BOTTOM | EdgeAaSegmentMask::TOP,
-            &mut instances,
+            &mut border_segments,
             BrushFlags::SEGMENT_RELATIVE | BrushFlags::SEGMENT_REPEAT_X,
-            &mut segments,
+            brush_segments,
         );
 
         add_corner_segment(
             LayoutRect::from_floats(
                 rect.origin.x,
                 rect.origin.y,
                 rect.origin.x + local_size_tl.width,
                 rect.origin.y + local_size_tl.height,
             ),
             DeviceRect::from_floats(
                 0.0,
                 0.0,
                 dp_size_tl.width,
                 dp_size_tl.height,
             ),
-            border.left.style,
-            left_color,
-            border.top.style,
-            top_color,
+            &border.left,
+            &border.top,
             DeviceSize::new(dp_width_left, dp_width_top),
             dp_corner_tl,
             BorderSegment::TopLeft,
             EdgeAaSegmentMask::TOP | EdgeAaSegmentMask::LEFT,
-            &mut instances,
-            &mut segments,
+            &mut border_segments,
+            brush_segments,
         );
 
         add_corner_segment(
             LayoutRect::from_floats(
                 rect.origin.x + rect.size.width - local_size_tr.width,
                 rect.origin.y,
                 rect.origin.x + rect.size.width,
                 rect.origin.y + local_size_tr.height,
             ),
             DeviceRect::from_floats(
                 size.width - dp_size_tr.width,
                 0.0,
                 size.width,
                 dp_size_tr.height,
             ),
-            border.top.style,
-            top_color,
-            border.right.style,
-            right_color,
+            &border.top,
+            &border.right,
             DeviceSize::new(dp_width_right, dp_width_top),
             dp_corner_tr,
             BorderSegment::TopRight,
             EdgeAaSegmentMask::TOP | EdgeAaSegmentMask::RIGHT,
-            &mut instances,
-            &mut segments,
+            &mut border_segments,
+            brush_segments,
         );
 
         add_corner_segment(
             LayoutRect::from_floats(
                 rect.origin.x + rect.size.width - local_size_br.width,
                 rect.origin.y + rect.size.height - local_size_br.height,
                 rect.origin.x + rect.size.width,
                 rect.origin.y + rect.size.height,
             ),
             DeviceRect::from_floats(
                 size.width - dp_size_br.width,
                 size.height - dp_size_br.height,
                 size.width,
                 size.height,
             ),
-            border.right.style,
-            right_color,
-            border.bottom.style,
-            bottom_color,
+            &border.right,
+            &border.bottom,
             DeviceSize::new(dp_width_right, dp_width_bottom),
             dp_corner_br,
             BorderSegment::BottomRight,
             EdgeAaSegmentMask::BOTTOM | EdgeAaSegmentMask::RIGHT,
-            &mut instances,
-            &mut segments,
+            &mut border_segments,
+            brush_segments,
         );
 
         add_corner_segment(
             LayoutRect::from_floats(
                 rect.origin.x,
                 rect.origin.y + rect.size.height - local_size_bl.height,
                 rect.origin.x + local_size_bl.width,
                 rect.origin.y + rect.size.height,
             ),
             DeviceRect::from_floats(
                 0.0,
                 size.height - dp_size_bl.height,
                 dp_size_bl.width,
                 size.height,
             ),
-            border.bottom.style,
-            bottom_color,
-            border.left.style,
-            left_color,
+            &border.bottom,
+            &border.left,
             DeviceSize::new(dp_width_left, dp_width_bottom),
             dp_corner_bl,
             BorderSegment::BottomLeft,
             EdgeAaSegmentMask::BOTTOM | EdgeAaSegmentMask::LEFT,
-            &mut instances,
-            &mut segments,
+            &mut border_segments,
+            brush_segments,
         );
 
         BorderRenderTaskInfo {
-            segments,
-            instances,
+            border_segments,
             size: size.to_i32(),
         }
     }
+
+    pub fn build_instances(
+        &self,
+        border: &NormalBorder,
+    ) -> Vec<BorderInstance> {
+        let mut instances = Vec::new();
+
+        for info in &self.border_segments {
+            let (side0, side1, flip0, flip1) = match info.segment {
+                BorderSegment::Left => (&border.left, &border.left, false, false),
+                BorderSegment::Top => (&border.top, &border.top, false, false),
+                BorderSegment::Right => (&border.right, &border.right, true, true),
+                BorderSegment::Bottom => (&border.bottom, &border.bottom, true, true),
+                BorderSegment::TopLeft => (&border.left, &border.top, false, false),
+                BorderSegment::TopRight => (&border.top, &border.right, false, true),
+                BorderSegment::BottomRight => (&border.right, &border.bottom, true, true),
+                BorderSegment::BottomLeft => (&border.bottom, &border.left, true, false),
+            };
+
+            let style0 = if side0.style.is_hidden() {
+                side1.style
+            } else {
+                side0.style
+            };
+            let style1 = if side1.style.is_hidden() {
+                side0.style
+            } else {
+                side1.style
+            };
+
+            // These modulate colors are not part of the specification. They
+            // are derived from the Gecko source code and experimentation, and
+            // used to modulate the colors in order to generate colors for
+            // the inset/outset and groove/ridge border styles.
+            let color0 = if flip0 {
+                side0.border_color(2.0 / 3.0, 1.0, 0.7, 0.3)
+            } else {
+                side0.border_color(1.0, 2.0 / 3.0, 0.3, 0.7)
+            };
+
+            let color1 = if flip1 {
+                side1.border_color(2.0 / 3.0, 1.0, 0.7, 0.3)
+            } else {
+                side1.border_color(1.0, 2.0 / 3.0, 0.3, 0.7)
+            };
+
+            add_segment(
+                info.task_rect,
+                style0,
+                style1,
+                color0,
+                color1,
+                info.segment,
+                &mut instances,
+                info.widths,
+                info.radius,
+            );
+        }
+
+        instances
+    }
 }
 
 fn add_brush_segment(
     image_rect: LayoutRect,
     task_rect: DeviceRect,
     brush_flags: BrushFlags,
     edge_flags: EdgeAaSegmentMask,
     brush_segments: &mut Vec<BrushSegment>,
@@ -1342,105 +1388,77 @@ fn add_segment(
     };
 
     instances.push(base_instance);
 }
 
 fn add_corner_segment(
     image_rect: LayoutRect,
     task_rect: DeviceRect,
-    mut style0: BorderStyle,
-    color0: ColorF,
-    mut style1: BorderStyle,
-    color1: ColorF,
+    side0: &BorderSide,
+    side1: &BorderSide,
     widths: DeviceSize,
     radius: DeviceSize,
     segment: BorderSegment,
     edge_flags: EdgeAaSegmentMask,
-    instances: &mut Vec<BorderInstance>,
+    border_segments: &mut Vec<BorderSegmentInfo>,
     brush_segments: &mut Vec<BrushSegment>,
 ) {
-    // TODO(gw): This will need to be a bit more involved when
-    //           we support other border types here. For example,
-    //           groove / ridge borders will always need to
-    //           use two instances.
-
-    if color0.a <= 0.0 && color1.a <= 0.0 {
+    if side0.color.a <= 0.0 && side1.color.a <= 0.0 {
         return;
     }
 
     if widths.width <= 0.0 && widths.height <= 0.0 {
         return;
     }
 
-    let style0_hidden = style0 == BorderStyle::Hidden || style0 == BorderStyle::None;
-    let style1_hidden = style1 == BorderStyle::Hidden || style1 == BorderStyle::None;
-
-    if style0_hidden && style1_hidden {
+    if side0.style.is_hidden() && side1.style.is_hidden() {
         return;
     }
 
-    if style0_hidden {
-        style0 = style1;
-    }
-    if style1_hidden {
-        style1 = style0;
-    }
-
-    add_segment(
+    border_segments.push(BorderSegmentInfo {
         task_rect,
-        style0,
-        style1,
-        color0,
-        color1,
         segment,
-        instances,
+        radius,
         widths,
-        radius,
-    );
+    });
 
     add_brush_segment(
         image_rect,
         task_rect,
         BrushFlags::SEGMENT_RELATIVE,
         edge_flags,
         brush_segments,
     );
 }
 
 fn add_edge_segment(
     image_rect: LayoutRect,
     task_rect: DeviceRect,
-    style: BorderStyle,
-    color: ColorF,
+    side: &BorderSide,
     segment: BorderSegment,
     edge_flags: EdgeAaSegmentMask,
-    instances: &mut Vec<BorderInstance>,
+    border_segments: &mut Vec<BorderSegmentInfo>,
     brush_flags: BrushFlags,
     brush_segments: &mut Vec<BrushSegment>,
 ) {
-    if color.a <= 0.0 {
+    if side.color.a <= 0.0 {
         return;
     }
 
-    if style == BorderStyle::Hidden || style == BorderStyle::None {
+    if side.style.is_hidden() {
         return;
     }
 
-    add_segment(
+    border_segments.push(BorderSegmentInfo {
         task_rect,
-        style,
-        style,
-        color,
-        color,
         segment,
-        instances,
-        DeviceSize::zero(),
-        DeviceSize::zero(),
-    );
+        radius: DeviceSize::zero(),
+        widths: task_rect.size,
+    });
 
     add_brush_segment(
         image_rect,
         task_rect,
         brush_flags,
         edge_flags,
         brush_segments,
     );
--- a/gfx/webrender/src/display_list_flattener.rs
+++ b/gfx/webrender/src/display_list_flattener.rs
@@ -3,20 +3,20 @@
  * 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 api::{AlphaType, BorderDetails, BorderDisplayItem, BuiltDisplayListIter, ClipAndScrollInfo};
 use api::{ClipId, ColorF, ComplexClipRegion, DeviceIntPoint, DeviceIntRect, DeviceIntSize};
 use api::{DevicePixelScale, DeviceUintRect, DisplayItemRef, Epoch, ExtendMode, ExternalScrollId};
 use api::{FilterOp, FontInstanceKey, GlyphInstance, GlyphOptions, GlyphRasterSpace, GradientStop};
 use api::{IframeDisplayItem, ImageKey, ImageRendering, ItemRange, LayoutPoint};
-use api::{LayoutPrimitiveInfo, LayoutRect, LayoutVector2D, LayoutSize, LayoutTransform};
+use api::{LayoutPrimitiveInfo, LayoutRect, LayoutSize, LayoutTransform, LayoutVector2D};
 use api::{LineOrientation, LineStyle, LocalClip, NinePatchBorderSource, PipelineId};
-use api::{PropertyBinding, RepeatMode, ScrollFrameDisplayItem, ScrollSensitivity, Shadow};
-use api::{SpecificDisplayItem, StackingContext, StickyFrameDisplayItem, TexelRect};
+use api::{PropertyBinding, ReferenceFrame, RepeatMode, ScrollFrameDisplayItem, ScrollSensitivity};
+use api::{Shadow, SpecificDisplayItem, StackingContext, StickyFrameDisplayItem, TexelRect};
 use api::{TransformStyle, YuvColorSpace, YuvData};
 use app_units::Au;
 use clip::{ClipRegion, ClipSource, ClipSources, ClipStore};
 use clip_scroll_node::{ClipScrollNode, NodeType, StickyFrameInfo};
 use clip_scroll_tree::{ClipChainIndex, ClipScrollNodeIndex, ClipScrollTree};
 use euclid::{SideOffsets2D, vec2};
 use frame_builder::{FrameBuilder, FrameBuilderConfig};
 use glyph_rasterizer::FontInstance;
@@ -152,20 +152,16 @@ pub struct DisplayListFlattener<'a> {
 
     /// Used to track the latest flattened epoch for each pipeline.
     pipeline_epochs: Vec<(PipelineId, Epoch)>,
 
     /// A set of pipelines that the caller has requested be made available as
     /// output textures.
     output_pipelines: &'a FastHashSet<PipelineId>,
 
-    /// A list of replacements to make in order to properly handle fixed position
-    /// content as well as stacking contexts that create reference frames.
-    replacements: Vec<(ClipId, ClipId)>,
-
     /// The data structure that converting between ClipId and the various index
     /// types that the ClipScrollTree uses.
     id_to_index_mapper: ClipIdToIndexMapper,
 
     /// A stack of scroll nodes used during display list processing to properly
     /// parent new scroll nodes.
     reference_frame_stack: Vec<(ClipId, ClipScrollNodeIndex)>,
 
@@ -220,17 +216,16 @@ impl<'a> DisplayListFlattener<'a> {
             .and_then(|color| if color.a > 0.0 { Some(color) } else { None });
 
         let mut flattener = DisplayListFlattener {
             scene,
             clip_scroll_tree,
             font_instances,
             config: *frame_builder_config,
             pipeline_epochs: Vec::new(),
-            replacements: Vec::new(),
             output_pipelines,
             id_to_index_mapper: ClipIdToIndexMapper::default(),
             hit_testing_runs: recycle_vec(old_builder.hit_testing_runs),
             cached_gradients: recycle_vec(old_builder.cached_gradients),
             scrollbar_prims: recycle_vec(old_builder.scrollbar_prims),
             reference_frame_stack: Vec::new(),
             picture_stack: Vec::new(),
             shadow_stack: Vec::new(),
@@ -258,61 +253,36 @@ impl<'a> DisplayListFlattener<'a> {
         FrameBuilder::with_display_list_flattener(
             view.inner_rect,
             background_color,
             view.window_size,
             flattener
         )
     }
 
-    /// Since WebRender still handles fixed position and reference frame content internally
-    /// we need to apply this table of id replacements only to the id that affects the
-    /// position of a node. We can eventually remove this when clients start handling
-    /// reference frames themselves. This method applies these replacements.
-    fn apply_scroll_frame_id_replacement(&self, index: ClipId) -> ClipId {
-        match self.replacements.last() {
-            Some(&(to_replace, replacement)) if to_replace == index => replacement,
-            _ => index,
-        }
-    }
-
     fn get_complex_clips(
         &self,
         pipeline_id: PipelineId,
         complex_clips: ItemRange<ComplexClipRegion>,
     ) -> Vec<ComplexClipRegion> {
         if complex_clips.is_empty() {
             return vec![];
         }
-
-        self.scene
-            .pipelines
-            .get(&pipeline_id)
-            .expect("No display list?")
-            .display_list
-            .get(complex_clips)
-            .collect()
+        self.scene.get_display_list_for_pipeline(pipeline_id).get(complex_clips).collect()
     }
 
     fn get_clip_chain_items(
         &self,
         pipeline_id: PipelineId,
         items: ItemRange<ClipId>,
     ) -> Vec<ClipId> {
         if items.is_empty() {
             return vec![];
         }
-
-        self.scene
-            .pipelines
-            .get(&pipeline_id)
-            .expect("No display list?")
-            .display_list
-            .get(items)
-            .collect()
+        self.scene.get_display_list_for_pipeline(pipeline_id).get(items).collect()
     }
 
     fn flatten_root(&mut self, pipeline: &'a ScenePipeline, frame_size: &LayoutSize) {
         let pipeline_id = pipeline.pipeline_id;
         let reference_frame_info = self.id_to_index_mapper.simple_scroll_and_clip_chain(
             &ClipId::root_reference_frame(pipeline_id)
         );
 
@@ -374,16 +344,20 @@ impl<'a> DisplayListFlattener<'a> {
     ) {
         loop {
             let subtraversal = {
                 let item = match traversal.next() {
                     Some(item) => item,
                     None => break,
                 };
 
+                if SpecificDisplayItem::PopReferenceFrame == *item.item() {
+                    return;
+                }
+
                 if SpecificDisplayItem::PopStackingContext == *item.item() {
                     return;
                 }
 
                 self.flatten_item(
                     item,
                     pipeline_id,
                     reference_frame_relative_offset,
@@ -457,96 +431,81 @@ impl<'a> DisplayListFlattener<'a> {
             info.external_id,
             pipeline_id,
             &frame_rect,
             &content_rect.size,
             info.scroll_sensitivity,
         );
     }
 
+    fn flatten_reference_frame(
+        &mut self,
+        traversal: &mut BuiltDisplayListIter<'a>,
+        pipeline_id: PipelineId,
+        item: &DisplayItemRef,
+        reference_frame: &ReferenceFrame,
+        scroll_node_id: ClipId,
+        reference_frame_relative_offset: LayoutVector2D,
+    ) {
+        self.push_reference_frame(
+            reference_frame.id,
+            Some(scroll_node_id),
+            pipeline_id,
+            reference_frame.transform,
+            reference_frame.perspective,
+            reference_frame_relative_offset + item.rect().origin.to_vector(),
+        );
+
+        self.flatten_items(traversal, pipeline_id, LayoutVector2D::zero());
+
+        self.pop_reference_frame();
+    }
+
     fn flatten_stacking_context(
         &mut self,
         traversal: &mut BuiltDisplayListIter<'a>,
         pipeline_id: PipelineId,
         item: &DisplayItemRef,
         stacking_context: &StackingContext,
-        unreplaced_scroll_id: ClipId,
         scroll_node_id: ClipId,
-        mut reference_frame_relative_offset: LayoutVector2D,
+        reference_frame_relative_offset: LayoutVector2D,
         is_backface_visible: bool,
     ) {
         // Avoid doing unnecessary work for empty stacking contexts.
         if traversal.current_stacking_context_empty() {
             traversal.skip_current_stacking_context();
             return;
         }
 
         let composition_operations = {
             // TODO(optimization?): self.traversal.display_list()
-            let display_list = &self
-                .scene
-                .pipelines
-                .get(&pipeline_id)
-                .expect("No display list?!")
-                .display_list;
+            let display_list = self.scene.get_display_list_for_pipeline(pipeline_id);
             CompositeOps::new(
                 stacking_context.filter_ops_for_compositing(display_list, item.filters()),
                 stacking_context.mix_blend_mode_for_compositing(),
             )
         };
 
-        let bounds = item.rect();
-        reference_frame_relative_offset += bounds.origin.to_vector();
-
-        // If we have a transformation or a perspective, we should have been assigned a new
-        // reference frame id. This means this stacking context establishes a new reference frame.
-        // Descendant fixed position content will be positioned relative to us.
-        if let Some(reference_frame_id) = stacking_context.reference_frame_id {
-            debug_assert!(
-                stacking_context.transform.is_some() ||
-                stacking_context.perspective.is_some()
-            );
-
-            self.push_reference_frame(
-                reference_frame_id,
-                Some(scroll_node_id),
-                pipeline_id,
-                stacking_context.transform,
-                stacking_context.perspective,
-                reference_frame_relative_offset,
-            );
-            self.replacements.push((unreplaced_scroll_id, reference_frame_id));
-            reference_frame_relative_offset = LayoutVector2D::zero();
-        }
-
-        // We apply the replacements one more time in case we need to set it to a replacement
-        // that we just pushed above.
-        let final_scroll_node = self.apply_scroll_frame_id_replacement(unreplaced_scroll_id);
         self.push_stacking_context(
             pipeline_id,
             composition_operations,
             stacking_context.transform_style,
             is_backface_visible,
             false,
-            final_scroll_node,
+            scroll_node_id,
             stacking_context.clip_node_id,
             stacking_context.glyph_raster_space,
         );
 
         self.flatten_items(
             traversal,
             pipeline_id,
-            reference_frame_relative_offset,
+            reference_frame_relative_offset + item.rect().origin.to_vector(),
         );
 
-        if stacking_context.reference_frame_id.is_some() {
-            self.replacements.pop();
-            self.pop_reference_frame();
-        }
-
         self.pop_stacking_context();
     }
 
     fn flatten_iframe(
         &mut self,
         item: &DisplayItemRef,
         info: &IframeDisplayItem,
         clip_and_scroll_ids: &ClipAndScrollInfo,
@@ -603,20 +562,17 @@ impl<'a> DisplayListFlattener<'a> {
     }
 
     fn flatten_item<'b>(
         &'b mut self,
         item: DisplayItemRef<'a, 'b>,
         pipeline_id: PipelineId,
         reference_frame_relative_offset: LayoutVector2D,
     ) -> Option<BuiltDisplayListIter<'a>> {
-        let mut clip_and_scroll_ids = item.clip_and_scroll();
-        let unreplaced_scroll_id = clip_and_scroll_ids.scroll_node_id;
-        clip_and_scroll_ids.scroll_node_id =
-            self.apply_scroll_frame_id_replacement(clip_and_scroll_ids.scroll_node_id);
+        let clip_and_scroll_ids = item.clip_and_scroll();
         let clip_and_scroll = self.id_to_index_mapper.map_clip_and_scroll(&clip_and_scroll_ids);
 
         let prim_info = item.get_layout_primitive_info(&reference_frame_relative_offset);
         match *item.item() {
             SpecificDisplayItem::Image(ref info) => {
                 self.add_image(
                     clip_and_scroll,
                     &prim_info,
@@ -728,23 +684,35 @@ impl<'a> DisplayListFlattener<'a> {
             }
             SpecificDisplayItem::PushStackingContext(ref info) => {
                 let mut subtraversal = item.sub_iter();
                 self.flatten_stacking_context(
                     &mut subtraversal,
                     pipeline_id,
                     &item,
                     &info.stacking_context,
-                    unreplaced_scroll_id,
                     clip_and_scroll_ids.scroll_node_id,
                     reference_frame_relative_offset,
                     prim_info.is_backface_visible,
                 );
                 return Some(subtraversal);
             }
+            SpecificDisplayItem::PushReferenceFrame(ref info) => {
+                let mut subtraversal = item.sub_iter();
+                self.flatten_reference_frame(
+                    &mut subtraversal,
+                    pipeline_id,
+                    &item,
+                    &info.reference_frame,
+                    clip_and_scroll_ids.scroll_node_id,
+                    reference_frame_relative_offset,
+                );
+                return Some(subtraversal);
+
+            }
             SpecificDisplayItem::Iframe(ref info) => {
                 self.flatten_iframe(
                     &item,
                     info,
                     &clip_and_scroll_ids,
                     &reference_frame_relative_offset
                 );
             }
@@ -787,17 +755,17 @@ impl<'a> DisplayListFlattener<'a> {
                     &clip_and_scroll_ids.scroll_node_id,
                     &reference_frame_relative_offset
                 );
             }
 
             // Do nothing; these are dummy items for the display list parser
             SpecificDisplayItem::SetGradientStops => {}
 
-            SpecificDisplayItem::PopStackingContext => {
+            SpecificDisplayItem::PopStackingContext | SpecificDisplayItem::PopReferenceFrame => {
                 unreachable!("Should have returned in parent method.")
             }
             SpecificDisplayItem::PushShadow(shadow) => {
                 let mut prim_info = prim_info.clone();
                 prim_info.rect = LayoutRect::zero();
                 self
                     .push_shadow(shadow, clip_and_scroll, &prim_info);
             }
--- a/gfx/webrender/src/glyph_rasterizer/pathfinder.rs
+++ b/gfx/webrender/src/glyph_rasterizer/pathfinder.rs
@@ -76,17 +76,16 @@ impl Deref for ThreadSafePathfinderFontC
 
 /// PathfinderFontContext can contain a *mut IDWriteFactory.
 /// However, since we know that it is wrapped in a Mutex, it is safe
 /// to assume that this struct is thread-safe
 unsafe impl Send for ThreadSafePathfinderFontContext {}
 unsafe impl Sync for ThreadSafePathfinderFontContext { }
 
 impl GlyphRasterizer {
-
     pub(in super) fn add_font_to_pathfinder(&mut self, font_key: &FontKey, template: &FontTemplate) {
         let font_contexts = Arc::clone(&self.font_contexts);
         debug!("add_font_to_pathfinder({:?})", font_key);
         font_contexts.lock_pathfinder_context().add_font(&font_key, &template);
     }
 
     pub fn get_cache_item_for_glyph(
         &self,
@@ -175,66 +174,65 @@ impl GlyphRasterizer {
                             cached_glyph_info = Some(glyph_info.clone())
                         }
                         GlyphCacheEntry::Blank | GlyphCacheEntry::Pending => {}
                     }
                 }
                 Entry::Vacant(_) => {}
             }
 
-            let cached_glyph_info = match cached_glyph_info {
-                Some(cached_glyph_info) => cached_glyph_info,
-                None => {
-                    let mut pathfinder_font_context = self.font_contexts.lock_pathfinder_context();
+            if cached_glyph_info.is_none() {
+                let mut pathfinder_font_context = self.font_contexts.lock_pathfinder_context();
 
-                    let pathfinder_font_instance = pathfinder_font_renderer::FontInstance {
-                        font_key: font.font_key.clone(),
-                        size: font.size,
-                    };
+                let pathfinder_font_instance = pathfinder_font_renderer::FontInstance {
+                    font_key: font.font_key.clone(),
+                    size: font.size,
+                };
 
-                    // TODO: pathfinder will need to support 2D subpixel offset