Merge mozilla-inbound to mozilla-central. a=merge
authorDorel Luca <dluca@mozilla.com>
Mon, 04 Jun 2018 21:11:34 +0300
changeset 421178 d8f180ab74921fd07a66d6868914a48e5f9ea797
parent 421177 3aaea88740602dbb570cec5df348beff7abf1842 (current diff)
parent 421136 5b15326286d466b5cf4889160cc09b59bdde08fd (diff)
child 421240 425c5899aa74427a1b34e2e6610b220d1a0cf960
child 421293 799bbe3cec7d3baa85fe3889c87d4a8ca185e703
push id34089
push userdluca@mozilla.com
push dateMon, 04 Jun 2018 18:11:55 +0000
treeherdermozilla-central@d8f180ab7492 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone62.0a1
first release with
nightly linux32
d8f180ab7492 / 62.0a1 / 20180604220149 / files
nightly linux64
d8f180ab7492 / 62.0a1 / 20180604220149 / files
nightly mac
d8f180ab7492 / 62.0a1 / 20180604220149 / files
nightly win32
d8f180ab7492 / 62.0a1 / 20180604220149 / files
nightly win64
d8f180ab7492 / 62.0a1 / 20180604220149 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-inbound to mozilla-central. a=merge
devtools/client/inspector/animation/test/browser_animation_keyframes-graph_computed-value-path.js
gfx/gl/SharedSurfaceEGL.cpp
js/src/builtin/TestingFunctions.cpp
js/src/gc/GC.cpp
js/src/vm/CodeCoverage.cpp
js/src/wasm/WasmValidate.cpp
modules/libpref/init/all.js
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
testing/web-platform/meta/MANIFEST.json
testing/web-platform/meta/html/editing/dnd/datastore/datatransfer-constructor-001.html.ini
testing/web-platform/meta/html/editing/dnd/datastore/datatransfer-types.html.ini
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
@@ -140,13 +140,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
@@ -433,18 +433,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/geolocation/nsGeolocation.cpp
+++ b/dom/geolocation/nsGeolocation.cpp
@@ -1159,17 +1159,17 @@ void
 Geolocation::GetCurrentPosition(PositionCallback& aCallback,
                                 PositionErrorCallback* aErrorCallback,
                                 const PositionOptions& aOptions,
                                 CallerType aCallerType,
                                 ErrorResult& aRv)
 {
   nsresult rv = GetCurrentPosition(GeoPositionCallback(&aCallback),
                                    GeoPositionErrorCallback(aErrorCallback),
-                                   std::move(CreatePositionOptionsCopy(aOptions)),
+                                   CreatePositionOptionsCopy(aOptions),
                                    aCallerType);
 
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
   }
 }
 
 static nsIEventTarget* MainThreadTarget(Geolocation* geo)
@@ -1237,17 +1237,17 @@ Geolocation::WatchPosition(PositionCallb
                            PositionErrorCallback* aErrorCallback,
                            const PositionOptions& aOptions,
                            CallerType aCallerType,
                            ErrorResult& aRv)
 {
   int32_t ret = 0;
   nsresult rv = WatchPosition(GeoPositionCallback(&aCallback),
                               GeoPositionErrorCallback(aErrorCallback),
-                              std::move(CreatePositionOptionsCopy(aOptions)),
+                              CreatePositionOptionsCopy(aOptions),
                               aCallerType,
                               &ret);
 
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
   }
 
   return ret;
--- 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
@@ -4464,18 +4464,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();