Merge autoland to mozilla-central. a=merge
authorCiure Andrei <aciure@mozilla.com>
Thu, 04 Apr 2019 07:32:51 +0300
changeset 467886 b72c02e3426199c098f542aba3ff0ef197e347d4
parent 467687 82ba38c4aa6acc7b322bcb56c417c0f64d5d3660 (current diff)
parent 467885 b1d1995b5e6a700b4f9600a76b5268ee62003f97 (diff)
child 467900 a5ba6ffec2a7b6431404bf1d87a67b90a6fe8a35
push id35810
push useraciure@mozilla.com
push dateThu, 04 Apr 2019 04:33:36 +0000
treeherdermozilla-central@b72c02e34261 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge autoland to mozilla-central. a=merge
dom/commandhandler/nsPICommandUpdater.idl
js/src/vm/RegExpConstants.h
testing/mozharness/configs/partner_repacks/release_mozilla-esr52_desktop.py
testing/mozharness/configs/releases/bouncer_fennec.py
testing/mozharness/configs/releases/bouncer_fennec_beta.py
testing/mozharness/configs/releases/dev_bouncer_firefox_beta.py
testing/mozharness/configs/releases/dev_bouncer_firefox_devedition.py
testing/mozharness/configs/releases/dev_bouncer_firefox_esr.py
third_party/rust/cc/.travis.yml
third_party/rust/cc/appveyor.yml
--- a/.cargo/config.in
+++ b/.cargo/config.in
@@ -12,21 +12,16 @@ git = "https://github.com/servo/serde"
 branch = "deserialize_from_enums9"
 replace-with = "vendored-sources"
 
 [source."https://github.com/retep998/winapi-rs"]
 git = "https://github.com/froydnj/winapi-rs"
 branch = "aarch64"
 replace-with = "vendored-sources"
 
-[source."https://github.com/alexcrichton/cc-rs"]
-git = "https://github.com/glandium/cc-rs"
-branch = "1.0.23-clang-cl-aarch64"
-replace-with = "vendored-sources"
-
 [source."https://github.com/rust-lang-nursery/packed_simd"]
 git = "https://github.com/hsivonen/packed_simd"
 branch = "rust_1_32"
 replace-with = "vendored-sources"
 
 [source."https://github.com/CraneStation/target-lexicon"]
 git = "https://github.com/glandium/target-lexicon"
 branch = "thumbv7neon-v0.2"
--- a/.clang-format-ignore
+++ b/.clang-format-ignore
@@ -159,16 +159,17 @@ security/nss/.*
 security/sandbox/chromium/.*
 security/sandbox/chromium-shim/.*
 testing/gtest/gmock/.*
 testing/gtest/gtest/.*
 testing/talos/talos/tests/dromaeo/.*
 testing/talos/talos/tests/kraken/.*
 testing/talos/talos/tests/v8_7/.*
 testing/web-platform/tests/resources/webidl2/.*
+testing/web-platform/tests/tools/third_party/.*
 third_party/.*
 toolkit/components/jsoncpp/.*
 toolkit/components/protobuf/.*
 toolkit/components/url-classifier/chromium/.*
 toolkit/components/url-classifier/protobuf/.*
 toolkit/crashreporter/breakpad-client/.*
 toolkit/crashreporter/google-breakpad/.*
 toolkit/recordreplay/udis86/.*
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -82,20 +82,16 @@ module.exports = {
     // TODO: Bug 1515949. Enable no-undef for gfx/
     "files": "gfx/layers/apz/test/mochitest/**",
     "rules": {
       "no-undef": "off",
     }
   }, {
     // TODO: Bug 1246594. Empty this list once the rule has landed for all dirs
     "files": [
-      "modules/libmar/tests/unit/head_libmar.js",
-      "netwerk/protocol/http/WellKnownOpportunisticUtils.jsm",
-      "netwerk/test/httpserver/httpd.js",
-      "netwerk/test/httpserver/test/**",
       "parser/htmlparser/tests/mochitest/parser_datreader.js",
       "testing/marionette/event.js",
       "testing/mochitest/**",
       "testing/modules/tests/xpcshell/test_assert.js",
       "testing/specialpowers/content/specialpowersAPI.js",
       "testing/talos/talos/**",
       "toolkit/components/aboutmemory/content/aboutMemory.js",
       "toolkit/components/captivedetect/test/unit/test_multiple_requests.js",
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,10 +1,8 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
 [[package]]
 name = "Inflector"
 version = "0.11.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -85,17 +83,17 @@ dependencies = [
 ]
 
 [[package]]
 name = "audioipc"
 version = "0.2.4"
 dependencies = [
  "bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "cc 1.0.23 (git+https://github.com/glandium/cc-rs?branch=1.0.23-clang-cl-aarch64)",
+ "cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
  "cubeb 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
  "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "memmap 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "mio-named-pipes 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -152,17 +150,17 @@ dependencies = [
  "winapi 0.3.6 (git+https://github.com/froydnj/winapi-rs?branch=aarch64)",
 ]
 
 [[package]]
 name = "backtrace-sys"
 version = "0.1.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "cc 1.0.23 (git+https://github.com/glandium/cc-rs?branch=1.0.23-clang-cl-aarch64)",
+ "cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "baldrdash"
 version = "0.1.0"
 dependencies = [
  "bindgen 0.49.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -410,36 +408,38 @@ dependencies = [
  "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "bzip2-sys"
 version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "cc 1.0.23 (git+https://github.com/glandium/cc-rs?branch=1.0.23-clang-cl-aarch64)",
+ "cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "cast"
 version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "cc"
-version = "1.0.23"
-source = "git+https://github.com/glandium/cc-rs?branch=1.0.23-clang-cl-aarch64#2aa71628b1261b5515bd8668afca591669ba195d"
+version = "1.0.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "cert_storage"
 version = "0.0.1"
 dependencies = [
  "base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-utils 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "lmdb-rkv 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "moz_task 0.1.0",
  "nserror 0.1.0",
  "nsstring 0.1.0",
  "rkv 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "style 0.0.1",
  "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "xpcom 0.1.0",
 ]
@@ -492,17 +492,17 @@ dependencies = [
  "vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "cmake"
 version = "0.1.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "cc 1.0.23 (git+https://github.com/glandium/cc-rs?branch=1.0.23-clang-cl-aarch64)",
+ "cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "comedy"
 version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1571,17 +1571,17 @@ name = "libc"
 version = "0.2.43"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "libloading"
 version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "cc 1.0.23 (git+https://github.com/glandium/cc-rs?branch=1.0.23-clang-cl-aarch64)",
+ "cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.3.6 (git+https://github.com/froydnj/winapi-rs?branch=aarch64)",
 ]
 
 [[package]]
 name = "libudev"
 version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
@@ -1623,17 +1623,17 @@ dependencies = [
  "lmdb-rkv-sys 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "lmdb-rkv-sys"
 version = "0.8.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "cc 1.0.23 (git+https://github.com/glandium/cc-rs?branch=1.0.23-clang-cl-aarch64)",
+ "cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
  "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "lock_api"
 version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1739,17 +1739,17 @@ dependencies = [
  "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "miniz_oxide_c_api"
 version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "cc 1.0.23 (git+https://github.com/glandium/cc-rs?branch=1.0.23-clang-cl-aarch64)",
+ "cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
  "crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
  "miniz_oxide 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "mio"
 version = "0.6.15"
@@ -3540,17 +3540,17 @@ dependencies = [
 "checksum build_const 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e90dc84f5e62d2ebe7676b83c22d33b6db8bd27340fb6ffbff0a364efa0cb9c9"
 "checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40"
 "checksum byte-tools 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "980479e6fde23246dfb54d47580d66b4e99202e7579c5eaa9fe10ecb5ebd2182"
 "checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d"
 "checksum bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e178b8e0e239e844b083d5a0d4a156b2654e67f9f80144d48398fcd736a24fb8"
 "checksum bzip2 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3eafc42c44e0d827de6b1c131175098fe7fb53b8ce8a47e65cb3ea94688be24"
 "checksum bzip2-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2c5162604199bbb17690ede847eaa6120a3f33d5ab4dcc8e7c25b16d849ae79b"
 "checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427"
-"checksum cc 1.0.23 (git+https://github.com/glandium/cc-rs?branch=1.0.23-clang-cl-aarch64)" = "<none>"
+"checksum cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)" = "30f813bf45048a18eda9190fd3c6b78644146056740c43172a5a3699118588fd"
 "checksum cexpr 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8fc0086be9ca82f7fc89fc873435531cb898b86e850005850de1f820e2db6e9b"
 "checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
 "checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878"
 "checksum clang-sys 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4227269cec09f5f83ff160be12a1e9b0262dd1aa305302d5ba296c2ebd291055"
 "checksum clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f16b89cbb9ee36d87483dc939fe9f1e13c05898d56d7b230a0d4dff033a536"
 "checksum cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "56d741ea7a69e577f6d06b36b7dff4738f680593dc27a701ffa8506b73ce28bb"
 "checksum comedy 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4f03fbb05a4df3523a44cda10340e6ae6bea03ee9d01240a1a2c1ef6c73e95"
 "checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e"
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -55,11 +55,10 @@ rpath = false
 debug-assertions = false
 panic = "abort"
 codegen-units = 1
 
 [patch.crates-io]
 libudev-sys = { path = "dom/webauthn/libudev-sys" }
 serde_derive = { git = "https://github.com/servo/serde", branch = "deserialize_from_enums9" }
 winapi = { git = "https://github.com/froydnj/winapi-rs", branch = "aarch64" }
-cc = { git = "https://github.com/glandium/cc-rs", branch = "1.0.23-clang-cl-aarch64" }
 packed_simd = { git = "https://github.com/hsivonen/packed_simd", branch = "rust_1_32" }
 target-lexicon = { git = "https://github.com/glandium/target-lexicon", branch = "thumbv7neon-v0.2" }
--- a/accessible/base/SelectionManager.cpp
+++ b/accessible/base/SelectionManager.cpp
@@ -10,18 +10,18 @@
 #include "HyperTextAccessible-inl.h"
 #include "nsAccessibilityService.h"
 #include "nsAccUtils.h"
 #include "nsCoreUtils.h"
 #include "nsEventShell.h"
 #include "nsFrameSelection.h"
 
 #include "nsIAccessibleTypes.h"
+#include "mozilla/PresShell.h"
 #include "mozilla/dom/Document.h"
-#include "nsIPresShell.h"
 #include "mozilla/dom/Selection.h"
 #include "mozilla/dom/Element.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 using mozilla::dom::Selection;
 
 struct mozilla::a11y::SelData final {
--- a/accessible/generic/Accessible.cpp
+++ b/accessible/generic/Accessible.cpp
@@ -39,17 +39,16 @@
 
 #include "mozilla/dom/Document.h"
 #include "nsIContent.h"
 #include "nsIForm.h"
 #include "nsIFormControl.h"
 
 #include "nsDeckFrame.h"
 #include "nsLayoutUtils.h"
-#include "nsIPresShell.h"
 #include "nsIStringBundle.h"
 #include "nsPresContext.h"
 #include "nsIFrame.h"
 #include "nsView.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIScrollableFrame.h"
 #include "nsFocusManager.h"
 
@@ -69,16 +68,17 @@
 
 #include "mozilla/Assertions.h"
 #include "mozilla/BasicEvents.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/MouseEvents.h"
+#include "mozilla/PresShell.h"
 #include "mozilla/Unused.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/CanvasRenderingContext2D.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/HTMLCanvasElement.h"
 #include "mozilla/dom/HTMLBodyElement.h"
 #include "mozilla/dom/KeyboardEventBinding.h"
 #include "mozilla/dom/TreeWalker.h"
--- a/accessible/generic/DocAccessible.cpp
+++ b/accessible/generic/DocAccessible.cpp
@@ -14,19 +14,19 @@
 #include "nsAccUtils.h"
 #include "nsEventShell.h"
 #include "nsTextEquivUtils.h"
 #include "Role.h"
 #include "RootAccessible.h"
 #include "TreeWalker.h"
 #include "xpcAccessibleDocument.h"
 
+#include "nsCommandManager.h"
 #include "nsContentUtils.h"
 #include "nsIMutableArray.h"
-#include "nsICommandManager.h"
 #include "nsIDocShell.h"
 #include "mozilla/dom/Document.h"
 #include "nsPIDOMWindow.h"
 #include "nsIEditingSession.h"
 #include "nsIFrame.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsImageFrame.h"
 #include "nsIPersistentProperties2.h"
@@ -500,17 +500,17 @@ nsRect DocAccessible::RelativeBounds(nsI
 
 // DocAccessible protected member
 nsresult DocAccessible::AddEventListeners() {
   nsCOMPtr<nsIDocShell> docShell(mDocumentNode->GetDocShell());
 
   // We want to add a command observer only if the document is content and has
   // an editor.
   if (docShell->ItemType() == nsIDocShellTreeItem::typeContent) {
-    nsCOMPtr<nsICommandManager> commandManager = docShell->GetCommandManager();
+    RefPtr<nsCommandManager> commandManager = docShell->GetCommandManager();
     if (commandManager)
       commandManager->AddCommandObserver(this, "obs_documentCreated");
   }
 
   SelectionMgr()->AddDocSelectionListener(mPresShell);
 
   // Add document observer.
   mDocumentNode->AddObserver(this);
@@ -528,18 +528,17 @@ nsresult DocAccessible::RemoveEventListe
   if (mDocumentNode) {
     mDocumentNode->RemoveObserver(this);
 
     nsCOMPtr<nsIDocShell> docShell(mDocumentNode->GetDocShell());
     NS_ASSERTION(docShell, "doc should support nsIDocShellTreeItem.");
 
     if (docShell) {
       if (docShell->ItemType() == nsIDocShellTreeItem::typeContent) {
-        nsCOMPtr<nsICommandManager> commandManager =
-            docShell->GetCommandManager();
+        RefPtr<nsCommandManager> commandManager = docShell->GetCommandManager();
         if (commandManager) {
           commandManager->RemoveCommandObserver(this, "obs_documentCreated");
         }
       }
     }
   }
 
   if (mScrollWatchTimer) {
--- a/accessible/generic/HyperTextAccessible.cpp
+++ b/accessible/generic/HyperTextAccessible.cpp
@@ -32,16 +32,17 @@
 #include "nsIMathMLFrame.h"
 #include "nsRange.h"
 #include "nsTextFragment.h"
 #include "mozilla/BinarySearch.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/dom/Selection.h"
 #include "mozilla/MathAlgorithms.h"
+#include "mozilla/PresShell.h"
 #include "mozilla/TextEditor.h"
 #include "gfxSkipChars.h"
 #include <algorithm>
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
--- a/accessible/tests/crashtests/crashtests.list
+++ b/accessible/tests/crashtests/crashtests.list
@@ -8,9 +8,9 @@ load 1380199.html
 load 1402999.html
 load 1463962.html
 load 1484778.html
 load 1494707.html
 load 1503964.html
 
 # last_test_to_unload_testsuite.xul MUST be the last test in the list because it
 # is responsible for shutting down accessibility service affecting later tests.
-load last_test_to_unload_testsuite.xul
+skip-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)&&/^aarch64-msvc/.test(xulRuntime.XPCOMABI)) load last_test_to_unload_testsuite.xul
--- a/accessible/xul/XULTreeAccessible.cpp
+++ b/accessible/xul/XULTreeAccessible.cpp
@@ -25,16 +25,17 @@
 #include "nsIAutoCompletePopup.h"
 #include "nsIDOMXULMenuListElement.h"
 #include "nsIDOMXULMultSelectCntrlEl.h"
 #include "nsITreeSelection.h"
 #include "nsIMutableArray.h"
 #include "nsTreeBodyFrame.h"
 #include "nsTreeColumns.h"
 #include "nsTreeUtils.h"
+#include "mozilla/PresShell.h"
 #include "mozilla/dom/XULTreeElementBinding.h"
 
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULTreeAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
@@ -155,17 +156,17 @@ role XULTreeAccessible::NativeRole() con
 // XULTreeAccessible: Accessible implementation (DON'T put methods here)
 
 Accessible* XULTreeAccessible::ChildAtPoint(int32_t aX, int32_t aY,
                                             EWhichChildAtPoint aWhichChild) {
   nsIFrame* frame = GetFrame();
   if (!frame) return nullptr;
 
   nsPresContext* presContext = frame->PresContext();
-  nsIPresShell* presShell = presContext->PresShell();
+  PresShell* presShell = presContext->PresShell();
 
   nsIFrame* rootFrame = presShell->GetRootFrame();
   NS_ENSURE_TRUE(rootFrame, nullptr);
 
   CSSIntRect rootRect = rootFrame->GetScreenRect();
 
   int32_t clientX = presContext->DevPixelsToIntCSSPixels(aX) - rootRect.X();
   int32_t clientY = presContext->DevPixelsToIntCSSPixels(aY) - rootRect.Y();
--- a/accessible/xul/XULTreeGridAccessible.cpp
+++ b/accessible/xul/XULTreeGridAccessible.cpp
@@ -15,16 +15,17 @@
 #include "States.h"
 #include "nsQueryObject.h"
 #include "nsTreeColumns.h"
 
 #include "nsIMutableArray.h"
 #include "nsPersistentProperties.h"
 #include "nsITreeSelection.h"
 #include "nsComponentManagerUtils.h"
+#include "mozilla/PresShell.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/TreeColumnBinding.h"
 #include "mozilla/dom/XULTreeElementBinding.h"
 
 using namespace mozilla::a11y;
 using namespace mozilla;
 
 XULTreeGridAccessible::~XULTreeGridAccessible() {}
@@ -252,17 +253,17 @@ ENameValueFlag XULTreeGridRowAccessible:
 }
 
 Accessible* XULTreeGridRowAccessible::ChildAtPoint(
     int32_t aX, int32_t aY, EWhichChildAtPoint aWhichChild) {
   nsIFrame* frame = GetFrame();
   if (!frame) return nullptr;
 
   nsPresContext* presContext = frame->PresContext();
-  nsIPresShell* presShell = presContext->PresShell();
+  PresShell* presShell = presContext->PresShell();
 
   nsIFrame* rootFrame = presShell->GetRootFrame();
   NS_ENSURE_TRUE(rootFrame, nullptr);
 
   CSSIntRect rootRect = rootFrame->GetScreenRect();
 
   int32_t clientX = presContext->DevPixelsToIntCSSPixels(aX) - rootRect.X();
   int32_t clientY = presContext->DevPixelsToIntCSSPixels(aY) - rootRect.Y();
--- a/browser/base/content/test/about/browser_aboutCertError_telemetry.js
+++ b/browser/base/content/test/about/browser_aboutCertError_telemetry.js
@@ -28,17 +28,17 @@ add_task(async function checkTelemetryCl
   // previous tests and don't receive random events in the middle of our tests.
   // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
   await new Promise(c => setTimeout(c, 2000));
 
   // Clear everything.
   Services.telemetry.clearEvents();
   await TestUtils.waitForCondition(() => {
     let events = Services.telemetry.snapshotEvents(
-      Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true).content;
+      Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS, true).content;
     return !events || !events.length;
   });
 
   // Now enable recording our telemetry. Even if this is disabled, content
   // processes will send event telemetry to the parent, thus we needed to ensure
   // we waited and cleared first. Sigh.
   Services.telemetry.setEventRecordingEnabled("security.ui.certerror", true);
 
@@ -59,17 +59,17 @@ add_task(async function checkTelemetryCl
     }
 
     for (let object of recordedObjects) {
       let tab = await openErrorPage(BAD_CERT, useFrame);
       let browser = tab.linkedBrowser;
 
       let loadEvents = await TestUtils.waitForCondition(() => {
         let events = Services.telemetry.snapshotEvents(
-          Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true).content;
+          Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS, true).content;
         if (events && events.length) {
           events = events.filter(e => e[1] == "security.ui.certerror" && e[2] == "load");
           if (events.length == 1 && events[0][5].is_frame == useFrame.toString()) {
             return events;
           }
         }
         return null;
       }, "recorded telemetry for the load");
@@ -82,17 +82,17 @@ add_task(async function checkTelemetryCl
         await ContentTaskUtils.waitForCondition(() => doc.body.classList.contains("certerror"), "Wait for certerror to be loaded");
 
         let domElement = doc.querySelector(`[data-telemetry-id='${objectId}']`);
         domElement.click();
       });
 
       let clickEvents = await TestUtils.waitForCondition(() => {
         let events = Services.telemetry.snapshotEvents(
-          Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true).content;
+          Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS, true).content;
         if (events && events.length) {
           events = events.filter(e => e[1] == "security.ui.certerror" && e[2] == "click" && e[3] == object);
           if (events.length == 1 && events[0][5].is_frame == useFrame.toString()) {
             return events;
           }
         }
         return null;
       }, "Has captured telemetry events.");
--- a/browser/base/content/test/general/browser_alltabslistener.js
+++ b/browser/base/content/test/general/browser_alltabslistener.js
@@ -28,19 +28,16 @@ var gFrontProgressListener = {
     }
     var state = "onLocationChange";
     info("FrontProgress: " + state + " " + aLocationURI.spec);
     ok(gFrontNotificationsPos < gFrontNotifications.length, "Got an expected notification for the front notifications listener");
     is(state, gFrontNotifications[gFrontNotificationsPos], "Got a notification for the front notifications listener");
     gFrontNotificationsPos++;
   },
 
-  onStatusChange(aWebProgress, aRequest, aStatus, aMessage) {
-  },
-
   onSecurityChange(aWebProgress, aRequest, aState) {
     if (aRequest &&
         aRequest.QueryInterface(Ci.nsIChannel).originalURI.spec == "about:blank") {
       // ignore initial about blank
       return;
     }
     var state = "onSecurityChange";
     info("FrontProgress: " + state + " 0x" + aState.toString(16));
@@ -80,26 +77,16 @@ var gAllProgressListener = {
     var state = "onLocationChange";
     info("AllProgress: " + state + " " + aLocationURI.spec);
     ok(aBrowser == gTestBrowser, state + " notification came from the correct browser");
     ok(gAllNotificationsPos < gAllNotifications.length, "Got an expected notification for the all notifications listener");
     is(state, gAllNotifications[gAllNotificationsPos], "Got a notification for the all notifications listener");
     gAllNotificationsPos++;
   },
 
-  onStatusChange(aBrowser, aWebProgress, aRequest, aStatus, aMessage) {
-    if (aRequest &&
-        aRequest.QueryInterface(Ci.nsIChannel).originalURI.spec == "about:blank") {
-      // ignore initial about blank
-      return;
-    }
-    var state = "onStatusChange";
-    ok(aBrowser == gTestBrowser, state + " notification came from the correct browser");
-  },
-
   onSecurityChange(aBrowser, aWebProgress, aRequest, aState) {
     if (aRequest &&
         aRequest.QueryInterface(Ci.nsIChannel).originalURI.spec == "about:blank") {
       // ignore initial about blank
       return;
     }
     var state = "onSecurityChange";
     info("AllProgress: " + state + " 0x" + aState.toString(16));
--- a/browser/base/content/test/siteIdentity/browser_identityPopup_clearSiteData.js
+++ b/browser/base/content/test/siteIdentity/browser_identityPopup_clearSiteData.js
@@ -67,17 +67,17 @@ async function testClearing(testQuota, t
     // Click the "Clear data" button.
     siteDataUpdated = TestUtils.topicObserved("sitedatamanager:sites-updated");
     let hideEvent = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "popuphidden");
     let removeDialogPromise = BrowserTestUtils.promiseAlertDialogOpen("accept", REMOVE_DIALOG_URL);
     clearButton.click();
     await hideEvent;
     await removeDialogPromise;
 
-    let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN).parent;
+    let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS).parent;
     let buttonEvents = events.filter(
       e => e[1] == "security.ui.identitypopup" && e[2] == "click" && e[3] == "clear_sitedata");
     is(buttonEvents.length, 1, "recorded telemetry for the button click");
 
     await siteDataUpdated;
 
     // Check that cookies were deleted.
     if (testCookies) {
--- a/browser/base/content/test/trackingUI/browser_trackingUI_cookies_subview.js
+++ b/browser/base/content/test/trackingUI/browser_trackingUI_cookies_subview.js
@@ -49,17 +49,17 @@ async function assertSitesListed(tracker
   ok(BrowserTestUtils.is_visible(categoryItem), "TP category item is visible");
   let cookiesView = document.getElementById("identity-popup-cookiesView");
   let viewShown = BrowserTestUtils.waitForEvent(cookiesView, "ViewShown");
   categoryItem.click();
   await viewShown;
 
   ok(true, "Cookies view was shown");
 
-  let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN).parent;
+  let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS).parent;
   let buttonEvents = events.filter(
     e => e[1] == "security.ui.identitypopup" && e[2] == "click" && e[3] == "cookies_subview_btn");
   is(buttonEvents.length, 1, "recorded telemetry for the button click");
 
   let listHeaders = cookiesView.querySelectorAll(".identity-popup-cookiesView-list-header");
   is(listHeaders.length, 3, "We have 3 list headers");
 
   let emptyLabels = cookiesView.querySelectorAll(".identity-popup-content-blocking-empty-label");
--- a/browser/base/content/test/trackingUI/browser_trackingUI_open_preferences.js
+++ b/browser/base/content/test/trackingUI/browser_trackingUI_open_preferences.js
@@ -47,17 +47,17 @@ add_task(async function testOpenPreferen
     ok(BrowserTestUtils.is_visible(preferencesButton), "The preferences button is shown.");
 
     Services.telemetry.clearEvents();
 
     let shown = waitAndAssertPreferencesShown("trackingprotection");
     preferencesButton.click();
     await shown;
 
-    let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true).parent;
+    let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS, true).parent;
     let clickEvents = events.filter(
       e => e[1] == "security.ui.identitypopup" && e[2] == "click" && e[3] == "cb_prefs_button");
     is(clickEvents.length, 1, "recorded telemetry for the click");
   });
 });
 
 // Tests that pressing the permissions preferences icon in the identity popup
 // links to about:preferences
@@ -72,17 +72,17 @@ add_task(async function testOpenPreferen
     ok(BrowserTestUtils.is_visible(preferencesButton), "The preferences button is shown.");
 
     Services.telemetry.clearEvents();
 
     let shown = waitAndAssertPreferencesShown("permissions");
     preferencesButton.click();
     await shown;
 
-    let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true).parent;
+    let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS, true).parent;
     let clickEvents = events.filter(
       e => e[1] == "security.ui.identitypopup" && e[2] == "click" && e[3] == "permission_prefs_btn");
     is(clickEvents.length, 1, "recorded telemetry for the click");
   });
 });
 
 // Tests that pressing the preferences button in the trackers subview
 // links to about:preferences
@@ -109,17 +109,17 @@ add_task(async function testOpenPreferen
     ok(BrowserTestUtils.is_visible(preferencesButton), "The preferences button is shown.");
 
     Services.telemetry.clearEvents();
 
     let shown = waitAndAssertPreferencesShown("trackingprotection");
     preferencesButton.click();
     await shown;
 
-    let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true).parent;
+    let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS, true).parent;
     let clickEvents = events.filter(
       e => e[1] == "security.ui.identitypopup" && e[2] == "click" && e[3] == "trackers_prefs_btn");
     is(clickEvents.length, 1, "recorded telemetry for the click");
   });
 
   Services.prefs.clearUserPref(TP_PREF);
 });
 
@@ -148,16 +148,16 @@ add_task(async function testOpenPreferen
     ok(BrowserTestUtils.is_visible(preferencesButton), "The preferences button is shown.");
 
     Services.telemetry.clearEvents();
 
     let shown = waitAndAssertPreferencesShown("trackingprotection");
     preferencesButton.click();
     await shown;
 
-    let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true).parent;
+    let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS, true).parent;
     let clickEvents = events.filter(
       e => e[1] == "security.ui.identitypopup" && e[2] == "click" && e[3] == "cookies_prefs_btn");
     is(clickEvents.length, 1, "recorded telemetry for the click");
   });
 
   Services.prefs.clearUserPref(TPC_PREF);
 });
--- a/browser/base/content/test/trackingUI/browser_trackingUI_report_breakage.js
+++ b/browser/base/content/test/trackingUI/browser_trackingUI_report_breakage.js
@@ -131,17 +131,17 @@ add_task(async function testReportBreaka
 
     let reportBreakageButton = document.getElementById("identity-popup-content-blocking-report-breakage");
     ok(BrowserTestUtils.is_visible(reportBreakageButton), "report breakage button is visible");
     let reportBreakageView = document.getElementById("identity-popup-breakageReportView");
     let viewShown = BrowserTestUtils.waitForEvent(reportBreakageView, "ViewShown");
     reportBreakageButton.click();
     await viewShown;
 
-    let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN).parent;
+    let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS).parent;
     let clickEvents = events.filter(
       e => e[1] == "security.ui.identitypopup" && e[2] == "click" && e[3] == "report_breakage");
     is(clickEvents.length, 1, "recorded telemetry for the click");
 
     ok(true, "Report breakage view was shown");
 
     let mainView = document.getElementById("identity-popup-mainView");
     viewShown = BrowserTestUtils.waitForEvent(mainView, "ViewShown");
--- a/browser/base/content/test/trackingUI/browser_trackingUI_telemetry.js
+++ b/browser/base/content/test/trackingUI/browser_trackingUI_telemetry.js
@@ -84,46 +84,46 @@ add_task(async function testIdentityPopu
   let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
 
   await promiseTabLoadEvent(tab, BENIGN_PAGE);
 
   Services.telemetry.clearEvents();
 
   await openIdentityPopup();
 
-  let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true).parent;
+  let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS, true).parent;
   let openEvents = events.filter(
     e => e[1] == "security.ui.identitypopup" && e[2] == "open" && e[3] == "identity_popup");
   is(openEvents.length, 1, "recorded telemetry for opening the identity popup");
   is(openEvents[0][4], "shield-hidden", "recorded the shield as hidden");
 
   await promiseTabLoadEvent(tab, TRACKING_PAGE);
 
   await openIdentityPopup();
 
-  events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true).parent;
+  events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS, true).parent;
   openEvents = events.filter(
     e => e[1] == "security.ui.identitypopup" && e[2] == "open" && e[3] == "identity_popup");
   is(openEvents.length, 1, "recorded telemetry for opening the identity popup");
   is(openEvents[0][4], "shield-showing", "recorded the shield as showing");
 
   info("Disable TP for the page (which reloads the page)");
   let tabReloadPromise = promiseTabLoadEvent(tab);
   document.querySelector("#tracking-action-unblock").doCommand();
   await tabReloadPromise;
 
-  events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true).parent;
+  events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS, true).parent;
   let clickEvents = events.filter(
     e => e[1] == "security.ui.identitypopup" && e[2] == "click" && e[3] == "unblock");
   is(clickEvents.length, 1, "recorded telemetry for the click");
 
   info("Re-enable TP for the page (which reloads the page)");
   tabReloadPromise = promiseTabLoadEvent(tab);
   document.querySelector("#tracking-action-block").doCommand();
   await tabReloadPromise;
 
-  events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true).parent;
+  events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS, true).parent;
   clickEvents = events.filter(
     e => e[1] == "security.ui.identitypopup" && e[2] == "click" && e[3] == "block");
   is(clickEvents.length, 1, "recorded telemetry for the click");
 
   gBrowser.removeCurrentTab();
 });
--- a/browser/base/content/test/trackingUI/browser_trackingUI_trackers_subview.js
+++ b/browser/base/content/test/trackingUI/browser_trackingUI_trackers_subview.js
@@ -33,17 +33,17 @@ async function assertSitesListed(blocked
     ok(BrowserTestUtils.is_visible(categoryItem), "TP category item is visible");
     let trackersView = document.getElementById("identity-popup-trackersView");
     let viewShown = BrowserTestUtils.waitForEvent(trackersView, "ViewShown");
     categoryItem.click();
     await viewShown;
 
     ok(true, "Trackers view was shown");
 
-    let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN).parent;
+    let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS).parent;
     let buttonEvents = events.filter(
       e => e[1] == "security.ui.identitypopup" && e[2] == "click" && e[3] == "trackers_subview_btn");
     is(buttonEvents.length, 1, "recorded telemetry for the button click");
 
     let listItems = trackersView.querySelectorAll(".identity-popup-content-blocking-list-item");
     is(listItems.length, 1, "We have 1 tracker in the list");
 
     let strictInfo = document.getElementById("identity-popup-trackersView-strict-info");
--- a/browser/base/content/test/webextensions/browser_permissions_local_file.js
+++ b/browser/base/content/test/webextensions/browser_permissions_local_file.js
@@ -36,17 +36,17 @@ add_task(async function test_install_ext
   // Install the add-ons.
   await testInstallMethod(installFile, "installLocal");
 
   // Check we got an installId.
   ok(firstInstallId != null && !isNaN(firstInstallId), "There was an installId found");
 
   // Check the telemetry.
   let snapshot = Services.telemetry.snapshotEvents(
-    Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true);
+    Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS, true);
 
   // Make sure we got some data.
   ok(snapshot.parent && snapshot.parent.length > 0, "Got parent telemetry events in the snapshot");
 
   // Only look at the related events after stripping the timestamp and category.
   let relatedEvents = snapshot.parent
     .filter(([timestamp, category, method, object]) =>
       category == "addonsManager" && method == "action" && object == "aboutAddons")
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -204,16 +204,18 @@ file, You can obtain one at http://mozil
           this._deferredKeyEventTimeout = null;
         }
 
         // Null out the one-offs' popup and textbox so that it cleans up its
         // internal state for both.  Most importantly, it removes the event
         // listeners that it added to both.
         this.popup.oneOffSearchButtons.popup = null;
         this.popup.oneOffSearchButtons.textbox = null;
+
+        this.valueFormatter.uninit();
       ]]></destructor>
 
       <field name="valueFormatter" readonly="true">
         new UrlbarValueFormatter(this);
       </field>
 
       <field name="goButton">
         document.getAnonymousElementByAttribute(this, "anonid", "urlbar-go-button");
@@ -1343,28 +1345,16 @@ file, You can obtain one at http://mozil
               this.controller.resetInternalState();
               break;
             case "resize":
               if (aEvent.target == window) {
                 // Close the popup since it would be wrongly sized, we'll
                 // recalculate a proper size on reopening. For example, this may
                 // happen when using special OS resize functions like Win+Arrow.
                 this.closePopup();
-
-                // Make sure the host remains visible in the input field
-                // when the window is resized.  We don't want to
-                // hurt resize performance though, so do this only after resize
-                // events have stopped and a small timeout has elapsed.
-                if (this._resizeThrottleTimeout) {
-                  clearTimeout(this._resizeThrottleTimeout);
-                }
-                this._resizeThrottleTimeout = setTimeout(() => {
-                  this._resizeThrottleTimeout = null;
-                  this.valueFormatter.ensureFormattedHostVisible();
-                }, 100);
               }
               break;
           }
         ]]></body>
       </method>
 
       <method name="updateTextOverflow">
         <body><![CDATA[
--- a/browser/components/customizableui/test/browser_lwt_telemetry.js
+++ b/browser/components/customizableui/test/browser_lwt_telemetry.js
@@ -32,17 +32,17 @@ add_task(async function testCustomize() 
   waitForNewTab = BrowserTestUtils.waitForNewTab(gBrowser, getMoreURL);
   getMoreButton.click();
   addonsTab = await waitForNewTab;
 
   is(gBrowser.currentURI.spec, getMoreURL, "Get more opened AMO");
   BrowserTestUtils.removeTab(addonsTab);
 
   let snapshot = Services.telemetry.snapshotEvents(
-    Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true);
+    Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS, true);
 
   // Make sure we got some data.
   ok(snapshot.parent && snapshot.parent.length > 0, "Got parent telemetry events in the snapshot");
 
   // Only look at the related events after stripping the timestamp and category.
   let relatedEvents = snapshot.parent
     .filter(([timestamp, category, method, object]) =>
       category == "addonsManager" && object == "customize")
--- a/browser/components/extensions/test/browser/browser_ext_browserAction_contextMenu.js
+++ b/browser/components/extensions/test/browser/browser_ext_browserAction_contextMenu.js
@@ -45,17 +45,17 @@ let contextMenuItems = {
 };
 
 const TELEMETRY_CATEGORY = "addonsManager";
 const TELEMETRY_METHODS = new Set(["action", "link", "view"]);
 const type = "extension";
 
 function assertTelemetryMatches(events) {
   let snapshot = Services.telemetry.snapshotEvents(
-    Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true);
+    Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS, true);
 
   if (events.length == 0) {
     ok(!snapshot.parent || snapshot.parent.length == 0, "There are no telemetry events");
     return;
   }
 
   // Make sure we got some data.
   ok(snapshot.parent && snapshot.parent.length > 0, "Got parent telemetry events in the snapshot");
@@ -65,16 +65,21 @@ function assertTelemetryMatches(events) 
     .filter(([timestamp, category, method]) =>
       category == TELEMETRY_CATEGORY && TELEMETRY_METHODS.has(method))
     .map(relatedEvent => relatedEvent.slice(2, 6));
 
   // Events are now [method, object, value, extra] as expected.
   Assert.deepEqual(relatedEvents, events, "The events are recorded correctly");
 }
 
+add_task(async function test_setup() {
+  // Clear any previosuly collected telemetry event.
+  Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true);
+});
+
 add_task(async function browseraction_popup_contextmenu() {
   let extension = ExtensionTestUtils.loadExtension(extData);
   await extension.startup();
 
   await clickBrowserAction(extension, window);
 
   let contentAreaContextMenu = await openContextMenuInPopup(extension);
   let item = contentAreaContextMenu.getElementsByAttribute("label", "Click me!");
--- a/browser/components/places/tests/browser/browser.ini
+++ b/browser/components/places/tests/browser/browser.ini
@@ -65,17 +65,16 @@ skip-if = (verify && debug && (os == 'ma
 [browser_library_commands.js]
 [browser_library_delete_bookmarks_in_tags.js]
 [browser_library_delete_tags.js]
 [browser_library_delete.js]
 [browser_library_downloads.js]
 [browser_library_left_pane_middleclick.js]
 [browser_library_left_pane_select_hierarchy.js]
 [browser_library_middleclick.js]
-skip-if = (os == 'mac') # Re-enable once bug 1530188 has been fixed
 [browser_library_new_bookmark.js]
 [browser_library_open_leak.js]
 [browser_library_openFlatContainer.js]
 [browser_library_open_bookmark.js]
 [browser_library_panel_leak.js]
 [browser_library_search.js]
 [browser_library_tree_leak.js]
 [browser_library_views_liveupdate.js]
--- a/browser/components/preferences/in-content/main.js
+++ b/browser/components/preferences/in-content/main.js
@@ -639,64 +639,16 @@ var gMainPane = {
 
     const link = document.getElementById("browserContainersLearnMore");
     link.href = Services.urlFormatter.formatURLPref("app.support.baseURL") + "containers";
 
     document.getElementById("browserContainersbox").hidden = false;
     this.readBrowserContainersCheckbox();
   },
 
-  async separateProfileModeChange() {
-    if (AppConstants.MOZ_DEV_EDITION) {
-      function quitApp() {
-        Services.startup.quit(Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestartNotSameProfile);
-      }
-      function revertCheckbox(error) {
-        separateProfileModeCheckbox.checked = !separateProfileModeCheckbox.checked;
-        if (error) {
-          Cu.reportError("Failed to toggle separate profile mode: " + error);
-        }
-      }
-      function createOrRemoveSpecialDevEditionFile(onSuccess) {
-        let uAppData = OS.Constants.Path.userApplicationDataDir;
-        let ignoreSeparateProfile = OS.Path.join(uAppData, "ignore-dev-edition-profile");
-
-        if (separateProfileModeCheckbox.checked) {
-          OS.File.remove(ignoreSeparateProfile).then(onSuccess, revertCheckbox);
-        } else {
-          OS.File.writeAtomic(ignoreSeparateProfile, new Uint8Array()).then(onSuccess, revertCheckbox);
-        }
-      }
-
-      let separateProfileModeCheckbox = document.getElementById("separateProfileMode");
-      let button_index = await confirmRestartPrompt(separateProfileModeCheckbox.checked,
-        0, false, true);
-      switch (button_index) {
-        case CONFIRM_RESTART_PROMPT_CANCEL:
-          revertCheckbox();
-          return;
-        case CONFIRM_RESTART_PROMPT_RESTART_NOW:
-          let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"]
-            .createInstance(Ci.nsISupportsPRBool);
-          Services.obs.notifyObservers(cancelQuit, "quit-application-requested",
-            "restart");
-          if (!cancelQuit.data) {
-            createOrRemoveSpecialDevEditionFile(quitApp);
-            return;
-          }
-
-          // Revert the checkbox in case we didn't quit
-          revertCheckbox();
-          return;
-        case CONFIRM_RESTART_PROMPT_RESTART_LATER:
-          createOrRemoveSpecialDevEditionFile();
-      }
-    }
-  },
-
   async onGetStarted(aEvent) {
     if (!AppConstants.MOZ_DEV_EDITION) {
       return;
     }
     const win = Services.wm.getMostRecentWindow("navigator:browser");
     if (!win) {
       return;
     }
--- a/browser/components/preferences/in-content/tests/browser_browser_languages_subdialog.js
+++ b/browser/components/preferences/in-content/tests/browser_browser_languages_subdialog.js
@@ -151,17 +151,17 @@ function assertAvailableLocales(list, lo
 }
 
 function getDialogId(dialogDoc) {
   return dialogDoc.ownerGlobal.arguments[0].telemetryId;
 }
 
 function assertTelemetryRecorded(events) {
   let snapshot = Services.telemetry.snapshotEvents(
-    Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true);
+    Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS, true);
 
   // Make sure we got some data.
   ok(snapshot.parent && snapshot.parent.length > 0, "Got parent telemetry events in the snapshot");
 
   // Only look at the related events after stripping the timestamp and category.
   let relatedEvents = snapshot.parent
     .filter(([timestamp, category]) => category == TELEMETRY_CATEGORY)
     .map(relatedEvent => relatedEvent.slice(2, 6));
--- a/browser/components/search/SearchTelemetry.jsm
+++ b/browser/components/search/SearchTelemetry.jsm
@@ -55,17 +55,17 @@ const SEARCH_PROVIDER_INFO = {
   "yahoo": {
     "regexp": /^https:\/\/(?:.*)search\.yahoo\.com\/search/,
     "queryParam": "p",
   },
   "baidu": {
     "regexp": /^https:\/\/www\.baidu\.com\/(?:s|baidu)/,
     "queryParam": "wd",
     "codeParam": "tn",
-    "codePrefixes": ["monline_dg"],
+    "codePrefixes": ["34046034_", "monline_"],
     "followonParams": ["oq"],
   },
   "bing": {
     "regexp": /^https:\/\/www\.bing\.com\/search/,
     "queryParam": "q",
     "codeParam": "pc",
     "codePrefixes": ["MOZ", "MZ"],
   },
--- a/browser/components/search/searchplugins/baidu.xml
+++ b/browser/components/search/searchplugins/baidu.xml
@@ -4,19 +4,19 @@
 
 <SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
 <ShortName>百度</ShortName>
 <Description>百度网页搜索</Description>
 <InputEncoding>UTF-8</InputEncoding>
 <Image width="16" height="16">data:image/x-icon;base64, AAABAAIAEBAAAAEACABoBQAAJgAAACAgAAABACAAqBAAAI4FAAAoAAAAEAAAACAAAAABAAgAAAAAAEABAAAAAAAAAAAAAAABAAAAAAAAAAAAAP///wDhMikA9b67AOI3LgDzr6wA8ZyYAO2EfwD//fwA6WxlAOZUTAD3yMUA9bu5AP3u7QDrdm8A6GVeAPfFwwD4z80A6WdgAPrg3gDsfXcA+dTSAP3x8ADsenUA8qaiAPzp6ADujokA+t3cAORFPQDyqKQA4jkxAPnW1ADnWVEA51tUAPvk4wD++PcA7H96APS3swD74uEA4z42AOVPRwDpaWMA9sC+APzs6wDnXVYA6GJbAP3z8gDxoZ0A8qOfAO6LhgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIGBQAFBQUABQUFAAUFBQAFBQUABQUFAAUFBQAFBQYAFwUFAAUFBQAFBQUABQUFAAUFBQAFBQUABQUFAAUFBQAFBQIAAQEBAAEBAQABAQEAAQEBAAEBAQABAQEAAQIFAAUFAQABAQEAJTVLAAICAgICAgICAgICAgICAgICAQEBAQEBAQEBAQEBAQECAgEBLgkCKDEaIAIPLgEBAgIBARgCAgICAgICAi8BAQICAQEvAgICAgICAgIwAQECAgEBFigCAgICAgItLgEBAgIBAQErKAICAgIsIwEBAQICAQglHyYnAgIoDSkEKgECAgEYAh4WHyAhIiMCAiQBAgIBGgICGwEBAQEBHAIdAQICARECEhMUFRYXGBkLAQECAgEBDQEOAg8FAgIQAQEBAgIBAQEBCQIKCwICDAEBAQICAQEBAQMEBQEGBwgBAQECAgEBAQEBAQEBAQEBAQEBAgICAgICAgICAgICAgICAgIAAABpAAAAaQAAAGkAAABpAAAAaQAAAGkAAABpAAAAaQAAAGkAAABpAAAAaQAAAGkAAABpAAAAaQAAAGkAAABpKAAAACAAAABAAAAAAQAgAAAAAACAEAAAAAAAAAAAAAAAAAAAAAAAAOEyKUjhMinn4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKefhMilI4TIp5OEyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKeThMin/4TIp//fFw/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////fFw//hMin/4TIp/+EyKf/hMin////////////////////////////97u3/8Z+a/+lpY//nW1T/6nFq/+6JhP/zran/98rI//rg3v/629n/+MzK//CXk//oZV7/5U9H/+EyKf/iNy7/6m5o//nU0v///////////////////////////+EyKf/hMin/4TIp/+EyKf//////////////////////++Lh/+RFPf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TQs//jPzf//////////////////////4TIp/+EyKf/hMin/4TIp///////////////////////pbGX/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/51lR///////////////////////hMin/4TIp/+EyKf/hMin/////////////////++fm/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/++fm/////////////////+EyKf/hMin/4TIp/+EyKf/////////////////2wL7/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/3yMX/////////////////4TIp/+EyKf/hMin/4TIp//////////////////W+u//hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp//jPzf/////////////////hMin/4TIp/+EyKf/hMin/////////////////++fm/+E0LP/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/jQzv//vj3/////////////////+EyKf/hMin/4TIp/+EyKf//////////////////////7YJ8/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp//Otqf//////////////////////4TIp/+EyKf/hMin/4TIp///////////////////////+9fX/5lRM/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/xn5r////////////////////////////hMin/4TIp/+EyKf/hMin////////////////////////////97u3/6GVe/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hNCz/9LKu/////////////////////////////////+EyKf/hMin/4TIp/+EyKf/////////////////////////////////++vr/63hy/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TQs//W5tv/51tT/8qOf//CXk//51NL/////////////////4TIp/+EyKf/hMin/4TIp/////////////////////////////////////////fz/63Zv/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/0sq7/9Lez/+E0LP/hMin/4TIp/+EyKf/1ubb////////////hMin/4TIp/+EyKf/hMin/////////////////9bm2/+lpY//oYlv/86+s///////++Pf/5lZP/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/7ouG///////lT0f/4TIp/+EyKf/hMin/4TIp/+ZRSv///////////+EyKf/hMin/4TIp/+EyKf////////////W+u//hMin/4TIp/+EyKf/hMin/8qai///////74uH/4z42/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+hiW//++vr//////+I5Mf/hMin/4TIp/+EyKf/hMin/4TIp////////////4TIp/+EyKf/hMin/4TIp////////////511W/+EyKf/hMin/4TIp/+EyKf/lSkL////////////2w8D/4jcu/+EyKf/hMin/4TIp/+EyKf/kSED//Ozr////////////4jcu/+EyKf/hMin/4TIp/+EyKf/hMin//vX1///////hMin/4TIp/+EyKf/hMin////////////iNy7/4TIp/+EyKf/hMin/4TIp/+EyKf/++Pf////////////4z83/6GBZ/+EyKf/jQzv/7H96//zs6//////////////////lTUX/4TIp/+EyKf/hMin/4TIp/+RIQP///////////+EyKf/hMin/4TIp/+EyKf///////////+I8M//hMin/4TIp/+EyKf/hMin/4TIp//749////////////////////////////////////////////////////////////+6Lhv/hMin/4TIp/+EyKf/hMin/8aGd////////////4TIp/+EyKf/hMin/4TIp////////////6m5o/+EyKf/hMin/4TIp/+EyKf/mVk///////////////////////////////////////////////fz/9sPA//fKyP///fz//vj3/+t2b//iPDP/5EhA/++VkP/////////////////hMin/4TIp/+EyKf/hMin////////////3ysj/4TIp/+EyKf/hMin/4TIp//bDwP//////8Z+a/+I8M//jQzv/9bu5/////////////fHw/+ZUTP/hMin/4TIp/+ZWT//86ej//////////////////////////////////////+EyKf/hMin/4TIp/+EyKf/////////////////yqKT/5EU9/+dZUf/1vrv///////bDwP/hMin/4TIp/+EyKf/hNCz/++Tj///////xnJj/4TIp/+EyKf/hMin/4TIp/+puaP//////////////////////////////////////4TIp/+EyKf/hMin/4TIp////////////////////////////////////////////6nFq/+EyKf/hMin/4TIp/+EyKf/vlZD//////+t2b//hMin/4TIp/+EyKf/hMin/4TIp//rb2f/////////////////////////////////hMin/4TIp/+EyKf/hMin////////////////////////////////////////////lTUX/4TIp/+EyKf/hMin/4TIp/+pxav//////6nFq/+EyKf/hMin/4TIp/+EyKf/hMin/862p/////////////////////////////////+EyKf/hMin/4TIp/+EyKf///////////////////////////////////////////+RIQP/hMin/4TIp/+EyKf/hMin/6m5o///////ypqL/4TIp/+EyKf/hMin/4TIp/+EyKf/1ubb/////////////////////////////////4TIp/+EyKf/hMin/4TIp////////////////////////////////////////////6nFq/+EyKf/hMin/4TIp/+EyKf/vlZD///////719f/lSkL/4TIp/+EyKf/hMin/5EhA//719f/////////////////////////////////hMin/4TIp/+EyKf/hMin////////////////////////////////////////////3ysj/4TIp/+EyKf/hMin/4jcu//zp6P////////////nY1//kRT3/4TIp/+I8M//4z83//////////////////////////////////////+EyKf/hMin/4TIp/+EyKf/////////////////////////////////////////////////zq6f/5EU9/+VNRf/3yMX///////////////////////3z8v/1u7n//fHw////////////////////////////////////////////4TIp/+EyKf/hMin/4TIp//fKyP////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////fKyP/hMin/4TIp/+EyKefhMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMinn4TIpP+EyKcnhMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIp/+EyKf/hMin/4TIpyeEyKT8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==</Image>
 <Url type="application/x-suggestions+json" method="GET" template="https://www.baidu.com/su">
   <Param name="wd" value="{searchTerms}"/>
-  <Param name="tn" value="monline_dg"/>
+  <Param name="tn" value="monline_7_dg"/>
   <Param name="ie" value="utf-8"/>
   <Param name="action" value="opensearch"/>
 </Url>
 <Url type="text/html" method="GET" template="https://www.baidu.com/baidu" resultdomain="baidu.com">
   <Param name="wd" value="{searchTerms}"/>
-  <Param name="tn" value="monline_dg"/>
+  <Param name="tn" value="monline_7_dg"/>
   <Param name="ie" value="utf-8"/>
 </Url>
 <SearchForm>https://www.baidu.com/</SearchForm>
 </SearchPlugin>
--- a/browser/components/search/test/unit/test_urlTelemetry.js
+++ b/browser/components/search/test/unit/test_urlTelemetry.js
@@ -62,25 +62,25 @@ add_task(async function test_parsing_sea
 
   // DuckDuckGo organic.
   SearchTelemetry.updateTrackingStatus({}, "https://duckduckgo.com/?q=test&t=hi&ia=news");
   hs = Services.telemetry.getKeyedHistogramById("SEARCH_COUNTS").snapshot();
   Assert.ok(hs);
   Assert.ok("duckduckgo.in-content:organic:hi" in hs, "The histogram must contain the correct key");
 
   // Baidu search access point.
-  SearchTelemetry.updateTrackingStatus({}, "https://www.baidu.com/baidu?wd=test&tn=monline_dg&ie=utf-8");
+  SearchTelemetry.updateTrackingStatus({}, "https://www.baidu.com/baidu?wd=test&tn=monline_7_dg&ie=utf-8");
   hs = Services.telemetry.getKeyedHistogramById("SEARCH_COUNTS").snapshot();
   Assert.ok(hs);
-  Assert.ok("baidu.in-content:sap:monline_dg" in hs, "The histogram must contain the correct key");
+  Assert.ok("baidu.in-content:sap:monline_7_dg" in hs, "The histogram must contain the correct key");
 
   // Baidu search access point follow-on.
-  SearchTelemetry.updateTrackingStatus({}, "https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&tn=monline_dg&wd=test2&oq=test&rsv_pq=RSV_PQ_VALUE&rsv_t=RSV_T_VALUE&rqlang=cn&rsv_enter=1&rsv_sug3=2&rsv_sug2=0&inputT=227&rsv_sug4=397");
+  SearchTelemetry.updateTrackingStatus({}, "https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&tn=monline_7_dg&wd=test2&oq=test&rsv_pq=RSV_PQ_VALUE&rsv_t=RSV_T_VALUE&rqlang=cn&rsv_enter=1&rsv_sug3=2&rsv_sug2=0&inputT=227&rsv_sug4=397");
   hs = Services.telemetry.getKeyedHistogramById("SEARCH_COUNTS").snapshot();
   Assert.ok(hs);
-  Assert.ok("baidu.in-content:sap-follow-on:monline_dg" in hs, "The histogram must contain the correct key");
+  Assert.ok("baidu.in-content:sap-follow-on:monline_7_dg" in hs, "The histogram must contain the correct key");
 
   // Baidu organic.
   SearchTelemetry.updateTrackingStatus({}, "https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&ch=&tn=baidu&bar=&wd=test&rn=&oq=&rsv_pq=RSV_PQ_VALUE&rsv_t=RSV_T_VALUE&rqlang=cn");
   hs = Services.telemetry.getKeyedHistogramById("SEARCH_COUNTS").snapshot();
   Assert.ok(hs);
   Assert.ok("baidu.in-content:organic:baidu" in hs, "The histogram must contain the correct key");
 });
--- a/browser/components/urlbar/UrlbarInput.jsm
+++ b/browser/components/urlbar/UrlbarInput.jsm
@@ -171,16 +171,20 @@ class UrlbarInput {
       this.inputField.removeEventListener(name, this);
     }
     this.removeEventListener("mousedown", this);
 
     this.view.panel.remove();
 
     this.inputField.controllers.removeControllerAt(0);
 
+    if (Object.getOwnPropertyDescriptor(this, "valueFormatter").get) {
+      this.valueFormatter.uninit();
+    }
+
     delete this.document;
     delete this.window;
     delete this.eventBufferer;
     delete this.valueFormatter;
     delete this.panel;
     delete this.view;
     delete this.controller;
     delete this.textbox;
--- a/browser/components/urlbar/UrlbarValueFormatter.jsm
+++ b/browser/components/urlbar/UrlbarValueFormatter.jsm
@@ -26,16 +26,22 @@ class UrlbarValueFormatter {
   constructor(urlbarInput) {
     this.urlbarInput = urlbarInput;
     this.window = this.urlbarInput.window;
     this.document = this.window.document;
 
     // This is used only as an optimization to avoid removing formatting in
     // the _remove* format methods when no formatting is actually applied.
     this._formattingApplied = false;
+
+    this.window.addEventListener("resize", this);
+  }
+
+  uninit() {
+    this.window.removeEventListener("resize", this);
   }
 
   get inputField() {
     return this.urlbarInput.inputField;
   }
 
   get scheme() {
     return this.document.getAnonymousElementByAttribute(
@@ -54,17 +60,17 @@ class UrlbarValueFormatter {
     // Apply new formatting.  Formatter methods should return true if they
     // successfully formatted the value and false if not.  We apply only
     // one formatter at a time, so we stop at the first successful one.
     this._formattingApplied =
       this._formatURL() ||
       this._formatSearchAlias();
   }
 
-  ensureFormattedHostVisible(urlMetaData) {
+  _ensureFormattedHostVisible(urlMetaData) {
     // Used to avoid re-entrance in the requestAnimationFrame callback.
     let instance = this._formatURLInstance = {};
 
     // Make sure the host is always visible. Since it is aligned on
     // the first strong directional character, we set scrollLeft
     // appropriately to ensure the domain stays visible in case of an
     // overflow.
     this.window.requestAnimationFrame(() => {
@@ -189,17 +195,17 @@ class UrlbarValueFormatter {
     let { url, uriInfo, preDomain, schemeWSlashes, domain, trimmedLength } = urlMetaData;
     // We strip http, so we should not show the scheme box for it.
     if (!UrlbarPrefs.get("trimURLs") || schemeWSlashes != "http://") {
       this.scheme.value = schemeWSlashes;
       this.inputField.style.setProperty("--urlbar-scheme-size",
                                         schemeWSlashes.length + "ch");
     }
 
-    this.ensureFormattedHostVisible(urlMetaData);
+    this._ensureFormattedHostVisible(urlMetaData);
 
     if (!UrlbarPrefs.get("formatting.enabled")) {
       return false;
     }
 
     let editor = this.urlbarInput.editor;
     let controller = editor.selectionController;
 
@@ -406,9 +412,39 @@ class UrlbarValueFormatter {
 
     let url = item.getAttribute("url");
     let action = this.urlbarInput._parseActionUrl(url);
     if (!action) {
       return null;
     }
     return action.params.alias || null;
   }
+
+  /**
+   * Passes DOM events to the _on_<event type> methods.
+   * @param {Event} event
+   *   DOM event.
+   */
+  handleEvent(event) {
+    let methodName = "_on_" + event.type;
+    if (methodName in this) {
+      this[methodName](event);
+    } else {
+      throw new Error("Unrecognized UrlbarValueFormatter event: " + event.type);
+    }
+  }
+
+  _on_resize(event) {
+    if (event.target != this.window) {
+      return;
+    }
+    // Make sure the host remains visible in the input field when the window is
+    // resized.  We don't want to hurt resize performance though, so do this
+    // only after resize events have stopped and a small timeout has elapsed.
+    if (this._resizeThrottleTimeout) {
+      this.window.clearTimeout(this._resizeThrottleTimeout);
+    }
+    this._resizeThrottleTimeout = this.window.setTimeout(() => {
+      this._resizeThrottleTimeout = null;
+      this._ensureFormattedHostVisible();
+    }, 100);
+  }
 }
--- a/browser/components/urlbar/tests/browser/browser.ini
+++ b/browser/components/urlbar/tests/browser/browser.ini
@@ -107,16 +107,17 @@ support-files =
 [browser_urlbarEnter.js]
 [browser_urlbarEnterAfterMouseOver.js]
 skip-if = os == "linux" # Bug 1073339 - Investigate autocomplete test unreliability on Linux/e10s
 [browser_urlbarFocusedCmdK.js]
 [browser_urlbarHashChangeProxyState.js]
 [browser_UrlbarInput_formatValue.js]
 [browser_UrlbarInput_hiddenFocus.js]
 [browser_UrlbarInput_overflow.js]
+[browser_UrlbarInput_overflow_resize.js]
 [browser_UrlbarInput_tooltip.js]
 [browser_UrlbarInput_trimURLs.js]
 subsuite = clipboard
 [browser_UrlbarInput_unit.js]
 support-files = empty.xul
 [browser_UrlbarLoadRace.js]
 [browser_urlbarOneOffs_contextMenu.js]
 support-files =
new file mode 100644
--- /dev/null
+++ b/browser/components/urlbar/tests/browser/browser_UrlbarInput_overflow_resize.js
@@ -0,0 +1,50 @@
+/* Any copyright is dedicated to the Public Domain.
+ * https://creativecommons.org/publicdomain/zero/1.0/ */
+
+async function testVal(win, url) {
+  info(`Testing ${url}`);
+  win.URLBarSetURI(makeURI(url));
+
+  let urlbar = win.gURLBar;
+  urlbar.blur();
+
+  for (let width of [1000, 800]) {
+    win.resizeTo(width, 500);
+    await win.promiseDocumentFlushed(() => {});
+    Assert.greater(urlbar.inputField.scrollWidth, urlbar.inputField.clientWidth,
+                   "Check The input field overflows");
+    // Resize is handled on a timer, so we must wait for it.
+    await TestUtils.waitForCondition(
+      () => urlbar.inputField.scrollLeft == urlbar.inputField.scrollLeftMax,
+      "The urlbar input field is completely scrolled to the end");
+    await TestUtils.waitForCondition(
+      () => urlbar.getAttribute("textoverflow") == "start",
+      "Wait for the textoverflow attribute");
+  }
+}
+
+add_task(async function() {
+  // We use a new tab for the test to be sure all the tab switching and loading
+  // is complete before starting, otherwise onLocationChange for this tab could
+  // override the value we set with an empty value.
+  let win = await BrowserTestUtils.openNewBrowserWindow();
+  registerCleanupFunction(() => BrowserTestUtils.closeWindow(win));
+
+  let lotsOfSpaces = "%20".repeat(200);
+
+  // اسماء.شبكة
+  let rtlDomain = "\u0627\u0633\u0645\u0627\u0621\u002e\u0634\u0628\u0643\u0629";
+
+  // Mix the direction of the tests to cover more cases, and to ensure the
+  // textoverflow attribute changes every time, because tewtVal waits for that.
+  await testVal(win, `https://${rtlDomain}/${lotsOfSpaces}/test/`);
+
+  info("Test with formatting and trimurl disabled");
+  await SpecialPowers.pushPrefEnv({set: [
+    ["browser.urlbar.formatting.enabled", false],
+    ["browser.urlbar.trimURLs", false],
+  ]});
+
+  await testVal(win, `https://${rtlDomain}/${lotsOfSpaces}/test/`);
+  await testVal(win, `http://${rtlDomain}/${lotsOfSpaces}/test/`);
+});
--- a/browser/components/urlbar/tests/legacy/browser.ini
+++ b/browser/components/urlbar/tests/legacy/browser.ini
@@ -117,16 +117,17 @@ support-files =
   ../browser/file_urlbar_edit_dos.html
 [../browser/browser_urlbarDelete.js]
 [../browser/browser_urlbarEnter.js]
 [../browser/browser_urlbarEnterAfterMouseOver.js]
 skip-if = os == "linux" # Bug 1073339 - Investigate autocomplete test unreliability on Linux/e10s
 [../browser/browser_urlbar_whereToOpen.js]
 [../browser/browser_urlbarFocusedCmdK.js]
 [../browser/browser_urlbarHashChangeProxyState.js]
+[../browser/browser_UrlbarInput_overflow_resize.js]
 [../browser/browser_urlbarOneOffs_contextMenu.js]
 support-files =
   ../browser/searchSuggestionEngine.xml
   ../browser/searchSuggestionEngine.sjs
 [../browser/browser_urlbarOneOffs_searchSuggestions.js]
 support-files =
   ../browser/searchSuggestionEngine.xml
   ../browser/searchSuggestionEngine.sjs
--- a/browser/modules/test/browser/browser_PageActions.js
+++ b/browser/modules/test/browser/browser_PageActions.js
@@ -1444,17 +1444,17 @@ add_task(async function contextMenu() {
   aboutAddonsTab = values[0];
   BrowserTestUtils.removeTab(aboutAddonsTab);
 
   // Done, clean up.
   action.remove();
 
   // Check the telemetry was collected properly.
   let snapshot = Services.telemetry.snapshotEvents(
-    Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true);
+    Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS, true);
   ok(snapshot.parent && snapshot.parent.length > 0,
      "Got parent telemetry events in the snapshot");
   let relatedEvents = snapshot.parent
     .filter(([timestamp, category, method]) =>
       category == "addonsManager" && method == "action")
     .map(relatedEvent => relatedEvent.slice(3, 6));
   Assert.deepEqual(relatedEvents, [
     ["pageAction", null, {action: "manage"}],
--- a/browser/modules/test/browser/browser_UsageTelemetry_urlbar_extension.js
+++ b/browser/modules/test/browser/browser_UsageTelemetry_urlbar_extension.js
@@ -20,17 +20,17 @@ function assertSearchTelemetryEmpty(sear
   const scalars = TelemetryTestUtils.getProcessScalars("parent", true, false);
   Assert.ok(!(SCALAR_URLBAR in scalars), `Should not have recorded ${SCALAR_URLBAR}`);
 
   // Make sure SEARCH_COUNTS contains identical values.
   TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.urlbar", undefined);
   TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.alias", undefined);
 
   // Also check events.
-  let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
+  let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS, false);
   events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search");
   Assert.deepEqual(events, [], "Should not have recorded any navigation search events");
 }
 
 function snapshotHistograms() {
   Services.telemetry.clearScalars();
   Services.telemetry.clearEvents();
   return {
--- a/browser/modules/test/browser/browser_UsageTelemetry_urlbar_places.js
+++ b/browser/modules/test/browser/browser_UsageTelemetry_urlbar_places.js
@@ -28,17 +28,17 @@ function assertSearchTelemetryEmpty(sear
   const scalars = TelemetryTestUtils.getProcessScalars("parent", true, false);
   Assert.ok(!(SCALAR_URLBAR in scalars), `Should not have recorded ${SCALAR_URLBAR}`);
 
   // Make sure SEARCH_COUNTS contains identical values.
   TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.urlbar", undefined);
   TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.alias", undefined);
 
   // Also check events.
-  let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
+  let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS, false);
   events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search");
   Assert.deepEqual(events, [], "Should not have recorded any navigation search events");
 }
 
 function snapshotHistograms() {
   Services.telemetry.clearScalars();
   Services.telemetry.clearEvents();
   return {
--- a/browser/modules/test/browser/browser_UsageTelemetry_urlbar_remotetab.js
+++ b/browser/modules/test/browser/browser_UsageTelemetry_urlbar_remotetab.js
@@ -22,17 +22,17 @@ function assertSearchTelemetryEmpty(sear
   const scalars = TelemetryTestUtils.getProcessScalars("parent", true, false);
   Assert.ok(!(SCALAR_URLBAR in scalars), `Should not have recorded ${SCALAR_URLBAR}`);
 
   // Make sure SEARCH_COUNTS contains identical values.
   TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.urlbar", undefined);
   TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.alias", undefined);
 
   // Also check events.
-  let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
+  let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS, false);
   events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search");
   Assert.deepEqual(events, [], "Should not have recorded any navigation search events");
 }
 
 function snapshotHistograms() {
   Services.telemetry.clearScalars();
   Services.telemetry.clearEvents();
   return {
--- a/browser/themes/shared/fxa/choose-what-to-sync-devices.svg
+++ b/browser/themes/shared/fxa/choose-what-to-sync-devices.svg
@@ -1,27 +1,23 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="201" height="102">
   <g>
     <path fill="#eaeaee" d="M142.1 93.3c-3 0-5.9-.3-8.8-.9-.3-.1-.4-.3-.4-.6.1-.3.3-.4.6-.4 2.8.6 5.6.9 8.5.9.7 0 1.5 0 2.2-.1.3 0 .5.2.5.4 0 .3-.2.5-.5.5-.7.2-1.4.2-2.1.2zm8.6-.9c-.3 0-.5-.2-.5-.5 0-.2.2-.4.4-.5.7-.1 1.4-.3 2.1-.5.3-.1.5.1.6.4.1.3-.1.5-.4.6-.7.2-1.4.4-2.1.5h-.1zm6.2-1.8c-.3 0-.5-.2-.5-.5 0-.2.1-.4.3-.5 2.7-1 5.2-2.3 7.6-3.9.2-.2.5-.1.7.1s.1.5-.1.7c-2.5 1.6-5.1 2.9-7.8 4-.1.1-.1.1-.2.1zm-31.8-.8h-.2c-2.7-1.2-5.2-2.7-7.6-4.4-.2-.2-.3-.5-.1-.7.2-.2.5-.3.7-.1 2.3 1.7 4.8 3.1 7.4 4.3.3.1.4.4.3.7-.1 0-.3.2-.5.2zm-10.9-7.1c-.1 0-.2 0-.3-.1-.5-.5-1.1-1-1.6-1.5-.2-.2-.2-.5 0-.7.2-.2.5-.2.7 0 .5.5 1 1 1.6 1.5.2.2.2.5 0 .7-.1 0-.2.1-.4.1zm57.2-1.6c-.3 0-.5-.2-.5-.5 0-.1.1-.3.1-.4 2.5-2.5 4.7-5.4 6.5-8.5.1-.2.4-.3.7-.2.2.1.3.4.2.7-1.8 3.2-4.1 6.1-6.7 8.7 0 .2-.2.2-.3.2zm-63-4.9c-.2 0-.3-.1-.4-.2-2.2-3-3.9-6.2-5.3-9.6-.1-.3 0-.5.3-.6s.5 0 .6.3c1.3 3.3 3 6.5 5.1 9.4.2.2.1.5-.1.7h-.2zm72.4-9.5c-.3 0-.5-.2-.5-.5V66c.3-.7.5-1.3.7-2 .1-.3.4-.4.6-.3.3.1.4.4.3.6-.2.7-.5 1.4-.7 2.1 0 .1-.2.3-.4.3zm1.9-6.3h-.1c-.3-.1-.4-.3-.4-.6.6-2.8.9-5.7.9-8.5v-.2c0-.3.2-.5.5-.5s.5.2.5.5v.2c0 2.9-.3 5.9-.9 8.7-.1.2-.3.4-.5.4zM101 58.3c-.2 0-.5-.2-.5-.4-.3-2.2-.5-4.4-.5-6.7 0-.7 0-1.4.1-2.1 0-.3.2-.5.5-.5s.5.2.5.5c0 .7-.1 1.4-.1 2.1 0 2.2.2 4.4.5 6.5 0 .3-.2.6-.5.6zm82.3-11c-.3 0-.5-.2-.5-.4-.3-2.9-.9-5.7-1.8-8.4-.1-.3.1-.5.3-.6s.5.1.6.3c.9 2.8 1.5 5.7 1.9 8.6 0 .2-.2.4-.5.5.1 0 .1 0 0 0 .1 0 0 0 0 0zm-82.4-2c-.3 0-.5-.3-.5-.6.1-.7.2-1.5.4-2.2.1-.3.3-.4.6-.4.3.1.4.3.4.6-.1.7-.3 1.4-.4 2.1 0 .4-.2.5-.5.5zm2.3-8.4c-.3 0-.5-.2-.5-.5v-.2c1.3-3.4 3.1-6.7 5.2-9.7.2-.2.5-.3.7-.1s.3.5.1.7c-2.1 2.9-3.8 6.1-5.1 9.4 0 .3-.2.4-.4.4zm74.7-6.1c-.2 0-.3-.1-.4-.2-1.8-3.1-4-5.9-6.6-8.5-.2-.2-.2-.5 0-.7.2-.2.5-.2.7 0 2.6 2.6 4.9 5.5 6.7 8.7.1.2.1.5-.2.7h-.2zm-63.8-9.9c-.3 0-.5-.2-.5-.5 0-.1.1-.3.2-.4 2.2-2 4.6-3.7 7.1-5.2.2-.1.5-.1.7.2s.1.5-.2.7c-2.5 1.4-4.8 3.1-6.9 5.1-.1.1-.3.1-.4.1zm52.2-2.8c-.1 0-.2 0-.3-.1l-1.8-1.2c-.2-.1-.3-.5-.1-.7.1-.2.5-.3.7-.1l1.8 1.2c.2.2.3.5.1.7-.1.1-.2.2-.4.2zm-5.6-3.4c-.1 0-.2 0-.2-.1-2.6-1.3-5.2-2.3-8-3.1-.3-.1-.4-.3-.4-.6.1-.3.3-.4.6-.4 2.8.8 5.6 1.8 8.2 3.1.2.1.3.4.2.7 0 .3-.2.4-.4.4zm-35.7-.9c-.3 0-.5-.2-.5-.5 0-.2.1-.4.3-.5.7-.3 1.3-.6 2-.8.3-.1.5 0 .6.3.1.3 0 .5-.3.6-.7.3-1.3.5-2 .8 0 .1 0 .1-.1.1zm8.2-2.7c-.3 0-.5-.2-.5-.5 0-.2.2-.4.4-.5 3.6-.8 7.3-1.1 10.9-.9.3 0 .5.2.5.5s-.2.5-.5.5c-3.6-.2-7.2.1-10.7.9h-.1z"/>
-    <animateTransform attributeName="transform" attributeType="XML" dur="10s" from="0 142 51" repeatCount="indefinite" to="-360 142 51" type="rotate"/>
   </g>
   <g>
     <path fill="#eaeaee" d="M62.8 93.3c-3 0-5.9-.3-8.8-.9-.3-.1-.4-.3-.4-.6.1-.3.3-.4.6-.4 2.8.6 5.6.9 8.5.9.7 0 1.5 0 2.2-.1.3 0 .5.2.5.4 0 .3-.2.5-.5.5-.6.2-1.3.2-2.1.2zm8.6-.9c-.3 0-.5-.2-.5-.5 0-.2.2-.4.4-.5.7-.1 1.4-.3 2.1-.5.3-.1.5.1.6.4.1.3-.1.5-.4.6-.7.2-1.4.4-2.1.5h-.1zm6.3-1.8c-.3 0-.5-.2-.5-.5 0-.2.1-.4.3-.5 2.7-1 5.2-2.3 7.6-3.9.2-.2.5-.1.7.1s.1.5-.1.7c-2.5 1.6-5.1 2.9-7.8 4-.1.1-.2.1-.2.1zm-31.8-.8h-.2c-2.7-1.2-5.2-2.7-7.6-4.4-.2-.2-.3-.5-.1-.7.2-.2.5-.3.7-.1 2.3 1.7 4.8 3.1 7.4 4.3.3.1.4.4.3.7-.1 0-.3.2-.5.2zM35 82.7c-.1 0-.2 0-.3-.1-.5-.5-1.1-1-1.6-1.5-.2-.2-.2-.5 0-.7.2-.2.5-.2.7 0 .5.5 1 1 1.6 1.5.2.2.2.5 0 .7-.1 0-.3.1-.4.1zm57.2-1.6c-.3 0-.5-.2-.5-.5 0-.1.1-.3.1-.4 2.5-2.5 4.7-5.4 6.5-8.5.1-.2.4-.3.7-.2.2.1.3.4.2.7-1.8 3.2-4.1 6.1-6.7 8.7-.1.2-.2.2-.3.2zm-63-4.9c-.2 0-.3-.1-.4-.2-2.2-3-3.9-6.2-5.3-9.6-.1-.3 0-.5.3-.6s.5 0 .6.3c1.3 3.3 3 6.5 5.1 9.4.2.2.1.5-.1.7h-.2zm72.4-9.5c-.3 0-.5-.2-.5-.5V66c.3-.7.5-1.3.7-2 .1-.3.4-.4.6-.3.3.1.4.4.3.6-.2.7-.5 1.4-.7 2.1 0 .1-.2.3-.4.3zm1.8-6.3h-.1c-.3-.1-.4-.3-.4-.6.6-2.8.9-5.7.9-8.5v-.2c0-.3.2-.5.5-.5s.5.2.5.5v.2c0 2.9-.3 5.9-.9 8.7 0 .2-.2.4-.5.4zm-81.7-2.1c-.2 0-.5-.2-.5-.4-.3-2.2-.5-4.4-.5-6.7 0-.7 0-1.4.1-2.1 0-.3.2-.5.5-.5s.5.2.5.5c0 .7-.1 1.4-.1 2.1 0 2.2.2 4.4.5 6.5.1.3-.1.6-.5.6.1 0 0 0 0 0zm82.4-11c-.3 0-.5-.2-.5-.4-.3-2.9-.9-5.7-1.8-8.4-.1-.3.1-.5.3-.6s.5.1.6.3c.9 2.8 1.5 5.7 1.9 8.6 0 .2-.2.4-.5.5zm-82.4-2s-.1 0 0 0c-.3 0-.5-.3-.5-.6.1-.7.2-1.5.4-2.2.1-.3.3-.4.6-.4.3.1.4.3.4.6-.1.7-.3 1.4-.4 2.1 0 .4-.3.5-.5.5zm2.2-8.4c-.3 0-.5-.2-.5-.5v-.2c1.3-3.4 3.1-6.7 5.2-9.7.2-.2.5-.3.7-.1s.3.5.1.7c-2.1 2.9-3.8 6.1-5.1 9.4 0 .3-.2.4-.4.4zm74.8-6.1c-.2 0-.3-.1-.4-.2-1.8-3.1-4-5.9-6.6-8.5-.2-.2-.2-.5 0-.7.2-.2.5-.2.7 0 2.6 2.6 4.9 5.5 6.7 8.7.1.2.1.5-.2.7h-.2zm-63.8-9.9c-.3 0-.5-.2-.5-.5 0-.1.1-.3.2-.4 2.2-2 4.6-3.7 7.1-5.2.2-.1.5-.1.7.2s.1.5-.2.7c-2.5 1.4-4.8 3.1-6.9 5.1-.2.1-.3.1-.4.1zm52.2-2.8c-.1 0-.2 0-.3-.1L85 16.8c-.2-.1-.3-.5-.1-.7.1-.2.5-.3.7-.1l1.8 1.2c.2.2.3.5.1.7-.1.1-.3.2-.4.2zm-5.6-3.4c-.1 0-.2 0-.2-.1-2.6-1.3-5.2-2.3-8-3.1-.3-.1-.4-.3-.4-.6.1-.3.3-.4.6-.4 2.8.8 5.6 1.8 8.2 3.1.2.1.3.4.2.7 0 .3-.2.4-.4.4zm-35.7-.9c-.3 0-.5-.2-.5-.5 0-.2.1-.4.3-.5.7-.3 1.3-.6 2-.8.3-.1.5 0 .6.3.1.3 0 .5-.3.6-.7.3-1.3.5-2 .8 0 .1-.1.1-.1.1zm8.2-2.7c-.3 0-.5-.2-.5-.5 0-.2.2-.4.4-.5 3.6-.8 7.3-1.1 10.9-.9.3 0 .5.2.5.5s-.2.5-.5.5c-3.6-.2-7.2.1-10.7.9H54z"/>
-    <animateTransform attributeName="transform" attributeType="XML" dur="10s" from="0 62 51" repeatCount="indefinite" to="360 62 51" type="rotate"/>
   </g>
   <g>
     <path fill="#eaeaee" d="M62.6 102.5c-.9 0-1.7 0-2.6-.1-.3 0-.5-.2-.5-.5s.3-.5.5-.5c3.8.2 7.6 0 11.3-.7.3 0 .5.1.6.4 0 .3-.1.5-.4.6-2.9.5-5.9.8-8.9.8zm-10.1-1h-.1c-.9-.2-1.9-.4-2.8-.7-.3-.1-.4-.3-.4-.6s.3-.4.6-.4c.9.2 1.8.5 2.8.6.3.1.4.3.4.6-.1.3-.3.5-.5.5zM46 99.7h-.2l-.9-.3c-.3-.1-.4-.4-.3-.6s.4-.4.6-.3l.9.3c.3.1.4.4.3.6 0 .2-.2.3-.4.3zm33.8-.2c-.3 0-.5-.2-.5-.5 0-.2.1-.4.3-.5l.9-.3c.3-.1.5 0 .6.3s0 .5-.3.6l-.9.3c0 .1 0 .1-.1.1zm4.4-1.8c-.3 0-.5-.2-.5-.5 0-.2.1-.4.3-.5.9-.4 1.7-.8 2.5-1.3.2-.1.5 0 .7.2s0 .5-.2.7c-.8.5-1.7.9-2.6 1.3 0 .1-.1.1-.2.1zm-46.9-2c-.1 0-.2 0-.2-.1-3.4-1.9-6.5-4.2-9.3-6.9-.2-.2-.2-.5 0-.7.2-.2.5-.2.7 0 2.8 2.6 5.8 4.8 9.1 6.7.2.1.3.4.2.7-.1.3-.3.4-.5.3zm55.9-3.4c-.3 0-.5-.2-.5-.5 0-.2.1-.3.2-.4 3-2.3 5.8-4.9 8.2-7.8.2-.2.5-.2.7-.1s.2.5.1.7c-2.5 3-5.3 5.6-8.4 8-.1 0-.2.1-.3.1zm-70.3-9c-.2 0-.3-.1-.4-.2-.6-.7-1.2-1.5-1.7-2.3-.2-.2-.1-.5.1-.7.2-.2.5-.1.7.1.5.8 1.1 1.5 1.7 2.3.2.2.1.5-.1.7-.1.1-.2.1-.3.1zm-3.8-5.5c-.2 0-.3-.1-.4-.2-.2-.3-.3-.6-.5-.8-.1-.2-.1-.5.2-.7s.5-.1.7.2c.2.3.3.5.5.8.1.2.1.5-.2.7h-.3zm87.4-.5c-.3 0-.5-.2-.5-.5 0-.1 0-.2.1-.3.2-.3.3-.5.5-.8.1-.2.4-.3.7-.2.2.1.3.4.2.7-.2.3-.3.6-.5.8-.2.2-.3.3-.5.3zm2.2-4.2h-.2c-.3-.1-.4-.4-.2-.7.4-.9.8-1.7 1.1-2.6.1-.3.4-.4.7-.3.3.1.4.4.3.6-.4.9-.7 1.8-1.1 2.7-.2.2-.4.3-.6.3zM15 69.2c-.2 0-.4-.1-.5-.3-1.3-3.6-2.2-7.4-2.7-11.2 0-.3.2-.5.4-.6.3 0 .5.2.6.4.5 3.8 1.4 7.5 2.7 11 .1.3 0 .5-.3.6-.1.1-.2.1-.2.1zm97.1-6.1h-.1c-.3-.1-.4-.3-.4-.6.8-3.7 1.3-7.5 1.3-11.3V51c0-.3.2-.5.5-.5s.5.2.5.5v.2c0 3.9-.4 7.7-1.3 11.5-.1.3-.3.4-.5.4zM11.9 50.4c-.3 0-.5-.2-.5-.5 0-1 .1-1.9.2-2.9 0-.3.3-.5.5-.5.3 0 .5.3.5.5-.1.9-.1 1.9-.2 2.8 0 .4-.2.6-.5.6zm.6-6.6c-.4 0-.5-.3-.5-.6.1-.3.1-.6.2-1 0-.3.3-.5.6-.4s.5.3.4.6c-.1.3-.1.6-.2.9 0 .3-.2.5-.5.5zm100.1-.8c-.2 0-.5-.2-.5-.4-.1-.3-.1-.6-.2-.9-.1-.3.1-.5.4-.6s.5.1.6.4c.1.3.1.6.2 1 .1.2-.1.4-.5.5.1 0 .1 0 0 0 .1 0 .1 0 0 0zm-1-4.7c-.2 0-.4-.2-.5-.4-.2-.9-.5-1.8-.8-2.7-.1-.3.1-.5.3-.6.3-.1.5.1.6.3.3.9.6 1.8.8 2.8.1.3-.1.5-.4.6.1 0 0 0 0 0zm-96.7-3.8h-.2c-.3-.1-.4-.4-.3-.6 1.3-3.6 3-7.1 5.1-10.4.1-.2.5-.3.7-.1.2.1.3.5.1.7-2.1 3.2-3.8 6.6-5 10.2 0 .1-.2.2-.4.2zm92.9-6c-.2 0-.4-.1-.4-.3-1.7-3.4-3.9-6.5-6.3-9.4-.2-.2-.2-.5.1-.7s.5-.2.7.1c2.5 3 4.7 6.2 6.4 9.6.1.2 0 .5-.2.7h-.3zM24.6 18.1c-.3 0-.5-.2-.5-.5 0-.1 0-.2.1-.3.6-.7 1.3-1.4 2-2.1.2-.2.5-.2.7 0 .2.2.2.5 0 .7-.7.7-1.3 1.4-1.9 2.1-.1.1-.2.1-.4.1zm4.8-4.7c-.3 0-.5-.2-.5-.5 0-.1.1-.3.2-.4.2-.2.5-.4.7-.6.2-.2.5-.1.7.1.2.2.1.5-.1.7-.2.2-.5.4-.7.6-.1.1-.2.1-.3.1zm65.9-.5c-.1 0-.2 0-.3-.1-.2-.2-.5-.4-.7-.6-.3-.2-.3-.5-.1-.7s.5-.2.7-.1c.3.2.5.4.7.6.2.2.2.5.1.7-.1.2-.2.2-.4.2zM91.5 10c-.1 0-.2 0-.3-.1-.8-.5-1.6-1.1-2.4-1.6-.2-.1-.3-.5-.2-.7s.5-.3.7-.2c.8.5 1.6 1 2.4 1.6.2.2.3.5.1.7 0 .2-.1.3-.3.3zM37.1 7.9c-.3 0-.5-.2-.5-.5 0-.2.1-.3.2-.4 3.3-1.9 6.9-3.5 10.6-4.7.3-.1.5.1.6.3.1.3-.1.5-.3.6-3.6 1.1-7.1 2.7-10.4 4.6 0 0-.1.1-.2.1zM82.3 5h-.2c-3.5-1.5-7.2-2.5-10.9-3.2-.3 0-.5-.3-.4-.6 0-.3.3-.5.6-.4 3.8.7 7.5 1.7 11.1 3.2.3.1.4.4.3.7-.1.1-.3.3-.5.3zM55.1 1.6c-.3 0-.5-.2-.5-.5 0-.2.2-.5.4-.5.9-.1 1.9-.3 2.9-.3.3 0 .5.2.5.5s-.2.5-.5.5c-.9 0-1.8.1-2.8.3zm6.7-.6c-.3 0-.5-.2-.5-.5s.2-.5.5-.5h.9c.3 0 .5.2.5.5s-.2.5-.5.5h-.9z"/>
-    <animateTransform attributeName="transform" attributeType="XML" dur="10s" from="0 62 51" repeatCount="indefinite" to="-360 62 51" type="rotate"/>
   </g>
   <g>
     <path fill="#eaeaee" d="M142.1 102.5c-.9 0-1.7 0-2.6-.1-.3 0-.5-.2-.5-.5s.3-.5.5-.5c3.8.2 7.6 0 11.3-.7.3 0 .5.1.6.4 0 .3-.1.5-.4.6-2.9.5-5.9.8-8.9.8zm-10.2-1h-.1c-.9-.2-1.9-.4-2.8-.7-.3-.1-.4-.3-.4-.6s.3-.4.6-.4c.9.2 1.8.5 2.8.6.3.1.4.3.4.6s-.2.5-.5.5zm-6.4-1.8h-.2l-.9-.3c-.3-.1-.4-.4-.3-.6s.4-.4.6-.3l.9.3c.3.1.4.4.3.6 0 .2-.2.3-.4.3zm33.8-.2c-.3 0-.5-.2-.5-.5 0-.2.1-.4.3-.5l.9-.3c.3-.1.5 0 .6.3s0 .5-.3.6l-.9.3c0 .1-.1.1-.1.1zm4.4-1.8c-.3 0-.5-.2-.5-.5 0-.2.1-.4.3-.5.9-.4 1.7-.8 2.5-1.3.2-.1.5 0 .7.2s0 .5-.2.7c-.8.5-1.7.9-2.6 1.3-.1.1-.1.1-.2.1zm-46.9-2c-.1 0-.2 0-.2-.1-3.4-1.9-6.5-4.2-9.3-6.9-.2-.2-.2-.5 0-.7.2-.2.5-.2.7 0 2.8 2.6 5.8 4.8 9.1 6.7.2.1.3.4.2.7-.2.2-.3.3-.5.3zm55.9-3.4c-.3 0-.5-.2-.5-.5 0-.2.1-.3.2-.4 3-2.3 5.8-4.9 8.2-7.8.2-.2.5-.2.7-.1s.2.5.1.7c-2.5 3-5.3 5.6-8.4 8-.1 0-.2.1-.3.1zm-70.3-9c-.2 0-.3-.1-.4-.2-.6-.7-1.2-1.5-1.7-2.3-.2-.2-.1-.5.1-.7.2-.2.5-.1.7.1.5.8 1.1 1.5 1.7 2.3.2.2.1.5-.1.7-.1.1-.2.1-.3.1zm-3.9-5.5c-.2 0-.3-.1-.4-.2-.2-.3-.3-.6-.5-.8-.1-.2-.1-.5.2-.7s.5-.1.7.2c.2.3.3.5.5.8.1.2.1.5-.2.7h-.3zm87.4-.5c-.3 0-.5-.2-.5-.5 0-.1 0-.2.1-.3.2-.3.3-.5.5-.8.1-.2.4-.3.7-.2.2.1.3.4.2.7-.2.3-.3.6-.5.8-.1.2-.3.3-.5.3zm2.3-4.2h-.2c-.3-.1-.4-.4-.2-.7.4-.9.8-1.7 1.1-2.6.1-.3.4-.4.7-.3.3.1.4.4.3.6-.4.9-.7 1.8-1.1 2.7-.3.2-.4.3-.6.3zm-93.8-3.9c-.2 0-.4-.1-.5-.3-1.3-3.6-2.2-7.4-2.7-11.2 0-.3.2-.5.4-.6.3 0 .5.2.6.4.5 3.8 1.4 7.5 2.7 11 .1.3 0 .5-.3.6-.1.1-.1.1-.2.1zm97.2-6.1h-.1c-.3-.1-.4-.3-.4-.6.8-3.7 1.3-7.5 1.3-11.3V51c0-.3.2-.5.5-.5s.5.2.5.5v.2c0 3.9-.4 7.7-1.3 11.5-.1.3-.3.4-.5.4zM91.4 50.4c-.3 0-.5-.2-.5-.5 0-1 .1-1.9.2-2.9 0-.3.3-.5.5-.5.3 0 .5.3.5.5-.1.9-.1 1.9-.2 2.8 0 .4-.3.6-.5.6zm.6-6.6c-.1 0-.1 0 0 0-.4 0-.5-.3-.5-.6.1-.3.1-.6.2-1 0-.3.3-.5.6-.4s.5.3.4.6c-.1.3-.1.6-.2.9-.1.3-.3.5-.5.5zm100.1-.8c-.2 0-.5-.2-.5-.4-.1-.3-.1-.6-.2-.9-.1-.3.1-.5.4-.6s.5.1.6.4c.1.3.1.6.2 1 0 .2-.1.4-.5.5.1 0 .1 0 0 0zm-1.1-4.7c-.2 0-.4-.2-.5-.4-.2-.9-.5-1.8-.8-2.7-.1-.3.1-.5.3-.6.3-.1.5.1.6.3.3.9.6 1.8.8 2.8.1.3-.1.5-.4.6.1 0 .1 0 0 0zm-96.6-3.8h-.2c-.3-.1-.4-.4-.3-.6 1.3-3.6 3-7.1 5.1-10.4.1-.2.5-.3.7-.1.2.1.3.5.1.7-2.1 3.2-3.8 6.6-5 10.2 0 .1-.2.2-.4.2zm92.8-6c-.2 0-.4-.1-.4-.3-1.7-3.4-3.9-6.5-6.3-9.4-.2-.2-.2-.5.1-.7s.5-.2.7.1c2.5 3 4.7 6.2 6.4 9.6.1.2 0 .5-.2.7h-.3zm-83.1-10.4c-.3 0-.5-.2-.5-.5 0-.1 0-.2.1-.3.6-.7 1.3-1.4 2-2.1.2-.2.5-.2.7 0 .2.2.2.5 0 .7-.7.7-1.3 1.4-1.9 2.1-.1.1-.3.1-.4.1zm4.7-4.7c-.3 0-.5-.2-.5-.5 0-.1.1-.3.2-.4.2-.2.5-.4.7-.6.2-.2.5-.1.7.1.2.2.1.5-.1.7-.2.2-.5.4-.7.6 0 .1-.2.1-.3.1zm66-.5c-.1 0-.2 0-.3-.1-.2-.2-.5-.4-.7-.6-.2-.2-.2-.5-.1-.7s.5-.2.7-.1c.3.2.5.4.7.6.2.2.2.5.1.7-.1.1-.3.2-.4.2zM171 10c-.1 0-.2 0-.3-.1-.8-.5-1.6-1.1-2.4-1.6-.2-.1-.3-.5-.2-.7s.5-.3.7-.2c.8.5 1.6 1 2.4 1.6.2.2.3.5.1.7 0 .2-.2.3-.3.3zm-54.4-2.1c-.3 0-.5-.2-.5-.5 0-.2.1-.3.2-.4 3.3-1.9 6.9-3.5 10.6-4.7.3-.1.5.1.6.3.1.3-.1.5-.3.6-3.6 1.1-7.1 2.7-10.4 4.6 0 0-.1.1-.2.1zm45.2-3h-.2c-3.5-1.5-7.2-2.5-10.9-3.2-.3 0-.5-.3-.4-.6 0-.3.3-.5.6-.4 3.8.7 7.5 1.7 11.1 3.2.3.1.4.4.3.7-.2.2-.3.3-.5.3zm-27.3-3.3c-.3 0-.5-.2-.5-.5 0-.2.2-.5.4-.5.9-.1 1.9-.3 2.9-.3.3 0 .5.2.5.5s-.2.5-.5.5c-.8 0-1.7.1-2.8.3.1 0 .1 0 0 0zm6.7-.6c-.3 0-.5-.2-.5-.5s.2-.5.5-.5h.9c.3 0 .5.2.5.5s-.2.5-.4.5h-1z"/>
-    <animateTransform attributeName="transform" attributeType="XML" dur="10s" from="0 142 51" repeatCount="indefinite" to="360 142 51" type="rotate"/>
   </g>
   <path fill="#eaeaee" d="M142.1 6c12 0 23.5 4.8 32 13.3h2.8c-16.3-17.8-43.3-20.4-62.7-6.1h3.5c7.2-4.7 15.7-7.2 24.4-7.2zm0 90.5c-9.3 0-18.4-2.9-26.1-8.3h-3.3c20.3 16.2 50 12.9 66.2-7.4.1-.1.2-.2.2-.3h-2.6c-8.5 10.1-21.1 16-34.4 16zM62.6 6c8.7 0 17.2 2.5 24.5 7.2h3.5C74.5 1.3 52.7.9 36.1 12.1h3.8C46.8 8.1 54.6 6 62.6 6zm0 90.5c-10.1 0-20-3.4-27.9-9.7h-3.1c17.2 15.1 42.6 15.6 60.5 1.4h-3.3c-7.7 5.4-16.9 8.3-26.2 8.3z"/>
   <rect width="26" height="45.5" x="170" y="25" fill="#fff" rx="2" ry="2"/>
   <path fill="#90e8f0" d="M178.7 51.9c0 .3.1.7.4.9l.5.3 2.9-1.5 2.4 1.3c.3.2.7.2 1-.1l.5-.4-.4-3.4 2-2.1c.2-.3.3-.6.2-.9l-.2-.5-3.2-.6-1.3-2.6c-.2-.3-.5-.5-.9-.5h-.6l-1.5 3.1-2.7.5c-.3.1-.6.3-.7.6l-.1.6 2.3 2.5-.6 2.8zm2.9-5.6l1-1.9 1 1.9 2.1.4-1.5 1.6.3 2.2-1.9-1-1.9 1 .3-2.2-1.5-1.6 2.1-.4z"/>
   <rect width="42" height="58.5" x="5" y="18" fill="#fff" rx="2" ry="2"/>
   <path fill="#90e8f0" d="M31.7 45.3l-3.6-.6-1.4-2.8c-.2-.4-.6-.6-1-.6H25l-1.7 3.4-3 .5c-.4.1-.7.3-.8.7l-.2.6 2.6 2.8-.5 3.2c0 .4.1.8.4 1l.6.4 3.2-1.7 2.7 1.4c.4.2.8.2 1.1-.1l.5-.4-.5-3.8 2.2-2.3c.3-.3.4-.7.3-1l-.2-.7zm-4.2 3.4l.3 2.3-2-1.1-2 1.1.3-2.4-1.6-1.8 2.3-.4 1-2.1 1 2.1 2.3.4-1.6 1.9z"/>
   <rect width="63" height="39" x="73" y="21" fill="#fff" rx="2" ry="2"/>
   <path fill="#ccedf0" d="M195.6 21.3H170c-1.9 0-3.4 1.5-3.4 3.5V75c0 1.9 1.5 3.4 3.4 3.4h25.6c1.9 0 3.4-1.5 3.4-3.4V24.7c.1-1.9-1.5-3.4-3.4-3.4zm-8.7 52.8c0 .9-.7 1.6-1.6 1.6h-5c-.9 0-1.6-.7-1.6-1.5v-.1c0-.9.7-1.6 1.6-1.6h5c.9 0 1.6.7 1.6 1.6zm8.9-5.4c0 .9-.8 1.7-1.7 1.7h-22.3c-.9 0-1.7-.8-1.7-1.7V26.8c0-.9.8-1.7 1.7-1.7H194c.9 0 1.7.8 1.7 1.7l.1 41.9zM5.7 84.8h41c2 0 3.7-1.6 3.7-3.7V17.8c0-2-1.6-3.7-3.7-3.7h-41c-2 0-3.7 1.6-3.7 3.7v63.3c0 2.1 1.6 3.7 3.7 3.7zm14.4-4v-1.2c0-.7.6-1.3 1.3-1.3h9.5c.7 0 1.3.6 1.3 1.3v1.3c0 .7-.6 1.3-1.3 1.3h-9.5c-.7 0-1.3-.6-1.3-1.4zM5.5 20c0-1 .8-1.8 1.8-1.8H45c1 0 1.8.8 1.8 1.8v54.4c0 1-.8 1.8-1.8 1.9H7.3c-1 0-1.8-.8-1.8-1.8V20zm68.7 43h61.4c2 0 3.6-1.6 3.6-3.5V18.8c0-2-1.6-3.6-3.6-3.6H74.2c-2 0-3.6 1.6-3.6 3.5v40.7c0 2.1 1.6 3.7 3.6 3.6zm29.5-45c0-.6.5-1.1 1.2-1.1.6 0 1.2.5 1.2 1.1 0 .6-.5 1.1-1.2 1.1-.6 0-1.1-.5-1.1-1l-.1-.1zM74 23.3c0-1.2.9-2.1 2.1-2.1h57.7c1.2 0 2.1.9 2.1 2.1v34.4c0 1.2-.9 2.1-2.1 2.1H76.1c-1.2 0-2.1-.9-2.1-2.1V23.3zm70.4 62.9c1.2.1 2.2-.8 2.2-2v-1c0-.3-.1-.5-.2-.7l-7.3-16.1c-.4-.8-1.2-1.3-2.1-1.2H72.3c-.9 0-1.7.5-2.1 1.3l-6.9 16.1c-.1.2-.1.5-.1.7v1.1c.1 1.2 1 2.1 2.2 2l79-.2zm-8.5-15c.1.4.3.8.3 1.1.1.3-.4.6-.9.6h-3.7c-.3 0-.6-.1-.6-.3-.1-.4-.2-.8-.3-1.1-.1-.3.3-.6.8-.6h3.7c.3-.1.5.1.7.3zm-5.5-4h3.5c.3 0 .5.1.6.3.1.4.2.7.3 1.1.1.3-.3.6-.8.6h-3.4c-.3 0-.5-.1-.6-.3-.1-.4-.3-.7-.4-1.1-.1-.2.3-.5.8-.6zm-3.2 4l.2 1.2c.1.3-.4.6-.9.6h-3.8c-.3 0-.6-.1-.7-.3l-.3-1.2c-.1-.3.4-.7.9-.7h3.9c.4.1.7.2.7.4zm-5.2-4h3.7c.3 0 .6.1.6.3l.2 1.1c.1.3-.4.6-.9.6H122c-.3 0-.6-.1-.6-.3l-.3-1.1c-.1-.2.3-.5.9-.6zm-4.4 4c.1.5.1.7.2 1.2 0 .3-.4.6-.9.6H113c-.4 0-.7-.2-.7-.4l-.3-1.2c-.1-.3.4-.6.9-.6h4.1c.3.1.6.3.6.4zm-5-4h3.9c.4 0 .7.2.7.4l.2 1.1c0 .3-.4.6-.8.6h-3.8c-.4 0-.7-.2-.7-.4l-.2-1.1c-.2-.2.2-.5.7-.6zm-10 .5c.1-.2.4-.4.8-.4h3.5c.4 0 .7.2.7.4l.2 1.1c0 .3-.3.5-.8.5h-3.9c-.5 0-.8-.2-.8-.5.1-.4.2-.6.3-1.1zm-.2 3.7c.1-.2.4-.4.8-.4h3.7c.4 0 .8.2.8.4l.2 1.2c.1.3-.3.6-.8.6H103c-.5 0-.9-.3-.8-.6 0-.5.1-.7.2-1.2zm-8.6-4.1h3.9c.5 0 .9.3.8.6s-.2.7-.3 1.1c-.1.3-.4.4-.7.4h-3.8c-.5 0-.9-.3-.8-.6s.2-.7.3-1.1c0-.2.3-.3.6-.4zm-1.4 4.1c0-.2.3-.4.7-.4h4.1c.5 0 .9.3.8.6-.1.5-.2.7-.3 1.2-.1.3-.4.4-.7.4h-3.9c-.5 0-.9-.3-.9-.6.1-.4.1-.7.2-1.2zm-13.2.3c-.2.4-.3.8-.4 1.2-.1.2-.3.3-.6.4h-3.7c-.5 0-1-.3-.9-.7.1-.4.2-.8.4-1.1.1-.2.4-.4.7-.4h3.7c.6 0 .9.3.8.6zm.9-2.6c-.1.2-.4.4-.7.3H76c-.5 0-.8-.3-.7-.6.1-.4.3-.7.4-1.1.1-.2.3-.4.6-.3h3.5c.5 0 .9.3.8.6s-.3.7-.5 1.1zm7.8 3.8c-.1.2-.3.3-.7.3h-3.8c-.5 0-1-.3-.9-.7s.2-.7.3-1.2c.1-.2.3-.4.7-.4h3.9c.5 0 1 .3.9.7s-.3.8-.4 1.3zm.9-3.9c-.1.2-.4.4-.7.3h-3.6c-.5 0-.9-.3-.8-.6s.2-.7.3-1.1c.1-.2.4-.4.6-.3h3.7c.5 0 .9.3.8.6s-.2.8-.3 1.1zM91 80c.3-1.7.5-2.6.8-4.4 0-.2.3-.4.7-.4l25.3-.2c.4 0 .7.2.7.4.2 1.5.4 3 .4 4.5 0 .3-.4.6-.9.6H91.8c-.4 0-.8-.2-.8-.5z"/>
--- a/build/unix/build-binutils/build-binutils.sh
+++ b/build/unix/build-binutils/build-binutils.sh
@@ -58,17 +58,17 @@ index 8878ccd..d644b56 100644
        h->u.undef.abfd = NULL;
      }
 -- 
 2.17.1
 EOF
 
 cd ..
 
-TARGETS="aarch64-unknown-linux-gnu"
+TARGETS="aarch64-linux-gnu"
 
 # Build target-specific GNU as ; build them first so that the few documentation
 # files they install are overwritten by the full binutils build.
 
 for target in $TARGETS; do
 
   mkdir binutils-$target
   cd binutils-$target
--- a/devtools/client/aboutdebugging-new/test/browser/helper-telemetry.js
+++ b/devtools/client/aboutdebugging-new/test/browser/helper-telemetry.js
@@ -8,18 +8,18 @@
 /**
  * Reset all telemetry events.
  */
 function setupTelemetryTest() {
   // Let's reset the counts.
   Services.telemetry.clearEvents();
 
   // Ensure no events have been logged
-  const OPTOUT = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT;
-  const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
+  const ALL_CHANNELS = Ci.nsITelemetry.DATASET_ALL_CHANNELS;
+  const snapshot = Services.telemetry.snapshotEvents(ALL_CHANNELS, true);
   ok(!snapshot.parent, "No events have been logged for the main process");
 }
 /* exported setupTelemetryTest */
 
 /**
  * Check that the logged telemetry events exactly match the array of expected events.
  * Will compare the number of events, the event methods, and the event extras including
  * the about:debugging session id.
@@ -65,19 +65,19 @@ function getOpenEventSessionId() {
 }
 /* exported getOpenEventSessionId */
 
 /**
  * Read all the pending events that have "aboutdebugging" as their object property.
  * WARNING: Calling this method also flushes/clears the events.
  */
 function readAboutDebuggingEvents() {
-  const OPTOUT = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT;
+  const ALL_CHANNELS = Ci.nsITelemetry.DATASET_ALL_CHANNELS;
   // Retrieve and clear telemetry events.
-  const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
+  const snapshot = Services.telemetry.snapshotEvents(ALL_CHANNELS, true);
   // about:debugging events are logged in the parent process
   const parentEvents = snapshot.parent || [];
 
   return parentEvents
     .map(_toEventObject)
     .filter(e => e.object === "aboutdebugging");
 }
 /* exported getLoggedEvents */
--- a/devtools/client/debugger/new/src/components/PrimaryPanes/Outline.css
+++ b/devtools/client/debugger/new/src/components/PrimaryPanes/Outline.css
@@ -34,29 +34,39 @@
 }
 
 .outline-list__class-list {
   margin: 0;
   padding: 0;
   list-style: none;
 }
 
+.outline-list__class-list > .outline-list__element {
+  padding-inline-start: 2rem;
+}
+
 .outline-list__class-list .function-signature .function-name {
   color: var(--theme-highlight-green);
 }
 
 .outline-list .function-signature .paren {
   color: inherit;
 }
 
-.outline-list h2 {
-  margin: 10px 0 10px 10px;
+.outline-list__class h2 {
   font-weight: normal;
   font-size: 1em;
+  padding: 3px 0;
+  padding-inline-start: 10px;
   color: var(--blue-55);
+  margin: 0;
+}
+
+.outline-list__class:not(:first-child) h2 {
+  margin-top: 12px;
 }
 
 .outline-list h2:hover {
   background: var(--theme-toolbar-background-hover);
 }
 
 .theme-dark .outline-list h2 {
   color: var(--theme-highlight-blue);
@@ -67,19 +77,22 @@
 }
 
 .outline-list__element {
   padding: 3px 10px 3px 10px;
   cursor: default;
   white-space: nowrap;
 }
 
+.outline-list > .outline-list__element {
+  padding-inline-start: 1rem;
+}
+
 .outline-list__element-icon {
-  padding-right: 0.4rem;
-  padding-left: 1rem;
+  padding-inline-end: 0.4rem;
 }
 
 .outline-list__element:hover {
   background: var(--theme-toolbar-background-hover);
 }
 
 .outline-footer {
   display: flex;
--- a/devtools/client/debugger/new/src/components/PrimaryPanes/Outline.js
+++ b/devtools/client/debugger/new/src/components/PrimaryPanes/Outline.js
@@ -172,22 +172,22 @@ export class Outline extends Component<P
       <h2
         onClick={classInfo ? () => this.selectItem(classInfo.location) : null}
       >
         <span className="keyword">class</span> {klass}
       </h2>
     );
 
     return (
-      <div className="outline-list__class" key={klass}>
+      <li className="outline-list__class" key={klass}>
         {heading}
         <ul className="outline-list__class-list">
           {classFunctions.map(func => this.renderFunction(func))}
         </ul>
-      </div>
+      </li>
     );
   }
 
   renderFunctions(functions: Array<FunctionDeclaration>) {
     const { filter } = this.state;
     let classes = uniq(functions.map(func => func.klass));
     let namedFunctions = functions.filter(
       func =>
--- a/devtools/client/debugger/new/src/components/test/__snapshots__/Outline.spec.js.snap
+++ b/devtools/client/debugger/new/src/components/test/__snapshots__/Outline.spec.js.snap
@@ -74,17 +74,17 @@ exports[`Outline renders outline renders
   <div>
     <OutlineFilter
       filter=""
       updateFilter={[Function]}
     />
     <ul
       className="outline-list devtools-monospace"
     >
-      <div
+      <li
         className="outline-list__class"
         key="x_klass"
       >
         <h2
           onClick={[Function]}
         >
           <span
             className="keyword"
@@ -113,18 +113,18 @@ exports[`Outline renders outline renders
                 Object {
                   "name": "x_function",
                   "parameterNames": undefined,
                 }
               }
             />
           </li>
         </ul>
-      </div>
-      <div
+      </li>
+      <li
         className="outline-list__class"
         key="a_klass"
       >
         <h2
           onClick={[Function]}
         >
           <span
             className="keyword"
@@ -173,17 +173,17 @@ exports[`Outline renders outline renders
                 Object {
                   "name": "a1_function",
                   "parameterNames": undefined,
                 }
               }
             />
           </li>
         </ul>
-      </div>
+      </li>
     </ul>
     <div
       className="outline-footer bottom"
     >
       <button
         className=""
         onClick={[MockFunction]}
       >
@@ -201,17 +201,17 @@ exports[`Outline renders outline renders
   <div>
     <OutlineFilter
       filter=""
       updateFilter={[Function]}
     />
     <ul
       className="outline-list devtools-monospace"
     >
-      <div
+      <li
         className="outline-list__class"
         key="x_klass"
       >
         <h2
           onClick={[Function]}
         >
           <span
             className="keyword"
@@ -240,18 +240,18 @@ exports[`Outline renders outline renders
                 Object {
                   "name": "x_function",
                   "parameterNames": undefined,
                 }
               }
             />
           </li>
         </ul>
-      </div>
-      <div
+      </li>
+      <li
         className="outline-list__class"
         key="a_klass"
       >
         <h2
           onClick={[Function]}
         >
           <span
             className="keyword"
@@ -300,17 +300,17 @@ exports[`Outline renders outline renders
                 Object {
                   "name": "a2_function",
                   "parameterNames": undefined,
                 }
               }
             />
           </li>
         </ul>
-      </div>
+      </li>
     </ul>
     <div
       className="outline-footer bottom"
     >
       <button
         className="active"
         onClick={[MockFunction]}
       >
--- a/devtools/client/framework/test/browser_toolbox_telemetry_activate_splitconsole.js
+++ b/devtools/client/framework/test/browser_toolbox_telemetry_activate_splitconsole.js
@@ -1,16 +1,16 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 const URL =
   "data:text/html;charset=utf8,browser_toolbox_telemetry_activate_splitconsole.js";
-const OPTOUT = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT;
+const ALL_CHANNELS = Ci.nsITelemetry.DATASET_ALL_CHANNELS;
 const DATA = [
   {
     timestamp: null,
     category: "devtools.main",
     method: "activate",
     object: "split_console",
     value: null,
     extra: {
@@ -58,33 +58,33 @@ add_task(async function() {
   // or a promise on the inspector we can wait for to be sure the initialization is over.
   // Logged Bug 1500918 to investigate this.
   await pushPref("devtools.inspector.activeSidebar", "computedview");
 
   // Let's reset the counts.
   Services.telemetry.clearEvents();
 
   // Ensure no events have been logged
-  const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
+  const snapshot = Services.telemetry.snapshotEvents(ALL_CHANNELS, true);
   ok(!snapshot.parent, "No events have been logged for the main process");
 
   const tab = await addTab(URL);
   const target = await TargetFactory.forTab(tab);
   const toolbox = await gDevTools.showToolbox(target, "inspector");
 
   await toolbox.openSplitConsole();
   await toolbox.closeSplitConsole();
   await toolbox.openSplitConsole();
   await toolbox.closeSplitConsole();
 
   await checkResults();
 });
 
 async function checkResults() {
-  const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
+  const snapshot = Services.telemetry.snapshotEvents(ALL_CHANNELS, true);
   const events = snapshot.parent.filter(event => event[1] === "devtools.main" &&
                                                  (event[2] === "activate" ||
                                                  event[2] === "deactivate")
   );
 
   for (const i in DATA) {
     const [ timestamp, category, method, object, value, extra ] = events[i];
     const expected = DATA[i];
--- a/devtools/client/framework/test/browser_toolbox_telemetry_enter.js
+++ b/devtools/client/framework/test/browser_toolbox_telemetry_enter.js
@@ -1,15 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 const URL = "data:text/html;charset=utf8,browser_toolbox_telemetry_enter.js";
-const OPTOUT = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT;
+const ALL_CHANNELS = Ci.nsITelemetry.DATASET_ALL_CHANNELS;
 const DATA = [
   {
     timestamp: null,
     category: "devtools.main",
     method: "enter",
     object: "inspector",
     value: null,
     extra: {
@@ -87,17 +87,17 @@ const DATA = [
   },
 ];
 
 add_task(async function() {
   // Let's reset the counts.
   Services.telemetry.clearEvents();
 
   // Ensure no events have been logged
-  const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
+  const snapshot = Services.telemetry.snapshotEvents(ALL_CHANNELS, true);
   ok(!snapshot.parent, "No events have been logged for the main process");
 
   const tab = await addTab(URL);
   const target = await TargetFactory.forTab(tab);
 
   // Set up some cached messages for the web console.
   await ContentTask.spawn(tab.linkedBrowser, {}, () => {
     content.console.log("test 1");
@@ -116,17 +116,17 @@ add_task(async function() {
   await gDevTools.showToolbox(target, "netmonitor");
   await gDevTools.showToolbox(target, "storage");
   await gDevTools.showToolbox(target, "netmonitor");
 
   await checkResults();
 });
 
 async function checkResults() {
-  const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
+  const snapshot = Services.telemetry.snapshotEvents(ALL_CHANNELS, true);
   const events = snapshot.parent.filter(event => event[1] === "devtools.main" &&
                                                  event[2] === "enter" &&
                                                  event[4] === null
   );
 
   for (const i in DATA) {
     const [ timestamp, category, method, object, value, extra ] = events[i];
     const expected = DATA[i];
--- a/devtools/client/framework/test/browser_toolbox_telemetry_exit.js
+++ b/devtools/client/framework/test/browser_toolbox_telemetry_exit.js
@@ -1,15 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 const URL = "data:text/html;charset=utf8,browser_toolbox_telemetry_enter.js";
-const OPTOUT = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT;
+const ALL_CHANNELS = Ci.nsITelemetry.DATASET_ALL_CHANNELS;
 const DATA = [
   {
     timestamp: null,
     category: "devtools.main",
     method: "exit",
     object: "inspector",
     value: null,
     extra: {
@@ -74,17 +74,17 @@ const DATA = [
   },
 ];
 
 add_task(async function() {
   // Let's reset the counts.
   Services.telemetry.clearEvents();
 
   // Ensure no events have been logged
-  const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
+  const snapshot = Services.telemetry.snapshotEvents(ALL_CHANNELS, true);
   ok(!snapshot.parent, "No events have been logged for the main process");
 
   const tab = await addTab(URL);
   const target = await TargetFactory.forTab(tab);
 
   // Open the toolbox
   await gDevTools.showToolbox(target, "inspector");
 
@@ -94,17 +94,17 @@ add_task(async function() {
   await gDevTools.showToolbox(target, "netmonitor");
   await gDevTools.showToolbox(target, "storage");
   await gDevTools.showToolbox(target, "netmonitor");
 
   await checkResults();
 });
 
 async function checkResults() {
-  const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
+  const snapshot = Services.telemetry.snapshotEvents(ALL_CHANNELS, true);
   const events = snapshot.parent.filter(event => event[1] === "devtools.main" &&
                                                  event[2] === "exit" &&
                                                  event[4] === null
   );
 
   for (const i in DATA) {
     const [ timestamp, category, method, object, value, extra ] = events[i];
     const expected = DATA[i];
--- a/devtools/client/inspector/rules/test/browser_rules_edit-property_01.js
+++ b/devtools/client/inspector/rules/test/browser_rules_edit-property_01.js
@@ -4,17 +4,17 @@
 
 "use strict";
 
 // Testing adding new properties via the inplace-editors in the rule
 // view.
 // FIXME: some of the inplace-editor focus/blur/commit/revert stuff
 // should be factored out in head.js
 
-const OPTOUT = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT;
+const ALL_CHANNELS = Ci.nsITelemetry.DATASET_ALL_CHANNELS;
 
 const TEST_URI = `
   <style type="text/css">
   #testid {
     color: red;
     background-color: blue;
   }
   .testclass, .unmatched {
@@ -66,17 +66,17 @@ const DATA = [
   },
 ];
 
 add_task(async function() {
   // Let's reset the counts.
   Services.telemetry.clearEvents();
 
   // Ensure no events have been logged
-  const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
+  const snapshot = Services.telemetry.snapshotEvents(ALL_CHANNELS, true);
   ok(!snapshot.parent, "No events have been logged for the main process");
 
   await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
   const {inspector, view} = await openRuleView();
   await selectNode("#testid", inspector);
 
   const rule = getRuleViewRuleEditor(view, 1).rule;
   for (const {name, value, isValid} of TEST_DATA) {
@@ -132,17 +132,17 @@ async function testEditProperty(view, ru
   if (isValid) {
     is(propValue, value, name + " should have been set.");
   } else {
     isnot(propValue, value, name + " shouldn't have been set.");
   }
 }
 
 function checkResults() {
-  const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
+  const snapshot = Services.telemetry.snapshotEvents(ALL_CHANNELS, true);
   const events = snapshot.parent.filter(event => event[1] === "devtools.main" &&
                                                  event[2] === "edit_rule" &&
                                                  event[3] === "ruleview"
   );
 
   for (const i in DATA) {
     const [ timestamp, category, method, object ] = events[i];
     const expected = DATA[i];
--- a/devtools/client/inspector/test/browser_inspector_sidebarstate.js
+++ b/devtools/client/inspector/test/browser_inspector_sidebarstate.js
@@ -1,16 +1,16 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 "use strict";
 
 const TEST_URI = "data:text/html;charset=UTF-8," +
   "<h1>browser_inspector_sidebarstate.js</h1>";
-const OPTOUT = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT;
+const ALL_CHANNELS = Ci.nsITelemetry.DATASET_ALL_CHANNELS;
 
 const TELEMETRY_DATA = [
   {
     timestamp: null,
     category: "devtools.main",
     method: "tool_timer",
     object: "layoutview",
     value: null,
@@ -40,17 +40,17 @@ const TELEMETRY_DATA = [
   },
 ];
 
 add_task(async function() {
   // Let's reset the counts.
   Services.telemetry.clearEvents();
 
   // Ensure no events have been logged
-  const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
+  const snapshot = Services.telemetry.snapshotEvents(ALL_CHANNELS, true);
   ok(!snapshot.parent, "No events have been logged for the main process");
 
   let { inspector, toolbox } = await openInspectorForURL(TEST_URI);
 
   info("Selecting font inspector.");
   inspector.sidebar.select("fontinspector");
 
   is(inspector.sidebar.getCurrentTabID(), "fontinspector",
@@ -75,17 +75,17 @@ add_task(async function() {
 
   is(inspector.sidebar.getCurrentTabID(), "computedview",
      "Computed view is selected by default.");
 
   checkTelemetryResults();
 });
 
 function checkTelemetryResults() {
-  const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
+  const snapshot = Services.telemetry.snapshotEvents(ALL_CHANNELS, true);
   const events = snapshot.parent.filter(event => event[1] === "devtools.main" &&
                                                  event[2] === "tool_timer"
   );
 
   for (const i in TELEMETRY_DATA) {
     const [ timestamp, category, method, object, value, extra ] = events[i];
     const expected = TELEMETRY_DATA[i];
 
--- a/devtools/client/inspector/test/browser_inspector_switch-to-inspector-on-pick.js
+++ b/devtools/client/inspector/test/browser_inspector_switch-to-inspector-on-pick.js
@@ -3,17 +3,17 @@
  http://creativecommons.org/publicdomain/zero/1.0/ */
 "use strict";
 
 // Testing that clicking the pick button switches the toolbox to the inspector
 // panel.
 
 const TEST_URI = "data:text/html;charset=UTF-8," +
   "<p>Switch to inspector on pick</p>";
-const OPTOUT = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT;
+const ALL_CHANNELS = Ci.nsITelemetry.DATASET_ALL_CHANNELS;
 
 const DATA = [
   {
     timestamp: 3562,
     category: "devtools.main",
     method: "enter",
     object: "webconsole",
     extra: {
@@ -53,17 +53,17 @@ const DATA = [
   },
 ];
 
 add_task(async function() {
   // Let's reset the counts.
   Services.telemetry.clearEvents();
 
   // Ensure no events have been logged
-  const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
+  const snapshot = Services.telemetry.snapshotEvents(ALL_CHANNELS, true);
   ok(!snapshot.parent, "No events have been logged for the main process");
 
   const tab = await addTab(TEST_URI);
   const toolbox = await openToolbox(tab);
 
   await startPickerAndAssertSwitchToInspector(toolbox);
 
   info("Stoppping element picker.");
@@ -84,17 +84,17 @@ async function startPickerAndAssertSwitc
   pickButton.click();
 
   info("Waiting for inspector to be selected.");
   await toolbox.once("inspector-selected");
   is(toolbox.currentToolId, "inspector", "Switched to the inspector");
 }
 
 function checkResults() {
-  const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
+  const snapshot = Services.telemetry.snapshotEvents(ALL_CHANNELS, true);
   const events = snapshot.parent.filter(event => event[1] === "devtools.main" &&
                                                  event[2] === "enter" ||
                                                  event[2] === "exit"
   );
 
   for (const i in DATA) {
     const [ timestamp, category, method, object, value, extra ] = events[i];
     const expected = DATA[i];
--- a/devtools/client/netmonitor/src/components/NetworkDetailsPanel.js
+++ b/devtools/client/netmonitor/src/components/NetworkDetailsPanel.js
@@ -27,16 +27,17 @@ const { div } = dom;
 function NetworkDetailsPanel({
   connector,
   activeTabId,
   cloneSelectedRequest,
   request,
   selectTab,
   sourceMapService,
   toggleNetworkDetails,
+  openNetworkDetails,
   openLink,
 }) {
   if (!request) {
     return null;
   }
 
   return (
     div({ className: "network-details-panel" },
@@ -45,16 +46,17 @@ function NetworkDetailsPanel({
           activeTabId,
           cloneSelectedRequest,
           connector,
           openLink,
           request,
           selectTab,
           sourceMapService,
           toggleNetworkDetails,
+          openNetworkDetails,
         }) :
         CustomRequestPanel({
           connector,
           request,
         })
     )
   );
 }
@@ -77,10 +79,11 @@ module.exports = connect(
   (state) => ({
     activeTabId: state.ui.detailsPanelSelectedTab,
     request: getSelectedRequest(state),
   }),
   (dispatch) => ({
     cloneSelectedRequest: () => dispatch(Actions.cloneSelectedRequest()),
     selectTab: (tabId) => dispatch(Actions.selectDetailsPanelTab(tabId)),
     toggleNetworkDetails: () => dispatch(Actions.toggleNetworkDetails()),
+    openNetworkDetails: (open) => dispatch(Actions.openNetworkDetails(open)),
   }),
 )(NetworkDetailsPanel);
--- a/devtools/client/netmonitor/src/components/TabboxPanel.js
+++ b/devtools/client/netmonitor/src/components/TabboxPanel.js
@@ -1,15 +1,18 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-const { createFactory } = require("devtools/client/shared/vendor/react");
+const {
+  Component,
+  createFactory,
+} = require("devtools/client/shared/vendor/react");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 const { L10N } = require("../utils/l10n");
 const { PANELS } = require("../constants");
 
 // Components
 const Tabbar = createFactory(require("devtools/client/shared/components/tabs/TabBar"));
 const TabPanel = createFactory(require("devtools/client/shared/components/tabs/Tabs").TabPanel);
 const CookiesPanel = createFactory(require("./CookiesPanel"));
@@ -27,126 +30,148 @@ const COOKIES_TITLE = L10N.getStr("netmo
 const HEADERS_TITLE = L10N.getStr("netmonitor.tab.headers");
 const PARAMS_TITLE = L10N.getStr("netmonitor.tab.params");
 const RESPONSE_TITLE = L10N.getStr("netmonitor.tab.response");
 const SECURITY_TITLE = L10N.getStr("netmonitor.tab.security");
 const STACK_TRACE_TITLE = L10N.getStr("netmonitor.tab.stackTrace");
 const TIMINGS_TITLE = L10N.getStr("netmonitor.tab.timings");
 
 /**
- * Tabbox panel component
- * Display the network request details
- */
-function TabboxPanel({
-  activeTabId,
-  cloneSelectedRequest = () => {},
-  connector,
-  hideToggleButton,
-  openLink,
-  request,
-  selectTab,
-  sourceMapService,
-  toggleNetworkDetails,
-}) {
-  if (!request) {
-    return null;
+* Tabbox panel component
+* Display the network request details
+*/
+class TabboxPanel extends Component {
+  static get propTypes() {
+    return {
+      activeTabId: PropTypes.string,
+      cloneSelectedRequest: PropTypes.func,
+      connector: PropTypes.object.isRequired,
+      openLink: PropTypes.func,
+      request: PropTypes.object,
+      selectTab: PropTypes.func.isRequired,
+      sourceMapService: PropTypes.object,
+      hideToggleButton: PropTypes.bool,
+      toggleNetworkDetails: PropTypes.func.isRequired,
+      openNetworkDetails: PropTypes.func.isRequired,
+    };
+  }
+
+  componentDidMount() {
+    this.closeOnEscRef = this.closeOnEsc.bind(this);
+    window.addEventListener("keydown", this.closeOnEscRef);
+  }
+
+  componentWillUnmount() {
+    window.removeEventListener("keydown", this.closeOnEscRef);
+  }
+
+  closeOnEsc(event) {
+    if (event.key == "Escape") {
+      event.preventDefault();
+      this.props.openNetworkDetails(false);
+    }
   }
 
-  return (
-    Tabbar({
+  render() {
+    const {
       activeTabId,
-      menuDocument: window.parent.document,
-      onSelect: selectTab,
-      renderOnlySelected: true,
-      showAllTabsMenu: true,
-      sidebarToggleButton: hideToggleButton ? null :
-      {
-        collapsed: false,
-        collapsePaneTitle: COLLAPSE_DETAILS_PANE,
-        expandPaneTitle: "",
-        onClick: toggleNetworkDetails,
-      },
-    },
-      TabPanel({
-        id: PANELS.HEADERS,
-        title: HEADERS_TITLE,
-      },
-        HeadersPanel({
-          cloneSelectedRequest,
-          connector,
-          openLink,
-          request,
-        }),
-      ),
-      TabPanel({
-        id: PANELS.COOKIES,
-        title: COOKIES_TITLE,
-      },
-        CookiesPanel({
-          connector,
-          openLink,
-          request,
-        }),
-      ),
-      TabPanel({
-        id: PANELS.PARAMS,
-        title: PARAMS_TITLE,
+      cloneSelectedRequest = () => {},
+      connector,
+      hideToggleButton,
+      openLink,
+      request,
+      selectTab,
+      sourceMapService,
+      toggleNetworkDetails,
+    } = this.props;
+
+    if (!request) {
+      return null;
+    }
+
+    return (
+      Tabbar({
+        activeTabId,
+        menuDocument: window.parent.document,
+        onSelect: selectTab,
+        renderOnlySelected: true,
+        showAllTabsMenu: true,
+        sidebarToggleButton: hideToggleButton ? null :
+        {
+          collapsed: false,
+          collapsePaneTitle: COLLAPSE_DETAILS_PANE,
+          expandPaneTitle: "",
+          onClick: toggleNetworkDetails,
+        },
       },
-        ParamsPanel({ connector, openLink, request }),
-      ),
-      TabPanel({
-        id: PANELS.RESPONSE,
-        title: RESPONSE_TITLE,
-      },
-        ResponsePanel({ request, openLink, connector }),
-      ),
-      (request.fromCache || request.status == "304") &&
-      TabPanel({
-        id: PANELS.CACHE,
-        title: CACHE_TITLE,
-      },
-        CachePanel({ request, openLink, connector }),
-      ),
-      TabPanel({
-        id: PANELS.TIMINGS,
-        title: TIMINGS_TITLE,
-      },
-        TimingsPanel({
-          connector,
-          request,
-        }),
-      ),
-      request.cause && request.cause.stacktraceAvailable &&
-      TabPanel({
-        id: PANELS.STACK_TRACE,
-        title: STACK_TRACE_TITLE,
-      },
-        StackTracePanel({ connector, openLink, request, sourceMapService }),
-      ),
-      request.securityState && request.securityState !== "insecure" &&
-      TabPanel({
-        id: PANELS.SECURITY,
-        title: SECURITY_TITLE,
-      },
-        SecurityPanel({
-          connector,
-          openLink,
-          request,
-        }),
-      ),
-    )
-  );
+        TabPanel({
+          id: PANELS.HEADERS,
+          title: HEADERS_TITLE,
+        },
+          HeadersPanel({
+            cloneSelectedRequest,
+            connector,
+            openLink,
+            request,
+          }),
+        ),
+        TabPanel({
+          id: PANELS.COOKIES,
+          title: COOKIES_TITLE,
+        },
+          CookiesPanel({
+            connector,
+            openLink,
+            request,
+          }),
+        ),
+        TabPanel({
+          id: PANELS.PARAMS,
+          title: PARAMS_TITLE,
+        },
+          ParamsPanel({ connector, openLink, request }),
+        ),
+        TabPanel({
+          id: PANELS.RESPONSE,
+          title: RESPONSE_TITLE,
+        },
+          ResponsePanel({ request, openLink, connector }),
+        ),
+        (request.fromCache || request.status == "304") &&
+        TabPanel({
+          id: PANELS.CACHE,
+          title: CACHE_TITLE,
+        },
+          CachePanel({ request, openLink, connector }),
+        ),
+        TabPanel({
+          id: PANELS.TIMINGS,
+          title: TIMINGS_TITLE,
+        },
+          TimingsPanel({
+            connector,
+            request,
+          }),
+        ),
+        request.cause && request.cause.stacktraceAvailable &&
+        TabPanel({
+          id: PANELS.STACK_TRACE,
+          title: STACK_TRACE_TITLE,
+        },
+          StackTracePanel({ connector, openLink, request, sourceMapService }),
+        ),
+        request.securityState && request.securityState !== "insecure" &&
+        TabPanel({
+          id: PANELS.SECURITY,
+          title: SECURITY_TITLE,
+        },
+          SecurityPanel({
+            connector,
+            openLink,
+            request,
+          }),
+        ),
+      )
+    );
+  }
 }
 
-TabboxPanel.displayName = "TabboxPanel";
-
-TabboxPanel.propTypes = {
-  activeTabId: PropTypes.string,
-  cloneSelectedRequest: PropTypes.func,
-  connector: PropTypes.object.isRequired,
-  openLink: PropTypes.func,
-  request: PropTypes.object,
-  selectTab: PropTypes.func.isRequired,
-  sourceMapService: PropTypes.object,
-  hideToggleButton: PropTypes.bool,
-};
-
 module.exports = TabboxPanel;
--- a/devtools/client/netmonitor/test/browser_net_simple-request-details.js
+++ b/devtools/client/netmonitor/test/browser_net_simple-request-details.js
@@ -47,16 +47,17 @@ add_task(async function() {
 
   await waitForHeaders;
 
   await testHeadersTab();
   await testCookiesTab();
   await testParamsTab();
   await testResponseTab();
   await testTimingsTab();
+  await closePanelOnEsc();
   return teardown(monitor);
 
   function getSelectedIndex(state) {
     if (!state.requests.selectedId) {
       return -1;
     }
     return getSortedRequests(state).findIndex(r => r.id === state.requests.selectedId);
   }
@@ -247,9 +248,21 @@ add_task(async function() {
     EventUtils.sendMouseEvent({ type: "click" }, tabEl);
     await onPanelOpen;
 
     is(tabEl.getAttribute("aria-selected"), "true",
       `The ${tabName} tab in the network details pane should be selected.`);
 
     return document.querySelector(".network-details-panel .tab-panel");
   }
+
+  // This test will timeout on failure
+  async function closePanelOnEsc() {
+    EventUtils.sendKey("ESCAPE", window);
+
+    await waitUntil(() => {
+      return document.querySelector(".network-details-panel") == null;
+    });
+
+    is(document.querySelectorAll(".network-details-panel").length, 0,
+      "Network details panel should close on ESC key");
+  }
 });
--- a/devtools/client/netmonitor/test/browser_net_telemetry_edit_resend.js
+++ b/devtools/client/netmonitor/test/browser_net_telemetry_edit_resend.js
@@ -1,33 +1,33 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
-const OPTOUT = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT;
+const ALL_CHANNELS = Ci.nsITelemetry.DATASET_ALL_CHANNELS;
 
 /**
  * Test the edit_resend telemetry event.
  */
 add_task(async function() {
   const { tab, monitor } = await initNetMonitor(SIMPLE_URL);
   info("Starting test... ");
 
   const { document, store, windowRequire } = monitor.panelWin;
   const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
   store.dispatch(Actions.batchEnable(false));
 
   // Remove all telemetry events (you can check about:telemetry).
   Services.telemetry.clearEvents();
 
   // Ensure no events have been logged
-  const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
+  const snapshot = Services.telemetry.snapshotEvents(ALL_CHANNELS, true);
   ok(!snapshot.parent, "No events have been logged for the main process");
 
   // Reload to have one request in the list.
   const waitForEvents = waitForNetworkEvents(monitor, 1);
   BrowserTestUtils.loadURI(tab.linkedBrowser, SIMPLE_URL);
   await waitForEvents;
 
   // Open context menu and execute "Edit & Resend".
--- a/devtools/client/netmonitor/test/browser_net_telemetry_filters_changed.js
+++ b/devtools/client/netmonitor/test/browser_net_telemetry_filters_changed.js
@@ -1,16 +1,16 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
-const OPTOUT = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT;
+const ALL_CHANNELS = Ci.nsITelemetry.DATASET_ALL_CHANNELS;
 
 /**
  * Test the filters_changed telemetry event.
  */
 add_task(async function() {
   const { tab, monitor } = await initNetMonitor(SIMPLE_URL);
   info("Starting test... ");
 
@@ -21,17 +21,17 @@ add_task(async function() {
   } = windowRequire("devtools/client/netmonitor/src/selectors/index");
 
   store.dispatch(Actions.batchEnable(false));
 
   // Remove all telemetry events (you can check about:telemetry).
   Services.telemetry.clearEvents();
 
   // Ensure no events have been logged
-  const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
+  const snapshot = Services.telemetry.snapshotEvents(ALL_CHANNELS, true);
   ok(!snapshot.parent, "No events have been logged for the main process");
 
   // Reload to have one request in the list.
   const wait = waitForNetworkEvents(monitor, 1);
   BrowserTestUtils.loadURI(tab.linkedBrowser, SIMPLE_URL);
   await wait;
 
   info("Click on the 'HTML' filter");
--- a/devtools/client/netmonitor/test/browser_net_telemetry_sidepanel_changed.js
+++ b/devtools/client/netmonitor/test/browser_net_telemetry_sidepanel_changed.js
@@ -1,33 +1,33 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
-const OPTOUT = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT;
+const ALL_CHANNELS = Ci.nsITelemetry.DATASET_ALL_CHANNELS;
 
 /**
  * Test the sidepanel_changed telemetry event.
  */
 add_task(async function() {
   const { tab, monitor } = await initNetMonitor(SIMPLE_URL);
   info("Starting test... ");
 
   const { document, store, windowRequire } = monitor.panelWin;
   const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
   store.dispatch(Actions.batchEnable(false));
 
   // Remove all telemetry events (you can check about:telemetry).
   Services.telemetry.clearEvents();
 
   // Ensure no events have been logged
-  const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
+  const snapshot = Services.telemetry.snapshotEvents(ALL_CHANNELS, true);
   ok(!snapshot.parent, "No events have been logged for the main process");
 
   // Reload to have one request in the list.
   const waitForEvents = waitForNetworkEvents(monitor, 1);
   BrowserTestUtils.loadURI(tab.linkedBrowser, SIMPLE_URL);
   await waitForEvents;
 
   // Click on a request and wait till the default "Headers" side panel is opened.
--- a/devtools/client/netmonitor/test/browser_net_telemetry_throttle_changed.js
+++ b/devtools/client/netmonitor/test/browser_net_telemetry_throttle_changed.js
@@ -1,33 +1,33 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
-const OPTOUT = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT;
+const ALL_CHANNELS = Ci.nsITelemetry.DATASET_ALL_CHANNELS;
 
 /**
  * Test the throttle_change telemetry event.
  */
 add_task(async function() {
   const { monitor } = await initNetMonitor(SIMPLE_URL);
   info("Starting test... ");
 
   const { document, store, windowRequire } = monitor.panelWin;
   const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
   store.dispatch(Actions.batchEnable(false));
 
   // Remove all telemetry events.
   Services.telemetry.clearEvents();
 
   // Ensure no events have been logged
-  const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
+  const snapshot = Services.telemetry.snapshotEvents(ALL_CHANNELS, true);
   ok(!snapshot.parent, "No events have been logged for the main process");
 
   document.getElementById("network-throttling-menu").click();
   monitor.panelWin.parent.document.querySelector("menuitem[label='GPRS']").click();
   await waitFor(monitor.panelWin.api, EVENTS.THROTTLING_CHANGED);
 
   // Verify existence of the telemetry event.
   checkTelemetryEvent({
--- a/devtools/client/netmonitor/test/head.js
+++ b/devtools/client/netmonitor/test/head.js
@@ -847,18 +847,18 @@ function checkTelemetryEvent(expectedEve
   const f = e => JSON.stringify(e, null, 2);
   is(f(event), f({
     ...expectedEvent,
     "session_id": event.session_id,
   }), "The event has the expected data");
 }
 
 function queryTelemetryEvents(query) {
-  const OPTOUT = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT;
-  const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
+  const ALL_CHANNELS = Ci.nsITelemetry.DATASET_ALL_CHANNELS;
+  const snapshot = Services.telemetry.snapshotEvents(ALL_CHANNELS, true);
   const category = query.category || "devtools.main";
   const object = query.object || "netmonitor";
 
   const filtersChangedEvents = snapshot.parent.filter(event =>
     event[1] === category &&
     event[2] === query.method &&
     event[3] === object
   );
--- a/devtools/client/responsive.html/browser/tunnel.js
+++ b/devtools/client/responsive.html/browser/tunnel.js
@@ -203,17 +203,18 @@ function tunnelToInnerBrowser(outer, inn
       // Now that we've flipped to the remote browser mode, add `progressListener`
       // onto the remote version of `webProgress`.  Normally tabbrowser.xml does this step
       // when it creates a new browser, etc.  Since we manually changed the mode
       // above, it caused a fresh webProgress object to be created which does not have any
       // listeners added.  So, we get the listener that gBrowser is using for the tab and
       // reattach it here.
       const tab = gBrowser.getTabForBrowser(outer);
       const filteredProgressListener = gBrowser._tabFilters.get(tab);
-      outer.webProgress.addProgressListener(filteredProgressListener);
+      outer.webProgress.addProgressListener(filteredProgressListener,
+                                            Ci.nsIWebProgress.NOTIFY_ALL);
 
       // Add the inner browser to tabbrowser's WeakMap from browser to tab.  This assists
       // with tabbrowser's processing of some events such as MozLayerTreeReady which
       // bubble up from the remote content frame and trigger tabbrowser to lookup the tab
       // associated with the browser that triggered the event.
       gBrowser._tabForBrowser.set(inner, tab);
 
       // All of the browser state from content was swapped onto the inner browser.  Pull
@@ -424,20 +425,18 @@ MessageManagerTunnel.prototype = {
     "Link:SetIcon",
     "Link:SetFailedIcon",
     "Link:AddFeed",
     "Link:AddSearch",
     "PageStyle:StyleSheets",
     // Messages sent to RemoteWebProgress.jsm
     "Content:LoadURIResult",
     "Content:LocationChange",
-    "Content:ProgressChange",
     "Content:SecurityChange",
     "Content:StateChange",
-    "Content:StatusChange",
     // Messages sent to browser.js
     "DOMTitleChanged",
     "ImageDocumentLoaded",
     "Forms:ShowDropDown",
     "Forms:HideDropDown",
     "InPermitUnload",
     "PermitUnload",
     // Messages sent to tabbrowser.xml
--- a/devtools/client/responsive.html/test/browser/browser_telemetry_activate_rdm.js
+++ b/devtools/client/responsive.html/test/browser/browser_telemetry_activate_rdm.js
@@ -1,14 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 const URL = "data:text/html;charset=utf8,browser_telemetry_activate_rdm.js";
-const OPTOUT = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT;
+const ALL_CHANNELS = Ci.nsITelemetry.DATASET_ALL_CHANNELS;
 const DATA = [
   {
     timestamp: null,
     category: "devtools.main",
     method: "activate",
     object: "responsive_design",
     value: null,
     extra: {
@@ -48,17 +48,17 @@ const DATA = [
   },
 ];
 
 add_task(async function() {
   // Let's reset the counts.
   Services.telemetry.clearEvents();
 
   // Ensure no events have been logged
-  const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
+  const snapshot = Services.telemetry.snapshotEvents(ALL_CHANNELS, true);
   ok(!snapshot.parent, "No events have been logged for the main process");
 
   const tab = await addTab(URL);
   const target = await TargetFactory.forTab(tab);
 
   await openCloseRDM(tab);
   await gDevTools.showToolbox(target, "inspector");
   await openCloseRDM(tab);
@@ -77,17 +77,17 @@ async function openCloseRDM(tab) {
   // without waiting for `closeRDM` above, then we must have closed
   // synchronously.
   is(ui.destroyed, true, "RDM closed synchronously");
 
   await clientClosed;
 }
 
 async function checkResults() {
-  const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
+  const snapshot = Services.telemetry.snapshotEvents(ALL_CHANNELS, true);
   const events = snapshot.parent.filter(event => event[1] === "devtools.main" &&
                                                  (event[2] === "activate" ||
                                                  event[2] === "deactivate")
   );
 
   for (const i in events) {
     const [ timestamp, category, method, object, value, extra ] = events[i];
 
--- a/devtools/client/shared/test/browser_telemetry_sidebar.js
+++ b/devtools/client/shared/test/browser_telemetry_sidebar.js
@@ -1,16 +1,16 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 /* eslint-disable mozilla/no-arbitrary-setTimeout */
 
 "use strict";
 
 const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_sidebar.js</p>";
-const OPTOUT = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT;
+const ALL_CHANNELS = Ci.nsITelemetry.DATASET_ALL_CHANNELS;
 
 // Because we need to gather stats for the period of time that a tool has been
 // opened we make use of setTimeout() to create tool active times.
 const TOOL_DELAY = 200;
 
 const DATA = [
   {
     timestamp: null,
@@ -102,17 +102,17 @@ const DATA = [
   },
 ];
 
 add_task(async function() {
   // Let's reset the counts.
   Services.telemetry.clearEvents();
 
   // Ensure no events have been logged
-  const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
+  const snapshot = Services.telemetry.snapshotEvents(ALL_CHANNELS, true);
   ok(!snapshot.parent, "No events have been logged for the main process");
 
   await addTab(TEST_URI);
   startTelemetry();
 
   const target = await TargetFactory.forTab(gBrowser.selectedTab);
   const toolbox = await gDevTools.showToolbox(target, "inspector");
   info("inspector opened");
@@ -160,17 +160,17 @@ function checkResults() {
   checkTelemetry("DEVTOOLS_LAYOUTVIEW_OPENED_COUNT", "", {0: 3, 1: 0}, "array");
   checkTelemetry("DEVTOOLS_FONTINSPECTOR_OPENED_COUNT", "", {0: 2, 1: 0}, "array");
   checkTelemetry("DEVTOOLS_COMPUTEDVIEW_TIME_ACTIVE_SECONDS", "", null, "hasentries");
   checkTelemetry("DEVTOOLS_LAYOUTVIEW_TIME_ACTIVE_SECONDS", "", null, "hasentries");
   checkTelemetry("DEVTOOLS_FONTINSPECTOR_TIME_ACTIVE_SECONDS", "", null, "hasentries");
 }
 
 function checkEventTelemetry() {
-  const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
+  const snapshot = Services.telemetry.snapshotEvents(ALL_CHANNELS, true);
   const events = snapshot.parent.filter(event => event[1] === "devtools.main" &&
                                                   event[2] === "sidepanel_changed" &&
                                                   event[3] === "inspector" &&
                                                   event[4] === null
   );
 
   for (const i in DATA) {
     const [ timestamp, category, method, object, value, extra ] = events[i];
--- a/devtools/client/storage/test/browser_storage_values.js
+++ b/devtools/client/storage/test/browser_storage_values.js
@@ -144,16 +144,18 @@ const testCases = [
     {name: "1.id2", value: "1"},
     {name: "1.name", value: "foo"},
     {name: "1.email", value: "foo@bar.com"},
     {name: "1.extra", value: "baz"},
   ], true],
 ];
 
 add_task(async function() {
+  await SpecialPowers.pushPrefEnv({set: [["privacy.documentCookies.maxage", 0]]});
+
   await openTabAndSetupStorage(MAIN_DOMAIN + "storage-complex-values.html");
 
   gUI.tree.expandAll();
 
   for (const item of testCases) {
     info("clicking for item " + item);
 
     if (Array.isArray(item[0])) {
--- a/devtools/client/webconsole/test/mochitest/browser_jsterm_multiline.js
+++ b/devtools/client/webconsole/test/mochitest/browser_jsterm_multiline.js
@@ -6,17 +6,17 @@
 // Tests that the console waits for more input instead of evaluating
 // when valid, but incomplete, statements are present upon pressing enter
 // -or- when the user ends a line with shift + enter.
 
 "use strict";
 
 const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
                  "test/mochitest/test-console.html";
-const OPTOUT = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT;
+const ALL_CHANNELS = Ci.nsITelemetry.DATASET_ALL_CHANNELS;
 
 const SHOULD_ENTER_MULTILINE = [
   {input: "function foo() {" },
   {input: "var a = 1," },
   {input: "var a = 1;", shiftKey: true },
   {input: "function foo() { }", shiftKey: true },
   {input: "function" },
   {input: "(x) =>" },
@@ -84,17 +84,17 @@ add_task(async function() {
   await performTests();
 });
 
 async function performTests() {
   // Let's reset the counts.
   Services.telemetry.clearEvents();
 
   // Ensure no events have been logged
-  const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
+  const snapshot = Services.telemetry.snapshotEvents(ALL_CHANNELS, true);
   ok(!snapshot.parent, "No events have been logged for the main process");
 
   const hud = await openNewTabAndConsole(TEST_URI);
   const {jsterm} = hud;
 
   for (const {input, shiftKey} of SHOULD_ENTER_MULTILINE) {
     setInputValue(hud, input);
     EventUtils.synthesizeKey("VK_RETURN", { shiftKey });
@@ -114,17 +114,17 @@ async function performTests() {
   }
 
   await jsterm.execute("document.\nlocation.\nhref");
 
   checkEventTelemetry();
 }
 
 function checkEventTelemetry() {
-  const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
+  const snapshot = Services.telemetry.snapshotEvents(ALL_CHANNELS, true);
   const events = snapshot.parent.filter(event => event[1] === "devtools.main" &&
                                                   event[2] === "execute_js" &&
                                                   event[3] === "webconsole" &&
                                                   event[4] === null
   );
 
   for (const i in DATA) {
     const [ timestamp, category, method, object, value, extra ] = events[i];
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_telemetry_filters_changed.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_telemetry_filters_changed.js
@@ -6,24 +6,24 @@
 // Tests the filters_changed telemetry event.
 
 "use strict";
 
 const TEST_URI = `data:text/html,<meta charset=utf8><script>
   console.log("test message");
 </script>`;
 
-const OPTOUT = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT;
+const ALL_CHANNELS = Ci.nsITelemetry.DATASET_ALL_CHANNELS;
 
 add_task(async function() {
   // Let's reset the counts.
   Services.telemetry.clearEvents();
 
   // Ensure no events have been logged
-  const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
+  const snapshot = Services.telemetry.snapshotEvents(ALL_CHANNELS, true);
   ok(!snapshot.parent, "No events have been logged for the main process");
 
   const hud = await openNewTabAndConsole(TEST_URI);
 
   info("Click on the 'log' filter");
   await setFilterState(hud, {
     log: false,
   });
@@ -80,17 +80,17 @@ function checkTelemetryEvent(expectedEve
   is(f(event), f({
     ...expectedEvent,
     "session_id": event.session_id,
   }), "The event has the expected data");
 }
 
 function getFiltersChangedEventsExtra() {
   // Retrieve and clear telemetry events.
-  const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
+  const snapshot = Services.telemetry.snapshotEvents(ALL_CHANNELS, true);
 
   const filtersChangedEvents = snapshot.parent.filter(event =>
     event[1] === "devtools.main" &&
     event[2] === "filters_changed" &&
     event[3] === "webconsole"
   );
 
   // Since we already know we have the correct event, we only return the `extra` field
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_telemetry_jump_to_definition.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_telemetry_jump_to_definition.js
@@ -7,24 +7,24 @@
 
 "use strict";
 
 const TEST_URI = `data:text/html,<meta charset=utf8><script>
   function x(){}
   console.log("test message", x);
 </script>`;
 
-const OPTOUT = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT;
+const ALL_CHANNELS = Ci.nsITelemetry.DATASET_ALL_CHANNELS;
 
 add_task(async function() {
   // Let's reset the counts.
   Services.telemetry.clearEvents();
 
   // Ensure no events have been logged
-  const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
+  const snapshot = Services.telemetry.snapshotEvents(ALL_CHANNELS, true);
   ok(!snapshot.parent, "No events have been logged for the main process");
 
   const hud = await openNewTabAndConsole(TEST_URI);
 
   const message = await waitFor(() => findMessage(hud, "test message"));
   info("Click on the 'jump to definition' button");
   const jumpIcon = message.querySelector(".jump-definition");
   jumpIcon.click();
@@ -32,17 +32,17 @@ add_task(async function() {
   const events = getJumpToDefinitionEventsExtra();
   is(events.length, 1, "There was 1 event logged");
   const [event] = events;
   ok(event.session_id > 0, "There is a valid session_id in the logged event");
 });
 
 function getJumpToDefinitionEventsExtra() {
   // Retrieve and clear telemetry events.
-  const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
+  const snapshot = Services.telemetry.snapshotEvents(ALL_CHANNELS, true);
 
   const events = snapshot.parent.filter(event =>
     event[1] === "devtools.main" &&
     event[2] === "jump_to_definition" &&
     event[3] === "webconsole"
   );
 
   // Since we already know we have the correct event, we only return the `extra` field
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_telemetry_object_expanded.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_telemetry_object_expanded.js
@@ -6,24 +6,24 @@
 // Tests the object_expanded telemetry event.
 
 "use strict";
 
 const TEST_URI = `data:text/html,<meta charset=utf8><script>
   console.log("test message", [1,2,3]);
 </script>`;
 
-const OPTOUT = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT;
+const ALL_CHANNELS = Ci.nsITelemetry.DATASET_ALL_CHANNELS;
 
 add_task(async function() {
   // Let's reset the counts.
   Services.telemetry.clearEvents();
 
   // Ensure no events have been logged
-  const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
+  const snapshot = Services.telemetry.snapshotEvents(ALL_CHANNELS, true);
   ok(!snapshot.parent, "No events have been logged for the main process");
 
   const hud = await openNewTabAndConsole(TEST_URI);
 
   const message = await waitFor(() => findMessage(hud, "test message"));
 
   info("Click on the arrow icon to expand the node");
   const arrowIcon = message.querySelector(".arrow");
@@ -52,17 +52,17 @@ add_task(async function() {
   // Let's wait until there's only one arrow visible, i.e. the node is collapsed.
   await waitFor(() => message.querySelectorAll(".arrow").length === 1);
 
   ok(!snapshot.parent, "There was no event logged when collapsing the node");
 });
 
 function getObjectExpandedEventsExtra() {
   // Retrieve and clear telemetry events.
-  const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
+  const snapshot = Services.telemetry.snapshotEvents(ALL_CHANNELS, true);
 
   const events = snapshot.parent.filter(event =>
     event[1] === "devtools.main" &&
     event[2] === "object_expanded" &&
     event[3] === "webconsole"
   );
 
   // Since we already know we have the correct event, we only return the `extra` field
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -74,17 +74,16 @@
 #include "nsIAsyncVerifyRedirectCallback.h"
 #include "nsIAuthPrompt.h"
 #include "nsIAuthPrompt2.h"
 #include "nsICachingChannel.h"
 #include "nsICaptivePortalService.h"
 #include "nsIChannel.h"
 #include "nsIChannelEventSink.h"
 #include "nsIClassOfService.h"
-#include "nsICommandManager.h"
 #include "nsIConsoleReportCollector.h"
 #include "nsIContent.h"
 #include "nsIContentInlines.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsIContentViewer.h"
 #include "nsIController.h"
 #include "nsICookieService.h"
 #include "nsIDocShellTreeItem.h"
@@ -174,16 +173,17 @@
 #include "nsDocShellCID.h"
 #include "nsDocShellEditorData.h"
 #include "nsDocShellEnumerator.h"
 #include "nsDocShellLoadState.h"
 #include "nsDocShellLoadTypes.h"
 #include "nsDOMCID.h"
 #include "nsDOMNavigationTiming.h"
 #include "nsDSURIContentListener.h"
+#include "nsEditingSession.h"
 #include "nsError.h"
 #include "nsEscape.h"
 #include "nsFocusManager.h"
 #include "nsGlobalWindow.h"
 #include "nsJSEnvironment.h"
 #include "nsNetCID.h"
 #include "nsNetUtil.h"
 #include "nsObjectLoadingContent.h"
@@ -569,17 +569,17 @@ NS_INTERFACE_MAP_END_INHERITING(nsDocLoa
 NS_IMETHODIMP
 nsDocShell::GetInterface(const nsIID& aIID, void** aSink) {
   MOZ_ASSERT(aSink, "null out param");
 
   *aSink = nullptr;
 
   if (aIID.Equals(NS_GET_IID(nsICommandManager))) {
     NS_ENSURE_SUCCESS(EnsureCommandHandler(), NS_ERROR_FAILURE);
-    *aSink = mCommandManager;
+    *aSink = static_cast<nsICommandManager*>(mCommandManager.get());
   } else if (aIID.Equals(NS_GET_IID(nsIURIContentListener))) {
     *aSink = mContentListener;
   } else if ((aIID.Equals(NS_GET_IID(nsIScriptGlobalObject)) ||
               aIID.Equals(NS_GET_IID(nsIGlobalObject)) ||
               aIID.Equals(NS_GET_IID(nsPIDOMWindowOuter)) ||
               aIID.Equals(NS_GET_IID(mozIDOMWindowProxy)) ||
               aIID.Equals(NS_GET_IID(nsIDOMWindow))) &&
              NS_SUCCEEDED(EnsureScriptEnvironment())) {
@@ -11790,19 +11790,17 @@ nsDocShell::GetEditable(bool* aEditable)
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetHasEditingSession(bool* aHasEditingSession) {
   NS_ENSURE_ARG_POINTER(aHasEditingSession);
 
   if (mEditorData) {
-    nsCOMPtr<nsIEditingSession> editingSession;
-    mEditorData->GetEditingSession(getter_AddRefs(editingSession));
-    *aHasEditingSession = (editingSession.get() != nullptr);
+    *aHasEditingSession = !!mEditorData->GetEditingSession();
   } else {
     *aHasEditingSession = false;
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -12379,25 +12377,20 @@ nsDocShell::DoCommandWithParams(const ch
     return rv;
   }
 
   return commandController->DoCommandWithParams(aCommand, aParams);
 }
 
 nsresult nsDocShell::EnsureCommandHandler() {
   if (!mCommandManager) {
-    nsCOMPtr<nsPICommandUpdater> commandUpdater = new nsCommandManager();
-
-    nsCOMPtr<nsPIDOMWindowOuter> domWindow = GetWindow();
-    nsresult rv = commandUpdater->Init(domWindow);
-    if (NS_SUCCEEDED(rv)) {
-      mCommandManager = do_QueryInterface(commandUpdater);
-    }
-  }
-
+    if (nsCOMPtr<nsPIDOMWindowOuter> domWindow = GetWindow()) {
+      mCommandManager = new nsCommandManager(domWindow);
+    }
+  }
   return mCommandManager ? NS_OK : NS_ERROR_FAILURE;
 }
 
 // link handling
 
 class OnLinkClickEvent : public Runnable {
  public:
   OnLinkClickEvent(nsDocShell* aHandler, nsIContent* aContent, nsIURI* aURI,
@@ -13270,32 +13263,32 @@ nsDocShell::IssueWarning(uint32_t aWarni
 }
 
 NS_IMETHODIMP
 nsDocShell::GetEditingSession(nsIEditingSession** aEditSession) {
   if (!NS_SUCCEEDED(EnsureEditorData())) {
     return NS_ERROR_FAILURE;
   }
 
-  mEditorData->GetEditingSession(aEditSession);
+  *aEditSession = do_AddRef(mEditorData->GetEditingSession()).take();
   return *aEditSession ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetScriptableTabChild(nsITabChild** aTabChild) {
   *aTabChild = GetTabChild().take();
   return *aTabChild ? NS_OK : NS_ERROR_FAILURE;
 }
 
 already_AddRefed<nsITabChild> nsDocShell::GetTabChild() {
   nsCOMPtr<nsITabChild> tc = do_QueryReferent(mTabChild);
   return tc.forget();
 }
 
-nsICommandManager* nsDocShell::GetCommandManager() {
+nsCommandManager* nsDocShell::GetCommandManager() {
   NS_ENSURE_SUCCESS(EnsureCommandHandler(), nullptr);
   return mCommandManager;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetIsOnlyToplevelInTabGroup(bool* aResult) {
   MOZ_ASSERT(aResult);
 
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -68,33 +68,33 @@ class HTMLEditor;
 enum class TaskCategory;
 namespace dom {
 class ClientInfo;
 class ClientSource;
 class EventTarget;
 }  // namespace dom
 }  // namespace mozilla
 
-class nsICommandManager;
 class nsIContentViewer;
 class nsIController;
 class nsIDocShellTreeOwner;
 class nsIHttpChannel;
 class nsIMutableArray;
 class nsIPrompt;
 class nsIScrollableFrame;
 class nsISecureBrowserUI;
 class nsISHistory;
 class nsIStringBundle;
 class nsIURIFixup;
 class nsIURILoader;
 class nsIWebBrowserFind;
 class nsIWidget;
 class nsIReferrerInfo;
 
+class nsCommandManager;
 class nsDocShell;
 class nsDocShellEditorData;
 class nsDOMNavigationTiming;
 class nsDSURIContentListener;
 class nsGlobalWindowInner;
 class nsGlobalWindowOuter;
 
 class FramingChecker;
@@ -949,17 +949,17 @@ class nsDocShell final : public nsDocLoa
   nsCOMPtr<nsIMutableArray> mRefreshURIList;
   nsCOMPtr<nsIMutableArray> mSavedRefreshURIList;
   nsCOMPtr<nsIDOMStorageManager> mSessionStorageManager;
   uint64_t mContentWindowID;
   nsCOMPtr<nsIContentViewer> mContentViewer;
   nsCOMPtr<nsIWidget> mParentWidget;
   RefPtr<mozilla::dom::ChildSHistory> mSessionHistory;
   nsCOMPtr<nsIWebBrowserFind> mFind;
-  nsCOMPtr<nsICommandManager> mCommandManager;
+  RefPtr<nsCommandManager> mCommandManager;
   RefPtr<mozilla::dom::BrowsingContext> mBrowsingContext;
 
   // Weak reference to our TabChild actor.
   nsWeakPtr mTabChild;
 
   // Dimensions of the docshell
   nsIntRect mBounds;
 
--- a/docshell/base/nsDocShellEditorData.cpp
+++ b/docshell/base/nsDocShellEditorData.cpp
@@ -53,22 +53,20 @@ nsresult nsDocShellEditorData::MakeEdita
   }
   return NS_OK;
 }
 
 bool nsDocShellEditorData::GetEditable() {
   return mMakeEditable || (mHTMLEditor != nullptr);
 }
 
-nsresult nsDocShellEditorData::GetEditingSession(nsIEditingSession** aResult) {
+nsEditingSession* nsDocShellEditorData::GetEditingSession() {
   EnsureEditingSession();
 
-  NS_ADDREF(*aResult = mEditingSession);
-
-  return NS_OK;
+  return mEditingSession.get();
 }
 
 nsresult nsDocShellEditorData::SetHTMLEditor(HTMLEditor* aHTMLEditor) {
   // destroy any editor that we have. Checks for equality are
   // necessary to ensure that assigment into the nsCOMPtr does
   // not temporarily reduce the refCount of the editor to zero
   if (mHTMLEditor == aHTMLEditor) {
     return NS_OK;
--- a/docshell/base/nsDocShellEditorData.h
+++ b/docshell/base/nsDocShellEditorData.h
@@ -10,41 +10,41 @@
 #  include "nsCOMPtr.h"
 #endif
 
 #include "mozilla/HTMLEditor.h"
 #include "mozilla/RefPtr.h"
 #include "nsIHTMLDocument.h"
 
 class nsIDocShell;
-class nsIEditingSession;
+class nsEditingSession;
 
 class nsDocShellEditorData {
  public:
   explicit nsDocShellEditorData(nsIDocShell* aOwningDocShell);
   ~nsDocShellEditorData();
 
   nsresult MakeEditable(bool aWaitForUriLoad);
   bool GetEditable();
-  nsresult GetEditingSession(nsIEditingSession** aResult);
+  nsEditingSession* GetEditingSession();
   mozilla::HTMLEditor* GetHTMLEditor() const { return mHTMLEditor; }
   nsresult SetHTMLEditor(mozilla::HTMLEditor* aHTMLEditor);
   void TearDownEditor();
   nsresult DetachFromWindow();
   nsresult ReattachToWindow(nsIDocShell* aDocShell);
   bool WaitingForLoad() const { return mMakeEditable; }
 
  protected:
   void EnsureEditingSession();
 
   // The doc shell that owns us. Weak ref, since it always outlives us.
   nsIDocShell* mDocShell;
 
   // Only present for the content root docShell. Session is owned here.
-  nsCOMPtr<nsIEditingSession> mEditingSession;
+  RefPtr<nsEditingSession> mEditingSession;
 
   // If this frame is editable, store HTML editor here. It's owned here.
   RefPtr<mozilla::HTMLEditor> mHTMLEditor;
 
   // Backup for the corresponding nsIHTMLDocument's  editing state while
   // the editor is detached.
   nsIHTMLDocument::EditingState mDetachedEditingState;
 
--- a/docshell/base/nsDocShellTreeOwner.cpp
+++ b/docshell/base/nsDocShellTreeOwner.cpp
@@ -28,40 +28,39 @@
 #include "nsINode.h"
 #include "Link.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/MouseEvent.h"
 #include "mozilla/dom/SVGTitleElement.h"
 #include "nsIFormControl.h"
 #include "nsIImageLoadingContent.h"
 #include "nsIWebNavigation.h"
-#include "nsIPresShell.h"
 #include "nsIStringBundle.h"
 #include "nsPIDOMWindow.h"
 #include "nsPIWindowRoot.h"
 #include "nsIWindowWatcher.h"
 #include "nsPIWindowWatcher.h"
 #include "nsIPrompt.h"
 #include "nsITabParent.h"
 #include "nsITabChild.h"
 #include "nsRect.h"
 #include "nsIWebBrowserChromeFocus.h"
 #include "nsIContent.h"
 #include "imgIContainer.h"
-#include "nsPresContext.h"
 #include "nsViewManager.h"
 #include "nsView.h"
 #include "nsIConstraintValidation.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/dom/DragEvent.h"
 #include "mozilla/dom/Event.h"     // for Event
 #include "mozilla/dom/File.h"      // for input type=file
 #include "mozilla/dom/FileList.h"  // for input type=file
 #include "mozilla/dom/LoadURIOptionsBinding.h"
+#include "mozilla/PresShell.h"
 #include "mozilla/TextEvents.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 // A helper routine that navigates the tricky path from a |nsWebBrowser| to
 // a |EventTarget| via the window root and chrome event handler.
 static nsresult GetDOMEventTarget(nsWebBrowser* aInBrowser,
@@ -389,17 +388,17 @@ nsDocShellTreeOwner::SizeShellTo(nsIDocS
   NS_ERROR("Implement this");
   /*
   Set the preferred size on the aShellItem.
   */
 
   RefPtr<nsPresContext> presContext = mWebBrowser->mDocShell->GetPresContext();
   NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
 
-  nsIPresShell* presShell = presContext->GetPresShell();
+  PresShell* presShell = presContext->GetPresShell();
   NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
 
   NS_ENSURE_SUCCESS(
       presShell->ResizeReflow(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE),
       NS_ERROR_FAILURE);
 
   // XXX: this is weird, but we used to call a method here
   // (webBrowserChrome->SizeBrowserTo()) whose implementations all failed like
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -10,16 +10,17 @@
 
 %{ C++
 #include "js/TypeDecls.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/NotNull.h"
 #include "mozilla/UniquePtr.h"
 #include "nsCOMPtr.h"
 #include "nsIURI.h"
+class nsCommandManager;
 class nsPresContext;
 class nsIPresShell;
 class nsDocShellLoadState;
 namespace mozilla {
 class Encoding;
 class HTMLEditor;
 namespace dom {
 class BrowsingContext;
@@ -29,16 +30,17 @@ class ClientSource;
 %}
 
 /**
  * The nsIDocShell interface.
  */
 
 [ptr] native nsPresContext(nsPresContext);
 [ptr] native nsIPresShell(nsIPresShell);
+[ptr] native nsCommandManager(nsCommandManager);
 [ref] native MaybeURI(mozilla::Maybe<nsCOMPtr<nsIURI>>);
 [ref] native Encoding(const mozilla::Encoding*);
       native UniqueClientSource(mozilla::UniquePtr<mozilla::dom::ClientSource>);
 
 interface nsIURI;
 interface nsIChannel;
 interface nsIContentViewer;
 interface nsIDocShellLoadInfo;
@@ -55,17 +57,16 @@ interface nsIStructuredCloneContainer;
 interface nsIDOMStorage;
 interface nsIPrincipal;
 interface nsIWebBrowserPrint;
 interface nsIPrivacyTransitionObserver;
 interface nsIReflowObserver;
 interface nsIScrollObserver;
 interface nsITabParent;
 interface nsITabChild;
-interface nsICommandManager;
 interface nsICommandParams;
 interface nsILoadURIDelegate;
 native TabChildRef(already_AddRefed<nsITabChild>);
 native nsDocShellLoadStatePtr(nsDocShellLoadState*);
 
 webidl BrowsingContext;
 webidl ContentFrameMessageManager;
 webidl EventTarget;
@@ -999,17 +1000,17 @@ interface nsIDocShell : nsIDocShellTreeI
   readonly attribute nsIEditingSession editingSession;
 
   /**
    * The tab child for this docshell.
    */
   [binaryname(ScriptableTabChild)] readonly attribute nsITabChild tabChild;
   [noscript,notxpcom,nostdcall] TabChildRef GetTabChild();
 
-  [noscript,nostdcall,notxpcom] nsICommandManager GetCommandManager();
+  [noscript,nostdcall,notxpcom] nsCommandManager GetCommandManager();
 
   cenum TouchEventsOverride: 8 {
     /**
      * Override platform/pref default behaviour and force-disable touch events.
      */
     TOUCHEVENTS_OVERRIDE_DISABLED = 0,
     /**
      * Override platform/pref default behaviour and force-enable touch events.
--- a/dom/animation/EffectCompositor.cpp
+++ b/dom/animation/EffectCompositor.cpp
@@ -15,28 +15,28 @@
 #include "mozilla/AnimationComparator.h"
 #include "mozilla/AnimationPerformanceWarning.h"
 #include "mozilla/AnimationTarget.h"
 #include "mozilla/AnimationUtils.h"
 #include "mozilla/AutoRestore.h"
 #include "mozilla/ComputedStyleInlines.h"
 #include "mozilla/EffectSet.h"
 #include "mozilla/LayerAnimationInfo.h"
+#include "mozilla/PresShell.h"
 #include "mozilla/RestyleManager.h"
 #include "mozilla/ServoBindings.h"  // Servo_GetProperties_Overriding_Animation
 #include "mozilla/ServoStyleSet.h"
 #include "mozilla/StyleAnimationValue.h"
 #include "mozilla/TypeTraits.h"  // For std::forward<>
 #include "nsContentUtils.h"
 #include "nsCSSPseudoElements.h"
 #include "nsCSSPropertyIDSet.h"
 #include "nsCSSProps.h"
 #include "nsDisplayItemTypes.h"
 #include "nsAtom.h"
-#include "nsIPresShell.h"
 #include "nsIPresShellInlines.h"
 #include "nsLayoutUtils.h"
 #include "nsTArray.h"
 #include "PendingAnimationTracker.h"
 
 using mozilla::dom::Animation;
 using mozilla::dom::Element;
 using mozilla::dom::KeyframeEffect;
--- a/dom/animation/KeyframeEffect.cpp
+++ b/dom/animation/KeyframeEffect.cpp
@@ -27,16 +27,17 @@
 #include "Layers.h"              // For Layer
 #include "nsComputedDOMStyle.h"  // nsComputedDOMStyle::GetComputedStyle
 #include "nsContentUtils.h"
 #include "nsCSSPropertyIDSet.h"
 #include "nsCSSProps.h"             // For nsCSSProps::PropHasFlags
 #include "nsCSSPseudoElements.h"    // For PseudoStyleType
 #include "nsDOMMutationObserver.h"  // For nsAutoAnimationMutationBatch
 #include "nsIFrame.h"
+#include "nsIPresShellInlines.h"
 #include "nsIScriptError.h"
 #include "nsPresContextInlines.h"
 #include "nsRefreshDriver.h"
 
 namespace mozilla {
 
 void AnimationProperty::SetPerformanceWarning(
     const AnimationPerformanceWarning& aWarning, const Element* aElement) {
--- a/dom/base/Document.cpp
+++ b/dom/base/Document.cpp
@@ -40,16 +40,17 @@
 #include "nsITextControlFrame.h"
 #include "nsNumberControlFrame.h"
 #include "nsUnicharUtils.h"
 #include "nsContentList.h"
 #include "nsCSSPseudoElements.h"
 #include "nsIObserver.h"
 #include "nsIBaseWindow.h"
 #include "nsILayoutHistoryState.h"
+#include "nsLayoutStylesheetCache.h"
 #include "mozilla/css/Loader.h"
 #include "mozilla/css/ImageLoader.h"
 #include "nsDocShell.h"
 #include "nsDocShellLoadTypes.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsCOMArray.h"
 #include "nsQueryObject.h"
 #include "mozilla/Services.h"
@@ -68,16 +69,17 @@
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/FeaturePolicy.h"
 #include "mozilla/dom/FramingChecker.h"
 #include "mozilla/dom/HTMLSharedElement.h"
 #include "mozilla/dom/Navigator.h"
 #include "mozilla/dom/Performance.h"
+#include "mozilla/dom/TreeOrderedArrayInlines.h"
 #include "mozilla/dom/ServiceWorkerContainer.h"
 #include "mozilla/dom/ScriptLoader.h"
 #include "mozilla/dom/ShadowIncludingTreeIterator.h"
 #include "mozilla/dom/StyleSheetList.h"
 #include "mozilla/dom/SVGUseElement.h"
 #include "mozilla/net/CookieSettings.h"
 #include "nsGenericHTMLElement.h"
 #include "mozilla/dom/CDATASection.h"
@@ -266,16 +268,17 @@
 #include "mozilla/dom/SVGDocument.h"
 #include "mozilla/dom/SVGSVGElement.h"
 #include "mozilla/dom/DocGroup.h"
 #include "mozilla/dom/TabGroup.h"
 #ifdef MOZ_XUL
 #  include "mozilla/dom/XULBroadcastManager.h"
 #  include "mozilla/dom/XULPersist.h"
 #  include "nsIXULWindow.h"
+#  include "nsIChromeRegistry.h"
 #  include "nsXULPrototypeDocument.h"
 #  include "nsXULCommandDispatcher.h"
 #  include "nsXULPopupManager.h"
 #  include "nsIDocShellTreeOwner.h"
 #endif
 #include "nsIPresShellInlines.h"
 #include "mozilla/dom/BoxObject.h"
 
@@ -376,32 +379,24 @@ void IdentifierMapEntry::Traverse(
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback,
                                        "mIdentifierMap mImageElement element");
     nsIContent* imageElement = mImageElement;
     aCallback->NoteXPCOMChild(imageElement);
   }
 }
 
 bool IdentifierMapEntry::IsEmpty() {
-  return mIdContentList.IsEmpty() && !mNameContentList && !mChangeCallbacks &&
+  return mIdContentList->IsEmpty() && !mNameContentList && !mChangeCallbacks &&
          !mImageElement;
 }
 
 bool IdentifierMapEntry::HasNameElement() const {
   return mNameContentList && mNameContentList->Length() != 0;
 }
 
-Element* IdentifierMapEntry::GetIdElement() {
-  return mIdContentList.SafeElementAt(0);
-}
-
-Element* IdentifierMapEntry::GetImageIdElement() {
-  return mImageElement ? mImageElement.get() : GetIdElement();
-}
-
 void IdentifierMapEntry::AddContentChangeCallback(
     Document::IDTargetObserver aCallback, void* aData, bool aForImage) {
   if (!mChangeCallbacks) {
     mChangeCallbacks = new nsTHashtable<ChangeCallbackEntry>;
   }
 
   ChangeCallback cc = {aCallback, aData, aForImage};
   mChangeCallbacks->PutEntry(cc);
@@ -431,80 +426,46 @@ void IdentifierMapEntry::FireChangeCallb
     }
 
     if (!entry->mKey.mCallback(aOldElement, aNewElement, entry->mKey.mData)) {
       iter.Remove();
     }
   }
 }
 
-struct PositionComparator {
-  Element* const mElement;
-  explicit PositionComparator(Element* const aElement) : mElement(aElement) {}
-
-  int operator()(void* aElement) const {
-    Element* curElement = static_cast<Element*>(aElement);
-    MOZ_DIAGNOSTIC_ASSERT(mElement != curElement);
-    if (nsContentUtils::PositionIsBefore(mElement, curElement)) {
-      return -1;
-    }
-    return 1;
-  }
-};
-
 void IdentifierMapEntry::AddIdElement(Element* aElement) {
   MOZ_ASSERT(aElement, "Must have element");
-  MOZ_ASSERT(!mIdContentList.Contains(nullptr), "Why is null in our list?");
-
-  // Common case
-  if (mIdContentList.IsEmpty()) {
-    mIdContentList.AppendElement(aElement);
-    FireChangeCallbacks(nullptr, aElement);
-    return;
-  }
-
-#ifdef DEBUG
-  Element* currentElement = mIdContentList.ElementAt(0);
-#endif
-
-  // We seem to have multiple content nodes for the same id, or XUL is messing
-  // with us.  Search for the right place to insert the content.
-
-  size_t idx;
-  BinarySearchIf(mIdContentList, 0, mIdContentList.Length(),
-                 PositionComparator(aElement), &idx);
-
-  mIdContentList.InsertElementAt(idx, aElement);
-
-  if (idx == 0) {
-    Element* oldElement = mIdContentList.SafeElementAt(1);
-    NS_ASSERTION(currentElement == oldElement, "How did that happen?");
+  MOZ_ASSERT(!mIdContentList->Contains(nullptr), "Why is null in our list?");
+
+  size_t index = mIdContentList.Insert(*aElement);
+  if (index == 0) {
+    Element* oldElement = mIdContentList->SafeElementAt(1);
     FireChangeCallbacks(oldElement, aElement);
   }
 }
 
 void IdentifierMapEntry::RemoveIdElement(Element* aElement) {
   MOZ_ASSERT(aElement, "Missing element");
 
   // This should only be called while the document is in an update.
   // Assertions near the call to this method guarantee this.
 
   // This could fire in OOM situations
   // Only assert this in HTML documents for now as XUL does all sorts of weird
   // crap.
   NS_ASSERTION(!aElement->OwnerDoc()->IsHTMLDocument() ||
-                   mIdContentList.Contains(aElement),
+                   mIdContentList->Contains(aElement),
                "Removing id entry that doesn't exist");
 
   // XXXbz should this ever Compact() I guess when all the content is gone
   // we'll just get cleaned up in the natural order of things...
-  Element* currentElement = mIdContentList.SafeElementAt(0);
-  mIdContentList.RemoveElement(aElement);
+  Element* currentElement = mIdContentList->SafeElementAt(0);
+  mIdContentList.RemoveElement(*aElement);
   if (currentElement == aElement) {
-    FireChangeCallbacks(currentElement, mIdContentList.SafeElementAt(0));
+    FireChangeCallbacks(currentElement, mIdContentList->SafeElementAt(0));
   }
 }
 
 void IdentifierMapEntry::SetImageElement(Element* aElement) {
   Element* oldElement = GetImageIdElement();
   mImageElement = aElement;
   Element* newElement = GetImageIdElement();
   if (oldElement != newElement) {
@@ -1256,16 +1217,17 @@ Document::Document(const char* aContentT
       mAllowPaymentRequest(false),
       mEncodingMenuDisabled(false),
       mIsSVGGlyphsDocument(false),
       mInDestructor(false),
       mIsGoingAway(false),
       mInXBLUpdate(false),
       mNeedsReleaseAfterStackRefCntRelease(false),
       mStyleSetFilled(false),
+      mQuirkSheetAdded(false),
       mSSApplicableStateNotificationPending(false),
       mMayHaveTitleElement(false),
       mDOMLoadingSet(false),
       mDOMInteractiveSet(false),
       mDOMCompleteSet(false),
       mAutoFocusFired(false),
       mScrolledToRefAlready(false),
       mChangeScrollPosWhenScrollingToRef(false),
@@ -1685,34 +1647,29 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
 
   if (tmp->mMaybeEndOutermostXBLUpdateRunner) {
     // The cached runnable keeps a reference to the document object..
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
         cb, "mMaybeEndOutermostXBLUpdateRunner.mObj");
     cb.NoteXPCOMChild(ToSupports(tmp));
   }
 
-  for (auto iter = tmp->mIdentifierMap.ConstIter(); !iter.Done(); iter.Next()) {
-    iter.Get()->Traverse(&cb);
-  }
-
   tmp->mExternalResourceMap.Traverse(&cb);
 
   // Traverse all Document pointer members.
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSecurityInfo)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDisplayDocument)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFontFaceSet)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReadyForIdle)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentL10n)
 
   // Traverse all Document nsCOMPtrs.
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParser)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptGlobalObject)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListenerManager)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMStyleSheets)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheetSetList)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptLoader)
 
   DocumentOrShadowRoot::Traverse(tmp, cb);
 
   // The boxobject for an element will only exist as long as it's in the
   // document, so we'll traverse the table here instead of from the element.
   if (tmp->mBoxObjectTable) {
@@ -1744,17 +1701,16 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnchors);
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnonymousContents)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCommandDispatcher)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFeaturePolicy)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSuppressedEventListener)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrototypeDocument)
 
   // Traverse all our nsCOMArrays.
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheets)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPreloadingImages)
 
   for (uint32_t i = 0; i < tmp->mFrameRequestCallbacks.Length(); ++i) {
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mFrameRequestCallbacks[i]");
     cb.NoteXPCOMChild(tmp->mFrameRequestCallbacks[i].mCallback);
   }
 
   // Traverse animation components
@@ -1850,18 +1806,16 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Do
   tmp->ClearAllBoxObjects();
 
   if (tmp->mListenerManager) {
     tmp->mListenerManager->Disconnect();
     tmp->UnsetFlags(NODE_HAS_LISTENERMANAGER);
     tmp->mListenerManager = nullptr;
   }
 
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMStyleSheets)
-
   if (tmp->mStyleSheetSetList) {
     tmp->mStyleSheetSetList->Disconnect();
     tmp->mStyleSheetSetList = nullptr;
   }
 
   delete tmp->mSubDocuments;
   tmp->mSubDocuments = nullptr;
 
@@ -1871,17 +1825,16 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Do
                      "first?");
 
   DocumentOrShadowRoot::Unlink(tmp);
 
   // Document has a pretty complex destructor, so we're going to
   // assume that *most* cycles you actually want to break somewhere
   // else, and not unlink an awful lot here.
 
-  tmp->mIdentifierMap.Clear();
   tmp->mExpandoAndGeneration.OwnerUnlinked();
 
   if (tmp->mAnimationController) {
     tmp->mAnimationController->Unlink();
   }
 
   tmp->mPendingTitleChangeEvent.Revoke();
 
@@ -1949,16 +1902,18 @@ nsresult Document::Init() {
 
   mScriptLoader = new dom::ScriptLoader(this);
 
   // we need to create a policy here so getting the policy within
   // ::Policy() can *always* return a non null policy
   mFeaturePolicy = new FeaturePolicy(this);
   mFeaturePolicy->SetDefaultOrigin(NodePrincipal());
 
+  mStyleSet = MakeUnique<ServoStyleSet>(*this);
+
   mozilla::HoldJSObjects(this);
 
   return NS_OK;
 }
 
 void Document::DeleteAllProperties() { PropertyTable().DeleteAllProperties(); }
 
 void Document::DeleteAllPropertiesFor(nsINode* aNode) {
@@ -2241,41 +2196,34 @@ already_AddRefed<nsIPrincipal> Document:
       }
     }
   }
   nsCOMPtr<nsIPrincipal> principal(aPrincipal);
   return principal.forget();
 }
 
 void Document::RemoveDocStyleSheetsFromStyleSets() {
+  MOZ_ASSERT(mStyleSetFilled);
   // The stylesheets should forget us
   for (StyleSheet* sheet : Reversed(mStyleSheets)) {
     sheet->ClearAssociatedDocumentOrShadowRoot();
-
     if (sheet->IsApplicable()) {
-      RefPtr<PresShell> presShell = GetPresShell();
-      if (presShell) {
-        presShell->StyleSet()->RemoveDocStyleSheet(sheet);
-      }
+      mStyleSet->RemoveDocStyleSheet(sheet);
     }
     // XXX Tell observers?
   }
 }
 
 void Document::RemoveStyleSheetsFromStyleSets(
     const nsTArray<RefPtr<StyleSheet>>& aSheets, SheetType aType) {
   // The stylesheets should forget us
   for (StyleSheet* sheet : Reversed(aSheets)) {
     sheet->ClearAssociatedDocumentOrShadowRoot();
-
-    if (sheet->IsApplicable()) {
-      RefPtr<PresShell> presShell = GetPresShell();
-      if (presShell) {
-        presShell->StyleSet()->RemoveStyleSheet(aType, sheet);
-      }
+    if (mStyleSetFilled && sheet->IsApplicable()) {
+      mStyleSet->RemoveStyleSheet(aType, sheet);
     }
     // XXX Tell observers?
   }
 }
 
 void Document::ResetStylesheetsToURI(nsIURI* aURI) {
   MOZ_ASSERT(aURI);
 
@@ -2291,18 +2239,16 @@ void Document::ResetStylesheetsToURI(nsI
     RemoveStyleSheetsFromStyleSets(mAdditionalSheets[eAuthorSheet],
                                    SheetType::Doc);
 
     if (nsStyleSheetService* sheetService =
             nsStyleSheetService::GetInstance()) {
       RemoveStyleSheetsFromStyleSets(*sheetService->AuthorStyleSheets(),
                                      SheetType::Doc);
     }
-
-    mStyleSetFilled = false;
   }
 
   // Release all the sheets
   mStyleSheets.Clear();
   for (auto& sheets : mAdditionalSheets) {
     sheets.Clear();
   }
 
@@ -2317,61 +2263,155 @@ void Document::ResetStylesheetsToURI(nsI
   } else {
     mAttrStyleSheet = new nsHTMLStyleSheet(this);
   }
 
   if (!mStyleAttrStyleSheet) {
     mStyleAttrStyleSheet = new nsHTMLCSSStyleSheet();
   }
 
-  // Now set up our style sets
-  if (PresShell* presShell = GetPresShell()) {
-    FillStyleSet(presShell->StyleSet());
-    if (presShell->StyleSet()->StyleSheetsHaveChanged()) {
-      presShell->ApplicableStylesChanged();
+  if (mStyleSetFilled) {
+    FillStyleSetDocumentSheets();
+
+    if (mStyleSet->StyleSheetsHaveChanged()) {
+      if (PresShell* presShell = GetPresShell()) {
+        presShell->ApplicableStylesChanged();
+      }
     }
   }
 }
 
 static void AppendSheetsToStyleSet(ServoStyleSet* aStyleSet,
                                    const nsTArray<RefPtr<StyleSheet>>& aSheets,
                                    SheetType aType) {
   for (StyleSheet* sheet : Reversed(aSheets)) {
     aStyleSet->AppendStyleSheet(aType, sheet);
   }
 }
 
-void Document::FillStyleSet(ServoStyleSet* aStyleSet) {
-  MOZ_ASSERT(aStyleSet, "Must have a style set");
-  MOZ_ASSERT(aStyleSet->SheetCount(SheetType::Doc) == 0,
+void Document::FillStyleSetUserAndUASheets() {
+  // Make sure this does the same thing as PresShell::Add{User,Agent}Sheet wrt
+  // ordering.
+
+  // The document will fill in the document sheets when we create the presshell
+  auto cache = nsLayoutStylesheetCache::Singleton();
+
+  nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance();
+  MOZ_ASSERT(sheetService,
+             "should never be creating a StyleSet after the style sheet "
+             "service has gone");
+
+  for (StyleSheet* sheet : *sheetService->UserStyleSheets()) {
+    mStyleSet->AppendStyleSheet(SheetType::User, sheet);
+  }
+
+  StyleSheet* sheet = IsInChromeDocShell() ? cache->GetUserChromeSheet()
+                                           : cache->GetUserContentSheet();
+  if (sheet) {
+    mStyleSet->AppendStyleSheet(SheetType::User, sheet);
+  }
+
+  mStyleSet->AppendStyleSheet(SheetType::Agent, cache->UASheet());
+
+  if (MOZ_LIKELY(NodeInfoManager()->MathMLEnabled())) {
+    mStyleSet->AppendStyleSheet(SheetType::Agent, cache->MathMLSheet());
+  }
+
+  if (MOZ_LIKELY(NodeInfoManager()->SVGEnabled())) {
+    mStyleSet->AppendStyleSheet(SheetType::Agent, cache->SVGSheet());
+  }
+
+  mStyleSet->AppendStyleSheet(SheetType::Agent, cache->HTMLSheet());
+
+  if (nsLayoutUtils::ShouldUseNoFramesSheet(this)) {
+    mStyleSet->AppendStyleSheet(SheetType::Agent, cache->NoFramesSheet());
+  }
+
+  if (nsLayoutUtils::ShouldUseNoScriptSheet(this)) {
+    mStyleSet->AppendStyleSheet(SheetType::Agent, cache->NoScriptSheet());
+  }
+
+  mStyleSet->AppendStyleSheet(SheetType::Agent, cache->CounterStylesSheet());
+
+  // Load the minimal XUL rules for scrollbars and a few other XUL things
+  // that non-XUL (typically HTML) documents commonly use.
+  mStyleSet->AppendStyleSheet(SheetType::Agent, cache->MinimalXULSheet());
+
+  // Only load the full XUL sheet if we'll need it.
+  if (LoadsFullXULStyleSheetUpFront()) {
+    mStyleSet->AppendStyleSheet(SheetType::Agent, cache->XULSheet());
+  }
+
+  MOZ_ASSERT(!mQuirkSheetAdded);
+  if (mCompatMode == eCompatibility_NavQuirks) {
+    mStyleSet->AppendStyleSheet(SheetType::Agent, cache->QuirkSheet());
+    mQuirkSheetAdded = true;
+  }
+
+  mStyleSet->AppendStyleSheet(SheetType::Agent, cache->FormsSheet());
+  mStyleSet->AppendStyleSheet(SheetType::Agent, cache->ScrollbarsSheet());
+  mStyleSet->AppendStyleSheet(SheetType::Agent, cache->PluginProblemSheet());
+
+  for (StyleSheet* sheet : *sheetService->AgentStyleSheets()) {
+    mStyleSet->AppendStyleSheet(SheetType::Agent, sheet);
+  }
+}
+
+void Document::FillStyleSet() {
+  MOZ_ASSERT(!mStyleSetFilled);
+  FillStyleSetUserAndUASheets();
+  FillStyleSetDocumentSheets();
+  mStyleSetFilled = true;
+}
+
+void Document::FillStyleSetDocumentSheets() {
+  MOZ_ASSERT(mStyleSet->SheetCount(SheetType::Doc) == 0,
              "Style set already has document sheets?");
 
-  MOZ_ASSERT(!mStyleSetFilled);
-
   for (StyleSheet* sheet : Reversed(mStyleSheets)) {
     if (sheet->IsApplicable()) {
-      aStyleSet->AddDocStyleSheet(sheet, this);
-    }
-  }
-
-  if (nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance()) {
-    nsTArray<RefPtr<StyleSheet>>& sheets = *sheetService->AuthorStyleSheets();
-    for (StyleSheet* sheet : sheets) {
-      aStyleSet->AppendStyleSheet(SheetType::Doc, sheet);
-    }
-  }
-
-  AppendSheetsToStyleSet(aStyleSet, mAdditionalSheets[eAgentSheet],
+      mStyleSet->AddDocStyleSheet(sheet, this);
+    }
+  }
+
+  nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance();
+  for (StyleSheet* sheet : *sheetService->AuthorStyleSheets()) {
+    mStyleSet->AppendStyleSheet(SheetType::Doc, sheet);
+  }
+
+  AppendSheetsToStyleSet(mStyleSet.get(), mAdditionalSheets[eAgentSheet],
                          SheetType::Agent);
-  AppendSheetsToStyleSet(aStyleSet, mAdditionalSheets[eUserSheet],
+  AppendSheetsToStyleSet(mStyleSet.get(), mAdditionalSheets[eUserSheet],
                          SheetType::User);
-  AppendSheetsToStyleSet(aStyleSet, mAdditionalSheets[eAuthorSheet],
+  AppendSheetsToStyleSet(mStyleSet.get(), mAdditionalSheets[eAuthorSheet],
                          SheetType::Doc);
-
-  mStyleSetFilled = true;
+}
+
+void Document::CompatibilityModeChanged() {
+  MOZ_ASSERT(IsHTMLOrXHTML());
+  CSSLoader()->SetCompatibilityMode(mCompatMode);
+  mStyleSet->CompatibilityModeChanged();
+  if (!mStyleSetFilled) {
+    MOZ_ASSERT(!mQuirkSheetAdded);
+    return;
+  }
+  if (mQuirkSheetAdded == NeedsQuirksSheet()) {
+    return;
+  }
+  auto cache = nsLayoutStylesheetCache::Singleton();
+  StyleSheet* sheet = cache->QuirkSheet();
+  if (mQuirkSheetAdded) {
+    mStyleSet->RemoveStyleSheet(SheetType::Agent, sheet);
+  } else {
+    mStyleSet->AppendStyleSheet(SheetType::Agent, sheet);
+  }
+  mQuirkSheetAdded = !mQuirkSheetAdded;
+  if (PresShell* presShell = GetPresShell()) {
+    presShell->ApplicableStylesChanged();
+  }
 }
 
 static void WarnIfSandboxIneffective(nsIDocShell* aDocShell,
                                      uint32_t aSandboxFlags,
                                      nsIChannel* aChannel) {
   // If the document is sandboxed (via the HTML5 iframe sandbox
   // attribute) and both the allow-scripts and allow-same-origin
   // keywords are supplied, the sandboxed document can call into its
@@ -3626,29 +3666,39 @@ static inline void AssertNoStaleServoDat
         }
       }
     }
   }
 #endif
 }
 
 already_AddRefed<PresShell> Document::CreatePresShell(
-    nsPresContext* aContext, nsViewManager* aViewManager,
-    UniquePtr<ServoStyleSet> aStyleSet) {
-  NS_ASSERTION(!mPresShell, "We have a presshell already!");
+    nsPresContext* aContext, nsViewManager* aViewManager) {
+  MOZ_ASSERT(!mPresShell, "We have a presshell already!");
 
   NS_ENSURE_FALSE(GetBFCacheEntry(), nullptr);
 
-  FillStyleSet(aStyleSet.get());
   AssertNoStaleServoDataIn(*this);
 
   RefPtr<PresShell> presShell = new PresShell;
   // Note: we don't hold a ref to the shell (it holds a ref to us)
   mPresShell = presShell;
-  presShell->Init(this, aContext, aViewManager, std::move(aStyleSet));
+
+  bool hadStyleSheets = mStyleSetFilled;
+  if (!hadStyleSheets) {
+    FillStyleSet();
+  }
+
+  presShell->Init(this, aContext, aViewManager);
+
+  if (hadStyleSheets) {
+    // Gaining a shell causes changes in how media queries are evaluated, so
+    // invalidate that.
+    aContext->MediaFeatureValuesChanged({MediaFeatureChange::kAllChanges});
+  }
 
   // Make sure to never paint if we belong to an invisible DocShell.
   nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
   if (docShell && docShell->IsInvisible()) {
     presShell->SetNeverPainting(true);
   }
 
   MOZ_LOG(gDocumentLeakPRLog, LogLevel::Debug,
@@ -3741,31 +3791,32 @@ bool Document::ShouldThrottleFrameReques
 }
 
 void Document::DeletePresShell() {
   mExternalResourceMap.HideViewers();
   if (nsPresContext* presContext = mPresShell->GetPresContext()) {
     presContext->RefreshDriver()->CancelPendingFullscreenEvents(this);
   }
 
+  mStyleSet->ShellDetachedFromDocument();
+
   // When our shell goes away, request that all our images be immediately
   // discarded, so we don't carry around decoded image data for a document we
   // no longer intend to paint.
   ImageTracker()->RequestDiscardAll();
 
   // Now that we no longer have a shell, we need to forget about any FontFace
   // objects for @font-face rules that came from the style set. There's no need
   // to call EnsureStyleFlush either, the shell is going away anyway, so there's
   // no point on it.
   MarkUserFontSetDirty();
 
   PresShell* oldPresShell = mPresShell;
   mPresShell = nullptr;
   UpdateFrameRequestCallbackSchedulingState(oldPresShell);
-  mStyleSetFilled = false;
 
   ClearStaleServoData();
   AssertNoStaleServoDataIn(*this);
 }
 
 void Document::SetBFCacheEntry(nsIBFCacheEntry* aEntry) {
   MOZ_ASSERT(IsBFCachingAllowed() || !aEntry, "You should have checked!");
 
@@ -3949,19 +4000,21 @@ void Document::RemoveChildNode(nsIConten
   mCachedRootElement = nullptr;
   nsINode::RemoveChildNode(aKid, aNotify);
   MOZ_ASSERT(mCachedRootElement != aKid,
              "Stale pointer in mCachedRootElement, after we tried to clear it "
              "(maybe somebody called GetRootElement() too early?)");
 }
 
 void Document::AddStyleSheetToStyleSets(StyleSheet* aSheet) {
-  if (PresShell* presShell = GetPresShell()) {
-    presShell->StyleSet()->AddDocStyleSheet(aSheet, this);
-    presShell->ApplicableStylesChanged();
+  if (mStyleSetFilled) {
+    mStyleSet->AddDocStyleSheet(aSheet, this);
+    if (PresShell* presShell = GetPresShell()) {
+      presShell->ApplicableStylesChanged();
+    }
   }
 }
 
 #define DO_STYLESHEET_NOTIFICATION(className, type, memberName, argName) \
   do {                                                                   \
     className##Init init;                                                \
     init.mBubbles = true;                                                \
     init.mCancelable = true;                                             \
@@ -3989,19 +4042,21 @@ void Document::NotifyStyleSheetRemoved(S
                                        bool aDocumentSheet) {
   if (StyleSheetChangeEventsEnabled()) {
     DO_STYLESHEET_NOTIFICATION(StyleSheetChangeEvent, "StyleSheetRemoved",
                                mDocumentSheet, aDocumentSheet);
   }
 }
 
 void Document::RemoveStyleSheetFromStyleSets(StyleSheet* aSheet) {
-  if (PresShell* presShell = GetPresShell()) {
-    presShell->StyleSet()->RemoveDocStyleSheet(aSheet);
-    presShell->ApplicableStylesChanged();
+  if (mStyleSetFilled) {
+    mStyleSet->RemoveDocStyleSheet(aSheet);
+    if (PresShell* presShell = GetPresShell()) {
+      presShell->ApplicableStylesChanged();
+    }
   }
 }
 
 void Document::RemoveStyleSheet(StyleSheet* aSheet) {
   MOZ_ASSERT(aSheet);
   RefPtr<StyleSheet> sheet = DocumentOrShadowRoot::RemoveSheet(*aSheet);
 
   if (!sheet) {
@@ -4171,20 +4226,22 @@ nsresult Document::LoadAdditionalStyleSh
 nsresult Document::AddAdditionalStyleSheet(additionalSheetType aType,
                                            StyleSheet* aSheet) {
   if (mAdditionalSheets[aType].Contains(aSheet)) return NS_ERROR_INVALID_ARG;
 
   if (!aSheet->IsApplicable()) return NS_ERROR_INVALID_ARG;
 
   mAdditionalSheets[aType].AppendElement(aSheet);
 
-  if (PresShell* presShell = GetPresShell()) {
+  if (mStyleSetFilled) {
     SheetType type = ConvertAdditionalSheetType(aType);
-    presShell->StyleSet()->AppendStyleSheet(type, aSheet);
-    presShell->ApplicableStylesChanged();
+    mStyleSet->AppendStyleSheet(type, aSheet);
+    if (PresShell* presShell = GetPresShell()) {
+      presShell->ApplicableStylesChanged();
+    }
   }
 
   // Passing false, so documet.styleSheets.length will not be affected by
   // these additional sheets.
   NotifyStyleSheetAdded(aSheet, false);
   return NS_OK;
 }
 
@@ -4196,20 +4253,22 @@ void Document::RemoveAdditionalStyleShee
 
   int32_t i = FindSheet(mAdditionalSheets[aType], aSheetURI);
   if (i >= 0) {
     RefPtr<StyleSheet> sheetRef = sheets[i];
     sheets.RemoveElementAt(i);
 
     if (!mIsGoingAway) {
       MOZ_ASSERT(sheetRef->IsApplicable());
-      if (PresShell* presShell = GetPresShell()) {
+      if (mStyleSetFilled) {
         SheetType type = ConvertAdditionalSheetType(aType);
-        presShell->StyleSet()->RemoveStyleSheet(type, sheetRef);
-        presShell->ApplicableStylesChanged();
+        mStyleSet->RemoveStyleSheet(type, sheetRef);
+        if (PresShell* presShell = GetPresShell()) {
+          presShell->ApplicableStylesChanged();
+        }
       }
     }
 
     // Passing false, so documet.styleSheets.length will not be affected by
     // these additional sheets.
     NotifyStyleSheetRemoved(sheetRef, false);
     sheetRef->ClearAssociatedDocumentOrShadowRoot();
   }
@@ -8537,16 +8596,73 @@ void Document::PreloadStyle(
 
 nsresult Document::LoadChromeSheetSync(nsIURI* uri, bool isAgentSheet,
                                        RefPtr<mozilla::StyleSheet>* aSheet) {
   css::SheetParsingMode mode =
       isAgentSheet ? css::eAgentSheetFeatures : css::eAuthorSheetFeatures;
   return CSSLoader()->LoadSheetSync(uri, mode, isAgentSheet, aSheet);
 }
 
+void Document::ResetDocumentDirection() {
+  if (!(nsContentUtils::IsChromeDoc(this) || IsXULDocument())) {
+    return;
+  }
+  DocumentStatesChanged(NS_DOCUMENT_STATE_RTL_LOCALE);
+}
+
+bool Document::IsDocumentRightToLeft() {
+  if (!(nsContentUtils::IsChromeDoc(this) || IsXULDocument())) {
+    return false;
+  }
+  // setting the localedir attribute on the root element forces a
+  // specific direction for the document.
+  Element* element = GetRootElement();
+  if (element) {
+    static Element::AttrValuesArray strings[] = {nsGkAtoms::ltr, nsGkAtoms::rtl,
+                                                 nullptr};
+    switch (element->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::localedir,
+                                     strings, eCaseMatters)) {
+      case 0:
+        return false;
+      case 1:
+        return true;
+      default:
+        break;  // otherwise, not a valid value, so fall through
+    }
+  }
+
+  // otherwise, get the locale from the chrome registry and
+  // look up the intl.uidirection.<locale> preference
+  nsCOMPtr<nsIXULChromeRegistry> reg =
+      mozilla::services::GetXULChromeRegistryService();
+  if (!reg) return false;
+
+  nsAutoCString package;
+  bool isChrome;
+  if (NS_SUCCEEDED(mDocumentURI->SchemeIs("chrome", &isChrome)) && isChrome) {
+    mDocumentURI->GetHostPort(package);
+  } else {
+    // use the 'global' package for about and resource uris.
+    // otherwise, just default to left-to-right.
+    bool isAbout, isResource;
+    if (NS_SUCCEEDED(mDocumentURI->SchemeIs("about", &isAbout)) && isAbout) {
+      package.AssignLiteral("global");
+    } else if (NS_SUCCEEDED(mDocumentURI->SchemeIs("resource", &isResource)) &&
+               isResource) {
+      package.AssignLiteral("global");
+    } else {
+      return false;
+    }
+  }
+
+  bool isRTL = false;
+  reg->IsLocaleRTL(package, &isRTL);
+  return isRTL;
+}
+
 class nsDelayedEventDispatcher : public Runnable {
  public:
   explicit nsDelayedEventDispatcher(nsTArray<nsCOMPtr<Document>>& aDocuments)
       : mozilla::Runnable("nsDelayedEventDispatcher") {
     mDocuments.SwapElements(aDocuments);
   }
   virtual ~nsDelayedEventDispatcher() {}
 
@@ -11704,18 +11820,17 @@ void Document::FlushUserFontSet() {
   if (!mFontFaceSetDirty) {
     return;
   }
 
   mFontFaceSetDirty = false;
 
   if (gfxPlatform::GetPlatform()->DownloadableFontsEnabled()) {
     nsTArray<nsFontFaceRuleContainer> rules;
-    PresShell* presShell = GetPresShell();
-    if (presShell && !presShell->StyleSet()->AppendFontFaceRules(rules)) {
+    if (mStyleSetFilled && !mStyleSet->AppendFontFaceRules(rules)) {
       return;
     }
 
     if (!mFontFaceSet && !rules.IsEmpty()) {
       nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(GetScopeObject());
       mFontFaceSet = new FontFaceSet(window, this);
     }
 
@@ -11723,16 +11838,17 @@ void Document::FlushUserFontSet() {
     if (mFontFaceSet) {
       changed = mFontFaceSet->UpdateRules(rules);
     }
 
     // We need to enqueue a style change reflow (for later) to
     // reflect that we're modifying @font-face rules.  (However,
     // without a reflow, nothing will happen to start any downloads
     // that are needed.)
+    PresShell* presShell = GetPresShell();
     if (changed && presShell) {
       if (nsPresContext* presContext = presShell->GetPresContext()) {
         presContext->UserFontSetUpdated();
       }
     }
   }
 }
 
--- a/dom/base/Document.h
+++ b/dom/base/Document.h
@@ -1239,19 +1239,18 @@ class Document : public nsINode,
 
   /**
    * Create a new presentation shell that will use aContext for its
    * presentation context (presentation contexts <b>must not</b> be
    * shared among multiple presentation shells). The caller of this
    * method is responsible for calling BeginObservingDocument() on the
    * presshell if the presshell should observe document mutations.
    */
-  already_AddRefed<PresShell> CreatePresShell(
-      nsPresContext* aContext, nsViewManager* aViewManager,
-      UniquePtr<ServoStyleSet> aStyleSet);
+  already_AddRefed<PresShell> CreatePresShell(nsPresContext* aContext,
+                                              nsViewManager* aViewManager);
   void DeletePresShell();
 
   PresShell* GetPresShell() const {
     return GetBFCacheEntry() ? nullptr : mPresShell;
   }
 
   inline PresShell* GetObservingPresShell() const;
 
@@ -1626,16 +1625,24 @@ class Document : public nsINode,
   // Get the "body" in the sense of document.body: The first <body> or
   // <frameset> that's a child of a root <html>
   nsGenericHTMLElement* GetBody();
   // Set the "body" in the sense of document.body.
   void SetBody(nsGenericHTMLElement* aBody, ErrorResult& rv);
   // Get the "head" element in the sense of document.head.
   HTMLSharedElement* GetHead();
 
+  ServoStyleSet* StyleSetForPresShellOrMediaQueryEvaluation() const {
+    return mStyleSet.get();
+  }
+
+  // Whether we filled the style set with any style sheet. Only meant to be used
+  // from DocumentOrShadowRoot::Traverse.
+  bool StyleSetFilled() const { return mStyleSetFilled; }
+
   /**
    * Accessors to the collection of stylesheets owned by this document.
    * Style sheets are ordered, most significant last.
    */
 
   StyleSheetList* StyleSheets() {
     return &DocumentOrShadowRoot::EnsureDOMStyleSheets();
   }
@@ -2009,16 +2016,18 @@ class Document : public nsINode,
   // a scriptblocker but NOT within a begin/end update.
   void ContentStateChanged(nsIContent* aContent, EventStates aStateMask);
 
   // Notify that a document state has changed.
   // This should only be called by callers whose state is also reflected in the
   // implementation of Document::GetDocumentState.
   void DocumentStatesChanged(EventStates aStateMask);
 
+  void ResetDocumentDirection();
+
   // Observation hooks for style data to propagate notifications
   // to document observers
   void StyleRuleChanged(StyleSheet* aStyleSheet, css::Rule* aStyleRule);
   void StyleRuleAdded(StyleSheet* aStyleSheet, css::Rule* aStyleRule);
   void StyleRuleRemoved(StyleSheet* aStyleSheet, css::Rule* aStyleRule);
 
   /**
    * Flush notifications for this document and its parent documents
@@ -2853,17 +2862,17 @@ class Document : public nsINode,
 
   /**
    * Returns true if the locale used for the document specifies a direction of
    * right to left. For chrome documents, this comes from the chrome registry.
    * This is used to determine the current state for the :-moz-locale-dir
    * pseudoclass so once can know whether a document is expected to be rendered
    * left-to-right or right-to-left.
    */
-  virtual bool IsDocumentRightToLeft() { return false; }
+  bool IsDocumentRightToLeft();
 
   /**
    * Called by Parser for link rel=preconnect
    */
   void MaybePreconnect(nsIURI* uri, CORSMode aCORSMode);
 
   enum DocumentTheme {
     Doc_Theme_Uninitialized,  // not determined yet
@@ -3779,17 +3788,24 @@ class Document : public nsINode,
   }
 
   void UpdateDocumentStates(EventStates);
 
   void RemoveDocStyleSheetsFromStyleSets();
   void RemoveStyleSheetsFromStyleSets(
       const nsTArray<RefPtr<StyleSheet>>& aSheets, SheetType aType);
   void ResetStylesheetsToURI(nsIURI* aURI);
-  void FillStyleSet(ServoStyleSet* aStyleSet);
+  void FillStyleSet();
+  void FillStyleSetUserAndUASheets();
+  void FillStyleSetDocumentSheets();
+  void CompatibilityModeChanged();
+  bool NeedsQuirksSheet() const {
+    // SVG documents never load quirk.css.
+    return mCompatMode == eCompatibility_NavQuirks && !IsSVGDocument();
+  }
   void AddStyleSheetToStyleSets(StyleSheet* aSheet);
   void RemoveStyleSheetFromStyleSets(StyleSheet* aSheet);
   void NotifyStyleSheetAdded(StyleSheet* aSheet, bool aDocumentSheet);
   void NotifyStyleSheetRemoved(StyleSheet* aSheet, bool aDocumentSheet);
   void NotifyStyleSheetApplicableStateChanged();
   // Just like EnableStyleSheetsForSet, but doesn't check whether
   // aSheetSet is null and allows the caller to control whether to set
   // aSheetSet as the preferred set in the CSSLoader.
@@ -3803,16 +3819,17 @@ class Document : public nsINode,
   }
 
   mutable std::bitset<eDeprecatedOperationCount> mDeprecationWarnedAbout;
   mutable std::bitset<eDocumentWarningCount> mDocWarningWarnedAbout;
 
   // Lazy-initialization to have mDocGroup initialized in prior to the
   // SelectorCaches.
   UniquePtr<SelectorCache> mSelectorCache;
+  UniquePtr<ServoStyleSet> mStyleSet;
 
  protected:
   friend class nsDocumentOnStack;
 
   void IncreaseStackRefCnt() { ++mStackRefCnt; }
 
   void DecreaseStackRefCnt() {
     if (--mStackRefCnt == 0 && mNeedsReleaseAfterStackRefCntRelease) {
@@ -4160,20 +4177,22 @@ class Document : public nsINode,
 
   // True if the document has been detached from its content viewer.
   bool mIsGoingAway : 1;
 
   bool mInXBLUpdate : 1;
 
   bool mNeedsReleaseAfterStackRefCntRelease : 1;
 
-  // Whether we have filled our pres shell's style set with the document's
-  // additional sheets and sheets from the nsStyleSheetService.
+  // Whether we have filled our style set with all the stylesheets.
   bool mStyleSetFilled : 1;
 
+  // Whether we have a quirks mode stylesheet in the style set.
+  bool mQuirkSheetAdded : 1;
+
   // Keeps track of whether we have a pending
   // 'style-sheet-applicable-state-changed' notification.
   bool mSSApplicableStateNotificationPending : 1;
 
   // True if this document has ever had an HTML or SVG <title> element
   // bound to it
   bool mMayHaveTitleElement : 1;
 
--- a/dom/base/DocumentOrShadowRoot.cpp
+++ b/dom/base/DocumentOrShadowRoot.cpp
@@ -583,29 +583,54 @@ nsRadioGroupStruct* DocumentOrShadowRoot
 nsRadioGroupStruct* DocumentOrShadowRoot::GetOrCreateRadioGroup(
     const nsAString& aName) {
   return mRadioGroups.LookupForAdd(aName).OrInsert(
       []() { return new nsRadioGroupStruct(); });
 }
 
 void DocumentOrShadowRoot::Traverse(DocumentOrShadowRoot* tmp,
                                     nsCycleCollectionTraversalCallback& cb) {
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheets)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMStyleSheets)
+  for (StyleSheet* sheet : tmp->mStyleSheets) {
+    if (!sheet->IsApplicable()) {
+      continue;
+    }
+    // The style set or mServoStyles keep more references to it if the sheet is
+    // applicable.
+    if (tmp->mKind == Kind::ShadowRoot) {
+      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mServoStyles->sheets[i]");
+      cb.NoteXPCOMChild(sheet);
+    } else if (tmp->AsNode().AsDocument()->StyleSetFilled()) {
+      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
+          cb, "mStyleSet->mStyleSheets[SheetType::Author][i]");
+      cb.NoteXPCOMChild(sheet);
+      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
+          cb, "mStyleSet->mRawSet.stylist.stylesheets.author[i]");
+      cb.NoteXPCOMChild(sheet);
+    }
+  }
+  for (auto iter = tmp->mIdentifierMap.ConstIter(); !iter.Done(); iter.Next()) {
+    iter.Get()->Traverse(&cb);
+  }
   for (auto iter = tmp->mRadioGroups.Iter(); !iter.Done(); iter.Next()) {
     nsRadioGroupStruct* radioGroup = iter.UserData();
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
         cb, "mRadioGroups entry->mSelectedRadioButton");
     cb.NoteXPCOMChild(ToSupports(radioGroup->mSelectedRadioButton));
 
     uint32_t i, count = radioGroup->mRadioButtons.Count();
     for (i = 0; i < count; ++i) {
       NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
           cb, "mRadioGroups entry->mRadioButtons[i]");
       cb.NoteXPCOMChild(radioGroup->mRadioButtons[i]);
     }
   }
 }
 
 void DocumentOrShadowRoot::Unlink(DocumentOrShadowRoot* tmp) {
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMStyleSheets)
+  tmp->mIdentifierMap.Clear();
   tmp->mRadioGroups.Clear();
 }
 
 }  // namespace dom
 }  // namespace mozilla
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -2153,26 +2153,26 @@ nsresult Element::DispatchEvent(nsPresCo
   MOZ_ASSERT(aTarget, "Must have target");
   MOZ_ASSERT(aEvent, "Must have source event");
   MOZ_ASSERT(aStatus, "Null out param?");
 
   if (!aPresContext) {
     return NS_OK;
   }
 
-  nsCOMPtr<nsIPresShell> shell = aPresContext->GetPresShell();
-  if (!shell) {
+  RefPtr<PresShell> presShell = aPresContext->GetPresShell();
+  if (!presShell) {
     return NS_OK;
   }
 
   if (aFullDispatch) {
-    return shell->HandleEventWithTarget(aEvent, nullptr, aTarget, aStatus);
-  }
-
-  return shell->HandleDOMEventWithTarget(aTarget, aEvent, aStatus);
+    return presShell->HandleEventWithTarget(aEvent, nullptr, aTarget, aStatus);
+  }
+
+  return presShell->HandleDOMEventWithTarget(aTarget, aEvent, aStatus);
 }
 
 /* static */
 nsresult Element::DispatchClickEvent(nsPresContext* aPresContext,
                                      WidgetInputEvent* aSourceEvent,
                                      nsIContent* aTarget, bool aFullDispatch,
                                      const EventFlags* aExtraEventFlags,
                                      nsEventStatus* aStatus) {
@@ -3115,26 +3115,26 @@ nsresult Element::PostHandleEventForLink
       WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
       if (mouseEvent->IsLeftClickEvent()) {
         if (mouseEvent->IsControl() || mouseEvent->IsMeta() ||
             mouseEvent->IsAlt() || mouseEvent->IsShift()) {
           break;
         }
 
         // The default action is simply to dispatch DOMActivate
-        nsCOMPtr<nsIPresShell> shell = aVisitor.mPresContext->GetPresShell();
-        if (shell) {
+        if (RefPtr<PresShell> presShell =
+                aVisitor.mPresContext->GetPresShell()) {
           // single-click
           nsEventStatus status = nsEventStatus_eIgnore;
           // DOMActive event should be trusted since the activation is actually
           // occurred even if the cause is an untrusted click event.
           InternalUIEvent actEvent(true, eLegacyDOMActivate, mouseEvent);
           actEvent.mDetail = 1;
 
-          rv = shell->HandleDOMEventWithTarget(this, &actEvent, &status);
+          rv = presShell->HandleDOMEventWithTarget(this, &actEvent, &status);
           if (NS_SUCCEEDED(rv)) {
             aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
           }
         }
       }
       break;
     }
     case eLegacyDOMActivate: {
--- a/dom/base/IdentifierMapEntry.h
+++ b/dom/base/IdentifierMapEntry.h
@@ -1,25 +1,26 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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/. */
 
 /*
- * Base class for all our document implementations.
+ * Entry for the Document or ShadowRoot's identifier map.
  */
 
 #ifndef mozilla_IdentifierMapEntry_h
 #define mozilla_IdentifierMapEntry_h
 
 #include "PLDHashTable.h"
 
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Move.h"
+#include "mozilla/dom/TreeOrderedArray.h"
 #include "mozilla/net/ReferrerPolicy.h"
 
 #include "nsCOMPtr.h"
 #include "nsAtom.h"
 #include "nsHashKeys.h"
 #include "nsTArray.h"
 #include "nsTHashtable.h"
 
@@ -115,26 +116,31 @@ class IdentifierMapEntry : public PLDHas
   bool IsEmpty();
   nsBaseContentList* GetNameContentList() { return mNameContentList; }
   bool HasNameElement() const;
 
   /**
    * Returns the element if we know the element associated with this
    * id. Otherwise returns null.
    */
-  Element* GetIdElement();
+  Element* GetIdElement() { return mIdContentList->SafeElementAt(0); }
+
   /**
    * Returns the list of all elements associated with this id.
    */
   const nsTArray<Element*>& GetIdElements() const { return mIdContentList; }
+
   /**
    * If this entry has a non-null image element set (using SetImageElement),
    * the image element will be returned, otherwise the same as GetIdElement().
    */
-  Element* GetImageIdElement();
+  Element* GetImageIdElement() {
+    return mImageElement ? mImageElement.get() : GetIdElement();
+  }
+
   /**
    * This can fire ID change callbacks.
    */
   void AddIdElement(Element* aElement);
   /**
    * This can fire ID change callbacks.
    */
   void RemoveIdElement(Element* aElement);
@@ -187,19 +193,17 @@ class IdentifierMapEntry : public PLDHas
  private:
   IdentifierMapEntry(const IdentifierMapEntry& aOther) = delete;
   IdentifierMapEntry& operator=(const IdentifierMapEntry& aOther) = delete;
 
   void FireChangeCallbacks(Element* aOldElement, Element* aNewElement,
                            bool aImageOnly = false);
 
   AtomOrString mKey;
-  // empty if there are no elements with this ID.
-  // The elements are stored as weak pointers.
-  AutoTArray<Element*, 1> mIdContentList;
+  dom::TreeOrderedArray<Element> mIdContentList;
   RefPtr<nsBaseContentList> mNameContentList;
   nsAutoPtr<nsTHashtable<ChangeCallbackEntry> > mChangeCallbacks;
   RefPtr<Element> mImageElement;
 };
 
 }  // namespace mozilla
 
 #endif  // #ifndef mozilla_IdentifierMapEntry_h
--- a/dom/base/ResponsiveImageSelector.cpp
+++ b/dom/base/ResponsiveImageSelector.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/ResponsiveImageSelector.h"
 #include "mozilla/PresShell.h"
 #include "mozilla/ServoStyleSetInlines.h"
 #include "mozilla/TextUtils.h"
 #include "nsIURI.h"
+#include "nsIPresShellInlines.h"
 #include "mozilla/dom/Document.h"
 #include "nsContentUtils.h"
 #include "nsPresContext.h"
 
 #include "nsCSSProps.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
--- a/dom/base/Selection.cpp
+++ b/dom/base/Selection.cpp
@@ -16,16 +16,17 @@
 #include "mozilla/AutoRestore.h"
 #include "mozilla/ContentIterator.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/SelectionBinding.h"
 #include "mozilla/dom/ShadowRoot.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/HTMLEditor.h"
+#include "mozilla/PresShell.h"
 #include "mozilla/RangeBoundary.h"
 #include "mozilla/Telemetry.h"
 
 #include "nsCOMPtr.h"
 #include "nsString.h"
 #include "nsFrameSelection.h"
 #include "nsISelectionListener.h"
 #include "nsContentCID.h"
@@ -47,17 +48,16 @@
 #include "nsLayoutUtils.h"
 #include "nsBidiPresUtils.h"
 #include "nsTextFrame.h"
 
 #include "nsContentUtils.h"
 #include "nsThreadUtils.h"
 
 #include "nsPresContext.h"
-#include "nsIPresShell.h"
 #include "nsCaret.h"
 
 #include "nsITimer.h"
 #include "mozilla/dom/Document.h"
 #include "nsINamed.h"
 
 #include "nsISelectionController.h"  //for the enums
 #include "nsCopySupport.h"
@@ -381,25 +381,25 @@ void printRange(nsRange* aDomRange) {
          (unsigned long)aDomRange, (unsigned long)startNode, (long)startOffset,
          (unsigned long)endNode, (long)endOffset);
 }
 #endif /* PRINT_RANGE */
 
 void Selection::Stringify(nsAString& aResult, FlushFrames aFlushFrames) {
   if (aFlushFrames == FlushFrames::Yes) {
     // We need FlushType::Frames here to make sure frames have been created for
-    // the selected content.  Use mFrameSelection->GetShell() which returns
+    // the selected content.  Use mFrameSelection->GetPresShell() which returns
     // null if the Selection has been disconnected (the shell is Destroyed).
-    nsCOMPtr<nsIPresShell> shell =
-        mFrameSelection ? mFrameSelection->GetShell() : nullptr;
-    if (!shell) {
+    RefPtr<PresShell> presShell =
+        mFrameSelection ? mFrameSelection->GetPresShell() : nullptr;
+    if (!presShell) {
       aResult.Truncate();
       return;
     }
-    shell->FlushPendingNotifications(FlushType::Frames);
+    presShell->FlushPendingNotifications(FlushType::Frames);
   }
 
   IgnoredErrorResult rv;
   ToStringWithFormat(NS_LITERAL_STRING("text/plain"),
                      nsIDocumentEncoder::SkipInvisibleContent, 0, aResult, rv);
   if (rv.Failed()) {
     aResult.Truncate();
   }
@@ -410,23 +410,23 @@ void Selection::ToStringWithFormat(const
                                    nsAString& aReturn, ErrorResult& aRv) {
   nsCOMPtr<nsIDocumentEncoder> encoder =
       do_createDocumentEncoder(NS_ConvertUTF16toUTF8(aFormatType).get());
   if (!encoder) {
     aRv.Throw(NS_ERROR_FAILURE);
     return;
   }
 
-  nsIPresShell* shell = GetPresShell();
-  if (!shell) {
+  PresShell* presShell = GetPresShell();
+  if (!presShell) {
     aRv.Throw(NS_ERROR_FAILURE);
     return;
   }
 
-  Document* doc = shell->GetDocument();
+  Document* doc = presShell->GetDocument();
 
   // Flags should always include OutputSelectionOnly if we're coming from here:
   aFlags |= nsIDocumentEncoder::OutputSelectionOnly;
   nsAutoString readstring;
   readstring.Assign(aFormatType);
   nsresult rv = encoder->Init(doc, readstring, aFlags);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
@@ -526,22 +526,22 @@ nsresult Selection::GetTableCellLocation
   // Get the child content (the cell) pointed to by starting node of range
   // We do minimal checking since GetTableSelectionType assures
   // us that this really is a table cell
   nsCOMPtr<nsIContent> child = aRange->GetChildAtStartOffset();
   if (!child) return NS_ERROR_FAILURE;
 
   // GetCellLayout depends on current frame, we need flush frame to get
   // nsITableCellLayout
-  nsCOMPtr<nsIPresShell> presShell = mFrameSelection->GetShell();
+  RefPtr<PresShell> presShell = mFrameSelection->GetPresShell();
   if (presShell) {
     presShell->FlushPendingNotifications(FlushType::Frames);
 
     // Since calling FlushPendingNotifications, so check whether disconnected.
-    if (!mFrameSelection || !mFrameSelection->GetShell()) {
+    if (!mFrameSelection || !mFrameSelection->GetPresShell()) {
       return NS_ERROR_FAILURE;
     }
   }
 
   // Note: This is a non-ref-counted pointer to the frame
   nsITableCellLayout* cellLayout = mFrameSelection->GetCellLayout(child);
   if (!cellLayout) return NS_ERROR_FAILURE;
 
@@ -672,30 +672,26 @@ void Selection::Disconnect() {
 
   if (mCachedOffsetForFrame) {
     delete mCachedOffsetForFrame;
     mCachedOffsetForFrame = nullptr;
   }
 }
 
 Document* Selection::GetParentObject() const {
-  nsIPresShell* shell = GetPresShell();
-  if (shell) {
-    return shell->GetDocument();
-  }
-  return nullptr;
+  PresShell* presShell = GetPresShell();
+  return presShell ? presShell->GetDocument() : nullptr;
 }
 
 DocGroup* Selection::GetDocGroup() const {
-  nsIPresShell* shell = GetPresShell();
-  if (!shell) {
+  PresShell* presShell = GetPresShell();
+  if (!presShell) {
     return nullptr;
   }
-
-  Document* doc = shell->GetDocument();
+  Document* doc = presShell->GetDocument();
   return doc ? doc->GetDocGroup() : nullptr;
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(Selection)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Selection)
   // Unlink the selection listeners *before* we do RemoveAllRanges since
   // we don't want to notify the listeners during JS GC (they could be
@@ -1863,38 +1859,39 @@ nsresult Selection::StopAutoScrollTimer(
 nsresult Selection::DoAutoScroll(nsIFrame* aFrame, nsPoint aPoint) {
   MOZ_ASSERT(aFrame, "Need a frame");
 
   if (mAutoScrollTimer) {
     (void)mAutoScrollTimer->Stop();
   }
 
   nsPresContext* presContext = aFrame->PresContext();
-  nsCOMPtr<nsIPresShell> shell = presContext->PresShell();
+  RefPtr<PresShell> presShell = presContext->PresShell();
   nsRootPresContext* rootPC = presContext->GetRootPresContext();
   if (!rootPC) return NS_OK;
   nsIFrame* rootmostFrame = rootPC->PresShell()->GetRootFrame();
   AutoWeakFrame weakRootFrame(rootmostFrame);
   AutoWeakFrame weakFrame(aFrame);
   // Get the point relative to the root most frame because the scroll we are
   // about to do will change the coordinates of aFrame.
   nsPoint globalPoint = aPoint + aFrame->GetOffsetToCrossDoc(rootmostFrame);
 
   bool done = false;
   bool didScroll;
   while (true) {
-    didScroll = shell->ScrollFrameRectIntoView(
+    didScroll = presShell->ScrollFrameRectIntoView(
         aFrame, nsRect(aPoint, nsSize(0, 0)), nsIPresShell::ScrollAxis(),
         nsIPresShell::ScrollAxis(), 0);
     if (!weakFrame || !weakRootFrame) {
       return NS_OK;
     }
     if (!didScroll && !done) {
       // If aPoint is at the screen edge then try to scroll anyway, once.
-      RefPtr<nsDeviceContext> dx = shell->GetViewManager()->GetDeviceContext();
+      RefPtr<nsDeviceContext> dx =
+          presShell->GetViewManager()->GetDeviceContext();
       nsRect screen;
       dx->GetRect(screen);
       nsPoint screenPoint =
           globalPoint + rootmostFrame->GetScreenRectInAppUnits().TopLeft();
       nscoord onePx = AppUnitsPerCSSPixel();
       nscoord scrollAmount = 10 * onePx;
       if (std::abs(screen.x - screenPoint.x) <= onePx) {
         aPoint.x -= scrollAmount;
@@ -1911,17 +1908,18 @@ nsresult Selection::DoAutoScroll(nsIFram
       continue;
     }
     break;
   }
 
   // Start the AutoScroll timer if necessary.
   if (didScroll && mAutoScrollTimer) {
     nsPoint presContextPoint =
-        globalPoint - shell->GetRootFrame()->GetOffsetToCrossDoc(rootmostFrame);
+        globalPoint -
+        presShell->GetRootFrame()->GetOffsetToCrossDoc(rootmostFrame);
     mAutoScrollTimer->Start(presContext, presContextPoint);
   }
 
   return NS_OK;
 }
 
 void Selection::RemoveAllRanges(ErrorResult& aRv) {
   if (!mFrameSelection) return;  // nothing to do
@@ -2855,32 +2853,29 @@ bool Selection::ContainsPoint(const nsPo
     if (checker.MatchFound()) {
       return true;
     }
   }
   return false;
 }
 
 nsPresContext* Selection::GetPresContext() const {
-  nsIPresShell* shell = GetPresShell();
-  if (!shell) {
-    return nullptr;
+  PresShell* presShell = GetPresShell();
+  return presShell ? presShell->GetPresContext() : nullptr;
+}
+
+PresShell* Selection::GetPresShell() const {
+  if (!mFrameSelection) {
+    return nullptr;  // nothing to do
   }
-
-  return shell->GetPresContext();
-}
-
-nsIPresShell* Selection::GetPresShell() const {
-  if (!mFrameSelection) return nullptr;  // nothing to do
-
-  return mFrameSelection->GetShell();
+  return mFrameSelection->GetPresShell();
 }
 
 Document* Selection::GetDocument() const {
-  nsIPresShell* presShell = GetPresShell();
+  PresShell* presShell = GetPresShell();
   return presShell ? presShell->GetDocument() : nullptr;
 }
 
 nsPIDOMWindowOuter* Selection::GetWindow() const {
   Document* document = GetDocument();
   return document ? document->GetWindow() : nullptr;
 }
 
@@ -3045,43 +3040,45 @@ void Selection::ScrollIntoView(int16_t a
 nsresult Selection::ScrollIntoView(SelectionRegion aRegion,
                                    nsIPresShell::ScrollAxis aVertical,
                                    nsIPresShell::ScrollAxis aHorizontal,
                                    int32_t aFlags) {
   if (!mFrameSelection) {
     return NS_OK;
   }
 
-  nsIPresShell* presShell = mFrameSelection->GetShell();
+  PresShell* presShell = mFrameSelection->GetPresShell();
   if (!presShell || !presShell->GetDocument()) {
     return NS_OK;
   }
 
   if (mFrameSelection->GetBatching()) return NS_OK;
 
   if (!(aFlags & Selection::SCROLL_SYNCHRONOUS))
     return PostScrollSelectionIntoViewEvent(aRegion, aFlags, aVertical,
                                             aHorizontal);
 
   // From this point on, the presShell may get destroyed by the calls below, so
   // hold on to it using a strong reference to ensure the safety of the
   // accesses to frame pointers in the callees.
-  nsCOMPtr<nsIPresShell> kungFuDeathGrip(presShell);
+  RefPtr<PresShell> kungFuDeathGrip(presShell);
 
   // Now that text frame character offsets are always valid (though not
   // necessarily correct), the worst that will happen if we don't flush here
   // is that some callers might scroll to the wrong place.  Those should
   // either manually flush if they're in a safe position for it or use the
   // async version of this method.
   if (aFlags & Selection::SCROLL_DO_FLUSH) {
     presShell->GetDocument()->FlushPendingNotifications(FlushType::Layout);
 
     // Reget the presshell, since it might have been Destroy'ed.
-    presShell = mFrameSelection ? mFrameSelection->GetShell() : nullptr;
-    if (!presShell) return NS_OK;
+    presShell = mFrameSelection ? mFrameSelection->GetPresShell() : nullptr;
+    if (!presShell) {
+      return NS_OK;
+    }
   }
 
   //
   // Scroll the selection region into view.
   //
 
   nsRect rect;
   nsIFrame* frame = GetSelectionAnchorGeometry(aRegion, &rect);
@@ -3207,19 +3204,19 @@ nsresult Selection::NotifySelectionListe
     return NS_OK;
   }
   if (mSelectionListeners.IsEmpty()) {
     // If there are no selection listeners, we're done!
     return NS_OK;
   }
 
   nsCOMPtr<Document> doc;
-  nsIPresShell* ps = GetPresShell();
-  if (ps) {
-    doc = ps->GetDocument();
+  PresShell* presShell = GetPresShell();
+  if (presShell) {
+    doc = presShell->GetDocument();
   }
 
   // We've notified all selection listeners even when some of them are removed
   // (and may be destroyed) during notifying one of them.  Therefore, we should
   // copy all listeners to the local variable first.
   AutoTArray<nsCOMPtr<nsISelectionListener>, 5> selectionListeners(
       mSelectionListeners);
 
@@ -3372,20 +3369,21 @@ void Selection::Modify(const nsAString& 
   // case we call nsISelectionController::CompleteMove to move the cursor to
   // the beginning/end of the line.
   RefPtr<nsFrameSelection> frameSelection = mFrameSelection;
   rv = frameSelection->MoveCaret(
       forward ? eDirNext : eDirPrevious, extend, amount,
       visual ? nsFrameSelection::eVisual : nsFrameSelection::eLogical);
 
   if (aGranularity.LowerCaseEqualsLiteral("line") && NS_FAILED(rv)) {
-    nsCOMPtr<nsISelectionController> shell =
-        do_QueryInterface(frameSelection->GetShell());
-    if (!shell) return;
-    shell->CompleteMove(forward, extend);
+    RefPtr<PresShell> presShell = frameSelection->GetPresShell();
+    if (!presShell) {
+      return;
+    }
+    presShell->CompleteMove(forward, extend);
   }
 }
 
 void Selection::SetBaseAndExtentJS(nsINode& aAnchorNode, uint32_t aAnchorOffset,
                                    nsINode& aFocusNode, uint32_t aFocusOffset,
                                    ErrorResult& aRv) {
   AutoRestore<bool> calledFromJSRestorer(mCalledByJS);
   mCalledByJS = true;
--- a/dom/base/Selection.h
+++ b/dom/base/Selection.h
@@ -6,23 +6,23 @@
 
 #ifndef mozilla_Selection_h__
 #define mozilla_Selection_h__
 
 #include "nsIWeakReference.h"
 
 #include "mozilla/AccessibleCaretEventHub.h"
 #include "mozilla/AutoRestore.h"
+#include "mozilla/PresShell.h"  // For ScrollAxis
 #include "mozilla/RangeBoundary.h"
 #include "mozilla/SelectionChangeEventDispatcher.h"
 #include "mozilla/TextRange.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/WeakPtr.h"
 #include "nsDirection.h"
-#include "nsIPresShell.h"  // For ScrollAxis
 #include "nsISelectionController.h"
 #include "nsISelectionListener.h"
 #include "nsRange.h"
 #include "nsTArrayForwardDeclare.h"
 #include "nsThreadUtils.h"
 #include "nsWrapperCache.h"
 
 struct CachedOffsetForFrame;
@@ -87,17 +87,17 @@ class Selection final : public nsSupport
    * NotifyAutoCopy() starts to notify AutoCopyListener of selection changes.
    */
   void NotifyAutoCopy() { mNotifyAutoCopy = true; }
 
   /**
    * MaybeNotifyAccessibleCaretEventHub() starts to notify
    * AccessibleCaretEventHub of selection change if aPresShell has it.
    */
-  void MaybeNotifyAccessibleCaretEventHub(nsIPresShell* aPresShell) {
+  void MaybeNotifyAccessibleCaretEventHub(PresShell* aPresShell) {
     if (!mAccessibleCaretEventHub && aPresShell) {
       mAccessibleCaretEventHub = aPresShell->GetAccessibleCaretEventHub();
     }
   }
 
   /**
    * StopNotifyingAccessibleCaretEventHub() stops notifying
    * AccessibleCaretEventHub of selection change.
@@ -117,17 +117,17 @@ class Selection final : public nsSupport
     }
   }
 
   Document* GetParentObject() const;
   DocGroup* GetDocGroup() const;
 
   // utility methods for scrolling the selection into view
   nsPresContext* GetPresContext() const;
-  nsIPresShell* GetPresShell() const;
+  PresShell* GetPresShell() const;
   nsFrameSelection* GetFrameSelection() const { return mFrameSelection; }
   // Returns a rect containing the selection region, and frame that that
   // position is relative to. For SELECTION_ANCHOR_REGION or
   // SELECTION_FOCUS_REGION the rect is a zero-width rectangle. For
   // SELECTION_WHOLE_SELECTION the rect contains both the anchor and focus
   // region rects.
   nsIFrame* GetSelectionAnchorGeometry(SelectionRegion aRegion, nsRect* aRect);
   // Returns the position of the region (SELECTION_ANCHOR_REGION or
--- a/dom/base/ShadowRoot.cpp
+++ b/dom/base/ShadowRoot.cpp
@@ -10,52 +10,38 @@
 #include "ChildIterator.h"
 #include "nsContentUtils.h"
 #include "nsIStyleSheetLinkingElement.h"
 #include "nsWindowSizes.h"
 #include "nsXBLPrototypeBinding.h"
 #include "mozilla/dom/DirectionalityUtils.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/HTMLSlotElement.h"
+#include "mozilla/dom/TreeOrderedArrayInlines.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/IdentifierMapEntry.h"
 #include "mozilla/PresShell.h"
 #include "mozilla/ServoStyleRuleMap.h"
 #include "mozilla/StyleSheet.h"
 #include "mozilla/StyleSheetInlines.h"
 #include "mozilla/dom/StyleSheetList.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(ShadowRoot)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ShadowRoot, DocumentFragment)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheets)
-  for (StyleSheet* sheet : tmp->mStyleSheets) {
-    // mServoStyles keeps another reference to it if applicable.
-    if (sheet->IsApplicable()) {
-      MOZ_ASSERT(tmp->mServoStyles);
-      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mServoStyles->sheets[i]");
-      cb.NoteXPCOMChild(sheet);
-    }
-  }
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMStyleSheets)
-  for (auto iter = tmp->mIdentifierMap.ConstIter(); !iter.Done(); iter.Next()) {
-    iter.Get()->Traverse(&cb);
-  }
   DocumentOrShadowRoot::Traverse(tmp, cb);
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ShadowRoot)
   if (tmp->GetHost()) {
     tmp->GetHost()->RemoveMutationObserver(tmp);
   }
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMStyleSheets)
-  tmp->mIdentifierMap.Clear();
   DocumentOrShadowRoot::Unlink(tmp);
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(DocumentFragment)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ShadowRoot)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
   NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
   NS_INTERFACE_MAP_ENTRY(nsIRadioGroupContainer)
 NS_INTERFACE_MAP_END_INHERITING(DocumentFragment)
@@ -196,97 +182,96 @@ void ShadowRoot::InvalidateStyleAndLayou
 
 void ShadowRoot::AddSlot(HTMLSlotElement* aSlot) {
   MOZ_ASSERT(aSlot);
 
   // Note that if name attribute missing, the slot is a default slot.
   nsAutoString name;
   aSlot->GetName(name);
 
-  nsTArray<HTMLSlotElement*>* currentSlots = mSlotMap.LookupOrAdd(name);
-  MOZ_ASSERT(currentSlots);
-
-  HTMLSlotElement* oldSlot = currentSlots->SafeElementAt(0);
+  SlotArray& currentSlots = *mSlotMap.LookupOrAdd(name);
 
-  TreeOrderComparator comparator;
-  currentSlots->InsertElementSorted(aSlot, comparator);
-
-  HTMLSlotElement* currentSlot = currentSlots->ElementAt(0);
-  if (currentSlot != aSlot) {
+  size_t index = currentSlots.Insert(*aSlot);
+  if (index != 0) {
     return;
   }
 
-  if (oldSlot && oldSlot != currentSlot) {
+  HTMLSlotElement* oldSlot = currentSlots->SafeElementAt(1);
+  if (oldSlot) {
+    MOZ_DIAGNOSTIC_ASSERT(oldSlot != aSlot);
+
     // Move assigned nodes from old slot to new slot.
     InvalidateStyleAndLayoutOnSubtree(oldSlot);
     const nsTArray<RefPtr<nsINode>>& assignedNodes = oldSlot->AssignedNodes();
     bool doEnqueueSlotChange = false;
     while (assignedNodes.Length() > 0) {
       nsINode* assignedNode = assignedNodes[0];
 
       oldSlot->RemoveAssignedNode(assignedNode);
-      currentSlot->AppendAssignedNode(assignedNode);
+      aSlot->AppendAssignedNode(assignedNode);
       doEnqueueSlotChange = true;
     }
 
     if (doEnqueueSlotChange) {
       oldSlot->EnqueueSlotChangeEvent();
-      currentSlot->EnqueueSlotChangeEvent();
+      aSlot->EnqueueSlotChangeEvent();
       SlotStateChanged(oldSlot);
-      SlotStateChanged(currentSlot);
+      SlotStateChanged(aSlot);
     }
   } else {
     bool doEnqueueSlotChange = false;
     // Otherwise add appropriate nodes to this slot from the host.
     for (nsIContent* child = GetHost()->GetFirstChild(); child;
          child = child->GetNextSibling()) {
       nsAutoString slotName;
       if (child->IsElement()) {
         child->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::slot,
                                     slotName);
       }
       if (!child->IsSlotable() || !slotName.Equals(name)) {
         continue;
       }
       doEnqueueSlotChange = true;
-      currentSlot->AppendAssignedNode(child);
+      aSlot->AppendAssignedNode(child);
     }
 
     if (doEnqueueSlotChange) {
-      currentSlot->EnqueueSlotChangeEvent();
-      SlotStateChanged(currentSlot);
+      aSlot->EnqueueSlotChangeEvent();
+      SlotStateChanged(aSlot);
     }
   }
 }
 
 void ShadowRoot::RemoveSlot(HTMLSlotElement* aSlot) {
   MOZ_ASSERT(aSlot);
 
   nsAutoString name;
   aSlot->GetName(name);
 
-  SlotArray* currentSlots = mSlotMap.Get(name);
-  MOZ_DIAGNOSTIC_ASSERT(currentSlots && currentSlots->Contains(aSlot),
-                        "Slot to deregister wasn't found?");
+  MOZ_ASSERT(mSlotMap.Get(name));
+
+  SlotArray& currentSlots = *mSlotMap.Get(name);
+  MOZ_DIAGNOSTIC_ASSERT(currentSlots->Contains(aSlot),
+                        "Slot to de-register wasn't found?");
   if (currentSlots->Length() == 1) {
     MOZ_ASSERT(currentSlots->ElementAt(0) == aSlot);
 
     InvalidateStyleAndLayoutOnSubtree(aSlot);
 
     mSlotMap.Remove(name);
     if (!aSlot->AssignedNodes().IsEmpty()) {
       aSlot->ClearAssignedNodes();
       aSlot->EnqueueSlotChangeEvent();
     }
 
     return;
   }
 
   const bool wasFirstSlot = currentSlots->ElementAt(0) == aSlot;
-  currentSlots->RemoveElement(aSlot);
+  currentSlots.RemoveElement(*aSlot);
 
   // Move assigned nodes from removed slot to the next slot in
   // tree order with the same name.
   if (!wasFirstSlot) {
     return;
   }
 
   InvalidateStyleAndLayoutOnSubtree(aSlot);
@@ -486,22 +471,22 @@ ShadowRoot::SlotAssignment ShadowRoot::S
   nsAutoString slotName;
   // Note that if slot attribute is missing, assign it to the first default
   // slot, if exists.
   if (aContent->IsElement()) {
     aContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::slot,
                                    slotName);
   }
 
-  nsTArray<HTMLSlotElement*>* slots = mSlotMap.Get(slotName);
+  SlotArray* slots = mSlotMap.Get(slotName);
   if (!slots) {
     return {};
   }
 
-  HTMLSlotElement* slot = slots->ElementAt(0);
+  HTMLSlotElement* slot = (*slots)->ElementAt(0);
   MOZ_ASSERT(slot);
 
   // Find the appropriate position in the assigned node list for the
   // newly assigned content.
   const nsTArray<RefPtr<nsINode>>& assignedNodes = slot->AssignedNodes();
   nsIContent* currentContent = GetHost()->GetFirstChild();
   Maybe<uint32_t> insertionIndex;
   for (uint32_t i = 0; i < assignedNodes.Length(); i++) {
--- a/dom/base/ShadowRoot.h
+++ b/dom/base/ShadowRoot.h
@@ -247,17 +247,17 @@ class ShadowRoot final : public Document
   virtual ~ShadowRoot();
 
   const ShadowRootMode mMode;
 
   // The computed data from the style sheets.
   UniquePtr<RawServoAuthorStyles> mServoStyles;
   UniquePtr<mozilla::ServoStyleRuleMap> mStyleRuleMap;
 
-  using SlotArray = AutoTArray<HTMLSlotElement*, 1>;
+  using SlotArray = TreeOrderedArray<HTMLSlotElement>;
   // Map from name of slot to an array of all slots in the shadow DOM with with
   // the given name. The slots are stored as a weak pointer because the elements
   // are in the shadow tree and should be kept alive by its parent.
   nsClassHashtable<nsStringHashKey, SlotArray> mSlotMap;
 
   bool mIsUAWidget;
 
   nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override;
new file mode 100644
--- /dev/null
+++ b/dom/base/TreeOrderedArray.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#ifndef mozilla_dom_TreeOrderedArray_h
+#define mozilla_dom_TreeOrderedArray_h
+
+#include "nsTArray.h"
+
+namespace mozilla {
+namespace dom {
+
+// A sorted tree-ordered list of raw pointers to nodes.
+template <typename Node>
+class TreeOrderedArray {
+ public:
+  operator const nsTArray<Node*>&() const { return mList; }
+
+  const nsTArray<Node*>* operator->() const { return &mList; }
+
+  // Inserts a node into the list, and returns the new index in the array.
+  //
+  // All the nodes in the list should be in the same subtree, and debug builds
+  // assert this.
+  //
+  // It's also forbidden to call Insert() with the same node multiple times, and
+  // it will assert as well.
+  inline size_t Insert(Node&);
+
+  bool RemoveElement(Node& aNode) { return mList.RemoveElement(&aNode); }
+
+ private:
+  AutoTArray<Node*, 1> mList;
+};
+
+}  // namespace dom
+}  // namespace mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/base/TreeOrderedArrayInlines.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#ifndef mozilla_dom_TreeOrderedArrayInlines_h
+#define mozilla_dom_TreeOrderedArrayInlines_h
+
+#include "mozilla/dom/TreeOrderedArray.h"
+#include "mozilla/BinarySearch.h"
+#include "nsContentUtils.h"
+#include <type_traits>
+
+namespace mozilla {
+namespace dom {
+
+template <typename Node>
+size_t TreeOrderedArray<Node>::Insert(Node& aNode) {
+  static_assert(std::is_base_of<nsINode, Node>::value, "Should be a node");
+
+#ifdef DEBUG
+  for (Node* n : mList) {
+    MOZ_ASSERT(n->SubtreeRoot() == aNode.SubtreeRoot(),
+               "Should only insert nodes on the same subtree");
+  }
+#endif
+
+  if (mList.IsEmpty()) {
+    mList.AppendElement(&aNode);
+    return 0;
+  }
+
+  struct PositionComparator {
+    Node& mNode;
+    explicit PositionComparator(Node& aNode) : mNode(aNode) {}
+
+    int operator()(void* aNode) const {
+      auto* curNode = static_cast<Node*>(aNode);
+      MOZ_DIAGNOSTIC_ASSERT(curNode != &mNode,
+                            "Tried to insert a node already in the list");
+      if (nsContentUtils::PositionIsBefore(&mNode, curNode)) {
+        return -1;
+      }
+      return 1;
+    }
+  };
+
+  size_t idx;
+  BinarySearchIf(mList, 0, mList.Length(),
+                 PositionComparator(aNode), &idx);
+  mList.InsertElementAt(idx, &aNode);
+  return idx;
+}
+
+}  // namespace dom
+}  // namespace mozilla
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/base/UIDirectionManager.cpp
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 "mozilla/dom/UIDirectionManager.h"
+#include "mozilla/Preferences.h"
+#include "nsIWindowMediator.h"
+#include "nsDocShell.h"
+#include "mozilla/dom/Document.h"
+#include "mozilla/SimpleEnumerator.h"
+
+namespace mozilla {
+namespace dom {
+
+/* static */
+void OnPrefChange(const char* aPrefName, void*) {
+  // Iterate over all of the windows and notify them of the direction change.
+  nsCOMPtr<nsIWindowMediator> windowMediator =
+      do_GetService(NS_WINDOWMEDIATOR_CONTRACTID);
+  NS_ENSURE_TRUE_VOID(windowMediator);
+
+  nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
+  windowMediator->GetEnumerator(nullptr, getter_AddRefs(windowEnumerator));
+  NS_ENSURE_TRUE_VOID(windowEnumerator);
+
+  for (auto& elements : SimpleEnumerator<nsISupports>(windowEnumerator)) {
+    nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryInterface(elements);
+    if (window->Closed()) {
+      continue;
+    }
+
+    nsCOMPtr<nsIDocShell> rootDocShell = window->GetDocShell();
+    nsCOMPtr<nsISimpleEnumerator> docShellEnumerator;
+    rootDocShell->GetDocShellEnumerator(nsIDocShell::typeAll,
+                                        nsIDocShell::ENUMERATE_FORWARDS,
+                                        getter_AddRefs(docShellEnumerator));
+    NS_ENSURE_TRUE_VOID(docShellEnumerator);
+    for (auto& docShell : SimpleEnumerator<nsIDocShell>(docShellEnumerator)) {
+      if (nsCOMPtr<nsPIDOMWindowOuter> win = do_GetInterface(docShell)) {
+        if (dom::Document* doc = win->GetExtantDoc()) {
+          doc->ResetDocumentDirection();
+        }
+      }
+    }
+  }
+}
+
+/* static */
+void UIDirectionManager::Initialize() {
+  DebugOnly<nsresult> rv =
+      Preferences::RegisterCallback(OnPrefChange, "intl.uidirection");
+  MOZ_ASSERT(NS_SUCCEEDED(rv),
+             "Failed to observe \"intl.uidirection\"");
+}
+
+/* static */
+void UIDirectionManager::Shutdown() {
+  Preferences::UnregisterCallback(OnPrefChange, "intl.uidirection");
+}
+
+}  // namespace dom
+}  // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/base/UIDirectionManager.h
@@ -0,0 +1,22 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#ifndef mozilla_dom_UIDirectionManager_h
+#define mozilla_dom_UIDirectionManager_h
+
+namespace mozilla {
+namespace dom {
+
+class UIDirectionManager final {
+ public:
+  static void Initialize();
+  static void Shutdown();
+};
+
+}  // namespace dom
+}  // namespace mozilla
+
+#endif
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -231,17 +231,20 @@ EXPORTS.mozilla.dom += [
     'SubtleCrypto.h',
     'SyncMessageSender.h',
     'TabGroup.h',
     'Text.h',
     'Timeout.h',
     'TimeoutHandler.h',
     'TimeoutManager.h',
     'TreeIterator.h',
+    'TreeOrderedArray.h',
+    'TreeOrderedArrayInlines.h',
     'TreeWalker.h',
+    'UIDirectionManager.h',
     'VisualViewport.h',
     'WebKitCSSMatrix.h',
     'WindowOrientationObserver.h',
     'WindowProxyHolder.h',
 ]
 
 if CONFIG['FUZZING']:
     EXPORTS.mozilla.dom += [
@@ -396,16 +399,17 @@ UNIFIED_SOURCES += [
     'TextInputProcessor.cpp',
     'ThirdPartyUtil.cpp',
     'Timeout.cpp',
     'TimeoutBudgetManager.cpp',
     'TimeoutExecutor.cpp',
     'TimeoutHandler.cpp',
     'TimeoutManager.cpp',
     'TreeWalker.cpp',
+    'UIDirectionManager.cpp',
     'VisualViewport.cpp',
     'WebKitCSSMatrix.cpp',
     'WindowDestroyedEvent.cpp',
     'WindowNamedPropertiesHandler.cpp',
     'WindowOrientationObserver.cpp',
     'XPathGenerator.cpp',
 ]
 
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -25,16 +25,17 @@
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsDocShellLoadState.h"
 #include "nsIBaseWindow.h"
 #include "nsIBrowser.h"
 #include "nsContentUtils.h"
 #include "nsIXPConnect.h"
 #include "nsUnicharUtils.h"
+#include "nsIPresShellInlines.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIScrollable.h"
 #include "nsFrameLoader.h"
 #include "nsFrameLoaderOwner.h"
 #include "nsIFrame.h"
 #include "nsIScrollableFrame.h"
 #include "nsSubDocumentFrame.h"
@@ -72,16 +73,17 @@
 #include "ContentParent.h"
 #include "TabParent.h"
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/BasePrincipal.h"
 #include "mozilla/GuardObjects.h"
 #include "mozilla/HTMLEditor.h"
 #include "mozilla/NullPrincipal.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/PresShell.h"
 #include "mozilla/Unused.h"
 #include "mozilla/dom/ChromeMessageSender.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/FrameLoaderBinding.h"
 #include "mozilla/dom/MozFrameLoaderOwnerBinding.h"
 #include "mozilla/gfx/CrossProcessPaint.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
 #include "mozilla/layout/RenderFrame.h"
@@ -958,18 +960,18 @@ void nsFrameLoader::ForceLayoutIfNecessa
   nsPresContext* presContext = frame->PresContext();
   if (!presContext) {
     return;
   }
 
   // Only force the layout flush if the frameloader hasn't ever been
   // run through layout.
   if (frame->GetStateBits() & NS_FRAME_FIRST_REFLOW) {
-    if (nsCOMPtr<nsIPresShell> shell = presContext->GetPresShell()) {
-      shell->FlushPendingNotifications(FlushType::Layout);
+    if (RefPtr<PresShell> presShell = presContext->GetPresShell()) {
+      presShell->FlushPendingNotifications(FlushType::Layout);
     }
   }
 }
 
 nsresult nsFrameLoader::SwapWithOtherRemoteLoader(
     nsFrameLoader* aOther, nsFrameLoaderOwner* aThisOwner,
     nsFrameLoaderOwner* aOtherOwner) {
   MOZ_ASSERT(NS_IsMainThread());
--- a/dom/base/nsGlobalWindowCommands.cpp
+++ b/dom/base/nsGlobalWindowCommands.cpp
@@ -10,18 +10,18 @@
 #include "nsIInterfaceRequestor.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsCommandParams.h"
 #include "nsCRT.h"
 #include "nsString.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Preferences.h"
 
-#include "nsIControllerCommandTable.h"
-#include "nsICommandParams.h"
+#include "nsControllerCommandTable.h"
+#include "nsCommandParams.h"
 
 #include "nsPIDOMWindow.h"
 #include "nsIPresShell.h"
 #include "nsIDocShell.h"
 #include "nsISelectionController.h"
 #include "nsIWebNavigation.h"
 #include "nsIContentViewerEdit.h"
 #include "nsIContentViewer.h"
@@ -1018,38 +1018,38 @@ nsLookUpDictionaryCommand::DoCommandPara
 
   RegisterWindowCommands
 
 ----------------------------------------------------------------------------*/
 
 #define NS_REGISTER_ONE_COMMAND(_cmdClass, _cmdName)            \
   {                                                             \
     _cmdClass *theCmd = new _cmdClass();                        \
-    rv = inCommandTable->RegisterCommand(                       \
+    rv = aCommandTable->RegisterCommand(                        \
         _cmdName, static_cast<nsIControllerCommand *>(theCmd)); \
   }
 
 #define NS_REGISTER_FIRST_COMMAND(_cmdClass, _cmdName) \
   {                                                    \
     _cmdClass *theCmd = new _cmdClass();               \
-    rv = inCommandTable->RegisterCommand(              \
+    rv = aCommandTable->RegisterCommand(               \
         _cmdName, static_cast<nsIControllerCommand *>(theCmd));
 
 #define NS_REGISTER_NEXT_COMMAND(_cmdClass, _cmdName) \
-  rv = inCommandTable->RegisterCommand(               \
+  rv = aCommandTable->RegisterCommand(                \
       _cmdName, static_cast<nsIControllerCommand *>(theCmd));
 
 #define NS_REGISTER_LAST_COMMAND(_cmdClass, _cmdName)         \
-  rv = inCommandTable->RegisterCommand(                       \
+  rv = aCommandTable->RegisterCommand(                        \
       _cmdName, static_cast<nsIControllerCommand *>(theCmd)); \
   }
 
 // static
 nsresult nsWindowCommandRegistration::RegisterWindowCommands(
-    nsIControllerCommandTable *inCommandTable) {
+    nsControllerCommandTable *aCommandTable) {
   nsresult rv;
 
   // XXX rework the macros to use a loop is possible, reducing code size
 
   // this set of commands is affected by the 'browse with caret' setting
   NS_REGISTER_FIRST_COMMAND(nsSelectMoveScrollCommand, sScrollTopString);
   NS_REGISTER_NEXT_COMMAND(nsSelectMoveScrollCommand, sScrollBottomString);
   NS_REGISTER_NEXT_COMMAND(nsSelectMoveScrollCommand, sScrollPageUpString);
--- a/dom/base/nsGlobalWindowCommands.h
+++ b/dom/base/nsGlobalWindowCommands.h
@@ -10,21 +10,22 @@
 #include "nscore.h"
 
 namespace mozilla {
 namespace layers {
 struct KeyboardScrollAction;
 }  // namespace layers
 }  // namespace mozilla
 
-class nsIControllerCommandTable;
+class nsControllerCommandTable;
 
 class nsWindowCommandRegistration {
  public:
-  static nsresult RegisterWindowCommands(nsIControllerCommandTable* ccm);
+  static nsresult RegisterWindowCommands(
+      nsControllerCommandTable* aCommandTable);
 };
 
 class nsGlobalWindowCommands {
  public:
   typedef mozilla::layers::KeyboardScrollAction KeyboardScrollAction;
 
   /**
    * Search through nsGlobalWindowCommands to find the keyboard scrolling action
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -139,17 +139,16 @@
 #include "nsIWindowMediator.h"  // For window.find()
 #include "nsDOMCID.h"
 #include "nsDOMWindowUtils.h"
 #include "nsIWindowWatcher.h"
 #include "nsPIWindowWatcher.h"
 #include "nsIContentViewer.h"
 #include "nsIScriptError.h"
 #include "nsIControllers.h"
-#include "nsIControllerContext.h"
 #include "nsGlobalWindowCommands.h"
 #include "nsQueryObject.h"
 #include "nsContentUtils.h"
 #include "nsCSSProps.h"
 #include "nsIURIFixup.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventStateManager.h"
 #include "nsIObserverService.h"
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -38,30 +38,30 @@
 #include "mozilla/dom/Timeout.h"
 #include "mozilla/dom/TimeoutHandler.h"
 #include "mozilla/dom/TimeoutManager.h"
 #include "mozilla/dom/WindowProxyHolder.h"
 #include "mozilla/IntegerPrintfMacros.h"
 #if defined(MOZ_WIDGET_ANDROID)
 #  include "mozilla/dom/WindowOrientationObserver.h"
 #endif
+#include "nsBaseCommandController.h"
 #include "nsError.h"
 #include "nsISizeOfEventTarget.h"
 #include "nsDOMJSUtils.h"
 #include "nsArrayUtils.h"
 #include "nsDOMWindowList.h"
 #include "mozilla/dom/WakeLock.h"
 #include "mozilla/dom/power/PowerManagerService.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIPermissionManager.h"
 #include "nsIScriptContext.h"
 #include "nsIScriptTimeoutHandler.h"
 #include "nsITimeoutHandler.h"
-#include "nsIController.h"
 #include "nsISlowScriptDebug.h"
 #include "nsWindowMemoryReporter.h"
 #include "nsWindowSizes.h"
 #include "WindowNamedPropertiesHandler.h"
 #include "nsFrameSelection.h"
 #include "nsNetUtil.h"
 #include "nsVariant.h"
 #include "nsPrintfCString.h"
@@ -93,16 +93,17 @@
 #include "mozilla/dom/ToJSValue.h"
 #include "nsJSPrincipals.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Components.h"
 #include "mozilla/Debug.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/MouseEvents.h"
+#include "mozilla/PresShell.h"
 #include "mozilla/ProcessHangMonitor.h"
 #include "mozilla/StaticPrefs.h"
 #include "mozilla/ThrottledEventQueue.h"
 #include "AudioChannelService.h"
 #include "nsAboutProtocolUtils.h"
 #include "nsCharTraits.h"  // NS_IS_HIGH/LOW_SURROGATE
 #include "PostMessageEvent.h"
 #include "mozilla/dom/DocGroup.h"
@@ -118,17 +119,16 @@
 #include "nsIContent.h"
 #include "nsIDocShell.h"
 #include "mozilla/dom/Document.h"
 #include "Crypto.h"
 #include "nsDOMString.h"
 #include "nsIEmbeddingSiteWindow.h"
 #include "nsThreadUtils.h"
 #include "nsILoadContext.h"
-#include "nsIPresShell.h"
 #include "nsIScrollableFrame.h"
 #include "nsView.h"
 #include "nsViewManager.h"
 #include "nsISelectionController.h"
 #include "nsIPrompt.h"
 #include "nsIPromptService.h"
 #include "nsIPromptFactory.h"
 #include "nsIAddonPolicyService.h"
@@ -140,17 +140,16 @@
 #include "nsComputedDOMStyle.h"
 #include "nsDOMCID.h"
 #include "nsDOMWindowUtils.h"
 #include "nsIWindowWatcher.h"
 #include "nsPIWindowWatcher.h"
 #include "nsIContentViewer.h"
 #include "nsIScriptError.h"
 #include "nsIControllers.h"
-#include "nsIControllerContext.h"
 #include "nsGlobalWindowCommands.h"
 #include "nsQueryObject.h"
 #include "nsContentUtils.h"
 #include "nsCSSProps.h"
 #include "nsIURIFixup.h"
 #include "nsIURIMutator.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventStateManager.h"
@@ -3190,32 +3189,25 @@ nsIControllers* nsGlobalWindowOuter::Get
   if (!mControllers) {
     mControllers = new nsXULControllers();
     if (!mControllers) {
       aError.Throw(NS_ERROR_FAILURE);
       return nullptr;
     }
 
     // Add in the default controller
-    nsCOMPtr<nsIController> controller =
+    RefPtr<nsBaseCommandController> commandController =
         nsBaseCommandController::CreateWindowController();
-    if (!controller) {
+    if (!commandController) {
       aError.Throw(NS_ERROR_FAILURE);
       return nullptr;
     }
 
-    mControllers->InsertControllerAt(0, controller);
-    nsCOMPtr<nsIControllerContext> controllerContext =
-        do_QueryInterface(controller);
-    if (!controllerContext) {
-      aError.Throw(NS_ERROR_FAILURE);
-      return nullptr;
-    }
-
-    controllerContext->SetCommandContext(static_cast<nsIDOMWindow*>(this));
+    mControllers->InsertControllerAt(0, commandController);
+    commandController->SetCommandContext(static_cast<nsIDOMWindow*>(this));
   }
 
   return mControllers;
 }
 
 nsresult nsGlobalWindowOuter::GetControllers(nsIControllers** aResult) {
   FORWARD_TO_INNER(GetControllers, (aResult), NS_ERROR_UNEXPECTED);
 }
@@ -6288,27 +6280,28 @@ void nsGlobalWindowOuter::EnterModalStat
     return;
   }
 
   // If there is an active ESM in this window, clear it. Otherwise, this can
   // cause a problem if a modal state is entered during a mouseup event.
   EventStateManager* activeESM = static_cast<EventStateManager*>(
       EventStateManager::GetActiveEventStateManager());
   if (activeESM && activeESM->GetPresContext()) {
-    nsIPresShell* activeShell = activeESM->GetPresContext()->GetPresShell();
-    if (activeShell && (nsContentUtils::ContentIsCrossDocDescendantOf(
-                            activeShell->GetDocument(), mDoc) ||
-                        nsContentUtils::ContentIsCrossDocDescendantOf(
-                            mDoc, activeShell->GetDocument()))) {
+    PresShell* activePresShell = activeESM->GetPresContext()->GetPresShell();
+    if (activePresShell && (nsContentUtils::ContentIsCrossDocDescendantOf(
+                                activePresShell->GetDocument(), mDoc) ||
+                            nsContentUtils::ContentIsCrossDocDescendantOf(
+                                mDoc, activePresShell->GetDocument()))) {
       EventStateManager::ClearGlobalActiveContent(activeESM);
 
       nsIPresShell::SetCapturingContent(nullptr, 0);
 
-      if (activeShell) {
-        RefPtr<nsFrameSelection> frameSelection = activeShell->FrameSelection();
+      if (activePresShell) {
+        RefPtr<nsFrameSelection> frameSelection =
+            activePresShell->FrameSelection();
         frameSelection->SetDragState(false);
       }
     }
   }
 
   // If there are any drag and drop operations in flight, try to end them.
   nsCOMPtr<nsIDragService> ds =
       do_GetService("@mozilla.org/widget/dragservice;1");
--- a/dom/base/nsImageLoadingContent.cpp
+++ b/dom/base/nsImageLoadingContent.cpp
@@ -24,18 +24,16 @@
 #include "imgIContainer.h"
 #include "imgLoader.h"
 #include "imgRequestProxy.h"
 #include "nsThreadUtils.h"
 #include "nsNetUtil.h"
 #include "nsImageFrame.h"
 #include "nsSVGImageFrame.h"
 
-#include "nsIPresShell.h"
-
 #include "nsIChannel.h"
 #include "nsIStreamListener.h"
 
 #include "nsIFrame.h"
 
 #include "nsContentUtils.h"
 #include "nsLayoutUtils.h"
 #include "nsIContentPolicy.h"
@@ -48,16 +46,17 @@
 #include "mozilla/AutoRestore.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/ImageTracker.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/net/UrlClassifierFeatureFactory.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/PresShell.h"
 
 #ifdef LoadImage
 // Undefine LoadImage to prevent naming conflict with Windows.
 #  undef LoadImage
 #endif
 
 using namespace mozilla;
 using namespace mozilla::dom;
@@ -313,17 +312,17 @@ void nsImageLoadingContent::OnUnlockedDr
     return;
   }
 
   nsPresContext* presContext = frame->PresContext();
   if (!presContext) {
     return;
   }
 
-  nsIPresShell* presShell = presContext->PresShell();
+  PresShell* presShell = presContext->GetPresShell();
   if (!presShell) {
     return;
   }
 
   presShell->EnsureFrameInApproximatelyVisibleList(frame);
 }
 
 nsresult nsImageLoadingContent::OnImageIsAnimated(imgIRequest* aRequest) {
@@ -860,17 +859,17 @@ nsImageLoadingContent::FrameDestroyed(ns
   if (mPendingRequest) {
     nsLayoutUtils::DeregisterImageRequest(presContext, mPendingRequest,
                                           &mPendingRequestRegistered);
   }
 
   UntrackImage(mCurrentRequest);
   UntrackImage(mPendingRequest);
 
-  nsIPresShell* presShell = presContext ? presContext->GetPresShell() : nullptr;
+  PresShell* presShell = presContext ? presContext->GetPresShell() : nullptr;
   if (presShell) {
     presShell->RemoveFrameFromApproximatelyVisibleList(aFrame);
   }
 }
 
 /* static */
 nsContentPolicyType nsImageLoadingContent::PolicyTypeForLoad(
     ImageLoadType aImageLoadType) {
--- a/dom/base/test/chrome/test_bug682305.html
+++ b/dom/base/test/chrome/test_bug682305.html
@@ -108,17 +108,17 @@ CustomProtocol.prototype = {
     return false;
   },
   newURI: function newURI(spec, charset, baseURI) {
     return Cc["@mozilla.org/network/simple-uri-mutator;1"]
              .createInstance(Ci.nsIURIMutator)
              .setSpec(spec)
              .finalize();
   },
-  newChannel: function newChannel2(URI, loadInfo) {
+  newChannel: function newChannel(URI, loadInfo) {
     return new CustomChannel(URI, loadInfo);
   },
   QueryInterface: ChromeUtils.generateQI([Ci.nsISupportsWeakReference, Ci.nsIProtocolHandler]),
 };
 
 var gFactory = {
   register() {
     var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -677,16 +677,17 @@ skip-if = (toolkit == 'android') # Andro
 [test_gsp-standards.html]
 [test_history_document_open.html]
 [test_history_state_null.html]
 [test_html_colors_quirks.html]
 [test_html_colors_standards.html]
 [test_htmlcopyencoder.html]
 [test_htmlcopyencoder.xhtml]
 [test_iframe_event_listener_leaks.html]
+skip-if = (processor == 'aarch64' && os == 'win') # aarch64 due to 1530895
 [test_iframe_referrer.html]
 [test_iframe_referrer_changing.html]
 [test_iframe_referrer_invalid.html]
 [test_Image_constructor.html]
 [test_img_referrer.html]
 skip-if = (verify && debug && (os == 'linux'))
 [test_innersize_scrollport.html]
 skip-if = (verify && (os == 'win' || os == 'mac'))
--- a/dom/base/test/test_bug218236.html
+++ b/dom/base/test/test_bug218236.html
@@ -29,17 +29,17 @@ var url_connection_error = url_200.repla
 
 // List of tests: name of the test, URL to be requested, expected sequence
 // of events and optionally a function to be called from readystatechange handler.
 // Numbers in the list of events are values of XMLHttpRequest.readyState
 // when readystatechange event is triggered.
 var tests = [
   ["200 OK",                            url_200,                [1, 2, 3, 4, "load"], null],
   ["404 Not Found",                     url_404,                [1, 2, 3, 4, "load"], null],
-  ["connection error",                  url_connection_error,   [1, 2, 4, "error"],   null],
+  ["connection error",                  url_connection_error,   [1, 4, "error"],      null],
   ["abort() call on readyState = 1",    url_200,                [1, 4],               null, doAbort1],
   ["abort() call on readyState = 2",    url_200,                [1, 2, 4],            doAbort2],
 ];
 
 var testName = null;
 var currentState = 0;
 var currentSequence = null;
 var expectedSequence = null;
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -10,21 +10,22 @@
 
 #include "nsAutoPtr.h"
 #include "nsIServiceManager.h"
 #include "nsMathUtils.h"
 #include "SVGImageContext.h"
 
 #include "nsContentUtils.h"
 
+#include "mozilla/PresShell.h"
 #include "mozilla/dom/Document.h"
 #include "mozilla/dom/HTMLCanvasElement.h"
 #include "SVGObserverUtils.h"
 #include "nsPresContext.h"
-#include "nsIPresShell.h"
+#include "nsIPresShellInlines.h"
 
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIFrame.h"
 #include "nsError.h"
 
 #include "nsCSSPseudoElements.h"
 #include "nsComputedDOMStyle.h"
 
@@ -4731,19 +4732,20 @@ void CanvasRenderingContext2D::DrawWindo
       return;
     }
 
     thebes = gfxContext::CreateOrNull(drawDT);
     MOZ_ASSERT(thebes);  // alrady checked the draw target above
     thebes->SetMatrix(Matrix::Scaling(matrix._11, matrix._22));
   }
 
-  nsCOMPtr<nsIPresShell> shell = presContext->PresShell();
-
-  Unused << shell->RenderDocument(r, renderDocFlags, backgroundColor, thebes);
+  RefPtr<PresShell> presShell = presContext->PresShell();
+
+  Unused << presShell->RenderDocument(r, renderDocFlags, backgroundColor,
+                                      thebes);
   // If this canvas was contained in the drawn window, the pre-transaction
   // callback may have returned its DT. If so, we must reacquire it here.
   EnsureTarget(discardContent ? &drawRect : nullptr);
 
   if (drawDT) {
     RefPtr<SourceSurface> snapshot = drawDT->Snapshot();
     if (NS_WARN_IF(!snapshot)) {
       aError.Throw(NS_ERROR_FAILURE);
--- a/dom/commandhandler/moz.build
+++ b/dom/commandhandler/moz.build
@@ -15,17 +15,16 @@ EXPORTS += [
 ]
 
 XPIDL_SOURCES += [
     'nsICommandManager.idl',
     'nsICommandParams.idl',
     'nsIControllerCommand.idl',
     'nsIControllerCommandTable.idl',
     'nsIControllerContext.idl',
-    'nsPICommandUpdater.idl',
 ]
 
 XPIDL_MODULE = 'commandhandler'
 
 UNIFIED_SOURCES += [
     'nsBaseCommandController.cpp',
     'nsCommandManager.cpp',
     'nsCommandParams.cpp',
--- a/dom/commandhandler/nsBaseCommandController.cpp
+++ b/dom/commandhandler/nsBaseCommandController.cpp
@@ -16,33 +16,23 @@ NS_IMPL_RELEASE(nsBaseCommandController)
 NS_INTERFACE_MAP_BEGIN(nsBaseCommandController)
   NS_INTERFACE_MAP_ENTRY(nsIController)
   NS_INTERFACE_MAP_ENTRY(nsICommandController)
   NS_INTERFACE_MAP_ENTRY(nsIControllerContext)
   NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIControllerContext)
 NS_INTERFACE_MAP_END
 
-nsBaseCommandController::nsBaseCommandController()
-    : mCommandContextRawPtr(nullptr) {}
+nsBaseCommandController::nsBaseCommandController(
+    nsControllerCommandTable* aControllerCommandTable)
+    : mCommandContextRawPtr(nullptr), mCommandTable(aControllerCommandTable) {}
 
 nsBaseCommandController::~nsBaseCommandController() {}
 
 NS_IMETHODIMP
-nsBaseCommandController::Init(nsIControllerCommandTable* aCommandTable) {
-  if (aCommandTable) {
-    mCommandTable = aCommandTable;
-  } else {
-    mCommandTable = new nsControllerCommandTable();
-  }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 nsBaseCommandController::SetCommandContext(nsISupports* aCommandContext) {
   mCommandContextWeakPtr = nullptr;
   mCommandContextRawPtr = nullptr;
 
   if (aCommandContext) {
     nsCOMPtr<nsISupportsWeakReference> weak =
         do_QueryInterface(aCommandContext);
     if (weak) {
@@ -62,17 +52,20 @@ nsBaseCommandController::GetInterface(co
   NS_ENSURE_ARG_POINTER(aResult);
 
   if (NS_SUCCEEDED(QueryInterface(aIID, aResult))) {
     return NS_OK;
   }
 
   if (aIID.Equals(NS_GET_IID(nsIControllerCommandTable))) {
     if (mCommandTable) {
-      return mCommandTable->QueryInterface(aIID, aResult);
+      *aResult =
+          do_AddRef(static_cast<nsIControllerCommandTable*>(mCommandTable))
+              .take();
+      return NS_OK;
     }
     return NS_ERROR_NOT_INITIALIZED;
   }
 
   return NS_NOINTERFACE;
 }
 
 /* =======================================================================
@@ -113,31 +106,31 @@ NS_IMETHODIMP
 nsBaseCommandController::DoCommand(const char* aCommand) {
   NS_ENSURE_ARG_POINTER(aCommand);
   NS_ENSURE_STATE(mCommandTable);
 
   nsCOMPtr<nsISupports> context = mCommandContextRawPtr;
   if (!context) {
     context = do_QueryReferent(mCommandContextWeakPtr);
   }
-  nsCOMPtr<nsIControllerCommandTable> commandTable(mCommandTable);
+  RefPtr<nsControllerCommandTable> commandTable(mCommandTable);
   return commandTable->DoCommand(aCommand, context);
 }
 
 NS_IMETHODIMP
 nsBaseCommandController::DoCommandWithParams(const char* aCommand,
                                              nsICommandParams* aParams) {
   NS_ENSURE_ARG_POINTER(aCommand);
   NS_ENSURE_STATE(mCommandTable);
 
   nsCOMPtr<nsISupports> context = mCommandContextRawPtr;
   if (!context) {
     context = do_QueryReferent(mCommandContextWeakPtr);
   }
-  nsCOMPtr<nsIControllerCommandTable> commandTable(mCommandTable);
+  RefPtr<nsControllerCommandTable> commandTable(mCommandTable);
   return commandTable->DoCommandParams(aCommand, aParams, context);
 }
 
 NS_IMETHODIMP
 nsBaseCommandController::GetCommandStateWithParams(const char* aCommand,
                                                    nsICommandParams* aParams) {
   NS_ENSURE_ARG_POINTER(aCommand);
   NS_ENSURE_STATE(mCommandTable);
@@ -159,60 +152,54 @@ nsBaseCommandController::OnEvent(const c
 
 NS_IMETHODIMP
 nsBaseCommandController::GetSupportedCommands(uint32_t* aCount,
                                               char*** aCommands) {
   NS_ENSURE_STATE(mCommandTable);
   return mCommandTable->GetSupportedCommands(aCount, aCommands);
 }
 
-typedef already_AddRefed<nsIControllerCommandTable> (*CommandTableCreatorFn)();
+typedef already_AddRefed<nsControllerCommandTable> (*CommandTableCreatorFn)();
 
-static already_AddRefed<nsIController>
+static already_AddRefed<nsBaseCommandController>
 CreateControllerWithSingletonCommandTable(CommandTableCreatorFn aCreatorFn) {
-  nsCOMPtr<nsIController> controller = new nsBaseCommandController();
-
-  nsCOMPtr<nsIControllerCommandTable> commandTable = aCreatorFn();
-  if (!commandTable) return nullptr;
+  RefPtr<nsControllerCommandTable> commandTable = aCreatorFn();
+  if (!commandTable) {
+    return nullptr;
+  }
 
   // this is a singleton; make it immutable
   commandTable->MakeImmutable();
 
-  nsresult rv;
-  nsCOMPtr<nsIControllerContext> controllerContext =
-      do_QueryInterface(controller, &rv);
-  if (NS_FAILED(rv)) return nullptr;
-
-  rv = controllerContext->Init(commandTable);
-  if (NS_FAILED(rv)) return nullptr;
-
-  return controller.forget();
+  RefPtr<nsBaseCommandController> commandController =
+      new nsBaseCommandController(commandTable);
+  return commandController.forget();
 }
 
-already_AddRefed<nsIController>
+already_AddRefed<nsBaseCommandController>
 nsBaseCommandController::CreateWindowController() {
   return CreateControllerWithSingletonCommandTable(
       nsControllerCommandTable::CreateWindowCommandTable);
 }
 
-already_AddRefed<nsIController>
+already_AddRefed<nsBaseCommandController>
 nsBaseCommandController::CreateEditorController() {
   return CreateControllerWithSingletonCommandTable(
       nsControllerCommandTable::CreateEditorCommandTable);
 }
 
-already_AddRefed<nsIController>
+already_AddRefed<nsBaseCommandController>
 nsBaseCommandController::CreateEditingController() {
   return CreateControllerWithSingletonCommandTable(
       nsControllerCommandTable::CreateEditingCommandTable);
 }
 
-already_AddRefed<nsIController>
+already_AddRefed<nsBaseCommandController>
 nsBaseCommandController::CreateHTMLEditorController() {
   return CreateControllerWithSingletonCommandTable(
       nsControllerCommandTable::CreateHTMLEditorCommandTable);
 }
 
-already_AddRefed<nsIController>
+already_AddRefed<nsBaseCommandController>
 nsBaseCommandController::CreateHTMLEditorDocStateController() {
   return CreateControllerWithSingletonCommandTable(
       nsControllerCommandTable::CreateHTMLEditorDocStateCommandTable);
 }
--- a/dom/commandhandler/nsBaseCommandController.h
+++ b/dom/commandhandler/nsBaseCommandController.h
@@ -4,45 +4,54 @@
  * 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/. */
 
 #ifndef nsBaseCommandController_h__
 #define nsBaseCommandController_h__
 
 #include "nsIController.h"
 #include "nsIControllerContext.h"
-#include "nsIControllerCommandTable.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIWeakReferenceUtils.h"
+#include "nsControllerCommandTable.h"
 
 // The base editor controller is used for both text widgets, and all other text
 // and html editing
-class nsBaseCommandController : public nsIController,
-                                public nsIControllerContext,
-                                public nsIInterfaceRequestor,
-                                public nsICommandController {
+class nsBaseCommandController final : public nsIController,
+                                      public nsIControllerContext,
+                                      public nsIInterfaceRequestor,
+                                      public nsICommandController {
  public:
-  nsBaseCommandController();
+  /**
+   * The default constructor initializes the instance with new
+   * nsControllerCommandTable.  The other constructor does it with
+   * the given aControllerCommandTable.
+   */
+  nsBaseCommandController() = delete;
+  explicit nsBaseCommandController(
+      nsControllerCommandTable* aControllerCommandTable =
+          new nsControllerCommandTable());
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSICONTROLLER
   NS_DECL_NSICOMMANDCONTROLLER
   NS_DECL_NSICONTROLLERCONTEXT
   NS_DECL_NSIINTERFACEREQUESTOR
 
-  static already_AddRefed<nsIController> CreateWindowController();
-  static already_AddRefed<nsIController> CreateEditorController();
-  static already_AddRefed<nsIController> CreateEditingController();
-  static already_AddRefed<nsIController> CreateHTMLEditorController();
-  static already_AddRefed<nsIController> CreateHTMLEditorDocStateController();
+  static already_AddRefed<nsBaseCommandController> CreateWindowController();
+  static already_AddRefed<nsBaseCommandController> CreateEditorController();
+  static already_AddRefed<nsBaseCommandController> CreateEditingController();
+  static already_AddRefed<nsBaseCommandController> CreateHTMLEditorController();
+  static already_AddRefed<nsBaseCommandController>
+  CreateHTMLEditorDocStateController();
 
  protected:
   virtual ~nsBaseCommandController();
 
  private:
   nsWeakPtr mCommandContextWeakPtr;
   nsISupports* mCommandContextRawPtr;
 
   // Our reference to the command manager
-  nsCOMPtr<nsIControllerCommandTable> mCommandTable;
+  RefPtr<nsControllerCommandTable> mCommandTable;
 };
 
 #endif /* nsBaseCommandController_h_ */
--- a/dom/commandhandler/nsCommandManager.cpp
+++ b/dom/commandhandler/nsCommandManager.cpp
@@ -20,17 +20,20 @@
 #include "nsPIDOMWindow.h"
 #include "nsPIWindowRoot.h"
 #include "nsIFocusManager.h"
 
 #include "nsCOMArray.h"
 
 #include "nsCommandManager.h"
 
-nsCommandManager::nsCommandManager() : mWindow(nullptr) {}
+nsCommandManager::nsCommandManager(mozIDOMWindowProxy* aWindow)
+    : mWindow(aWindow) {
+  MOZ_DIAGNOSTIC_ASSERT(mWindow);
+}
 
 nsCommandManager::~nsCommandManager() {}
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsCommandManager)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsCommandManager)
   tmp->mObserversTable.Clear();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
@@ -44,31 +47,21 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
   }
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsCommandManager)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsCommandManager)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsCommandManager)
   NS_INTERFACE_MAP_ENTRY(nsICommandManager)
-  NS_INTERFACE_MAP_ENTRY(nsPICommandUpdater)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsICommandManager)
 NS_INTERFACE_MAP_END
 
-NS_IMETHODIMP
-nsCommandManager::Init(mozIDOMWindowProxy* aWindow) {
-  NS_ENSURE_ARG_POINTER(aWindow);
-
-  mWindow = aWindow;  // weak ptr
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsCommandManager::CommandStatusChanged(const char* aCommandName) {
+nsresult nsCommandManager::CommandStatusChanged(const char* aCommandName) {
   ObserverList* commandObservers;
   mObserversTable.Get(aCommandName, &commandObservers);
 
   if (commandObservers) {
     // XXX Should we worry about observers removing themselves from Observe()?
     int32_t i, numItems = commandObservers->Length();
     for (i = 0; i < numItems; ++i) {
       nsCOMPtr<nsIObserver> observer = commandObservers->ElementAt(i);
@@ -139,27 +132,36 @@ nsCommandManager::IsCommandSupported(con
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCommandManager::IsCommandEnabled(const char* aCommandName,
                                    mozIDOMWindowProxy* aTargetWindow,
                                    bool* aResult) {
   NS_ENSURE_ARG_POINTER(aResult);
-
-  bool commandEnabled = false;
+  if (!aCommandName) {
+    *aResult = false;
+    return NS_OK;
+  }
+  *aResult = IsCommandEnabled(nsDependentCString(aCommandName), aTargetWindow);
+  return NS_OK;
+}
 
+bool nsCommandManager::IsCommandEnabled(const nsCString& aCommandName,
+                                        mozIDOMWindowProxy* aTargetWindow) {
   nsCOMPtr<nsIController> controller;
-  GetControllerForCommand(aCommandName, aTargetWindow,
+  GetControllerForCommand(aCommandName.get(), aTargetWindow,
                           getter_AddRefs(controller));
-  if (controller) {
-    controller->IsCommandEnabled(aCommandName, &commandEnabled);
+  if (!controller) {
+    return false;
   }
-  *aResult = commandEnabled;
-  return NS_OK;
+
+  bool enabled = false;
+  controller->IsCommandEnabled(aCommandName.get(), &enabled);
+  return enabled;
 }
 
 NS_IMETHODIMP
 nsCommandManager::GetCommandState(const char* aCommandName,
                                   mozIDOMWindowProxy* aTargetWindow,
                                   nsICommandParams* aCommandParams) {
   nsCOMPtr<nsIController> controller;
   nsAutoString tValue;
--- a/dom/commandhandler/nsCommandManager.h
+++ b/dom/commandhandler/nsCommandManager.h
@@ -7,43 +7,63 @@
 #ifndef nsCommandManager_h__
 #define nsCommandManager_h__
 
 #include "nsString.h"
 #include "nsClassHashtable.h"
 #include "nsWeakReference.h"
 
 #include "nsICommandManager.h"
-#include "nsPICommandUpdater.h"
 #include "nsCycleCollectionParticipant.h"
 
 class nsIController;
 template <class E>
 class nsCOMArray;
 
-class nsCommandManager : public nsICommandManager,
-                         public nsPICommandUpdater,
-                         public nsSupportsWeakReference {
+class nsCommandManager final : public nsICommandManager,
+                               public nsSupportsWeakReference {
  public:
   typedef nsTArray<nsCOMPtr<nsIObserver> > ObserverList;
 
-  nsCommandManager();
+  nsCommandManager() = delete;
+
+  /**
+   * @param aWindow     An window which is what this command manager lives on.
+   */
+  explicit nsCommandManager(mozIDOMWindowProxy* aWindow);
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsCommandManager, nsICommandManager)
 
   NS_DECL_NSICOMMANDMANAGER
-  NS_DECL_NSPICOMMANDUPDATER
+
+  /**
+   * Notify the command manager that the status of a command changed. It may
+   * have changed from enabled to disabled, or vice versa, or become toggled
+   * etc.
+   */
+  nsresult CommandStatusChanged(const char* aCommandName);
+
+  bool IsCommandEnabled(const nsCString& aCommandName,
+                        mozIDOMWindowProxy* aTargetWindow);
 
  protected:
   virtual ~nsCommandManager();
 
   nsresult GetControllerForCommand(const char* aCommand,
                                    mozIDOMWindowProxy* aDirectedToThisWindow,
                                    nsIController** aResult);
 
  protected:
   nsClassHashtable<nsCharPtrHashKey, ObserverList> mObserversTable;
 
   mozIDOMWindowProxy* mWindow;  // weak ptr. The window should always outlive us
 };
 
+nsCommandManager* nsICommandManager::AsCommandManager() {
+  return static_cast<nsCommandManager*>(this);
+}
+
+const nsCommandManager* nsICommandManager::AsCommandManager() const {
+  return static_cast<const nsCommandManager*>(this);
+}
+
 #endif  // nsCommandManager_h__
--- a/dom/commandhandler/nsControllerCommandTable.cpp
+++ b/dom/commandhandler/nsControllerCommandTable.cpp
@@ -6,18 +6,16 @@
 
 #include "nsString.h"
 #include "nsIControllerCommand.h"
 #include "nsControllerCommandTable.h"
 #include "nsGlobalWindowCommands.h"
 #include "mozilla/EditorController.h"
 #include "mozilla/HTMLEditorController.h"
 
-nsresult NS_NewControllerCommandTable(nsIControllerCommandTable** aResult);
-
 // this value is used to size the hash table. Just a sensible upper bound
 #define NUM_COMMANDS_LENGTH 32
 
 nsControllerCommandTable::nsControllerCommandTable()
     : mCommandsTable(NUM_COMMANDS_LENGTH), mMutable(true) {}
 
 nsControllerCommandTable::~nsControllerCommandTable() {}
 
@@ -181,70 +179,58 @@ nsControllerCommandTable::GetSupportedCo
 
   for (auto iter = mCommandsTable.Iter(); !iter.Done(); iter.Next()) {
     *commands = ToNewCString(iter.Key());
     commands++;
   }
   return NS_OK;
 }
 
-typedef nsresult (*CommandTableRegistrar)(nsIControllerCommandTable*);
+typedef nsresult (*CommandTableRegistrar)(nsControllerCommandTable*);
 
-static already_AddRefed<nsIControllerCommandTable>
+static already_AddRefed<nsControllerCommandTable>
 CreateCommandTableWithCommands(CommandTableRegistrar aRegistrar) {
-  nsCOMPtr<nsIControllerCommandTable> commandTable =
+  RefPtr<nsControllerCommandTable> commandTable =
       new nsControllerCommandTable();
 
   nsresult rv = aRegistrar(commandTable);
   if (NS_FAILED(rv)) return nullptr;
 
   // we don't know here whether we're being created as an instance,
   // or a service, so we can't become immutable
 
   return commandTable.forget();
 }
 
 // static
-already_AddRefed<nsIControllerCommandTable>
+already_AddRefed<nsControllerCommandTable>
 nsControllerCommandTable::CreateEditorCommandTable() {
   return CreateCommandTableWithCommands(
       EditorController::RegisterEditorCommands);
 }
 
 // static
-already_AddRefed<nsIControllerCommandTable>
+already_AddRefed<nsControllerCommandTable>
 nsControllerCommandTable::CreateEditingCommandTable() {
   return CreateCommandTableWithCommands(
       EditorController::RegisterEditingCommands);
 }
 
 // static
-already_AddRefed<nsIControllerCommandTable>
+already_AddRefed<nsControllerCommandTable>
 nsControllerCommandTable::CreateHTMLEditorCommandTable() {
   return CreateCommandTableWithCommands(
       HTMLEditorController::RegisterHTMLEditorCommands);
 }
 
 // static
-already_AddRefed<nsIControllerCommandTable>
+already_AddRefed<nsControllerCommandTable>
 nsControllerCommandTable::CreateHTMLEditorDocStateCommandTable() {
   return CreateCommandTableWithCommands(
       HTMLEditorController::RegisterEditorDocStateCommands);
 }
 
 // static
-already_AddRefed<nsIControllerCommandTable>
+already_AddRefed<nsControllerCommandTable>
 nsControllerCommandTable::CreateWindowCommandTable() {
   return CreateCommandTableWithCommands(
       nsWindowCommandRegistration::RegisterWindowCommands);
 }
-
-nsresult NS_NewControllerCommandTable(nsIControllerCommandTable** aResult) {
-  MOZ_ASSERT(aResult != nullptr, "null ptr");
-  if (!aResult) {
-    return NS_ERROR_NULL_POINTER;
-  }
-
-  nsControllerCommandTable* newCommandTable = new nsControllerCommandTable();
-  NS_ADDREF(newCommandTable);
-  *aResult = newCommandTable;
-  return NS_OK;
-}
--- a/dom/commandhandler/nsControllerCommandTable.h
+++ b/dom/commandhandler/nsControllerCommandTable.h
@@ -16,28 +16,37 @@ class nsIControllerCommand;
 class nsControllerCommandTable final : public nsIControllerCommandTable,
                                        public nsSupportsWeakReference {
  public:
   nsControllerCommandTable();
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSICONTROLLERCOMMANDTABLE
 
-  static already_AddRefed<nsIControllerCommandTable> CreateEditorCommandTable();
-  static already_AddRefed<nsIControllerCommandTable>
-  CreateEditingCommandTable();
-  static already_AddRefed<nsIControllerCommandTable>
+  static already_AddRefed<nsControllerCommandTable> CreateEditorCommandTable();
+  static already_AddRefed<nsControllerCommandTable> CreateEditingCommandTable();
+  static already_AddRefed<nsControllerCommandTable>
   CreateHTMLEditorCommandTable();
-  static already_AddRefed<nsIControllerCommandTable>
+  static already_AddRefed<nsControllerCommandTable>
   CreateHTMLEditorDocStateCommandTable();
-  static already_AddRefed<nsIControllerCommandTable> CreateWindowCommandTable();
+  static already_AddRefed<nsControllerCommandTable> CreateWindowCommandTable();
 
  protected:
   virtual ~nsControllerCommandTable();
 
   // Hash table of nsIControllerCommands, keyed by command name.
   nsInterfaceHashtable<nsCStringHashKey, nsIControllerCommand> mCommandsTable;
 
   // Are we mutable?
   bool mMutable;
 };
 
+nsControllerCommandTable*
+nsIControllerCommandTable::AsControllerCommandTable() {
+  return static_cast<nsControllerCommandTable*>(this);
+}
+
+const nsControllerCommandTable*
+nsIControllerCommandTable::AsControllerCommandTable() const {
+  return static_cast<const nsControllerCommandTable*>(this);
+}
+
 #endif  // nsControllerCommandTable_h_
--- a/dom/commandhandler/nsICommandManager.idl
+++ b/dom/commandhandler/nsICommandManager.idl
@@ -4,28 +4,32 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 #include "nsIObserver.idl"
 #include "nsICommandParams.idl"
 
 interface mozIDOMWindowProxy;
 
+%{C++
+class nsCommandManager;
+%}
+
 /*
  * nsICommandManager is an interface used to executing user-level commands,
  * and getting the state of available commands.
  *
  * Commands are identified by strings, which are documented elsewhere.
  * In addition, the list of required and optional parameters for
  * each command, that are passed in via the nsICommandParams, are
  * also documented elsewhere. (Where? Need a good location for this).
  */
- 
- 
-[scriptable, uuid(bb5a1730-d83b-4fa2-831b-35b9d5842e84)]
+
+
+[scriptable, builtinclass, uuid(bb5a1730-d83b-4fa2-831b-35b9d5842e84)]
 interface nsICommandManager : nsISupports
 {
   /*
    * Register an observer on the specified command. The observer's Observe
    * method will get called when the state (enabled/disbaled, or toggled etc)
    * of the command changes.
    *
    * You can register the same observer on multiple commmands by calling this
@@ -73,31 +77,39 @@ interface nsICommandManager : nsISupport
    * aTargetWindow is the source of command controller 
    *      (null means use focus controller)
    * On output: aCommandParams: values set by the caller filled in with
    * state from the command.
    */
   void        getCommandState(in string aCommandName,
                               in mozIDOMWindowProxy aTargetWindow,
                   /* inout */ in nsICommandParams aCommandParams);
-    
+
   /*
    * Execute the specified command.
    * The command will be executed in aTargetWindow if it is specified.
    * If aTargetWindow is null, it will go to the focused window.
    *
    * param: aCommandParams, a list of name-value pairs of command parameters,
    * may be null for parameter-less commands.
    *
    */
   [can_run_script]
   void        doCommand(in string aCommandName,
                         in nsICommandParams aCommandParams,
                         in mozIDOMWindowProxy aTargetWindow);
 
+%{C++
+  /**
+   * In order to avoid circular dependency issues, these methods are defined
+   * in nsCommandManager.h.  Consumers need to #include that header.
+   */
+  inline nsCommandManager* AsCommandManager();
+  inline const nsCommandManager* AsCommandManager() const;
+%}
 };
 
 
 /*
 
 Arguments to observers "Observe" method are as follows:
 
   void Observe(   in nsISupports aSubject,          // The nsICommandManager calling this Observer
--- a/dom/commandhandler/nsIControllerCommandTable.idl
+++ b/dom/commandhandler/nsIControllerCommandTable.idl
@@ -1,29 +1,33 @@
 /* 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 "nsISupports.idl"
 #include "nsIControllerCommand.idl"
 #include "nsICommandParams.idl"
 
+%{C++
+class nsControllerCommandTable;
+%}
+
 /**
  * nsIControllerCommandTable
  * 
  * An interface via which a controller can maintain a series of commands,
  * and efficiently dispatch commands to their respective handlers.
  *
  * Controllers that use an nsIControllerCommandTable should support
  * nsIInterfaceRequestor, and be able to return an interface to their
  * controller command table via getInterface().
  * 
  */
 
-[scriptable, uuid(c847f90e-b8f3-49db-a4df-8867831f2800)]
+[scriptable, builtinclass, uuid(c847f90e-b8f3-49db-a4df-8867831f2800)]
 interface nsIControllerCommandTable : nsISupports
 {
   /**
    * Make this command table immutable, so that commands cannot
    * be registered or unregistered. Some command tables are made
    * mutable after command registration so that they can be 
    * used as singletons.
    */
@@ -82,10 +86,19 @@ interface nsIControllerCommandTable : ns
 
   [can_run_script]
 	void    doCommandParams(in string aCommandName, in nsICommandParams aParam, in nsISupports aCommandRefCon);
 
 	void    getCommandState(in string aCommandName, in nsICommandParams aParam, in nsISupports aCommandRefCon);
 
   void getSupportedCommands(out unsigned long count,
                             [array, size_is(count), retval] out string commands);
+
+%{C++
+  /**
+   * In order to avoid circular dependency issues, these methods are defined
+   * in nsControllerCommandTable.h.  Consumers need to #include that header.
+   */
+  inline nsControllerCommandTable* AsControllerCommandTable();
+  inline const nsControllerCommandTable* AsControllerCommandTable() const;
+%}
 };
 
--- a/dom/commandhandler/nsIControllerContext.idl
+++ b/dom/commandhandler/nsIControllerContext.idl
@@ -1,35 +1,22 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 "nsISupports.idl"
 #include "nsIControllerCommandTable.idl"
 
-[scriptable, uuid(47B82B60-A36F-4167-8072-6F421151ED50)]
+[scriptable, builtinclass, uuid(47B82B60-A36F-4167-8072-6F421151ED50)]
 interface nsIControllerContext : nsISupports
 {
-
   /**
-   *  Init the controller, optionally passing a controller
-   *  command table.
-   *
-   * @param aCommandTable  a command table, used internally
-   *                       by this controller. May be null, in
-   *                       which case the controller will create
-   *                       a new, empty table.
-   */
-  void init(in nsIControllerCommandTable aCommandTable);
-
-  /** 
    *  Set a context on this controller, which is passed
    *  to commands to give them some context when they execute.
    *
    * @param aCommandContext  the context passed to commands.
    *                        Note that this is *not* addreffed by the
    *                        controller, and so needs to outlive it,
    *                        or be nulled out.
    */
   void setCommandContext(in nsISupports aCommandContext);
-  
 };
deleted file mode 100644
--- a/dom/commandhandler/nsPICommandUpdater.idl
+++ /dev/null
@@ -1,39 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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 "nsISupports.idl"
-
-interface mozIDOMWindowProxy;
-
-/*
-	The nsPICommandUpdater interface is used by modules that implement
-	commands, to tell the command manager that commands need updating.
-	This is a private interface; embedders should not use it.
-	
-	Command-implementing modules should get one of these by a QI
-	from an nsICommandManager.
-*/
-
-[scriptable, uuid(35e474ae-8016-4c34-9644-edc11f8b0ce1)]
-interface nsPICommandUpdater : nsISupports
-{
-
-  /*
-   * Init the command updater, passing an nsIDOMWindow which 
-   * is the window that the command updater lives on.
-   * 
-   */
-  void    init(in mozIDOMWindowProxy aWindow);
-   
-  /*
-   * Notify the command manager that the status of a command
-   * changed. It may have changed from enabled to disabled,
-   * or vice versa, or become toggled etc.
-   */
-	void		commandStatusChanged(in string aCommandName);
-	
-};
-
-
--- a/dom/crypto/WebCryptoTask.cpp
+++ b/dom/crypto/WebCryptoTask.cpp
@@ -80,16 +80,17 @@ enum TelemetryAlgorithm {
   TA_SHA_384 = 17,
   TA_SHA_512 = 18,
   // Later additions
   TA_AES_KW = 19,
   TA_ECDH = 20,
   TA_PBKDF2 = 21,
   TA_ECDSA = 22,
   TA_HKDF = 23,
+  TA_DH = 24,
 };
 
 // Convenience functions for extracting / converting information
 
 // OOM-safe CryptoBuffer initialization, suitable for constructors
 #define ATTEMPT_BUFFER_INIT(dst, src)    \
   if (!dst.Assign(src)) {                \
     mEarlyRv = NS_ERROR_DOM_UNKNOWN_ERR; \
@@ -2878,16 +2879,17 @@ class DeriveDhBitsTask : public ReturnAr
       : mPrivKey(aKey.GetPrivateKey()) {
     mEarlyRv = GetKeyLengthForAlgorithm(aCx, aTargetAlgorithm, mLength);
     if (NS_SUCCEEDED(mEarlyRv)) {
       Init(aCx, aAlgorithm, aKey);
     }
   }
 
   void Init(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey) {
+    Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_DH);
     CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_DH);
 
     // Check that we have a private key.
     if (!mPrivKey) {
       mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
       return;
     }
 
--- a/dom/crypto/moz.build
+++ b/dom/crypto/moz.build
@@ -29,8 +29,9 @@ include('/ipc/chromium/chromium-config.m
 FINAL_LIBRARY = 'xul'
 
 LOCAL_INCLUDES += [
     '/security/manager/ssl',
     '/xpcom/build',
 ]
 
 MOCHITEST_MANIFESTS += ['test/mochitest.ini']
+BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini']
new file mode 100644
--- /dev/null
+++ b/dom/crypto/test/browser/browser.ini
@@ -0,0 +1,8 @@
+[DEFAULT]
+support-files =
+  head.js
+  ../test-vectors.js
+  ../util.js
+
+[browser_WebCrypto_telemetry.js]
+disabled = for telemetry intermittents, see bug 1539578
new file mode 100644
--- /dev/null
+++ b/dom/crypto/test/browser/browser_WebCrypto_telemetry.js
@@ -0,0 +1,41 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+/* global tv */
+
+const WEBCRYPTO_ALG_PROBE = "WEBCRYPTO_ALG";
+
+ChromeUtils.defineModuleGetter(this, "TelemetryTestUtils",
+  "resource://testing-common/TelemetryTestUtils.jsm");
+
+add_task(async function ecdh_key() {
+  let hist = TelemetryTestUtils.getAndClearHistogram(WEBCRYPTO_ALG_PROBE);
+
+  let alg = { name: "ECDH", namedCurve: "P-256" };
+
+  let x = await crypto.subtle.generateKey(alg, false, ["deriveKey", "deriveBits"]);
+  let data = await crypto.subtle.deriveBits({ name: "ECDH", public: x.publicKey }, x.privateKey, 128);
+  is(data.byteLength, 128 / 8, "Should be 16 bytes derived");
+
+  TelemetryTestUtils.assertHistogram(hist, 20, 1);
+});
+
+
+add_task(async function dh_key() {
+  let hist = TelemetryTestUtils.getAndClearHistogram(WEBCRYPTO_ALG_PROBE);
+
+  let alg = {
+    name: "DH",
+    prime: tv.dh.prime,
+    generator: new Uint8Array([0x02]),
+  };
+
+  let x = await crypto.subtle.generateKey(alg, false, ["deriveKey", "deriveBits"]);
+  let data = await crypto.subtle.deriveBits({ name: "DH", public: x.publicKey }, x.privateKey, 128);
+  is(data.byteLength, 128 / 8, "Should be 16 bytes derived");
+
+  TelemetryTestUtils.assertHistogram(hist, 24, 1);
+});
new file mode 100644
--- /dev/null
+++ b/dom/crypto/test/browser/head.js
@@ -0,0 +1,18 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+let exports = this;
+
+const scripts = [
+  "util.js",
+  "test-vectors.js",
+];
+
+for (let script of scripts) {
+  Services.scriptloader.loadSubScript(
+    `chrome://mochitests/content/browser/dom/crypto/test/browser/${script}`,
+    this);
+}
--- a/dom/events/Event.cpp
+++ b/dom/events/Event.cpp
@@ -12,31 +12,31 @@
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/InternalMutationEvent.h"
 #include "mozilla/dom/Performance.h"
 #include "mozilla/dom/WorkerPrivate.h"
 #include "mozilla/MiscEvents.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/PresShell.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/TouchEvents.h"
 #include "mozilla/dom/Document.h"
 #include "mozilla/dom/DocumentInlines.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/ShadowRoot.h"
 #include "nsContentUtils.h"
 #include "nsCOMPtr.h"
 #include "nsDeviceContext.h"
 #include "nsError.h"
 #include "nsGlobalWindow.h"
 #include "nsIFrame.h"
 #include "nsIContent.h"
 #include "nsIContentInlines.h"
-#include "nsIPresShell.h"
 #include "nsIScrollableFrame.h"
 #include "nsJSEnvironment.h"
 #include "nsLayoutUtils.h"
 #include "nsPIWindowRoot.h"
 #include "nsRFPService.h"
 
 namespace mozilla {
 namespace dom {
@@ -528,18 +528,19 @@ CSSIntPoint Event::GetScreenCoords(nsPre
   if (!aPresContext || !(guiEvent && guiEvent->mWidget)) {
     return CSSIntPoint(aPoint.x, aPoint.y);
   }
 
   nsPoint pt = LayoutDevicePixel::ToAppUnits(
       aPoint,
       aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom());
 
-  if (nsIPresShell* ps = aPresContext->GetPresShell()) {
-    pt = pt.RemoveResolution(nsLayoutUtils::GetCurrentAPZResolutionScale(ps));
+  if (PresShell* presShell = aPresContext->GetPresShell()) {
+    pt = pt.RemoveResolution(
+        nsLayoutUtils::GetCurrentAPZResolutionScale(presShell));
   }
 
   pt += LayoutDevicePixel::ToAppUnits(
       guiEvent->mWidget->WidgetToScreenOffset(),
       aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom());
 
   return CSSPixel::FromAppUnitsRounded(pt);
 }
@@ -549,18 +550,19 @@ CSSIntPoint Event::GetPageCoords(nsPresC
                                  WidgetEvent* aEvent,
                                  LayoutDeviceIntPoint aPoint,
                                  CSSIntPoint aDefaultPoint) {
   CSSIntPoint pagePoint =
       Event::GetClientCoords(aPresContext, aEvent, aPoint, aDefaultPoint);
 
   // If there is some scrolling, add scroll info to client point.
   if (aPresContext && aPresContext->GetPresShell()) {
-    nsIPresShell* shell = aPresContext->GetPresShell();
-    nsIScrollableFrame* scrollframe = shell->GetRootScrollFrameAsScrollable();
+    PresShell* presShell = aPresContext->PresShell();
+    nsIScrollableFrame* scrollframe =
+        presShell->GetRootScrollFrameAsScrollable();
     if (scrollframe) {
       pagePoint +=
           CSSIntPoint::FromAppUnitsRounded(scrollframe->GetScrollPosition());
     }
   }
 
   return pagePoint;
 }
@@ -607,26 +609,26 @@ CSSIntPoint Event::GetOffsetCoords(nsPre
                                    CSSIntPoint aDefaultPoint) {
   if (!aEvent->mTarget) {
     return GetPageCoords(aPresContext, aEvent, aPoint, aDefaultPoint);
   }
   nsCOMPtr<nsIContent> content = do_QueryInterface(aEvent->mTarget);
   if (!content || !aPresContext) {
     return CSSIntPoint(0, 0);
   }
-  nsCOMPtr<nsIPresShell> shell = aPresContext->GetPresShell();
-  if (!shell) {
+  RefPtr<PresShell> presShell = aPresContext->GetPresShell();
+  if (!presShell) {
     return CSSIntPoint(0, 0);
   }
-  shell->FlushPendingNotifications(FlushType::Layout);
+  presShell->FlushPendingNotifications(FlushType::Layout);
   nsIFrame* frame = content->GetPrimaryFrame();
   if (!frame) {
     return CSSIntPoint(0, 0);
   }
-  nsIFrame* rootFrame = shell->GetRootFrame();
+  nsIFrame* rootFrame = presShell->GetRootFrame();
   if (!rootFrame) {
     return CSSIntPoint(0, 0);
   }
   CSSIntPoint clientCoords =
       GetClientCoords(aPresContext, aEvent, aPoint, aDefaultPoint);
   nsPoint pt = CSSPixel::ToAppUnits(clientCoords);
   if (nsLayoutUtils::TransformPoint(rootFrame, frame, pt) ==
       nsLayoutUtils::TRANSFORM_SUCCEEDED) {
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -8,16 +8,17 @@
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/HTMLEditor.h"
 #include "mozilla/IMEStateManager.h"
 #include "mozilla/MiscEvents.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/MouseEvents.h"
+#include "mozilla/PresShell.h"
 #include "mozilla/ScrollTypes.h"
 #include "mozilla/TextComposition.h"
 #include "mozilla/TextEditor.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/TouchEvents.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/DragEvent.h"
 #include "mozilla/dom/Event.h"
@@ -42,17 +43,16 @@
 #include "nsIContent.h"
 #include "nsIContentInlines.h"
 #include "mozilla/dom/Document.h"
 #include "nsIFrame.h"
 #include "nsFrameLoaderOwner.h"
 #include "nsITextControlElement.h"
 #include "nsIWidget.h"
 #include "nsPresContext.h"
-#include "nsIPresShell.h"
 #include "nsGkAtoms.h"
 #include "nsIFormControl.h"
 #include "nsComboboxControlFrame.h"
 #include "nsIScrollableFrame.h"
 #include "nsIDOMXULControlElement.h"
 #include "nsNameSpaceManager.h"
 #include "nsIBaseWindow.h"
 #include "nsFrameSelection.h"
@@ -1649,20 +1649,21 @@ void EventStateManager::FillInEventFromG
   // different
   aEvent->mRefPoint =
       mGestureDownPoint - aEvent->mWidget->WidgetToScreenOffset();
   aEvent->mModifiers = mGestureModifiers;
   aEvent->buttons = mGestureDownButtons;
 }
 
 void EventStateManager::MaybeFirePointerCancel(WidgetInputEvent* aEvent) {
-  nsCOMPtr<nsIPresShell> shell = mPresContext->GetPresShell();
+  RefPtr<PresShell> presShell = mPresContext->GetPresShell();
   AutoWeakFrame targetFrame = mCurrentTarget;
 
-  if (!PointerEventHandler::IsPointerEventEnabled() || !shell || !targetFrame) {
+  if (!PointerEventHandler::IsPointerEventEnabled() || !presShell ||
+      !targetFrame) {
     return;
   }
 
   nsCOMPtr<nsIContent> content;
   targetFrame->GetContentForEvent(aEvent, getter_AddRefs(content));
   if (!content) {
     return;
   }
@@ -1670,26 +1671,26 @@ void EventStateManager::MaybeFirePointer
   nsEventStatus status = nsEventStatus_eIgnore;
 
   if (WidgetMouseEvent* aMouseEvent = aEvent->AsMouseEvent()) {
     WidgetPointerEvent event(*aMouseEvent);
     PointerEventHandler::InitPointerEventFromMouse(&event, aMouseEvent,
                                                    ePointerCancel);
 
     event.convertToPointer = false;
-    shell->HandleEventWithTarget(&event, targetFrame, content, &status);
+    presShell->HandleEventWithTarget(&event, targetFrame, content, &status);
   } else if (WidgetTouchEvent* aTouchEvent = aEvent->AsTouchEvent()) {
     WidgetPointerEvent event(aTouchEvent->IsTrusted(), ePointerCancel,
                              aTouchEvent->mWidget);
 
     PointerEventHandler::InitPointerEventFromTouch(
         &event, aTouchEvent, aTouchEvent->mTouches[0], true);
 
     event.convertToPointer = false;
-    shell->HandleEventWithTarget(&event, targetFrame, content, &status);
+    presShell->HandleEventWithTarget(&event, targetFrame, content, &status);
   } else {
     MOZ_ASSERT(false);
   }
 
   // HandleEventWithTarget clears out mCurrentTarget, which may be used in the
   // caller GenerateDragGesture. We have to restore mCurrentTarget.
   mCurrentTarget = targetFrame;
 }
@@ -3234,19 +3235,18 @@ nsresult EventStateManager::PostHandleEv
         // Make sure to dispatch the click even if there is no frame for
         // the current target element. This is required for Web compatibility.
         RefPtr<EventStateManager> esm =
             ESMFromContentOrThis(aOverrideClickTarget);
         ret =
             esm->PostHandleMouseUp(mouseUpEvent, aStatus, aOverrideClickTarget);
       }
 
-      nsIPresShell* shell = presContext->GetPresShell();
-      if (shell) {
-        RefPtr<nsFrameSelection> frameSelection = shell->FrameSelection();
+      if (PresShell* presShell = presContext->GetPresShell()) {
+        RefPtr<nsFrameSelection> frameSelection = presShell->FrameSelection();
         frameSelection->SetDragState(false);
       }
     } break;
     case eWheelOperationEnd: {
       MOZ_ASSERT(aEvent->IsTrusted());
       ScrollbarsForWheel::MayInactivate();
       WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent();
       nsIScrollableFrame* scrollTarget =
@@ -4896,17 +4896,17 @@ nsresult EventStateManager::InitAndDispa
 
 nsresult EventStateManager::PostHandleMouseUp(
     WidgetMouseEvent* aMouseUpEvent, nsEventStatus* aStatus,
     nsIContent* aOverrideClickTarget) {
   MOZ_ASSERT(aMouseUpEvent);
   MOZ_ASSERT(EventCausesClickEvents(*aMouseUpEvent));
   MOZ_ASSERT(aStatus);
 
-  nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell();
+  RefPtr<PresShell> presShell = mPresContext->GetPresShell();
   if (!presShell) {
     return NS_OK;
   }
 
   nsCOMPtr<nsIContent> clickTarget =
       do_QueryInterface(aMouseUpEvent->mClickTarget);
   NS_ENSURE_STATE(clickTarget);
 
@@ -5110,49 +5110,47 @@ nsresult EventStateManager::HandleMiddle
     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to paste");
   }
   *aStatus = nsEventStatus_eConsumeNoDefault;
 
   return NS_OK;
 }
 
 nsIFrame* EventStateManager::GetEventTarget() {
-  nsIPresShell* shell;
+  PresShell* presShell;
   if (mCurrentTarget || !mPresContext ||
-      !(shell = mPresContext->GetPresShell())) {
+      !(presShell = mPresContext->GetPresShell())) {
     return mCurrentTarget;
   }
 
   if (mCurrentTargetContent) {
     mCurrentTarget = mPresContext->GetPrimaryFrameFor(mCurrentTargetContent);
     if (mCurrentTarget) {
       return mCurrentTarget;
     }
   }
 
-  nsIFrame* frame = shell->GetCurrentEventFrame();
+  nsIFrame* frame = presShell->GetCurrentEventFrame();
   return (mCurrentTarget = frame);
 }
 
 already_AddRefed<nsIContent> EventStateManager::GetEventTargetContent(
     WidgetEvent* aEvent) {
   if (aEvent && (aEvent->mMessage == eFocus || aEvent->mMessage == eBlur)) {
     nsCOMPtr<nsIContent> content = GetFocusedContent();
     return content.forget();
   }
 
   if (mCurrentTargetContent) {
     nsCOMPtr<nsIContent> content = mCurrentTargetContent;
     return content.forget();
   }
 
   nsCOMPtr<nsIContent> content;
-
-  nsIPresShell* presShell = mPresContext->GetPresShell();
-  if (presShell) {
+  if (PresShell* presShell = mPresContext->GetPresShell()) {
     content = presShell->GetEventTargetContent(aEvent);
   }
 
   // Some events here may set mCurrentTarget but not set the corresponding
   // event target in the PresShell.
   if (!content && mCurrentTarget) {
     mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(content));
   }
@@ -5485,20 +5483,19 @@ uint32_t EventStateManager::GetRegistere
   return accessKey.First();
 }
 
 void EventStateManager::EnsureDocument(nsPresContext* aPresContext) {
   if (!mDocument) mDocument = aPresContext->Document();
 }
 
 void EventStateManager::FlushPendingEvents(nsPresContext* aPresContext) {
-  MOZ_ASSERT(nullptr != aPresContext, "nullptr ptr");
-  nsIPresShell* shell = aPresContext->GetPresShell();
-  if (shell) {
-    shell->FlushPendingNotifications(FlushType::InterruptibleLayout);
+  MOZ_ASSERT(aPresContext, "nullptr ptr");
+  if (RefPtr<PresShell> presShell = aPresContext->GetPresShell()) {
+    presShell->FlushPendingNotifications(FlushType::InterruptibleLayout);
   }
 }
 
 nsIContent* EventStateManager::GetFocusedContent() {
   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
   EnsureDocument(mPresContext);
   if (!fm || !mDocument) return nullptr;
 
@@ -5644,18 +5641,18 @@ nsresult EventStateManager::DoContentCom
   }
   aEvent->mSucceeded = true;
   return NS_OK;
 }
 
 nsresult EventStateManager::DoContentCommandScrollEvent(
     WidgetContentCommandEvent* aEvent) {
   NS_ENSURE_TRUE(mPresContext, NS_ERROR_NOT_AVAILABLE);
-  nsIPresShell* ps = mPresContext->GetPresShell();
-  NS_ENSURE_TRUE(ps, NS_ERROR_NOT_AVAILABLE);
+  PresShell* presShell = mPresContext->GetPresShell();
+  NS_ENSURE_TRUE(presShell, NS_ERROR_NOT_AVAILABLE);
   NS_ENSURE_TRUE(aEvent->mScroll.mAmount != 0, NS_ERROR_INVALID_ARG);
 
   nsIScrollableFrame::ScrollUnit scrollUnit;
   switch (aEvent->mScroll.mUnit) {
     case WidgetContentCommandEvent::eCmdScrollUnit_Line:
       scrollUnit = nsIScrollableFrame::LINES;
       break;
     case WidgetContentCommandEvent::eCmdScrollUnit_Page:
@@ -5666,17 +5663,17 @@ nsresult EventStateManager::DoContentCom
       break;
     default:
       return NS_ERROR_INVALID_ARG;
   }
 
   aEvent->mSucceeded = true;
 
   nsIScrollableFrame* sf =
-      ps->GetScrollableFrameToScroll(nsIPresShell::eEither);
+      presShell->GetScrollableFrameToScroll(nsIPresShell::eEither);
   aEvent->mIsEnabled =
       sf ? (aEvent->mScroll.mIsHorizontal ? WheelHandlingUtils::CanScrollOn(
                                                 sf, aEvent->mScroll.mAmount, 0)
                                           : WheelHandlingUtils::CanScrollOn(
                                                 sf, 0, aEvent->mScroll.mAmount))
          : false;
 
   if (!aEvent->mIsEnabled || aEvent->mOnlyEnabledCheck) {
--- a/dom/events/IMEContentObserver.cpp
+++ b/dom/events/IMEContentObserver.cpp
@@ -8,28 +8,28 @@
 
 #include "ContentEventHandler.h"
 #include "IMEContentObserver.h"
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/AutoRestore.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/IMEStateManager.h"
 #include "mozilla/MouseEvents.h"
+#include "mozilla/PresShell.h"
 #include "mozilla/TextComposition.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/Selection.h"
 #include "nsContentUtils.h"
 #include "nsGkAtoms.h"
 #include "nsAtom.h"
 #include "nsIContent.h"
 #include "mozilla/dom/Document.h"
 #include "nsIFrame.h"
 #include "nsINode.h"
-#include "nsIPresShell.h"
 #include "nsISelectionController.h"
 #include "nsISupports.h"
 #include "nsIWeakReferenceUtils.h"
 #include "nsIWidget.h"
 #include "nsPresContext.h"
 #include "nsRange.h"
 #include "nsRefreshDriver.h"
 #include "WritingModes.h"
@@ -300,30 +300,30 @@ bool IMEContentObserver::InitWithEditor(
     return false;
   }
 
   mEditorBase = aEditorBase;
   if (NS_WARN_IF(!mEditorBase)) {
     return false;
   }
 
-  nsIPresShell* presShell = aPresContext->PresShell();
+  PresShell* presShell = aPresContext->GetPresShell();
 
   // get selection and root content
   nsCOMPtr<nsISelectionController> selCon;
   if (mEditableNode->IsContent()) {
     nsIFrame* frame = mEditableNode->AsContent()->GetPrimaryFrame();
     if (NS_WARN_IF(!frame)) {
       return false;
     }
 
     frame->GetSelectionController(aPresContext, getter_AddRefs(selCon));
   } else {
     // mEditableNode is a document
-    selCon = do_QueryInterface(presShell);
+    selCon = presShell;
   }
 
   if (NS_WARN_IF(!selCon)) {
     return false;
   }
 
   mSelection = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL);
   if (NS_WARN_IF(!mSelection)) {
@@ -1455,17 +1455,17 @@ void IMEContentObserver::PostComposition
   mNeedsToNotifyIMEOfCompositionEventHandled = true;
 }
 
 bool IMEContentObserver::IsReflowLocked() const {
   nsPresContext* presContext = GetPresContext();
   if (NS_WARN_IF(!presContext)) {
     return false;
   }
-  nsIPresShell* presShell = presContext->GetPresShell();
+  PresShell* presShell = presContext->GetPresShell();
   if (NS_WARN_IF(!presShell)) {
     return false;
   }
   // During reflow, we shouldn't notify IME because IME may query content
   // synchronously.  Then, it causes ContentEventHandler will try to flush
   // pending notifications during reflow.
   return presShell->IsReflowLocked();
 }
@@ -1808,19 +1808,25 @@ void IMEContentObserver::IMENotification
              "SendFocusSet(), retrying to send NOTIFY_IME_OF_FOCUS...",
              this));
     observer->PostFocusSetNotification();
     return;
   }
 
   observer->mIMEHasFocus = true;
   // Initialize selection cache with the first selection data.
+#ifdef XP_MACOSX
+  // We need to flush layout only on macOS because character coordinates are
+  // cached by cocoa with this call, but we don't have a way to update them
+  // after that.  Therefore, we need the latest layout information right now.
+  observer->UpdateSelectionCache(true);
+#else
   // We avoid flushing for focus in the general case.
   observer->UpdateSelectionCache(false);
-
+#endif  // #ifdef XP_MACOSX #else
   MOZ_LOG(sIMECOLog, LogLevel::Info,
           ("0x%p IMEContentObserver::IMENotificationSender::"
            "SendFocusSet(), sending NOTIFY_IME_OF_FOCUS...",
            this));
 
   MOZ_RELEASE_ASSERT(observer->mSendingNotification == NOTIFY_IME_OF_NOTHING);
   observer->mSendingNotification = NOTIFY_IME_OF_FOCUS;
   IMEStateManager::NotifyIME(IMENotification(NOTIFY_IME_OF_FOCUS),
--- a/dom/events/TextComposition.cpp
+++ b/dom/events/TextComposition.cpp
@@ -4,24 +4,24 @@
  * 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 "ContentEventHandler.h"
 #include "IMEContentObserver.h"
 #include "IMEStateManager.h"
 #include "nsContentUtils.h"
 #include "nsIContent.h"
-#include "nsIPresShell.h"
 #include "nsPresContext.h"
 #include "mozilla/AutoRestore.h"
 #include "mozilla/EditorBase.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/IMEStateManager.h"
 #include "mozilla/MiscEvents.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/PresShell.h"
 #include "mozilla/StaticPrefs.h"
 #include "mozilla/TextComposition.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/Unused.h"
 #include "mozilla/dom/TabParent.h"
 
 #ifdef XP_MACOSX
 // Some defiens will be conflict with OSX SDK
@@ -85,17 +85,17 @@ void TextComposition::Destroy() {
   mCompositionLengthInTextNode = UINT32_MAX;
   // TODO: If the editor is still alive and this is held by it, we should tell
   //       this being destroyed for cleaning up the stuff.
 }
 
 bool TextComposition::IsValidStateForComposition(nsIWidget* aWidget) const {
   return !Destroyed() && aWidget && !aWidget->Destroyed() &&
          mPresContext->GetPresShell() &&
-         !mPresContext->GetPresShell()->IsDestroying();
+         !mPresContext->PresShell()->IsDestroying();
 }
 
 bool TextComposition::MaybeDispatchCompositionUpdate(
     const WidgetCompositionEvent* aCompositionEvent) {
   MOZ_RELEASE_ASSERT(!mTabParent);
 
   if (!IsValidStateForComposition(aCompositionEvent->mWidget)) {
     return false;
--- a/dom/events/UIEvent.cpp
+++ b/dom/events/UIEvent.cpp
@@ -6,16 +6,17 @@
 
 #include "base/basictypes.h"
 #include "ipc/IPCMessageUtils.h"
 #include "mozilla/dom/UIEvent.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/ContentEvents.h"
 #include "mozilla/EventStateManager.h"
+#include "mozilla/PresShell.h"
 #include "mozilla/TextEvents.h"
 #include "nsCOMPtr.h"
 #include "nsContentUtils.h"
 #include "nsIContent.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIDocShell.h"
 #include "nsIDOMWindow.h"
 #include "nsIFrame.h"
@@ -160,31 +161,31 @@ int32_t UIEvent::PageY() const {
                               mClientPoint)
       .y;
 }
 
 already_AddRefed<nsINode> UIEvent::GetRangeParent() {
   if (NS_WARN_IF(!mPresContext)) {
     return nullptr;
   }
-  nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell();
+  RefPtr<PresShell> presShell = mPresContext->GetPresShell();
   if (NS_WARN_IF(!presShell)) {
     return nullptr;
   }
   nsCOMPtr<nsIContent> container;
   nsLayoutUtils::GetContainerAndOffsetAtEvent(
       presShell, mEvent, getter_AddRefs(container), nullptr);
   return container.forget();
 }
 
 int32_t UIEvent::RangeOffset() const {
   if (NS_WARN_IF(!mPresContext)) {
     return 0;
   }
-  nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell();
+  RefPtr<PresShell> presShell = mPresContext->GetPresShell();
   if (NS_WARN_IF(!presShell)) {
     return 0;
   }
   int32_t offset = 0;
   nsLayoutUtils::GetContainerAndOffsetAtEvent(presShell, mEvent, nullptr,
                                               &offset);
   return offset;
 }
--- a/dom/html/HTMLButtonElement.cpp
+++ b/dom/html/HTMLButtonElement.cpp
@@ -6,29 +6,29 @@
 
 #include "mozilla/dom/HTMLButtonElement.h"
 
 #include "HTMLFormSubmissionConstants.h"
 #include "mozilla/dom/HTMLButtonElementBinding.h"
 #include "mozilla/dom/HTMLFormSubmission.h"
 #include "nsAttrValueInlines.h"
 #include "nsGkAtoms.h"
-#include "nsIPresShell.h"
 #include "nsStyleConsts.h"
 #include "nsPresContext.h"
 #include "nsIFormControl.h"
 #include "nsIURL.h"
 #include "nsIFrame.h"
 #include "nsIFormControlFrame.h"
 #include "mozilla/dom/Document.h"
 #include "mozilla/ContentEvents.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/MouseEvents.h"
+#include "mozilla/PresShell.h"
 #include "mozilla/TextEvents.h"
 #include "nsUnicharUtils.h"
 #include "nsLayoutUtils.h"
 #include "mozilla/PresState.h"
 #include "nsError.h"
 #include "nsFocusManager.h"
 #include "mozilla/dom/HTMLFormElement.h"
 #include "mozAutoDocUpdate.h"
@@ -199,21 +199,20 @@ nsresult HTMLButtonElement::PostHandleEv
   if (aVisitor.mEventStatus != nsEventStatus_eConsumeNoDefault) {
     WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
     if (mouseEvent && mouseEvent->IsLeftClickEvent()) {
       // DOMActive event should be trusted since the activation is actually
       // occurred even if the cause is an untrusted click event.
       InternalUIEvent actEvent(true, eLegacyDOMActivate, mouseEvent);
       actEvent.mDetail = 1;
 
-      nsCOMPtr<nsIPresShell> shell = aVisitor.mPresContext->GetPresShell();
-      if (shell) {
+      if (RefPtr<PresShell> presShell = aVisitor.mPresContext->GetPresShell()) {
         nsEventStatus status = nsEventStatus_eIgnore;
         mInInternalActivate = true;
-        shell->HandleDOMEventWithTarget(this, &actEvent, &status);
+        presShell->HandleDOMEventWithTarget(this, &actEvent, &status);
         mInInternalActivate = false;
 
         // If activate is cancelled, we must do the same as when click is
         // cancelled (revert the checkbox to its original value).
         if (status == nsEventStatus_eConsumeNoDefault) {
           aVisitor.mEventStatus = status;
         }
       }
@@ -253,18 +252,17 @@ nsresult HTMLButtonElement::PostHandleEv
     if (aVisitor.mItemFlags & NS_OUTER_ACTIVATE_EVENT) {
       if (mForm &&
           (mType == NS_FORM_BUTTON_SUBMIT || mType == NS_FORM_BUTTON_RESET)) {
         InternalFormEvent event(
             true, (mType == NS_FORM_BUTTON_RESET) ? eFormReset : eFormSubmit);
         event.mOriginator = this;
         nsEventStatus status = nsEventStatus_eIgnore;
 
-        nsCOMPtr<nsIPresShell> presShell =
-            aVisitor.mPresContext->GetPresShell();
+        RefPtr<PresShell> presShell = aVisitor.mPresContext->GetPresShell();
         // If |nsIPresShell::Destroy| has been called due to
         // handling the event, the pres context will return
         // a null pres shell.  See bug 125624.
         //
         // Using presShell to dispatch the event. It makes sure that
         // event is not handled if the window is being destroyed.
         if (presShell && (event.mMessage != eFormSubmit ||
                           mForm->SubmissionCanProceed(this))) {
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -11,44 +11,44 @@
 #include "mozilla/DebugOnly.h"
 #include "mozilla/dom/Date.h"
 #include "mozilla/dom/Directory.h"
 #include "mozilla/dom/DocumentOrShadowRoot.h"
 #include "mozilla/dom/HTMLFormSubmission.h"
 #include "mozilla/dom/FileSystemUtils.h"
 #include "mozilla/dom/GetFilesHelper.h"
 #include "mozilla/dom/WheelEventBinding.h"
+#include "mozilla/PresShell.h"
 #include "mozilla/StaticPrefs.h"
 #include "nsAttrValueInlines.h"
 #include "nsCRTGlue.h"
 #include "nsQueryObject.h"
 
 #include "nsITextControlElement.h"
 #include "nsIRadioVisitor.h"
 #include "InputType.h"
 
 #include "HTMLFormSubmissionConstants.h"
 #include "mozilla/Telemetry.h"
-#include "nsIControllers.h"
+#include "nsBaseCommandController.h"
 #include "nsIStringBundle.h"
 #include "nsFocusManager.h"
 #include "nsColorControlFrame.h"
 #include "nsNumberControlFrame.h"
 #include "nsPIDOMWindow.h"
 #include "nsRepeatService.h"
 #include "nsContentCID.h"
 #include "nsIComponentManager.h"
 #include "mozilla/dom/ProgressEvent.h"
 #include "nsGkAtoms.h"
 #include "nsStyleConsts.h"
 #include "nsPresContext.h"
 #include "nsMappedAttributes.h"
 #include "nsIFormControl.h"
 #include "mozilla/dom/Document.h"
-#include "nsIPresShell.h"
 #include "nsIFormControlFrame.h"
 #include "nsITextControlFrame.h"
 #include "nsIFrame.h"
 #include "nsRangeFrame.h"
 #include "nsIServiceManager.h"
 #include "nsError.h"
 #include "nsIEditor.h"
 #include "nsAttrValueOrString.h"
@@ -104,17 +104,16 @@
 
 #include "nsIIDNService.h"
 
 #include <limits>
 
 #include "nsIColorPicker.h"
 #include "nsIStringEnumerator.h"
 #include "HTMLSplitOnSpacesTokenizer.h"
-#include "nsIController.h"
 #include "nsIMIMEInfo.h"
 #include "nsFrameSelection.h"
 #include "nsBaseCommandController.h"
 #include "nsXULControllers.h"
 
 // input type=date
 #include "js/Date.h"
 
@@ -5443,32 +5442,32 @@ nsIControllers* HTMLInputElement::GetCon
   if (IsSingleLineTextControl(false)) {
     if (!mControllers) {
       mControllers = new nsXULControllers();
       if (!mControllers) {
         aRv.Throw(NS_ERROR_FAILURE);
         return nullptr;
       }
 
-      nsCOMPtr<nsIController> controller =
+      RefPtr<nsBaseCommandController> commandController =
           nsBaseCommandController::CreateEditorController();
-      if (!controller) {
+      if (!commandController) {
         aRv.Throw(NS_ERROR_FAILURE);
         return nullptr;
       }
 
-      mControllers->AppendController(controller);
-
-      controller = nsBaseCommandController::CreateEditingController();
-      if (!controller) {
+      mControllers->AppendController(commandController);
+
+      commandController = nsBaseCommandController::CreateEditingController();
+      if (!commandController) {
         aRv.Throw(NS_ERROR_FAILURE);
         return nullptr;
       }
 
-      mControllers->AppendController(controller);
+      mControllers->AppendController(commandController);
     }
   }
 
   return mControllers;
 }
 
 nsresult HTMLInputElement::GetControllers(nsIControllers** aResult) {
   NS_ENSURE_ARG_POINTER(aResult);
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -51,16 +51,17 @@
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/EMEUtils.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/NotNull.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/PresShell.h"
 #include "mozilla/Sprintf.h"
 #include "mozilla/StaticPrefs.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/dom/AudioTrack.h"
 #include "mozilla/dom/AudioTrackList.h"
 #include "mozilla/dom/BlobURLProtocolHandler.h"
 #include "mozilla/dom/ElementInlines.h"
 #include "mozilla/dom/HTMLAudioElement.h"
@@ -96,17 +97,16 @@
 #include "nsIClassOfService.h"
 #include "nsIContentPolicy.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsIDocShell.h"
 #include "mozilla/dom/Document.h"
 #include "nsIFrame.h"
 #include "nsIObserverService.h"
 #include "nsIPermissionManager.h"
-#include "nsIPresShell.h"
 #include "nsIRequest.h"
 #include "nsIScriptError.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsISupportsPrimitives.h"
 #include "nsIThreadInternal.h"
 #include "nsITimer.h"
 #include "nsIXPConnect.h"
 #include "nsJSUtils.h"
@@ -5913,17 +5913,17 @@ void HTMLMediaElement::NotifyDecoderPrin
 void HTMLMediaElement::Invalidate(bool aImageSizeChanged,
                                   Maybe<nsIntSize>& aNewIntrinsicSize,
                                   bool aForceInvalidate) {
   nsIFrame* frame = GetPrimaryFrame();
   if (aNewIntrinsicSize) {
     UpdateMediaSize(aNewIntrinsicSize.value());
     if (frame) {
       nsPresContext* presContext = frame->PresContext();
-      nsIPresShell* presShell = presContext->PresShell();
+      PresShell* presShell = presContext->PresShell();
       presShell->FrameNeedsReflow(frame, nsIPresShell::eStyleChange,
                                   NS_FRAME_IS_DIRTY);
     }
   }
 
   RefPtr<ImageContainer> imageContainer = GetImageContainer();
   bool asyncInvalidate =
       imageContainer && imageContainer->IsAsync() && !aForceInvalidate;
--- a/dom/html/HTMLTextAreaElement.cpp
+++ b/dom/html/HTMLTextAreaElement.cpp
@@ -11,16 +11,17 @@
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/HTMLFormSubmission.h"
 #include "mozilla/dom/HTMLTextAreaElementBinding.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/MappedDeclarations.h"
 #include "mozilla/MouseEvents.h"
 #include "nsAttrValueInlines.h"
+#include "nsBaseCommandController.h"
 #include "nsContentCID.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsError.h"
 #include "nsFocusManager.h"
 #include "nsIComponentManager.h"
 #include "nsIConstraintValidation.h"
 #include "nsIControllers.h"
 #include "mozilla/dom/Document.h"
@@ -34,17 +35,16 @@
 #include "nsLinebreakConverter.h"
 #include "nsMappedAttributes.h"
 #include "nsPIDOMWindow.h"
 #include "nsPresContext.h"
 #include "mozilla/PresState.h"
 #include "nsReadableUtils.h"
 #include "nsStyleConsts.h"
 #include "nsTextEditorState.h"
-#include "nsIController.h"
 #include "nsBaseCommandController.h"
 #include "nsXULControllers.h"
 
 #define NS_NO_CONTENT_DISPATCH (1 << 0)
 
 NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(TextArea)
 
 namespace mozilla {
@@ -553,32 +553,32 @@ bool HTMLTextAreaElement::IsDoneAddingCh
 nsIControllers* HTMLTextAreaElement::GetControllers(ErrorResult& aError) {
   if (!mControllers) {
     mControllers = new nsXULControllers();
     if (!mControllers) {
       aError.Throw(NS_ERROR_FAILURE);
       return nullptr;
     }
 
-    nsCOMPtr<nsIController> controller =
+    RefPtr<nsBaseCommandController> commandController =
         nsBaseCommandController::CreateEditorController();
-    if (!controller) {
+    if (!commandController) {
       aError.Throw(NS_ERROR_FAILURE);
       return nullptr;
     }
 
-    mControllers->AppendController(controller);
+    mControllers->AppendController(commandController);
 
-    controller = nsBaseCommandController::CreateEditingController();
-    if (!controller) {
+    commandController = nsBaseCommandController::CreateEditingController();
+    if (!commandController) {
       aError.Throw(NS_ERROR_FAILURE);
       return nullptr;
     }
 
-    mControllers->AppendController(controller);
+    mControllers->AppendController(commandController);
   }
 
   return mControllers;
 }
 
 nsresult HTMLTextAreaElement::GetControllers(nsIControllers** aResult) {
   NS_ENSURE_ARG_POINTER(aResult);
 
--- a/dom/html/nsGenericHTMLFrameElement.cpp
+++ b/dom/html/nsGenericHTMLFrameElement.cpp
@@ -5,25 +5,25 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsGenericHTMLFrameElement.h"
 
 #include "mozilla/dom/HTMLIFrameElement.h"
 #include "mozilla/dom/XULFrameElement.h"
 #include "mozilla/dom/WindowProxyHolder.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/PresShell.h"
 #include "mozilla/ErrorResult.h"
 #include "GeckoProfiler.h"
 #include "nsAttrValueInlines.h"
 #include "nsContentUtils.h"
 #include "nsIDocShell.h"
 #include "nsIFrame.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIPermissionManager.h"
-#include "nsIPresShell.h"
 #include "nsIScrollable.h"
 #include "nsPresContext.h"
 #include "nsServiceManagerUtils.h"
 #include "nsSubDocumentFrame.h"
 #include "nsAttrValueOrString.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
@@ -291,23 +291,23 @@ nsresult nsGenericHTMLFrameElement::Afte
               nsIScrollable::ScrollOrientation_X, &cur);
           int32_t val = MapScrollingAttribute(aValue);
           if (cur != val) {
             scrollable->SetDefaultScrollbarPreferences(
                 nsIScrollable::ScrollOrientation_X, val);
             scrollable->SetDefaultScrollbarPreferences(
                 nsIScrollable::ScrollOrientation_Y, val);
             RefPtr<nsPresContext> presContext = docshell->GetPresContext();
-            nsIPresShell* shell =
+            PresShell* presShell =
                 presContext ? presContext->GetPresShell() : nullptr;
             nsIFrame* rootScroll =
-                shell ? shell->GetRootScrollFrame() : nullptr;
+                presShell ? presShell->GetRootScrollFrame() : nullptr;
             if (rootScroll) {
-              shell->FrameNeedsReflow(rootScroll, nsIPresShell::eStyleChange,
-                                      NS_FRAME_IS_DIRTY);
+              presShell->FrameNeedsReflow(
+                  rootScroll, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
             }
           }
         }
       }
     } else if (aName == nsGkAtoms::mozbrowser) {
       mReallyIsBrowser = !!aValue && BrowserFramesEnabled() &&
                          PrincipalAllowsBrowserFrame(NodePrincipal());
     }
--- a/dom/html/nsHTMLDocument.cpp
+++ b/dom/html/nsHTMLDocument.cpp
@@ -6,16 +6,17 @@
 
 #include "nsHTMLDocument.h"
 
 #include "nsIContentPolicy.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/PresShell.h"
 #include "mozilla/dom/HTMLAllCollection.h"
 #include "mozilla/dom/FeaturePolicyUtils.h"
+#include "nsCommandManager.h"
 #include "nsCOMPtr.h"
 #include "nsGlobalWindow.h"
 #include "nsString.h"
 #include "nsPrintfCString.h"
 #include "nsReadableUtils.h"
 #include "nsUnicharUtils.h"
 #include "nsGlobalWindowInner.h"
 #include "nsIDocumentLoader.h"
@@ -504,17 +505,17 @@ nsresult nsHTMLDocument::StartDocumentLo
   bool forceUtf8 =
       mIsPlainText && nsContentUtils::IsUtf8OnlyPlainTextType(contentType);
 
   bool loadAsHtml5 = true;
 
   if (!viewSource && xhtml) {
     // We're parsing XHTML as XML, remember that.
     mType = eXHTML;
-    mCompatMode = eCompatibility_FullStandards;
+    SetCompatibilityMode(eCompatibility_FullStandards);
     loadAsHtml5 = false;
   }
 
   // TODO: Proper about:blank treatment is bug 543435
   if (loadAsHtml5 && view) {
     // mDocumentURI hasn't been set, yet, so get the URI from the channel
     nsCOMPtr<nsIURI> uri;
     aChannel->GetOriginalURI(getter_AddRefs(uri));
@@ -523,18 +524,16 @@ nsresult nsHTMLDocument::StartDocumentLo
     bool isAbout = false;
     if (uri && NS_SUCCEEDED(uri->SchemeIs("about", &isAbout)) && isAbout) {
       if (uri->GetSpecOrDefault().EqualsLiteral("about:blank")) {
         loadAsHtml5 = false;
       }
     }
   }
 
-  CSSLoader()->SetCompatibilityMode(mCompatMode);
-
   nsresult rv = Document::StartDocumentLoad(aCommand, aChannel, aLoadGroup,
                                             aContainer, aDocListener, aReset);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   // Store the security info for future use.
   aChannel->GetSecurityInfo(getter_AddRefs(mSecurityInfo));
@@ -777,20 +776,17 @@ void nsHTMLDocument::EndLoad() {
 void nsHTMLDocument::SetCompatibilityMode(nsCompatibility aMode) {
   NS_ASSERTION(IsHTMLDocument() || aMode == eCompatibility_FullStandards,
                "Bad compat mode for XHTML document!");
 
   if (mCompatMode == aMode) {
     return;
   }
   mCompatMode = aMode;
-  CSSLoader()->SetCompatibilityMode(mCompatMode);
-  if (nsPresContext* pc = GetPresContext()) {
-    pc->CompatibilityModeChanged();
-  }
+  CompatibilityModeChanged();
 }
 
 bool nsHTMLDocument::UseWidthDeviceWidthFallbackViewport() const {
   if (mIsPlainText) {
     // Plain text documents are simple enough that font inflation doesn't offer
     // any appreciable advantage over defaulting to "width=device-width" and
     // subsequently turning on word-wrapping.
     return true;
@@ -2227,40 +2223,34 @@ void nsHTMLDocument::SetDesignMode(
   bool editableMode = HasFlag(NODE_IS_EDITABLE);
   if (aDesignMode.LowerCaseEqualsASCII(editableMode ? "off" : "on")) {
     SetEditableFlag(!editableMode);
 
     rv = EditingStateChanged();
   }
 }
 
-nsresult nsHTMLDocument::GetMidasCommandManager(nsICommandManager** aCmdMgr) {
-  // initialize return value
-  NS_ENSURE_ARG_POINTER(aCmdMgr);
-
+nsCommandManager* nsHTMLDocument::GetMidasCommandManager() {
   // check if we have it cached
   if (mMidasCommandManager) {
-    NS_ADDREF(*aCmdMgr = mMidasCommandManager);
-    return NS_OK;
+    return mMidasCommandManager;
   }
 
-  *aCmdMgr = nullptr;
-
   nsPIDOMWindowOuter* window = GetWindow();
-  if (!window) return NS_ERROR_FAILURE;
+  if (!window) {
+    return nullptr;
+  }
 
   nsIDocShell* docshell = window->GetDocShell();
-  if (!docshell) return NS_ERROR_FAILURE;
+  if (!docshell) {
+    return nullptr;
+  }
 
   mMidasCommandManager = docshell->GetCommandManager();
-  if (!mMidasCommandManager) return NS_ERROR_FAILURE;
-
-  NS_ADDREF(*aCmdMgr = mMidasCommandManager);
-
-  return NS_OK;
+  return mMidasCommandManager;
 }
 
 struct MidasCommand {
   const char* incomingCommandString;
   const char* internalCommandString;
   const char* internalParamString;
   bool useNewParam;
   bool convertToBoolean;
@@ -2543,19 +2533,18 @@ bool nsHTMLDocument::ExecCommand(const n
   }
 
   if (isPaste && !nsContentUtils::PrincipalHasPermission(
                      &aSubjectPrincipal, nsGkAtoms::clipboardRead)) {
     return false;
   }
 
   // get command manager and dispatch command to our window if it's acceptable
-  nsCOMPtr<nsICommandManager> cmdMgr;
-  GetMidasCommandManager(getter_AddRefs(cmdMgr));
-  if (!cmdMgr) {
+  RefPtr<nsCommandManager> commandManager = GetMidasCommandManager();
+  if (!commandManager) {
     rv.Throw(NS_ERROR_FAILURE);
     return false;
   }
 
   nsCOMPtr<nsPIDOMWindowOuter> window = GetWindow();
   if (!window) {
     rv.Throw(NS_ERROR_FAILURE);
     return false;
@@ -2574,24 +2563,22 @@ bool nsHTMLDocument::ExecCommand(const n
       !paramStr.LowerCaseEqualsLiteral("div") &&
       !paramStr.LowerCaseEqualsLiteral("p") &&
       !paramStr.LowerCaseEqualsLiteral("br")) {
     // Invalid value
     return false;
   }
 
   // Return false for disabled commands (bug 760052)
-  bool enabled = false;
-  cmdMgr->IsCommandEnabled(cmdToDispatch.get(), window, &enabled);
-  if (!enabled) {
+  if (!commandManager->IsCommandEnabled(cmdToDispatch, window)) {
     return false;
   }
 
   if (!isBool && paramStr.IsEmpty()) {
-    rv = cmdMgr->DoCommand(cmdToDispatch.get(), nullptr, window);
+    rv = commandManager->DoCommand(cmdToDispatch.get(), nullptr, window);
   } else {
     // we have a command that requires a parameter, create params
     RefPtr<nsCommandParams> params = new nsCommandParams();
     if (isBool) {
       rv = params->SetBool("state_attribute", boolVal);
     } else if (cmdToDispatch.EqualsLiteral("cmd_fontFace") ||
                cmdToDispatch.EqualsLiteral("cmd_insertImageNoUI") ||
                cmdToDispatch.EqualsLiteral("cmd_insertLinkNoUI")) {
@@ -2600,17 +2587,17 @@ bool nsHTMLDocument::ExecCommand(const n
                cmdToDispatch.EqualsLiteral("cmd_insertText")) {
       rv = params->SetString("state_data", value);
     } else {
       rv = params->SetCString("state_attribute", paramStr);
     }
     if (rv.Failed()) {
       return false;
     }
-    rv = cmdMgr->DoCommand(cmdToDispatch.get(), params, window);
+    rv = commandManager->DoCommand(cmdToDispatch.get(), params, window);
   }
 
   return !rv.Failed();
 }
 
 bool nsHTMLDocument::QueryCommandEnabled(const nsAString& commandID,
                                          nsIPrincipal& aSubjectPrincipal,
                                          ErrorResult& rv) {
@@ -2633,62 +2620,58 @@ bool nsHTMLDocument::QueryCommandEnabled
   }
 
   // if editing is not on, bail
   if (!IsEditingOnAfterFlush()) {
     return false;
   }
 
   // get command manager and dispatch command to our window if it's acceptable
-  nsCOMPtr<nsICommandManager> cmdMgr;
-  GetMidasCommandManager(getter_AddRefs(cmdMgr));
-  if (!cmdMgr) {
+  RefPtr<nsCommandManager> commandManager = GetMidasCommandManager();
+  if (!commandManager) {
     rv.Throw(NS_ERROR_FAILURE);
     return false;
   }
 
   nsPIDOMWindowOuter* window = GetWindow();
   if (!window) {
     rv.Throw(NS_ERROR_FAILURE);
     return false;
   }
 
-  bool retval;
-  rv = cmdMgr->IsCommandEnabled(cmdToDispatch.get(), window, &retval);
-  return retval;
+  return commandManager->IsCommandEnabled(cmdToDispatch, window);
 }
 
 bool nsHTMLDocument::QueryCommandIndeterm(const nsAString& commandID,
                                           ErrorResult& rv) {
   nsAutoCString cmdToDispatch;
   if (!ConvertToMidasInternalCommand(commandID, cmdToDispatch)) {
     return false;
   }
 
   // if editing is not on, bail
   if (!IsEditingOnAfterFlush()) {
     return false;
   }
 
   // get command manager and dispatch command to our window if it's acceptable
-  nsCOMPtr<nsICommandManager> cmdMgr;
-  GetMidasCommandManager(getter_AddRefs(cmdMgr));
-  if (!cmdMgr) {
+  RefPtr<nsCommandManager> commandManager = GetMidasCommandManager();
+  if (!commandManager) {
     rv.Throw(NS_ERROR_FAILURE);
     return false;
   }
 
   nsPIDOMWindowOuter* window = GetWindow();
   if (!window) {
     rv.Throw(NS_ERROR_FAILURE);
     return false;
   }
 
   RefPtr<nsCommandParams> params = new nsCommandParams();
-  rv = cmdMgr->GetCommandState(cmdToDispatch.get(), window, params);
+  rv = commandManager->GetCommandState(cmdToDispatch.get(), window, params);
   if (rv.Failed()) {
     return false;
   }
 
   // If command does not have a state_mixed value, this call fails and sets
   // retval to false.  This is fine -- we want to return false in that case
   // anyway (bug 738385), so we just don't throw regardless.
   return params->GetBool("state_mixed");
@@ -2704,19 +2687,18 @@ bool nsHTMLDocument::QueryCommandState(c
   }
 
   // if editing is not on, bail
   if (!IsEditingOnAfterFlush()) {
     return false;
   }
 
   // get command manager and dispatch command to our window if it's acceptable
-  nsCOMPtr<nsICommandManager> cmdMgr;
-  GetMidasCommandManager(getter_AddRefs(cmdMgr));
-  if (!cmdMgr) {
+  RefPtr<nsCommandManager> commandManager = GetMidasCommandManager();
+  if (!commandManager) {
     rv.Throw(NS_ERROR_FAILURE);
     return false;
   }
 
   nsPIDOMWindowOuter* window = GetWindow();
   if (!window) {
     rv.Throw(NS_ERROR_FAILURE);
     return false;
@@ -2724,17 +2706,17 @@ bool nsHTMLDocument::QueryCommandState(c
 
   if (commandID.LowerCaseEqualsLiteral("usecss")) {
     // Per spec, state is supported for styleWithCSS but not useCSS, so we just
     // return false always.
     return false;
   }
 
   RefPtr<nsCommandParams> params = new nsCommandParams();
-  rv = cmdMgr->GetCommandState(cmdToDispatch.get(), window, params);
+  rv = commandManager->GetCommandState(cmdToDispatch.get(), window, params);
   if (rv.Failed()) {
     return false;
   }
 
   // handle alignment as a special case (possibly other commands too?)
   // Alignment is special because the external api is individual
   // commands but internally we use cmd_align with different
   // parameters.  When getting the state of this command, we need to
@@ -2792,19 +2774,18 @@ void nsHTMLDocument::QueryCommandValue(c
   }
 
   // if editing is not on, bail
   if (!IsEditingOnAfterFlush()) {
     return;
   }
 
   // get command manager and dispatch command to our window if it's acceptable
-  nsCOMPtr<nsICommandManager> cmdMgr;
-  GetMidasCommandManager(getter_AddRefs(cmdMgr));
-  if (!cmdMgr) {
+  RefPtr<nsCommandManager> commandManager = GetMidasCommandManager();
+  if (!commandManager) {
     rv.Throw(NS_ERROR_FAILURE);
     return;
   }
 
   nsCOMPtr<nsPIDOMWindowOuter> window = GetWindow();
   if (!window) {
     rv.Throw(NS_ERROR_FAILURE);
     return;
@@ -2817,30 +2798,30 @@ void nsHTMLDocument::QueryCommandValue(c
     rv = params->SetBool("selection_only", true);
     if (rv.Failed()) {
       return;
     }
     rv = params->SetCString("format", NS_LITERAL_CSTRING("text/html"));
     if (rv.Failed()) {
       return;
     }
-    rv = cmdMgr->DoCommand(cmdToDispatch.get(), params, window);
+    rv = commandManager->DoCommand(cmdToDispatch.get(), params, window);
     if (rv.Failed()) {
       return;
     }
     params->GetString("result", aValue);
     return;
   }
 
   rv = params->SetCString("state_attribute", paramStr);
   if (rv.Failed()) {
     return;
   }
 
-  rv = cmdMgr->GetCommandState(cmdToDispatch.get(), window, params);
+  rv = commandManager->GetCommandState(cmdToDispatch.get(), window, params);
   if (rv.Failed()) {
     return;
   }
 
   // If command does not have a state_attribute value, this call fails, and
   // aValue will wind up being the empty string.  This is fine -- we want to
   // return "" in that case anyway (bug 738385), so we just return NS_OK
   // regardless.
--- a/dom/html/nsHTMLDocument.h
+++ b/dom/html/nsHTMLDocument.h
@@ -12,20 +12,20 @@
 #include "nsIHTMLDocument.h"
 #include "nsIHTMLCollection.h"
 #include "nsIScriptElement.h"
 #include "nsTArray.h"
 
 #include "PLDHashTable.h"
 #include "nsIHttpChannel.h"
 #include "nsThreadUtils.h"
-#include "nsICommandManager.h"
 #include "mozilla/dom/HTMLSharedElement.h"
 #include "mozilla/dom/BindingDeclarations.h"
 
+class nsCommandManager;
 class nsIURI;
 class nsIDocShell;
 class nsICachingChannel;
 class nsILoadGroup;
 
 namespace mozilla {
 namespace dom {
 class HTMLAllCollection;
@@ -316,19 +316,19 @@ class nsHTMLDocument : public mozilla::d
 
   bool mTooDeepWriteRecursion;
 
   bool mDisableDocWrite;
 
   bool mWarnedWidthHeight;
 
   /* Midas implementation */
-  nsresult GetMidasCommandManager(nsICommandManager** aCommandManager);
+  nsCommandManager* GetMidasCommandManager();
 
-  nsCOMPtr<nsICommandManager> mMidasCommandManager;
+  RefPtr<nsCommandManager> mMidasCommandManager;
 
   nsresult TurnEditingOff();
   // MOZ_CAN_RUN_SCRIPT_BOUNDARY because this is called from all sorts
   // of places, and I'm pretty sure the exact ExecCommand call it
   // makes cannot actually run script.
   MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult EditingStateChanged();
   void MaybeEditingStateChanged();
 
--- a/dom/html/nsTextEditorState.cpp
+++ b/dom/html/nsTextEditorState.cpp
@@ -287,17 +287,17 @@ class nsTextInputSelectionImpl final : p
                                        public nsISelectionController {
   ~nsTextInputSelectionImpl() {}
 
  public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsTextInputSelectionImpl,
                                            nsISelectionController)
 
-  nsTextInputSelectionImpl(nsFrameSelection* aSel, nsIPresShell* aShell,
+  nsTextInputSelectionImpl(nsFrameSelection* aSel, PresShell* aPresShell,
                            nsIContent* aLimiter);
 
   void SetScrollableFrame(nsIScrollableFrame* aScrollableFrame);
   nsFrameSelection* GetConstFrameSelection() { return mFrameSelection; }
   // Will return null if !mFrameSelection.
   Selection* GetSelection(SelectionType aSelectionType);
 
   // NSISELECTIONCONTROLLER INTERFACES
@@ -357,26 +357,26 @@ NS_INTERFACE_TABLE_HEAD(nsTextInputSelec
   NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsTextInputSelectionImpl)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTION(nsTextInputSelectionImpl, mFrameSelection, mLimiter)
 
 // BEGIN nsTextInputSelectionImpl
 
 nsTextInputSelectionImpl::nsTextInputSelectionImpl(nsFrameSelection* aSel,
-                                                   nsIPresShell* aShell,
+                                                   PresShell* aPresShell,
                                                    nsIContent* aLimiter)
     : mScrollFrame(nullptr) {
-  if (aSel && aShell) {
+  if (aSel && aPresShell) {
     mFrameSelection = aSel;  // we are the owner now!
     mLimiter = aLimiter;
     bool accessibleCaretEnabled =
         PresShell::AccessibleCaretEnabled(aLimiter->OwnerDoc()->GetDocShell());
-    mFrameSelection->Init(aShell, mLimiter, accessibleCaretEnabled);
-    mPresShellWeak = do_GetWeakReference(aShell);
+    mFrameSelection->Init(aPresShell, mLimiter, accessibleCaretEnabled);
+    mPresShellWeak = do_GetWeakReference(aPresShell);
   }
 }
 
 void nsTextInputSelectionImpl::SetScrollableFrame(
     nsIScrollableFrame* aScrollableFrame) {
   mScrollFrame = aScrollableFrame;
   if (!mScrollFrame && mFrameSelection) {
     mFrameSelection->DisconnectFromPresShell();
@@ -1173,37 +1173,37 @@ nsresult nsTextEditorState::BindToFrame(
     GetValue(currentValue, true);
   }
 
   mBoundFrame = aFrame;
 
   Element* rootNode = aFrame->GetRootNode();
   MOZ_ASSERT(rootNode);
 
-  nsIPresShell* shell = aFrame->PresContext()->GetPresShell();
-  MOZ_ASSERT(shell);
+  PresShell* presShell = aFrame->PresContext()->GetPresShell();
+  MOZ_ASSERT(presShell);
 
   // Create selection
   RefPtr<nsFrameSelection> frameSel = new nsFrameSelection();
 
   // Create a SelectionController
-  mSelCon = new nsTextInputSelectionImpl(frameSel, shell, rootNode);
+  mSelCon = new nsTextInputSelectionImpl(frameSel, presShell, rootNode);
   MOZ_ASSERT(!mTextListener, "Should not overwrite the object");
   mTextListener = new TextInputListener(mTextCtrlElement);
 
   mTextListener->SetFrame(mBoundFrame);
   mSelCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
 
   // Get the caret and make it a selection listener.
   // FYI: It's safe to use raw pointer for calling
   //      Selection::AddSelectionListner() because it only appends the listener
   //      to its internal array.
   Selection* selection = mSelCon->GetSelection(SelectionType::eNormal);
   if (selection) {
-    RefPtr<nsCaret> caret = shell->GetCaret();
+    RefPtr<nsCaret> caret = presShell->GetCaret();
     if (caret) {
       selection->AddSelectionListener(caret);
     }
     mTextListener->StartToListenToSelectionChange();
   }
 
   // If an editor exists from before, prepare it for usage
   if (mTextEditor) {
@@ -1263,17 +1263,17 @@ nsresult nsTextEditorState::PrepareEdito
     return NS_ERROR_NOT_INITIALIZED;
   }
 
   // Note that we don't check mTextEditor here, because we might already have
   // one around, in which case we don't create a new one, and we'll just tie
   // the required machinery to it.
 
   nsPresContext* presContext = mBoundFrame->PresContext();
-  nsIPresShell* shell = presContext->GetPresShell();
+  PresShell* presShell = presContext->GetPresShell();
 
   // Setup the editor flags
   uint32_t editorFlags = nsIPlaintextEditor::eEditorPlaintextMask;
   if (IsSingleLineTextControl())
     editorFlags |= nsIPlaintextEditor::eEditorSingleLineMask;
   if (IsPasswordTextControl())
     editorFlags |= nsIPlaintextEditor::eEditorPasswordMask;
 
@@ -1326,17 +1326,17 @@ nsresult nsTextEditorState::PrepareEdito
 
   if (!mEditorInitialized) {
     // Now initialize the editor.
     //
     // NOTE: Conversion of '\n' to <BR> happens inside the
     //       editor's Init() call.
 
     // Get the DOM document
-    nsCOMPtr<Document> doc = shell->GetDocument();
+    nsCOMPtr<Document> doc = presShell->GetDocument();
     if (NS_WARN_IF(!doc)) {
       return NS_ERROR_FAILURE;
     }
 
     // What follows is a bit of a hack.  The editor uses the public DOM APIs
     // for its content manipulations, and it causes it to fail some security
     // checks deep inside when initializing. So we explictly make it clear that
     // we're native code.
--- a/dom/interfaces/base/nsIBrowser.idl
+++ b/dom/interfaces/base/nsIBrowser.idl
@@ -1,16 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #include "nsISupports.idl"
 
 interface nsIContentSecurityPolicy;
 interface nsIPrincipal;
-interface nsIURI;
+interface nsIWebProgress;
 
 webidl FrameLoader;
 
 [scriptable, uuid(14e5a0cb-e223-4202-95e8-fe53275193ea)]
 interface nsIBrowser : nsISupports
 {
   /**
    * Gets an optional frame loader that is "related" to this browser.
@@ -56,16 +56,24 @@ interface nsIBrowser : nsISupports
   /**
    * A browser can change from remote to non-remote and vice versa.
    * For example, when navigating from an in-process chrome page to
    * a web page, this value would change from false to true.
    */
   readonly attribute boolean isRemoteBrowser;
 
   /**
+   * The nsIWebProgress instance responsible for handling progress events
+   * from the content process.
+   *
+   * Will always be non-null when isRemoteBrowser is true.
+   */
+  readonly attribute nsIWebProgress remoteWebProgressManager;
+
+  /**
    * Called by the child to inform the parent that a command update has occurred
    * and the supplied set of commands are now enabled and disabled.
    *
    * @param action command updater action
    * @param enabledLength length of enabledCommands array
    * @param enabledCommands commands to enable
    * @param disabledLength length of disabledCommands array
    * @param disabledCommand commands to disable
@@ -73,34 +81,9 @@ interface nsIBrowser : nsISupports
   void enableDisableCommandsRemoteOnly(in AString action,
                                        in unsigned long enabledLength,
                                        [array, size_is(enabledLength)] in string enabledCommands,
                                        in unsigned long disabledLength,
                                        [array, size_is(disabledLength)] in string disabledCommands);
 
   readonly attribute nsIPrincipal contentPrincipal;
   readonly attribute nsIContentSecurityPolicy csp;
-
-  /**
-   * Called by Gecko when we need to call the web progress listeners on our
-   * browser element in order to notify them about a content blocking event
-   * which happened in the content process.
-   * @param isWebProgressPassed whether we're passed a webProgress argument
-   * @param isTopLevel whether we're in the top-level document
-   * @param isLoadingDocument whether we're in the process of loading a document
-   * @param loadType the type of load in progress
-   * @param DOMWindowID the ID of the window receiving the notification
-   * @param requestURI the current URI of the request
-   * @param originalRequestURI the original URI of the request
-   * @param matchedList the matched list for the content blocking event
-   * @param eventType one of the content blocking event codes defined in
-   *                  nsIWebProgressListener.idl.
-   */
-  void callWebProgressContentBlockingEventListeners(in boolean isWebProgressPassed,
-                                                    in boolean isTopLevel,
-                                                    in boolean isLoadingDocument,
-                                                    in unsigned long loadType,
-                                                    in uint64_t DOMWindowID,
-                                                    in nsIURI requestURI,
-                                                    in nsIURI originalRequestURI,
-                                                    in ACString matchedList,
-                                                    in unsigned long eventType);
 };
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -1168,19 +1168,17 @@ void ContentChild::LaunchRDDProcess() {
   SynchronousTask task("LaunchRDDProcess");
   SystemGroup::Dispatch(
       TaskCategory::Other,
       NS_NewRunnableFunction("LaunchRDDProcess", [&task, this] {
         AutoCompleteTask complete(&task);
         nsresult rv;
         Endpoint<PRemoteDecoderManagerChild> endpoint;
         Unused << SendLaunchRDDProcess(&rv, &endpoint);
-        // Only call InitForContent if we got a valid enpoint back which
-        // indicates we needed to launch an RDD process.
-        if (rv == NS_OK && endpoint.IsValid()) {
+        if (rv == NS_OK) {
           RemoteDecoderManagerChild::InitForContent(std::move(endpoint));
         }
       }));
   task.Wait();
 }
 
 bool ContentChild::IsAlive() const { return mIsAlive; }
 
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -1063,24 +1063,16 @@ mozilla::ipc::IPCResult ContentParent::R
     nsresult* aRv, Endpoint<PRemoteDecoderManagerChild>* aEndpoint) {
   *aRv = NS_OK;
 
   if (XRE_IsParentProcess() &&
       BrowserTabsRemoteAutostart() &&  // only do rdd process if e10s on
       Preferences::GetBool("media.rdd-process.enabled", false)) {
     RDDProcessManager* rdd = RDDProcessManager::Get();
     if (rdd) {
-      // If there is already an RDDChild, then we've already launched the
-      // RDD process.  We don't need to do anything else.  Specifically,
-      // we want to avoid calling CreateContentBridge again because that
-      // causes the RemoteDecoderManagerParent to rebuild needlessly.
-      if (rdd->GetRDDChild()) {
-        return IPC_OK();
-      }
-
       rdd->LaunchRDDProcess();
 
       bool rddOpened = rdd->CreateContentBridge(OtherPid(), aEndpoint);
       MOZ_ASSERT(rddOpened);
 
       if (!rddOpened) {
         *aRv = NS_ERROR_NOT_AVAILABLE;
       }
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -103,17 +103,18 @@ struct ShowInfo
   double defaultScale;
 };
 
 struct WebProgressData
 {
   bool isTopLevel;
   bool isLoadingDocument;
   uint32_t loadType;
-  uint64_t DOMWindowID;
+  uint64_t outerDOMWindowID;
+  uint64_t innerDOMWindowID;
 };
 
 struct RequestData
 {
   nsIURI requestURI;
   nsIURI originalRequestURI;
   nsCString matchedList;
 };
@@ -531,16 +532,25 @@ parent:
 
     async AccessKeyNotHandled(WidgetKeyboardEvent event);
 
     async SetHasBeforeUnload(bool aHasBeforeUnload);
 
     async RegisterProtocolHandler(nsString scheme, nsIURI handlerURI, nsString title,
                                   nsIURI documentURI);
 
+    async OnProgressChange(WebProgressData? aWebProgressData,
+                           RequestData aRequestData, int32_t aCurSelfProgress,
+                           int32_t aMaxSelfProgress, int32_t aCurTotalProgress,
+                           int32_t aMaxTotalProgress);
+
+    async OnStatusChange(WebProgressData? aWebProgressData,
+                         RequestData aRequestData, nsresult aStatus,
+                         nsString aMessage);
+
     async OnContentBlockingEvent(WebProgressData? aWebProgressData,
                                  RequestData aRequestData, uint32_t aEvent);
 
 child:
     async NativeSynthesisResponse(uint64_t aObserverId, nsCString aResponse);
 
 parent:
 
new file mode 100644
--- /dev/null
+++ b/dom/ipc/RemoteWebProgress.cpp
@@ -0,0 +1,106 @@
+/* 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 "RemoteWebProgress.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION(RemoteWebProgress, mManager)
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(RemoteWebProgress)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(RemoteWebProgress)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(RemoteWebProgress)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_INTERFACE_MAP_ENTRY(nsIWebProgress)
+  NS_INTERFACE_MAP_ENTRY(nsIRemoteWebProgress)
+NS_INTERFACE_MAP_END
+
+NS_IMETHODIMP RemoteWebProgress::Init(nsIWebProgress *aManager,
+                                      bool aIsTopLevel) {
+  mManager = aManager;
+  mIsTopLevel = aIsTopLevel;
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP RemoteWebProgress::Update(uint64_t aOuterDOMWindowID,
+                                        uint64_t aInnerDOMWindowID,
+                                        uint32_t aLoadType,
+                                        bool aIsLoadingDocument) {
+  mOuterDOMWindowID = aOuterDOMWindowID;
+  mInnerDOMWindowID = aInnerDOMWindowID;
+  mLoadType = aLoadType;
+  mIsLoadingDocument = aIsLoadingDocument;
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP RemoteWebProgress::AddProgressListener(
+    nsIWebProgressListener *aListener, uint32_t aNotifyMask) {
+  if (mManager) {
+    return mManager->AddProgressListener(aListener, aNotifyMask);
+  } else {
+    NS_WARNING("RemoteWebProgres::mManager should not be null!");
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP RemoteWebProgress::RemoveProgressListener(
+    nsIWebProgressListener *aListener) {
+  if (mManager) {
+    return mManager->RemoveProgressListener(aListener);
+  } else {
+    NS_WARNING("RemoteWebProgres::mManager should not be null!");
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP RemoteWebProgress::GetDOMWindow(mozIDOMWindowProxy **aDOMWindow) {
+  return NS_ERROR_NOT_AVAILABLE;
+}
+
+NS_IMETHODIMP RemoteWebProgress::GetDOMWindowID(uint64_t *aDOMWindowID) {
+  *aDOMWindowID = mOuterDOMWindowID;
+  return NS_OK;
+}
+
+NS_IMETHODIMP RemoteWebProgress::GetInnerDOMWindowID(
+    uint64_t *aInnerDOMWindowID) {
+  *aInnerDOMWindowID = mInnerDOMWindowID;
+  return NS_OK;
+}
+
+NS_IMETHODIMP RemoteWebProgress::GetIsTopLevel(bool *aIsTopLevel) {
+  NS_ENSURE_ARG_POINTER(aIsTopLevel);
+  *aIsTopLevel = mIsTopLevel;
+  return NS_OK;
+}
+
+NS_IMETHODIMP RemoteWebProgress::GetIsLoadingDocument(
+    bool *aIsLoadingDocument) {
+  NS_ENSURE_ARG_POINTER(aIsLoadingDocument);
+  *aIsLoadingDocument = mIsLoadingDocument;
+  return NS_OK;
+}
+
+NS_IMETHODIMP RemoteWebProgress::GetLoadType(uint32_t *aLoadType) {
+  NS_ENSURE_ARG_POINTER(aLoadType);
+  *aLoadType = mLoadType;
+  return NS_OK;
+}
+
+NS_IMETHODIMP RemoteWebProgress::GetTarget(nsIEventTarget **aTarget) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP RemoteWebProgress::SetTarget(nsIEventTarget *aTarget) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+}  // namespace dom
+}  // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/ipc/RemoteWebProgress.h
@@ -0,0 +1,54 @@
+/* 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/. */
+
+#ifndef mozilla_dom_RemoteWebProgress_h
+#define mozilla_dom_RemoteWebProgress_h
+
+#include "nsIRemoteWebProgress.h"
+
+namespace mozilla {
+namespace dom {
+
+class RemoteWebProgress final : public nsIRemoteWebProgress {
+ public:
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS(RemoteWebProgress)
+
+  NS_DECL_NSIWEBPROGRESS
+  NS_DECL_NSIREMOTEWEBPROGRESS
+
+  RemoteWebProgress()
+      : mManager(nullptr),
+        mOuterDOMWindowID(0),
+        mInnerDOMWindowID(0),
+        mLoadType(0),
+        mIsLoadingDocument(false),
+        mIsTopLevel(false) {}
+
+  RemoteWebProgress(nsIWebProgress *aManager, uint64_t aOuterDOMWindowID,
+                    uint64_t aInnerDOMWindowID, uint32_t aLoadType,
+                    bool aIsLoadingDocument, bool aIsTopLevel)
+      : mManager(aManager),
+        mOuterDOMWindowID(aOuterDOMWindowID),
+        mInnerDOMWindowID(aInnerDOMWindowID),
+        mLoadType(aLoadType),
+        mIsLoadingDocument(aIsLoadingDocument),
+        mIsTopLevel(aIsTopLevel) {}
+
+ private:
+  virtual ~RemoteWebProgress() = default;
+
+  nsCOMPtr<nsIWebProgress> mManager;
+
+  uint64_t mOuterDOMWindowID;
+  uint64_t mInnerDOMWindowID;
+  uint32_t mLoadType;
+  bool mIsLoadingDocument;
+  bool mIsTopLevel;
+};
+
+}  // namespace dom
+}  // namespace mozilla
+
+#endif  // mozilla_dom_RemoteWebProgress_h
new file mode 100644
--- /dev/null
+++ b/dom/ipc/RemoteWebProgressRequest.cpp
@@ -0,0 +1,207 @@
+/* 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 "RemoteWebProgressRequest.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_ISUPPORTS(RemoteWebProgressRequest, nsIRequest, nsIChannel,
+                  nsIClassifiedChannel, nsIRemoteWebProgressRequest)
+
+NS_IMETHODIMP RemoteWebProgressRequest::Init(nsIURI *aURI, nsIURI *aOriginalURI,
+                                             const nsACString &aMatchedList) {
+  mURI = aURI;
+  mOriginalURI = aOriginalURI;
+  mMatchedList = aMatchedList;
+
+  return NS_OK;
+}
+
+// nsIChannel methods
+
+NS_IMETHODIMP RemoteWebProgressRequest::GetOriginalURI(nsIURI **aOriginalURI) {
+  NS_ENSURE_ARG_POINTER(aOriginalURI);
+  NS_ADDREF(*aOriginalURI = mOriginalURI);
+  return NS_OK;
+}
+
+NS_IMETHODIMP RemoteWebProgressRequest::SetOriginalURI(nsIURI *aOriginalURI) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP RemoteWebProgressRequest::GetURI(nsIURI **aURI) {
+  NS_ENSURE_ARG_POINTER(aURI);
+  NS_ADDREF(*aURI = mURI);
+  return NS_OK;
+}
+
+NS_IMETHODIMP RemoteWebProgressRequest::GetOwner(nsISupports **aOwner) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP RemoteWebProgressRequest::SetOwner(nsISupports *aOwner) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP RemoteWebProgressRequest::GetNotificationCallbacks(
+    nsIInterfaceRequestor **aNotificationCallbacks) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP RemoteWebProgressRequest::SetNotificationCallbacks(
+    nsIInterfaceRequestor *aNotificationCallbacks) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP RemoteWebProgressRequest::GetSecurityInfo(
+    nsISupports **aSecurityInfo) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP RemoteWebProgressRequest::GetContentType(
+    nsACString &aContentType) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP RemoteWebProgressRequest::SetContentType(
+    const nsACString &aContentType) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP RemoteWebProgressRequest::GetContentCharset(
+    nsACString &aContentCharset) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP RemoteWebProgressRequest::SetContentCharset(
+    const nsACString &aContentCharset) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP RemoteWebProgressRequest::GetContentLength(
+    int64_t *aContentLength) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP RemoteWebProgressRequest::SetContentLength(
+    int64_t aContentLength) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP RemoteWebProgressRequest::Open(nsIInputStream **_retval) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP RemoteWebProgressRequest::AsyncOpen(
+    nsIStreamListener *aListener) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP RemoteWebProgressRequest::GetContentDisposition(
+    uint32_t *aContentDisposition) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP RemoteWebProgressRequest::SetContentDisposition(
+    uint32_t aContentDisposition) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP RemoteWebProgressRequest::GetContentDispositionFilename(
+    nsAString &aContentDispositionFilename) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP RemoteWebProgressRequest::SetContentDispositionFilename(
+    const nsAString &aContentDispositionFilename) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP RemoteWebProgressRequest::GetContentDispositionHeader(
+    nsACString &aContentDispositionHeader) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP RemoteWebProgressRequest::GetLoadInfo(nsILoadInfo **aLoadInfo) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP RemoteWebProgressRequest::SetLoadInfo(nsILoadInfo *aLoadInfo) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP RemoteWebProgressRequest::GetIsDocument(bool *aIsDocument) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+// nsIClassifiedChannel methods
+
+NS_IMETHODIMP RemoteWebProgressRequest::SetMatchedInfo(
+    const nsACString &aList, const nsACString &aProvider,
+    const nsACString &aFullHash) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP RemoteWebProgressRequest::GetMatchedList(
+    nsACString &aMatchedList) {
+  aMatchedList = mMatchedList;
+  return NS_OK;
+}
+
+NS_IMETHODIMP RemoteWebProgressRequest::GetMatchedProvider(
+    nsACString &aMatchedProvider) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP RemoteWebProgressRequest::GetMatchedFullHash(
+    nsACString &aMatchedFullHash) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+// nsIRequest methods
+
+NS_IMETHODIMP RemoteWebProgressRequest::GetName(nsACString &aName) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP RemoteWebProgressRequest::IsPending(bool *_retval) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP RemoteWebProgressRequest::GetStatus(nsresult *aStatus) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP RemoteWebProgressRequest::Cancel(nsresult aStatus) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP RemoteWebProgressRequest::Suspend(void) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP RemoteWebProgressRequest::Resume(void) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP RemoteWebProgressRequest::GetLoadGroup(
+    nsILoadGroup **aLoadGroup) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP RemoteWebProgressRequest::SetLoadGroup(nsILoadGroup *aLoadGroup) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP RemoteWebProgressRequest::GetLoadFlags(nsLoadFlags *aLoadFlags) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP RemoteWebProgressRequest::SetLoadFlags(nsLoadFlags aLoadFlags) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+}  // namespace dom
+}  // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/ipc/RemoteWebProgressRequest.h
@@ -0,0 +1,44 @@
+/* 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/. */
+
+#ifndef mozilla_dom_RemoteWebProgressRequest_h
+#define mozilla_dom_RemoteWebProgressRequest_h
+
+#include "nsIChannel.h"
+#include "nsIClassifiedChannel.h"
+#include "nsIRemoteWebProgressRequest.h"
+
+namespace mozilla {
+namespace dom {
+
+class RemoteWebProgressRequest final : public nsIRemoteWebProgressRequest,
+                                       public nsIChannel,
+                                       public nsIClassifiedChannel {
+ public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIREMOTEWEBPROGRESSREQUEST
+  NS_DECL_NSICHANNEL
+  NS_DECL_NSICLASSIFIEDCHANNEL
+  NS_DECL_NSIREQUEST
+
+  RemoteWebProgressRequest()
+      : mURI(nullptr), mOriginalURI(nullptr), mMatchedList(VoidCString()) {}
+
+  RemoteWebProgressRequest(nsIURI* aURI, nsIURI* aOriginalURI,
+                           const nsACString& aMatchedList)
+      : mURI(aURI), mOriginalURI(aOriginalURI), mMatchedList(aMatchedList) {}
+
+ protected:
+  ~RemoteWebProgressRequest() = default;
+
+ private:
+  nsCOMPtr<nsIURI> mURI;
+  nsCOMPtr<nsIURI> mOriginalURI;
+  nsCString mMatchedList;
+};
+
+}  // namespace dom
+}  // namespace mozilla
+
+#endif  // mozilla_dom_RemoteWebProgressRequest_h
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -55,16 +55,17 @@
 #include "mozilla/PresShell.h"
 #include "mozilla/ProcessHangMonitor.h"
 #include "mozilla/ScopeExit.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/TouchEvents.h"
 #include "mozilla/Unused.h"
+#include "nsBrowserStatusFilter.h"
 #include "nsContentUtils.h"
 #include "nsDocShell.h"
 #include "nsEmbedCID.h"
 #include "nsGlobalWindow.h"
 #include <algorithm>
 #include "nsExceptionHandler.h"
 #include "nsFilePickerProxy.h"
 #include "mozilla/dom/Element.h"
@@ -376,17 +377,16 @@ TabChild::TabChild(ContentChild* aManage
       mBeforeUnloadListeners(0),
       mDidFakeShow(false),
       mNotified(false),
       mTriedBrowserInit(false),
       mOrientation(hal::eScreenOrientation_PortraitPrimary),
       mIgnoreKeyPressEvent(false),
       mHasValidInnerSize(false),
       mDestroyed(false),
-      mProgressListenerRegistered(false),
       mUniqueId(aTabId),
       mHasSiblings(false),
       mIsTransparent(false),
       mIPCOpen(false),
       mParentIsActive(false),
       mDidSetRealShowInfo(false),
       mDidLoadURLInit(false),
       mAwaitingLA(false),
@@ -535,21 +535,34 @@ nsresult TabChild::Init(mozIDOMWindowPro
 
   // IPC uses a WebBrowser object for which DNS prefetching is turned off
   // by default. But here we really want it, so enable it explicitly
   mWebBrowser->SetAllowDNSPrefetch(true);
 
   nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
   MOZ_ASSERT(docShell);
 
-  nsCOMPtr<nsIWebProgress> webProgress = do_QueryInterface(docShell);
-  nsresult rv = webProgress->AddProgressListener(
-      this, nsIWebProgress::NOTIFY_CONTENT_BLOCKING);
+  const uint32_t notifyMask =
+      nsIWebProgress::NOTIFY_PROGRESS | nsIWebProgress::NOTIFY_STATUS |
+      nsIWebProgress::NOTIFY_REFRESH | nsIWebProgress::NOTIFY_CONTENT_BLOCKING;
+
+  mStatusFilter = new nsBrowserStatusFilter();
+
+  RefPtr<nsIEventTarget> eventTarget =
+      TabGroup()->EventTargetFor(TaskCategory::Network);
+
+  mStatusFilter->SetTarget(eventTarget);
+  nsresult rv = mStatusFilter->AddProgressListener(this, notifyMask);
   NS_ENSURE_SUCCESS(rv, rv);
-  mProgressListenerRegistered = true;
+
+  {
+    nsCOMPtr<nsIWebProgress> webProgress = do_QueryInterface(docShell);
+    rv = webProgress->AddProgressListener(mStatusFilter, notifyMask);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
 
   docShell->SetAffectPrivateSessionLifetime(
       mChromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME);
   nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(WebNavigation());
   MOZ_ASSERT(loadContext);
   loadContext->SetPrivateBrowsing(OriginAttributesRef().mPrivateBrowsingId > 0);
   loadContext->SetRemoteTabs(mChromeFlags &
                              nsIWebBrowserChrome::CHROME_REMOTE_WINDOW);
@@ -629,21 +642,23 @@ void TabChild::UpdateFrameType() {
   docShell->SetFrameType(IsMozBrowserElement()
                              ? nsIDocShell::FRAME_TYPE_BROWSER
                              : nsIDocShell::FRAME_TYPE_REGULAR);
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(TabChild)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(TabChild, TabChildBase)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mStatusFilter)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mWebNav)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowsingContext)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(TabChild, TabChildBase)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStatusFilter)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWebNav)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowsingContext)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(TabChild, TabChildBase)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TabChild)
@@ -925,16 +940,26 @@ TabChild::ProvideWindow(mozIDOMWindowPro
       aWindowIsNew, aReturn);
 }
 
 void TabChild::DestroyWindow() {
   if (mBrowsingContext) {
     mBrowsingContext = nullptr;
   }
 
+  if (mStatusFilter) {
+    if (nsCOMPtr<nsIWebProgress> webProgress =
+            do_QueryInterface(WebNavigation())) {
+      webProgress->RemoveProgressListener(mStatusFilter);
+    }
+
+    mStatusFilter->RemoveProgressListener(this);
+    mStatusFilter = nullptr;
+  }
+
   if (mCoalescedMouseEventFlusher) {
     mCoalescedMouseEventFlusher->RemoveObserver();
     mCoalescedMouseEventFlusher = nullptr;
   }
 
   // In case we don't have chance to process all entries, clean all data in
   // the queue.
   while (mToBeDispatchedMouseData.GetSize() > 0) {
@@ -958,24 +983,16 @@ void TabChild::DestroyWindow() {
     MOZ_ASSERT(sTabChildren);
     sTabChildren->Remove(uint64_t(mLayersId));
     if (!sTabChildren->Count()) {
       delete sTabChildren;
       sTabChildren = nullptr;
     }
     mLayersId = layers::LayersId{0};
   }
-
-  if (mProgressListenerRegistered) {
-    nsCOMPtr<nsIWebProgress> webProgress = do_QueryInterface(WebNavigation());
-    if (webProgress) {
-      webProgress->RemoveProgressListener(this);
-      mProgressListenerRegistered = false;
-    }
-  }
 }
 
 void TabChild::ActorDestroy(ActorDestroyReason why) {
   mIPCOpen = false;
 
   DestroyWindow();
 
   if (mTabChildMessageManager) {
@@ -3268,79 +3285,136 @@ NS_IMETHODIMP TabChild::OnStateChange(ns
 }
 
 NS_IMETHODIMP TabChild::OnProgressChange(nsIWebProgress* aWebProgress,
                                          nsIRequest* aRequest,
                                          int32_t aCurSelfProgress,
                                          int32_t aMaxSelfProgress,
                                          int32_t aCurTotalProgress,
                                          int32_t aMaxTotalProgress) {
-  return NS_ERROR_NOT_IMPLEMENTED;
+  if (!IPCOpen()) {
+    return NS_OK;
+  }
+
+  Maybe<WebProgressData> webProgressData;
+  RequestData requestData;
+
+  nsresult rv = PrepareProgressListenerData(aWebProgress, aRequest,
+                                            webProgressData, requestData);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  Unused << SendOnProgressChange(webProgressData, requestData, aCurSelfProgress,
+                                 aMaxSelfProgress, aCurTotalProgress,
+                                 aMaxTotalProgress);
+
+  return NS_OK;
 }
 
 NS_IMETHODIMP TabChild::OnLocationChange(nsIWebProgress* aWebProgress,
                                          nsIRequest* aRequest,
                                          nsIURI* aLocation, uint32_t aFlags) {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP TabChild::OnStatusChange(nsIWebProgress* aWebProgress,
                                        nsIRequest* aRequest, nsresult aStatus,
                                        const char16_t* aMessage) {
-  return NS_ERROR_NOT_IMPLEMENTED;
+  if (!IPCOpen()) {
+    return NS_OK;
+  }
+
+  Maybe<WebProgressData> webProgressData;
+  RequestData requestData;
+
+  nsresult rv = PrepareProgressListenerData(aWebProgress, aRequest,
+                                            webProgressData, requestData);
+
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  const nsString message(aMessage);
+
+  Unused << SendOnStatusChange(webProgressData, requestData, aStatus, message);
+
+  return NS_OK;
 }
+
 NS_IMETHODIMP TabChild::OnSecurityChange(nsIWebProgress* aWebProgress,
                                          nsIRequest* aRequest,
                                          uint32_t aState) {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 NS_IMETHODIMP TabChild::OnContentBlockingEvent(nsIWebProgress* aWebProgress,
                                                nsIRequest* aRequest,
                                                uint32_t aEvent) {
-  WebProgressData webProgressData;
+  if (!IPCOpen()) {
+    return NS_OK;
+  }
+
+  Maybe<WebProgressData> webProgressData;
   RequestData requestData;
   nsresult rv = PrepareProgressListenerData(aWebProgress, aRequest,
                                             webProgressData, requestData);
   NS_ENSURE_SUCCESS(rv, rv);
-
-  Maybe<WebProgressData> maybeWebProgressData;
-  if (aWebProgress) {
-    maybeWebProgressData.emplace(webProgressData);
-  }
-  Unused << SendOnContentBlockingEvent(maybeWebProgressData, requestData,
-                                       aEvent);
+  Unused << SendOnContentBlockingEvent(webProgressData, requestData, aEvent);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP TabChild::OnProgressChange64(nsIWebProgress* aWebProgress,
+                                           nsIRequest* aRequest,
+                                           int64_t aCurSelfProgress,
+                                           int64_t aMaxSelfProgress,
+                                           int64_t aCurTotalProgress,
+                                           int64_t aMaxTotalProgress) {
+  // All the events we receive are filtered through an nsBrowserStatusFilter,
+  // which accepts ProgressChange64 events, but truncates the progress values to
+  // uint32_t and calls OnProgressChange.
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP TabChild::OnRefreshAttempted(nsIWebProgress* aWebProgress,
+                                           nsIURI* aRefreshURI, int32_t aMillis,
+                                           bool aSameURI, bool* aOut) {
+  NS_ENSURE_ARG_POINTER(aOut);
+  *aOut = true;
 
   return NS_OK;
 }
 
 nsresult TabChild::PrepareProgressListenerData(
     nsIWebProgress* aWebProgress, nsIRequest* aRequest,
-    WebProgressData& aWebProgressData, RequestData& aRequestData) {
+    Maybe<WebProgressData>& aWebProgressData, RequestData& aRequestData) {
   if (aWebProgress) {
+    aWebProgressData.emplace();
+
     bool isTopLevel = false;
     nsresult rv = aWebProgress->GetIsTopLevel(&isTopLevel);
     NS_ENSURE_SUCCESS(rv, rv);
-    aWebProgressData.isTopLevel() = isTopLevel;
+    aWebProgressData->isTopLevel() = isTopLevel;
 
     bool isLoadingDocument = false;
     rv = aWebProgress->GetIsLoadingDocument(&isLoadingDocument);
     NS_ENSURE_SUCCESS(rv, rv);
-    aWebProgressData.isLoadingDocument() = isLoadingDocument;
+    aWebProgressData->isLoadingDocument() = isLoadingDocument;
 
     uint32_t loadType = 0;
     rv = aWebProgress->GetLoadType(&loadType);
     NS_ENSURE_SUCCESS(rv, rv);
-    aWebProgressData.loadType() = loadType;
-
-    uint64_t DOMWindowID = 0;
-    // The DOM Window ID getter here may throw if the inner or outer windows
+    aWebProgressData->loadType() = loadType;
+
+    uint64_t outerDOMWindowID = 0;
+    uint64_t innerDOMWindowID = 0;
+    // The DOM Window ID getters here may throw if the inner or outer windows
     // aren't created yet or are destroyed at the time we're making this call
     // but that isn't fatal so ignore the exceptions here.
-    Unused << aWebProgress->GetDOMWindowID(&DOMWindowID);
-    aWebProgressData.DOMWindowID() = DOMWindowID;
+    Unused << aWebProgress->GetDOMWindowID(&outerDOMWindowID);
+    aWebProgressData->outerDOMWindowID() = outerDOMWindowID;
+
+    Unused << aWebProgress->GetInnerDOMWindowID(&innerDOMWindowID);
+    aWebProgressData->innerDOMWindowID() = innerDOMWindowID;
   }
 
   nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
   if (channel) {
     nsCOMPtr<nsIURI> uri;
     nsresult rv = channel->GetURI(getter_AddRefs(uri));
     NS_ENSURE_SUCCESS(rv, rv);
     aRequestData.requestURI() = uri;
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -22,16 +22,17 @@
 #include "nsIDocShell.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsFrameMessageManager.h"
 #include "nsIPresShell.h"
 #include "nsWeakReference.h"
 #include "nsITabChild.h"
 #include "nsITooltipListener.h"
 #include "nsIWebProgressListener.h"
+#include "nsIWebProgressListener2.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/TabContext.h"
 #include "mozilla/dom/CoalescedMouseData.h"
 #include "mozilla/dom/CoalescedWheelData.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventForwards.h"
 #include "mozilla/layers/CompositorTypes.h"
@@ -40,16 +41,17 @@
 #include "nsIWebBrowserChrome3.h"
 #include "mozilla/dom/ipc/IdType.h"
 #include "AudioChannelService.h"
 #include "PuppetWidget.h"
 #include "mozilla/layers/GeckoContentController.h"
 #include "nsDeque.h"
 #include "nsISHistoryListener.h"
 
+class nsBrowserStatusFilter;
 class nsIDOMWindowUtils;
 class nsIHttpChannel;
 class nsIRequest;
 class nsISerialEventTarget;
 class nsIWebProgress;
 class nsWebBrowser;
 
 template <typename T>
@@ -198,17 +200,17 @@ class TabChild final : public TabChildBa
                        public nsIWebBrowserChrome2,
                        public nsIEmbeddingSiteWindow,
                        public nsIWebBrowserChromeFocus,
                        public nsIInterfaceRequestor,
                        public nsIWindowProvider,
                        public nsSupportsWeakReference,
                        public nsITabChild,
                        public nsIObserver,
-                       public nsIWebProgressListener,
+                       public nsIWebProgressListener2,
                        public TabContext,
                        public nsITooltipListener,
                        public mozilla::ipc::IShmemAllocator {
   typedef mozilla::dom::ClonedMessageData ClonedMessageData;
   typedef mozilla::dom::CoalescedMouseData CoalescedMouseData;
   typedef mozilla::dom::CoalescedWheelData CoalescedWheelData;
   typedef mozilla::layers::APZEventState APZEventState;
   typedef mozilla::layers::SetAllowedTouchBehaviorCallback
@@ -258,16 +260,17 @@ class TabChild final : public TabChildBa
   NS_DECL_NSIWEBBROWSERCHROME2
   NS_DECL_NSIEMBEDDINGSITEWINDOW
   NS_DECL_NSIWEBBROWSERCHROMEFOCUS
   NS_DECL_NSIINTERFACEREQUESTOR
   NS_DECL_NSIWINDOWPROVIDER
   NS_DECL_NSITABCHILD
   NS_DECL_NSIOBSERVER
   NS_DECL_NSIWEBPROGRESSLISTENER
+  NS_DECL_NSIWEBPROGRESSLISTENER2
   NS_DECL_NSITOOLTIPLISTENER
 
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(TabChild, TabChildBase)
 
   FORWARD_SHMEM_ALLOCATOR_TO(PBrowserChild)
 
   TabChildMessageManager* GetMessageManager() {
     return mTabChildMessageManager;
@@ -786,46 +789,47 @@ class TabChild final : public TabChildBa
 
   void InternalSetDocShellIsActive(bool aIsActive);
 
   bool CreateRemoteLayerManager(
       mozilla::layers::PCompositorBridgeChild* aCompositorChild);
 
   nsresult PrepareProgressListenerData(nsIWebProgress* aWebProgress,
                                        nsIRequest* aRequest,
-                                       WebProgressData& aWebProgressData,
+                                       Maybe<WebProgressData>& aWebProgressData,
                                        RequestData& aRequestData);
 
   class DelayedDeleteRunnable;
 
   TextureFactoryIdentifier mTextureFactoryIdentifier;
   RefPtr<nsWebBrowser> mWebBrowser;
   nsCOMPtr<nsIWebNavigation> mWebNav;
   RefPtr<mozilla::dom::TabGroup> mTabGroup;
   RefPtr<PuppetWidget> mPuppetWidget;
   nsCOMPtr<nsIURI> mLastURI;
   RefPtr<ContentChild> mManager;
   RefPtr<BrowsingContext> mBrowsingContext;
+  RefPtr<nsBrowserStatusFilter> mStatusFilter;
   uint32_t mChromeFlags;
   uint32_t mMaxTouchPoints;
   layers::LayersId mLayersId;
   int64_t mBeforeUnloadListeners;
   CSSRect mUnscaledOuterRect;
   Maybe<bool> mLayersConnected;
   bool mDidFakeShow;
   bool mNotified;
   bool mTriedBrowserInit;
   hal::ScreenOrientation mOrientation;
 
   bool mIgnoreKeyPressEvent;
   RefPtr<APZEventState> mAPZEventState;
   SetAllowedTouchBehaviorCallback mSetAllowedTouchBehaviorCallback;
   bool mHasValidInnerSize;
   bool mDestroyed;
-  bool mProgressListenerRegistered;
+
   // Position of client area relative to the outer window
   LayoutDeviceIntPoint mClientOffset;
   // Position of tab, relative to parent widget (typically the window)
   LayoutDeviceIntPoint mChromeOffset;
   TabId mUniqueId;
 
   // Whether or not this tab has siblings (other tabs in the same window).
   // This is one factor used when choosing to allow or deny a non-system
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -17,16 +17,18 @@
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/DataTransfer.h"
 #include "mozilla/dom/DataTransferItemList.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/indexedDB/ActorsParent.h"
 #include "mozilla/dom/IPCBlobUtils.h"
 #include "mozilla/dom/PaymentRequestParent.h"
 #include "mozilla/dom/BrowserBridgeParent.h"
+#include "mozilla/dom/RemoteWebProgress.h"
+#include "mozilla/dom/RemoteWebProgressRequest.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/DataSurfaceHelpers.h"
 #include "mozilla/gfx/GPUProcessManager.h"
 #include "mozilla/Hal.h"
 #include "mozilla/IMEStateManager.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
 #include "mozilla/layers/AsyncDragMetrics.h"
@@ -2204,41 +2206,134 @@ mozilla::ipc::IPCResult TabParent::RecvR
   if (registrar) {
     registrar->RegisterProtocolHandler(aScheme, aHandlerURI, aTitle, aDocURI,
                                        mFrameElement);
   }
 
   return IPC_OK();
 }
 
+mozilla::ipc::IPCResult TabParent::RecvOnProgressChange(
+    const Maybe<WebProgressData>& aWebProgressData,
+    const RequestData& aRequestData, const int32_t aCurSelfProgress,
+    const int32_t aMaxSelfProgress, const int32_t aCurTotalProgress,
+    const int32_t aMaxTotalProgress) {
+  nsCOMPtr<nsIBrowser> browser =
+      mFrameElement ? mFrameElement->AsBrowser() : nullptr;
+
+  if (!browser) {
+    return IPC_OK();
+  }
+
+  nsCOMPtr<nsIWebProgress> manager;
+  nsresult rv = browser->GetRemoteWebProgressManager(getter_AddRefs(manager));
+  NS_ENSURE_SUCCESS(rv, IPC_OK());
+
+  nsCOMPtr<nsIWebProgressListener> managerAsListener =
+      do_QueryInterface(manager);
+
+  if (!managerAsListener) {
+    // We are no longer remote, so we cannot propagate this message.
+    return IPC_OK();
+  }
+
+  nsCOMPtr<nsIWebProgress> webProgress;
+  nsCOMPtr<nsIRequest> request;
+  ReconstructWebProgressAndRequest(manager, aWebProgressData, aRequestData,
+                                   webProgress, request);
+
+  Unused << managerAsListener->OnProgressChange(
+      webProgress, request, aCurSelfProgress, aMaxSelfProgress,
+      aCurTotalProgress, aMaxTotalProgress);
+
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TabParent::RecvOnStatusChange(
+    const Maybe<WebProgressData>& aWebProgressData,
+    const RequestData& aRequestData, const nsresult aStatus,
+    const nsString& aMessage) {
+  nsCOMPtr<nsIBrowser> browser =
+      mFrameElement ? mFrameElement->AsBrowser() : nullptr;
+
+  if (!browser) {
+    return IPC_OK();
+  }
+
+  nsCOMPtr<nsIWebProgress> manager;
+  nsresult rv = browser->GetRemoteWebProgressManager(getter_AddRefs(manager));
+  NS_ENSURE_SUCCESS(rv, IPC_OK());
+
+  nsCOMPtr<nsIWebProgressListener> managerAsListener =
+      do_QueryInterface(manager);
+
+  if (!managerAsListener) {
+    // We are no longer remote, so we cannot propagate this message.
+    return IPC_OK();
+  }
+
+  nsCOMPtr<nsIWebProgress> webProgress;
+  nsCOMPtr<nsIRequest> request;
+  ReconstructWebProgressAndRequest(manager, aWebProgressData, aRequestData,
+                                   webProgress, request);
+
+  Unused << managerAsListener->OnStatusChange(webProgress, request, aStatus,
+                                              aMessage.get());
+
+  return IPC_OK();
+}
+
 mozilla::ipc::IPCResult TabParent::RecvOnContentBlockingEvent(
     const Maybe<WebProgressData>& aWebProgressData,
     const RequestData& aRequestData, const uint32_t& aEvent) {
   nsCOMPtr<nsIBrowser> browser =
       mFrameElement ? mFrameElement->AsBrowser() : nullptr;
   if (browser) {
-    if (aWebProgressData.isNothing()) {
-      Unused << browser->CallWebProgressContentBlockingEventListeners(
-          false, false, false, 0, 0, aRequestData.requestURI(),
-          aRequestData.originalRequestURI(), aRequestData.matchedList(),
-          aEvent);
-    } else {
-      Unused << browser->CallWebProgressContentBlockingEventListeners(
-          true, aWebProgressData.ref().isTopLevel(),
-          aWebProgressData.ref().isLoadingDocument(),
-          aWebProgressData.ref().loadType(),
-          aWebProgressData.ref().DOMWindowID(), aRequestData.requestURI(),
-          aRequestData.originalRequestURI(), aRequestData.matchedList(),
-          aEvent);
+    nsCOMPtr<nsIWebProgress> manager;
+    nsresult rv = browser->GetRemoteWebProgressManager(getter_AddRefs(manager));
+    NS_ENSURE_SUCCESS(rv, IPC_OK());
+
+    nsCOMPtr<nsIWebProgressListener> managerAsListener =
+        do_QueryInterface(manager);
+    if (!managerAsListener) {
+      // We are no longer remote, so we cannot propagate this message.
+      return IPC_OK();
     }
+
+    nsCOMPtr<nsIWebProgress> webProgress;
+    nsCOMPtr<nsIRequest> request;
+    ReconstructWebProgressAndRequest(manager, aWebProgressData, aRequestData,
+                                     webProgress, request);
+
+    Unused << managerAsListener->OnContentBlockingEvent(webProgress, request,
+                                                        aEvent);
   }
 
   return IPC_OK();
 }
 
+void TabParent::ReconstructWebProgressAndRequest(
+    nsIWebProgress* aManager, const Maybe<WebProgressData>& aWebProgressData,
+    const RequestData& aRequestData, nsCOMPtr<nsIWebProgress>& aOutWebProgress,
+    nsCOMPtr<nsIRequest>& aOutRequest) {
+  if (aWebProgressData) {
+    aOutWebProgress = MakeAndAddRef<RemoteWebProgress>(
+        aManager, aWebProgressData->outerDOMWindowID(),
+        aWebProgressData->innerDOMWindowID(), aWebProgressData->loadType(),
+        aWebProgressData->isLoadingDocument(), aWebProgressData->isTopLevel());
+  } else {
+    aOutWebProgress =
+        MakeAndAddRef<RemoteWebProgress>(aManager, 0, 0, 0, false, false);
+  }
+
+  aOutRequest = MakeAndAddRef<RemoteWebProgressRequest>(
+      aRequestData.requestURI(), aRequestData.originalRequestURI(),
+      aRequestData.matchedList());
+}
+
 bool TabParent::HandleQueryContentEvent(WidgetQueryContentEvent& aEvent) {
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
     return true;
   }
   if (NS_WARN_IF(!mContentCache.HandleQueryContentEvent(aEvent, widget)) ||
       NS_WARN_IF(!aEvent.mSucceeded)) {
     return true;
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -164,20 +164,37 @@ class TabParent final : public PBrowserP
 
   mozilla::ipc::IPCResult RecvSetHasBeforeUnload(const bool& aHasBeforeUnload);
 
   mozilla::ipc::IPCResult RecvRegisterProtocolHandler(const nsString& aScheme,
                                                       nsIURI* aHandlerURI,
                                                       const nsString& aTitle,
                                                       nsIURI* aDocURI);
 
+  mozilla::ipc::IPCResult RecvOnProgressChange(
+      const Maybe<WebProgressData>& aWebProgressData,
+      const RequestData& aRequestData, const int32_t aCurSelfProgress,
+      const int32_t aMaxSelfProgress, const int32_t aCurTotalProgres,
+      const int32_t aMaxTotalProgress);
+
+  mozilla::ipc::IPCResult RecvOnStatusChange(
+      const Maybe<WebProgressData>& aWebProgressData,
+      const RequestData& aRequestData, const nsresult aStatus,
+      const nsString& aMessage);
+
   mozilla::ipc::IPCResult RecvOnContentBlockingEvent(
       const Maybe<WebProgressData>& aWebProgressData,
       const RequestData& aRequestData, const uint32_t& aEvent);
 
+  void ReconstructWebProgressAndRequest(
+      nsIWebProgress* aManager, const Maybe<WebProgressData>& aWebProgressData,
+      const RequestData& aRequestData,
+      nsCOMPtr<nsIWebProgress>& aOutWebProgress,
+      nsCOMPtr<nsIRequest>& aOutRequest);
+
   mozilla::ipc::IPCResult RecvBrowserFrameOpenWindow(
       PBrowserParent* aOpener, const nsString& aURL, const nsString& aName,
       const nsString& aFeatures, BrowserFrameOpenWindowResolver&& aResolve);
 
   mozilla::ipc::IPCResult RecvSyncMessage(
       const nsString& aMessage, const ClonedMessageData& aData,
       InfallibleTArray<CpowEntry>&& aCpows, const IPC::Principal& aPrincipal,
       nsTArray<ipc::StructuredCloneData>* aRetVal);
--- a/dom/ipc/WindowGlobalChild.cpp
+++ b/dom/ipc/WindowGlobalChild.cpp
@@ -1,23 +1,32 @@
 /* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
 /* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
 /* 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 "mozilla/dom/WindowGlobalChild.h"
-#include "mozilla/ipc/InProcessChild.h"
+
+#include "mozilla/ClearOnShutdown.h"
 #include "mozilla/dom/BrowsingContext.h"
+#include "mozilla/dom/TabChild.h"
 #include "mozilla/dom/WindowGlobalActorsBinding.h"
+#include "mozilla/dom/WindowGlobalParent.h"
+#include "mozilla/ipc/InProcessChild.h"
+#include "nsDocShell.h"
+#include "nsGlobalWindowInner.h"
 
 #include "mozilla/dom/JSWindowActorBinding.h"
 #include "mozilla/dom/JSWindowActorChild.h"
 #include "mozilla/dom/JSWindowActorService.h"
 
+using namespace mozilla::ipc;
+using namespace mozilla::dom::ipc;
+
 namespace mozilla {
 namespace dom {
 
 typedef nsRefPtrHashtable<nsUint64HashKey, WindowGlobalChild> WGCByIdMap;
 static StaticAutoPtr<WGCByIdMap> gWindowGlobalChildById;
 
 WindowGlobalChild::WindowGlobalChild(nsGlobalWindowInner* aWindow,
                                      dom::BrowsingContext* aBrowsingContext)
@@ -216,9 +225,9 @@ nsISupports* WindowGlobalChild::GetParen
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WindowGlobalChild, mWindowGlobal,
                                       mBrowsingContext, mWindowActors)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WindowGlobalChild, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WindowGlobalChild, Release)
 
 }  // namespace dom
-}  // namespace mozilla
\ No newline at end of file
+}  // namespace mozilla
--- a/dom/ipc/WindowGlobalParent.cpp
+++ b/dom/ipc/WindowGlobalParent.cpp
@@ -1,29 +1,41 @@
 /* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
 /* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
 /* 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 "mozilla/dom/WindowGlobalParent.h"
+
+#include "mozilla/ClearOnShutdown.h"
 #include "mozilla/ipc/InProcessParent.h"
 #include "mozilla/dom/CanonicalBrowsingContext.h"
+#include "mozilla/dom/ContentParent.h"
+#include "mozilla/dom/TabParent.h"
 #include "mozilla/dom/WindowGlobalActorsBinding.h"
+#include "mozilla/dom/WindowGlobalChild.h"
 #include "mozilla/dom/ChromeUtils.h"
+#include "mozilla/dom/ipc/IdType.h"
+#include "mozilla/dom/ipc/StructuredCloneData.h"
 #include "mozJSComponentLoader.h"
 #include "nsContentUtils.h"
+#include "nsDocShell.h"
 #include "nsError.h"
+#include "nsFrameLoader.h"
+#include "nsFrameLoaderOwner.h"
+#include "nsGlobalWindowInner.h"
 #include "nsQueryObject.h"
 
 #include "mozilla/dom/JSWindowActorBinding.h"
 #include "mozilla/dom/JSWindowActorParent.h"
 #include "mozilla/dom/JSWindowActorService.h"
 
 using namespace mozilla::ipc;
+using namespace mozilla::dom::ipc;
 
 namespace mozilla {
 namespace dom {
 
 typedef nsRefPtrHashtable<nsUint64HashKey, WindowGlobalParent> WGPByIdMap;
 static StaticAutoPtr<WGPByIdMap> gWindowGlobalParentsById;
 
 WindowGlobalParent::WindowGlobalParent(const WindowGlobalInit& aInit,
new file mode 100644
--- /dev/null
+++ b/dom/ipc/components.conf
@@ -0,0 +1,20 @@
+# 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/.
+
+Classes = [
+    {
+        'name': 'RemoteWebProgress',
+        'cid': 'a87eb91c-2a5c-11e9-ac91-d027ecb1fb94',
+        'contract_ids': ['@mozilla.org/dom/remote-web-progress;1'],
+        'type': 'mozilla::dom::RemoteWebProgress',
+        'headers': ['mozilla/dom/RemoteWebProgress.h'],
+    },
+    {
+        'name': 'RemoteWebProgressRequest',
+        'cid': 'eec2e27d-dc1d-4ab3-bed4-63536bd2a21e',
+        'contract_ids': ['@mozilla.org/dom/remote-web-progress-request;1'],
+        'type': 'mozilla::dom::RemoteWebProgressRequest',
+        'headers': ['mozilla/dom/RemoteWebProgressRequest.h'],
+    },
+]
--- a/dom/ipc/moz.build
+++ b/dom/ipc/moz.build
@@ -4,20 +4,26 @@
 # 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/.
 
 with Files("**"):
     BUG_COMPONENT = ("Core", "DOM: Content Processes")
 
 XPIDL_SOURCES += [
     'nsIHangReport.idl',
+    'nsIRemoteWebProgress.idl',
+    'nsIRemoteWebProgressRequest.idl',
 ]
 
 XPIDL_MODULE = 'dom'
 
+XPCOM_MANIFESTS += [
+    'components.conf',
+]
+
 EXTRA_JS_MODULES += [
     'ManifestMessagesChild.jsm',
 ]
 
 EXPORTS.mozilla.dom.ipc += [
     'IdType.h',
     'MemMapSnapshot.h',
     'SharedMap.h',
@@ -42,16 +48,18 @@ EXPORTS.mozilla.dom += [
     'DocShellMessageUtils.h',
     'FilePickerParent.h',
     'JSWindowActorChild.h',
     'JSWindowActorParent.h',
     'JSWindowActorService.h',
     'MemoryReportRequest.h',
     'PermissionMessageUtils.h',
     'ReferrerInfoUtils.h',
+    'RemoteWebProgress.h',
+    'RemoteWebProgressRequest.h',
     'TabChild.h',
     'TabContext.h',
     'TabMessageUtils.h',
     'TabParent.h',
     'URLClassifierChild.h',
     'URLClassifierParent.h',
     'WindowGlobalChild.h',
     'WindowGlobalParent.h',
@@ -81,16 +89,18 @@ UNIFIED_SOURCES += [
     'JSWindowActorService.cpp',
     'MemMapSnapshot.cpp',
     'MemoryReportRequest.cpp',
     'MMPrinter.cpp',
     'PermissionMessageUtils.cpp',
     'PreallocatedProcessManager.cpp',
     'ProcessPriorityManager.cpp',
     'ReferrerInfoUtils.cpp',
+    'RemoteWebProgress.cpp',
+    'RemoteWebProgressRequest.cpp',
     'SharedMap.cpp',
     'SharedStringMap.cpp',
     'StructuredCloneData.cpp',
     'TabChild.cpp',
     'TabContext.cpp',
     'TabMessageUtils.cpp',
     'TabParent.cpp',
     'URLClassifierParent.cpp',
new file mode 100644
--- /dev/null
+++ b/dom/ipc/nsIRemoteWebProgress.idl
@@ -0,0 +1,30 @@
+/* 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 "nsIWebProgress.idl"
+
+[scriptable, uuid(2104bfce-bbbe-4111-aa29-cd7c91d1023b)]
+interface nsIRemoteWebProgress : nsIWebProgress {
+  /**
+   * Initialize the web progress.
+   *
+   * @param aManager The RemoteWebProgressManager for this remote nsIWebProgress.
+   * @param aIsTopLevel Whether or not this is a top-level web progress.
+   */
+  void init(in nsIWebProgress aManager,
+            in boolean aIsTopLevel);
+
+  /**
+   * Update the RemoteWebProgress with values from the content process.
+   *
+   * @param aOuterWindowID The outer window ID.
+   * @param aInnerWindowID The inner window ID.
+   * @param aLoadType The load type.
+   * @param aIsLoadingDocument Whether or not a document is being loaded.
+   */
+  void update(in uint64_t aOuterWindowID,
+              in uint64_t aInnerWindowID,
+              in uint32_t aLoadType,
+              in boolean aIsLoadingDocument);
+};
new file mode 100644
--- /dev/null
+++ b/dom/ipc/nsIRemoteWebProgressRequest.idl
@@ -0,0 +1,15 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsISupports.idl"
+
+interface nsIURI;
+
+[scriptable, uuid(e14ff4c2-7e26-4748-8755-dfd074b9c746)]
+interface nsIRemoteWebProgressRequest : nsISupports
+{
+  void init(in nsIURI aURI,
+            in nsIURI aOriginalURI,
+            in ACString aMatchedList);
+};
--- a/dom/media/tests/mochitest/pc.js
+++ b/dom/media/tests/mochitest/pc.js
@@ -1649,17 +1649,17 @@ PeerConnectionWrapper.prototype = {
           return null;
         }
       }
       return report;
     }
     let attempts = 0;
     // Time-units are MS
     const waitPeriod = 500;
-    const maxTime = 15000;
+    const maxTime = 20000;
     for (let totalTime = maxTime; totalTime > 0; totalTime -= waitPeriod) {
       try {
         let syncedStats = await ensureSyncedRtcp();
         if (syncedStats) {
           return syncedStats;
         }
       } catch (e) {
           info(e);
--- a/dom/media/webaudio/AudioWorkletNode.cpp
+++ b/dom/media/webaudio/AudioWorkletNode.cpp
@@ -11,20 +11,23 @@
 #include "mozilla/dom/MessagePort.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(AudioWorkletNode, AudioNode)
 
 AudioWorkletNode::AudioWorkletNode(AudioContext* aAudioContext,
-                                   const nsAString& aName)
+                                   const nsAString& aName,
+                                   const AudioWorkletNodeOptions& aOptions)
     : AudioNode(aAudioContext, 2, ChannelCountMode::Max,
                 ChannelInterpretation::Speakers),
-      mNodeName(aName) {}
+      mNodeName(aName),
+      mInputCount(aOptions.mNumberOfInputs),
+      mOutputCount(aOptions.mNumberOfOutputs) {}
 
 /* static */
 already_AddRefed<AudioWorkletNode> AudioWorkletNode::Constructor(
     const GlobalObject& aGlobal, AudioContext& aAudioContext,
     const nsAString& aName, const AudioWorkletNodeOptions& aOptions,
     ErrorResult& aRv) {
   if (aOptions.mNumberOfInputs == 0 && aOptions.mNumberOfOutputs == 0) {
     aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
@@ -52,18 +55,30 @@ already_AddRefed<AudioWorkletNode> Audio
    */
   const AudioParamDescriptorMap* parameterDescriptors =
       aAudioContext.GetParamMapForWorkletName(aName);
   if (!parameterDescriptors) {
     aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     return nullptr;
   }
 
+  // MSG does not support more than UINT16_MAX inputs or outputs.
+  if (aOptions.mNumberOfInputs > UINT16_MAX) {
+    aRv.ThrowRangeError<MSG_VALUE_OUT_OF_RANGE>(
+        NS_LITERAL_STRING("numberOfInputs"));
+    return nullptr;
+  }
+  if (aOptions.mNumberOfOutputs > UINT16_MAX) {
+    aRv.ThrowRangeError<MSG_VALUE_OUT_OF_RANGE>(
+        NS_LITERAL_STRING("numberOfOutputs"));
+    return nullptr;
+  }
+
   RefPtr<AudioWorkletNode> audioWorkletNode =
-      new AudioWorkletNode(&aAudioContext, aName);
+      new AudioWorkletNode(&aAudioContext, aName, aOptions);
 
   audioWorkletNode->Initialize(aOptions, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   return audioWorkletNode.forget();
 }
--- a/dom/media/webaudio/AudioWorkletNode.h
+++ b/dom/media/webaudio/AudioWorkletNode.h
@@ -29,24 +29,30 @@ class AudioWorkletNode : public AudioNod
 
   AudioParamMap* GetParameters(ErrorResult& aRv) const;
 
   MessagePort* GetPort(ErrorResult& aRv) const;
 
   JSObject* WrapObject(JSContext* aCx,
                        JS::Handle<JSObject*> aGivenProto) override;
 
+  // AudioNode methods
+  uint16_t NumberOfInputs() const override { return mInputCount; }
+  uint16_t NumberOfOutputs() const override { return mOutputCount; }
   const char* NodeType() const override { return "AudioWorkletNode"; }
 
   size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override;
   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override;
 
  private:
-  AudioWorkletNode(AudioContext* aAudioContext, const nsAString& aName);
+  AudioWorkletNode(AudioContext* aAudioContext, const nsAString& aName,
+                   const AudioWorkletNodeOptions& aOptions);
   ~AudioWorkletNode() = default;
 
   nsString mNodeName;
+  uint16_t mInputCount;
+  uint16_t mOutputCount;
 };
 
 }  // namespace dom
 }  // namespace mozilla
 
-#endif  // AudioWorkletNode_h_
\ No newline at end of file
+#endif  // AudioWorkletNode_h_
--- a/dom/media/webaudio/test/mochitest.ini
+++ b/dom/media/webaudio/test/mochitest.ini
@@ -59,16 +59,17 @@ skip-if = (toolkit == 'android' && debug
 [test_audioBufferSourceNodeOffset.html]
 skip-if = (toolkit == 'android') || debug #bug 906752
 [test_audioBufferSourceNodePassThrough.html]
 [test_audioBufferSourceNodeRate.html]
 [test_AudioContext.html]
 [test_AudioContext_disabled.html]
 [test_audioContextSuspendResumeClose.html]
 tags=capturestream
+skip-if = (os == "win" && processor == "aarch64") # aarch64 due to 1539522
 [test_audioDestinationNode.html]
 [test_AudioListener.html]
 [test_AudioNodeDevtoolsAPI.html]
 [test_audioParamChaining.html]
 [test_AudioParamDevtoolsAPI.html]
 [test_audioParamExponentialRamp.html]
 [test_audioParamGain.html]
 [test_audioParamLinearRamp.html]
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -46,16 +46,17 @@ using mozilla::DefaultXDisplay;
 #include "nsIDocShell.h"
 #include "ImageContainer.h"
 #include "GLContext.h"
 #include "EGLUtils.h"
 #include "nsIContentInlines.h"
 #include "mozilla/MiscEvents.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/NullPrincipal.h"
+#include "mozilla/PresShell.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/dom/DocumentInlines.h"
 #include "mozilla/dom/DragEvent.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/HTMLObjectElementBinding.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/dom/WheelEventBinding.h"
--- a/dom/plugins/ipc/PPluginInstance.ipdl
+++ b/dom/plugins/ipc/PPluginInstance.ipdl
@@ -61,17 +61,17 @@ intr protocol PPluginInstance
 
   manages PPluginBackgroundDestroyer;
   manages PPluginScriptableObject;
   manages PBrowserStream;
   manages PStreamNotify;
   manages PPluginSurface;
 
 child:
-  intr __delete__();
+  async __delete__();
 
   // This is only used on Windows and, for windowed plugins, must be called
   // before the first call to NPP_SetWindow.
   intr CreateChildPluginWindow()
     returns (NativeWindowHandle childPluginWindow);
 
   // This is only used on Windows and, for windowless plugins.
   async CreateChildPopupSurrogate(NativeWindowHandle netscapeWindow);
--- a/dom/plugins/ipc/PluginInstanceChild.cpp
+++ b/dom/plugins/ipc/PluginInstanceChild.cpp
@@ -335,18 +335,18 @@ NPError PluginInstanceChild::InternalGet
                  "Cached actor is out of date!");
   }
 #endif
 
   if (result != NPERR_NO_ERROR) {
     return result;
   }
 
-  NPObject* object = actor->GetObject(false);
-  if (!actor->GetObject(false)) {
+  NPObject* object;
+  if (!(object = actor->GetObject(false))) {
     return NPERR_GENERIC_ERROR;
   }
 
   *aObject = PluginModuleChild::sBrowserFuncs.retainobject(object);
   return NPERR_NO_ERROR;
 }
 
 NPError PluginInstanceChild::NPN_GetValue(NPNVariable aVar, void* aValue) {
--- a/dom/plugins/ipc/PluginModuleChild.cpp
+++ b/dom/plugins/ipc/PluginModuleChild.cpp
@@ -1668,16 +1668,20 @@ NPObject* PluginModuleChild::NPN_CreateO
   PluginScriptableObjectChild::RegisterObject(newObject, i);
 
   return newObject;
 }
 
 NPObject* PluginModuleChild::NPN_RetainObject(NPObject* aNPObj) {
   AssertPluginThread();
 
+  if (NS_WARN_IF(!aNPObj)) {
+    return nullptr;
+  }
+
 #ifdef NS_BUILD_REFCNT_LOGGING
   int32_t refCnt =
 #endif
       PR_ATOMIC_INCREMENT((int32_t*)&aNPObj->referenceCount);
   NS_LOG_ADDREF(aNPObj, refCnt, "NPObject", sizeof(NPObject));
 
   return aNPObj;
 }
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -1484,17 +1484,17 @@ NPError PluginModuleParent::NPP_Destroy(
 
   PLUGIN_LOG_DEBUG_FUNCTION;
   PluginInstanceParent* pip = PluginInstanceParent::Cast(instance);
   if (!pip) return NPERR_NO_ERROR;
 
   NPError retval = pip->Destroy();
   instance->pdata = nullptr;
 
-  Unused << PluginInstanceParent::Call__delete__(pip);
+  Unused << PluginInstanceParent::Send__delete__(pip);
   return retval;
 }
 
 NPError PluginModuleParent::NPP_NewStream(NPP instance, NPMIMEType type,
                                           NPStream* stream, NPBool seekable,
                                           uint16_t* stype) {
   AUTO_PROFILER_LABEL("PluginModuleParent::NPP_NewStream", OTHER);
 
--- a/dom/plugins/test/mochitest/mochitest.ini
+++ b/dom/plugins/test/mochitest/mochitest.ini
@@ -58,17 +58,17 @@ skip-if = toolkit == 'android' # needs p
 [test_bug985859.html]
 [test_bug986930.html]
 [test_bug1092842.html]
 skip-if = (verify && (os == 'win'))
 [test_bug1165981.html]
 skip-if = (processor == 'aarch64' && os == 'win') # aarch64 due to 1538785
 [test_bug1245545.html]
 [test_bug1307694.html]
-skip-if = verify
+skip-if = verify || (processor == 'aarch64' && os == 'win') # aarch64 due to 1541241
 [test_cocoa_focus.html]
 skip-if = toolkit != "cocoa" || e10s # Bug 1194534
 support-files = cocoa_focus.html
 [test_cocoa_window_focus.html]
 skip-if = toolkit != "cocoa" # Bug 1194534
 support-files = cocoa_window_focus.html
 [test_copyText.html]
 skip-if = toolkit != "gtk3"
--- a/dom/security/test/cors/test_CrossSiteXHR.html
+++ b/dom/security/test/cors/test_CrossSiteXHR.html
@@ -755,25 +755,19 @@ function* runTest() {
         "should have failed in test for " + test.toSource());
       is(res.status, 0, "wrong status in test for " + test.toSource());
       is(res.statusText, "", "wrong status text for " + test.toSource());
       is(res.responseXML, null,
          "wrong responseXML in test for " + test.toSource());
       is(res.responseText, "",
          "wrong responseText in test for " + test.toSource());
       if (!res.sendThrew) {
-        if (test.username || test.password) {
-          is(res.events.join(","),
-             "opening,rs1,sending,loadstart,rs4,error,loadend",
-             "wrong events in test for " + test.toSource());
-        } else {
-          is(res.events.join(","),
-             "opening,rs1,sending,loadstart,rs2,rs4,error,loadend",
-             "wrong events in test for " + test.toSource());
-        }
+        is(res.events.join(","),
+           "opening,rs1,sending,loadstart,rs4,error,loadend",
+           "wrong events in test for " + test.toSource());
       }
       is(res.progressEvents, 0,
          "wrong events in test for " + test.toSource());
       if (test.responseHeaders) {
         for (header in test.responseHeaders) {
           is(res.responseHeaders[header], null,
              "wrong response header (" + header + ") in test for " +
              test.toSource());
@@ -903,17 +897,17 @@ function* runTest() {
         "should have failed in test for " + test.toSource());
       is(res.status, 0, "wrong status in test for " + test.toSource());
       is(res.statusText, "", "wrong status text for " + test.toSource());
       is(res.responseXML, null,
          "wrong responseXML in test for " + test.toSource());
       is(res.responseText, "",
          "wrong responseText in test for " + test.toSource());
       is(res.events.join(","),
-         "opening,rs1,sending,loadstart,rs2,rs4,error,loadend",
+         "opening,rs1,sending,loadstart,rs4,error,loadend",
          "wrong events in test for " + test.toSource());
       is(res.progressEvents, 0,
          "wrong events in test for " + test.toSource());
     }
   }
 
   // Make sure to clear cookies to avoid affecting other tests
   document.cookie = "a=; path=/; expires=Thu, 01-Jan-1970 00:00:01 GMT"
@@ -1469,17 +1463,17 @@ function* runTest() {
         "should have failed in test for " + test.toSource());
       is(res.status, 0, "wrong status in test for " + test.toSource());
       is(res.statusText, "", "wrong status text for " + test.toSource());
       is(res.responseXML, null,
          "wrong responseXML in test for " + test.toSource());
       is(res.responseText, "",
          "wrong responseText in test for " + test.toSource());
       is(res.events.join(","),
-         "opening,rs1,sending,loadstart,rs2,rs4,error,loadend",
+         "opening,rs1,sending,loadstart,rs4,error,loadend",
          "wrong events in test for " + test.toSource());
       is(res.progressEvents, 0,
          "wrong progressevents in test for " + test.toSource());
     }
   }
 
 
   SimpleTest.finish();
--- a/dom/security/test/cors/test_CrossSiteXHR_cache.html
+++ b/dom/security/test/cors/test_CrossSiteXHR_cache.html
@@ -568,17 +568,17 @@ function* runTest() {
       is(res.didFail, true,
         "should have failed in test for " + testName);
       is(res.status, 0, "wrong status in test for " + testName);
       is(res.responseXML, null,
          "wrong responseXML in test for " + testName);
       is(res.responseText, "",
          "wrong responseText in test for " + testName);
       is(res.events.join(","),
-         "opening,rs1,sending,loadstart,rs2,rs4,error,loadend",
+         "opening,rs1,sending,loadstart,rs4,error,loadend",
          "wrong events in test for " + testName);
       is(res.progressEvents, 0,
          "wrong events in test for " + testName);
     }
   }
 
   SimpleTest.finish();
 }
--- a/dom/security/test/cors/test_CrossSiteXHR_origin.html
+++ b/dom/security/test/cors/test_CrossSiteXHR_origin.html
@@ -143,17 +143,17 @@ function* runTest() {
 
       res = eval(yield);
       is(res.didFail, true, "should have failed for " + allowOrigin);
       is(res.responseText, "", "should have no text for " + allowOrigin);
       is(res.status, 0, "should have no status for " + allowOrigin);
       is(res.statusText, "", "wrong status text for " + allowOrigin);
       is(res.responseXML, null, "should have no XML for " + allowOrigin);
       is(res.events.join(","),
-         "opening,rs1,sending,loadstart,rs2,rs4,error,loadend",
+         "opening,rs1,sending,loadstart,rs4,error,loadend",
          "wrong events in test for " + allowOrigin);
       is(res.progressEvents, 0,
          "wrong events in test for " + allowOrigin);
     }
   }
 
   SimpleTest.finish();
 }
--- a/dom/serviceworkers/ServiceWorkerScriptCache.cpp
+++ b/dom/serviceworkers/ServiceWorkerScriptCache.cpp
@@ -1276,16 +1276,33 @@ void CompareManager::Cleanup() {
     // Abort and release CompareNetworks.
     for (uint32_t i = 0; i < mCNList.Length(); ++i) {
       mCNList[i]->Abort();
     }
     mCNList.Clear();
   }
 }
 
+class NoopPromiseHandler final : public PromiseNativeHandler {
+ public:
+  NS_DECL_ISUPPORTS
+
+  NoopPromiseHandler() { AssertIsOnMainThread(); }
+
+  void ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override {
+  }
+  void RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override {
+  }
+
+ private:
+  ~NoopPromiseHandler() { AssertIsOnMainThread(); }
+};
+
+NS_IMPL_ISUPPORTS0(NoopPromiseHandler)
+
 }  // namespace
 
 nsresult PurgeCache(nsIPrincipal* aPrincipal, const nsAString& aCacheName) {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aPrincipal);
 
   if (aCacheName.IsEmpty()) {
     return NS_OK;
@@ -1301,16 +1318,21 @@ nsresult PurgeCache(nsIPrincipal* aPrinc
   }
 
   // We use the ServiceWorker scope as key for the cacheStorage.
   RefPtr<Promise> promise = cacheStorage->Delete(aCacheName, rv);
   if (NS_WARN_IF(rv.Failed())) {
     return rv.StealNSResult();
   }
 
+  // Add a no-op promise handler to ensure that if this promise gets rejected,
+  // we don't end up reporting a rejected promise to the console.
+  RefPtr<NoopPromiseHandler> promiseHandler = new NoopPromiseHandler();
+  promise->AppendNativeHandler(promiseHandler);
+
   // We don't actually care about the result of the delete operation.
   return NS_OK;
 }
 
 nsresult GenerateCacheName(nsAString& aName) {
   nsresult rv;
   nsCOMPtr<nsIUUIDGenerator> uuidGenerator =
       do_GetService("@mozilla.org/uuid-generator;1", &rv);
--- a/dom/serviceworkers/test/test_serviceworker_interfaces.js
+++ b/dom/serviceworkers/test/test_serviceworker_interfaces.js
@@ -23,16 +23,18 @@
 //            a JavaScript Engine peer!
 var ecmaGlobals =
   [
     "Array",
     "ArrayBuffer",
     {name: "Atomics", disabled: true},
     "Boolean",
     {name: "BigInt", nightly: true},
+    {name: "BigInt64Array", nightly: true},
+    {name: "BigUint64Array", nightly: true},
     {name: "ByteLengthQueuingStrategy", optional: true},
     {name: "CountQueuingStrategy", optional: true},
     "DataView",
     "Date",
     "Error",
     "EvalError",
     "Float32Array",
     "Float64Array",
--- a/dom/smil/SMILCSSValueType.cpp
+++ b/dom/smil/SMILCSSValueType.cpp
@@ -11,16 +11,17 @@
 #include "nsComputedDOMStyle.h"
 #include "nsColor.h"
 #include "nsCSSProps.h"
 #include "nsCSSValue.h"
 #include "nsDebug.h"
 #include "nsPresContext.h"
 #include "nsString.h"
 #include "nsStyleUtil.h"
+#include "nsIPresShellInlines.h"
 #include "mozilla/DeclarationBlock.h"
 #include "mozilla/ServoBindings.h"
 #include "mozilla/StyleAnimationValue.h"
 #include "mozilla/ServoCSSParser.h"
 #include "mozilla/ServoStyleSet.h"
 #include "mozilla/SMILParserUtils.h"
 #include "mozilla/SMILValue.h"
 #include "mozilla/dom/BaseKeyframeTypesBinding.h"
--- a/dom/tests/mochitest/general/test_interfaces.js
+++ b/dom/tests/mochitest/general/test_interfaces.js
@@ -40,16 +40,18 @@ const isFennec = isAndroid && SpecialPow
 // IMPORTANT: Do not change this list without review from
 //            a JavaScript Engine peer!
 var ecmaGlobals =
   [
     {name: "Array", insecureContext: true},
     {name: "ArrayBuffer", insecureContext: true},
     {name: "Atomics", insecureContext: true, disabled: true},
     {name: "BigInt", insecureContext: true, nightly: true},
+    {name: "BigInt64Array", insecureContext: true, nightly: true},
+    {name: "BigUint64Array", insecureContext: true, nightly: true},
     {name: "Boolean", insecureContext: true},
     {name: "ByteLengthQueuingStrategy", insecureContext: true},
     {name: "CountQueuingStrategy", insecureContext: true},
     {name: "DataView", insecureContext: true},
     {name: "Date", insecureContext: true},
     {name: "Error", insecureContext: true},
     {name: "EvalError", insecureContext: true},
     {name: "Float32Array", insecureContext: true},
--- a/dom/vr/VRDisplay.cpp
+++ b/dom/vr/VRDisplay.cpp
@@ -321,17 +321,17 @@ VRDisplay::VRDisplay(nsPIDOMWindowInner*
       mDepthNear(0.01f)  // Default value from WebVR Spec
       ,
       mDepthFar(10000.0f)  // Default value from WebVR Spec
       ,
       mVRNavigationEventDepth(0),
       mShutdown(false) {
   const gfx::VRDisplayInfo& info = aClient->GetDisplayInfo();
   mDisplayId = info.GetDisplayID();
-  mDisplayName = NS_ConvertASCIItoUTF16(info.GetDisplayName());
+  mDisplayName = NS_ConvertUTF8toUTF16(info.GetDisplayName());
   mCapabilities = new VRDisplayCapabilities(aWindow, info.GetCapabilities());
   if (info.GetCapabilities() &
       gfx::VRDisplayCapabilityFlags::Cap_StageParameters) {
     mStageParameters = new VRStageParameters(
         aWindow, info.GetSittingToStandingTransform(), info.GetStageSize());
   }
   mozilla::HoldJSObjects(this);
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
--- a/dom/vr/test/mochitest/test_vrController_displayId.html
+++ b/dom/vr/test/mochitest/test_vrController_displayId.html
@@ -22,31 +22,33 @@
           });
         }, "Finish to add VRController.");
       }
 
       function listenControllerEvents() {
         async_test(function(t) {