Merge mozilla-central to mozilla-inbound. a=merge on a CLOSED TREE
authorRazvan Maries <rmaries@mozilla.com>
Thu, 14 Mar 2019 23:50:44 +0200
changeset 522008 afd8d968a200
parent 522007 d57a9605a6d1 (current diff)
parent 521970 49d94c83bb22 (diff)
child 522009 3befa22661a8
push id10870
push usernbeleuzu@mozilla.com
push dateFri, 15 Mar 2019 20:00:07 +0000
treeherdermozilla-beta@c594aee5b7a4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to mozilla-inbound. a=merge on a CLOSED TREE
dom/base/Document.h
--- a/.eslintignore
+++ b/.eslintignore
@@ -22,18 +22,16 @@ extensions/spellcheck/**
 extensions/universalchardet/**
 image/**
 layout/**
 netwerk/cookie/test/browser/**
 netwerk/test/browser/**
 netwerk/test/mochitests/**
 netwerk/test/unit*/**
 tools/update-packaging/**
-uriloader/exthandler/**
-uriloader/exthandler/tests/mochitest/**
 xpfe/**
 
 # We currently have no js files in these directories, so we ignore them by
 # default to aid ESLint's performance.
 build/**
 config/**
 db/**
 embedding/**
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1242,17 +1242,19 @@ pref("services.sync.prefs.sync.privacy.c
 pref("services.sync.prefs.sync.privacy.clearOnShutdown.sessions", true);
 pref("services.sync.prefs.sync.privacy.clearOnShutdown.siteSettings", true);
 pref("services.sync.prefs.sync.privacy.donottrackheader.enabled", true);
 pref("services.sync.prefs.sync.privacy.fuzzyfox.enabled", false);
 pref("services.sync.prefs.sync.privacy.fuzzyfox.clockgrainus", false);
 pref("services.sync.prefs.sync.privacy.sanitize.sanitizeOnShutdown", true);
 pref("services.sync.prefs.sync.privacy.trackingprotection.enabled", true);
 pref("services.sync.prefs.sync.privacy.trackingprotection.cryptomining.enabled", true);
+pref("services.sync.prefs.sync.privacy.trackingprotection.cryptomining.annotate.enabled", true);
 pref("services.sync.prefs.sync.privacy.trackingprotection.fingerprinting.enabled", true);
+pref("services.sync.prefs.sync.privacy.trackingprotection.fingerprinting.annotate.enabled", true);
 pref("services.sync.prefs.sync.privacy.trackingprotection.pbmode.enabled", true);
 pref("services.sync.prefs.sync.privacy.resistFingerprinting", true);
 pref("services.sync.prefs.sync.privacy.reduceTimerPrecision", true);
 pref("services.sync.prefs.sync.privacy.resistFingerprinting.reduceTimerPrecision.microseconds", true);
 pref("services.sync.prefs.sync.privacy.resistFingerprinting.reduceTimerPrecision.jitter", true);
 pref("services.sync.prefs.sync.security.OCSP.enabled", true);
 pref("services.sync.prefs.sync.security.OCSP.require", true);
 pref("services.sync.prefs.sync.security.default_personal_cert", true);
--- a/browser/base/content/test/trackingUI/browser_trackingUI_cryptominers.js
+++ b/browser/base/content/test/trackingUI/browser_trackingUI_cryptominers.js
@@ -1,24 +1,27 @@
 /* eslint-disable mozilla/no-arbitrary-setTimeout */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 const TRACKING_PAGE = "http://example.org/browser/browser/base/content/test/trackingUI/trackingPage.html";
-const CM_PREF = "privacy.trackingprotection.cryptomining.enabled";
+const CM_PROTECTION_PREF = "privacy.trackingprotection.cryptomining.enabled";
+const CM_ANNOTATION_PREF = "privacy.trackingprotection.cryptomining.annotate.enabled";
 
 add_task(async function setup() {
   await SpecialPowers.pushPrefEnv({set: [
     [ ContentBlocking.prefIntroCount, ContentBlocking.MAX_INTROS ],
     [ "urlclassifier.features.cryptomining.blacklistHosts", "cryptomining.example.com" ],
+    [ "urlclassifier.features.cryptomining.annotate.blacklistHosts", "cryptomining.example.com" ],
     [ "privacy.trackingprotection.enabled", false ],
     [ "privacy.trackingprotection.annotate_channels", false ],
     [ "privacy.trackingprotection.fingerprinting.enabled", false ],
+    [ "privacy.trackingprotection.fingerprinting.annotate.enabled", false ],
   ]});
 });
 
 async function testIdentityState(hasException) {
   let promise = BrowserTestUtils.openNewForegroundTab({url: TRACKING_PAGE, gBrowser});
   let [tab] = await Promise.all([promise, waitForContentBlockingEvent()]);
 
   if (hasException) {
@@ -99,19 +102,21 @@ async function testSubview(hasException)
     ContentBlocking.enableForCurrentPage();
     await loaded;
   }
 
   BrowserTestUtils.removeTab(tab);
 }
 
 add_task(async function test() {
-  Services.prefs.setBoolPref(CM_PREF, true);
+  Services.prefs.setBoolPref(CM_PROTECTION_PREF, true);
+  Services.prefs.setBoolPref(CM_ANNOTATION_PREF, true);
 
   await testIdentityState(false);
   await testIdentityState(true);
 
   await testSubview(false);
   await testSubview(true);
 
-  Services.prefs.clearUserPref(CM_PREF);
+  Services.prefs.clearUserPref(CM_PROTECTION_PREF);
+  Services.prefs.clearUserPref(CM_ANNOTATION_PREF);
 });
 
--- a/browser/base/content/test/trackingUI/browser_trackingUI_fingerprinters.js
+++ b/browser/base/content/test/trackingUI/browser_trackingUI_fingerprinters.js
@@ -1,24 +1,27 @@
 /* eslint-disable mozilla/no-arbitrary-setTimeout */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 const TRACKING_PAGE = "http://example.org/browser/browser/base/content/test/trackingUI/trackingPage.html";
-const FP_PREF = "privacy.trackingprotection.fingerprinting.enabled";
+const FP_PROTECTION_PREF = "privacy.trackingprotection.fingerprinting.enabled";
+const FP_ANNOTATION_PREF = "privacy.trackingprotection.fingerprinting.annotate.enabled";
 
 add_task(async function setup() {
   await SpecialPowers.pushPrefEnv({set: [
     [ ContentBlocking.prefIntroCount, ContentBlocking.MAX_INTROS ],
     [ "urlclassifier.features.fingerprinting.blacklistHosts", "fingerprinting.example.com" ],
+    [ "urlclassifier.features.fingerprinting.annotate.blacklistHosts", "fingerprinting.example.com" ],
     [ "privacy.trackingprotection.enabled", false ],
     [ "privacy.trackingprotection.annotate_channels", false ],
     [ "privacy.trackingprotection.cryptomining.enabled", false ],
+    [ "privacy.trackingprotection.cryptomining.annotate.enabled", false ],
   ]});
 });
 
 async function testIdentityState(hasException) {
   let promise = BrowserTestUtils.openNewForegroundTab({url: TRACKING_PAGE, gBrowser});
   let [tab] = await Promise.all([promise, waitForContentBlockingEvent()]);
 
   if (hasException) {
@@ -99,19 +102,20 @@ async function testSubview(hasException)
     ContentBlocking.enableForCurrentPage();
     await loaded;
   }
 
   BrowserTestUtils.removeTab(tab);
 }
 
 add_task(async function test() {
-  Services.prefs.setBoolPref(FP_PREF, true);
+  Services.prefs.setBoolPref(FP_PROTECTION_PREF, true);
+  Services.prefs.setBoolPref(FP_ANNOTATION_PREF, true);
 
   await testIdentityState(false);
   await testIdentityState(true);
 
   await testSubview(false);
   await testSubview(true);
 
-  Services.prefs.clearUserPref(FP_PREF);
+  Services.prefs.clearUserPref(FP_PROTECTION_PREF);
+  Services.prefs.clearUserPref(FP_ANNOTATION_PREF);
 });
-
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -17,30 +17,29 @@ file, You can obtain one at http://mozil
 ]>
 
 <bindings id="urlbarBindings" xmlns="http://www.mozilla.org/xbl"
           xmlns:html="http://www.w3.org/1999/xhtml"
           xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
           xmlns:xbl="http://www.mozilla.org/xbl">
 
   <binding id="urlbar" extends="chrome://global/content/bindings/textbox.xml#textbox">
-    <content>
+    <content role="combobox">
       <children includes="box"/>
       <xul:moz-input-box anonid="moz-input-box"
                          tooltip="aHTMLTooltip"
                          class="urlbar-input-box"
                          flex="1">
         <children/>
         <html:input anonid="scheme"
                     class="urlbar-scheme textbox-input"
                     required="required"
                     xbl:inherits="textoverflow,focused"/>
         <html:input anonid="input"
                     class="urlbar-input textbox-input"
-                    role="combobox"
                     aria-owns="urlbarView-results"
                     aria-controls="urlbarView-results"
                     aria-autocomplete="both"
                     allowevents="true"
                     inputmode="mozAwesomebar"
                     xbl:inherits="value,maxlength,disabled,size,readonly,placeholder,tabindex,accesskey,focused,textoverflow"/>
       </xul:moz-input-box>
       <xul:image anonid="urlbar-go-button"
--- a/browser/components/preferences/in-content/tests/browser_subdialogs.js
+++ b/browser/components/preferences/in-content/tests/browser_subdialogs.js
@@ -18,20 +18,26 @@ function open_subdialog_and_test_generic
     let rv = { acceptCount: 0 };
     let win = content.window;
     content.gSubDialog.open(args.url, null, rv);
     let subdialog = content.gSubDialog._topDialog;
 
     info("waiting for subdialog DOMFrameContentLoaded");
     let dialogOpenPromise;
     await new Promise(resolve => {
-      win.addEventListener("DOMFrameContentLoaded", () => {
+      win.addEventListener("DOMFrameContentLoaded", function frameContentLoaded(ev) {
+        // We can get events for loads in other frames, so we have to filter
+        // those out.
+        if (ev.target != subdialog._frame) {
+          return;
+        }
+        win.removeEventListener("DOMFrameContentLoaded", frameContentLoaded);
         dialogOpenPromise = ContentTaskUtils.waitForEvent(subdialog._overlay, "dialogopen");
         resolve();
-      }, { once: true, capture: true });
+      }, { capture: true });
     });
     let result;
     if (args.domcontentloadedFnStr) {
       // eslint-disable-next-line no-eval
       result = eval(args.domcontentloadedFnStr);
     }
 
     info("waiting for subdialog load");
--- a/browser/components/urlbar/UrlbarInput.jsm
+++ b/browser/components/urlbar/UrlbarInput.jsm
@@ -366,17 +366,19 @@ class UrlbarInput {
   pickResult(event, resultIndex) {
     let result = this.view.getResult(resultIndex);
     let isCanonized = this.setValueFromResult(result, event);
     let where = this._whereToOpen(event);
     let openParams = {
       allowInheritPrincipal: false,
     };
 
-    this.view.close();
+    if (!result.payload.isKeywordOffer) {
+      this.view.close();
+    }
     this.controller.recordSelectedResult(event, resultIndex);
 
     if (isCanonized) {
       this._loadURL(this.value, where, openParams);
       return;
     }
 
     let {url, postData} = UrlbarUtils.getUrlFromResult(result);
--- a/browser/components/urlbar/UrlbarProviderUnifiedComplete.jsm
+++ b/browser/components/urlbar/UrlbarProviderUnifiedComplete.jsm
@@ -243,17 +243,17 @@ function makeUrlbarResult(tokens, info) 
             engine: [action.params.engineName, true],
             suggestion: [action.params.searchSuggestion, true],
             keyword: [action.params.alias, true],
             query: [action.params.searchQuery.trim(), true],
             icon: [info.icon, false],
             isKeywordOffer: [
               action.params.alias &&
                 !action.params.searchQuery.trim() &&
-                !info.style.includes("heuristic"),
+                action.params.alias.startsWith("@"),
               false,
             ],
           })
         );
       case "keyword": {
         let title = info.comment;
         if (tokens && tokens.length > 1) {
           title = bundle.formatStringFromName("bookmarkKeywordSearch",
--- a/browser/components/urlbar/UrlbarView.jsm
+++ b/browser/components/urlbar/UrlbarView.jsm
@@ -40,16 +40,17 @@ class UrlbarView {
     this._rows.addEventListener("mousedown", this);
 
     // For the horizontal fade-out effect, set the overflow attribute on result
     // rows when they overflow.
     this._rows.addEventListener("overflow", this);
     this._rows.addEventListener("underflow", this);
 
     this.panel.addEventListener("popupshowing", this);
+    this.panel.addEventListener("popupshown", this);
     this.panel.addEventListener("popuphiding", this);
 
     this.controller.setView(this);
     this.controller.addQueryListener(this);
   }
 
   get oneOffSearchButtons() {
     if (!this._oneOffSearchButtons) {
@@ -652,19 +653,24 @@ class UrlbarView {
       event.target.toggleAttribute("overflow", false);
     }
   }
 
   _on_popupshowing() {
     this.window.addEventListener("resize", this);
   }
 
+  _on_popupshown() {
+    this.input.inputField.setAttribute("aria-expanded", "true");
+  }
+
   _on_popuphiding() {
     this.controller.cancelQuery();
     this.window.removeEventListener("resize", this);
+    this.input.inputField.setAttribute("aria-expanded", "false");
     this.input.inputField.removeAttribute("aria-activedescendant");
   }
 
   _on_resize() {
     // Close the popup as it would be wrongly sized. This can
     // happen when using special OS resize functions like Win+Arrow.
     this.close();
   }
--- a/browser/components/urlbar/tests/browser/browser_urlbarTokenAlias.js
+++ b/browser/components/urlbar/tests/browser/browser_urlbarTokenAlias.js
@@ -206,46 +206,111 @@ add_task(async function nonTokenAlias() 
 
   await UrlbarTestUtils.promisePopupClose(window,
     () => EventUtils.synthesizeKey("KEY_Escape"));
 
   engine.alias = ALIAS;
 });
 
 
-// Clicking on an @ alias in the popup should fill it in the urlbar input.
+// Clicking on an @ alias offer (an @ alias with an empty search string) in the
+// popup should fill it in the urlbar input.
 add_task(async function clickAndFillAlias() {
   // Do a search for "@" to show all the @ aliases.
   gURLBar.search("@");
   await promiseSearchComplete();
 
   // Find our test engine in the results.  It's probably last, but for
   // robustness don't assume it is.
   let testEngineItem;
   for (let i = 0; !testEngineItem; i++) {
     let details = await UrlbarTestUtils.getDetailsOfResultAt(window, i);
     if (details.searchParams && details.searchParams.keyword == ALIAS) {
       testEngineItem = await waitForAutocompleteResultAt(i);
     }
   }
 
   // Click it.
-  await UrlbarTestUtils.promisePopupClose(window, () => {
-    EventUtils.synthesizeMouseAtCenter(testEngineItem, {});
-  });
+  EventUtils.synthesizeMouseAtCenter(testEngineItem, {});
 
   // A new search will start and its result should be the alias.
   await promiseSearchComplete();
   await waitForAutocompleteResultAt(0);
   await assertAlias(true);
 
   // The urlbar input value should be the alias followed by a space so that it's
   // ready for the user to start typing.
   Assert.equal(gURLBar.textValue, `${ALIAS} `);
 
+  // Press the enter key a couple of times.  Nothing should happen except a new
+  // search will start and its result should be the alias again.  The urlbar
+  // should still contain the alias.  An empty search results page should not
+  // load.  The test will hang if that happens.
+  for (let i = 0; i < 2; i++) {
+    EventUtils.synthesizeKey("KEY_Enter");
+    await promiseSearchComplete();
+    await waitForAutocompleteResultAt(0);
+    await assertAlias(true);
+    Assert.equal(gURLBar.textValue, `${ALIAS} `);
+  }
+
+  await UrlbarTestUtils.promisePopupClose(window,
+    () => EventUtils.synthesizeKey("KEY_Escape"));
+});
+
+
+// Pressing enter on an @ alias offer (an @ alias with an empty search string)
+// in the popup should fill it in the urlbar input.
+add_task(async function enterAndFillAlias() {
+  // Do a search for "@" to show all the @ aliases.
+  gURLBar.search("@");
+  await promiseSearchComplete();
+
+  // Find our test engine in the results.  It's probably last, but for
+  // robustness don't assume it is.
+  let index = 0;
+  for (;; index++) {
+    let details = await UrlbarTestUtils.getDetailsOfResultAt(window, index);
+    if (details.searchParams && details.searchParams.keyword == ALIAS) {
+      index++;
+      break;
+    }
+  }
+
+  if (!UrlbarPrefs.get("quantumbar")) {
+    // With awesomebar, the first result ends up preselected, so one fewer key
+    // down is needed to reach the engine.
+    index--;
+  }
+
+  // Key down to it and press enter.
+  EventUtils.synthesizeKey("KEY_ArrowDown", { repeat: index });
+  EventUtils.synthesizeKey("KEY_Enter");
+
+  // A new search will start and its result should be the alias.
+  await promiseSearchComplete();
+  await waitForAutocompleteResultAt(0);
+  await assertAlias(true);
+
+  // The urlbar input value should be the alias followed by a space so that it's
+  // ready for the user to start typing.
+  Assert.equal(gURLBar.textValue, `${ALIAS} `);
+
+  // Press the enter key a couple of times.  Nothing should happen except a new
+  // search will start and its result should be the alias again.  The urlbar
+  // should still contain the alias.  An empty search results page should not
+  // load.  The test will hang if that happens.
+  for (let i = 0; i < 2; i++) {
+    EventUtils.synthesizeKey("KEY_Enter");
+    await promiseSearchComplete();
+    await waitForAutocompleteResultAt(0);
+    await assertAlias(true);
+    Assert.equal(gURLBar.textValue, `${ALIAS} `);
+  }
+
   await UrlbarTestUtils.promisePopupClose(window,
     () => EventUtils.synthesizeKey("KEY_Escape"));
 });
 
 
 async function doSimpleTest(revertBetweenSteps) {
   // When autofill is enabled, searching for "@tes" will autofill to "@test",
   // which gets in the way of this test task, so temporarily disable it.
--- a/build.gradle
+++ b/build.gradle
@@ -76,17 +76,17 @@ buildscript {
     ext.jacoco_version = '0.8.1'
 
     if (gradle.mozconfig.substs.MOZ_ANDROID_GOOGLE_PLAY_SERVICES) {
         ext.google_play_services_version = '15.0.1'
         ext.google_play_services_cast_version = '16.0.0'
     }
 
     dependencies {
-        classpath 'org.mozilla.apilint:apilint:0.1.7'
+        classpath 'org.mozilla.apilint:apilint:0.1.8'
         classpath 'com.android.tools.build:gradle:3.1.4'
         classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.8.2'
         classpath 'org.apache.commons:commons-exec:1.3'
         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
     }
 }
 
 // A stream that processes bytes line by line, prepending a tag before sending
--- a/devtools/client/netmonitor/test/browser_net_autoscroll.js
+++ b/devtools/client/netmonitor/test/browser_net_autoscroll.js
@@ -49,17 +49,18 @@ add_task(async function() {
 
   // (4) Now select the first item in the list
   // and check that additional requests do not change the scroll position
   // from just below the headers.
   store.dispatch(Actions.selectRequestByIndex(0));
   await waitForNetworkEvents(monitor, 8);
   await waitSomeTime();
   const requestsContainerHeaders = document.querySelector(".requests-list-headers");
-  const headersHeight = requestsContainerHeaders.offsetHeight;
+  const headersHeight =
+    Math.floor(requestsContainerHeaders.getBoundingClientRect().height);
   is(requestsContainer.scrollTop, headersHeight, "Did not scroll.");
 
   // Stop doing requests.
   await ContentTask.spawn(tab.linkedBrowser, {}, function() {
     content.wrappedJSObject.stopRequests();
   });
 
   // Done: clean up.
--- a/devtools/client/themes/toolbars.css
+++ b/devtools/client/themes/toolbars.css
@@ -29,16 +29,21 @@
   line-height: 24px;
   box-sizing: border-box;
 }
 
 .devtools-toolbar {
   padding: 0 3px;
 }
 
+/* <thead> nor <tr> support border, we have to style the <td> */
+.devtools-toolbar td {
+  border-bottom: 1px solid var(--theme-splitter-color);
+}
+
 .devtools-toolbar-bottom {
   border-top-width: 1px;
   border-bottom: none;
 }
 
 /* Expected space around a separator:
  * -----------------------
  *            4
--- a/dom/base/Document.h
+++ b/dom/base/Document.h
@@ -444,18 +444,17 @@ class Document : public nsINode,
  protected:
   explicit Document(const char* aContentType);
   virtual ~Document();
 
   Document(const Document&) = delete;
   Document& operator=(const Document&) = delete;
 
  public:
-  typedef mozilla::dom::ExternalResourceMap::ExternalResourceLoad
-      ExternalResourceLoad;
+  typedef dom::ExternalResourceMap::ExternalResourceLoad ExternalResourceLoad;
   typedef net::ReferrerPolicy ReferrerPolicyEnum;
 
   MOZ_DECLARE_WEAKREFERENCE_TYPENAME(Document)
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IDOCUMENT_IID)
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
 
@@ -480,38 +479,36 @@ class Document : public nsINode,
 
   // nsIRadioGroupContainer
   NS_IMETHOD WalkRadioGroup(const nsAString& aName, nsIRadioVisitor* aVisitor,
                             bool aFlushContent) final {
     return DocumentOrShadowRoot::WalkRadioGroup(aName, aVisitor, aFlushContent);
   }
 
   void SetCurrentRadioButton(const nsAString& aName,
-                             mozilla::dom::HTMLInputElement* aRadio) final {
+                             HTMLInputElement* aRadio) final {
     DocumentOrShadowRoot::SetCurrentRadioButton(aName, aRadio);
   }
 
-  mozilla::dom::HTMLInputElement* GetCurrentRadioButton(
-      const nsAString& aName) final {
+  HTMLInputElement* GetCurrentRadioButton(const nsAString& aName) final {
     return DocumentOrShadowRoot::GetCurrentRadioButton(aName);
   }
 
   NS_IMETHOD
   GetNextRadioButton(const nsAString& aName, const bool aPrevious,
-                     mozilla::dom::HTMLInputElement* aFocusedRadio,
-                     mozilla::dom::HTMLInputElement** aRadioOut) final {
+                     HTMLInputElement* aFocusedRadio,
+                     HTMLInputElement** aRadioOut) final {
     return DocumentOrShadowRoot::GetNextRadioButton(aName, aPrevious,
                                                     aFocusedRadio, aRadioOut);
   }
-  void AddToRadioGroup(const nsAString& aName,
-                       mozilla::dom::HTMLInputElement* aRadio) final {
+  void AddToRadioGroup(const nsAString& aName, HTMLInputElement* aRadio) final {
     DocumentOrShadowRoot::AddToRadioGroup(aName, aRadio);
   }
   void RemoveFromRadioGroup(const nsAString& aName,
-                            mozilla::dom::HTMLInputElement* aRadio) final {
+                            HTMLInputElement* aRadio) final {
     DocumentOrShadowRoot::RemoveFromRadioGroup(aName, aRadio);
   }
   uint32_t GetRequiredRadioCount(const nsAString& aName) const final {
     return DocumentOrShadowRoot::GetRequiredRadioCount(aName);
   }
   void RadioRequiredWillChange(const nsAString& aName,
                                bool aRequiredAdded) final {
     DocumentOrShadowRoot::RadioRequiredWillChange(aName, aRequiredAdded);
@@ -522,19 +519,19 @@ class Document : public nsINode,
   void SetValueMissingState(const nsAString& aName, bool aValue) final {
     return DocumentOrShadowRoot::SetValueMissingState(aName, aValue);
   }
 
   // nsIScriptObjectPrincipal
   nsIPrincipal* GetPrincipal() final { return NodePrincipal(); }
 
   // EventTarget
-  void GetEventTargetParent(mozilla::EventChainPreVisitor& aVisitor) override;
-  mozilla::EventListenerManager* GetOrCreateListenerManager() override;
-  mozilla::EventListenerManager* GetExistingListenerManager() const override;
+  void GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
+  EventListenerManager* GetOrCreateListenerManager() override;
+  EventListenerManager* GetExistingListenerManager() const override;
 
   // This helper class must be set when we dispatch beforeunload and unload
   // events in order to avoid unterminate sync XHRs.
   class MOZ_RAII PageUnloadingEventTimeStamp {
     RefPtr<Document> mDocument;
     bool mSet;
 
    public:
@@ -604,18 +601,17 @@ class Document : public nsINode,
   virtual void SetSuppressParserErrorConsoleMessages(bool aSuppress) {}
   virtual bool SuppressParserErrorConsoleMessages() { return false; }
 
   // nsINode
   bool IsNodeOfType(uint32_t aFlags) const final;
   nsresult InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
                              bool aNotify) override;
   void RemoveChildNode(nsIContent* aKid, bool aNotify) final;
-  nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo,
-                 nsINode** aResult) const override {
+  nsresult Clone(dom::NodeInfo* aNodeInfo, nsINode** aResult) const override {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
   nsresult CloneDocHelper(Document* clone) const;
 
   Document* GetLatestStaticClone() const { return mLatestStaticClone; }
 
   /**
    * Signal that the document title may have changed
@@ -809,17 +805,17 @@ class Document : public nsINode,
 
   /**
    * Return the URL data which style system needs for resolving url value.
    * This method attempts to use the cached object in mCachedURLData, but
    * if the base URI, document URI, or principal has changed since last
    * call to this function, or the function is called the first time for
    * the document, a new one is created.
    */
-  mozilla::URLExtraData* DefaultStyleAttrURLData();
+  URLExtraData* DefaultStyleAttrURLData();
 
   /**
    * Get/Set the base target of a link in a document.
    */
   void GetBaseTarget(nsAString& aBaseTarget) const {
     aBaseTarget = mBaseTarget;
   }
 
@@ -999,19 +995,17 @@ class Document : public nsINode,
    */
   void SetHasUnsafeEvalCSP(bool aHasUnsafeEvalCSP) {
     mHasUnsafeEvalCSP = aHasUnsafeEvalCSP;
   }
 
   /**
    * Get the content blocking log.
    */
-  mozilla::dom::ContentBlockingLog* GetContentBlockingLog() {
-    return &mContentBlockingLog;
-  }
+  ContentBlockingLog* GetContentBlockingLog() { return &mContentBlockingLog; }
 
   /**
    * Get tracking content blocked flag for this document.
    */
   bool GetHasTrackingContentBlocked() {
     return mContentBlockingLog.HasBlockedAnyOfType(
         nsIWebProgressListener::STATE_BLOCKED_TRACKING_CONTENT);
   }
@@ -1321,29 +1315,27 @@ class Document : public nsINode,
   /**
    * Find the content node for which aDocument is a sub document.
    */
   Element* FindContentForSubDocument(Document* aDocument) const;
 
   /**
    * Return the doctype for this document.
    */
-  mozilla::dom::DocumentType* GetDoctype() const;
+  DocumentType* GetDoctype() const;
 
   /**
    * Return the root element for this document.
    */
   Element* GetRootElement() const;
 
-  mozilla::dom::Selection* GetSelection(mozilla::ErrorResult& aRv);
-
-  already_AddRefed<mozilla::dom::Promise> HasStorageAccess(
-      mozilla::ErrorResult& aRv);
-  already_AddRefed<mozilla::dom::Promise> RequestStorageAccess(
-      mozilla::ErrorResult& aRv);
+  Selection* GetSelection(ErrorResult& aRv);
+
+  already_AddRefed<Promise> HasStorageAccess(ErrorResult& aRv);
+  already_AddRefed<Promise> RequestStorageAccess(ErrorResult& aRv);
 
   /**
    * Gets the event target to dispatch key events to if there is no focused
    * content in the document.
    */
   virtual Element* GetUnfocusedKeyEventTarget();
 
   /**
@@ -1354,17 +1346,17 @@ class Document : public nsINode,
    * of returning it directly.
    *
    * @param aDisplaySize size of the on-screen display area for this
    * document, in device pixels.
    *
    * NOTE: If the site is optimized for mobile (via the doctype), this
    * will return viewport information that specifies default information.
    */
-  nsViewportInfo GetViewportInfo(const mozilla::ScreenIntSize& aDisplaySize);
+  nsViewportInfo GetViewportInfo(const ScreenIntSize& aDisplaySize);
 
   /**
    * It updates the viewport overflow type with the given two widths
    * and the viewport setting of the document.
    * This should only be called when there is out-of-reach overflow
    * happens on the viewport, i.e. the viewport should be using
    * `overflow: hidden`. And it should only be called on a top level
    * content document.
@@ -1393,37 +1385,36 @@ class Document : public nsINode,
 
   /*
    * Gets the srcdoc string from within the channel (assuming both exist).
    * Returns a void string if this isn't a srcdoc document or if
    * the channel has not been set.
    */
   nsresult GetSrcdocData(nsAString& aSrcdocData);
 
-  already_AddRefed<mozilla::dom::AnonymousContent> InsertAnonymousContent(
-      mozilla::dom::Element& aElement, mozilla::ErrorResult& aError);
-  void RemoveAnonymousContent(mozilla::dom::AnonymousContent& aContent,
-                              mozilla::ErrorResult& aError);
+  already_AddRefed<AnonymousContent> InsertAnonymousContent(
+      Element& aElement, ErrorResult& aError);
+  void RemoveAnonymousContent(AnonymousContent& aContent, ErrorResult& aError);
   /**
    * If aNode is a descendant of anonymous content inserted by
    * InsertAnonymousContent, this method returns the root element of the
    * inserted anonymous content (in other words, the clone of the aElement
    * that was passed to InsertAnonymousContent).
    */
   Element* GetAnonRootIfInAnonymousContentContainer(nsINode* aNode) const;
-  nsTArray<RefPtr<mozilla::dom::AnonymousContent>>& GetAnonymousContents() {
+  nsTArray<RefPtr<AnonymousContent>>& GetAnonymousContents() {
     return mAnonymousContents;
   }
 
-  mozilla::TimeStamp GetPageUnloadingEventTimeStamp() const {
+  TimeStamp GetPageUnloadingEventTimeStamp() const {
     if (!mParentDocument) {
       return mPageUnloadingEventTimeStamp;
     }
 
-    mozilla::TimeStamp parentTimeStamp(
+    TimeStamp parentTimeStamp(
         mParentDocument->GetPageUnloadingEventTimeStamp());
     if (parentTimeStamp.IsNull()) {
       return mPageUnloadingEventTimeStamp;
     }
 
     if (!mPageUnloadingEventTimeStamp ||
         parentTimeStamp < mPageUnloadingEventTimeStamp) {
       return parentTimeStamp;
@@ -1449,19 +1440,19 @@ class Document : public nsINode,
   // when it is destroyed)
   void UnscheduleSVGForPresAttrEvaluation(SVGElement* aSVG) {
     mLazySVGPresElements.RemoveEntry(aSVG);
   }
 
   // Resolve all SVG pres attrs scheduled in ScheduleSVGForPresAttrEvaluation
   void ResolveScheduledSVGPresAttrs();
 
-  mozilla::Maybe<mozilla::dom::ClientInfo> GetClientInfo() const;
-  mozilla::Maybe<mozilla::dom::ClientState> GetClientState() const;
-  mozilla::Maybe<mozilla::dom::ServiceWorkerDescriptor> GetController() const;
+  Maybe<ClientInfo> GetClientInfo() const;
+  Maybe<ClientState> GetClientState() const;
+  Maybe<ServiceWorkerDescriptor> GetController() const;
 
   // Returns the size of the mBlockedNodesByClassifier array.
   //
   // This array contains nodes that have been blocked to prevent user tracking,
   // fingerprinting, cryptomining, etc. They most likely have had their
   // nsIChannel canceled by the URL classifier (Safebrowsing).
   //
   // A script can subsequently use GetBlockedNodesByClassifier()
@@ -1526,35 +1517,35 @@ class Document : public nsINode,
   void RetrieveRelevantHeaders(nsIChannel* aChannel);
 
   void TryChannelCharset(nsIChannel* aChannel, int32_t& aCharsetSource,
                          NotNull<const Encoding*>& aEncoding,
                          nsHtml5TreeOpExecutor* aExecutor);
 
   void DispatchContentLoadedEvents();
 
-  void DispatchPageTransition(mozilla::dom::EventTarget* aDispatchTarget,
+  void DispatchPageTransition(EventTarget* aDispatchTarget,
                               const nsAString& aType, bool aPersisted,
                               bool aOnlySystemGroup = false);
 
   // Call this before the document does something that will unbind all content.
   // That will stop us from doing a lot of work as each element is removed.
   void DestroyElementMaps();
 
   Element* GetRootElementInternal() const;
   void DoNotifyPossibleTitleChange();
 
   void SetPageUnloadingEventTimeStamp() {
     MOZ_ASSERT(!mPageUnloadingEventTimeStamp);
-    mPageUnloadingEventTimeStamp = mozilla::TimeStamp::NowLoRes();
+    mPageUnloadingEventTimeStamp = TimeStamp::NowLoRes();
   }
 
   void CleanUnloadEventsTimeStamp() {
     MOZ_ASSERT(mPageUnloadingEventTimeStamp);
-    mPageUnloadingEventTimeStamp = mozilla::TimeStamp();
+    mPageUnloadingEventTimeStamp = TimeStamp();
   }
 
   /**
    * Clears any Servo element data stored on Elements in the document.
    */
   void ClearStaleServoData();
 
   /**
@@ -1614,128 +1605,125 @@ class Document : public nsINode,
     ~SelectorCache();
 
    private:
     nsDataHashtable<nsStringHashKey, SelectorList> mTable;
   };
 
   SelectorCache& GetSelectorCache() {
     if (!mSelectorCache) {
-      mSelectorCache = mozilla::MakeUnique<SelectorCache>(
-          EventTargetFor(mozilla::TaskCategory::Other));
+      mSelectorCache =
+          MakeUnique<SelectorCache>(EventTargetFor(TaskCategory::Other));
     }
     return *mSelectorCache;
   }
   // Get the root <html> element, or return null if there isn't one (e.g.
   // if the root isn't <html>)
   Element* GetHtmlElement() const;
   // Returns the first child of GetHtmlContent which has the given tag,
   // or nullptr if that doesn't exist.
   Element* GetHtmlChildElement(nsAtom* aTag);
   // Get the canonical <body> element, or return null if there isn't one (e.g.
   // if the root isn't <html> or if the <body> isn't there)
-  mozilla::dom::HTMLBodyElement* GetBodyElement();
+  HTMLBodyElement* GetBodyElement();
   // Get the canonical <head> element, or return null if there isn't one (e.g.
   // if the root isn't <html> or if the <head> isn't there)
   Element* GetHeadElement() { return GetHtmlChildElement(nsGkAtoms::head); }
   // 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, mozilla::ErrorResult& rv);
+  void SetBody(nsGenericHTMLElement* aBody, ErrorResult& rv);
   // Get the "head" element in the sense of document.head.
-  mozilla::dom::HTMLSharedElement* GetHead();
+  HTMLSharedElement* GetHead();
 
   /**
    * Accessors to the collection of stylesheets owned by this document.
    * Style sheets are ordered, most significant last.
    */
 
-  mozilla::dom::StyleSheetList* StyleSheets() {
+  StyleSheetList* StyleSheets() {
     return &DocumentOrShadowRoot::EnsureDOMStyleSheets();
   }
 
-  void InsertSheetAt(size_t aIndex, mozilla::StyleSheet&);
+  void InsertSheetAt(size_t aIndex, StyleSheet&);
 
   /**
    * Replace the stylesheets in aOldSheets with the stylesheets in
    * aNewSheets. The two lists must have equal length, and the sheet
    * at positon J in the first list will be replaced by the sheet at
    * position J in the second list.  Some sheets in the second list
    * may be null; if so the corresponding sheets in the first list
    * will simply be removed.
    */
-  void UpdateStyleSheets(nsTArray<RefPtr<mozilla::StyleSheet>>& aOldSheets,
-                         nsTArray<RefPtr<mozilla::StyleSheet>>& aNewSheets);
+  void UpdateStyleSheets(nsTArray<RefPtr<StyleSheet>>& aOldSheets,
+                         nsTArray<RefPtr<StyleSheet>>& aNewSheets);
 
   /**
    * Add a stylesheet to the document
    *
    * TODO(emilio): This is only used by parts of editor that are no longer in
    * use by m-c or c-c, so remove.
    */
-  void AddStyleSheet(mozilla::StyleSheet* aSheet) {
+  void AddStyleSheet(StyleSheet* aSheet) {
     MOZ_ASSERT(aSheet);
     InsertSheetAt(SheetCount(), *aSheet);
   }
 
   /**
    * Remove a stylesheet from the document
    */
-  void RemoveStyleSheet(mozilla::StyleSheet* aSheet);
+  void RemoveStyleSheet(StyleSheet* aSheet);
 
   /**
    * Notify the document that the applicable state of the sheet changed
    * and that observers should be notified and style sets updated
    */
-  void SetStyleSheetApplicableState(mozilla::StyleSheet* aSheet,
-                                    bool aApplicable);
+  void SetStyleSheetApplicableState(StyleSheet* aSheet, bool aApplicable);
 
   enum additionalSheetType {
     eAgentSheet,
     eUserSheet,
     eAuthorSheet,
     AdditionalSheetTypeCount
   };
 
   nsresult LoadAdditionalStyleSheet(additionalSheetType aType,
                                     nsIURI* aSheetURI);
   nsresult AddAdditionalStyleSheet(additionalSheetType aType,
-                                   mozilla::StyleSheet* aSheet);
+                                   StyleSheet* aSheet);
   void RemoveAdditionalStyleSheet(additionalSheetType aType, nsIURI* sheetURI);
 
-  mozilla::StyleSheet* GetFirstAdditionalAuthorSheet() {
+  StyleSheet* GetFirstAdditionalAuthorSheet() {
     return mAdditionalSheets[eAuthorSheet].SafeElementAt(0);
   }
 
   /**
    * Assuming that aDocSheets is an array of document-level style
    * sheets for this document, returns the index that aSheet should
    * be inserted at to maintain document ordering.
    *
    * Type T has to cast to StyleSheet*.
    *
    * Defined in DocumentInlines.h.
    */
   template <typename T>
   size_t FindDocStyleSheetInsertionPoint(const nsTArray<T>& aDocSheets,
-                                         const mozilla::StyleSheet& aSheet);
+                                         const StyleSheet& aSheet);
 
   /**
    * Get this document's CSSLoader.  This is guaranteed to not return null.
    */
-  mozilla::css::Loader* CSSLoader() const { return mCSSLoader; }
+  css::Loader* CSSLoader() const { return mCSSLoader; }
 
   /**
    * Get this document's StyleImageLoader.  This is guaranteed to not return
    * null.
    */
-  mozilla::css::ImageLoader* StyleImageLoader() const {
-    return mStyleImageLoader;
-  }
+  css::ImageLoader* StyleImageLoader() const { return mStyleImageLoader; }
 
   /**
    * Get the channel that was passed to StartDocumentLoad or Reset for this
    * document.  Note that this may be null in some cases (eg if
    * StartDocumentLoad or Reset were never called)
    */
   nsIChannel* GetChannel() const { return mChannel; }
 
@@ -1819,17 +1807,17 @@ class Document : public nsINode,
     return window ? window->WindowID() : 0;
   }
 
   bool IsTopLevelWindowInactive() const;
 
   /**
    * Get the script loader for this document
    */
-  mozilla::dom::ScriptLoader* ScriptLoader() { return mScriptLoader; }
+  dom::ScriptLoader* ScriptLoader() { return mScriptLoader; }
 
   /**
    * Add/Remove an element to the document's id and name hashes
    */
   void AddToIdTable(Element* aElement, nsAtom* aId);
   void RemoveFromIdTable(Element* aElement, nsAtom* aId);
   void AddToNameTable(Element* aElement, nsAtom* aName);
   void RemoveFromNameTable(Element* aElement, nsAtom* aName);
@@ -1876,17 +1864,17 @@ class Document : public nsINode,
   void FullscreenStackPop();
 
   /**
    * Called when a frame in a child process has entered fullscreen or when a
    * fullscreen frame in a child process changes to another origin.
    * aFrameElement is the frame element which contains the child-process
    * fullscreen document.
    */
-  nsresult RemoteFrameFullscreenChanged(mozilla::dom::Element* aFrameElement);
+  nsresult RemoteFrameFullscreenChanged(Element* aFrameElement);
 
   /**
    * Called when a frame in a remote child document has rolled back fullscreen
    * so that all its fullscreen element stacks are empty; we must continue the
    * rollback in this parent process' doc tree branch which is fullscreen.
    * Note that only one branch of the document tree can have its documents in
    * fullscreen state at one time. We're in inconsistent state if a
    * fullscreen document has a parent and that parent isn't fullscreen. We
@@ -1954,28 +1942,27 @@ class Document : public nsINode,
 
   void RequestPointerLock(Element* aElement, CallerType);
   bool SetPointerLock(Element* aElement, StyleCursorKind);
 
   static void UnlockPointer(Document* aDoc = nullptr);
 
   // ScreenOrientation related APIs
 
-  void SetCurrentOrientation(mozilla::dom::OrientationType aType,
-                             uint16_t aAngle) {
+  void SetCurrentOrientation(OrientationType aType, uint16_t aAngle) {
     mCurrentOrientationType = aType;
     mCurrentOrientationAngle = aAngle;
   }
 
   uint16_t CurrentOrientationAngle() const { return mCurrentOrientationAngle; }
-  mozilla::dom::OrientationType CurrentOrientationType() const {
+  OrientationType CurrentOrientationType() const {
     return mCurrentOrientationType;
   }
-  void SetOrientationPendingPromise(mozilla::dom::Promise* aPromise);
-  mozilla::dom::Promise* GetOrientationPendingPromise() const {
+  void SetOrientationPendingPromise(Promise* aPromise);
+  Promise* GetOrientationPendingPromise() const {
     return mOrientationPendingPromise;
   }
 
   //----------------------------------------------------------------------
 
   // Document notification API's
 
   /**
@@ -2019,54 +2006,50 @@ class Document : public nsINode,
 
   void SetAncestorLoading(bool aAncestorIsLoading);
   void NotifyLoading(const bool& aCurrentParentIsLoading,
                      bool aNewParentIsLoading, const ReadyState& aCurrentState,
                      ReadyState aNewState);
 
   // notify that a content node changed state.  This must happen under
   // a scriptblocker but NOT within a begin/end update.
-  void ContentStateChanged(nsIContent* aContent,
-                           mozilla::EventStates aStateMask);
+  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(mozilla::EventStates aStateMask);
+  void DocumentStatesChanged(EventStates aStateMask);
 
   // Observation hooks for style data to propagate notifications
   // to document observers
-  void StyleRuleChanged(mozilla::StyleSheet* aStyleSheet,
-                        mozilla::css::Rule* aStyleRule);
-  void StyleRuleAdded(mozilla::StyleSheet* aStyleSheet,
-                      mozilla::css::Rule* aStyleRule);
-  void StyleRuleRemoved(mozilla::StyleSheet* aStyleSheet,
-                        mozilla::css::Rule* aStyleRule);
+  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
    * (since those may affect the layout of this one).
    */
-  void FlushPendingNotifications(mozilla::FlushType aType);
+  void FlushPendingNotifications(FlushType aType);
 
   /**
    * Another variant of the above FlushPendingNotifications.  This function
    * takes a ChangesToFlush to specify whether throttled animations are flushed
    * or not.
    * If in doublt, use the above FlushPendingNotifications.
    */
-  void FlushPendingNotifications(mozilla::ChangesToFlush aFlush);
+  void FlushPendingNotifications(ChangesToFlush aFlush);
 
   /**
    * Calls FlushPendingNotifications on any external resources this document
    * has. If this document has no external resources or is an external resource
    * itself this does nothing. This should only be called with
    * aType >= FlushType::Style.
    */
-  void FlushExternalResources(mozilla::FlushType aType);
+  void FlushExternalResources(FlushType aType);
 
   // Triggers an update of <svg:use> element shadow trees.
   void UpdateSVGUseElementShadowTrees() {
     if (mSVGUseElementsNeedingShadowTreeUpdate.IsEmpty()) {
       return;
     }
     DoUpdateSVGUseElementShadowTrees();
   }
@@ -2316,64 +2299,62 @@ class Document : public nsINode,
    * PageTransitionEvent.webidl for a description of the |aPersisted|
    * parameter. If aDispatchStartTarget is null, the pageshow event is
    * dispatched on the ScriptGlobalObject for this document, otherwise it's
    * dispatched on aDispatchStartTarget. If |aOnlySystemGroup| is true, the
    * event is only dispatched to listeners in the system group.
    * Note: if aDispatchStartTarget isn't null, the showing state of the
    * document won't be altered.
    */
-  virtual void OnPageShow(bool aPersisted,
-                          mozilla::dom::EventTarget* aDispatchStartTarget,
+  virtual void OnPageShow(bool aPersisted, EventTarget* aDispatchStartTarget,
                           bool aOnlySystemGroup = false);
 
   /**
    * Notification that the page has been hidden, for documents which are loaded
    * into a DOM window.  This corresponds to the unloading of the document, or
    * to the document's presentation being saved but removed from an existing
    * DOM window.  This notification fires applicable DOM events to the content
    * window.  See PageTransitionEvent.webidl for a description of the
    * |aPersisted| parameter. If aDispatchStartTarget is null, the pagehide
    * event is dispatched on the ScriptGlobalObject for this document,
    * otherwise it's dispatched on aDispatchStartTarget. If |aOnlySystemGroup| is
    * true, the event is only dispatched to listeners in the system group.
    * Note: if aDispatchStartTarget isn't null, the showing state of the
    * document won't be altered.
    */
-  void OnPageHide(bool aPersisted,
-                  mozilla::dom::EventTarget* aDispatchStartTarget,
+  void OnPageHide(bool aPersisted, EventTarget* aDispatchStartTarget,
                   bool aOnlySystemGroup = false);
 
   /*
    * We record the set of links in the document that are relevant to
    * style.
    */
   /**
    * Notification that an element is a link that is relevant to style.
    */
-  void AddStyleRelevantLink(mozilla::dom::Link* aLink) {
+  void AddStyleRelevantLink(Link* aLink) {
     NS_ASSERTION(aLink, "Passing in a null link.  Expect crashes RSN!");
 #ifdef DEBUG
-    nsPtrHashKey<mozilla::dom::Link>* entry = mStyledLinks.GetEntry(aLink);
+    nsPtrHashKey<Link>* entry = mStyledLinks.GetEntry(aLink);
     NS_ASSERTION(!entry, "Document already knows about this Link!");
     mStyledLinksCleared = false;
 #endif
     mStyledLinks.PutEntry(aLink);
   }
 
   /**
    * Notification that an element is a link and its URI might have been
    * changed or the element removed. If the element is still a link relevant
    * to style, then someone must ensure that AddStyleRelevantLink is
    * (eventually) called on it again.
    */
-  void ForgetLink(mozilla::dom::Link* aLink) {
+  void ForgetLink(Link* aLink) {
     NS_ASSERTION(aLink, "Passing in a null link.  Expect crashes RSN!");
 #ifdef DEBUG
-    nsPtrHashKey<mozilla::dom::Link>* entry = mStyledLinks.GetEntry(aLink);
+    nsPtrHashKey<Link>* entry = mStyledLinks.GetEntry(aLink);
     NS_ASSERTION(entry || mStyledLinksCleared,
                  "Document knows nothing about this Link!");
 #endif
     mStyledLinks.RemoveEntry(aLink);
   }
 
   // Refreshes the hrefs of all the links in the document.
   void RefreshLinkHrefs();
@@ -2384,29 +2365,27 @@ class Document : public nsINode,
    * @param aElement canonical nsIContent pointer of the box object's element
    */
   void ClearBoxObjectFor(nsIContent* aContent);
 
   /**
    * Get the box object for an element. This is not exposed through a
    * scriptable interface except for XUL documents.
    */
-  already_AddRefed<mozilla::dom::BoxObject> GetBoxObjectFor(
-      mozilla::dom::Element* aElement, mozilla::ErrorResult& aRv);
+  already_AddRefed<BoxObject> GetBoxObjectFor(Element* aElement,
+                                              ErrorResult& aRv);
 
   /**
    * Support for window.matchMedia()
    */
 
-  already_AddRefed<mozilla::dom::MediaQueryList> MatchMedia(
-      const nsAString& aMediaQueryList, mozilla::dom::CallerType aCallerType);
-
-  mozilla::LinkedList<mozilla::dom::MediaQueryList>& MediaQueryLists() {
-    return mDOMMediaQueryLists;
-  }
+  already_AddRefed<MediaQueryList> MatchMedia(const nsAString& aMediaQueryList,
+                                              CallerType aCallerType);
+
+  LinkedList<MediaQueryList>& MediaQueryLists() { return mDOMMediaQueryLists; }
 
   /**
    * Get the compatibility mode for this document
    */
   nsCompatibility GetCompatibilityMode() const { return mCompatMode; }
 
   /**
    * Check whether we've ever fired a DOMTitleChanged event for this
@@ -2571,17 +2550,17 @@ class Document : public nsINode,
 
   /**
    * Enumerate the external resource documents associated with this document.
    * The enumerator callback should return true to continue enumerating, or
    * false to stop.  This callback will never get passed a null aDocument.
    */
   void EnumerateExternalResources(SubDocEnumFunc aCallback, void* aData);
 
-  mozilla::dom::ExternalResourceMap& ExternalResourceMap() {
+  dom::ExternalResourceMap& ExternalResourceMap() {
     return mExternalResourceMap;
   }
 
   /**
    * Return whether the document is currently showing (in the sense of
    * OnPageShow() having been called already and OnPageHide() not having been
    * called yet.
    */
@@ -2651,30 +2630,30 @@ class Document : public nsINode,
   // will have a non-null return value.
   bool HasAnimationController() { return !!mAnimationController; }
 
   // Getter for this document's SMIL Animation Controller. Performs lazy
   // initialization, if this document supports animation and if
   // mAnimationController isn't yet initialized.
   //
   // If HasAnimationController is true, this is guaranteed to return non-null.
-  mozilla::SMILAnimationController* GetAnimationController();
+  SMILAnimationController* GetAnimationController();
 
   // Gets the tracker for animations that are waiting to start.
   // Returns nullptr if there is no pending animation tracker for this document
   // which will be the case if there have never been any CSS animations or
   // transitions on elements in the document.
-  mozilla::PendingAnimationTracker* GetPendingAnimationTracker() {
+  PendingAnimationTracker* GetPendingAnimationTracker() {
     return mPendingAnimationTracker;
   }
 
   // Gets the tracker for animations that are waiting to start and
   // creates it if it doesn't already exist. As a result, the return value
   // will never be nullptr.
-  mozilla::PendingAnimationTracker* GetOrCreatePendingAnimationTracker();
+  PendingAnimationTracker* GetOrCreatePendingAnimationTracker();
 
   /**
    * Prevents user initiated events from being dispatched to the document and
    * subdocuments.
    */
   void SuppressEventHandling(uint32_t aIncrease = 1);
 
   /**
@@ -2697,17 +2676,17 @@ class Document : public nsINode,
   }
 
   /**
    * Note a ChannelEventQueue which has been suspended on the document's behalf
    * to prevent XHRs from running content scripts while event handling is
    * suppressed. The document is responsible for resuming the queue after
    * event handling is unsuppressed.
    */
-  void AddSuspendedChannelEventQueue(mozilla::net::ChannelEventQueue* aQueue);
+  void AddSuspendedChannelEventQueue(net::ChannelEventQueue* aQueue);
 
   void SetHasDelayedRefreshEvent() { mHasDelayedRefreshEvent = true; }
 
   /**
    * Flag whether we're about to fire the window's load event for this document.
    */
   void SetLoadEventFiring(bool aFiring) { mLoadEventFiring = aFiring; }
 
@@ -2855,45 +2834,45 @@ class Document : public nsINode,
    */
   void ForgetImagePreload(nsIURI* aURI);
 
   /**
    * Called by nsParser to preload style sheets.  Can also be merged into the
    * parser if and when the parser is merged with libgklayout.  aCrossOriginAttr
    * should be a void string if the attr is not present.
    */
-  void PreloadStyle(nsIURI* aURI, const mozilla::Encoding* aEncoding,
+  void PreloadStyle(nsIURI* aURI, const Encoding* aEncoding,
                     const nsAString& aCrossOriginAttr,
                     ReferrerPolicyEnum aReferrerPolicy,
                     const nsAString& aIntegrity);
 
   /**
    * Called by the chrome registry to load style sheets.  Can be put
    * back there if and when when that module is merged with libgklayout.
    *
    * This always does a synchronous load.  If aIsAgentSheet is true,
    * it also uses the system principal and enables unsafe rules.
    * DO NOT USE FOR UNTRUSTED CONTENT.
    */
   nsresult LoadChromeSheetSync(nsIURI* aURI, bool aIsAgentSheet,
-                               RefPtr<mozilla::StyleSheet>* aSheet);
+                               RefPtr<StyleSheet>* aSheet);
 
   /**
    * 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; }
 
   /**
    * Called by Parser for link rel=preconnect
    */
-  void MaybePreconnect(nsIURI* uri, mozilla::CORSMode aCORSMode);
+  void MaybePreconnect(nsIURI* uri, CORSMode aCORSMode);
 
   enum DocumentTheme {
     Doc_Theme_Uninitialized,  // not determined yet
     Doc_Theme_None,
     Doc_Theme_Neutral,
     Doc_Theme_Dark,
     Doc_Theme_Bright
   };
@@ -2926,17 +2905,17 @@ class Document : public nsINode,
     return MediaDocumentKind::NotMedia;
   }
 
   /**
    * Returns the document state.
    * Document state bits have the form NS_DOCUMENT_STATE_* and are declared in
    * Document.h.
    */
-  mozilla::EventStates GetDocumentState() const { return mDocumentState; }
+  EventStates GetDocumentState() const { return mDocumentState; }
 
   nsISupports* GetCurrentContentSink();
 
   void SetAutoFocusElement(Element* aAutoFocusElement);
   void TriggerAutoFocus();
 
   void SetScrollToRef(nsIURI* aDocumentURI);
   void ScrollToRef();
@@ -2947,17 +2926,17 @@ class Document : public nsINode,
   }
 
   using DocumentOrShadowRoot::GetElementById;
   using DocumentOrShadowRoot::GetElementsByClassName;
   using DocumentOrShadowRoot::GetElementsByTagName;
   using DocumentOrShadowRoot::GetElementsByTagNameNS;
 
   DocumentTimeline* Timeline();
-  mozilla::LinkedList<DocumentTimeline>& Timelines() { return mTimelines; }
+  LinkedList<DocumentTimeline>& Timelines() { return mTimelines; }
 
   void GetAnimations(nsTArray<RefPtr<Animation>>& aAnimations);
 
   SVGSVGElement* GetSVGRootElement() const;
 
   nsresult ScheduleFrameRequestCallback(FrameRequestCallback& aCallback,
                                         int32_t* aHandle);
   void CancelFrameRequestCallback(int32_t aHandle);
@@ -2974,17 +2953,17 @@ class Document : public nsINode,
    * throttled. We throttle requestAnimationFrame for documents which aren't
    * visible (e.g. scrolled out of the viewport).
    */
   bool ShouldThrottleFrameRequests();
 
   // This returns true when the document tree is being teared down.
   bool InUnlinkOrDeletion() { return mInUnlinkOrDeletion; }
 
-  mozilla::dom::ImageTracker* ImageTracker();
+  dom::ImageTracker* ImageTracker();
 
   // AddPlugin adds a plugin-related element to mPlugins when the element is
   // added to the tree.
   void AddPlugin(nsIObjectLoadingContent* aPlugin) {
     MOZ_ASSERT(aPlugin);
     mPlugins.PutEntry(aPlugin);
   }
 
@@ -3142,18 +3121,18 @@ class Document : public nsINode,
    * Creates a new element in the HTML namespace with a local name given by
    * aTag.
    */
   already_AddRefed<Element> CreateHTMLElement(nsAtom* aTag);
 
   // WebIDL API
   nsIGlobalObject* GetParentObject() const { return GetScopeObject(); }
   static already_AddRefed<Document> Constructor(const GlobalObject& aGlobal,
-                                                mozilla::ErrorResult& rv);
-  DOMImplementation* GetImplementation(mozilla::ErrorResult& rv);
+                                                ErrorResult& rv);
+  DOMImplementation* GetImplementation(ErrorResult& rv);
   MOZ_MUST_USE nsresult GetURL(nsString& retval) const;
   MOZ_MUST_USE nsresult GetDocumentURI(nsString& retval) const;
   // Return the URI for the document.
   // The returned value may differ if the document is loaded via XHR, and
   // when accessed from chrome privileged script and
   // from content privileged script for compatibility.
   void GetDocumentURIFromJS(nsString& aDocumentURI, CallerType aCallerType,
                             ErrorResult& aRv) const;
@@ -3186,68 +3165,67 @@ class Document : public nsINode,
   already_AddRefed<Element> CreateXULElement(
       const nsAString& aTagName, const ElementCreationOptionsOrString& aOptions,
       ErrorResult& aRv);
   already_AddRefed<DocumentFragment> CreateDocumentFragment() const;
   already_AddRefed<nsTextNode> CreateTextNode(const nsAString& aData) const;
   already_AddRefed<nsTextNode> CreateEmptyTextNode() const;
   already_AddRefed<Comment> CreateComment(const nsAString& aData) const;
   already_AddRefed<ProcessingInstruction> CreateProcessingInstruction(
-      const nsAString& target, const nsAString& data,
-      mozilla::ErrorResult& rv) const;
+      const nsAString& target, const nsAString& data, ErrorResult& rv) const;
   already_AddRefed<nsINode> ImportNode(nsINode& aNode, bool aDeep,
-                                       mozilla::ErrorResult& rv) const;
-  nsINode* AdoptNode(nsINode& aNode, mozilla::ErrorResult& rv);
+                                       ErrorResult& rv) const;
+  nsINode* AdoptNode(nsINode& aNode, ErrorResult& rv);
   already_AddRefed<Event> CreateEvent(const nsAString& aEventType,
                                       CallerType aCallerType,
-                                      mozilla::ErrorResult& rv) const;
-  already_AddRefed<nsRange> CreateRange(mozilla::ErrorResult& rv);
-  already_AddRefed<NodeIterator> CreateNodeIterator(
-      nsINode& aRoot, uint32_t aWhatToShow, NodeFilter* aFilter,
-      mozilla::ErrorResult& rv) const;
+                                      ErrorResult& rv) const;
+  already_AddRefed<nsRange> CreateRange(ErrorResult& rv);
+  already_AddRefed<NodeIterator> CreateNodeIterator(nsINode& aRoot,
+                                                    uint32_t aWhatToShow,
+                                                    NodeFilter* aFilter,
+                                                    ErrorResult& rv) const;
   already_AddRefed<TreeWalker> CreateTreeWalker(nsINode& aRoot,
                                                 uint32_t aWhatToShow,
                                                 NodeFilter* aFilter,
-                                                mozilla::ErrorResult& rv) const;
+                                                ErrorResult& rv) const;
   // Deprecated WebIDL bits
   already_AddRefed<CDATASection> CreateCDATASection(const nsAString& aData,
-                                                    mozilla::ErrorResult& rv);
+                                                    ErrorResult& rv);
   already_AddRefed<Attr> CreateAttribute(const nsAString& aName,
-                                         mozilla::ErrorResult& rv);
+                                         ErrorResult& rv);
   already_AddRefed<Attr> CreateAttributeNS(const nsAString& aNamespaceURI,
                                            const nsAString& aQualifiedName,
-                                           mozilla::ErrorResult& rv);
+                                           ErrorResult& rv);
   void GetInputEncoding(nsAString& aInputEncoding) const;
   already_AddRefed<Location> GetLocation() const;
   void GetReferrer(nsAString& aReferrer) const;
   void GetLastModified(nsAString& aLastModified) const;
   void GetReadyState(nsAString& aReadyState) const;
 
   void GetTitle(nsAString& aTitle);
-  void SetTitle(const nsAString& aTitle, mozilla::ErrorResult& rv);
+  void SetTitle(const nsAString& aTitle, ErrorResult& rv);
   void GetDir(nsAString& aDirection) const;
   void SetDir(const nsAString& aDirection);
   nsIHTMLCollection* Images();
   nsIHTMLCollection* Embeds();
   nsIHTMLCollection* Plugins() { return Embeds(); }
   nsIHTMLCollection* Links();
   nsIHTMLCollection* Forms();
   nsIHTMLCollection* Scripts();
   already_AddRefed<nsContentList> GetElementsByName(const nsAString& aName) {
     return GetFuncStringContentList<nsCachableElementsByNameNodeList>(
         this, MatchNameAttribute, nullptr, UseExistingNameString, aName);
   }
-  mozilla::dom::Nullable<mozilla::dom::WindowProxyHolder> GetDefaultView()
-      const;
+  Nullable<WindowProxyHolder> GetDefaultView() const;
   Element* GetActiveElement();
-  bool HasFocus(mozilla::ErrorResult& rv) const;
+  bool HasFocus(ErrorResult& rv) const;
   nsIHTMLCollection* Applets();
   nsIHTMLCollection* Anchors();
-  mozilla::TimeStamp LastFocusTime() const;
-  void SetLastFocusTime(const mozilla::TimeStamp& aFocusTime);
+  TimeStamp LastFocusTime() const;
+  void SetLastFocusTime(const TimeStamp& aFocusTime);
   // Event handlers are all on nsINode already
   bool MozSyntheticDocument() const { return IsSyntheticDocument(); }
   Element* GetCurrentScript();
   void ReleaseCapture() const;
   void MozSetImageElement(const nsAString& aImageElementId, Element* aElement);
   nsIURI* GetDocumentURIObject() const;
   // Not const because all the fullscreen goop is not const
   bool FullscreenEnabled(CallerType aCallerType);
@@ -3266,19 +3244,17 @@ class Document : public nsINode,
                                                        JSObject* aObject);
   static bool AreWebAnimationsTimelinesEnabled(JSContext* aCx,
                                                JSObject* aObject);
   // Checks that the caller is either chrome or some addon.
   static bool IsCallerChromeOrAddon(JSContext* aCx, JSObject* aObject);
 
 #ifdef MOZILLA_INTERNAL_API
   bool Hidden() const { return mVisibilityState != VisibilityState::Visible; }
-  mozilla::dom::VisibilityState VisibilityState() const {
-    return mVisibilityState;
-  }
+  dom::VisibilityState VisibilityState() const { return mVisibilityState; }
 #endif
   void GetSelectedStyleSheetSet(nsAString& aSheetSet);
   void SetSelectedStyleSheetSet(const nsAString& aSheetSet);
   void GetLastStyleSheetSet(nsAString& aSheetSet) {
     aSheetSet = mLastStyleSheetSet;
   }
   const nsString& GetCurrentStyleSheetSet() const {
     return mLastStyleSheetSet.IsEmpty() ? mPreferredStyleSheetSet
@@ -3312,62 +3288,59 @@ class Document : public nsINode,
 
   // QuerySelector and QuerySelectorAll already defined on nsINode
   nsINodeList* GetAnonymousNodes(Element& aElement);
   Element* GetAnonymousElementByAttribute(Element& aElement,
                                           const nsAString& aAttrName,
                                           const nsAString& aAttrValue);
   Element* GetBindingParent(nsINode& aNode);
   void LoadBindingDocument(const nsAString& aURI,
-                           nsIPrincipal& aSubjectPrincipal,
-                           mozilla::ErrorResult& rv);
+                           nsIPrincipal& aSubjectPrincipal, ErrorResult& rv);
   XPathExpression* CreateExpression(const nsAString& aExpression,
                                     XPathNSResolver* aResolver,
-                                    mozilla::ErrorResult& rv);
+                                    ErrorResult& rv);
   nsINode* CreateNSResolver(nsINode& aNodeResolver);
   already_AddRefed<XPathResult> Evaluate(
       JSContext* aCx, const nsAString& aExpression, nsINode& aContextNode,
       XPathNSResolver* aResolver, uint16_t aType, JS::Handle<JSObject*> aResult,
-      mozilla::ErrorResult& rv);
+      ErrorResult& rv);
   // Touch event handlers already on nsINode
-  already_AddRefed<Touch> CreateTouch(
-      nsGlobalWindowInner* aView, mozilla::dom::EventTarget* aTarget,
-      int32_t aIdentifier, int32_t aPageX, int32_t aPageY, int32_t aScreenX,
-      int32_t aScreenY, int32_t aClientX, int32_t aClientY, int32_t aRadiusX,
-      int32_t aRadiusY, float aRotationAngle, float aForce);
-  already_AddRefed<mozilla::dom::TouchList> CreateTouchList();
-  already_AddRefed<mozilla::dom::TouchList> CreateTouchList(
-      mozilla::dom::Touch& aTouch,
-      const mozilla::dom::Sequence<mozilla::OwningNonNull<mozilla::dom::Touch>>&
-          aTouches);
-  already_AddRefed<mozilla::dom::TouchList> CreateTouchList(
-      const mozilla::dom::Sequence<mozilla::OwningNonNull<mozilla::dom::Touch>>&
-          aTouches);
+  already_AddRefed<Touch> CreateTouch(nsGlobalWindowInner* aView,
+                                      EventTarget* aTarget, int32_t aIdentifier,
+                                      int32_t aPageX, int32_t aPageY,
+                                      int32_t aScreenX, int32_t aScreenY,
+                                      int32_t aClientX, int32_t aClientY,
+                                      int32_t aRadiusX, int32_t aRadiusY,
+                                      float aRotationAngle, float aForce);
+  already_AddRefed<TouchList> CreateTouchList();
+  already_AddRefed<TouchList> CreateTouchList(
+      Touch& aTouch, const Sequence<OwningNonNull<Touch>>& aTouches);
+  already_AddRefed<TouchList> CreateTouchList(
+      const Sequence<OwningNonNull<Touch>>& aTouches);
 
   void SetStyleSheetChangeEventsEnabled(bool aValue) {
     mStyleSheetChangeEventsEnabled = aValue;
   }
 
   bool StyleSheetChangeEventsEnabled() const {
     return mStyleSheetChangeEventsEnabled;
   }
 
-  already_AddRefed<mozilla::dom::Promise> BlockParsing(
-      mozilla::dom::Promise& aPromise,
-      const mozilla::dom::BlockParsingOptions& aOptions,
-      mozilla::ErrorResult& aRv);
+  already_AddRefed<Promise> BlockParsing(Promise& aPromise,
+                                         const BlockParsingOptions& aOptions,
+                                         ErrorResult& aRv);
 
   already_AddRefed<nsIURI> GetMozDocumentURIIfNotForErrorPages();
 
-  mozilla::dom::Promise* GetDocumentReadyForIdle(mozilla::ErrorResult& aRv);
+  Promise* GetDocumentReadyForIdle(ErrorResult& aRv);
 
   nsIDOMXULCommandDispatcher* GetCommandDispatcher();
   bool HasXULBroadcastManager() const { return mXULBroadcastManager; };
   void InitializeXULBroadcastManager();
-  mozilla::dom::XULBroadcastManager* GetXULBroadcastManager() const {
+  XULBroadcastManager* GetXULBroadcastManager() const {
     return mXULBroadcastManager;
   }
   already_AddRefed<nsINode> GetPopupNode();
   void SetPopupNode(nsINode* aNode);
   nsINode* GetPopupRangeParent(ErrorResult& aRv);
   int32_t GetPopupRangeOffset(ErrorResult& aRv);
   already_AddRefed<nsINode> GetTooltipNode();
   void SetTooltipNode(nsINode* aNode) { /* do nothing */
@@ -3382,23 +3355,23 @@ class Document : public nsINode,
    * Defined inline in nsHTMLDocument.h
    */
   inline nsHTMLDocument* AsHTMLDocument();
 
   /**
    * Asserts IsSVGDocument, and can't return null.
    * Defined inline in SVGDocument.h
    */
-  inline mozilla::dom::SVGDocument* AsSVGDocument();
+  inline SVGDocument* AsSVGDocument();
 
   /**
    * Asserts IsXULDocument, and can't return null.
    * Defined inline in XULDocument.h
    */
-  inline mozilla::dom::XULDocument* AsXULDocument();
+  inline XULDocument* AsXULDocument();
 
   /*
    * Given a node, get a weak reference to it and append that reference to
    * mBlockedNodesByClassifier. Can be used later on to look up a node in it.
    * (e.g., by the UI)
    */
   void AddBlockedNodeByClassifier(nsINode* node) {
     if (!node) {
@@ -3410,20 +3383,20 @@ class Document : public nsINode,
     if (weakNode) {
       mBlockedNodesByClassifier.AppendElement(weakNode);
     }
   }
 
   gfxUserFontSet* GetUserFontSet();
   void FlushUserFontSet();
   void MarkUserFontSetDirty();
-  mozilla::dom::FontFaceSet* GetFonts() { return mFontFaceSet; }
+  FontFaceSet* GetFonts() { return mFontFaceSet; }
 
   // FontFaceSource
-  mozilla::dom::FontFaceSet* Fonts();
+  FontFaceSet* Fonts();
 
   bool DidFireDOMContentLoaded() const { return mDidFireDOMContentLoaded; }
 
   bool IsSynthesized();
 
   enum class UseCounterReportKind {
     // Flush the document's use counters only; the use counters for any
     // external resource documents will be flushed when the external
@@ -3434,44 +3407,44 @@ class Document : public nsINode,
     // documents. (Should only be necessary for tests, where we need
     // flushing to happen synchronously and deterministically.)
     eIncludeExternalResources,
   };
 
   void ReportUseCounters(
       UseCounterReportKind aKind = UseCounterReportKind::eDefault);
 
-  void SetDocumentUseCounter(mozilla::UseCounter aUseCounter) {
+  void SetDocumentUseCounter(UseCounter aUseCounter) {
     if (!mUseCounters[aUseCounter]) {
       mUseCounters[aUseCounter] = true;
     }
   }
 
   const StyleUseCounters* GetStyleUseCounters() {
     return mStyleUseCounters.get();
   }
 
-  void SetPageUseCounter(mozilla::UseCounter aUseCounter);
-
-  void SetDocumentAndPageUseCounter(mozilla::UseCounter aUseCounter) {
+  void SetPageUseCounter(UseCounter aUseCounter);
+
+  void SetDocumentAndPageUseCounter(UseCounter aUseCounter) {
     SetDocumentUseCounter(aUseCounter);
     SetPageUseCounter(aUseCounter);
   }
 
   void PropagateUseCounters(Document* aParentDocument);
 
   // Called to track whether this document has had any interaction.
   // This is used to track whether we should permit "beforeunload".
   void SetUserHasInteracted();
   bool UserHasInteracted() { return mUserHasInteracted; }
   void ResetUserInteractionTimer();
 
   // This method would return current autoplay policy, it would be "allowed"
   // , "allowed-muted" or "disallowed".
-  mozilla::dom::DocumentAutoplayPolicy AutoplayPolicy() const;
+  DocumentAutoplayPolicy AutoplayPolicy() const;
 
   // This should be called when this document receives events which are likely
   // to be user interaction with the document, rather than the byproduct of
   // interaction with the browser (i.e. a keypress to scroll the view port,
   // keyboard shortcuts, etc). This is used to decide whether we should
   // permit autoplay audible media. This also gesture activates all other
   // content documents in this tab.
   void NotifyUserGestureActivation();
@@ -3491,71 +3464,69 @@ class Document : public nsINode,
 
   bool HasScriptsBlockedBySandbox();
 
   bool InlineScriptAllowedByCSP();
 
   void ReportHasScrollLinkedEffect();
   bool HasScrollLinkedEffect() const { return mHasScrollLinkedEffect; }
 
-  mozilla::dom::DocGroup* GetDocGroup() const;
-
-  void AddIntersectionObserver(
-      mozilla::dom::DOMIntersectionObserver* aObserver) {
+  DocGroup* GetDocGroup() const;
+
+  void AddIntersectionObserver(DOMIntersectionObserver* aObserver) {
     MOZ_ASSERT(!mIntersectionObservers.Contains(aObserver),
                "Intersection observer already in the list");
     mIntersectionObservers.PutEntry(aObserver);
   }
 
-  void RemoveIntersectionObserver(
-      mozilla::dom::DOMIntersectionObserver* aObserver) {
+  void RemoveIntersectionObserver(DOMIntersectionObserver* aObserver) {
     mIntersectionObservers.RemoveEntry(aObserver);
   }
 
   bool HasIntersectionObservers() const {
     return !mIntersectionObservers.IsEmpty();
   }
 
   void UpdateIntersectionObservations();
   void ScheduleIntersectionObserverNotification();
   void NotifyIntersectionObservers();
 
   // Dispatch a runnable related to the document.
-  nsresult Dispatch(mozilla::TaskCategory aCategory,
+  nsresult Dispatch(TaskCategory aCategory,
                     already_AddRefed<nsIRunnable>&& aRunnable) final;
 
   virtual nsISerialEventTarget* EventTargetFor(
-      mozilla::TaskCategory aCategory) const override;
-
-  virtual mozilla::AbstractThread* AbstractMainThreadFor(
-      mozilla::TaskCategory aCategory) override;
+      TaskCategory aCategory) const override;
+
+  virtual AbstractThread* AbstractMainThreadFor(
+      TaskCategory aCategory) override;
 
   // The URLs passed to these functions should match what
   // JS::DescribeScriptedCaller() returns, since these APIs are used to
   // determine whether some code is being called from a tracking script.
   void NoteScriptTrackingStatus(const nsACString& aURL, bool isTracking);
   bool IsScriptTracking(const nsACString& aURL) const;
 
   // For more information on Flash classification, see
   // toolkit/components/url-classifier/flash-block-lists.rst
-  mozilla::dom::FlashClassification DocumentFlashClassification();
+  FlashClassification DocumentFlashClassification();
 
   /**
    * Localization
    *
    * For more information on DocumentL10n see
    * intl/l10n/docs/fluent_tutorial.rst
    */
 
  public:
   /**
    * This is a public method exposed on Document WebIDL
    * to chrome only documents.
    */
-  mozilla::dom::DocumentL10n* GetL10n();
+  DocumentL10n* GetL10n();
 
   /**
    * This method should be called when the container
    * of l10n resources parsing is completed.
    *
    * It triggers initial async fetch of the resources
    * as early as possible.
    *
@@ -3598,33 +3569,33 @@ class Document : public nsINode,
    * It unblocks the layout.
    *
    * This method is virtual so that XULDocument can
    * override it.
    */
   virtual void InitialDocumentTranslationCompleted();
 
  protected:
-  RefPtr<mozilla::dom::DocumentL10n> mDocumentL10n;
+  RefPtr<DocumentL10n> mDocumentL10n;
 
   /**
    * Return true when you want a document without explicitly specified viewport
    * dimensions/scale to be treated as if "width=device-width" had in fact been
    * specified.
    */
   virtual bool UseWidthDeviceWidthFallbackViewport() const;
 
  private:
   void InitializeLocalization(nsTArray<nsString>& aResourceIds);
 
   void ParseWidthAndHeightInMetaViewport(const nsAString& aWidthString,
                                          const nsAString& aHeightString,
                                          const nsAString& aScaleString);
 
-  mozilla::dom::FlashClassification DocumentFlashClassificationInternal();
+  FlashClassification DocumentFlashClassificationInternal();
 
   nsTArray<nsString> mL10nResources;
 
   // The application cache that this document is associated with, if
   // any.  This can change during the lifetime of the document.
   nsCOMPtr<nsIApplicationCache> mApplicationCache;
 
  public:
@@ -3705,17 +3676,17 @@ class Document : public nsINode,
   }
 
   bool AllowPaymentRequest() const { return mAllowPaymentRequest; }
 
   void SetAllowPaymentRequest(bool aAllowPaymentRequest) {
     mAllowPaymentRequest = aAllowPaymentRequest;
   }
 
-  mozilla::dom::FeaturePolicy* Policy() const;
+  FeaturePolicy* Policy() const;
 
   bool ModuleScriptsEnabled();
 
   /**
    * Find the (non-anonymous) content in this document for aFrame. It will
    * be aFrame's content node if that content is in this document and not
    * anonymous. Otherwise, when aFrame is in a subdocument, we use the frame
    * element containing the subdocument containing aFrame, and/or find the
@@ -3729,17 +3700,17 @@ class Document : public nsINode,
   // When the doc is blocked permanantly, we would dispatch event to notify
   // front-end side to show blocking icon.
   void MaybeNotifyAutoplayBlocked();
 
   // Sets flags for media autoplay telemetry.
   void SetDocTreeHadAudibleMedia();
   void SetDocTreeHadPlayRevoked();
 
-  mozilla::dom::XPathEvaluator* XPathEvaluator();
+  dom::XPathEvaluator* XPathEvaluator();
 
   void MaybeInitializeFinalizeFrameLoaders();
 
   void SetDelayFrameLoaderInitialization(bool aDelayFrameLoaderInitialization) {
     mDelayFrameLoaderInitialization = aDelayFrameLoaderInitialization;
   }
 
   void SetPrototypeDocument(nsXULPrototypeDocument* aPrototype);
@@ -3771,54 +3742,52 @@ class Document : public nsINode,
 
   void RecordNavigationTiming(ReadyState aReadyState);
 
   // This method may fire a DOM event; if it does so it will happen
   // synchronously.
   void UpdateVisibilityState();
 
   // Recomputes the visibility state but doesn't set the new value.
-  mozilla::dom::VisibilityState ComputeVisibilityState() const;
+  dom::VisibilityState ComputeVisibilityState() const;
 
   // Since we wouldn't automatically play media from non-visited page, we need
   // to notify window when the page was first visited.
   void MaybeActiveMediaComponents();
 
   // Apply the fullscreen state to the document, and trigger related
   // events. It returns false if the fullscreen element ready check
   // fails and nothing gets changed.
   bool ApplyFullscreen(UniquePtr<FullscreenRequest>);
 
-  bool GetUseCounter(mozilla::UseCounter aUseCounter) {
+  bool GetUseCounter(UseCounter aUseCounter) {
     return mUseCounters[aUseCounter];
   }
 
-  void SetChildDocumentUseCounter(mozilla::UseCounter aUseCounter) {
+  void SetChildDocumentUseCounter(UseCounter aUseCounter) {
     if (!mChildDocumentUseCounters[aUseCounter]) {
       mChildDocumentUseCounters[aUseCounter] = true;
     }
   }
 
-  bool GetChildDocumentUseCounter(mozilla::UseCounter aUseCounter) {
+  bool GetChildDocumentUseCounter(UseCounter aUseCounter) {
     return mChildDocumentUseCounters[aUseCounter];
   }
 
-  void UpdateDocumentStates(mozilla::EventStates);
+  void UpdateDocumentStates(EventStates);
 
   void RemoveDocStyleSheetsFromStyleSets();
   void RemoveStyleSheetsFromStyleSets(
-      const nsTArray<RefPtr<mozilla::StyleSheet>>& aSheets,
-      mozilla::SheetType aType);
+      const nsTArray<RefPtr<StyleSheet>>& aSheets, SheetType aType);
   void ResetStylesheetsToURI(nsIURI* aURI);
-  void FillStyleSet(mozilla::ServoStyleSet* aStyleSet);
-  void AddStyleSheetToStyleSets(mozilla::StyleSheet* aSheet);
-  void RemoveStyleSheetFromStyleSets(mozilla::StyleSheet* aSheet);
-  void NotifyStyleSheetAdded(mozilla::StyleSheet* aSheet, bool aDocumentSheet);
-  void NotifyStyleSheetRemoved(mozilla::StyleSheet* aSheet,
-                               bool aDocumentSheet);
+  void FillStyleSet(ServoStyleSet* aStyleSet);
+  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.
   void EnableStyleSheetsForSetInternal(const nsAString& aSheetSet,
                                        bool aUpdateCSSLoader);
 
  private:
@@ -3875,29 +3844,28 @@ class Document : public nsINode,
   // schedule or unschedule them, if necessary, and update
   // mFrameRequestCallbacksScheduled.  aOldShell should only be passed when
   // mPresShell is becoming null; in that case it will be used to get hold of
   // the relevant refresh driver.
   void UpdateFrameRequestCallbackSchedulingState(
       nsIPresShell* aOldShell = nullptr);
 
   // Helper for GetScrollingElement/IsScrollingElement.
-  bool IsPotentiallyScrollable(mozilla::dom::HTMLBodyElement* aBody);
+  bool IsPotentiallyScrollable(HTMLBodyElement* aBody);
 
   // Return the same type parent docuement if exists, or return null.
   Document* GetSameTypeParentDocument();
 
   void MaybeAllowStorageForOpenerAfterUserInteraction();
 
   void MaybeStoreUserInteractionAsPermission();
 
   // Helpers for GetElementsByName.
-  static bool MatchNameAttribute(mozilla::dom::Element* aElement,
-                                 int32_t aNamespaceID, nsAtom* aAtom,
-                                 void* aData);
+  static bool MatchNameAttribute(Element* aElement, int32_t aNamespaceID,
+                                 nsAtom* aAtom, void* aData);
   static void* UseExistingNameString(nsINode* aRootNode, const nsString* aName);
 
   void MaybeResolveReadyForIdle();
 
   nsCString mReferrer;
   nsString mLastModified;
 
   nsCOMPtr<nsIURI> mDocumentURI;
@@ -3905,92 +3873,90 @@ class Document : public nsINode,
   nsCOMPtr<nsIURI> mChromeXHRDocURI;
   nsCOMPtr<nsIURI> mDocumentBaseURI;
   nsCOMPtr<nsIURI> mChromeXHRDocBaseURI;
 
   // The base domain of the document for third-party checks.
   nsCString mBaseDomain;
 
   // A lazily-constructed URL data for style system to resolve URL value.
-  RefPtr<mozilla::URLExtraData> mCachedURLData;
+  RefPtr<URLExtraData> mCachedURLData;
 
   nsWeakPtr mDocumentLoadGroup;
 
   bool mReferrerPolicySet;
   ReferrerPolicyEnum mReferrerPolicy;
 
   bool mBlockAllMixedContent;
   bool mBlockAllMixedContentPreloads;
   bool mUpgradeInsecureRequests;
   bool mUpgradeInsecurePreloads;
 
-  mozilla::WeakPtr<nsDocShell> mDocumentContainer;
+  WeakPtr<nsDocShell> mDocumentContainer;
 
   NotNull<const Encoding*> mCharacterSet;
   int32_t mCharacterSetSource;
 
   // This is just a weak pointer; the parent document owns its children.
   Document* mParentDocument;
 
   // A reference to the element last returned from GetRootElement().
-  mozilla::dom::Element* mCachedRootElement;
+  Element* mCachedRootElement;
 
   // This is a weak reference, but we hold a strong reference to mNodeInfo,
   // which in turn holds a strong reference to this mNodeInfoManager.
   nsNodeInfoManager* mNodeInfoManager;
-  RefPtr<mozilla::css::Loader> mCSSLoader;
-  RefPtr<mozilla::css::ImageLoader> mStyleImageLoader;
+  RefPtr<css::Loader> mCSSLoader;
+  RefPtr<css::ImageLoader> mStyleImageLoader;
   RefPtr<nsHTMLStyleSheet> mAttrStyleSheet;
   RefPtr<nsHTMLCSSStyleSheet> mStyleAttrStyleSheet;
 
   // Tracking for images in the document.
-  RefPtr<mozilla::dom::ImageTracker> mImageTracker;
+  RefPtr<dom::ImageTracker> mImageTracker;
 
   // A hashtable of ShadowRoots belonging to the composed doc.
   //
   // See ShadowRoot::Bind and ShadowRoot::Unbind.
   ShadowRootSet mComposedShadowRoots;
 
-  using SVGUseElementSet =
-      nsTHashtable<nsPtrHashKey<mozilla::dom::SVGUseElement>>;
+  using SVGUseElementSet = nsTHashtable<nsPtrHashKey<SVGUseElement>>;
 
   // The set of <svg:use> elements that need a shadow tree reclone because the
   // tree they map to has changed.
   SVGUseElementSet mSVGUseElementsNeedingShadowTreeUpdate;
 
   // The set of all object, embed, video/audio elements or
-  // nsIObjectLoadingContent or mozilla::dom::DocumentActivity for which this is
+  // nsIObjectLoadingContent or DocumentActivity for which this is
   // the owner document. (They might not be in the document.)
   //
   // These are non-owning pointers, the elements are responsible for removing
   // themselves when they go away.
   nsAutoPtr<nsTHashtable<nsPtrHashKey<nsISupports>>> mActivityObservers;
 
   // A hashtable of styled links keyed by address pointer.
-  nsTHashtable<nsPtrHashKey<mozilla::dom::Link>> mStyledLinks;
+  nsTHashtable<nsPtrHashKey<Link>> mStyledLinks;
 #ifdef DEBUG
   // Indicates whether mStyledLinks was cleared or not.  This is used to track
   // state so we can provide useful assertions to consumers of ForgetLink and
   // AddStyleRelevantLink.
   bool mStyledLinksCleared;
 #endif
 
   // The array of all links that need their status resolved.  Links must add
   // themselves to this set by calling RegisterPendingLinkUpdate when added to a
   // document.
   static const size_t kSegmentSize = 128;
 
-  typedef mozilla::SegmentedVector<nsCOMPtr<mozilla::dom::Link>, kSegmentSize,
-                                   InfallibleAllocPolicy>
+  typedef SegmentedVector<nsCOMPtr<Link>, kSegmentSize, InfallibleAllocPolicy>
       LinksToUpdateList;
 
   LinksToUpdateList mLinksToUpdate;
 
   // SMIL Animation Controller, lazily-initialized in GetAnimationController
-  RefPtr<mozilla::SMILAnimationController> mAnimationController;
+  RefPtr<SMILAnimationController> mAnimationController;
 
   // Table of element properties for this document.
   nsPropertyTable mPropertyTable;
 
   // Our cached .children collection
   nsCOMPtr<nsIHTMLCollection> mChildrenCollection;
 
   // Various DOM lists
@@ -3998,27 +3964,27 @@ class Document : public nsINode,
   RefPtr<nsContentList> mEmbeds;
   RefPtr<nsContentList> mLinks;
   RefPtr<nsContentList> mForms;
   RefPtr<nsContentList> mScripts;
   nsCOMPtr<nsIHTMLCollection> mApplets;
   RefPtr<nsContentList> mAnchors;
 
   // container for per-context fonts (downloadable, SVG, etc.)
-  RefPtr<mozilla::dom::FontFaceSet> mFontFaceSet;
+  RefPtr<FontFaceSet> mFontFaceSet;
 
   // Last time this document or a one of its sub-documents was focused.  If
   // focus has never occurred then mLastFocusTime.IsNull() will be true.
-  mozilla::TimeStamp mLastFocusTime;
-
-  mozilla::EventStates mDocumentState;
-
-  RefPtr<mozilla::dom::Promise> mReadyForIdle;
-
-  RefPtr<mozilla::dom::FeaturePolicy> mFeaturePolicy;
+  TimeStamp mLastFocusTime;
+
+  EventStates mDocumentState;
+
+  RefPtr<Promise> mReadyForIdle;
+
+  RefPtr<FeaturePolicy> mFeaturePolicy;
 
   // True if BIDI is enabled.
   bool mBidiEnabled : 1;
   // True if mLangGroupFontPrefs is not initialized or dirty in some other way.
   bool mFontGroupCacheDirty : 1;
   // True if a MathML element has ever been owned by this document.
   bool mMathMLEnabled : 1;
 
@@ -4288,24 +4254,18 @@ class Document : public nsINode,
   nsCompatibility mCompatMode;
 
   // Our readyState
   ReadyState mReadyState;
 
   // Ancestor's loading state
   bool mAncestorIsLoading;
 
-#ifdef MOZILLA_INTERNAL_API
   // Our visibility state
-  mozilla::dom::VisibilityState mVisibilityState;
-  static_assert(sizeof(mozilla::dom::VisibilityState) == sizeof(uint8_t),
-                "Error size of mVisibilityState and mDummy");
-#else
-  uint8_t mDummy;
-#endif
+  dom::VisibilityState mVisibilityState;
 
   enum Type {
     eUnknown,  // should never be used
     eHTML,
     eXHTML,
     eGenericXML,
     eSVG,
     eXUL
@@ -4392,17 +4352,17 @@ class Document : public nsINode,
   // point to our "display document": the one that all resource lookups should
   // go to.
   RefPtr<Document> mDisplayDocument;
 
   uint32_t mEventsSuppressed;
 
   // Any XHR ChannelEventQueues that were suspended on this document while
   // events were suppressed.
-  nsTArray<RefPtr<mozilla::net::ChannelEventQueue>> mSuspendedQueues;
+  nsTArray<RefPtr<net::ChannelEventQueue>> mSuspendedQueues;
 
   RefPtr<EventListener> mSuppressedEventListener;
 
   /**
    * https://html.spec.whatwg.org/#ignore-destructive-writes-counter
    */
   uint32_t mIgnoreDestructiveWritesCounter;
 
@@ -4443,60 +4403,60 @@ class Document : public nsINode,
   // Our base target.
   nsString mBaseTarget;
 
   nsCOMPtr<nsIStructuredCloneContainer> mStateObjectContainer;
   nsCOMPtr<nsIVariant> mStateObjectCached;
 
   uint32_t mInSyncOperationCount;
 
-  UniquePtr<mozilla::dom::XPathEvaluator> mXPathEvaluator;
+  UniquePtr<dom::XPathEvaluator> mXPathEvaluator;
 
   nsTArray<RefPtr<AnonymousContent>> mAnonymousContents;
 
   uint32_t mBlockDOMContentLoaded;
 
   // Our live MediaQueryLists
-  mozilla::LinkedList<mozilla::dom::MediaQueryList> mDOMMediaQueryLists;
+  LinkedList<MediaQueryList> mDOMMediaQueryLists;
 
   // Array of observers
   nsTObserverArray<nsIDocumentObserver*> mObservers;
 
   // Flags for use counters used directly by this document.
-  std::bitset<mozilla::eUseCounter_Count> mUseCounters;
+  std::bitset<eUseCounter_Count> mUseCounters;
   // Flags for use counters used by any child documents of this document.
-  std::bitset<mozilla::eUseCounter_Count> mChildDocumentUseCounters;
+  std::bitset<eUseCounter_Count> mChildDocumentUseCounters;
   // Flags for whether we've notified our top-level "page" of a use counter
   // for this child document.
-  std::bitset<mozilla::eUseCounter_Count> mNotifiedPageForUseCounter;
+  std::bitset<eUseCounter_Count> mNotifiedPageForUseCounter;
 
   // The CSS property use counters.
-  mozilla::UniquePtr<StyleUseCounters> mStyleUseCounters;
+  UniquePtr<StyleUseCounters> mStyleUseCounters;
 
   // Whether the user has interacted with the document or not:
   bool mUserHasInteracted;
 
   // We constantly update the user-interaction anti-tracking permission at any
   // user-interaction using a timer. This boolean value is set to true when this
   // timer is scheduled.
   bool mHasUserInteractionTimerScheduled;
 
-  mozilla::TimeStamp mPageUnloadingEventTimeStamp;
-
-  RefPtr<mozilla::dom::DocGroup> mDocGroup;
+  TimeStamp mPageUnloadingEventTimeStamp;
+
+  RefPtr<DocGroup> mDocGroup;
 
   // The set of all the tracking script URLs.  URLs are added to this set by
   // calling NoteScriptTrackingStatus().  Currently we assume that a URL not
   // existing in the set means the corresponding script isn't a tracking script.
   nsTHashtable<nsCStringHashKey> mTrackingScripts;
 
   // The log of all content blocking actions taken on this document.  This is
   // only stored on top-level documents and includes the activity log for all of
   // the nested subdocuments as well.
-  mozilla::dom::ContentBlockingLog mContentBlockingLog;
+  ContentBlockingLog mContentBlockingLog;
 
   // List of ancestor principals.  This is set at the point a document
   // is connected to a docshell and not mutated thereafter.
   nsTArray<nsCOMPtr<nsIPrincipal>> mAncestorPrincipals;
   // List of ancestor outerWindowIDs that correspond to the ancestor principals.
   nsTArray<uint64_t> mAncestorOuterWindowIDs;
 
   // Pointer to our parser if we're currently in the process of being
@@ -4546,119 +4506,116 @@ class Document : public nsINode,
   ViewportOverflowType mViewportOverflowType;
 
   PLDHashTable* mSubDocuments;
 
   DocHeaderData* mHeaderData;
 
   // For determining if this is a flash document which should be
   // blocked based on its principal.
-  mozilla::dom::FlashClassification mFlashClassification;
+  FlashClassification mFlashClassification;
 
   // Do not use this value directly. Call the |IsThirdPartyForFlashClassifier()|
   // method, which caches its result here.
-  mozilla::Maybe<bool> mIsThirdPartyForFlashClassifier;
+  Maybe<bool> mIsThirdPartyForFlashClassifier;
 
   nsRevocableEventPtr<nsRunnableMethod<Document, void, false>>
       mPendingTitleChangeEvent;
 
   RefPtr<nsDOMNavigationTiming> mTiming;
 
   // Recorded time of change to 'loading' state.
-  mozilla::TimeStamp mLoadingTimeStamp;
+  TimeStamp mLoadingTimeStamp;
 
   nsWeakPtr mAutoFocusElement;
 
   nsCString mScrollToRef;
 
   nscoord mScrollAnchorAdjustmentLength;
   int32_t mScrollAnchorAdjustmentCount;
 
   // Weak reference to the scope object (aka the script global object)
   // that, unlike mScriptGlobalObject, is never unset once set. This
   // is a weak reference to avoid leaks due to circular references.
   nsWeakPtr mScopeObject;
 
   // Array of intersection observers
-  nsTHashtable<nsPtrHashKey<mozilla::dom::DOMIntersectionObserver>>
-      mIntersectionObservers;
+  nsTHashtable<nsPtrHashKey<DOMIntersectionObserver>> mIntersectionObservers;
 
   // Stack of fullscreen elements. When we request fullscreen we push the
   // fullscreen element onto this stack, and when we cancel fullscreen we
   // pop one off this stack, restoring the previous fullscreen state
   nsTArray<nsWeakPtr> mFullscreenStack;
 
   // The root of the doc tree in which this document is in. This is only
   // non-null when this document is in fullscreen mode.
   nsWeakPtr mFullscreenRoot;
 
-  RefPtr<mozilla::dom::DOMImplementation> mDOMImplementation;
+  RefPtr<DOMImplementation> mDOMImplementation;
 
   RefPtr<nsContentList> mImageMaps;
 
   // A set of responsive images keyed by address pointer.
-  nsTHashtable<nsPtrHashKey<mozilla::dom::HTMLImageElement>> mResponsiveContent;
+  nsTHashtable<nsPtrHashKey<HTMLImageElement>> mResponsiveContent;
 
   // Tracking for plugins in the document.
   nsTHashtable<nsPtrHashKey<nsIObjectLoadingContent>> mPlugins;
 
-  RefPtr<mozilla::dom::DocumentTimeline> mDocumentTimeline;
-  mozilla::LinkedList<mozilla::dom::DocumentTimeline> mTimelines;
-
-  RefPtr<mozilla::dom::ScriptLoader> mScriptLoader;
-
-  nsRefPtrHashtable<nsPtrHashKey<nsIContent>, mozilla::dom::BoxObject>*
-      mBoxObjectTable;
+  RefPtr<DocumentTimeline> mDocumentTimeline;
+  LinkedList<DocumentTimeline> mTimelines;
+
+  RefPtr<dom::ScriptLoader> mScriptLoader;
+
+  nsRefPtrHashtable<nsPtrHashKey<nsIContent>, BoxObject>* mBoxObjectTable;
 
   // Tracker for animations that are waiting to start.
   // nullptr until GetOrCreatePendingAnimationTracker is called.
-  RefPtr<mozilla::PendingAnimationTracker> mPendingAnimationTracker;
+  RefPtr<PendingAnimationTracker> mPendingAnimationTracker;
 
   // A document "without a browsing context" that owns the content of
   // HTMLTemplateElement.
   RefPtr<Document> mTemplateContentsOwner;
 
-  mozilla::dom::ExternalResourceMap mExternalResourceMap;
+  dom::ExternalResourceMap mExternalResourceMap;
 
   // ScreenOrientation "pending promise" as described by
   // http://www.w3.org/TR/screen-orientation/
-  RefPtr<mozilla::dom::Promise> mOrientationPendingPromise;
+  RefPtr<Promise> mOrientationPendingPromise;
 
   uint16_t mCurrentOrientationAngle;
-  mozilla::dom::OrientationType mCurrentOrientationType;
+  OrientationType mCurrentOrientationType;
 
   nsTArray<RefPtr<nsFrameLoader>> mInitializableFrameLoaders;
   nsTArray<nsCOMPtr<nsIRunnable>> mFrameLoaderFinalizers;
   RefPtr<nsRunnableMethod<Document>> mFrameLoaderRunner;
 
   // The layout history state that should be used by nodes in this
   // document.  We only actually store a pointer to it when:
   // 1)  We have no script global object.
   // 2)  We haven't had Destroy() called on us yet.
   nsCOMPtr<nsILayoutHistoryState> mLayoutHistoryState;
 
   // These member variables cache information about the viewport so we don't
   // have to recalculate it each time.
-  mozilla::LayoutDeviceToScreenScale mScaleMinFloat;
-  mozilla::LayoutDeviceToScreenScale mScaleMaxFloat;
-  mozilla::LayoutDeviceToScreenScale mScaleFloat;
-  mozilla::CSSToLayoutDeviceScale mPixelRatio;
-
-  mozilla::CSSCoord mMinWidth;
-  mozilla::CSSCoord mMaxWidth;
-  mozilla::CSSCoord mMinHeight;
-  mozilla::CSSCoord mMaxHeight;
-
-  RefPtr<mozilla::EventListenerManager> mListenerManager;
+  LayoutDeviceToScreenScale mScaleMinFloat;
+  LayoutDeviceToScreenScale mScaleMaxFloat;
+  LayoutDeviceToScreenScale mScaleFloat;
+  CSSToLayoutDeviceScale mPixelRatio;
+
+  CSSCoord mMinWidth;
+  CSSCoord mMaxWidth;
+  CSSCoord mMinHeight;
+  CSSCoord mMaxHeight;
+
+  RefPtr<EventListenerManager> mListenerManager;
 
   nsCOMPtr<nsIRunnable> mMaybeEndOutermostXBLUpdateRunner;
   nsCOMPtr<nsIRequest> mOnloadBlocker;
 
-  nsTArray<RefPtr<mozilla::StyleSheet>>
-      mAdditionalSheets[AdditionalSheetTypeCount];
+  nsTArray<RefPtr<StyleSheet>> mAdditionalSheets[AdditionalSheetTypeCount];
 
   // Member to store out last-selected stylesheet set.
   nsString mLastStyleSheetSet;
   nsString mPreferredStyleSheetSet;
 
   RefPtr<DOMStyleSheetSetList> mStyleSheetSetList;
 
   // We lazily calculate declaration blocks for SVG elements with mapped
@@ -4695,18 +4652,18 @@ class Document : public nsINode,
   uint32_t mThrowOnDynamicMarkupInsertionCounter;
 
   // Count of unload/beforeunload/pagehide operations in progress.
   uint32_t mIgnoreOpensDuringUnloadCounter;
 
   nsCOMPtr<nsIDOMXULCommandDispatcher>
       mCommandDispatcher;  // [OWNER] of the focus tracker
 
-  RefPtr<mozilla::dom::XULBroadcastManager> mXULBroadcastManager;
-  RefPtr<mozilla::dom::XULPersist> mXULPersist;
+  RefPtr<XULBroadcastManager> mXULBroadcastManager;
+  RefPtr<XULPersist> mXULPersist;
 
   // document lightweight theme for use with :-moz-lwtheme,
   // :-moz-lwtheme-brighttext and :-moz-lwtheme-darktext
   DocumentTheme mDocLWTheme;
 
   // Pres shell resolution saved before entering fullscreen mode.
   float mSavedResolution;
 
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -1630,17 +1630,23 @@ bool nsFocusManager::Blur(nsPIDOMWindowO
         }
       }
     }
 
     // if the object being blurred is a remote browser, deactivate remote
     // content
     if (TabParent* remote = TabParent::GetFrom(element)) {
       remote->Deactivate();
-      LOGFOCUS(("Remote browser deactivated"));
+      LOGFOCUS(("Remote browser deactivated %p", remote));
+    }
+
+    // Same as above but for out-of-process iframes
+    if (BrowserBridgeChild* bbc = BrowserBridgeChild::GetFrom(element)) {
+      bbc->Deactivate();
+      LOGFOCUS(("Out-of-process iframe deactivated %p", bbc));
     }
   }
 
   bool result = true;
   if (sendBlurEvent) {
     // if there is an active window, update commands. If there isn't an active
     // window, then this was a blur caused by the active window being lowered,
     // so there is no need to update the commands
@@ -1845,23 +1851,23 @@ void nsFocusManager::Focus(nsPIDOMWindow
       if (presShell->GetDocument() == aElement->GetComposedDoc()) {
         if (aAdjustWidgets && objectFrameWidget && !sTestMode)
           objectFrameWidget->SetFocus(false);
 
         // if the object being focused is a remote browser, activate remote
         // content
         if (TabParent* remote = TabParent::GetFrom(aElement)) {
           remote->Activate();
-          LOGFOCUS(("Remote browser activated"));
+          LOGFOCUS(("Remote browser activated %p", remote));
         }
 
         // Same as above but for out-of-process iframes
         if (BrowserBridgeChild* bbc = BrowserBridgeChild::GetFrom(aElement)) {
           bbc->Activate();
-          LOGFOCUS(("Out-of-process iframe activated"));
+          LOGFOCUS(("Out-of-process iframe activated %p", bbc));
         }
       }
 
       IMEStateManager::OnChangeFocus(presContext, aElement,
                                      GetFocusMoveActionCause(aFlags));
 
       // as long as this focus wasn't because a window was raised, update the
       // commands
--- a/dom/ipc/BrowserBridgeChild.cpp
+++ b/dom/ipc/BrowserBridgeChild.cpp
@@ -1,15 +1,16 @@
 /* -*- 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/BrowserBridgeChild.h"
+#include "nsFocusManager.h"
 #include "nsFrameLoader.h"
 #include "nsFrameLoaderOwner.h"
 #include "nsQueryObject.h"
 
 using namespace mozilla::ipc;
 
 namespace mozilla {
 namespace dom {
@@ -79,16 +80,18 @@ void BrowserBridgeChild::UpdateDimension
 
 void BrowserBridgeChild::NavigateByKey(bool aForward,
                                        bool aForDocumentNavigation) {
   Unused << SendNavigateByKey(aForward, aForDocumentNavigation);
 }
 
 void BrowserBridgeChild::Activate() { Unused << SendActivate(); }
 
+void BrowserBridgeChild::Deactivate() { Unused << SendDeactivate(); }
+
 /*static*/
 BrowserBridgeChild* BrowserBridgeChild::GetFrom(nsFrameLoader* aFrameLoader) {
   if (!aFrameLoader) {
     return nullptr;
   }
   return aFrameLoader->GetBrowserBridgeChild();
 }
 
@@ -104,14 +107,66 @@ BrowserBridgeChild* BrowserBridgeChild::
 
 IPCResult BrowserBridgeChild::RecvSetLayersId(
     const mozilla::layers::LayersId& aLayersId) {
   MOZ_ASSERT(!mLayersId.IsValid() && aLayersId.IsValid());
   mLayersId = aLayersId;
   return IPC_OK();
 }
 
+mozilla::ipc::IPCResult BrowserBridgeChild::RecvRequestFocus(
+    const bool& aCanRaise) {
+  // Adapted from TabParent
+  nsCOMPtr<nsIFocusManager> fm = nsFocusManager::GetFocusManager();
+  if (!fm) {
+    return IPC_OK();
+  }
+
+  RefPtr<Element> owner = mFrameLoader->GetOwnerContent();
+
+  if (!owner || !owner->OwnerDoc()) {
+    return IPC_OK();
+  }
+
+  uint32_t flags = nsIFocusManager::FLAG_NOSCROLL;
+  if (aCanRaise) {
+    flags |= nsIFocusManager::FLAG_RAISE;
+  }
+
+  fm->SetFocus(owner, flags);
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserBridgeChild::RecvMoveFocus(
+    const bool& aForward, const bool& aForDocumentNavigation) {
+  // Adapted from TabParent
+  nsCOMPtr<nsIFocusManager> fm = nsFocusManager::GetFocusManager();
+  if (!fm) {
+    return IPC_OK();
+  }
+
+  RefPtr<Element> owner = mFrameLoader->GetOwnerContent();
+
+  if (!owner || !owner->OwnerDoc()) {
+    return IPC_OK();
+  }
+
+  RefPtr<Element> dummy;
+
+  uint32_t type =
+      aForward
+          ? (aForDocumentNavigation
+                 ? static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_FORWARDDOC)
+                 : static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_FORWARD))
+          : (aForDocumentNavigation
+                 ? static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_BACKWARDDOC)
+                 : static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_BACKWARD));
+  fm->MoveFocus(nullptr, owner, type, nsIFocusManager::FLAG_BYKEY,
+                getter_AddRefs(dummy));
+  return IPC_OK();
+}
+
 void BrowserBridgeChild::ActorDestroy(ActorDestroyReason aWhy) {
   mIPCOpen = false;
 }
 
 }  // namespace dom
 }  // namespace mozilla
--- a/dom/ipc/BrowserBridgeChild.h
+++ b/dom/ipc/BrowserBridgeChild.h
@@ -33,26 +33,33 @@ class BrowserBridgeChild : public PBrows
 
   void UpdateDimensions(const nsIntRect& aRect,
                         const mozilla::ScreenIntSize& aSize);
 
   void NavigateByKey(bool aForward, bool aForDocumentNavigation);
 
   void Activate();
 
+  void Deactivate();
+
   static BrowserBridgeChild* GetFrom(nsFrameLoader* aFrameLoader);
 
   static BrowserBridgeChild* GetFrom(nsIContent* aContent);
 
  protected:
   friend class PBrowserBridgeChild;
 
   mozilla::ipc::IPCResult RecvSetLayersId(
       const mozilla::layers::LayersId& aLayersId);
 
+  mozilla::ipc::IPCResult RecvRequestFocus(const bool& aCanRaise);
+
+  mozilla::ipc::IPCResult RecvMoveFocus(const bool& aForward,
+                                        const bool& aForDocumentNavigation);
+
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
  private:
   explicit BrowserBridgeChild(nsFrameLoader* aFrameLoader);
   ~BrowserBridgeChild();
 
   mozilla::layers::LayersId mLayersId;
   bool mIPCOpen;
--- a/dom/ipc/BrowserBridgeParent.cpp
+++ b/dom/ipc/BrowserBridgeParent.cpp
@@ -122,14 +122,19 @@ IPCResult BrowserBridgeParent::RecvNavig
   return IPC_OK();
 }
 
 IPCResult BrowserBridgeParent::RecvActivate() {
   mTabParent->Activate();
   return IPC_OK();
 }
 
+IPCResult BrowserBridgeParent::RecvDeactivate() {
+  mTabParent->Deactivate();
+  return IPC_OK();
+}
+
 void BrowserBridgeParent::ActorDestroy(ActorDestroyReason aWhy) {
   mIPCOpen = false;
 }
 
 }  // namespace dom
 }  // namespace mozilla
--- a/dom/ipc/BrowserBridgeParent.h
+++ b/dom/ipc/BrowserBridgeParent.h
@@ -43,16 +43,18 @@ class BrowserBridgeParent : public PBrow
                                            const bool& aForceRepaint,
                                            const LayersObserverEpoch& aEpoch);
 
   mozilla::ipc::IPCResult RecvNavigateByKey(const bool& aForward,
                                             const bool& aForDocumentNavigation);
 
   mozilla::ipc::IPCResult RecvActivate();
 
+  mozilla::ipc::IPCResult RecvDeactivate();
+
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
  private:
   ~BrowserBridgeParent();
 
   RefPtr<TabParent> mTabParent;
   bool mIPCOpen;
 };
--- a/dom/ipc/PBrowserBridge.ipdl
+++ b/dom/ipc/PBrowserBridge.ipdl
@@ -20,16 +20,29 @@ namespace dom {
  * PBrowserBridge corresponds to a remote iframe.
  */
 async protocol PBrowserBridge {
   manager PBrowser;
 
 child:
   async SetLayersId(LayersId layersId);
 
+  /**
+   * Request that the IPC child / Web parent process move focus to the
+   * browser's frame. If canRaise is true, the window can be raised if
+   * it is inactive.
+   */
+  async RequestFocus(bool canRaise);
+
+  /**
+   * When IPC parent / Web child sends this message, the IPC child / Web parent
+   * should move focus to the next or previous focusable element or document.
+   */
+  async MoveFocus(bool forward, bool forDocumentNavigation);
+
 parent:
   // Destroy the remote web browser due to the nsFrameLoader going away.
   async __delete__();
 
   // DocShell messaging.
   async LoadURL(nsCString aSpec);
 
   // Out of process rendering.
@@ -42,12 +55,14 @@ parent:
    */
   async NavigateByKey(bool aForward, bool aForDocumentNavigation);
 
   /**
    * Sending an activate message moves focus to the iframe.
    */
   async Activate();
 
+  async Deactivate();
+
 };
 
 }  // namespace dom
 }  // namespace mozilla
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -126,16 +126,21 @@ using namespace mozilla::layers;
 using namespace mozilla::layout;
 using namespace mozilla::services;
 using namespace mozilla::widget;
 using namespace mozilla::jsipc;
 using namespace mozilla::gfx;
 
 using mozilla::Unused;
 
+LazyLogModule gBrowserFocusLog("BrowserFocus");
+
+#define LOGBROWSERFOCUS(args) \
+  MOZ_LOG(gBrowserFocusLog, mozilla::LogLevel::Debug, args)
+
 // The flags passed by the webProgress notifications are 16 bits shifted
 // from the ones registered by webProgressListeners.
 #define NOTIFY_FLAG_SHIFT 16
 
 namespace mozilla {
 namespace dom {
 
 TabParent::LayerToTabParentTable* TabParent::sLayerToTabParentTable = nullptr;
@@ -477,17 +482,26 @@ void TabParent::ActorDestroy(ActorDestro
   if (os) {
     os->NotifyObservers(NS_ISUPPORTS_CAST(nsITabParent*, this),
                         "ipc:browser-destroyed", nullptr);
   }
 }
 
 mozilla::ipc::IPCResult TabParent::RecvMoveFocus(
     const bool& aForward, const bool& aForDocumentNavigation) {
-  nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
+  LOGBROWSERFOCUS(("RecvMoveFocus %p, aForward: %d, aForDocumentNavigation: %d",
+                   this, aForward, aForDocumentNavigation));
+  BrowserBridgeParent* bridgeParent = GetBrowserBridgeParent();
+  if (bridgeParent) {
+    mozilla::Unused << bridgeParent->SendMoveFocus(aForward,
+                                                   aForDocumentNavigation);
+    return IPC_OK();
+  }
+
+  nsCOMPtr<nsIFocusManager> fm = nsFocusManager::GetFocusManager();
   if (fm) {
     RefPtr<Element> dummy;
 
     uint32_t type =
         aForward
             ? (aForDocumentNavigation
                    ? static_cast<uint32_t>(
                          nsIFocusManager::MOVEFOCUS_FORWARDDOC)
@@ -814,22 +828,24 @@ void TabParent::HandleAccessKey(const Wi
     // because the event may be dispatched to it as normal keyboard event.
     // Therefore, we should use local copy to send it.
     WidgetKeyboardEvent localEvent(aEvent);
     Unused << SendHandleAccessKey(localEvent, aCharCodes);
   }
 }
 
 void TabParent::Activate() {
+  LOGBROWSERFOCUS(("Activate %p", this));
   if (!mIsDestroyed) {
     Unused << Manager()->SendActivate(this);
   }
 }
 
 void TabParent::Deactivate() {
+  LOGBROWSERFOCUS(("Deactivate %p", this));
   if (!mIsDestroyed) {
     Unused << Manager()->SendDeactivate(this);
   }
 }
 
 a11y::PDocAccessibleParent* TabParent::AllocPDocAccessibleParent(
     PDocAccessibleParent* aParent, const uint64_t&, const uint32_t&,
     const IAccessibleHolder&) {
@@ -1890,16 +1906,23 @@ mozilla::ipc::IPCResult TabParent::RecvO
   // plugin process of the key event's result.
   bool consumed = (rv == NS_SUCCESS_EVENT_CONSUMED);
   HandledWindowedPluginKeyEvent(aKeyEventData, consumed);
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult TabParent::RecvRequestFocus(const bool& aCanRaise) {
+  LOGBROWSERFOCUS(("RecvRequestFocus %p, aCanRaise: %d", this, aCanRaise));
+  BrowserBridgeParent* bridgeParent = GetBrowserBridgeParent();
+  if (bridgeParent) {
+    mozilla::Unused << bridgeParent->SendRequestFocus(aCanRaise);
+    return IPC_OK();
+  }
+
   nsCOMPtr<nsIFocusManager> fm = nsFocusManager::GetFocusManager();
   if (!fm) {
     return IPC_OK();
   }
 
   if (!mFrameElement || !mFrameElement->OwnerDoc()) {
     return IPC_OK();
   }
--- a/dom/media/webrtc/MediaEngineDefault.cpp
+++ b/dom/media/webrtc/MediaEngineDefault.cpp
@@ -32,24 +32,28 @@ namespace mozilla {
 
 using namespace mozilla::gfx;
 
 static nsString DefaultVideoName() {
   // For the purpose of testing we allow to change the name of the fake device
   // by pref.
   nsAutoString cameraNameFromPref;
   nsresult rv;
-  NS_DispatchToMainThread(
-      NS_NewRunnableFunction(__func__,
-                             [&]() {
-                               rv = Preferences::GetString(
-                                   "media.getusermedia.fake-camera-name",
-                                   cameraNameFromPref);
-                             }),
-      NS_DISPATCH_SYNC);
+  // Here it is preferred a "hard" block, provided by the combination of Await &
+  // InvokeAsync, instead of "soft" block, provided by sync dispatch which
+  // allows the waiting thread to spin its event loop. The latter would allow
+  // miltiple enumeration requests being processed out-of-order.
+  media::Await(
+      do_AddRef(SystemGroup::EventTargetFor(TaskCategory::Other)),
+      InvokeAsync(
+          SystemGroup::EventTargetFor(TaskCategory::Other), __func__, [&]() {
+            rv = Preferences::GetString("media.getusermedia.fake-camera-name",
+                                        cameraNameFromPref);
+            return GenericPromise::CreateAndResolve(true, __func__);
+          }));
 
   if (NS_SUCCEEDED(rv)) {
     return std::move(cameraNameFromPref);
   }
   return NS_LITERAL_STRING(u"Default Video Device");
 }
 
 /**
--- a/dom/script/ScriptLoader.cpp
+++ b/dom/script/ScriptLoader.cpp
@@ -3335,17 +3335,17 @@ void ScriptLoader::ReportPreloadErrorsTo
     }
   }
 }
 
 void ScriptLoader::HandleLoadError(ScriptLoadRequest* aRequest,
                                    nsresult aResult) {
   /*
    * Handle script not loading error because source was an tracking URL (or
-   * fingerprinting, cryptoming, etc).
+   * fingerprinting, cryptomining, etc).
    * We make a note of this script node by including it in a dedicated
    * array of blocked tracking nodes under its parent document.
    */
   if (net::UrlClassifierFeatureFactory::IsClassifierBlockingErrorCode(
           aResult)) {
     nsCOMPtr<nsIContent> cont = do_QueryInterface(aRequest->Element());
     mDocument->AddBlockedNodeByClassifier(cont);
   }
--- a/dom/tests/mochitest/fetch/mochitest.ini
+++ b/dom/tests/mochitest/fetch/mochitest.ini
@@ -52,16 +52,17 @@ prefs =
 [test_headers_sw_reroute.html]
 [test_headers_mainthread.html]
 [test_fetch_basic.html]
 [test_fetch_basic_sw_reroute.html]
 skip-if = toolkit == 'android' && !is_fennec # Bug 1525959
 [test_fetch_basic_sw_empty_reroute.html]
 [test_fetch_basic_http.html]
 [test_fetch_basic_http_sw_reroute.html]
+skip-if = os == "android" && !debug # Bug 1532023
 [test_fetch_basic_http_sw_empty_reroute.html]
 [test_fetch_cached_redirect.html]
 [test_fetch_cors.html]
 skip-if = toolkit == 'android' # Bug 1210282
 [test_fetch_cors_sw_reroute.html]
 skip-if = toolkit == 'android' # Bug 1210282
 [test_fetch_cors_sw_empty_reroute.html]
 skip-if = toolkit == 'android' # Bug 1210282
--- a/dom/workers/sharedworkers/SharedWorkerManager.cpp
+++ b/dom/workers/sharedworkers/SharedWorkerManager.cpp
@@ -14,16 +14,30 @@
 #include "nsIConsoleReportCollector.h"
 #include "nsINetworkInterceptController.h"
 #include "nsIPrincipal.h"
 #include "nsProxyRelease.h"
 
 namespace mozilla {
 namespace dom {
 
+// static
+already_AddRefed<SharedWorkerManagerHolder> SharedWorkerManager::Create(
+    SharedWorkerService* aService, nsIEventTarget* aPBackgroundEventTarget,
+    const RemoteWorkerData& aData, nsIPrincipal* aLoadingPrincipal) {
+  MOZ_ASSERT(NS_IsMainThread());
+
+  RefPtr<SharedWorkerManager> manager = new SharedWorkerManager(
+      aPBackgroundEventTarget, aData, aLoadingPrincipal);
+
+  RefPtr<SharedWorkerManagerHolder> holder =
+      new SharedWorkerManagerHolder(manager, aService);
+  return holder.forget();
+}
+
 SharedWorkerManager::SharedWorkerManager(
     nsIEventTarget* aPBackgroundEventTarget, const RemoteWorkerData& aData,
     nsIPrincipal* aLoadingPrincipal)
     : mPBackgroundEventTarget(aPBackgroundEventTarget),
       mLoadingPrincipal(aLoadingPrincipal),
       mDomain(aData.domain()),
       mResolvedScriptURL(DeserializeURI(aData.resolvedScriptURL())),
       mName(aData.name()),
@@ -60,30 +74,41 @@ bool SharedWorkerManager::MaybeCreateRem
   if (aWindowID) {
     mRemoteWorkerController->AddWindowID(aWindowID);
   }
 
   mRemoteWorkerController->AddPortIdentifier(aPortIdentifier);
   return true;
 }
 
-bool SharedWorkerManager::MatchOnMainThread(
-    const nsACString& aDomain, nsIURI* aScriptURL, const nsAString& aName,
-    nsIPrincipal* aLoadingPrincipal) const {
+already_AddRefed<SharedWorkerManagerHolder>
+SharedWorkerManager::MatchOnMainThread(SharedWorkerService* aService,
+                                       const nsACString& aDomain,
+                                       nsIURI* aScriptURL,
+                                       const nsAString& aName,
+                                       nsIPrincipal* aLoadingPrincipal) {
   MOZ_ASSERT(NS_IsMainThread());
+
   bool urlEquals;
   if (NS_FAILED(aScriptURL->Equals(mResolvedScriptURL, &urlEquals))) {
-    return false;
+    return nullptr;
   }
 
-  return aDomain == mDomain && urlEquals && aName == mName &&
-         // We want to be sure that the window's principal subsumes the
-         // SharedWorker's loading principal and vice versa.
-         mLoadingPrincipal->Subsumes(aLoadingPrincipal) &&
-         aLoadingPrincipal->Subsumes(mLoadingPrincipal);
+  bool match = aDomain == mDomain && urlEquals && aName == mName &&
+               // We want to be sure that the window's principal subsumes the
+               // SharedWorker's loading principal and vice versa.
+               mLoadingPrincipal->Subsumes(aLoadingPrincipal) &&
+               aLoadingPrincipal->Subsumes(mLoadingPrincipal);
+  if (!match) {
+    return nullptr;
+  }
+
+  RefPtr<SharedWorkerManagerHolder> holder =
+      new SharedWorkerManagerHolder(this, aService);
+  return holder.forget();
 }
 
 void SharedWorkerManager::AddActor(SharedWorkerParent* aParent) {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aParent);
   MOZ_ASSERT(!mActors.Contains(aParent));
 
   mActors.AppendElement(aParent);
@@ -107,24 +132,25 @@ void SharedWorkerManager::RemoveActor(Sh
   mActors.RemoveElement(aParent);
 
   if (!mActors.IsEmpty()) {
     // Our remaining actors could be all suspended or frozen.
     UpdateSuspend();
     UpdateFrozen();
     return;
   }
+}
 
-  // Time to go.
+void SharedWorkerManager::Terminate() {
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(mActors.IsEmpty());
+  MOZ_ASSERT(mHolders.IsEmpty());
 
   mRemoteWorkerController->Terminate();
   mRemoteWorkerController = nullptr;
-
-  // SharedWorkerService exists because it is kept alive by SharedWorkerParent.
-  SharedWorkerService::Get()->RemoveWorkerManager(this);
 }
 
 void SharedWorkerManager::UpdateSuspend() {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(mRemoteWorkerController);
 
   uint32_t suspended = 0;
 
@@ -204,10 +230,67 @@ void SharedWorkerManager::ErrorReceived(
 void SharedWorkerManager::Terminated() {
   AssertIsOnBackgroundThread();
 
   for (SharedWorkerParent* actor : mActors) {
     Unused << actor->SendTerminate();
   }
 }
 
+void SharedWorkerManager::RegisterHolder(SharedWorkerManagerHolder* aHolder) {
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aHolder);
+  MOZ_ASSERT(!mHolders.Contains(aHolder));
+
+  mHolders.AppendElement(aHolder);
+}
+
+void SharedWorkerManager::UnregisterHolder(SharedWorkerManagerHolder* aHolder) {
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aHolder);
+  MOZ_ASSERT(mHolders.Contains(aHolder));
+
+  mHolders.RemoveElement(aHolder);
+
+  if (!mHolders.IsEmpty()) {
+    return;
+  }
+
+  // Time to go.
+
+  aHolder->Service()->RemoveWorkerManagerOnMainThread(this);
+
+  RefPtr<SharedWorkerManager> self = this;
+  mPBackgroundEventTarget->Dispatch(
+      NS_NewRunnableFunction(
+          "SharedWorkerService::RemoveWorkerManagerOnMainThread",
+          [self]() { self->Terminate(); }),
+      NS_DISPATCH_NORMAL);
+}
+
+SharedWorkerManagerHolder::SharedWorkerManagerHolder(
+    SharedWorkerManager* aManager, SharedWorkerService* aService)
+    : mManager(aManager), mService(aService) {
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aManager);
+  MOZ_ASSERT(aService);
+
+  aManager->RegisterHolder(this);
+}
+
+SharedWorkerManagerHolder::~SharedWorkerManagerHolder() {
+  MOZ_ASSERT(NS_IsMainThread());
+  mManager->UnregisterHolder(this);
+}
+
+SharedWorkerManagerWrapper::SharedWorkerManagerWrapper(
+    already_AddRefed<SharedWorkerManagerHolder> aHolder)
+    : mHolder(aHolder) {
+  MOZ_ASSERT(NS_IsMainThread());
+}
+
+SharedWorkerManagerWrapper::~SharedWorkerManagerWrapper() {
+  NS_ReleaseOnMainThreadSystemGroup("SharedWorkerManagerWrapper::mHolder",
+                                    mHolder.forget());
+}
+
 }  // namespace dom
 }  // namespace mozilla
--- a/dom/workers/sharedworkers/SharedWorkerManager.h
+++ b/dom/workers/sharedworkers/SharedWorkerManager.h
@@ -13,31 +13,73 @@
 
 class nsIPrincipal;
 
 namespace mozilla {
 namespace dom {
 
 class MessagePortIdentifier;
 class RemoteWorkerData;
+class SharedWorkerManager;
+class SharedWorkerService;
 class SharedWorkerParent;
 
+// Main-thread only object that keeps a manager and the service alive.
+// When the last SharedWorkerManagerHolder is released, the corresponding
+// manager unregisters itself from the service and terminates the worker.
+class SharedWorkerManagerHolder final {
+ public:
+  NS_INLINE_DECL_REFCOUNTING(SharedWorkerManagerHolder);
+
+  SharedWorkerManagerHolder(SharedWorkerManager* aManager,
+                            SharedWorkerService* aService);
+
+  SharedWorkerManager* Manager() const { return mManager; }
+
+  SharedWorkerService* Service() const { return mService; }
+
+ private:
+  ~SharedWorkerManagerHolder();
+
+  RefPtr<SharedWorkerManager> mManager;
+  RefPtr<SharedWorkerService> mService;
+};
+
+// Thread-safe wrapper for SharedWorkerManagerHolder.
+class SharedWorkerManagerWrapper final {
+ public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedWorkerManagerWrapper);
+
+  explicit SharedWorkerManagerWrapper(
+      already_AddRefed<SharedWorkerManagerHolder> aHolder);
+
+  SharedWorkerManager* Manager() const { return mHolder->Manager(); }
+
+ private:
+  ~SharedWorkerManagerWrapper();
+
+  RefPtr<SharedWorkerManagerHolder> mHolder;
+};
+
 class SharedWorkerManager final : public RemoteWorkerObserver {
  public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedWorkerManager, override);
 
   // Called on main-thread thread methods
 
-  SharedWorkerManager(nsIEventTarget* aPBackgroundEventTarget,
-                      const RemoteWorkerData& aData,
-                      nsIPrincipal* aLoadingPrincipal);
+  static already_AddRefed<SharedWorkerManagerHolder> Create(
+      SharedWorkerService* aService, nsIEventTarget* aPBackgroundEventTarget,
+      const RemoteWorkerData& aData, nsIPrincipal* aLoadingPrincipal);
 
-  bool MatchOnMainThread(const nsACString& aDomain, nsIURI* aScriptURL,
-                         const nsAString& aName,
-                         nsIPrincipal* aLoadingPrincipal) const;
+  // Returns a holder if this manager matches. The holder blocks the shutdown of
+  // the manager.
+  already_AddRefed<SharedWorkerManagerHolder> MatchOnMainThread(
+      SharedWorkerService* aService, const nsACString& aDomain,
+      nsIURI* aScriptURL, const nsAString& aName,
+      nsIPrincipal* aLoadingPrincipal);
 
   // RemoteWorkerObserver
 
   void CreationFailed() override;
 
   void CreationSucceeded() override;
 
   void ErrorReceived(const ErrorValue& aValue) override;
@@ -56,17 +98,29 @@ class SharedWorkerManager final : public
   void RemoveActor(SharedWorkerParent* aParent);
 
   void UpdateSuspend();
 
   void UpdateFrozen();
 
   bool IsSecureContext() const;
 
+  void Terminate();
+
+  // Called on main-thread only.
+
+  void RegisterHolder(SharedWorkerManagerHolder* aHolder);
+
+  void UnregisterHolder(SharedWorkerManagerHolder* aHolder);
+
  private:
+  SharedWorkerManager(nsIEventTarget* aPBackgroundEventTarget,
+                      const RemoteWorkerData& aData,
+                      nsIPrincipal* aLoadingPrincipal);
+
   ~SharedWorkerManager();
 
   nsCOMPtr<nsIEventTarget> mPBackgroundEventTarget;
 
   nsCOMPtr<nsIPrincipal> mLoadingPrincipal;
   nsCString mDomain;
   nsCOMPtr<nsIURI> mResolvedScriptURL;
   nsString mName;
@@ -74,14 +128,18 @@ class SharedWorkerManager final : public
   bool mSuspended;
   bool mFrozen;
 
   // Raw pointers because SharedWorkerParent unregisters itself in
   // ActorDestroy().
   nsTArray<SharedWorkerParent*> mActors;
 
   RefPtr<RemoteWorkerController> mRemoteWorkerController;
+
+  // Main-thread only. Raw Pointers because holders keep the manager alive and
+  // they unregister themselves in their DTOR.
+  nsTArray<SharedWorkerManagerHolder*> mHolders;
 };
 
 }  // namespace dom
 }  // namespace mozilla
 
 #endif  // mozilla_dom_SharedWorkerManager_h
--- a/dom/workers/sharedworkers/SharedWorkerParent.cpp
+++ b/dom/workers/sharedworkers/SharedWorkerParent.cpp
@@ -26,130 +26,131 @@ SharedWorkerParent::SharedWorkerParent()
   AssertIsOnBackgroundThread();
 }
 
 SharedWorkerParent::~SharedWorkerParent() = default;
 
 void SharedWorkerParent::ActorDestroy(IProtocol::ActorDestroyReason aReason) {
   AssertIsOnBackgroundThread();
 
-  if (mWorkerManager) {
-    mWorkerManager->RemoveActor(this);
-    mWorkerManager = nullptr;
+  if (mWorkerManagerWrapper) {
+    mWorkerManagerWrapper->Manager()->RemoveActor(this);
+    mWorkerManagerWrapper = nullptr;
   }
 }
 
 void SharedWorkerParent::Initialize(
     const RemoteWorkerData& aData, uint64_t aWindowID,
     const MessagePortIdentifier& aPortIdentifier) {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(mStatus == eInit);
 
-  // Let's keep the service alive.
-  mService = SharedWorkerService::GetOrCreate();
-  MOZ_ASSERT(mService);
-
   mWindowID = aWindowID;
 
   mStatus = ePending;
-  mService->GetOrCreateWorkerManager(this, aData, aWindowID, aPortIdentifier);
+
+  RefPtr<SharedWorkerService> service = SharedWorkerService::GetOrCreate();
+  MOZ_ASSERT(service);
+  service->GetOrCreateWorkerManager(this, aData, aWindowID, aPortIdentifier);
 }
 
 IPCResult SharedWorkerParent::RecvClose() {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(mStatus == ePending || mStatus == eActive);
 
   mStatus = eClosed;
 
-  if (mWorkerManager) {
-    mWorkerManager->RemoveActor(this);
-    mWorkerManager = nullptr;
+  if (mWorkerManagerWrapper) {
+    mWorkerManagerWrapper->Manager()->RemoveActor(this);
+    mWorkerManagerWrapper = nullptr;
   }
 
   Unused << Send__delete__(this);
   return IPC_OK();
 }
 
 IPCResult SharedWorkerParent::RecvSuspend() {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(!mSuspended);
   MOZ_ASSERT(mStatus == ePending || mStatus == eActive);
 
   mSuspended = true;
 
   if (mStatus == eActive) {
-    MOZ_ASSERT(mWorkerManager);
-    mWorkerManager->UpdateSuspend();
+    MOZ_ASSERT(mWorkerManagerWrapper);
+    mWorkerManagerWrapper->Manager()->UpdateSuspend();
   }
 
   return IPC_OK();
 }
 
 IPCResult SharedWorkerParent::RecvResume() {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(mSuspended);
   MOZ_ASSERT(mStatus == ePending || mStatus == eActive);
 
   mSuspended = false;
 
   if (mStatus == eActive) {
-    MOZ_ASSERT(mWorkerManager);
-    mWorkerManager->UpdateSuspend();
+    MOZ_ASSERT(mWorkerManagerWrapper);
+    mWorkerManagerWrapper->Manager()->UpdateSuspend();
   }
 
   return IPC_OK();
 }
 
 IPCResult SharedWorkerParent::RecvFreeze() {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(!mFrozen);
   MOZ_ASSERT(mStatus == ePending || mStatus == eActive);
 
   mFrozen = true;
 
   if (mStatus == eActive) {
-    MOZ_ASSERT(mWorkerManager);
-    mWorkerManager->UpdateFrozen();
+    MOZ_ASSERT(mWorkerManagerWrapper);
+    mWorkerManagerWrapper->Manager()->UpdateFrozen();
   }
 
   return IPC_OK();
 }
 
 IPCResult SharedWorkerParent::RecvThaw() {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(mFrozen);
   MOZ_ASSERT(mStatus == ePending || mStatus == eActive);
 
   mFrozen = false;
 
   if (mStatus == eActive) {
-    MOZ_ASSERT(mWorkerManager);
-    mWorkerManager->UpdateFrozen();
+    MOZ_ASSERT(mWorkerManagerWrapper);
+    mWorkerManagerWrapper->Manager()->UpdateFrozen();
   }
 
   return IPC_OK();
 }
 
-void SharedWorkerParent::ManagerCreated(SharedWorkerManager* aWorkerManager) {
+void SharedWorkerParent::ManagerCreated(
+    already_AddRefed<SharedWorkerManagerWrapper> aWorkerManagerWrapper) {
   AssertIsOnBackgroundThread();
-  MOZ_ASSERT(aWorkerManager);
-  MOZ_ASSERT(!mWorkerManager);
+  MOZ_ASSERT(!mWorkerManagerWrapper);
   MOZ_ASSERT(mStatus == ePending || mStatus == eClosed);
 
+  RefPtr<SharedWorkerManagerWrapper> wrapper = aWorkerManagerWrapper;
+
   // Already gone.
   if (mStatus == eClosed) {
-    aWorkerManager->RemoveActor(this);
+    wrapper->Manager()->RemoveActor(this);
     return;
   }
 
   mStatus = eActive;
-  mWorkerManager = aWorkerManager;
+  mWorkerManagerWrapper = wrapper;
 
-  mWorkerManager->UpdateFrozen();
-  mWorkerManager->UpdateSuspend();
+  mWorkerManagerWrapper->Manager()->UpdateFrozen();
+  mWorkerManagerWrapper->Manager()->UpdateSuspend();
 }
 
 void SharedWorkerParent::ErrorPropagation(nsresult aError) {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(NS_FAILED(aError));
   MOZ_ASSERT(mStatus == ePending || mStatus == eClosed);
 
   // Already gone.
--- a/dom/workers/sharedworkers/SharedWorkerParent.h
+++ b/dom/workers/sharedworkers/SharedWorkerParent.h
@@ -11,29 +11,29 @@
 #include "mozilla/ipc/BackgroundUtils.h"
 #include "nsISupportsImpl.h"
 
 namespace mozilla {
 namespace dom {
 
 class MessagePortIdentifier;
 class RemoteWorkerData;
-class SharedWorkerManager;
-class SharedWorkerService;
+class SharedWorkerManagerWrapper;
 
 class SharedWorkerParent final : public mozilla::dom::PSharedWorkerParent {
  public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedWorkerParent)
 
   SharedWorkerParent();
 
   void Initialize(const RemoteWorkerData& aData, uint64_t aWindowID,
                   const MessagePortIdentifier& aPortIdentifier);
 
-  void ManagerCreated(SharedWorkerManager* aWorkerManager);
+  void ManagerCreated(
+      already_AddRefed<SharedWorkerManagerWrapper> aWorkerManagerWrapper);
 
   void ErrorPropagation(nsresult aError);
 
   mozilla::ipc::IPCResult RecvClose();
 
   mozilla::ipc::IPCResult RecvSuspend();
 
   mozilla::ipc::IPCResult RecvResume();
@@ -49,18 +49,17 @@ class SharedWorkerParent final : public 
   uint64_t WindowID() const { return mWindowID; }
 
  private:
   ~SharedWorkerParent();
 
   void ActorDestroy(IProtocol::ActorDestroyReason aReason) override;
 
   nsCOMPtr<nsIEventTarget> mBackgroundEventTarget;
-  RefPtr<SharedWorkerManager> mWorkerManager;
-  RefPtr<SharedWorkerService> mService;
+  RefPtr<SharedWorkerManagerWrapper> mWorkerManagerWrapper;
 
   enum {
     eInit,
     ePending,
     eActive,
     eClosed,
   } mStatus;
 
--- a/dom/workers/sharedworkers/SharedWorkerService.cpp
+++ b/dom/workers/sharedworkers/SharedWorkerService.cpp
@@ -4,28 +4,30 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SharedWorkerService.h"
 #include "mozilla/dom/RemoteWorkerTypes.h"
 #include "mozilla/ipc/BackgroundParent.h"
 #include "mozilla/StaticMutex.h"
 #include "mozilla/SystemGroup.h"
+#include "nsProxyRelease.h"
 
 namespace mozilla {
 
 using namespace ipc;
 
 namespace dom {
 
 namespace {
 
 StaticMutex sSharedWorkerMutex;
 
-// Raw pointer because SharedWorkerParent keeps this object alive.
+// Raw pointer because SharedWorkerParent keeps this object alive, indirectly
+// via SharedWorkerManagerHolder.
 SharedWorkerService* MOZ_NON_OWNING_REF sSharedWorkerService;
 
 nsresult PopulateContentSecurityPolicy(
     nsIContentSecurityPolicy* aCSP,
     const nsTArray<ContentSecurityPolicy>& aPolicies) {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aCSP);
   MOZ_ASSERT(!aPolicies.IsEmpty());
@@ -65,100 +67,76 @@ nsresult PopulatePrincipalContentSecurit
     }
   }
 
   return NS_OK;
 }
 
 class GetOrCreateWorkerManagerRunnable final : public Runnable {
  public:
-  GetOrCreateWorkerManagerRunnable(SharedWorkerParent* aActor,
+  GetOrCreateWorkerManagerRunnable(SharedWorkerService* aService,
+                                   SharedWorkerParent* aActor,
                                    const RemoteWorkerData& aData,
                                    uint64_t aWindowID,
                                    const MessagePortIdentifier& aPortIdentifier)
       : Runnable("GetOrCreateWorkerManagerRunnable"),
         mBackgroundEventTarget(GetCurrentThreadEventTarget()),
+        mService(aService),
         mActor(aActor),
         mData(aData),
         mWindowID(aWindowID),
         mPortIdentifier(aPortIdentifier) {}
 
   NS_IMETHOD
   Run() {
-    // The service is always available because it's kept alive by the actor.
-    SharedWorkerService* service = SharedWorkerService::Get();
-    MOZ_ASSERT(service);
-
-    service->GetOrCreateWorkerManagerOnMainThread(
+    mService->GetOrCreateWorkerManagerOnMainThread(
         mBackgroundEventTarget, mActor, mData, mWindowID, mPortIdentifier);
 
     return NS_OK;
   }
 
  private:
   nsCOMPtr<nsIEventTarget> mBackgroundEventTarget;
+  RefPtr<SharedWorkerService> mService;
   RefPtr<SharedWorkerParent> mActor;
   RemoteWorkerData mData;
   uint64_t mWindowID;
   MessagePortIdentifier mPortIdentifier;
 };
 
-class RemoveWorkerManagerRunnable final : public Runnable {
- public:
-  RemoveWorkerManagerRunnable(SharedWorkerService* aService,
-                              SharedWorkerManager* aManager)
-      : Runnable("RemoveWorkerManagerRunnable"),
-        mService(aService),
-        mManager(aManager) {
-    MOZ_ASSERT(mService);
-    MOZ_ASSERT(mManager);
-  }
-
-  NS_IMETHOD
-  Run() {
-    mService->RemoveWorkerManagerOnMainThread(mManager);
-    return NS_OK;
-  }
-
- private:
-  RefPtr<SharedWorkerService> mService;
-  RefPtr<SharedWorkerManager> mManager;
-};
-
 class WorkerManagerCreatedRunnable final : public Runnable {
  public:
-  WorkerManagerCreatedRunnable(SharedWorkerManager* aManager,
-                               SharedWorkerParent* aActor,
-                               const RemoteWorkerData& aData,
-                               uint64_t aWindowID,
-                               const MessagePortIdentifier& aPortIdentifier)
+  WorkerManagerCreatedRunnable(
+      already_AddRefed<SharedWorkerManagerWrapper> aManagerWrapper,
+      SharedWorkerParent* aActor, const RemoteWorkerData& aData,
+      uint64_t aWindowID, const MessagePortIdentifier& aPortIdentifier)
       : Runnable("WorkerManagerCreatedRunnable"),
-        mManager(aManager),
+        mManagerWrapper(aManagerWrapper),
         mActor(aActor),
         mData(aData),
         mWindowID(aWindowID),
         mPortIdentifier(aPortIdentifier) {}
 
   NS_IMETHOD
   Run() {
     AssertIsOnBackgroundThread();
 
-    if (NS_WARN_IF(!mManager->MaybeCreateRemoteWorker(
+    if (NS_WARN_IF(!mManagerWrapper->Manager()->MaybeCreateRemoteWorker(
             mData, mWindowID, mPortIdentifier, mActor->OtherPid()))) {
       mActor->ErrorPropagation(NS_ERROR_FAILURE);
       return NS_OK;
     }
 
-    mManager->AddActor(mActor);
-    mActor->ManagerCreated(mManager);
+    mManagerWrapper->Manager()->AddActor(mActor);
+    mActor->ManagerCreated(mManagerWrapper.forget());
     return NS_OK;
   }
 
  private:
-  RefPtr<SharedWorkerManager> mManager;
+  RefPtr<SharedWorkerManagerWrapper> mManagerWrapper;
   RefPtr<SharedWorkerParent> mActor;
   RemoteWorkerData mData;
   uint64_t mWindowID;
   MessagePortIdentifier mPortIdentifier;
 };
 
 class ErrorPropagationRunnable final : public Runnable {
  public:
@@ -218,35 +196,33 @@ SharedWorkerService::~SharedWorkerServic
 
 void SharedWorkerService::GetOrCreateWorkerManager(
     SharedWorkerParent* aActor, const RemoteWorkerData& aData,
     uint64_t aWindowID, const MessagePortIdentifier& aPortIdentifier) {
   AssertIsOnBackgroundThread();
 
   // The real check happens on main-thread.
   RefPtr<GetOrCreateWorkerManagerRunnable> r =
-      new GetOrCreateWorkerManagerRunnable(aActor, aData, aWindowID,
+      new GetOrCreateWorkerManagerRunnable(this, aActor, aData, aWindowID,
                                            aPortIdentifier);
 
   nsCOMPtr<nsIEventTarget> target =
       SystemGroup::EventTargetFor(TaskCategory::Other);
   nsresult rv = target->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
   Unused << NS_WARN_IF(NS_FAILED(rv));
 }
 
 void SharedWorkerService::GetOrCreateWorkerManagerOnMainThread(
     nsIEventTarget* aBackgroundEventTarget, SharedWorkerParent* aActor,
     const RemoteWorkerData& aData, uint64_t aWindowID,
     const MessagePortIdentifier& aPortIdentifier) {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aBackgroundEventTarget);
   MOZ_ASSERT(aActor);
 
-  RefPtr<SharedWorkerManager> manager;
-
   nsresult rv = NS_OK;
   nsCOMPtr<nsIPrincipal> principal =
       PrincipalInfoToPrincipal(aData.principalInfo(), &rv);
   if (NS_WARN_IF(!principal)) {
     ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor, rv);
     return;
   }
 
@@ -267,73 +243,67 @@ void SharedWorkerService::GetOrCreateWor
   rv = PopulatePrincipalContentSecurityPolicy(
       loadingPrincipal, aData.loadingPrincipalCsp(),
       aData.loadingPrincipalPreloadCsp());
   if (NS_WARN_IF(NS_FAILED(rv))) {
     ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor, rv);
     return;
   }
 
+  RefPtr<SharedWorkerManagerHolder> managerHolder;
+
   // Let's see if there is already a SharedWorker to share.
   nsCOMPtr<nsIURI> resolvedScriptURL =
       DeserializeURI(aData.resolvedScriptURL());
   for (SharedWorkerManager* workerManager : mWorkerManagers) {
-    if (workerManager->MatchOnMainThread(aData.domain(), resolvedScriptURL,
-                                         aData.name(), loadingPrincipal)) {
-      manager = workerManager;
+    managerHolder = workerManager->MatchOnMainThread(
+        this, aData.domain(), resolvedScriptURL, aData.name(),
+        loadingPrincipal);
+    if (managerHolder) {
       break;
     }
   }
 
   // Let's create a new one.
-  if (!manager) {
-    manager = new SharedWorkerManager(aBackgroundEventTarget, aData,
-                                      loadingPrincipal);
+  if (!managerHolder) {
+    managerHolder = SharedWorkerManager::Create(this, aBackgroundEventTarget,
+                                                aData, loadingPrincipal);
 
-    mWorkerManagers.AppendElement(manager);
+    mWorkerManagers.AppendElement(managerHolder->Manager());
   } else {
     // We are attaching the actor to an existing one.
-    if (manager->IsSecureContext() != aData.isSecureContext()) {
+    if (managerHolder->Manager()->IsSecureContext() !=
+        aData.isSecureContext()) {
       ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor,
                                    NS_ERROR_DOM_SECURITY_ERR);
       return;
     }
   }
 
+  RefPtr<SharedWorkerManagerWrapper> wrapper =
+      new SharedWorkerManagerWrapper(managerHolder.forget());
+
   RefPtr<WorkerManagerCreatedRunnable> r = new WorkerManagerCreatedRunnable(
-      manager, aActor, aData, aWindowID, aPortIdentifier);
+      wrapper.forget(), aActor, aData, aWindowID, aPortIdentifier);
   aBackgroundEventTarget->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
 }
 
 void SharedWorkerService::ErrorPropagationOnMainThread(
     nsIEventTarget* aBackgroundEventTarget, SharedWorkerParent* aActor,
     nsresult aError) {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aBackgroundEventTarget);
   MOZ_ASSERT(aActor);
   MOZ_ASSERT(NS_FAILED(aError));
 
   RefPtr<ErrorPropagationRunnable> r =
       new ErrorPropagationRunnable(aActor, aError);
   aBackgroundEventTarget->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
 }
 
-void SharedWorkerService::RemoveWorkerManager(SharedWorkerManager* aManager) {
-  AssertIsOnBackgroundThread();
-
-  // We pass 'this' in order to be kept alive.
-  RefPtr<RemoveWorkerManagerRunnable> r =
-      new RemoveWorkerManagerRunnable(this, aManager);
-
-  nsCOMPtr<nsIEventTarget> target =
-      SystemGroup::EventTargetFor(TaskCategory::Other);
-  nsresult rv = target->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
-  Unused << NS_WARN_IF(NS_FAILED(rv));
-}
-
 void SharedWorkerService::RemoveWorkerManagerOnMainThread(
     SharedWorkerManager* aManager) {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aManager);
   MOZ_ASSERT(mWorkerManagers.Contains(aManager));
 
   mWorkerManagers.RemoveElement(aManager);
 }
--- a/dom/workers/sharedworkers/SharedWorkerService.h
+++ b/dom/workers/sharedworkers/SharedWorkerService.h
@@ -40,19 +40,16 @@ class SharedWorkerService final {
                                 uint64_t aWindowID,
                                 const MessagePortIdentifier& aPortIdentifier);
 
   void GetOrCreateWorkerManagerOnMainThread(
       nsIEventTarget* aBackgroundEventTarget, SharedWorkerParent* aActor,
       const RemoteWorkerData& aData, uint64_t aWindowID,
       const MessagePortIdentifier& aPortIdentifier);
 
-  // PBackground method only.
-  void RemoveWorkerManager(SharedWorkerManager* aManager);
-
   void RemoveWorkerManagerOnMainThread(SharedWorkerManager* aManager);
 
  private:
   SharedWorkerService();
   ~SharedWorkerService();
 
   void ErrorPropagationOnMainThread(nsIEventTarget* aBackgroundEventTarget,
                                     SharedWorkerParent* aActor,
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -44,45 +44,46 @@ using mozilla::CheckedUint32;
 template <typename T>
 static void EmitTypeCheck(MacroAssembler& masm, Assembler::Condition cond,
                           const T& src, TypeSet::Type type, Label* label) {
   if (type.isAnyObject()) {
     masm.branchTestObject(cond, src, label);
     return;
   }
   switch (type.primitive()) {
-    case JSVAL_TYPE_DOUBLE:
+    case ValueType::Double:
       // TI double type includes int32.
       masm.branchTestNumber(cond, src, label);
       break;
-    case JSVAL_TYPE_INT32:
+    case ValueType::Int32:
       masm.branchTestInt32(cond, src, label);
       break;
-    case JSVAL_TYPE_BOOLEAN:
+    case ValueType::Boolean:
       masm.branchTestBoolean(cond, src, label);
       break;
-    case JSVAL_TYPE_STRING:
+    case ValueType::String:
       masm.branchTestString(cond, src, label);
       break;
-    case JSVAL_TYPE_SYMBOL:
+    case ValueType::Symbol:
       masm.branchTestSymbol(cond, src, label);
       break;
-    case JSVAL_TYPE_BIGINT:
+    case ValueType::BigInt:
       masm.branchTestBigInt(cond, src, label);
       break;
-    case JSVAL_TYPE_NULL:
+    case ValueType::Null:
       masm.branchTestNull(cond, src, label);
       break;
-    case JSVAL_TYPE_UNDEFINED:
+    case ValueType::Undefined:
       masm.branchTestUndefined(cond, src, label);
       break;
-    case JSVAL_TYPE_MAGIC:
+    case ValueType::Magic:
       masm.branchTestMagic(cond, src, label);
       break;
-    default:
+    case ValueType::PrivateGCThing:
+    case ValueType::Object:
       MOZ_CRASH("Unexpected type");
   }
 }
 
 template <typename Source>
 void MacroAssembler::guardTypeSet(const Source& address, const TypeSet* types,
                                   BarrierKind kind, Register unboxScratch,
                                   Register objScratch,
--- a/js/src/vm/ObjectGroup.cpp
+++ b/js/src/vm/ObjectGroup.cpp
@@ -782,19 +782,19 @@ struct ObjectGroupRealm::ArrayObjectKey 
         type = TypeSet::ObjectType(group);
       }
     }
     return false;
   }
 };
 
 static inline bool NumberTypes(TypeSet::Type a, TypeSet::Type b) {
-  return (a.isPrimitive(JSVAL_TYPE_INT32) ||
-          a.isPrimitive(JSVAL_TYPE_DOUBLE)) &&
-         (b.isPrimitive(JSVAL_TYPE_INT32) || b.isPrimitive(JSVAL_TYPE_DOUBLE));
+  return (a.isPrimitive(ValueType::Int32) ||
+          a.isPrimitive(ValueType::Double)) &&
+         (b.isPrimitive(ValueType::Int32) || b.isPrimitive(ValueType::Double));
 }
 
 /*
  * As for GetValueType, but requires object types to be non-singletons with
  * their default prototype. These are the only values that should appear in
  * arrays and objects whose type can be fixed.
  */
 static inline TypeSet::Type GetValueTypeForTable(const Value& v) {
@@ -1318,22 +1318,22 @@ JSObject* ObjectGroup::newPlainObject(JS
   // this table entry.
   if (!group->unknownProperties(*sweep)) {
     for (size_t i = 0; i < nproperties; i++) {
       TypeSet::Type type = p->value().types[i];
       TypeSet::Type ntype = GetValueTypeForTable(properties[i].value);
       if (ntype == type) {
         continue;
       }
-      if (ntype.isPrimitive(JSVAL_TYPE_INT32) &&
-          type.isPrimitive(JSVAL_TYPE_DOUBLE)) {
+      if (ntype.isPrimitive(ValueType::Int32) &&
+          type.isPrimitive(ValueType::Double)) {
         // The property types already reflect 'int32'.
       } else {
-        if (ntype.isPrimitive(JSVAL_TYPE_DOUBLE) &&
-            type.isPrimitive(JSVAL_TYPE_INT32)) {
+        if (ntype.isPrimitive(ValueType::Double) &&
+            type.isPrimitive(ValueType::Int32)) {
           // Include 'double' in the property types to avoid the update below
           // later.
           p->value().types[i] = TypeSet::DoubleType();
         }
         AddTypePropertyId(cx, group, nullptr, IdToTypeId(properties[i].id),
                           ntype);
       }
     }
--- a/js/src/vm/TypeInference-inl.h
+++ b/js/src/vm/TypeInference-inl.h
@@ -159,39 +159,42 @@ inline bool TypeSet::IsUntrackedValue(co
   return val.isMagic() && (val.whyMagic() == JS_OPTIMIZED_OUT ||
                            val.whyMagic() == JS_UNINITIALIZED_LEXICAL);
 }
 
 inline TypeSet::Type TypeSet::GetMaybeUntrackedValueType(const Value& val) {
   return IsUntrackedValue(val) ? UnknownType() : GetValueType(val);
 }
 
-inline TypeFlags PrimitiveTypeFlag(JSValueType type) {
+inline TypeFlags PrimitiveTypeFlag(ValueType type) {
   switch (type) {
-    case JSVAL_TYPE_UNDEFINED:
+    case ValueType::Undefined:
       return TYPE_FLAG_UNDEFINED;
-    case JSVAL_TYPE_NULL:
+    case ValueType::Null:
       return TYPE_FLAG_NULL;
-    case JSVAL_TYPE_BOOLEAN:
+    case ValueType::Boolean:
       return TYPE_FLAG_BOOLEAN;
-    case JSVAL_TYPE_INT32:
+    case ValueType::Int32:
       return TYPE_FLAG_INT32;
-    case JSVAL_TYPE_DOUBLE:
+    case ValueType::Double:
       return TYPE_FLAG_DOUBLE;
-    case JSVAL_TYPE_STRING:
+    case ValueType::String:
       return TYPE_FLAG_STRING;
-    case JSVAL_TYPE_SYMBOL:
+    case ValueType::Symbol:
       return TYPE_FLAG_SYMBOL;
-    case JSVAL_TYPE_BIGINT:
+    case ValueType::BigInt:
       return TYPE_FLAG_BIGINT;
-    case JSVAL_TYPE_MAGIC:
+    case ValueType::Magic:
       return TYPE_FLAG_LAZYARGS;
-    default:
-      MOZ_CRASH("Bad JSValueType");
+    case ValueType::PrivateGCThing:
+    case ValueType::Object:
+      break;
   }
+
+  MOZ_CRASH("Bad ValueType");
 }
 
 inline JSValueType TypeFlagPrimitive(TypeFlags flags) {
   switch (flags) {
     case TYPE_FLAG_UNDEFINED:
       return JSVAL_TYPE_UNDEFINED;
     case TYPE_FLAG_NULL:
       return JSVAL_TYPE_NULL;
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -88,35 +88,36 @@ const char* js::TypeIdStringImpl(jsid id
 
 /////////////////////////////////////////////////////////////////////
 // Logging
 /////////////////////////////////////////////////////////////////////
 
 /* static */ const char* TypeSet::NonObjectTypeString(TypeSet::Type type) {
   if (type.isPrimitive()) {
     switch (type.primitive()) {
-      case JSVAL_TYPE_UNDEFINED:
+      case ValueType::Undefined:
         return "void";
-      case JSVAL_TYPE_NULL:
+      case ValueType::Null:
         return "null";
-      case JSVAL_TYPE_BOOLEAN:
+      case ValueType::Boolean:
         return "bool";
-      case JSVAL_TYPE_INT32:
+      case ValueType::Int32:
         return "int";
-      case JSVAL_TYPE_DOUBLE:
+      case ValueType::Double:
         return "float";
-      case JSVAL_TYPE_STRING:
+      case ValueType::String:
         return "string";
-      case JSVAL_TYPE_SYMBOL:
+      case ValueType::Symbol:
         return "symbol";
-      case JSVAL_TYPE_BIGINT:
+      case ValueType::BigInt:
         return "BigInt";
-      case JSVAL_TYPE_MAGIC:
+      case ValueType::Magic:
         return "lazyargs";
-      default:
+      case ValueType::PrivateGCThing:
+      case ValueType::Object:
         MOZ_CRASH("Bad type");
     }
   }
   if (type.isUnknown()) {
     return "unknown";
   }
 
   MOZ_ASSERT(type.isAnyObject());
--- a/js/src/vm/TypeSet.h
+++ b/js/src/vm/TypeSet.h
@@ -323,27 +323,27 @@ class TypeSet {
     uintptr_t data;
     explicit Type(uintptr_t data) : data(data) {}
 
    public:
     uintptr_t raw() const { return data; }
 
     bool isPrimitive() const { return data < JSVAL_TYPE_OBJECT; }
 
-    bool isPrimitive(JSValueType type) const {
-      MOZ_ASSERT(type < JSVAL_TYPE_OBJECT);
-      return (uintptr_t)type == data;
+    bool isPrimitive(ValueType type) const {
+      MOZ_ASSERT(type != ValueType::Object);
+      return uintptr_t(type) == data;
     }
 
-    JSValueType primitive() const {
+    ValueType primitive() const {
       MOZ_ASSERT(isPrimitive());
-      return (JSValueType)data;
+      return ValueType(data);
     }
 
-    bool isMagicArguments() const { return primitive() == JSVAL_TYPE_MAGIC; }
+    bool isMagicArguments() const { return primitive() == ValueType::Magic; }
 
     bool isSomeObject() const {
       return data == JSVAL_TYPE_OBJECT || data > JSVAL_TYPE_UNKNOWN;
     }
 
     bool isAnyObject() const { return data == JSVAL_TYPE_OBJECT; }
 
     bool isUnknown() const { return data == JSVAL_TYPE_UNKNOWN; }
--- a/media/libdav1d/asm/moz.build
+++ b/media/libdav1d/asm/moz.build
@@ -176,9 +176,10 @@ elif CONFIG['CPU_ARCH'] == 'arm' or CONF
         SOURCES += ['../../../third_party/dav1d/src/arm/64/mc.S']
     elif CONFIG['CPU_ARCH'] == 'arm':
         SOURCES += ['../../../third_party/dav1d/src/arm/32/mc.S']
 
 USE_NASM = True
 
 FINAL_LIBRARY = 'gkmedias'
 
-DisableCompilerWarnings()
+# We allow warnings for third-party code that can be updated from upstream.
+AllowCompilerWarnings()
--- a/media/libdav1d/moz.build
+++ b/media/libdav1d/moz.build
@@ -181,11 +181,8 @@ if CONFIG['OS_TARGET'] == 'WINNT':
 if CONFIG['CC_TYPE'] == 'gcc':
     LOCAL_INCLUDES += ['../../third_party/dav1d/include/compat/gcc/']
     EXPORTS.dav1d += ['../../third_party/dav1d/include/compat/gcc/stdatomic.h']
 
 FINAL_LIBRARY = 'gkmedias'
 
 # We allow warnings for third-party code that can be updated from upstream.
 AllowCompilerWarnings()
-
-# And furthermore, don't show warnings.
-DisableCompilerWarnings()
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -84,18 +84,16 @@ import org.mozilla.gecko.delegates.Brows
 import org.mozilla.gecko.delegates.OfflineTabStatusDelegate;
 import org.mozilla.gecko.delegates.ScreenshotDelegate;
 import org.mozilla.gecko.distribution.Distribution;
 import org.mozilla.gecko.distribution.DistributionStoreCallback;
 import org.mozilla.gecko.dlc.DlcStudyService;
 import org.mozilla.gecko.dlc.DlcSyncService;
 import org.mozilla.gecko.extensions.ExtensionPermissionsHelper;
 import org.mozilla.gecko.firstrun.OnboardingHelper;
-import org.mozilla.gecko.search.SearchWidgetProvider;
-import org.mozilla.geckoview.DynamicToolbarAnimator.PinReason;
 import org.mozilla.gecko.home.BrowserSearch;
 import org.mozilla.gecko.home.HomeBanner;
 import org.mozilla.gecko.home.HomeConfig;
 import org.mozilla.gecko.home.HomeConfig.PanelType;
 import org.mozilla.gecko.home.HomeConfigPrefsBackend;
 import org.mozilla.gecko.home.HomeFragment;
 import org.mozilla.gecko.home.HomePager.OnUrlOpenInBackgroundListener;
 import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
@@ -121,16 +119,17 @@ import org.mozilla.gecko.preferences.Gec
 import org.mozilla.gecko.promotion.ReaderViewBookmarkPromotion;
 import org.mozilla.gecko.prompts.Prompt;
 import org.mozilla.gecko.reader.ReaderModeUtils;
 import org.mozilla.gecko.reader.ReadingListHelper;
 import org.mozilla.gecko.reader.SavedReaderViewHelper;
 import org.mozilla.gecko.restrictions.Restrictable;
 import org.mozilla.gecko.restrictions.Restrictions;
 import org.mozilla.gecko.search.SearchEngineManager;
+import org.mozilla.gecko.search.SearchWidgetProvider;
 import org.mozilla.gecko.switchboard.AsyncConfigLoader;
 import org.mozilla.gecko.switchboard.SwitchBoard;
 import org.mozilla.gecko.sync.repositories.android.FennecTabsRepository;
 import org.mozilla.gecko.tabqueue.TabQueueHelper;
 import org.mozilla.gecko.tabqueue.TabQueuePrompt;
 import org.mozilla.gecko.tabs.TabHistoryController;
 import org.mozilla.gecko.tabs.TabHistoryController.OnShowTabHistory;
 import org.mozilla.gecko.tabs.TabHistoryFragment;
@@ -163,40 +162,35 @@ import org.mozilla.gecko.util.StringUtil
 import org.mozilla.gecko.util.ThreadUtils;
 import org.mozilla.gecko.util.WindowUtil;
 import org.mozilla.gecko.widget.ActionModePresenter;
 import org.mozilla.gecko.widget.AnchoredPopup;
 import org.mozilla.gecko.widget.AnimatedProgressBar;
 import org.mozilla.gecko.widget.GeckoActionProvider;
 import org.mozilla.gecko.widget.SplashScreen;
 import org.mozilla.geckoview.DynamicToolbarAnimator;
+import org.mozilla.geckoview.DynamicToolbarAnimator.PinReason;
 import org.mozilla.geckoview.GeckoSession;
 
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.lang.reflect.Method;
 import java.net.URLEncoder;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.EnumSet;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.regex.Pattern;
 
-import static org.mozilla.gecko.Tabs.LOADURL_DELAY_LOAD;
-import static org.mozilla.gecko.Tabs.LOADURL_EXTERNAL;
-import static org.mozilla.gecko.Tabs.LOADURL_PINNED;
-import static org.mozilla.gecko.Tabs.LOADURL_START_EDITING;
-import static org.mozilla.gecko.Tabs.TabEvents.LOADED;
 import static org.mozilla.gecko.Tabs.TabEvents.THUMBNAIL;
 import static org.mozilla.gecko.mma.MmaDelegate.INTERACT_WITH_SEARCH_WIDGET_URL_AREA;
 import static org.mozilla.gecko.mma.MmaDelegate.NEW_TAB;
-import static org.mozilla.gecko.search.SearchWidgetProvider.INPUT_TYPE_KEY;
 import static org.mozilla.gecko.util.JavaUtil.getBundleSizeInBytes;
 
 public class BrowserApp extends GeckoApp
                         implements ActionModePresenter,
                                    AnchoredPopup.OnVisibilityChangeListener,
                                    BookmarkEditFragment.Callbacks,
                                    BrowserSearch.OnEditSuggestionListener,
                                    BrowserSearch.OnSearchListener,
@@ -892,28 +886,35 @@ public class BrowserApp extends GeckoApp
             return false;
         }
 
         MmaDelegate.track(INTERACT_WITH_SEARCH_WIDGET_URL_AREA);
         Telemetry.sendUIEvent(TelemetryContract.Event.SEARCH, TelemetryContract.Method.WIDGET);
 
         switch (input) {
             case TEXT:
+                cleanupForNewTabEditing();
                 handleTabEditingMode(false);
                 return true;
             case VOICE:
+                cleanupForNewTabEditing();
                 handleTabEditingMode(true);
                 return true;
             default:
                 // Can't handle this input type, where did it came from though?
                 Log.e(LOGTAG, "can't handle search action :: input == " + input);
                 return false;
         }
     }
 
+    private void cleanupForNewTabEditing() {
+        closeOptionsMenu();
+        autoHideTabs();
+    }
+
     private synchronized void handleTabEditingMode(boolean isVoice) {
         final Tabs.OnTabsChangedListener tabsChangedListener = new Tabs.OnTabsChangedListener() {
             @Override
             public void onTabChanged(Tab tab, TabEvents msg, String data) {
                 // Listening for THUMBNAIL, while entailing a small delay
                 // allows for fully loading the "about:home" screen and finishing all related operations
                 // so that we can safely enter editing mode.
                 if (tab != null && tab.getURL().equals("about:home") && (THUMBNAIL.equals(msg))) {
--- a/mobile/android/geckoview/api.txt
+++ b/mobile/android/geckoview/api.txt
@@ -66,17 +66,17 @@ package org.mozilla.geckoview {
 
   public static class ContentBlocking.BlockEvent {
     ctor public BlockEvent(@android.support.annotation.NonNull java.lang.String, int);
     field public final int categories;
     field @android.support.annotation.NonNull public final java.lang.String uri;
   }
 
   public static interface ContentBlocking.Delegate {
-    method @android.support.annotation.UiThread public void onContentBlocked(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.NonNull org.mozilla.geckoview.ContentBlocking.BlockEvent);
+    method @android.support.annotation.UiThread default public void onContentBlocked(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.NonNull org.mozilla.geckoview.ContentBlocking.BlockEvent);
   }
 
   @android.support.annotation.AnyThread public static class ContentBlocking.Settings extends org.mozilla.geckoview.RuntimeSettings {
     method public int getCategories();
     method public int getCookieBehavior();
     method public int getCookieLifetime();
     method @android.support.annotation.NonNull public org.mozilla.geckoview.ContentBlocking.Settings setCategories(int);
     method @android.support.annotation.NonNull public org.mozilla.geckoview.ContentBlocking.Settings setCookieBehavior(int);
@@ -119,19 +119,19 @@ package org.mozilla.geckoview {
     enum_constant public static final org.mozilla.geckoview.DynamicToolbarAnimator.PinReason DISABLED;
     enum_constant public static final org.mozilla.geckoview.DynamicToolbarAnimator.PinReason FULL_SCREEN;
     enum_constant public static final org.mozilla.geckoview.DynamicToolbarAnimator.PinReason PAGE_LOADING;
     enum_constant public static final org.mozilla.geckoview.DynamicToolbarAnimator.PinReason RELAYOUT;
     field public final int value;
   }
 
   public static interface DynamicToolbarAnimator.ToolbarChromeProxy {
-    method @android.support.annotation.UiThread @android.support.annotation.Nullable public android.graphics.Bitmap getBitmapOfToolbarChrome();
-    method @android.support.annotation.UiThread public boolean isToolbarChromeVisible();
-    method @android.support.annotation.UiThread public void toggleToolbarChrome(boolean);
+    method @android.support.annotation.UiThread @android.support.annotation.Nullable default public android.graphics.Bitmap getBitmapOfToolbarChrome();
+    method @android.support.annotation.UiThread default public boolean isToolbarChromeVisible();
+    method @android.support.annotation.UiThread default public void toggleToolbarChrome(boolean);
   }
 
   public class GeckoDisplay {
     ctor protected GeckoDisplay(org.mozilla.geckoview.GeckoSession);
     method @android.support.annotation.UiThread @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoResult<android.graphics.Bitmap> capturePixels();
     method @android.support.annotation.UiThread public void screenOriginChanged(int, int);
     method @android.support.annotation.UiThread public boolean shouldPinOnScreen();
     method @android.support.annotation.UiThread public void surfaceChanged(@android.support.annotation.NonNull android.view.Surface, int, int);
@@ -340,24 +340,24 @@ package org.mozilla.geckoview {
     field public static final int LOAD_FLAGS_BYPASS_CLASSIFIER = 16;
     field public static final int LOAD_FLAGS_BYPASS_PROXY = 2;
     field public static final int LOAD_FLAGS_EXTERNAL = 4;
     field public static final int LOAD_FLAGS_NONE = 0;
     field protected org.mozilla.geckoview.GeckoSession.Window mWindow;
   }
 
   public static interface GeckoSession.ContentDelegate {
-    method @android.support.annotation.UiThread public void onCloseRequest(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession);
-    method @android.support.annotation.UiThread public void onContextMenu(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, int, int, @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.ContentDelegate.ContextElement);
-    method @android.support.annotation.UiThread public void onCrash(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession);
-    method @android.support.annotation.UiThread public void onExternalResponse(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.WebResponseInfo);
-    method @android.support.annotation.UiThread public void onFirstComposite(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession);
-    method @android.support.annotation.UiThread public void onFocusRequest(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession);
-    method @android.support.annotation.UiThread public void onFullScreen(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, boolean);
-    method @android.support.annotation.UiThread public void onTitleChange(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.Nullable java.lang.String);
+    method @android.support.annotation.UiThread default public void onCloseRequest(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession);
+    method @android.support.annotation.UiThread default public void onContextMenu(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, int, int, @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.ContentDelegate.ContextElement);
+    method @android.support.annotation.UiThread default public void onCrash(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession);
+    method @android.support.annotation.UiThread default public void onExternalResponse(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.WebResponseInfo);
+    method @android.support.annotation.UiThread default public void onFirstComposite(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession);
+    method @android.support.annotation.UiThread default public void onFocusRequest(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession);
+    method @android.support.annotation.UiThread default public void onFullScreen(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, boolean);
+    method @android.support.annotation.UiThread default public void onTitleChange(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.Nullable java.lang.String);
   }
 
   public static class GeckoSession.ContentDelegate.ContextElement {
     ctor protected ContextElement(@android.support.annotation.Nullable java.lang.String, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.NonNull java.lang.String, @android.support.annotation.Nullable java.lang.String);
     field public static final int TYPE_AUDIO = 3;
     field public static final int TYPE_IMAGE = 1;
     field public static final int TYPE_NONE = 0;
     field public static final int TYPE_VIDEO = 2;
@@ -377,41 +377,41 @@ package org.mozilla.geckoview {
     field public final boolean found;
     field @android.support.annotation.Nullable public final java.lang.String linkUri;
     field @android.support.annotation.NonNull public final java.lang.String searchString;
     field public final int total;
     field public final boolean wrapped;
   }
 
   public static interface GeckoSession.HistoryDelegate {
-    method @android.support.annotation.UiThread @android.support.annotation.Nullable public org.mozilla.geckoview.GeckoResult<boolean[]> getVisited(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.NonNull java.lang.String[]);
-    method @android.support.annotation.UiThread @android.support.annotation.Nullable public org.mozilla.geckoview.GeckoResult<java.lang.Boolean> onVisited(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.NonNull java.lang.String, @android.support.annotation.Nullable java.lang.String, int);
+    method @android.support.annotation.UiThread @android.support.annotation.Nullable default public org.mozilla.geckoview.GeckoResult<boolean[]> getVisited(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.NonNull java.lang.String[]);
+    method @android.support.annotation.UiThread @android.support.annotation.Nullable default public org.mozilla.geckoview.GeckoResult<java.lang.Boolean> onVisited(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.NonNull java.lang.String, @android.support.annotation.Nullable java.lang.String, int);
     field public static final int VISIT_REDIRECT_PERMANENT = 4;
     field public static final int VISIT_REDIRECT_SOURCE = 8;
     field public static final int VISIT_REDIRECT_SOURCE_PERMANENT = 16;
     field public static final int VISIT_REDIRECT_TEMPORARY = 2;
     field public static final int VISIT_TOP_LEVEL = 1;
     field public static final int VISIT_UNRECOVERABLE_ERROR = 32;
   }
 
   public static interface GeckoSession.HistoryDelegate.VisitFlags implements java.lang.annotation.Annotation {
   }
 
   public static interface GeckoSession.MediaDelegate {
-    method @android.support.annotation.UiThread public void onMediaAdd(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.NonNull org.mozilla.geckoview.MediaElement);
-    method @android.support.annotation.UiThread public void onMediaRemove(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.NonNull org.mozilla.geckoview.MediaElement);
+    method @android.support.annotation.UiThread default public void onMediaAdd(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.NonNull org.mozilla.geckoview.MediaElement);
+    method @android.support.annotation.UiThread default public void onMediaRemove(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.NonNull org.mozilla.geckoview.MediaElement);
   }
 
   public static interface GeckoSession.NavigationDelegate {
-    method @android.support.annotation.UiThread public void onCanGoBack(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, boolean);
-    method @android.support.annotation.UiThread public void onCanGoForward(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, boolean);
-    method @android.support.annotation.UiThread @android.support.annotation.Nullable public org.mozilla.geckoview.GeckoResult<java.lang.String> onLoadError(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.NonNull org.mozilla.geckoview.WebRequestError);
-    method @android.support.annotation.UiThread @android.support.annotation.Nullable public org.mozilla.geckoview.GeckoResult<org.mozilla.geckoview.AllowOrDeny> onLoadRequest(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.NavigationDelegate.LoadRequest);
-    method @android.support.annotation.UiThread public void onLocationChange(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.Nullable java.lang.String);
-    method @android.support.annotation.UiThread @android.support.annotation.Nullable public org.mozilla.geckoview.GeckoResult<org.mozilla.geckoview.GeckoSession> onNewSession(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.NonNull java.lang.String);
+    method @android.support.annotation.UiThread default public void onCanGoBack(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, boolean);
+    method @android.support.annotation.UiThread default public void onCanGoForward(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, boolean);
+    method @android.support.annotation.UiThread @android.support.annotation.Nullable default public org.mozilla.geckoview.GeckoResult<java.lang.String> onLoadError(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.NonNull org.mozilla.geckoview.WebRequestError);
+    method @android.support.annotation.UiThread @android.support.annotation.Nullable default public org.mozilla.geckoview.GeckoResult<org.mozilla.geckoview.AllowOrDeny> onLoadRequest(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.NavigationDelegate.LoadRequest);
+    method @android.support.annotation.UiThread default public void onLocationChange(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.Nullable java.lang.String);
+    method @android.support.annotation.UiThread @android.support.annotation.Nullable default public org.mozilla.geckoview.GeckoResult<org.mozilla.geckoview.GeckoSession> onNewSession(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.NonNull java.lang.String);
     field public static final int LOAD_REQUEST_IS_REDIRECT = 8388608;
     field public static final int TARGET_WINDOW_CURRENT = 1;
     field public static final int TARGET_WINDOW_NEW = 2;
     field public static final int TARGET_WINDOW_NONE = 0;
   }
 
   public static class GeckoSession.NavigationDelegate.LoadRequest {
     ctor protected LoadRequest();
@@ -420,32 +420,32 @@ package org.mozilla.geckoview {
     field @android.support.annotation.Nullable public final java.lang.String triggerUri;
     field @android.support.annotation.NonNull public final java.lang.String uri;
   }
 
   public static interface GeckoSession.NavigationDelegate.TargetWindow implements java.lang.annotation.Annotation {
   }
 
   public static interface GeckoSession.PermissionDelegate {
-    method @android.support.annotation.UiThread public void onAndroidPermissionsRequest(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.Nullable java.lang.String[], @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.PermissionDelegate.Callback);
-    method @android.support.annotation.UiThread public void onContentPermissionRequest(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.Nullable java.lang.String, int, @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.PermissionDelegate.Callback);
-    method @android.support.annotation.UiThread public void onMediaPermissionRequest(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.NonNull java.lang.String, @android.support.annotation.Nullable org.mozilla.geckoview.GeckoSession.PermissionDelegate.MediaSource[], @android.support.annotation.Nullable org.mozilla.geckoview.GeckoSession.PermissionDelegate.MediaSource[], @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.PermissionDelegate.MediaCallback);
+    method @android.support.annotation.UiThread default public void onAndroidPermissionsRequest(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.Nullable java.lang.String[], @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.PermissionDelegate.Callback);
+    method @android.support.annotation.UiThread default public void onContentPermissionRequest(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.Nullable java.lang.String, int, @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.PermissionDelegate.Callback);
+    method @android.support.annotation.UiThread default public void onMediaPermissionRequest(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.NonNull java.lang.String, @android.support.annotation.Nullable org.mozilla.geckoview.GeckoSession.PermissionDelegate.MediaSource[], @android.support.annotation.Nullable org.mozilla.geckoview.GeckoSession.PermissionDelegate.MediaSource[], @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.PermissionDelegate.MediaCallback);
     field public static final int PERMISSION_DESKTOP_NOTIFICATION = 1;
     field public static final int PERMISSION_GEOLOCATION = 0;
   }
 
   public static interface GeckoSession.PermissionDelegate.Callback {
-    method @android.support.annotation.UiThread public void grant();
-    method @android.support.annotation.UiThread public void reject();
+    method @android.support.annotation.UiThread default public void grant();
+    method @android.support.annotation.UiThread default public void reject();
   }
 
   public static interface GeckoSession.PermissionDelegate.MediaCallback {
-    method @android.support.annotation.UiThread public void grant(@android.support.annotation.Nullable java.lang.String, @android.support.annotation.Nullable java.lang.String);
-    method @android.support.annotation.UiThread public void grant(@android.support.annotation.Nullable org.mozilla.geckoview.GeckoSession.PermissionDelegate.MediaSource, @android.support.annotation.Nullable org.mozilla.geckoview.GeckoSession.PermissionDelegate.MediaSource);
-    method @android.support.annotation.UiThread public void reject();
+    method @android.support.annotation.UiThread default public void grant(@android.support.annotation.Nullable java.lang.String, @android.support.annotation.Nullable java.lang.String);
+    method @android.support.annotation.UiThread default public void grant(@android.support.annotation.Nullable org.mozilla.geckoview.GeckoSession.PermissionDelegate.MediaSource, @android.support.annotation.Nullable org.mozilla.geckoview.GeckoSession.PermissionDelegate.MediaSource);
+    method @android.support.annotation.UiThread default public void reject();
   }
 
   public static class GeckoSession.PermissionDelegate.MediaSource {
     ctor protected MediaSource();
     field public static final int SOURCE_APPLICATION = 2;
     field public static final int SOURCE_AUDIOCAPTURE = 6;
     field public static final int SOURCE_BROWSER = 4;
     field public static final int SOURCE_CAMERA = 0;
@@ -461,20 +461,20 @@ package org.mozilla.geckoview {
     field public final int source;
     field public final int type;
   }
 
   public static interface GeckoSession.PermissionDelegate.Permission implements java.lang.annotation.Annotation {
   }
 
   public static interface GeckoSession.ProgressDelegate {
-    method @android.support.annotation.UiThread public void onPageStart(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.NonNull java.lang.String);
-    method @android.support.annotation.UiThread public void onPageStop(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, boolean);
-    method @android.support.annotation.UiThread public void onProgressChange(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, int);
-    method @android.support.annotation.UiThread public void onSecurityChange(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.ProgressDelegate.SecurityInformation);
+    method @android.support.annotation.UiThread default public void onPageStart(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.NonNull java.lang.String);
+    method @android.support.annotation.UiThread default public void onPageStop(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, boolean);
+    method @android.support.annotation.UiThread default public void onProgressChange(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, int);
+    method @android.support.annotation.UiThread default public void onSecurityChange(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.ProgressDelegate.SecurityInformation);
   }
 
   public static class GeckoSession.ProgressDelegate.SecurityInformation {
     ctor protected SecurityInformation();
     field public static final int CONTENT_BLOCKED = 1;
     field public static final int CONTENT_LOADED = 2;
     field public static final int CONTENT_UNKNOWN = 0;
     field public static final int SECURITY_MODE_IDENTIFIED = 1;
@@ -489,48 +489,48 @@ package org.mozilla.geckoview {
     field public final int mixedModePassive;
     field public final java.lang.String organization;
     field public final java.lang.String origin;
     field public final int securityMode;
     field public final java.lang.String subjectName;
   }
 
   public static interface GeckoSession.PromptDelegate {
-    method @android.support.annotation.UiThread public void onAlert(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.PromptDelegate.AlertCallback);
-    method @android.support.annotation.UiThread public void onAuthPrompt(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.PromptDelegate.AuthOptions, @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.PromptDelegate.AuthCallback);
-    method @android.support.annotation.UiThread public void onButtonPrompt(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.Nullable java.lang.String[], @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.PromptDelegate.ButtonCallback);
-    method @android.support.annotation.UiThread public void onChoicePrompt(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.Nullable java.lang.String, int, @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.PromptDelegate.Choice[], @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.PromptDelegate.ChoiceCallback);
-    method @android.support.annotation.UiThread public void onColorPrompt(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.PromptDelegate.TextCallback);
-    method @android.support.annotation.UiThread public void onDateTimePrompt(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.Nullable java.lang.String, int, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.PromptDelegate.TextCallback);
-    method @android.support.annotation.UiThread public void onFilePrompt(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.Nullable java.lang.String, int, @android.support.annotation.Nullable java.lang.String[], @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.PromptDelegate.FileCallback);
-    method @android.support.annotation.UiThread @android.support.annotation.Nullable public org.mozilla.geckoview.GeckoResult<org.mozilla.geckoview.AllowOrDeny> onPopupRequest(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.Nullable java.lang.String);
-    method @android.support.annotation.UiThread public void onTextPrompt(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.PromptDelegate.TextCallback);
+    method @android.support.annotation.UiThread default public void onAlert(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.PromptDelegate.AlertCallback);
+    method @android.support.annotation.UiThread default public void onAuthPrompt(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.PromptDelegate.AuthOptions, @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.PromptDelegate.AuthCallback);
+    method @android.support.annotation.UiThread default public void onButtonPrompt(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.Nullable java.lang.String[], @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.PromptDelegate.ButtonCallback);
+    method @android.support.annotation.UiThread default public void onChoicePrompt(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.Nullable java.lang.String, int, @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.PromptDelegate.Choice[], @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.PromptDelegate.ChoiceCallback);
+    method @android.support.annotation.UiThread default public void onColorPrompt(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.PromptDelegate.TextCallback);
+    method @android.support.annotation.UiThread default public void onDateTimePrompt(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.Nullable java.lang.String, int, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.PromptDelegate.TextCallback);
+    method @android.support.annotation.UiThread default public void onFilePrompt(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.Nullable java.lang.String, int, @android.support.annotation.Nullable java.lang.String[], @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.PromptDelegate.FileCallback);
+    method @android.support.annotation.UiThread @android.support.annotation.Nullable default public org.mozilla.geckoview.GeckoResult<org.mozilla.geckoview.AllowOrDeny> onPopupRequest(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.Nullable java.lang.String);
+    method @android.support.annotation.UiThread default public void onTextPrompt(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.Nullable java.lang.String, @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.PromptDelegate.TextCallback);
     field public static final int BUTTON_TYPE_NEGATIVE = 2;
     field public static final int BUTTON_TYPE_NEUTRAL = 1;
     field public static final int BUTTON_TYPE_POSITIVE = 0;
     field public static final int DATETIME_TYPE_DATE = 1;
     field public static final int DATETIME_TYPE_DATETIME_LOCAL = 5;
     field public static final int DATETIME_TYPE_MONTH = 2;
     field public static final int DATETIME_TYPE_TIME = 4;
     field public static final int DATETIME_TYPE_WEEK = 3;
     field public static final int FILE_TYPE_MULTIPLE = 2;
     field public static final int FILE_TYPE_SINGLE = 1;
   }
 
   public static interface GeckoSession.PromptDelegate.AlertCallback {
-    method @android.support.annotation.UiThread public void dismiss();
-    method @android.support.annotation.UiThread @android.support.annotation.Nullable public java.lang.String getCheckboxMessage();
-    method @android.support.annotation.UiThread public boolean getCheckboxValue();
-    method @android.support.annotation.UiThread public boolean hasCheckbox();
-    method @android.support.annotation.UiThread public void setCheckboxValue(boolean);
+    method @android.support.annotation.UiThread default public void dismiss();
+    method @android.support.annotation.UiThread @android.support.annotation.Nullable default public java.lang.String getCheckboxMessage();
+    method @android.support.annotation.UiThread default public boolean getCheckboxValue();
+    method @android.support.annotation.UiThread default public boolean hasCheckbox();
+    method @android.support.annotation.UiThread default public void setCheckboxValue(boolean);
   }
 
   public static interface GeckoSession.PromptDelegate.AuthCallback implements org.mozilla.geckoview.GeckoSession.PromptDelegate.AlertCallback {
-    method @android.support.annotation.UiThread public void confirm(@android.support.annotation.Nullable java.lang.String);
-    method @android.support.annotation.UiThread public void confirm(@android.support.annotation.NonNull java.lang.String, @android.support.annotation.NonNull java.lang.String);
+    method @android.support.annotation.UiThread default public void confirm(@android.support.annotation.Nullable java.lang.String);
+    method @android.support.annotation.UiThread default public void confirm(@android.support.annotation.NonNull java.lang.String, @android.support.annotation.NonNull java.lang.String);
   }
 
   public static class GeckoSession.PromptDelegate.AuthOptions {
     ctor protected AuthOptions();
     field public static final int AUTH_FLAG_CROSS_ORIGIN_SUB_RESOURCE = 32;
     field public static final int AUTH_FLAG_HOST = 1;
     field public static final int AUTH_FLAG_ONLY_PASSWORD = 8;
     field public static final int AUTH_FLAG_PREVIOUS_FAILED = 16;
@@ -541,17 +541,17 @@ package org.mozilla.geckoview {
     field public int flags;
     field public int level;
     field public java.lang.String password;
     field public java.lang.String uri;
     field public java.lang.String username;
   }
 
   public static interface GeckoSession.PromptDelegate.ButtonCallback implements org.mozilla.geckoview.GeckoSession.PromptDelegate.AlertCallback {
-    method @android.support.annotation.UiThread public void confirm(int);
+    method @android.support.annotation.UiThread default public void confirm(int);
   }
 
   public static class GeckoSession.PromptDelegate.Choice {
     ctor protected Choice();
     field public static final int CHOICE_TYPE_MENU = 1;
     field public static final int CHOICE_TYPE_MULTIPLE = 3;
     field public static final int CHOICE_TYPE_SINGLE = 2;
     field public final boolean disabled;
@@ -559,44 +559,44 @@ package org.mozilla.geckoview {
     field public final java.lang.String id;
     field public final org.mozilla.geckoview.GeckoSession.PromptDelegate.Choice[] items;
     field public final java.lang.String label;
     field public final boolean selected;
     field public final boolean separator;
   }
 
   public static interface GeckoSession.PromptDelegate.ChoiceCallback implements org.mozilla.geckoview.GeckoSession.PromptDelegate.AlertCallback {
-    method @android.support.annotation.UiThread public void confirm(@android.support.annotation.Nullable java.lang.String);
-    method @android.support.annotation.UiThread public void confirm(@android.support.annotation.NonNull java.lang.String[]);
-    method @android.support.annotation.UiThread public void confirm(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.PromptDelegate.Choice);
-    method @android.support.annotation.UiThread public void confirm(@android.support.annotation.Nullable org.mozilla.geckoview.GeckoSession.PromptDelegate.Choice[]);
+    method @android.support.annotation.UiThread default public void confirm(@android.support.annotation.Nullable java.lang.String);
+    method @android.support.annotation.UiThread default public void confirm(@android.support.annotation.NonNull java.lang.String[]);
+    method @android.support.annotation.UiThread default public void confirm(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.PromptDelegate.Choice);
+    method @android.support.annotation.UiThread default public void confirm(@android.support.annotation.Nullable org.mozilla.geckoview.GeckoSession.PromptDelegate.Choice[]);
   }
 
   public static interface GeckoSession.PromptDelegate.DatetimeType implements java.lang.annotation.Annotation {
   }
 
   public static interface GeckoSession.PromptDelegate.FileCallback implements org.mozilla.geckoview.GeckoSession.PromptDelegate.AlertCallback {
-    method @android.support.annotation.UiThread public void confirm(@android.support.annotation.Nullable android.content.Context, @android.support.annotation.Nullable android.net.Uri);
-    method @android.support.annotation.UiThread public void confirm(@android.support.annotation.Nullable android.content.Context, @android.support.annotation.Nullable android.net.Uri[]);
+    method @android.support.annotation.UiThread default public void confirm(@android.support.annotation.Nullable android.content.Context, @android.support.annotation.Nullable android.net.Uri);
+    method @android.support.annotation.UiThread default public void confirm(@android.support.annotation.Nullable android.content.Context, @android.support.annotation.Nullable android.net.Uri[]);
   }
 
   public static interface GeckoSession.PromptDelegate.FileType implements java.lang.annotation.Annotation {
   }
 
   public static interface GeckoSession.PromptDelegate.TextCallback implements org.mozilla.geckoview.GeckoSession.PromptDelegate.AlertCallback {
-    method @android.support.annotation.UiThread public void confirm(@android.support.annotation.Nullable java.lang.String);
+    method @android.support.annotation.UiThread default public void confirm(@android.support.annotation.Nullable java.lang.String);
   }
 
   public static interface GeckoSession.ScrollDelegate {
-    method @android.support.annotation.UiThread public void onScrollChanged(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, int, int);
+    method @android.support.annotation.UiThread default public void onScrollChanged(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, int, int);
   }
 
   public static interface GeckoSession.SelectionActionDelegate {
-    method @android.support.annotation.UiThread public void onHideAction(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, int);
-    method @android.support.annotation.UiThread public void onShowActionRequest(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.SelectionActionDelegate.Selection, java.lang.String[], @android.support.annotation.NonNull org.mozilla.geckoview.GeckoResponse<java.lang.String>);
+    method @android.support.annotation.UiThread default public void onHideAction(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, int);
+    method @android.support.annotation.UiThread default public void onShowActionRequest(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession.SelectionActionDelegate.Selection, java.lang.String[], @android.support.annotation.NonNull org.mozilla.geckoview.GeckoResponse<java.lang.String>);
     field public static final java.lang.String ACTION_COLLAPSE_TO_END = "org.mozilla.geckoview.COLLAPSE_TO_END";
     field public static final java.lang.String ACTION_COLLAPSE_TO_START = "org.mozilla.geckoview.COLLAPSE_TO_START";
     field public static final java.lang.String ACTION_COPY = "org.mozilla.geckoview.COPY";
     field public static final java.lang.String ACTION_CUT = "org.mozilla.geckoview.CUT";
     field public static final java.lang.String ACTION_DELETE = "org.mozilla.geckoview.DELETE";
     field public static final java.lang.String ACTION_HIDE = "org.mozilla.geckoview.HIDE";
     field public static final java.lang.String ACTION_PASTE = "org.mozilla.geckoview.PASTE";
     field public static final java.lang.String ACTION_SELECT_ALL = "org.mozilla.geckoview.SELECT_ALL";
@@ -628,23 +628,23 @@ package org.mozilla.geckoview {
 
   @android.support.annotation.AnyThread public static class GeckoSession.SessionState implements android.os.Parcelable {
     ctor public SessionState(java.lang.String);
     method public void readFromParcel(@android.support.annotation.NonNull android.os.Parcel);
     field public static final android.os.Parcelable.Creator<org.mozilla.geckoview.GeckoSession.SessionState> CREATOR;
   }
 
   public static interface GeckoSession.TextInputDelegate {
-    method @android.support.annotation.UiThread public void hideSoftInput(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession);
-    method @android.support.annotation.UiThread public void notifyAutoFill(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, int, int);
-    method @android.support.annotation.UiThread public void restartInput(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, int);
-    method @android.support.annotation.UiThread public void showSoftInput(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession);
-    method @android.support.annotation.UiThread public void updateCursorAnchorInfo(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.NonNull android.view.inputmethod.CursorAnchorInfo);
-    method @android.support.annotation.UiThread public void updateExtractedText(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.NonNull android.view.inputmethod.ExtractedTextRequest, @android.support.annotation.NonNull android.view.inputmethod.ExtractedText);
-    method @android.support.annotation.UiThread public void updateSelection(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, int, int, int, int);
+    method @android.support.annotation.UiThread default public void hideSoftInput(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession);
+    method @android.support.annotation.UiThread default public void notifyAutoFill(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, int, int);
+    method @android.support.annotation.UiThread default public void restartInput(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, int);
+    method @android.support.annotation.UiThread default public void showSoftInput(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession);
+    method @android.support.annotation.UiThread default public void updateCursorAnchorInfo(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.NonNull android.view.inputmethod.CursorAnchorInfo);
+    method @android.support.annotation.UiThread default public void updateExtractedText(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, @android.support.annotation.NonNull android.view.inputmethod.ExtractedTextRequest, @android.support.annotation.NonNull android.view.inputmethod.ExtractedText);
+    method @android.support.annotation.UiThread default public void updateSelection(@android.support.annotation.NonNull org.mozilla.geckoview.GeckoSession, int, int, int, int);
     field public static final int AUTO_FILL_NOTIFY_CANCELED = 2;
     field public static final int AUTO_FILL_NOTIFY_COMMITTED = 1;
     field public static final int AUTO_FILL_NOTIFY_STARTED = 0;
     field public static final int AUTO_FILL_NOTIFY_VIEW_ADDED = 3;
     field public static final int AUTO_FILL_NOTIFY_VIEW_ENTERED = 6;
     field public static final int AUTO_FILL_NOTIFY_VIEW_EXITED = 7;
     field public static final int AUTO_FILL_NOTIFY_VIEW_REMOVED = 4;
     field public static final int AUTO_FILL_NOTIFY_VIEW_UPDATED = 5;
@@ -792,25 +792,25 @@ package org.mozilla.geckoview {
     field public static final int MEDIA_STATE_SUSPEND = 7;
     field public static final int MEDIA_STATE_WAITING = 8;
     field protected org.mozilla.geckoview.MediaElement.Delegate mDelegate;
     field protected final org.mozilla.geckoview.GeckoSession mSession;
     field protected final long mVideoId;
   }
 
   public static interface MediaElement.Delegate {
-    method @android.support.annotation.UiThread public void onError(@android.support.annotation.NonNull org.mozilla.geckoview.MediaElement, int);
-    method @android.support.annotation.UiThread public void onFullscreenChange(@android.support.annotation.NonNull org.mozilla.geckoview.MediaElement, boolean);
-    method @android.support.annotation.UiThread public void onLoadProgress(@android.support.annotation.NonNull org.mozilla.geckoview.MediaElement, @android.support.annotation.NonNull org.mozilla.geckoview.MediaElement.LoadProgressInfo);
-    method @android.support.annotation.UiThread public void onMetadataChange(@android.support.annotation.NonNull org.mozilla.geckoview.MediaElement, @android.support.annotation.NonNull org.mozilla.geckoview.MediaElement.Metadata);
-    method @android.support.annotation.UiThread public void onPlaybackRateChange(@android.support.annotation.NonNull org.mozilla.geckoview.MediaElement, double);
-    method @android.support.annotation.UiThread public void onPlaybackStateChange(@android.support.annotation.NonNull org.mozilla.geckoview.MediaElement, int);
-    method @android.support.annotation.UiThread public void onReadyStateChange(@android.support.annotation.NonNull org.mozilla.geckoview.MediaElement, int);
-    method @android.support.annotation.UiThread public void onTimeChange(@android.support.annotation.NonNull org.mozilla.geckoview.MediaElement, double);
-    method @android.support.annotation.UiThread public void onVolumeChange(@android.support.annotation.NonNull org.mozilla.geckoview.MediaElement, double, boolean);
+    method @android.support.annotation.UiThread default public void onError(@android.support.annotation.NonNull org.mozilla.geckoview.MediaElement, int);
+    method @android.support.annotation.UiThread default public void onFullscreenChange(@android.support.annotation.NonNull org.mozilla.geckoview.MediaElement, boolean);
+    method @android.support.annotation.UiThread default public void onLoadProgress(@android.support.annotation.NonNull org.mozilla.geckoview.MediaElement, @android.support.annotation.NonNull org.mozilla.geckoview.MediaElement.LoadProgressInfo);
+    method @android.support.annotation.UiThread default public void onMetadataChange(@android.support.annotation.NonNull org.mozilla.geckoview.MediaElement, @android.support.annotation.NonNull org.mozilla.geckoview.MediaElement.Metadata);
+    method @android.support.annotation.UiThread default public void onPlaybackRateChange(@android.support.annotation.NonNull org.mozilla.geckoview.MediaElement, double);
+    method @android.support.annotation.UiThread default public void onPlaybackStateChange(@android.support.annotation.NonNull org.mozilla.geckoview.MediaElement, int);
+    method @android.support.annotation.UiThread default public void onReadyStateChange(@android.support.annotation.NonNull org.mozilla.geckoview.MediaElement, int);
+    method @android.support.annotation.UiThread default public void onTimeChange(@android.support.annotation.NonNull org.mozilla.geckoview.MediaElement, double);
+    method @android.support.annotation.UiThread default public void onVolumeChange(@android.support.annotation.NonNull org.mozilla.geckoview.MediaElement, double, boolean);
   }
 
   public static class MediaElement.LoadProgressInfo {
     ctor protected LoadProgressInfo();
     field @android.support.annotation.Nullable public final org.mozilla.geckoview.MediaElement.LoadProgressInfo.TimeRange[] buffered;
     field public final long loadedBytes;
     field public final long totalBytes;
   }
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/DynamicToolbarAnimator.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/DynamicToolbarAnimator.java
@@ -35,21 +35,25 @@ public final class DynamicToolbarAnimato
 
         PinReason(final int aValue) {
             value = aValue;
         }
     }
 
     public interface ToolbarChromeProxy {
         @UiThread
-        public @Nullable Bitmap getBitmapOfToolbarChrome();
+        @Nullable default Bitmap getBitmapOfToolbarChrome() {
+            return null;
+        }
         @UiThread
-        public boolean isToolbarChromeVisible();
+        default boolean isToolbarChromeVisible() {
+            return false;
+        }
         @UiThread
-        public void toggleToolbarChrome(boolean aShow);
+        default void toggleToolbarChrome(boolean aShow) {}
     }
 
     private final Set<PinReason> mPinFlags = EnumSet.noneOf(PinReason.class);
 
     private final GeckoSession mTarget;
     private final GeckoSession.Compositor mCompositor;
     private ToolbarChromeProxy mToolbarChromeProxy;
     private int mMaxToolbarHeight;
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
@@ -3118,53 +3118,59 @@ public class GeckoSession implements Par
          */
         interface AlertCallback {
             /**
              * Called by the prompt implementation when the prompt is dismissed without a
              * result, for example if the user presses the "Back" button. All prompts
              * must call dismiss() or confirm(), if available, when the prompt is dismissed.
              */
             @UiThread
-            void dismiss();
+            default void dismiss() {}
 
             /**
              * Return whether the prompt shown should include a checkbox. For example, if
              * a page shows multiple prompts within a short period of time, the next
              * prompt will include a checkbox to let the user disable future prompts.
              * Although the API allows checkboxes for all prompts, in practice, only
              * alert/button/text/auth prompts will possibly have a checkbox.
              *
              * @return True if prompt includes a checkbox.
              */
             @UiThread
-            boolean hasCheckbox();
+            default boolean hasCheckbox() {
+                return false;
+            }
 
             /**
              * Return the message label for the optional checkbox.
              *
              * @return Checkbox message or null if none.
              */
             @UiThread
-            @Nullable String getCheckboxMessage();
+            @Nullable default String getCheckboxMessage() {
+                return null;
+            }
 
             /**
              * Return the initial value for the optional checkbox.
              *
              * @return Initial checkbox value.
              */
             @UiThread
-            boolean getCheckboxValue();
+            default boolean getCheckboxValue() {
+                return false;
+            }
 
             /**
              * Set the current value for the optional checkbox.
              *
              * @param value New checkbox value.
              */
             @UiThread
-            void setCheckboxValue(boolean value);
+            default void setCheckboxValue(boolean value) {}
         }
 
         /**
          * Display a simple message prompt.
          *
          * @param session GeckoSession that triggered the prompt
          * @param title Title for the prompt dialog.
          * @param msg Message for the prompt dialog.
@@ -3183,17 +3189,17 @@ public class GeckoSession implements Par
         interface ButtonCallback extends AlertCallback {
             /**
              * Called by the prompt implementation when the button prompt is dismissed by
              * the user pressing one of the buttons.
              *
              * @param button Button result; one of BUTTON_TYPE_* constants.
              */
             @UiThread
-            void confirm(int button);
+            default void confirm(int button) {}
         }
 
         static final int BUTTON_TYPE_POSITIVE = 0;
         static final int BUTTON_TYPE_NEUTRAL = 1;
         static final int BUTTON_TYPE_NEGATIVE = 2;
 
         /**
          * Display a prompt with up to three buttons.
@@ -3223,17 +3229,17 @@ public class GeckoSession implements Par
         interface TextCallback extends AlertCallback {
             /**
              * Called by the prompt implementation when the text prompt is confirmed by
              * the user, for example by pressing the "OK" button.
              *
              * @param text Text result.
              */
             @UiThread
-            void confirm(@Nullable String text);
+            default void confirm(@Nullable String text) {}
         }
 
         /**
          * Display a prompt for inputting text.
          *
          * @param session GeckoSession that triggered the prompt
          * @param title Title for the prompt dialog.
          * @param msg Message for the prompt dialog.
@@ -3254,27 +3260,27 @@ public class GeckoSession implements Par
         interface AuthCallback extends AlertCallback {
             /**
              * Called by the prompt implementation when a password-only prompt is
              * confirmed by the user.
              *
              * @param password Entered password.
              */
             @UiThread
-            void confirm(@Nullable String password);
+            default void confirm(@Nullable String password) {}
 
             /**
              * Called by the prompt implementation when a username/password prompt is
              * confirmed by the user.
              *
              * @param username Entered username.
              * @param password Entered password.
              */
             @UiThread
-            void confirm(@NonNull String username, @NonNull String password);
+            default void confirm(@NonNull String username, @NonNull String password) {}
         }
 
         class AuthOptions {
             @Retention(RetentionPolicy.SOURCE)
             @IntDef(flag = true,
                     value = {AUTH_FLAG_HOST, AUTH_FLAG_PROXY,
                              AUTH_FLAG_ONLY_PASSWORD, AUTH_FLAG_PREVIOUS_FAILED,
                              AUTH_FLAG_CROSS_ORIGIN_SUB_RESOURCE})
@@ -3478,46 +3484,46 @@ public class GeckoSession implements Par
         interface ChoiceCallback extends AlertCallback {
             /**
              * Called by the prompt implementation when the menu or single-choice list is
              * dismissed by the user.
              *
              * @param id ID of the selected item.
              */
             @UiThread
-            void confirm(@Nullable String id);
+            default void confirm(@Nullable String id) {}
 
             /**
              * Called by the prompt implementation when the multiple-choice list is
              * dismissed by the user.
              *
              * @param ids IDs of the selected items.
              */
             @UiThread
-            void confirm(@NonNull String[] ids);
+            default void confirm(@NonNull String[] ids) {}
 
             /**
              * Called by the prompt implementation when the menu or single-choice list is
              * dismissed by the user.
              *
              * @param item Choice representing the selected item; must be an original
              *             Choice object that was passed to the implementation.
              */
             @UiThread
-            void confirm(@NonNull Choice item);
+            default void confirm(@NonNull Choice item) {}
 
             /**
              * Called by the prompt implementation when the multiple-choice list is
              * dismissed by the user.
              *
              * @param items Choice array representing the selected items; must be original
              *              Choice objects that were passed to the implementation.
              */
             @UiThread
-            void confirm(@Nullable Choice[] items);
+            default void confirm(@Nullable Choice[] items) {}
         }
 
 
         /**
          * Display a menu prompt or list prompt.
          *
          * @param session GeckoSession that triggered the prompt
          * @param title Title for the prompt dialog, or null for no title.
@@ -3607,27 +3613,27 @@ public class GeckoSession implements Par
             /**
              * Called by the prompt implementation when the user makes a file selection in
              * single-selection mode.
              *
              * @param context An application Context for parsing URIs.
              * @param uri The URI of the selected file.
              */
             @UiThread
-            void confirm(@Nullable Context context, @Nullable Uri uri);
+            default void confirm(@Nullable Context context, @Nullable Uri uri) {}
 
             /**
              * Called by the prompt implementation when the user makes file selections in
              * multiple-selection mode.
              *
              * @param context An application Context for parsing URIs.
              * @param uris Array of URI objects for the selected files.
              */
             @UiThread
-            void confirm(@Nullable Context context, @Nullable Uri[] uris);
+            default void confirm(@Nullable Context context, @Nullable Uri[] uris) {}
         }
 
         @Retention(RetentionPolicy.SOURCE)
         @IntDef({FILE_TYPE_SINGLE, FILE_TYPE_MULTIPLE})
         /* package */ @interface FileType {}
         static final int FILE_TYPE_SINGLE = 1;
         static final int FILE_TYPE_MULTIPLE = 2;
 
@@ -3877,24 +3883,24 @@ public class GeckoSession implements Par
          * Callback interface for notifying the result of a permission request.
          */
         interface Callback {
             /**
              * Called by the implementation after permissions are granted; the
              * implementation must call either grant() or reject() for every request.
              */
             @UiThread
-            void grant();
+            default void grant() {}
 
             /**
              * Called by the implementation when permissions are not granted; the
              * implementation must call either grant() or reject() for every request.
              */
             @UiThread
-            void reject();
+            default void reject() {}
         }
 
         /**
          * Request Android app permissions.
          *
          * @param session GeckoSession instance requesting the permissions.
          * @param permissions List of permissions to request; possible values are,
          *                    android.Manifest.permission.ACCESS_COARSE_LOCATION
@@ -4084,38 +4090,38 @@ public class GeckoSession implements Par
              * implementation must call one of grant() or reject() for every request.
              *
              * @param video "id" value from the bundle for the video source to use,
              *              or null when video is not requested.
              * @param audio "id" value from the bundle for the audio source to use,
              *              or null when audio is not requested.
              */
             @UiThread
-            void grant(final @Nullable String video, final @Nullable String audio);
+            default void grant(final @Nullable String video, final @Nullable String audio) {}
 
             /**
              * Called by the implementation after permissions are granted; the
              * implementation must call one of grant() or reject() for every request.
              *
              * @param video MediaSource for the video source to use (must be an original
              *              MediaSource object that was passed to the implementation);
              *              or null when video is not requested.
              * @param audio MediaSource for the audio source to use (must be an original
              *              MediaSource object that was passed to the implementation);
              *              or null when audio is not requested.
              */
             @UiThread
-            void grant(final @Nullable MediaSource video, final @Nullable MediaSource audio);
+            default void grant(final @Nullable MediaSource video, final @Nullable MediaSource audio) {}
 
             /**
              * Called by the implementation when permissions are not granted; the
              * implementation must call one of grant() or reject() for every request.
              */
             @UiThread
-            void reject();
+            default void reject() {}
         }
 
         /**
          * Request content media permissions, including request for which video and/or
          * audio source to use.
          *
          * Media permissions will still be requested if the associated device permissions have been
          * denied if there are video or audio sources in that category that can still be accessed.
@@ -4167,76 +4173,77 @@ public class GeckoSession implements Par
          * {@link #showSoftInput} or {@link #hideSoftInput}, because focus changes are not always
          * accompanied by requests to show or hide the soft input. This method is always called,
          * even in viewless mode.
          *
          * @param session Session instance.
          * @param reason Reason for the reset.
          */
         @UiThread
-        void restartInput(@NonNull GeckoSession session, @RestartReason int reason);
+        default void restartInput(@NonNull GeckoSession session, @RestartReason int reason) {}
 
         /**
          * Display the soft input. May be called consecutively, even if the soft input is
          * already shown. This method is always called, even in viewless mode.
          *
          * @param session Session instance.
          * @see #hideSoftInput
          * */
         @UiThread
-        void showSoftInput(@NonNull GeckoSession session);
+        default void showSoftInput(@NonNull GeckoSession session) {}
 
         /**
          * Hide the soft input. May be called consecutively, even if the soft input is
          * already hidden. This method is always called, even in viewless mode.
          *
          * @param session Session instance.
          * @see #showSoftInput
          * */
         @UiThread
-        void hideSoftInput(@NonNull GeckoSession session);
+        default void hideSoftInput(@NonNull GeckoSession session) {}
 
         /**
          * Update the soft input on the current selection. This method is <i>not</i> called
          * in viewless mode.
          *
          * @param session Session instance.
          * @param selStart Start offset of the selection.
          * @param selEnd End offset of the selection.
          * @param compositionStart Composition start offset, or -1 if there is no composition.
          * @param compositionEnd Composition end offset, or -1 if there is no composition.
          */
         @UiThread
-        void updateSelection(@NonNull GeckoSession session, int selStart, int selEnd,
-                             int compositionStart, int compositionEnd);
+        default void updateSelection(@NonNull GeckoSession session, int selStart, int selEnd,
+                                     int compositionStart, int compositionEnd) {}
 
         /**
          * Update the soft input on the current extracted text, as requested through
          * {@link android.view.inputmethod.InputConnection#getExtractedText}.
          * Consequently, this method is <i>not</i> called in viewless mode.
          *
          * @param session Session instance.
          * @param request The extract text request.
          * @param text The extracted text.
          */
         @UiThread
-        void updateExtractedText(@NonNull GeckoSession session,
-                                 @NonNull ExtractedTextRequest request,
-                                 @NonNull ExtractedText text);
+        default void updateExtractedText(@NonNull GeckoSession session,
+                                         @NonNull ExtractedTextRequest request,
+                                         @NonNull ExtractedText text) {}
 
         /**
          * Update the cursor-anchor information as requested through
          * {@link android.view.inputmethod.InputConnection#requestCursorUpdates}.
          * Consequently, this method is <i>not</i> called in viewless mode.
          *
          * @param session Session instance.
          * @param info Cursor-anchor information.
          */
         @UiThread
-        void updateCursorAnchorInfo(@NonNull GeckoSession session, @NonNull CursorAnchorInfo info);
+        default void updateCursorAnchorInfo(@NonNull GeckoSession session,
+                                            @NonNull CursorAnchorInfo info) {}
 
         @Retention(RetentionPolicy.SOURCE)
         @IntDef({AUTO_FILL_NOTIFY_STARTED, AUTO_FILL_NOTIFY_COMMITTED, AUTO_FILL_NOTIFY_CANCELED,
                 AUTO_FILL_NOTIFY_VIEW_ADDED, AUTO_FILL_NOTIFY_VIEW_REMOVED,
                 AUTO_FILL_NOTIFY_VIEW_UPDATED, AUTO_FILL_NOTIFY_VIEW_ENTERED,
                 AUTO_FILL_NOTIFY_VIEW_EXITED})
         /* package */ @interface AutoFillNotification {}
 
@@ -4266,18 +4273,19 @@ public class GeckoSession implements Par
          * @param notification Notification type as one of the {@link #AUTO_FILL_NOTIFY_STARTED
          *                     AUTO_FILL_NOTIFY_*} constants.
          * @param virtualId Virtual ID of the target, or {@link android.view.View#NO_ID} if not
          *                  applicable. The ID matches one of the virtual IDs provided by {@link
          *                  SessionTextInput#onProvideAutofillVirtualStructure} and can be used
          *                  with {@link SessionTextInput#autofill}.
          */
         @UiThread
-        void notifyAutoFill(@NonNull GeckoSession session, @AutoFillNotification int notification,
-                            int virtualId);
+        default void notifyAutoFill(@NonNull GeckoSession session,
+                                    @AutoFillNotification int notification,
+                                    int virtualId) {}
     }
 
     /* package */ void onSurfaceChanged(final Surface surface, final int x, final int y, final int width,
                                         final int height) {
         ThreadUtils.assertOnUiThread();
 
         mOffsetX = x;
         mOffsetY = y;
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/MediaElement.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/MediaElement.java
@@ -287,93 +287,97 @@ public class MediaElement {
         /**
          * The media playback state has changed.
          *
          * @param mediaElement A reference to the MediaElement that dispatched the event.
          * @param mediaState The playback state of the media.
          *                   One of the {@link #MEDIA_STATE_PLAY MEDIA_STATE_*} flags.
          */
         @UiThread
-        void onPlaybackStateChange(@NonNull MediaElement mediaElement, @MediaStateFlags int mediaState);
+        default void onPlaybackStateChange(@NonNull MediaElement mediaElement,
+                                           @MediaStateFlags int mediaState) {}
 
         /**
          * The readiness state of the media has changed.
          *
          * @param mediaElement A reference to the MediaElement that dispatched the event.
          * @param readyState The readiness state of the media.
          *                   One of the {@link #MEDIA_READY_STATE_HAVE_NOTHING MEDIA_READY_STATE_*} flags.
          */
         @UiThread
-        void onReadyStateChange(@NonNull MediaElement mediaElement, @ReadyStateFlags int readyState);
+        default void onReadyStateChange(@NonNull MediaElement mediaElement,
+                                        @ReadyStateFlags int readyState) {}
 
         /**
          * The media metadata has loaded or changed.
          *
          * @param mediaElement A reference to the MediaElement that dispatched the event.
          * @param metaData The MetaData values of the media.
          */
         @UiThread
-        void onMetadataChange(@NonNull MediaElement mediaElement, @NonNull Metadata metaData);
+        default void onMetadataChange(@NonNull MediaElement mediaElement,
+                                      @NonNull Metadata metaData) {}
 
         /**
          * Indicates that a loading operation is in progress for the media.
          *
          * @param mediaElement A reference to the MediaElement that dispatched the event.
          * @param progressInfo Information about the load progress and buffered ranges.
          */
         @UiThread
-        void onLoadProgress(@NonNull MediaElement mediaElement,
-                            @NonNull LoadProgressInfo progressInfo);
+        default void onLoadProgress(@NonNull MediaElement mediaElement,
+                                    @NonNull LoadProgressInfo progressInfo) {}
 
         /**
          * The media audio volume has changed.
          *
          * @param mediaElement A reference to the MediaElement that dispatched the event.
          * @param volume The volume of the media.
          * @param muted True if the media is muted.
          */
         @UiThread
-        void onVolumeChange(@NonNull MediaElement mediaElement, double volume, boolean muted);
+        default void onVolumeChange(@NonNull MediaElement mediaElement, double volume,
+                                    boolean muted) {}
 
         /**
          * The current playback time has changed. This event is usually dispatched every 250ms.
          *
          * @param mediaElement A reference to the MediaElement that dispatched the event.
          * @param time The current playback time in seconds.
          */
         @UiThread
-        void onTimeChange(@NonNull MediaElement mediaElement, double time);
+        default void onTimeChange(@NonNull MediaElement mediaElement, double time) {}
 
         /**
          * The media playback speed has changed.
          *
          * @param mediaElement A reference to the MediaElement that dispatched the event.
          * @param rate The current playback rate. A value of 1.0 indicates normal speed.
          */
         @UiThread
-        void onPlaybackRateChange(@NonNull MediaElement mediaElement, double rate);
+        default void onPlaybackRateChange(@NonNull MediaElement mediaElement, double rate) {}
 
         /**
          * A media element has entered or exited fullscreen mode.
          *
          * @param mediaElement A reference to the MediaElement that dispatched the event.
          * @param fullscreen True if the media has entered full screen mode.
          */
         @UiThread
-        void onFullscreenChange(@NonNull MediaElement mediaElement, boolean fullscreen);
+        default void onFullscreenChange(@NonNull MediaElement mediaElement, boolean fullscreen) {}
 
         /**
          * An error has occurred.
          *
          * @param mediaElement A reference to the MediaElement that dispatched the event.
          * @param errorCode The error code.
          *                  One of the {@link #MEDIA_ERROR_NETWORK_NO_SOURCE MEDIA_ERROR_*} flags.
          */
         @UiThread
-        void onError(@NonNull MediaElement mediaElement, @MediaErrorFlags int errorCode);
+        default void onError(@NonNull MediaElement mediaElement, @MediaErrorFlags int errorCode) {}
     }
 
     /* package */ long getVideoId() {
         return mVideoId;
     }
 
     /**
      * Gets the current the media callback handler.
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/doc-files/CHANGELOG.md
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/doc-files/CHANGELOG.md
@@ -83,16 +83,18 @@ exclude: true
 - Added API to capture a screenshot to [`GeckoDisplay`][67.20]. [`capturePixels`][67.21] returns a ['GeckoResult'][65.25] that completes to a [`Bitmap`][67.16] of the current [`Surface`][67.17] contents, or an [`IllegalStateException`][67.18] if the [`GeckoSession`][65.9] is not ready to render content.
 
 [67.20]: ../GeckoDisplay.html
 [67.21]: ../GeckoDisplay.html#capturePixels
 
 - Add missing `@Nullable` annotation to return value for
   `GeckoSession.PromptDelegate.ChoiceCallback.onPopupResult()`
 
+- Added `default` implementations for all non-functional `interface`s.
+
 ## v66
 - Removed redundant field `trackingMode` from [`SecurityInformation`][66.6].
   Use `TrackingProtectionDelegate.onTrackerBlocked` for notification of blocked
   elements during page load.
 
 [66.6]: ../GeckoSession.ProgressDelegate.SecurityInformation.html
 
 - Added [`@NonNull`][66.1] or [`@Nullable`][66.2] to all APIs.
@@ -202,9 +204,9 @@ exclude: true
 [65.23]: ../GeckoSession.FinderResult.html
 
 - Update [`CrashReporter#sendCrashReport`][65.24] to return the crash ID as a
   [`GeckoResult<String>`][65.25].
 
 [65.24]: ../CrashReporter.html#sendCrashReport-android.content.Context-android.os.Bundle-java.lang.String-
 [65.25]: ../GeckoResult.html
 
-[api-version]: 577c3b0d000b0b1da57f9af32331f1e9045939b9
+[api-version]: 09c473360eb5e17aa801fa0f966cd8671cf2f3d2
--- a/modules/libpref/init/StaticPrefList.h
+++ b/modules/libpref/init/StaticPrefList.h
@@ -2002,32 +2002,42 @@ VARCACHE_PREF(
 // Annotate channels based on the tracking protection list in all modes
 VARCACHE_PREF(
   "privacy.trackingprotection.annotate_channels",
    privacy_trackingprotection_annotate_channels,
   bool, true
 )
 
 // Block 3rd party fingerprinting resources.
-# define PREF_VALUE false
 VARCACHE_PREF(
   "privacy.trackingprotection.fingerprinting.enabled",
    privacy_trackingprotection_fingerprinting_enabled,
-  bool, PREF_VALUE
+  bool, false
 )
-#undef PREF_VALUE
+
+// Annotate fingerprinting resources.
+VARCACHE_PREF(
+  "privacy.trackingprotection.fingerprinting.annotate.enabled",
+   privacy_trackingprotection_fingerprinting_annotate_enabled,
+  bool, false
+)
 
 // Block 3rd party cryptomining resources.
-# define PREF_VALUE false
 VARCACHE_PREF(
   "privacy.trackingprotection.cryptomining.enabled",
    privacy_trackingprotection_cryptomining_enabled,
-  bool, PREF_VALUE
+  bool, false
 )
-#undef PREF_VALUE
+
+// Annotate cryptomining resources.
+VARCACHE_PREF(
+  "privacy.trackingprotection.cryptomining.annotate.enabled",
+   privacy_trackingprotection_cryptomining_annotate_enabled,
+  bool, false
+)
 
 // Lower the priority of network loads for resources on the tracking protection
 // list.  Note that this requires the
 // privacy.trackingprotection.annotate_channels pref to be on in order to have
 // any effect.
 #ifdef NIGHTLY_BUILD
 # define PREF_VALUE true
 #else
--- a/netwerk/base/SimpleChannelParent.cpp
+++ b/netwerk/base/SimpleChannelParent.cpp
@@ -43,17 +43,18 @@ SimpleChannelParent::NotifyCookieAllowed
 
 NS_IMETHODIMP
 SimpleChannelParent::NotifyCookieBlocked(uint32_t aRejectedReason) {
   // Nothing to do.
   return NS_OK;
 }
 
 NS_IMETHODIMP
-SimpleChannelParent::NotifyTrackingResource(bool aIsThirdParty) {
+SimpleChannelParent::NotifyClassificationFlags(uint32_t aClassificationFlags,
+                                               bool aIsThirdParty) {
   // Nothing to do.
   return NS_OK;
 }
 
 NS_IMETHODIMP
 SimpleChannelParent::NotifyFlashPluginStateChanged(
     nsIHttpChannel::FlashPluginState aState) {
   // Nothing to do.
--- a/netwerk/base/nsIParentChannel.idl
+++ b/netwerk/base/nsIParentChannel.idl
@@ -62,20 +62,23 @@ interface nsIParentChannel : nsIStreamLi
    *        String represents full hash that matched
    */
   [noscript] void setClassifierMatchedInfo(in ACString aList,
                                            in ACString aProvider,
                                            in ACString aFullHash);
 
   /**
    * Called to notify the HttpChannelChild that the resource being loaded
-   * is on the tracking protection list.
+   * has been classified.
+   * @param aClassificationFlags
+   *        What classifier identifies this channel.
    * @param aIsThirdParty
    *        Whether or not the resourced is considered first-party
    *        with the URI of the window.
    */
-  [noscript] void notifyTrackingResource(in bool aIsThirdParty);
+  [noscript] void notifyClassificationFlags(in uint32_t aClassificationFlags,
+                                            in bool aIsThirdParty);
 
   /**
    * Called to invoke deletion of the IPC protocol.
    */
   void delete();
 };
--- a/netwerk/cookie/CookieServiceParent.h
+++ b/netwerk/cookie/CookieServiceParent.h
@@ -49,17 +49,17 @@ class CookieServiceParent : public PCook
       const Maybe<LoadInfoArgs> &aLoadInfoArgs, const bool &aIsForeign,
       const bool &aIsTrackingResource,
       const bool &aFirstPartyStorageAccessGranted,
       const nsCString &aCookieString, const nsCString &aServerTime,
       const bool &aFromHttp);
 
   mozilla::ipc::IPCResult RecvPrepareCookieList(
       const URIParams &aHost, const bool &aIsForeign,
-      const bool &aIsTackingResource,
+      const bool &aIsTrackingResource,
       const bool &aFirstPartyStorageAccessGranted,
       const bool &aIsSafeTopLevelNav, const bool &aIsSameSiteForeign,
       const OriginAttributes &aAttrs);
 
   void SerialializeCookieList(const nsTArray<nsCookie *> &aFoundCookieList,
                               nsTArray<CookieStruct> &aCookiesList,
                               nsIURI *aHostURI);
 
--- a/netwerk/protocol/data/DataChannelParent.cpp
+++ b/netwerk/protocol/data/DataChannelParent.cpp
@@ -43,17 +43,18 @@ DataChannelParent::NotifyCookieAllowed()
 
 NS_IMETHODIMP
 DataChannelParent::NotifyCookieBlocked(uint32_t aRejectedReason) {
   // Nothing to do.
   return NS_OK;
 }
 
 NS_IMETHODIMP
-DataChannelParent::NotifyTrackingResource(bool aIsThirdParty) {
+DataChannelParent::NotifyClassificationFlags(uint32_t aClassificationFlags,
+                                             bool aIsThirdParty) {
   // Nothing to do.
   return NS_OK;
 }
 
 NS_IMETHODIMP
 DataChannelParent::NotifyFlashPluginStateChanged(
     nsIHttpChannel::FlashPluginState aState) {
   // Nothing to do.
--- a/netwerk/protocol/file/FileChannelParent.cpp
+++ b/netwerk/protocol/file/FileChannelParent.cpp
@@ -43,17 +43,18 @@ FileChannelParent::NotifyCookieAllowed()
 
 NS_IMETHODIMP
 FileChannelParent::NotifyCookieBlocked(uint32_t aRejectedReason) {
   // Nothing to do.
   return NS_OK;
 }
 
 NS_IMETHODIMP
-FileChannelParent::NotifyTrackingResource(bool aIsThirdParty) {
+FileChannelParent::NotifyClassificationFlags(uint32_t aClassificationFlags,
+                                             bool aIsThirdParty) {
   // Nothing to do.
   return NS_OK;
 }
 
 NS_IMETHODIMP
 FileChannelParent::NotifyFlashPluginStateChanged(
     nsIHttpChannel::FlashPluginState aState) {
   // Nothing to do.
--- a/netwerk/protocol/ftp/FTPChannelParent.cpp
+++ b/netwerk/protocol/ftp/FTPChannelParent.cpp
@@ -510,17 +510,18 @@ FTPChannelParent::NotifyCookieAllowed() 
 
 NS_IMETHODIMP
 FTPChannelParent::NotifyCookieBlocked(uint32_t aRejectedReason) {
   // One day, this should probably be filled in.
   return NS_OK;
 }
 
 NS_IMETHODIMP
-FTPChannelParent::NotifyTrackingResource(bool aIsThirdParty) {
+FTPChannelParent::NotifyClassificationFlags(uint32_t aClassificationFlags,
+                                            bool aIsThirdParty) {
   // One day, this should probably be filled in.
   return NS_OK;
 }
 
 NS_IMETHODIMP
 FTPChannelParent::NotifyFlashPluginStateChanged(
     nsIHttpChannel::FlashPluginState aState) {
   // One day, this should probably be filled in.
--- a/netwerk/protocol/http/HttpBackgroundChannelChild.cpp
+++ b/netwerk/protocol/http/HttpBackgroundChannelChild.cpp
@@ -339,31 +339,32 @@ IPCResult HttpBackgroundChannelChild::Re
     return IPC_OK();
   }
 
   mChannelChild->ProcessNotifyCookieBlocked(aRejectedReason);
 
   return IPC_OK();
 }
 
-IPCResult HttpBackgroundChannelChild::RecvNotifyTrackingResource(
-    const bool& aIsThirdParty) {
+IPCResult HttpBackgroundChannelChild::RecvNotifyClassificationFlags(
+    const uint32_t& aClassificationFlags, const bool& aIsThirdParty) {
   LOG(
-      ("HttpBackgroundChannelChild::RecvNotifyTrackingResource thirdparty=%d "
-       "[this=%p]\n",
-       static_cast<int>(aIsThirdParty), this));
+      ("HttpBackgroundChannelChild::RecvNotifyClassificationFlags "
+       "classificationFlags=%" PRIu32 ", thirdparty=%d [this=%p]\n",
+       aClassificationFlags, static_cast<int>(aIsThirdParty), this));
   MOZ_ASSERT(OnSocketThread());
 
   if (NS_WARN_IF(!mChannelChild)) {
     return IPC_OK();
   }
 
-  // NotifyTrackingResource has no order dependency to OnStartRequest.
+  // NotifyClassificationFlags has no order dependency to OnStartRequest.
   // It this be handled as soon as possible
-  mChannelChild->ProcessNotifyTrackingResource(aIsThirdParty);
+  mChannelChild->ProcessNotifyClassificationFlags(aClassificationFlags,
+                                                  aIsThirdParty);
 
   return IPC_OK();
 }
 
 IPCResult HttpBackgroundChannelChild::RecvNotifyFlashPluginStateChanged(
     const nsIHttpChannel::FlashPluginState& aState) {
   LOG(
       ("HttpBackgroundChannelChild::RecvNotifyFlashPluginStateChanged "
--- a/netwerk/protocol/http/HttpBackgroundChannelChild.h
+++ b/netwerk/protocol/http/HttpBackgroundChannelChild.h
@@ -66,17 +66,18 @@ class HttpBackgroundChannelChild final :
 
   IPCResult RecvNotifyChannelClassifierProtectionDisabled(
       const uint32_t& aAcceptedReason);
 
   IPCResult RecvNotifyCookieAllowed();
 
   IPCResult RecvNotifyCookieBlocked(const uint32_t& aRejectedReason);
 
-  IPCResult RecvNotifyTrackingResource(const bool& aIsThirdParty);
+  IPCResult RecvNotifyClassificationFlags(const uint32_t& aClassificationFlags,
+                                          const bool& aIsThirdParty);
 
   IPCResult RecvNotifyFlashPluginStateChanged(
       const nsIHttpChannel::FlashPluginState& aState);
 
   IPCResult RecvSetClassifierMatchedInfo(const ClassifierInfo& info);
 
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
--- a/netwerk/protocol/http/HttpBackgroundChannelParent.cpp
+++ b/netwerk/protocol/http/HttpBackgroundChannelParent.cpp
@@ -400,42 +400,43 @@ bool HttpBackgroundChannelParent::OnNoti
     MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
 
     return NS_SUCCEEDED(rv);
   }
 
   return SendNotifyCookieBlocked(aRejectedReason);
 }
 
-bool HttpBackgroundChannelParent::OnNotifyTrackingResource(bool aIsThirdParty) {
+bool HttpBackgroundChannelParent::OnNotifyClassificationFlags(
+    uint32_t aClassificationFlags, bool aIsThirdParty) {
   LOG(
-      ("HttpBackgroundChannelParent::OnNotifyTrackingResource thirdparty=%d "
-       "[this=%p]\n",
-       static_cast<int>(aIsThirdParty), this));
+      ("HttpBackgroundChannelParent::OnNotifyClassificationFlags "
+       "classificationFlags=%" PRIu32 ", thirdparty=%d [this=%p]\n",
+       aClassificationFlags, static_cast<int>(aIsThirdParty), this));
   AssertIsInMainProcess();
 
   if (NS_WARN_IF(!mIPCOpened)) {
     return false;
   }
 
   if (!IsOnBackgroundThread()) {
     MutexAutoLock lock(mBgThreadMutex);
     nsresult rv = mBackgroundThread->Dispatch(
-        NewRunnableMethod<bool>(
-            "net::HttpBackgroundChannelParent::OnNotifyTrackingResource", this,
-            &HttpBackgroundChannelParent::OnNotifyTrackingResource,
-            aIsThirdParty),
+        NewRunnableMethod<uint32_t, bool>(
+            "net::HttpBackgroundChannelParent::OnNotifyClassificationFlags",
+            this, &HttpBackgroundChannelParent::OnNotifyClassificationFlags,
+            aClassificationFlags, aIsThirdParty),
         NS_DISPATCH_NORMAL);
 
     MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
 
     return NS_SUCCEEDED(rv);
   }
 
-  return SendNotifyTrackingResource(aIsThirdParty);
+  return SendNotifyClassificationFlags(aClassificationFlags, aIsThirdParty);
 }
 
 bool HttpBackgroundChannelParent::OnNotifyFlashPluginStateChanged(
     nsIHttpChannel::FlashPluginState aState) {
   LOG(
       ("HttpBackgroundChannelParent::OnNotifyFlashPluginStateChanged "
        "[this=%p]\n",
        this));
--- a/netwerk/protocol/http/HttpBackgroundChannelParent.h
+++ b/netwerk/protocol/http/HttpBackgroundChannelParent.h
@@ -68,18 +68,19 @@ class HttpBackgroundChannelParent final 
   bool OnNotifyChannelClassifierProtectionDisabled(uint32_t aAcceptedReason);
 
   // To send NotifyCookieAllowed message over background channel.
   bool OnNotifyCookieAllowed();
 
   // To send NotifyCookieBlocked message over background channel.
   bool OnNotifyCookieBlocked(uint32_t aRejectedReason);
 
-  // To send NotifyTrackingResource message over background channel.
-  bool OnNotifyTrackingResource(bool aIsThirdParty);
+  // To send NotifyClassificationFlags message over background channel.
+  bool OnNotifyClassificationFlags(uint32_t aClassificationFlags,
+                                   bool aIsThirdParty);
 
   // To send NotifyFlashPluginStateChanged message over background channel.
   bool OnNotifyFlashPluginStateChanged(nsIHttpChannel::FlashPluginState aState);
 
   // To send SetClassifierMatchedInfo message over background channel.
   bool OnSetClassifierMatchedInfo(const nsACString& aList,
                                   const nsACString& aProvider,
                                   const nsACString& aFullHash);
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -59,16 +59,17 @@
 #include "nsISSLSocketControl.h"
 #include "mozilla/Telemetry.h"
 #include "nsIURL.h"
 #include "nsIConsoleService.h"
 #include "mozilla/BinarySearch.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Move.h"
 #include "mozilla/net/PartiallySeekableInputStream.h"
+#include "mozilla/net/UrlClassifierCommon.h"
 #include "mozilla/InputStreamLengthHelper.h"
 #include "nsIHttpHeaderVisitor.h"
 #include "nsIMIMEInputStream.h"
 #include "nsIXULRuntime.h"
 #include "nsICacheInfoChannel.h"
 #include "nsIDOMWindowUtils.h"
 #include "nsIURIFixup.h"
 #include "nsHttpChannel.h"
@@ -163,18 +164,18 @@ HttpBaseChannel::HttpBaseChannel()
       mRequestContextID(0),
       mContentWindowId(0),
       mTopLevelOuterContentWindowId(0),
       mAltDataLength(0),
       mChannelId(0),
       mReqContentLength(0U),
       mStatus(NS_OK),
       mCanceled(false),
-      mIsFirstPartyTrackingResource(false),
-      mIsThirdPartyTrackingResource(false),
+      mFirstPartyClassificationFlags(0),
+      mThirdPartyClassificationFlags(0),
       mFlashPluginState(nsIHttpChannel::FlashPluginUnknown),
       mLoadFlags(LOAD_NORMAL),
       mCaps(0),
       mClassOfService(0),
       mUpgradeToSecure(false),
       mApplyConversion(true),
       mIsPending(false),
       mWasOpened(false),
@@ -303,26 +304,27 @@ void HttpBaseChannel::ReleaseMainThreadO
 
     nsCOMPtr<nsISupports> nonTailRemover(new NonTailRemover(mRequestContext));
     arrayToRelease.AppendElement(nonTailRemover.forget());
   }
 
   NS_DispatchToMainThread(new ProxyReleaseRunnable(std::move(arrayToRelease)));
 }
 
-void HttpBaseChannel::SetIsTrackingResource(bool aIsThirdParty) {
-  LOG(("HttpBaseChannel::SetIsTrackingResource thirdparty=%d %p",
-       static_cast<int>(aIsThirdParty), this));
+void HttpBaseChannel::AddClassificationFlags(uint32_t aClassificationFlags,
+                                             bool aIsThirdParty) {
+  LOG(
+      ("HttpBaseChannel::AddClassificationFlags classificationFlags=%d "
+       "thirdparty=%d %p",
+       aClassificationFlags, static_cast<int>(aIsThirdParty), this));
 
   if (aIsThirdParty) {
-    MOZ_ASSERT(!mIsFirstPartyTrackingResource);
-    mIsThirdPartyTrackingResource = true;
+    mThirdPartyClassificationFlags |= aClassificationFlags;
   } else {
-    MOZ_ASSERT(!mIsThirdPartyTrackingResource);
-    mIsFirstPartyTrackingResource = true;
+    mFirstPartyClassificationFlags |= aClassificationFlags;
   }
 }
 
 void HttpBaseChannel::SetFlashPluginState(
     nsIHttpChannel::FlashPluginState aState) {
   LOG(("HttpBaseChannel::SetFlashPluginState %p", this));
   mFlashPluginState = aState;
 }
@@ -1464,58 +1466,99 @@ NS_IMETHODIMP HttpBaseChannel::GetTopLev
   return NS_OK;
 }
 
 NS_IMETHODIMP HttpBaseChannel::SetTopLevelContentWindowId(uint64_t aWindowId) {
   mContentWindowId = aWindowId;
   return NS_OK;
 }
 
+bool
+HttpBaseChannel::IsTrackingResource() const {
+  MOZ_ASSERT(!mFirstPartyClassificationFlags ||
+             !mThirdPartyClassificationFlags);
+  return UrlClassifierCommon::IsTrackingClassificationFlag(
+             mThirdPartyClassificationFlags) ||
+         UrlClassifierCommon::IsTrackingClassificationFlag(
+             mFirstPartyClassificationFlags);
+}
+
 NS_IMETHODIMP
 HttpBaseChannel::GetIsTrackingResource(bool* aIsTrackingResource) {
-  MOZ_ASSERT(!(mIsFirstPartyTrackingResource && mIsThirdPartyTrackingResource));
-  *aIsTrackingResource =
-      mIsThirdPartyTrackingResource || mIsFirstPartyTrackingResource;
+  *aIsTrackingResource = IsTrackingResource();
+  return NS_OK;
+}
+
+bool
+HttpBaseChannel::IsThirdPartyTrackingResource() const {
+  MOZ_ASSERT(
+      !(mFirstPartyClassificationFlags && mThirdPartyClassificationFlags));
+  return UrlClassifierCommon::IsTrackingClassificationFlag(
+      mThirdPartyClassificationFlags);
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::GetIsThirdPartyTrackingResource(bool* aIsTrackingResource) {
+  *aIsTrackingResource = IsThirdPartyTrackingResource();
   return NS_OK;
 }
 
 NS_IMETHODIMP
-HttpBaseChannel::GetIsThirdPartyTrackingResource(bool* aIsTrackingResource) {
-  MOZ_ASSERT(!(mIsFirstPartyTrackingResource && mIsThirdPartyTrackingResource));
-  *aIsTrackingResource = mIsThirdPartyTrackingResource;
+HttpBaseChannel::GetClassificationFlags(uint32_t* aFlags) {
+  MOZ_ASSERT(!mFirstPartyClassificationFlags ||
+             !mThirdPartyClassificationFlags);
+  if (mThirdPartyClassificationFlags) {
+    *aFlags = mThirdPartyClassificationFlags;
+  } else {
+    *aFlags = mFirstPartyClassificationFlags;
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::GetFirstPartyClassificationFlags(uint32_t* aFlags) {
+  MOZ_ASSERT(
+      !(mFirstPartyClassificationFlags && mFirstPartyClassificationFlags));
+  *aFlags = mFirstPartyClassificationFlags;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::GetThirdPartyClassificationFlags(uint32_t* aFlags) {
+  MOZ_ASSERT(
+      !(mFirstPartyClassificationFlags && mThirdPartyClassificationFlags));
+  *aFlags = mThirdPartyClassificationFlags;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HttpBaseChannel::GetFlashPluginState(nsIHttpChannel::FlashPluginState* aState) {
   uint32_t flashPluginState = mFlashPluginState;
   *aState = (nsIHttpChannel::FlashPluginState)flashPluginState;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HttpBaseChannel::OverrideTrackingFlagsForDocumentCookieAccessor(
     nsIHttpChannel* aDocumentChannel) {
-  LOG(
-      ("HttpBaseChannel::OverrideTrackingFlagsForDocumentCookieAccessor() %p "
-       "mIsFirstPartyTrackingResource=%d  mIsThirdPartyTrackingResource=%d",
-       this, static_cast<int>(mIsFirstPartyTrackingResource),
-       static_cast<int>(mIsThirdPartyTrackingResource)));
+  LOG(("HttpBaseChannel::OverrideTrackingFlagsForDocumentCookieAccessor() %p",
+       this));
 
   // The semantics we'd like to achieve here are that document.cookie
   // should follow the same rules that the document is subject to with
   // regards to content blocking. Therefore we need to propagate the
   // same flags from the document channel to the fake channel here.
-  if (aDocumentChannel->GetIsThirdPartyTrackingResource()) {
-    mIsThirdPartyTrackingResource = true;
-  } else {
-    mIsFirstPartyTrackingResource = true;
-  }
-
-  MOZ_ASSERT(!(mIsFirstPartyTrackingResource && mIsThirdPartyTrackingResource));
+
+  mThirdPartyClassificationFlags =
+      aDocumentChannel->GetThirdPartyClassificationFlags();
+  mFirstPartyClassificationFlags =
+      aDocumentChannel->GetFirstPartyClassificationFlags();
+
+  MOZ_ASSERT(
+      !(mFirstPartyClassificationFlags && mThirdPartyClassificationFlags));
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HttpBaseChannel::GetTransferSize(uint64_t* aTransferSize) {
   *aTransferSize = mTransferSize;
   return NS_OK;
 }
--- a/netwerk/protocol/http/HttpBaseChannel.h
+++ b/netwerk/protocol/http/HttpBaseChannel.h
@@ -234,16 +234,21 @@ class HttpBaseChannel : public nsHashPro
   NS_IMETHOD SetChannelId(uint64_t aChannelId) override;
   NS_IMETHOD GetTopLevelContentWindowId(uint64_t *aContentWindowId) override;
   NS_IMETHOD SetTopLevelContentWindowId(uint64_t aContentWindowId) override;
   NS_IMETHOD GetTopLevelOuterContentWindowId(uint64_t *aWindowId) override;
   NS_IMETHOD SetTopLevelOuterContentWindowId(uint64_t aWindowId) override;
   NS_IMETHOD GetIsTrackingResource(bool *aIsTrackingResource) override;
   NS_IMETHOD GetIsThirdPartyTrackingResource(
       bool *aIsTrackingResource) override;
+  NS_IMETHOD GetClassificationFlags(uint32_t *aIsClassificationFlags) override;
+  NS_IMETHOD GetFirstPartyClassificationFlags(
+      uint32_t *aIsClassificationFlags) override;
+  NS_IMETHOD GetThirdPartyClassificationFlags(
+      uint32_t *aIsClassificationFlags) override;
   NS_IMETHOD OverrideTrackingFlagsForDocumentCookieAccessor(
       nsIHttpChannel *aDocumentChannel) override;
   NS_IMETHOD GetFlashPluginState(
       nsIHttpChannel::FlashPluginState *aState) override;
 
   // nsIHttpChannelInternal
   NS_IMETHOD GetDocumentURI(nsIURI **aDocumentURI) override;
   NS_IMETHOD SetDocumentURI(nsIURI *aDocumentURI) override;
@@ -412,17 +417,17 @@ class HttpBaseChannel : public nsHashPro
   MOZ_MUST_USE nsresult DoApplyContentConversions(
       nsIStreamListener *aNextListener, nsIStreamListener **aNewNextListener);
 
   // Callback on STS thread called by CopyComplete when NS_AsyncCopy()
   // is finished. This function works as a proxy function to dispatch
   // |EnsureUploadStreamIsCloneableComplete| to main thread.
   virtual void OnCopyComplete(nsresult aStatus);
 
-  void SetIsTrackingResource(bool aIsThirdParty);
+  void AddClassificationFlags(uint32_t aFlags, bool aIsThirdParty);
 
   void SetFlashPluginState(nsIHttpChannel::FlashPluginState aState);
 
   const uint64_t &ChannelId() const { return mChannelId; }
 
   void InternalSetUploadStream(nsIInputStream *uploadStream) {
     mUploadStream = uploadStream;
   }
@@ -528,16 +533,19 @@ class HttpBaseChannel : public nsHashPro
   static void CallTypeSniffers(void *aClosure, const uint8_t *aData,
                                uint32_t aCount);
 
   nsresult CheckRedirectLimit(uint32_t aRedirectFlags) const;
 
   bool MaybeWaitForUploadStreamLength(nsIStreamListener *aListener,
                                       nsISupports *aContext);
 
+  bool IsThirdPartyTrackingResource() const;
+  bool IsTrackingResource() const;
+
   friend class PrivateBrowsingChannel<HttpBaseChannel>;
   friend class InterceptFailedOnStop;
 
  protected:
   // this section is for main-thread-only object
   // all the references need to be proxy released on main thread.
   nsCOMPtr<nsIURI> mURI;
   nsCOMPtr<nsIURI> mOriginalURI;
@@ -657,18 +665,18 @@ class HttpBaseChannel : public nsHashPro
   uint64_t mChannelId;
   uint64_t mReqContentLength;
 
   Atomic<nsresult, ReleaseAcquire> mStatus;
 
   // Use Release-Acquire ordering to ensure the OMT ODA is ignored while channel
   // is canceled on main thread.
   Atomic<bool, ReleaseAcquire> mCanceled;
-  Atomic<bool, ReleaseAcquire> mIsFirstPartyTrackingResource;
-  Atomic<bool, ReleaseAcquire> mIsThirdPartyTrackingResource;
+  Atomic<uint32_t, ReleaseAcquire> mFirstPartyClassificationFlags;
+  Atomic<uint32_t, ReleaseAcquire> mThirdPartyClassificationFlags;
   Atomic<uint32_t, ReleaseAcquire> mFlashPluginState;
 
   uint32_t mLoadFlags;
   uint32_t mCaps;
   uint32_t mClassOfService;
 
   uint32_t mUpgradeToSecure : 1;
   uint32_t mApplyConversion : 1;
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -1866,24 +1866,25 @@ void HttpChannelChild::ProcessNotifyCook
                                AntiTrackingCommon::NotifyBlockingDecision(
                                    self,
                                    AntiTrackingCommon::BlockingDecision::eBlock,
                                    aRejectedReason);
                              }),
       NS_DISPATCH_NORMAL);
 }
 
-void HttpChannelChild::ProcessNotifyTrackingResource(bool aIsThirdParty) {
+void HttpChannelChild::ProcessNotifyClassificationFlags(
+    uint32_t aClassificationFlags, bool aIsThirdParty) {
   LOG(
-      ("HttpChannelChild::ProcessNotifyTrackingResource thirdparty=%d "
-       "[this=%p]\n",
-       static_cast<int>(aIsThirdParty), this));
+      ("HttpChannelChild::ProcessNotifyClassificationFlags thirdparty=%d "
+       "flags=%" PRIu32 " [this=%p]\n",
+       static_cast<int>(aIsThirdParty), aClassificationFlags, this));
   MOZ_ASSERT(OnSocketThread());
 
-  SetIsTrackingResource(aIsThirdParty);
+  AddClassificationFlags(aClassificationFlags, aIsThirdParty);
 }
 
 void HttpChannelChild::ProcessNotifyFlashPluginStateChanged(
     nsIHttpChannel::FlashPluginState aState) {
   LOG(("HttpChannelChild::ProcessNotifyFlashPluginStateChanged [this=%p]\n",
        this));
   MOZ_ASSERT(OnSocketThread());
 
--- a/netwerk/protocol/http/HttpChannelChild.h
+++ b/netwerk/protocol/http/HttpChannelChild.h
@@ -261,17 +261,18 @@ class HttpChannelChild final : public PH
   void ProcessOnProgress(const int64_t& aProgress, const int64_t& aProgressMax);
   void ProcessOnStatus(const nsresult& aStatus);
   void ProcessFlushedForDiversion();
   void ProcessDivertMessages();
   void ProcessNotifyChannelClassifierProtectionDisabled(
       uint32_t aAcceptedReason);
   void ProcessNotifyCookieAllowed();
   void ProcessNotifyCookieBlocked(uint32_t aRejectedReason);
-  void ProcessNotifyTrackingResource(bool aIsThirdParty);
+  void ProcessNotifyClassificationFlags(uint32_t aClassificationFlags,
+                                        bool aIsThirdParty);
   void ProcessNotifyFlashPluginStateChanged(
       nsIHttpChannel::FlashPluginState aState);
   void ProcessSetClassifierMatchedInfo(const nsCString& aList,
                                        const nsCString& aProvider,
                                        const nsCString& aFullHash);
 
   // Return true if we need to tell the parent the size of unreported received
   // data
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -1843,22 +1843,26 @@ HttpChannelParent::SetClassifierMatchedI
     MOZ_ASSERT(mBgParent);
     Unused << mBgParent->OnSetClassifierMatchedInfo(aList, aProvider,
                                                     aFullHash);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
-HttpChannelParent::NotifyTrackingResource(bool aIsThirdParty) {
-  LOG(("HttpChannelParent::NotifyTrackingResource thirdparty=%d [this=%p]\n",
-       static_cast<int>(aIsThirdParty), this));
+HttpChannelParent::NotifyClassificationFlags(uint32_t aClassificationFlags,
+                                             bool aIsThirdParty) {
+  LOG(
+      ("HttpChannelParent::NotifyClassificationFlags "
+       "classificationFlags=%" PRIu32 ", thirdparty=%d [this=%p]\n",
+       aClassificationFlags, static_cast<int>(aIsThirdParty), this));
   if (!mIPCClosed) {
     MOZ_ASSERT(mBgParent);
-    Unused << mBgParent->OnNotifyTrackingResource(aIsThirdParty);
+    Unused << mBgParent->OnNotifyClassificationFlags(aClassificationFlags,
+                                                     aIsThirdParty);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HttpChannelParent::NotifyFlashPluginStateChanged(
     nsIHttpChannel::FlashPluginState aState) {
   LOG(("HttpChannelParent::NotifyFlashPluginStateChanged [this=%p]\n", this));
--- a/netwerk/protocol/http/NullHttpChannel.cpp
+++ b/netwerk/protocol/http/NullHttpChannel.cpp
@@ -84,23 +84,40 @@ NullHttpChannel::SetTopLevelOuterContent
 }
 
 NS_IMETHODIMP
 NullHttpChannel::GetIsTrackingResource(bool *aIsTrackingResource) {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
+NullHttpChannel::GetIsThirdPartyTrackingResource(bool *aIsTrackingResource) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+NullHttpChannel::GetClassificationFlags(uint32_t *aClassificationFlags) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
 NullHttpChannel::GetFlashPluginState(
     nsIHttpChannel::FlashPluginState *aResult) {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
-NullHttpChannel::GetIsThirdPartyTrackingResource(bool *aIsTrackingResource) {
+NullHttpChannel::GetFirstPartyClassificationFlags(
+    uint32_t *aClassificationFlags) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+NullHttpChannel::GetThirdPartyClassificationFlags(
+    uint32_t *aClassificationFlags) {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 NullHttpChannel::OverrideTrackingFlagsForDocumentCookieAccessor(
     nsIHttpChannel *aDocumentChannel) {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
--- a/netwerk/protocol/http/PHttpBackgroundChannel.ipdl
+++ b/netwerk/protocol/http/PHttpBackgroundChannel.ipdl
@@ -59,19 +59,18 @@ child:
   async NotifyChannelClassifierProtectionDisabled(uint32_t aAcceptedReason);
 
   // Tell the child that cookies are allowed for this load.
   async NotifyCookieAllowed();
 
   // Tell the child that tracking cookies are blocked for this load.
   async NotifyCookieBlocked(uint32_t aRejectedReason);
 
-  // Tell the child that the resource being loaded is on the tracking
-  // protection list.
-  async NotifyTrackingResource(bool aIsThirdParty);
+  // Tell the child that the resource being loaded has been classified.
+  async NotifyClassificationFlags(uint32_t aClassificationFlags, bool aIsThirdParty);
 
   // Tell the child that the current channel's document is not allowed to load
   // flash content.
   async NotifyFlashPluginStateChanged(FlashPluginState aState);
 
   // Tell the child information of matched URL againts SafeBrowsing list
   async SetClassifierMatchedInfo(ClassifierInfo info);
 
--- a/netwerk/protocol/http/PTrackingDummyChannel.ipdl
+++ b/netwerk/protocol/http/PTrackingDummyChannel.ipdl
@@ -6,19 +6,19 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include protocol PNecko;
 
 namespace mozilla {
 namespace net {
 
 // This protocol provides a mechanism for the "child intercept" mode of
-// ServiceWorker operation to work correctly with Tracking Protection
-// annotations.  ServiceWorkers should not be allowed for third-party iframes
-// which are annotated as tracking origins.
+// ServiceWorker operation to work correctly with Classified channels.
+// ServiceWorkers should not be allowed for third-party iframes which are
+// annotated as tracking origins.
 //
 // In child intercept mode, the decision to intercept a channel is made in the
 // child process without consulting the parent process.  The decision is based
 // on whether there is a ServiceWorker with a scope covering the URL in question
 // and whether storage is allowed for the origin/URL.  When the
 // "network.cookie.cookieBehavior" preference is set to BEHAVIOR_REJECT_TRACKER,
 // annotated channels are denied storage which means that the ServiceWorker
 // should not intercept the channel.  However, the decision for tracking
@@ -34,14 +34,14 @@ namespace net {
 // to be confident we will never need/want to turn it off.  Then as part of bug
 // 1496997 we can remove this implementation.  Bug 1498259 covers removing this
 // hack in particular.
 protocol PTrackingDummyChannel
 {
   manager PNecko;
 
 child:
-  async __delete__(bool aTrackingResource);
+  async __delete__(uint32_t aClassificationFlags);
 };
 
 } // namespace net
 } // namespace mozilla
 
--- a/netwerk/protocol/http/TrackingDummyChannel.cpp
+++ b/netwerk/protocol/http/TrackingDummyChannel.cpp
@@ -73,38 +73,39 @@ NS_INTERFACE_MAP_BEGIN(TrackingDummyChan
   NS_INTERFACE_MAP_ENTRY_CONCRETE(TrackingDummyChannel)
 NS_INTERFACE_MAP_END
 
 TrackingDummyChannel::TrackingDummyChannel(nsIURI* aURI, nsIURI* aTopWindowURI,
                                            nsresult aTopWindowURIResult,
                                            nsILoadInfo* aLoadInfo)
     : mTopWindowURI(aTopWindowURI),
       mTopWindowURIResult(aTopWindowURIResult),
-      mIsTrackingResource(false) {
+      mClassificationFlags(0) {
   MOZ_ASSERT(XRE_IsParentProcess());
 
   SetOriginalURI(aURI);
   SetLoadInfo(aLoadInfo);
 }
 
 TrackingDummyChannel::~TrackingDummyChannel() {
   NS_ReleaseOnMainThreadSystemGroup("TrackingDummyChannel::mLoadInfo",
                                     mLoadInfo.forget());
   NS_ReleaseOnMainThreadSystemGroup("TrackingDummyChannel::mURI",
                                     mURI.forget());
   NS_ReleaseOnMainThreadSystemGroup("TrackingDummyChannel::mTopWindowURI",
                                     mTopWindowURI.forget());
 }
 
-bool TrackingDummyChannel::IsTrackingResource() const {
-  return mIsTrackingResource;
+uint32_t TrackingDummyChannel::ClassificationFlags() const {
+  return mClassificationFlags;
 }
 
-void TrackingDummyChannel::SetIsTrackingResource() {
-  mIsTrackingResource = true;
+void TrackingDummyChannel::AddClassificationFlags(
+    uint32_t aClassificationFlags) {
+  mClassificationFlags |= aClassificationFlags;
 }
 
 //-----------------------------------------------------------------------------
 // TrackingDummyChannel::nsIChannel
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 TrackingDummyChannel::GetOriginalURI(nsIURI** aOriginalURI) {
--- a/netwerk/protocol/http/TrackingDummyChannel.h
+++ b/netwerk/protocol/http/TrackingDummyChannel.h
@@ -61,29 +61,29 @@ class TrackingDummyChannel final : publi
   };
 
   static StorageAllowedState StorageAllowed(
       nsIChannel* aChannel, const std::function<void(bool)>& aCallback);
 
   TrackingDummyChannel(nsIURI* aURI, nsIURI* aTopWindowURI,
                        nsresult aTopWindowURIResult, nsILoadInfo* aLoadInfo);
 
-  bool IsTrackingResource() const;
+  uint32_t ClassificationFlags() const;
 
-  void SetIsTrackingResource();
+  void AddClassificationFlags(uint32_t);
 
  private:
   ~TrackingDummyChannel();
 
   nsCOMPtr<nsILoadInfo> mLoadInfo;
   nsCOMPtr<nsIURI> mURI;
   nsCOMPtr<nsIURI> mTopWindowURI;
   nsresult mTopWindowURIResult;
 
-  bool mIsTrackingResource;
+  uint32_t mClassificationFlags;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(TrackingDummyChannel, TRACKING_DUMMY_CHANNEL_IID)
 
 }  // namespace net
 }  // namespace mozilla
 
 #endif  // mozilla_net_TrackingDummyChannel_h
--- a/netwerk/protocol/http/TrackingDummyChannelChild.cpp
+++ b/netwerk/protocol/http/TrackingDummyChannelChild.cpp
@@ -63,29 +63,27 @@ void TrackingDummyChannelChild::Initiali
 
   mChannel = aChannel;
   mURI = aURI;
   mIsThirdParty = aIsThirdParty;
   mCallback = aCallback;
 }
 
 mozilla::ipc::IPCResult TrackingDummyChannelChild::Recv__delete__(
-    const bool& aTrackingResource) {
+    const uint32_t& aClassificationFlags) {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (!mChannel) {
     return IPC_OK();
   }
 
   nsCOMPtr<nsIHttpChannel> channel = std::move(mChannel);
 
   RefPtr<HttpBaseChannel> httpChannel = do_QueryObject(channel);
-  if (aTrackingResource) {
-    httpChannel->SetIsTrackingResource(mIsThirdParty);
-  }
+  httpChannel->AddClassificationFlags(aClassificationFlags, mIsThirdParty);
 
   bool storageGranted = AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(
       httpChannel, mURI, nullptr);
   mCallback(storageGranted);
   return IPC_OK();
 }
 
 }  // namespace net
--- a/netwerk/protocol/http/TrackingDummyChannelChild.h
+++ b/netwerk/protocol/http/TrackingDummyChannelChild.h
@@ -29,17 +29,17 @@ class TrackingDummyChannelChild final : 
   TrackingDummyChannelChild();
   ~TrackingDummyChannelChild();
 
  private:
   void Initialize(nsIHttpChannel* aChannel, nsIURI* aURI, bool aIsThirdParty,
                   const std::function<void(bool)>& aCallback);
 
   mozilla::ipc::IPCResult Recv__delete__(
-      const bool& aTrackingResource) override;
+      const uint32_t& aClassificationFlags) override;
 
   nsCOMPtr<nsIHttpChannel> mChannel;
   nsCOMPtr<nsIURI> mURI;
   std::function<void(bool)> mCallback;
   bool mIsThirdParty;
 };
 
 }  // namespace net
--- a/netwerk/protocol/http/TrackingDummyChannelParent.cpp
+++ b/netwerk/protocol/http/TrackingDummyChannelParent.cpp
@@ -32,17 +32,17 @@ void TrackingDummyChannelParent::Init(ns
   }
 
   RefPtr<TrackingDummyChannel> channel = new TrackingDummyChannel(
       aURI, aTopWindowURI, aTopWindowURIResult, aLoadInfo);
 
   bool willCallback = NS_SUCCEEDED(AsyncUrlChannelClassifier::CheckChannel(
       channel, [self = std::move(self), channel]() {
         if (self->mIPCActive) {
-          Unused << Send__delete__(self, channel->IsTrackingResource());
+          Unused << Send__delete__(self, channel->ClassificationFlags());
         }
       }));
 
   if (willCallback) {
     onExit.release();
   }
 }
 
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -645,17 +645,17 @@ nsresult nsHttpChannel::Connect() {
     LOG(("Resuming from cache is not supported yet"));
     return NS_ERROR_DOCUMENT_NOT_CACHED;
   }
 
   if (ShouldIntercept()) {
     return RedirectToInterceptedChannel();
   }
 
-  bool isTrackingResource = mIsThirdPartyTrackingResource;  // is atomic
+  bool isTrackingResource = IsThirdPartyTrackingResource();
   LOG(("nsHttpChannel %p tracking resource=%d, cos=%u", this,
        isTrackingResource, mClassOfService));
 
   if (isTrackingResource) {
     AddClassFlags(nsIClassOfService::Tail);
   }
 
   if (WaitingForTailUnblock()) {
@@ -2345,17 +2345,17 @@ nsresult nsHttpChannel::ProcessResponse(
   if (!referrer) {
     referrer = mReferrer;
   }
 
   if (referrer) {
     nsCOMPtr<nsILoadContextInfo> lci = GetLoadContextInfo(this);
     mozilla::net::Predictor::UpdateCacheability(
         referrer, mURI, httpStatus, mRequestHead, mResponseHead, lci,
-        mIsThirdPartyTrackingResource);
+        IsThirdPartyTrackingResource());
   }
 
   // Only allow 407 (authentication required) to continue
   if (mTransaction && mTransaction->ProxyConnectFailed() && httpStatus != 407) {
     return ProcessFailedProxyConnect(httpStatus);
   }
 
   MOZ_ASSERT(!mCachedContentIsValid || mRaceCacheWithNetwork,
@@ -3903,17 +3903,17 @@ nsresult nsHttpChannel::OpenCacheEntryIn
 
   if (mPostID) {
     extension.Append(nsPrintfCString("%d", mPostID));
   }
   if (mTRR) {
     extension.Append("TRR");
   }
 
-  if (mIsThirdPartyTrackingResource &&
+  if (IsThirdPartyTrackingResource() &&
       !AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(this, mURI,
                                                                nullptr)) {
     nsCOMPtr<nsIURI> topWindowURI;
     rv = GetTopWindowURI(getter_AddRefs(topWindowURI));
     bool isDocument = false;
     if (NS_FAILED(rv) && NS_SUCCEEDED(GetIsMainDocumentChannel(&isDocument)) &&
         isDocument) {
       // For top-level documents, use the document channel's origin to compute
--- a/netwerk/protocol/http/nsIHttpChannel.idl
+++ b/netwerk/protocol/http/nsIHttpChannel.idl
@@ -490,33 +490,80 @@ interface nsIHttpChannel : nsIChannel
 
     /**
      * ID of the top-level document's inner window.  Identifies the content
      * this channels is being load in.
      */
     [must_use] attribute uint64_t topLevelContentWindowId;
 
     /**
-     * Returns true if the channel has loaded a resource that is on the tracking
-     * protection list.  This is only available if the
-     * privacy.trackingprotection.annotate_channels pref is set and its value
-     * should only be relied on after the channel has established a connection.
+     * Returns the classification flags if the channel has been processed by
+     * URL-Classifier features and is considered first-party.
+     */
+    [infallible] readonly attribute unsigned long firstPartyClassificationFlags;
+
+    /**
+     * Returns the classification flags if the channel has been processed by
+     * URL-Classifier features and is considered third-party with the top
+     * window URI.
+     */
+    [infallible] readonly attribute unsigned long thirdPartyClassificationFlags;
+
+    /*
+     * Returns the classification flags if the channel has been processed by
+     * URL-Classifier features. This value is equal to
+     * "firstPartyClassificationFlags || thirdPartyClassificationFlags".
+     *
+     * Note that top-level channels could be classified as well.
+     * In order to identify third-party resources specifically, use
+     * classificationThirdPartyFlags;
+     */
+    [infallible] readonly attribute unsigned long classificationFlags;
+
+    cenum ClassificationFlags : 32 {
+      /**
+       * The resource is on the fingerprinting list. This is only available if
+       * the privacy.trackingprotection.fingerprinting_annotate_enabled pref.
+       */
+      CLASSIFIED_FINGERPRINTING = 0x01,
+
+      /**
+       * The resource is on the cryptomining list. This is only available if
+       * the privacy.trackingprotection.cryptomining_annotate_enabled pref is set.
+       */
+      CLASSIFIED_CRYPTOMINING = 0x02,
+
+      /**
+       * The resource is on the tracking protection list. This is only available
+       * if the privacy.trackingprotection.annotate_channels pref.
+       */
+      CLASSIFIED_TRACKING = 0x04,
+    };
+
+    /**
+     * Returns true if the channel has loaded a resource that is classified as
+     * tracker.
+     * This is a helper attribute which returns the same value of
+     * (classificationFlags & CLASSIFIED_TRACKING) ||
+     *   (classificationFlags & CLASSIFIED_FINGERPRINTING)
      *
      * Note that top-level channels could be marked as tracking
      * resource. In order to identify third-party tracking resources
      * specifically, use isThirdPartyTrackingResource.
      */
     [infallible] readonly attribute boolean isTrackingResource;
 
     /**
-     * Returns true if the channel has loaded a resource that is on the tracking
-     * protection list and is considered third-party with the top window URI.
-     * This is only available if the privacy.trackingprotection.annotate_channels
-     * pref is set and its value should only be relied on after the channel has
-     * established a connection.
+     * Returns the classification flags if the channel has been processed by
+     * URL-Classifier features and is considered third-party with the top
+     * window URI.
+     *
+     * This is a helper attribute which returns the same value of
+     * (thirdPartyClassificationFlags & CLASSIFIED_TRACKING) ||
+     *   (thirdPartyClassificationFlags & CLASSIFIED_FINGERPRINTING)
      */
     [infallible] readonly attribute boolean isThirdPartyTrackingResource;
 
     /**
      * Returns the allowing status for flash plugin for this channel.
      */
     cenum FlashPluginState : 8 {
       FlashPluginUnknown = 0,
--- a/netwerk/protocol/viewsource/nsViewSourceChannel.cpp
+++ b/netwerk/protocol/viewsource/nsViewSourceChannel.cpp
@@ -706,31 +706,54 @@ nsViewSourceChannel::SetTopLevelOuterCon
 NS_IMETHODIMP
 nsViewSourceChannel::GetIsTrackingResource(bool *aIsTrackingResource) {
   return !mHttpChannel
              ? NS_ERROR_NULL_POINTER
              : mHttpChannel->GetIsTrackingResource(aIsTrackingResource);
 }
 
 NS_IMETHODIMP
-nsViewSourceChannel::GetFlashPluginState(
-    nsIHttpChannel::FlashPluginState *aResult) {
-  return !mHttpChannel ? NS_ERROR_NULL_POINTER
-                       : mHttpChannel->GetFlashPluginState(aResult);
-}
-
-NS_IMETHODIMP
 nsViewSourceChannel::GetIsThirdPartyTrackingResource(
     bool *aIsTrackingResource) {
   return !mHttpChannel ? NS_ERROR_NULL_POINTER
                        : mHttpChannel->GetIsThirdPartyTrackingResource(
                              aIsTrackingResource);
 }
 
 NS_IMETHODIMP
+nsViewSourceChannel::GetClassificationFlags(uint32_t *aClassificationFlags) {
+  return !mHttpChannel
+             ? NS_ERROR_NULL_POINTER
+             : mHttpChannel->GetClassificationFlags(aClassificationFlags);
+}
+
+NS_IMETHODIMP
+nsViewSourceChannel::GetFirstPartyClassificationFlags(
+    uint32_t *aClassificationFlags) {
+  return !mHttpChannel ? NS_ERROR_NULL_POINTER
+                       : mHttpChannel->GetFirstPartyClassificationFlags(
+                             aClassificationFlags);
+}
+
+NS_IMETHODIMP
+nsViewSourceChannel::GetThirdPartyClassificationFlags(
+    uint32_t *aClassificationFlags) {
+  return !mHttpChannel ? NS_ERROR_NULL_POINTER
+                       : mHttpChannel->GetThirdPartyClassificationFlags(
+                             aClassificationFlags);
+}
+
+NS_IMETHODIMP
+nsViewSourceChannel::GetFlashPluginState(
+    nsIHttpChannel::FlashPluginState *aResult) {
+  return !mHttpChannel ? NS_ERROR_NULL_POINTER
+                       : mHttpChannel->GetFlashPluginState(aResult);
+}
+
+NS_IMETHODIMP
 nsViewSourceChannel::OverrideTrackingFlagsForDocumentCookieAccessor(
     nsIHttpChannel *aDocumentChannel) {
   return !mHttpChannel
              ? NS_ERROR_NULL_POINTER
              : mHttpChannel->OverrideTrackingFlagsForDocumentCookieAccessor(
                    aDocumentChannel);
 }
 
--- a/netwerk/url-classifier/AsyncUrlChannelClassifier.cpp
+++ b/netwerk/url-classifier/AsyncUrlChannelClassifier.cpp
@@ -411,17 +411,18 @@ bool FeatureData::MaybeCompleteClassific
   nsresult rv = mFeature->GetSkipHostList(skipList);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     UC_LOG(
         ("FeatureData::MaybeCompleteClassification[%p] - error. Let's move on",
          this));
     return true;
   }
 
-  if (nsContentUtils::IsURIInList(mBlacklistTables[0]->URI(), skipList)) {
+  if (!mBlacklistTables.IsEmpty() &&
+      nsContentUtils::IsURIInList(mBlacklistTables[0]->URI(), skipList)) {
     UC_LOG(
         ("FeatureData::MaybeCompleteClassification[%p] - uri found in skiplist",
          this));
     return true;
   }
 
   nsAutoCString list;
   list.Assign(mHostInPrefTables[nsIUrlClassifierFeature::blacklist]);
--- a/netwerk/url-classifier/UrlClassifierCommon.cpp
+++ b/netwerk/url-classifier/UrlClassifierCommon.cpp
@@ -3,30 +3,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 "mozilla/net/UrlClassifierCommon.h"
 
 #include "mozilla/AntiTrackingCommon.h"
 #include "mozilla/BasePrincipal.h"
+#include "mozilla/net/HttpBaseChannel.h"
 #include "mozilla/net/UrlClassifierFeatureFactory.h"
 #include "mozilla/StaticPrefs.h"
 #include "mozIThirdPartyUtil.h"
 #include "nsContentUtils.h"
 #include "nsIChannel.h"
 #include "nsIClassifiedChannel.h"
 #include "mozilla/dom/Document.h"
 #include "nsIDocShell.h"
 #include "nsIHttpChannel.h"
 #include "nsIHttpChannelInternal.h"
 #include "nsIParentChannel.h"
 #include "nsIScriptError.h"
 #include "nsIWebProgressListener.h"
 #include "nsNetUtil.h"
+#include "nsQueryObject.h"
+#include "TrackingDummyChannel.h"
 
 namespace mozilla {
 namespace net {
 
 const nsCString::size_type UrlClassifierCommon::sMaxSpecLength = 128;
 
 // MOZ_LOG=nsChannelClassifier:5
 LazyLogModule UrlClassifierCommon::sLog("nsChannelClassifier");
@@ -270,10 +273,193 @@ nsresult UrlClassifierCommon::CreatePair
   nsCOMPtr<nsIURI> whitelistURI;
   rv = NS_NewURI(getter_AddRefs(whitelistURI), whitelistEntry);
   NS_ENSURE_SUCCESS(rv, rv);
 
   whitelistURI.forget(aURI);
   return NS_OK;
 }
 
+namespace {
+
+void SetClassificationFlagsHelper(nsIChannel* aChannel,
+                                  uint32_t aClassificationFlags,
+                                  bool aIsThirdParty) {
+  MOZ_ASSERT(aChannel);
+
+  nsCOMPtr<nsIParentChannel> parentChannel;
+  NS_QueryNotificationCallbacks(aChannel, parentChannel);
+  if (parentChannel) {
+    // This channel is a parent-process proxy for a child process
+    // request. We should notify the child process as well.
+    parentChannel->NotifyClassificationFlags(aClassificationFlags,
+                                             aIsThirdParty);
+  }
+
+  RefPtr<HttpBaseChannel> httpChannel = do_QueryObject(aChannel);
+  if (httpChannel) {
+    httpChannel->AddClassificationFlags(aClassificationFlags, aIsThirdParty);
+  }
+
+  RefPtr<TrackingDummyChannel> dummyChannel = do_QueryObject(aChannel);
+  if (dummyChannel) {
+    dummyChannel->AddClassificationFlags(aClassificationFlags);
+  }
+}
+
+void LowerPriorityHelper(nsIChannel* aChannel) {
+  MOZ_ASSERT(aChannel);
+
+  bool isBlockingResource = false;
+
+  nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(aChannel));
+  if (cos) {
+    if (nsContentUtils::IsTailingEnabled()) {
+      uint32_t cosFlags = 0;
+      cos->GetClassFlags(&cosFlags);
+      isBlockingResource =
+          cosFlags & (nsIClassOfService::UrgentStart |
+                      nsIClassOfService::Leader | nsIClassOfService::Unblocked);
+
+      // Requests not allowed to be tailed are usually those with higher
+      // prioritization.  That overweights being a tracker: don't throttle
+      // them when not in background.
+      if (!(cosFlags & nsIClassOfService::TailForbidden)) {
+        cos->AddClassFlags(nsIClassOfService::Throttleable);
+      }
+    } else {
+      // Yes, we even don't want to evaluate the isBlockingResource when tailing
+      // is off see bug 1395525.
+
+      cos->AddClassFlags(nsIClassOfService::Throttleable);
+    }
+  }
+
+  if (!isBlockingResource) {
+    nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(aChannel);
+    if (p) {
+      if (UC_LOG_ENABLED()) {
+        nsCOMPtr<nsIURI> uri;
+        aChannel->GetURI(getter_AddRefs(uri));
+        nsAutoCString spec;
+        uri->GetAsciiSpec(spec);
+        spec.Truncate(
+            std::min(spec.Length(), UrlClassifierCommon::sMaxSpecLength));
+        UC_LOG(("Setting PRIORITY_LOWEST for channel[%p] (%s)", aChannel,
+                spec.get()));
+      }
+      p->SetPriority(nsISupportsPriority::PRIORITY_LOWEST);
+    }
+  }
+}
+
+}  // namespace
+
+// static
+void UrlClassifierCommon::AnnotateChannel(
+    nsIChannel* aChannel,
+    AntiTrackingCommon::ContentBlockingAllowListPurpose aPurpose,
+    uint32_t aClassificationFlags, uint32_t aLoadingState) {
+  MOZ_ASSERT(aChannel);
+  MOZ_ASSERT(aPurpose == AntiTrackingCommon::eTrackingProtection ||
+             aPurpose == AntiTrackingCommon::eTrackingAnnotations ||
+             aPurpose == AntiTrackingCommon::eFingerprinting ||
+             aPurpose == AntiTrackingCommon::eCryptomining);
+
+  nsCOMPtr<nsIURI> chanURI;
+  nsresult rv = aChannel->GetURI(getter_AddRefs(chanURI));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    UC_LOG(
+        ("UrlClassifierCommon::AnnotateChannel nsIChannel::GetURI(%p) failed",
+         (void*)aChannel));
+    return;
+  }
+
+  bool isThirdPartyWithTopLevelWinURI =
+      nsContentUtils::IsThirdPartyWindowOrChannel(nullptr, aChannel, chanURI);
+
+  UC_LOG(("UrlClassifierCommon::AnnotateChannel, annotating channel[%p]",
+          aChannel));
+
+  SetClassificationFlagsHelper(aChannel, aClassificationFlags,
+                               isThirdPartyWithTopLevelWinURI);
+
+  if (isThirdPartyWithTopLevelWinURI || IsAllowListed(aChannel, aPurpose)) {
+    UrlClassifierCommon::NotifyChannelClassifierProtectionDisabled(
+        aChannel, aLoadingState);
+  }
+
+  if (isThirdPartyWithTopLevelWinURI &&
+      StaticPrefs::privacy_trackingprotection_lower_network_priority()) {
+    LowerPriorityHelper(aChannel);
+  }
+}
+
+// static
+bool UrlClassifierCommon::IsAllowListed(
+    nsIChannel* aChannel,
+    AntiTrackingCommon::ContentBlockingAllowListPurpose aPurpose) {
+  MOZ_ASSERT(aPurpose == AntiTrackingCommon::eTrackingProtection ||
+             aPurpose == AntiTrackingCommon::eTrackingAnnotations ||
+             aPurpose == AntiTrackingCommon::eFingerprinting ||
+             aPurpose == AntiTrackingCommon::eCryptomining);
+
+  nsCOMPtr<nsIHttpChannelInternal> channel = do_QueryInterface(aChannel);
+  if (!channel) {
+    UC_LOG(("nsChannelClassifier: Not an HTTP channel"));
+    return false;
+  }
+
+  nsCOMPtr<nsIURI> topWinURI;
+  nsresult rv = channel->GetTopWindowURI(getter_AddRefs(topWinURI));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return false;
+  }
+
+  if (!topWinURI && StaticPrefs::channelclassifier_allowlist_example()) {
+    UC_LOG(("nsChannelClassifier: Allowlisting test domain"));
+    nsCOMPtr<nsIIOService> ios = services::GetIOService();
+    if (NS_WARN_IF(!ios)) {
+      return false;
+    }
+
+    rv = ios->NewURI(NS_LITERAL_CSTRING("http://allowlisted.example.com"),
+                     nullptr, nullptr, getter_AddRefs(topWinURI));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return false;
+    }
+  }
+
+  bool isAllowListed = false;
+  rv = AntiTrackingCommon::IsOnContentBlockingAllowList(
+      topWinURI, NS_UsePrivateBrowsing(aChannel), aPurpose, isAllowListed);
+  if (NS_FAILED(rv)) {  // normal for some loads, no need to print a warning
+    return false;
+  }
+
+  if (isAllowListed) {
+    if (UC_LOG_ENABLED()) {
+      nsCOMPtr<nsIURI> chanURI;
+      nsresult rv = aChannel->GetURI(getter_AddRefs(chanURI));
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return isAllowListed;
+      }
+
+      nsCString chanSpec = chanURI->GetSpecOrDefault();
+      chanSpec.Truncate(
+          std::min(chanSpec.Length(), UrlClassifierCommon::sMaxSpecLength));
+      UC_LOG(("nsChannelClassifier: User override on channel[%p] (%s)",
+              aChannel, chanSpec.get()));
+    }
+  }
+
+  return isAllowListed;
+}
+
+// static
+bool UrlClassifierCommon::IsTrackingClassificationFlag(uint32_t aFlag) {
+  return (aFlag & nsIHttpChannel::ClassificationFlags::CLASSIFIED_TRACKING) ||
+         (aFlag &
+          nsIHttpChannel::ClassificationFlags::CLASSIFIED_FINGERPRINTING);
+}
+
 }  // namespace net
 }  // namespace mozilla
--- a/netwerk/url-classifier/UrlClassifierCommon.h
+++ b/netwerk/url-classifier/UrlClassifierCommon.h
@@ -37,16 +37,27 @@ class UrlClassifierCommon final {
                                     const nsACString& aProvider,
                                     const nsACString& aFullHash);
 
   // Use this function only when you are looking for a pairwise whitelist uri
   // with the format: http://toplevel.page/?resource=channel.uri.domain
   static nsresult CreatePairwiseWhiteListURI(nsIChannel* aChannel,
                                              nsIURI** aURI);
 
+  static void AnnotateChannel(
+      nsIChannel* aChannel,
+      AntiTrackingCommon::ContentBlockingAllowListPurpose aPurpose,
+      uint32_t aClassificationFlags, uint32_t aLoadingState);
+
+  static bool IsAllowListed(
+      nsIChannel* aChannel,
+      AntiTrackingCommon::ContentBlockingAllowListPurpose aPurpose);
+
+  static bool IsTrackingClassificationFlag(uint32_t aFlag);
+
  private:
   // aBlockedReason must be one of the nsIWebProgressListener state.
   static void NotifyChannelBlocked(nsIChannel* aChannel,
                                    nsIURI* aURIBeingLoaded,
                                    unsigned aBlockedReason);
 };
 
 }  // namespace net
--- a/netwerk/url-classifier/UrlClassifierFeatureBase.cpp
+++ b/netwerk/url-classifier/UrlClassifierFeatureBase.cpp
@@ -159,70 +159,10 @@ UrlClassifierFeatureBase::HasHostInPrefe
 }
 
 NS_IMETHODIMP
 UrlClassifierFeatureBase::GetSkipHostList(nsACString& aList) {
   aList = mSkipHosts;
   return NS_OK;
 }
 
-bool UrlClassifierFeatureBase::IsAllowListed(
-    nsIChannel* aChannel,
-    AntiTrackingCommon::ContentBlockingAllowListPurpose aPurpose) {
-  MOZ_ASSERT(aPurpose == AntiTrackingCommon::eTrackingProtection ||
-             aPurpose == AntiTrackingCommon::eTrackingAnnotations ||
-             aPurpose == AntiTrackingCommon::eFingerprinting ||
-             aPurpose == AntiTrackingCommon::eCryptomining);
-
-  nsCOMPtr<nsIHttpChannelInternal> channel = do_QueryInterface(aChannel);
-  if (!channel) {
-    UC_LOG(("nsChannelClassifier: Not an HTTP channel"));
-    return false;
-  }
-
-  nsCOMPtr<nsIURI> topWinURI;
-  nsresult rv = channel->GetTopWindowURI(getter_AddRefs(topWinURI));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return false;
-  }
-
-  if (!topWinURI && StaticPrefs::channelclassifier_allowlist_example()) {
-    UC_LOG(("nsChannelClassifier: Allowlisting test domain"));
-    nsCOMPtr<nsIIOService> ios = services::GetIOService();
-    if (NS_WARN_IF(!ios)) {
-      return false;
-    }
-
-    rv = ios->NewURI(NS_LITERAL_CSTRING("http://allowlisted.example.com"),
-                     nullptr, nullptr, getter_AddRefs(topWinURI));
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return false;
-    }
-  }
-
-  bool isAllowListed = false;
-  rv = AntiTrackingCommon::IsOnContentBlockingAllowList(
-      topWinURI, NS_UsePrivateBrowsing(aChannel), aPurpose, isAllowListed);
-  if (NS_FAILED(rv)) {  // normal for some loads, no need to print a warning
-    return false;
-  }
-
-  if (isAllowListed) {
-    if (UC_LOG_ENABLED()) {
-      nsCOMPtr<nsIURI> chanURI;
-      nsresult rv = aChannel->GetURI(getter_AddRefs(chanURI));
-      if (NS_WARN_IF(NS_FAILED(rv))) {
-        return isAllowListed;
-      }
-
-      nsCString chanSpec = chanURI->GetSpecOrDefault();
-      chanSpec.Truncate(
-          std::min(chanSpec.Length(), UrlClassifierCommon::sMaxSpecLength));
-      UC_LOG(("nsChannelClassifier: User override on channel[%p] (%s)",
-              aChannel, chanSpec.get()));
-    }
-  }
-
-  return isAllowListed;
-}
-
 }  // namespace net
 }  // namespace mozilla
--- a/netwerk/url-classifier/UrlClassifierFeatureBase.h
+++ b/netwerk/url-classifier/UrlClassifierFeatureBase.h
@@ -53,20 +53,16 @@ class UrlClassifierFeatureBase : public 
                            const nsACString& aPrefWhitelistTableName,
                            const nsACString& aPrefSkipHosts);
 
   virtual ~UrlClassifierFeatureBase();
 
   void InitializePreferences();
   void ShutdownPreferences();
 
-  bool IsAllowListed(
-      nsIChannel* aChannel,
-      AntiTrackingCommon::ContentBlockingAllowListPurpose aPurpose);
-
  private:
   nsCString mName;
 
   nsCString mPrefSkipHosts;
 
   // 2: blacklist and whitelist.
   nsCString mPrefTables[2];
   nsTArray<nsCString> mTables[2];
new file mode 100644
--- /dev/null
+++ b/netwerk/url-classifier/UrlClassifierFeatureCryptominingAnnotation.cpp
@@ -0,0 +1,158 @@
+/* -*- 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 "UrlClassifierFeatureCryptominingAnnotation.h"
+
+#include "mozilla/AntiTrackingCommon.h"
+#include "mozilla/net/UrlClassifierCommon.h"
+#include "mozilla/StaticPrefs.h"
+#include "nsContentUtils.h"
+#include "nsNetUtil.h"
+
+namespace mozilla {
+namespace net {
+
+namespace {
+
+#define CRYPTOMINING_ANNOTATION_FEATURE_NAME "cryptomining-annotation"
+
+#define URLCLASSIFIER_CRYPTOMINING_ANNOTATION_BLACKLIST \
+  "urlclassifier.features.cryptomining.annotate.blacklistTables"
+#define URLCLASSIFIER_CRYPTOMINING_ANNOTATION_BLACKLIST_TEST_ENTRIES \
+  "urlclassifier.features.cryptomining.annotate.blacklistHosts"
+#define URLCLASSIFIER_CRYPTOMINING_ANNOTATION_WHITELIST \
+  "urlclassifier.features.cryptomining.annotate.whitelistTables"
+#define URLCLASSIFIER_CRYPTOMINING_ANNOTATION_WHITELIST_TEST_ENTRIES \
+  "urlclassifier.features.cryptomining.annotate.whitelistHosts"
+#define TABLE_CRYPTOMINING_ANNOTATION_BLACKLIST_PREF \
+  "cryptomining-annotate-blacklist-pref"
+#define TABLE_CRYPTOMINING_ANNOTATION_WHITELIST_PREF \
+  "cryptomining-annotate-whitelist-pref"
+
+StaticRefPtr<UrlClassifierFeatureCryptominingAnnotation>
+    gFeatureCryptominingAnnotation;
+
+}  // namespace
+
+UrlClassifierFeatureCryptominingAnnotation::
+    UrlClassifierFeatureCryptominingAnnotation()
+    : UrlClassifierFeatureBase(
+          NS_LITERAL_CSTRING(CRYPTOMINING_ANNOTATION_FEATURE_NAME),
+          NS_LITERAL_CSTRING(URLCLASSIFIER_CRYPTOMINING_ANNOTATION_BLACKLIST),
+          NS_LITERAL_CSTRING(URLCLASSIFIER_CRYPTOMINING_ANNOTATION_WHITELIST),
+          NS_LITERAL_CSTRING(
+              URLCLASSIFIER_CRYPTOMINING_ANNOTATION_BLACKLIST_TEST_ENTRIES),
+          NS_LITERAL_CSTRING(
+              URLCLASSIFIER_CRYPTOMINING_ANNOTATION_WHITELIST_TEST_ENTRIES),
+          NS_LITERAL_CSTRING(TABLE_CRYPTOMINING_ANNOTATION_BLACKLIST_PREF),
+          NS_LITERAL_CSTRING(TABLE_CRYPTOMINING_ANNOTATION_WHITELIST_PREF),
+          EmptyCString()) {}
+
+/* static */ const char* UrlClassifierFeatureCryptominingAnnotation::Name() {
+  return CRYPTOMINING_ANNOTATION_FEATURE_NAME;
+}
+
+/* static */
+void UrlClassifierFeatureCryptominingAnnotation::MaybeInitialize() {
+  UC_LOG(("UrlClassifierFeatureCryptominingAnnotation: MaybeInitialize"));
+
+  if (!gFeatureCryptominingAnnotation) {
+    gFeatureCryptominingAnnotation =
+        new UrlClassifierFeatureCryptominingAnnotation();
+    gFeatureCryptominingAnnotation->InitializePreferences();
+  }
+}
+
+/* static */
+void UrlClassifierFeatureCryptominingAnnotation::MaybeShutdown() {
+  UC_LOG(("UrlClassifierFeatureCryptominingAnnotation: MaybeShutdown"));
+
+  if (gFeatureCryptominingAnnotation) {
+    gFeatureCryptominingAnnotation->ShutdownPreferences();
+    gFeatureCryptominingAnnotation = nullptr;
+  }
+}
+
+/* static */
+already_AddRefed<UrlClassifierFeatureCryptominingAnnotation>
+UrlClassifierFeatureCryptominingAnnotation::MaybeCreate(nsIChannel* aChannel) {
+  MOZ_ASSERT(aChannel);
+
+  UC_LOG(
+      ("UrlClassifierFeatureCryptominingAnnotation: MaybeCreate for channel %p",
+       aChannel));
+
+  if (!StaticPrefs::
+          privacy_trackingprotection_cryptomining_annotate_enabled()) {
+    return nullptr;
+  }
+
+  if (!UrlClassifierCommon::ShouldEnableClassifier(aChannel)) {
+    return nullptr;
+  }
+
+  MaybeInitialize();
+  MOZ_ASSERT(gFeatureCryptominingAnnotation);
+
+  RefPtr<UrlClassifierFeatureCryptominingAnnotation> self =
+      gFeatureCryptominingAnnotation;
+  return self.forget();
+}
+
+/* static */
+already_AddRefed<nsIUrlClassifierFeature>
+UrlClassifierFeatureCryptominingAnnotation::GetIfNameMatches(
+    const nsACString& aName) {
+  if (!aName.EqualsLiteral(CRYPTOMINING_ANNOTATION_FEATURE_NAME)) {
+    return nullptr;
+  }
+
+  MaybeInitialize();
+  MOZ_ASSERT(gFeatureCryptominingAnnotation);
+
+  RefPtr<UrlClassifierFeatureCryptominingAnnotation> self =
+      gFeatureCryptominingAnnotation;
+  return self.forget();
+}
+
+NS_IMETHODIMP
+UrlClassifierFeatureCryptominingAnnotation::ProcessChannel(
+    nsIChannel* aChannel, const nsACString& aList, bool* aShouldContinue) {
+  NS_ENSURE_ARG_POINTER(aChannel);
+  NS_ENSURE_ARG_POINTER(aShouldContinue);
+
+  // This is not a blocking feature.
+  *aShouldContinue = true;
+
+  UC_LOG(
+      ("UrlClassifierFeatureCryptominingAnnotation::ProcessChannel, annotating "
+       "channel[%p]",
+       aChannel));
+
+  UrlClassifierCommon::AnnotateChannel(
+      aChannel, AntiTrackingCommon::eCryptomining,
+      nsIHttpChannel::ClassificationFlags::CLASSIFIED_CRYPTOMINING,
+      nsIWebProgressListener::STATE_LOADED_CRYPTOMINING_CONTENT);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+UrlClassifierFeatureCryptominingAnnotation::GetURIByListType(
+    nsIChannel* aChannel, nsIUrlClassifierFeature::listType aListType,
+    nsIURI** aURI) {
+  NS_ENSURE_ARG_POINTER(aChannel);
+  NS_ENSURE_ARG_POINTER(aURI);
+
+  if (aListType == nsIUrlClassifierFeature::blacklist) {
+    return aChannel->GetURI(aURI);
+  }
+
+  MOZ_ASSERT(aListType == nsIUrlClassifierFeature::whitelist);
+  return UrlClassifierCommon::CreatePairwiseWhiteListURI(aChannel, aURI);
+}
+
+}  // namespace net
+}  // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/netwerk/url-classifier/UrlClassifierFeatureCryptominingAnnotation.h
@@ -0,0 +1,46 @@
+/* -*- 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_net_UrlClassifierFeatureCryptominingAnnotation_h
+#define mozilla_net_UrlClassifierFeatureCryptominingAnnotation_h
+
+#include "UrlClassifierFeatureBase.h"
+
+class nsIChannel;
+
+namespace mozilla {
+namespace net {
+
+class UrlClassifierFeatureCryptominingAnnotation final
+    : public UrlClassifierFeatureBase {
+ public:
+  static const char* Name();
+
+  static void MaybeShutdown();
+
+  static already_AddRefed<UrlClassifierFeatureCryptominingAnnotation>
+  MaybeCreate(nsIChannel* aChannel);
+
+  static already_AddRefed<nsIUrlClassifierFeature> GetIfNameMatches(
+      const nsACString& aName);
+
+  NS_IMETHOD ProcessChannel(nsIChannel* aChannel, const nsACString& aList,
+                            bool* aShouldContinue) override;
+
+  NS_IMETHOD GetURIByListType(nsIChannel* aChannel,
+                              nsIUrlClassifierFeature::listType aListType,
+                              nsIURI** aURI) override;
+
+ private:
+  UrlClassifierFeatureCryptominingAnnotation();
+
+  static void MaybeInitialize();
+};
+
+}  // namespace net
+}  // namespace mozilla
+
+#endif  // mozilla_net_UrlClassifierFeatureCryptominingAnnotation_h
--- a/netwerk/url-classifier/UrlClassifierFeatureCryptominingProtection.cpp
+++ b/netwerk/url-classifier/UrlClassifierFeatureCryptominingProtection.cpp
@@ -12,17 +12,17 @@
 #include "nsContentUtils.h"
 #include "nsNetUtil.h"
 
 namespace mozilla {
 namespace net {
 
 namespace {
 
-#define CRYPTOMINING_FEATURE_NAME "cryptomining"
+#define CRYPTOMINING_FEATURE_NAME "cryptomining-protection"
 
 #define URLCLASSIFIER_CRYPTOMINING_BLACKLIST \
   "urlclassifier.features.cryptomining.blacklistTables"
 #define URLCLASSIFIER_CRYPTOMINING_BLACKLIST_TEST_ENTRIES \
   "urlclassifier.features.cryptomining.blacklistHosts"
 #define URLCLASSIFIER_CRYPTOMINING_WHITELIST \
   "urlclassifier.features.cryptomining.whitelistTables"
 #define URLCLASSIFIER_CRYPTOMINING_WHITELIST_TEST_ENTRIES \
@@ -138,48 +138,40 @@ UrlClassifierFeatureCryptominingProtecti
 }
 
 NS_IMETHODIMP
 UrlClassifierFeatureCryptominingProtection::ProcessChannel(
     nsIChannel* aChannel, const nsACString& aList, bool* aShouldContinue) {
   NS_ENSURE_ARG_POINTER(aChannel);
   NS_ENSURE_ARG_POINTER(aShouldContinue);
 
-  bool isAllowListed =
-      IsAllowListed(aChannel, AntiTrackingCommon::eCryptomining);
+  bool isAllowListed = UrlClassifierCommon::IsAllowListed(
+      aChannel, AntiTrackingCommon::eCryptomining);
 
   // This is a blocking feature.
   *aShouldContinue = isAllowListed;
 
   if (isAllowListed) {
-    // Even with cryptomining blocking disabled, we still want to show the user
-    // that there are unblocked cryptominers on the site, so notify the UI that
-    // we loaded cryptomining content.  UI code can treat this notification
-    // differently depending on whether cryptomining blocking is enabled or
-    // disabled.
-    UrlClassifierCommon::NotifyChannelClassifierProtectionDisabled(
-        aChannel, nsIWebProgressListener::STATE_LOADED_CRYPTOMINING_CONTENT);
-  } else {
-    UrlClassifierCommon::SetBlockedContent(aChannel, NS_ERROR_CRYPTOMINING_URI,
-                                           aList, EmptyCString(),
-                                           EmptyCString());
+    return NS_OK;
+  }
+
+  UrlClassifierCommon::SetBlockedContent(aChannel, NS_ERROR_CRYPTOMINING_URI,
+                                         aList, EmptyCString(), EmptyCString());
 
-    UC_LOG(
-        ("UrlClassifierFeatureCryptominingProtection::ProcessChannel, "
-         "cancelling "
-         "channel[%p]",
-         aChannel));
-    nsCOMPtr<nsIHttpChannelInternal> httpChannel = do_QueryInterface(aChannel);
+  UC_LOG(
+      ("UrlClassifierFeatureCryptominingProtection::ProcessChannel, "
+       "cancelling "
+       "channel[%p]",
+       aChannel));
+  nsCOMPtr<nsIHttpChannelInternal> httpChannel = do_QueryInterface(aChannel);
 
-    if (httpChannel) {
-      Unused << httpChannel->CancelByChannelClassifier(
-          NS_ERROR_CRYPTOMINING_URI);
-    } else {
-      Unused << aChannel->Cancel(NS_ERROR_CRYPTOMINING_URI);
-    }
+  if (httpChannel) {
+    Unused << httpChannel->CancelByChannelClassifier(NS_ERROR_CRYPTOMINING_URI);
+  } else {
+    Unused << aChannel->Cancel(NS_ERROR_CRYPTOMINING_URI);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 UrlClassifierFeatureCryptominingProtection::GetURIByListType(
     nsIChannel* aChannel, nsIUrlClassifierFeature::listType aListType,
--- a/netwerk/url-classifier/UrlClassifierFeatureFactory.cpp
+++ b/netwerk/url-classifier/UrlClassifierFeatureFactory.cpp
@@ -2,17 +2,19 @@
 /* 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/net/UrlClassifierFeatureFactory.h"
 
 // List of Features
+#include "UrlClassifierFeatureCryptominingAnnotation.h"
 #include "UrlClassifierFeatureCryptominingProtection.h"
+#include "UrlClassifierFeatureFingerprintingAnnotation.h"
 #include "UrlClassifierFeatureFingerprintingProtection.h"
 #include "UrlClassifierFeatureFlash.h"
 #include "UrlClassifierFeatureLoginReputation.h"
 #include "UrlClassifierFeaturePhishingProtection.h"
 #include "UrlClassifierFeatureTrackingProtection.h"
 #include "UrlClassifierFeatureTrackingAnnotation.h"
 #include "UrlClassifierFeatureCustomTables.h"
 
@@ -23,17 +25,19 @@ namespace net {
 
 /* static */
 void UrlClassifierFeatureFactory::Shutdown() {
   // We want to expose Features only in the parent process.
   if (!XRE_IsParentProcess()) {
     return;
   }
 
+  UrlClassifierFeatureCryptominingAnnotation::MaybeShutdown();
   UrlClassifierFeatureCryptominingProtection::MaybeShutdown();
+  UrlClassifierFeatureFingerprintingAnnotation::MaybeShutdown();
   UrlClassifierFeatureFingerprintingProtection::MaybeShutdown();
   UrlClassifierFeatureFlash::MaybeShutdown();
   UrlClassifierFeatureLoginReputation::MaybeShutdown();
   UrlClassifierFeaturePhishingProtection::MaybeShutdown();
   UrlClassifierFeatureTrackingAnnotation::MaybeShutdown();
   UrlClassifierFeatureTrackingProtection::MaybeShutdown();
 }
 
@@ -64,16 +68,28 @@ void UrlClassifierFeatureFactory::GetFea
   }
 
   // Tracking Protection
   feature = UrlClassifierFeatureTrackingProtection::MaybeCreate(aChannel);
   if (feature) {
     aFeatures.AppendElement(feature);
   }
 
+  // Cryptomining Annotation
+  feature = UrlClassifierFeatureCryptominingAnnotation::MaybeCreate(aChannel);
+  if (feature) {
+    aFeatures.AppendElement(feature);
+  }
+
+  // Fingerprinting Annotation
+  feature = UrlClassifierFeatureFingerprintingAnnotation::MaybeCreate(aChannel);
+  if (feature) {
+    aFeatures.AppendElement(feature);
+  }
+
   // Tracking Annotation
   feature = UrlClassifierFeatureTrackingAnnotation::MaybeCreate(aChannel);
   if (feature) {
     aFeatures.AppendElement(feature);
   }
 
   // Flash
   nsTArray<nsCOMPtr<nsIUrlClassifierFeature>> flashFeatures;
@@ -97,22 +113,35 @@ UrlClassifierFeatureFactory::GetFeatureL
 already_AddRefed<nsIUrlClassifierFeature>
 UrlClassifierFeatureFactory::GetFeatureByName(const nsACString& aName) {
   if (!XRE_IsParentProcess()) {
     return nullptr;
   }
 
   nsCOMPtr<nsIUrlClassifierFeature> feature;
 
+  // Cryptomining Annotation
+  feature = UrlClassifierFeatureCryptominingAnnotation::GetIfNameMatches(aName);
+  if (feature) {
+    return feature.forget();
+  }
+
   // Cryptomining Protection
   feature = UrlClassifierFeatureCryptominingProtection::GetIfNameMatches(aName);
   if (feature) {
     return feature.forget();
   }
 
+  // Fingerprinting Annotation
+  feature =
+      UrlClassifierFeatureFingerprintingAnnotation::GetIfNameMatches(aName);
+  if (feature) {
+    return feature.forget();
+  }
+
   // Fingerprinting Protection
   feature =
       UrlClassifierFeatureFingerprintingProtection::GetIfNameMatches(aName);
   if (feature) {
     return feature.forget();
   }
 
   // Tracking Protection
@@ -149,23 +178,36 @@ UrlClassifierFeatureFactory::GetFeatureB
 }
 
 /* static */
 void UrlClassifierFeatureFactory::GetFeatureNames(nsTArray<nsCString>& aArray) {
   if (!XRE_IsParentProcess()) {
     return;
   }
 
+  nsAutoCString name;
+
+  // Cryptomining Annotation
+  name.Assign(UrlClassifierFeatureCryptominingAnnotation::Name());
+  if (!name.IsEmpty()) {
+    aArray.AppendElement(name);
+  }
+
   // Cryptomining Protection
-  nsAutoCString name;
   name.Assign(UrlClassifierFeatureCryptominingProtection::Name());
   if (!name.IsEmpty()) {
     aArray.AppendElement(name);
   }
 
+  // Fingerprinting Annotation
+  name.Assign(UrlClassifierFeatureFingerprintingAnnotation::Name());
+  if (!name.IsEmpty()) {
+    aArray.AppendElement(name);
+  }
+
   // Fingerprinting Protection
   name.Assign(UrlClassifierFeatureFingerprintingProtection::Name());
   if (!name.IsEmpty()) {
     aArray.AppendElement(name);
   }
 
   // Tracking Protection
   name.Assign(UrlClassifierFeatureTrackingProtection::Name());
new file mode 100644
--- /dev/null
+++ b/netwerk/url-classifier/UrlClassifierFeatureFingerprintingAnnotation.cpp
@@ -0,0 +1,160 @@
+/* -*- 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 "UrlClassifierFeatureFingerprintingAnnotation.h"
+
+#include "mozilla/AntiTrackingCommon.h"
+#include "mozilla/net/UrlClassifierCommon.h"
+#include "mozilla/StaticPrefs.h"
+#include "nsContentUtils.h"
+#include "nsNetUtil.h"
+
+namespace mozilla {
+namespace net {
+
+namespace {
+
+#define FINGERPRINTING_ANNOTATION_FEATURE_NAME "fingerprinting-annotation"
+
+#define URLCLASSIFIER_FINGERPRINTING_ANNOTATION_BLACKLIST \
+  "urlclassifier.features.fingerprinting.annotate.blacklistTables"
+#define URLCLASSIFIER_FINGERPRINTING_ANNOTATION_BLACKLIST_TEST_ENTRIES \
+  "urlclassifier.features.fingerprinting.annotate.blacklistHosts"
+#define URLCLASSIFIER_FINGERPRINTING_ANNOTATION_WHITELIST \
+  "urlclassifier.features.fingerprinting.annotate.whitelistTables"
+#define URLCLASSIFIER_FINGERPRINTING_ANNOTATION_WHITELIST_TEST_ENTRIES \
+  "urlclassifier.features.fingerprinting.annotate.whitelistHosts"
+#define TABLE_FINGERPRINTING_ANNOTATION_BLACKLIST_PREF \
+  "fingerprinting-annotate-blacklist-pref"
+#define TABLE_FINGERPRINTING_ANNOTATION_WHITELIST_PREF \
+  "fingerprinting-annotate-whitelist-pref"
+
+StaticRefPtr<UrlClassifierFeatureFingerprintingAnnotation>
+    gFeatureFingerprintingAnnotation;
+
+}  // namespace
+
+UrlClassifierFeatureFingerprintingAnnotation::
+    UrlClassifierFeatureFingerprintingAnnotation()
+    : UrlClassifierFeatureBase(
+          NS_LITERAL_CSTRING(FINGERPRINTING_ANNOTATION_FEATURE_NAME),
+          NS_LITERAL_CSTRING(URLCLASSIFIER_FINGERPRINTING_ANNOTATION_BLACKLIST),
+          NS_LITERAL_CSTRING(URLCLASSIFIER_FINGERPRINTING_ANNOTATION_WHITELIST),
+          NS_LITERAL_CSTRING(
+              URLCLASSIFIER_FINGERPRINTING_ANNOTATION_BLACKLIST_TEST_ENTRIES),
+          NS_LITERAL_CSTRING(
+              URLCLASSIFIER_FINGERPRINTING_ANNOTATION_WHITELIST_TEST_ENTRIES),
+          NS_LITERAL_CSTRING(TABLE_FINGERPRINTING_ANNOTATION_BLACKLIST_PREF),
+          NS_LITERAL_CSTRING(TABLE_FINGERPRINTING_ANNOTATION_WHITELIST_PREF),
+          EmptyCString()) {}
+
+/* static */ const char* UrlClassifierFeatureFingerprintingAnnotation::Name() {
+  return FINGERPRINTING_ANNOTATION_FEATURE_NAME;
+}
+
+/* static */
+void UrlClassifierFeatureFingerprintingAnnotation::MaybeInitialize() {
+  UC_LOG(("UrlClassifierFeatureFingerprintingAnnotation: MaybeInitialize"));
+
+  if (!gFeatureFingerprintingAnnotation) {
+    gFeatureFingerprintingAnnotation =
+        new UrlClassifierFeatureFingerprintingAnnotation();
+    gFeatureFingerprintingAnnotation->InitializePreferences();
+  }
+}
+
+/* static */
+void UrlClassifierFeatureFingerprintingAnnotation::MaybeShutdown() {
+  UC_LOG(("UrlClassifierFeatureFingerprintingAnnotation: MaybeShutdown"));
+
+  if (gFeatureFingerprintingAnnotation) {
+    gFeatureFingerprintingAnnotation->ShutdownPreferences();
+    gFeatureFingerprintingAnnotation = nullptr;
+  }
+}
+
+/* static */
+already_AddRefed<UrlClassifierFeatureFingerprintingAnnotation>
+UrlClassifierFeatureFingerprintingAnnotation::MaybeCreate(
+    nsIChannel* aChannel) {
+  MOZ_ASSERT(aChannel);
+
+  UC_LOG(
+      ("UrlClassifierFeatureFingerprintingAnnotation: MaybeCreate for channel "
+       "%p",
+       aChannel));
+
+  if (!StaticPrefs::
+          privacy_trackingprotection_fingerprinting_annotate_enabled()) {
+    return nullptr;
+  }
+
+  if (!UrlClassifierCommon::ShouldEnableClassifier(aChannel)) {
+    return nullptr;
+  }
+
+  MaybeInitialize();
+  MOZ_ASSERT(gFeatureFingerprintingAnnotation);
+
+  RefPtr<UrlClassifierFeatureFingerprintingAnnotation> self =
+      gFeatureFingerprintingAnnotation;
+  return self.forget();
+}
+
+/* static */
+already_AddRefed<nsIUrlClassifierFeature>
+UrlClassifierFeatureFingerprintingAnnotation::GetIfNameMatches(
+    const nsACString& aName) {
+  if (!aName.EqualsLiteral(FINGERPRINTING_ANNOTATION_FEATURE_NAME)) {
+    return nullptr;
+  }
+
+  MaybeInitialize();
+  MOZ_ASSERT(gFeatureFingerprintingAnnotation);
+
+  RefPtr<UrlClassifierFeatureFingerprintingAnnotation> self =
+      gFeatureFingerprintingAnnotation;
+  return self.forget();
+}
+
+NS_IMETHODIMP
+UrlClassifierFeatureFingerprintingAnnotation::ProcessChannel(
+    nsIChannel* aChannel, const nsACString& aList, bool* aShouldContinue) {
+  NS_ENSURE_ARG_POINTER(aChannel);
+  NS_ENSURE_ARG_POINTER(aShouldContinue);
+
+  // This is not a blocking feature.
+  *aShouldContinue = true;
+
+  UC_LOG(
+      ("UrlClassifierFeatureFingerprintingAnnotation::ProcessChannel, "
+       "annotating channel[%p]",
+       aChannel));
+
+  UrlClassifierCommon::AnnotateChannel(
+      aChannel, AntiTrackingCommon::eFingerprinting,
+      nsIHttpChannel::ClassificationFlags::CLASSIFIED_FINGERPRINTING,
+      nsIWebProgressListener::STATE_LOADED_FINGERPRINTING_CONTENT);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+UrlClassifierFeatureFingerprintingAnnotation::GetURIByListType(
+    nsIChannel* aChannel, nsIUrlClassifierFeature::listType aListType,
+    nsIURI** aURI) {
+  NS_ENSURE_ARG_POINTER(aChannel);
+  NS_ENSURE_ARG_POINTER(aURI);
+
+  if (aListType == nsIUrlClassifierFeature::blacklist) {
+    return aChannel->GetURI(aURI);
+  }
+
+  MOZ_ASSERT(aListType == nsIUrlClassifierFeature::whitelist);
+  return UrlClassifierCommon::CreatePairwiseWhiteListURI(aChannel, aURI);
+}
+
+}  // namespace net
+}  // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/netwerk/url-classifier/UrlClassifierFeatureFingerprintingAnnotation.h
@@ -0,0 +1,46 @@
+/* -*- 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_net_UrlClassifierFeatureFingerprintingAnnotation_h
+#define mozilla_net_UrlClassifierFeatureFingerprintingAnnotation_h
+
+#include "UrlClassifierFeatureBase.h"
+
+class nsIChannel;
+
+namespace mozilla {
+namespace net {
+
+class UrlClassifierFeatureFingerprintingAnnotation final
+    : public UrlClassifierFeatureBase {
+ public:
+  static const char* Name();
+
+  static void MaybeShutdown();
+
+  static already_AddRefed<UrlClassifierFeatureFingerprintingAnnotation>
+  MaybeCreate(nsIChannel* aChannel);
+
+  static already_AddRefed<nsIUrlClassifierFeature> GetIfNameMatches(
+      const nsACString& aName);
+
+  NS_IMETHOD ProcessChannel(nsIChannel* aChannel, const nsACString& aList,
+                            bool* aShouldContinue) override;
+
+  NS_IMETHOD GetURIByListType(nsIChannel* aChannel,
+                              nsIUrlClassifierFeature::listType aListType,
+                              nsIURI** aURI) override;
+
+ private:
+  UrlClassifierFeatureFingerprintingAnnotation();
+
+  static void MaybeInitialize();
+};
+
+}  // namespace net
+}  // namespace mozilla
+
+#endif  // mozilla_net_UrlClassifierFeatureFingerprintingAnnotation_h
--- a/netwerk/url-classifier/UrlClassifierFeatureFingerprintingProtection.cpp
+++ b/netwerk/url-classifier/UrlClassifierFeatureFingerprintingProtection.cpp
@@ -12,17 +12,17 @@
 #include "nsContentUtils.h"
 #include "nsNetUtil.h"
 
 namespace mozilla {
 namespace net {
 
 namespace {
 
-#define FINGERPRINTING_FEATURE_NAME "fingerprinting"
+#define FINGERPRINTING_FEATURE_NAME "fingerprinting-protection"
 
 #define URLCLASSIFIER_FINGERPRINTING_BLACKLIST \
   "urlclassifier.features.fingerprinting.blacklistTables"
 #define URLCLASSIFIER_FINGERPRINTING_BLACKLIST_TEST_ENTRIES \
   "urlclassifier.features.fingerprinting.blacklistHosts"
 #define URLCLASSIFIER_FINGERPRINTING_WHITELIST \
   "urlclassifier.features.fingerprinting.whitelistTables"
 #define URLCLASSIFIER_FINGERPRINTING_WHITELIST_TEST_ENTRIES \
@@ -142,48 +142,41 @@ UrlClassifierFeatureFingerprintingProtec
 }
 
 NS_IMETHODIMP
 UrlClassifierFeatureFingerprintingProtection::ProcessChannel(
     nsIChannel* aChannel, const nsACString& aList, bool* aShouldContinue) {
   NS_ENSURE_ARG_POINTER(aChannel);
   NS_ENSURE_ARG_POINTER(aShouldContinue);
 
-  bool isAllowListed =
-      IsAllowListed(aChannel, AntiTrackingCommon::eFingerprinting);
+  bool isAllowListed = UrlClassifierCommon::IsAllowListed(
+      aChannel, AntiTrackingCommon::eFingerprinting);
 
   // This is a blocking feature.
   *aShouldContinue = isAllowListed;
 
   if (isAllowListed) {
-    // Even with fingerprinting blocking disabled, we still want to show the
-    // user that there are unblocked trackers on the site, so notify the UI that
-    // we loaded tracking content.  UI code can treat this notification
-    // differently depending on whether fingerprinting blocking is enabled or
-    // not.
-    UrlClassifierCommon::NotifyChannelClassifierProtectionDisabled(
-        aChannel, nsIWebProgressListener::STATE_LOADED_FINGERPRINTING_CONTENT);
-  } else {
-    UrlClassifierCommon::SetBlockedContent(aChannel,
-                                           NS_ERROR_FINGERPRINTING_URI, aList,
-                                           EmptyCString(), EmptyCString());
+    return NS_OK;
+  }
+
+  UrlClassifierCommon::SetBlockedContent(aChannel, NS_ERROR_FINGERPRINTING_URI,
+                                         aList, EmptyCString(), EmptyCString());
 
-    UC_LOG(
-        ("UrlClassifierFeatureFingerprintingProtection::ProcessChannel, "
-         "cancelling "
-         "channel[%p]",
-         aChannel));
-    nsCOMPtr<nsIHttpChannelInternal> httpChannel = do_QueryInterface(aChannel);
+  UC_LOG(
+      ("UrlClassifierFeatureFingerprintingProtection::ProcessChannel, "
+       "cancelling "
+       "channel[%p]",
+       aChannel));
+  nsCOMPtr<nsIHttpChannelInternal> httpChannel = do_QueryInterface(aChannel);
 
-    if (httpChannel) {
-      Unused << httpChannel->CancelByChannelClassifier(
-          NS_ERROR_FINGERPRINTING_URI);
-    } else {
-      Unused << aChannel->Cancel(NS_ERROR_FINGERPRINTING_URI);
-    }
+  if (httpChannel) {
+    Unused << httpChannel->CancelByChannelClassifier(
+        NS_ERROR_FINGERPRINTING_URI);
+  } else {
+    Unused << aChannel->Cancel(NS_ERROR_FINGERPRINTING_URI);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 UrlClassifierFeatureFingerprintingProtection::GetURIByListType(
     nsIChannel* aChannel, nsIUrlClassifierFeature::listType aListType,
--- a/netwerk/url-classifier/UrlClassifierFeatureTrackingAnnotation.cpp
+++ b/netwerk/url-classifier/UrlClassifierFeatureTrackingAnnotation.cpp
@@ -3,23 +3,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/. */
 
 #include "UrlClassifierFeatureTrackingAnnotation.h"
 
 #include "mozilla/AntiTrackingCommon.h"
 #include "mozilla/Logging.h"
-#include "mozilla/net/HttpBaseChannel.h"
 #include "mozilla/StaticPrefs.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/net/UrlClassifierCommon.h"
 #include "nsContentUtils.h"
-#include "nsQueryObject.h"
-#include "TrackingDummyChannel.h"
 
 namespace mozilla {
 namespace net {
 
 namespace {
 
 #define TRACKING_ANNOTATION_FEATURE_NAME "tracking-annotation"
 
@@ -33,84 +30,16 @@ namespace {
   "urlclassifier.trackingAnnotationWhitelistTable.testEntries"
 #define URLCLASSIFIER_TRACKING_ANNOTATION_SKIP_URLS \
   "urlclassifier.trackingAnnotationSkipURLs"
 #define TABLE_ANNOTATION_BLACKLIST_PREF "annotation-blacklist-pref"
 #define TABLE_ANNOTATION_WHITELIST_PREF "annotation-whitelist-pref"
 
 StaticRefPtr<UrlClassifierFeatureTrackingAnnotation> gFeatureTrackingAnnotation;
 
-static void SetIsTrackingResourceHelper(nsIChannel* aChannel,
-                                        bool aIsThirdParty) {
-  MOZ_ASSERT(aChannel);
-
-  nsCOMPtr<nsIParentChannel> parentChannel;
-  NS_QueryNotificationCallbacks(aChannel, parentChannel);
-  if (parentChannel) {
-    // This channel is a parent-process proxy for a child process
-    // request. We should notify the child process as well.
-    parentChannel->NotifyTrackingResource(aIsThirdParty);
-  }
-
-  RefPtr<HttpBaseChannel> httpChannel = do_QueryObject(aChannel);
-  if (httpChannel) {
-    httpChannel->SetIsTrackingResource(aIsThirdParty);
-  }
-
-  RefPtr<TrackingDummyChannel> dummyChannel = do_QueryObject(aChannel);
-  if (dummyChannel) {
-    dummyChannel->SetIsTrackingResource();
-  }
-}
-
-static void LowerPriorityHelper(nsIChannel* aChannel) {
-  MOZ_ASSERT(aChannel);
-
-  bool isBlockingResource = false;
-
-  nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(aChannel));
-  if (cos) {
-    if (nsContentUtils::IsTailingEnabled()) {
-      uint32_t cosFlags = 0;
-      cos->GetClassFlags(&cosFlags);
-      isBlockingResource =
-          cosFlags & (nsIClassOfService::UrgentStart |
-                      nsIClassOfService::Leader | nsIClassOfService::Unblocked);
-
-      // Requests not allowed to be tailed are usually those with higher
-      // prioritization.  That overweights being a tracker: don't throttle
-      // them when not in background.
-      if (!(cosFlags & nsIClassOfService::TailForbidden)) {
-        cos->AddClassFlags(nsIClassOfService::Throttleable);
-      }
-    } else {
-      // Yes, we even don't want to evaluate the isBlockingResource when tailing
-      // is off see bug 1395525.
-
-      cos->AddClassFlags(nsIClassOfService::Throttleable);
-    }
-  }
-
-  if (!isBlockingResource) {
-    nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(aChannel);
-    if (p) {
-      if (UC_LOG_ENABLED()) {
-        nsCOMPtr<nsIURI> uri;
-        aChannel->GetURI(getter_AddRefs(uri));
-        nsAutoCString spec;
-        uri->GetAsciiSpec(spec);
-        spec.Truncate(
-            std::min(spec.Length(), UrlClassifierCommon::sMaxSpecLength));
-        UC_LOG(("Setting PRIORITY_LOWEST for channel[%p] (%s)", aChannel,
-                spec.get()));
-      }
-      p->SetPriority(nsISupportsPriority::PRIORITY_LOWEST);
-    }
-  }
-}
 
 }  // namespace
 
 UrlClassifierFeatureTrackingAnnotation::UrlClassifierFeatureTrackingAnnotation()
     : UrlClassifierFeatureBase(
           NS_LITERAL_CSTRING(TRACKING_ANNOTATION_FEATURE_NAME),
           NS_LITERAL_CSTRING(URLCLASSIFIER_ANNOTATION_BLACKLIST),
           NS_LITERAL_CSTRING(URLCLASSIFIER_ANNOTATION_WHITELIST),
@@ -190,52 +119,20 @@ UrlClassifierFeatureTrackingAnnotation::
                                                        const nsACString& aList,
                                                        bool* aShouldContinue) {
   NS_ENSURE_ARG_POINTER(aChannel);
   NS_ENSURE_ARG_POINTER(aShouldContinue);
 
   // This is not a blocking feature.
   *aShouldContinue = true;
 
-  nsCOMPtr<nsIURI> chanURI;
-  nsresult rv = aChannel->GetURI(getter_AddRefs(chanURI));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    UC_LOG(
-        ("UrlClassifierFeatureTrackingAnnotation::ProcessChannel "
-         "nsIChannel::GetURI(%p) failed",
-         (void*)aChannel));
-    return NS_OK;
-  }
-
-  bool isThirdPartyWithTopLevelWinURI =
-      nsContentUtils::IsThirdPartyWindowOrChannel(nullptr, aChannel, chanURI);
-
-  bool isAllowListed =
-      IsAllowListed(aChannel, AntiTrackingCommon::eTrackingAnnotations);
-
-  UC_LOG(
-      ("UrlClassifierFeatureTrackingAnnotation::ProcessChannel, annotating "
-       "channel[%p]",
-       aChannel));
-
-  SetIsTrackingResourceHelper(aChannel, isThirdPartyWithTopLevelWinURI);
-
-  if (isThirdPartyWithTopLevelWinURI || isAllowListed) {
-    // Even with TP disabled, we still want to show the user that there
-    // are unblocked trackers on the site, so notify the UI that we loaded
-    // tracking content. UI code can treat this notification differently
-    // depending on whether TP is enabled or disabled.
-    UrlClassifierCommon::NotifyChannelClassifierProtectionDisabled(
-        aChannel, nsIWebProgressListener::STATE_LOADED_TRACKING_CONTENT);
-  }
-
-  if (isThirdPartyWithTopLevelWinURI &&
-      StaticPrefs::privacy_trackingprotection_lower_network_priority()) {
-    LowerPriorityHelper(aChannel);
-  }
+  UrlClassifierCommon::AnnotateChannel(
+      aChannel, AntiTrackingCommon::eTrackingAnnotations,
+      nsIHttpChannel::ClassificationFlags::CLASSIFIED_TRACKING,
+      nsIWebProgressListener::STATE_LOADED_TRACKING_CONTENT);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 UrlClassifierFeatureTrackingAnnotation::GetURIByListType(
     nsIChannel* aChannel, nsIUrlClassifierFeature::listType aListType,
     nsIURI** aURI) {
--- a/netwerk/url-classifier/UrlClassifierFeatureTrackingProtection.cpp
+++ b/netwerk/url-classifier/UrlClassifierFeatureTrackingProtection.cpp
@@ -134,18 +134,18 @@ UrlClassifierFeatureTrackingProtection::
 
 NS_IMETHODIMP
 UrlClassifierFeatureTrackingProtection::ProcessChannel(nsIChannel* aChannel,
                                                        const nsACString& aList,
                                                        bool* aShouldContinue) {
   NS_ENSURE_ARG_POINTER(aChannel);
   NS_ENSURE_ARG_POINTER(aShouldContinue);
 
-  bool isAllowListed =
-      IsAllowListed(aChannel, AntiTrackingCommon::eTrackingProtection);
+  bool isAllowListed = UrlClassifierCommon::IsAllowListed(
+      aChannel, AntiTrackingCommon::eTrackingProtection);
 
   // This is a blocking feature.
   *aShouldContinue = isAllowListed;
 
   if (!isAllowListed) {
     UrlClassifierCommon::SetBlockedContent(
         aChannel, NS_ERROR_TRACKING_URI, aList, EmptyCString(), EmptyCString());
 
--- a/netwerk/url-classifier/moz.build
+++ b/netwerk/url-classifier/moz.build
@@ -26,19 +26,21 @@ XPCOM_MANIFESTS += [
 DEFINES['GOOGLE_PROTOBUF_NO_RTTI'] = True
 DEFINES['GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER'] = True
 
 UNIFIED_SOURCES += [
     'AsyncUrlChannelClassifier.cpp',
     'nsChannelClassifier.cpp',
     'UrlClassifierCommon.cpp',
     'UrlClassifierFeatureBase.cpp',
+    'UrlClassifierFeatureCryptominingAnnotation.cpp',
     'UrlClassifierFeatureCryptominingProtection.cpp',
     'UrlClassifierFeatureCustomTables.cpp',
     'UrlClassifierFeatureFactory.cpp',
+    'UrlClassifierFeatureFingerprintingAnnotation.cpp',
     'UrlClassifierFeatureFingerprintingProtection.cpp',
     'UrlClassifierFeatureFlash.cpp',
     'UrlClassifierFeatureLoginReputation.cpp',
     'UrlClassifierFeaturePhishingProtection.cpp',
     'UrlClassifierFeatureResult.cpp',
     'UrlClassifierFeatureTrackingAnnotation.cpp',
     'UrlClassifierFeatureTrackingProtection.cpp',
 ]
--- a/python/mach_commands.py
+++ b/python/mach_commands.py
@@ -165,39 +165,42 @@ class MachCommands(MachCommandBase):
                 self.log(logging.INFO, 'python-test', {'line': line.rstrip()}, '{line}')
 
             if ret and not return_code:
                 self.log(logging.ERROR, 'python-test', {'test_path': test_path, 'ret': ret},
                          'Setting retcode to {ret} from {test_path}')
             return return_code or ret
 
         with ThreadPoolExecutor(max_workers=self.jobs) as executor:
-            futures = [executor.submit(self._run_python_test, test['path'])
+            futures = [executor.submit(self._run_python_test, test)
                        for test in parallel]
 
             try:
                 for future in as_completed(futures):
                     return_code = on_test_finished(future.result())
             except KeyboardInterrupt:
                 # Hack to force stop currently running threads.
                 # https://gist.github.com/clchiou/f2608cbe54403edb0b13
                 executor._threads.clear()
                 thread._threads_queues.clear()
                 raise
 
         for test in sequential:
-            return_code = on_test_finished(self._run_python_test(test['path']))
+            return_code = on_test_finished(self._run_python_test(test))
 
         self.log(logging.INFO, 'python-test', {'return_code': return_code},
                  'Return code from mach python-test: {return_code}')
         return return_code
 
-    def _run_python_test(self, test_path):
+    def _run_python_test(self, test):
         from mozprocess import ProcessHandler
 
+        if test.get('requirements'):
+            self.virtualenv_manager.install_pip_requirements(test['requirements'], quiet=True)
+
         output = []
 
         def _log(line):
             # Buffer messages if more than one worker to avoid interleaving
             if self.jobs > 1:
                 output.append(line)
             else:
                 self.log(logging.INFO, 'python-test', {'line': line.rstrip()}, '{line}')
@@ -212,29 +215,29 @@ class MachCommands(MachCommandBase):
                     file_displayed_test.append(True)
 
             # Hack to make sure treeherder highlights pytest failures
             if 'FAILED' in line.rsplit(' ', 1)[-1]:
                 line = line.replace('FAILED', 'TEST-UNEXPECTED-FAIL')
 
             _log(line)
 
-        _log(test_path)
-        cmd = [self.virtualenv_manager.python_path, test_path]
+        _log(test['path'])
+        cmd = [self.virtualenv_manager.python_path, test['path']]
         env = os.environ.copy()
         env[b'PYTHONDONTWRITEBYTECODE'] = b'1'
 
         proc = ProcessHandler(cmd, env=env, processOutputLine=_line_handler, storeOutput=False)
         proc.run()
 
         return_code = proc.wait()
 
         if not file_displayed_test:
             _log('TEST-UNEXPECTED-FAIL | No test output (missing mozunit.main() '
-                 'call?): {}'.format(test_path))
+                 'call?): {}'.format(test['path']))
 
         if self.verbose:
             if return_code != 0:
-                _log('Test failed: {}'.format(test_path))
+                _log('Test failed: {}'.format(test['path']))
             else:
-                _log('Test passed: {}'.format(test_path))
+                _log('Test passed: {}'.format(test['path']))
 
-        return output, return_code, test_path
+        return output, return_code, test['path']
--- a/security/manager/pki/resources/content/pippki.js
+++ b/security/manager/pki/resources/content/pippki.js
@@ -86,17 +86,17 @@ const DEFAULT_CERT_EXTENSION = "crt";
  * @returns {String}
  *          Generated filename.
  */
 function certToFilename(cert) {
   let filename = cert.displayName;
 
   // Remove unneeded and/or unsafe characters.
   filename = filename.replace(/\s/g, "")
-                     .replace(/\./g, "")
+                     .replace(/\./g, "_")
                      .replace(/\\/g, "")
                      .replace(/\//g, "");
 
   // Ci.nsIFilePicker.defaultExtension is more of a suggestion to some
   // implementations, so we include the extension in the file name as well. This
   // is what the documentation for Ci.nsIFilePicker.defaultString says we should do
   // anyways.
   return `${filename}.${DEFAULT_CERT_EXTENSION}`;
--- a/testing/mozharness/mozharness/mozilla/secrets.py
+++ b/testing/mozharness/mozharness/mozilla/secrets.py
@@ -51,17 +51,17 @@ class SecretsMixin(object):
         secret_files = self.config.get('secret_files', [])
 
         scm_level = int(os.environ.get('MOZ_SCM_LEVEL', '1'))
         subst = {
             'scm-level': scm_level,
         }
 
         for sf in secret_files:
-            filename = sf['filename']
+            filename = os.path.abspath(sf['filename'])
             secret_name = sf['secret_name'] % subst
             min_scm_level = sf.get('min_scm_level', 0)
             if scm_level < min_scm_level:
                 if 'default' in sf:
                     self.info("Using default value for " + filename)
                     secret = sf['default']
                 elif 'default-file' in sf:
                     default_path = sf['default-file'].format(**dirs)
--- a/toolkit/components/url-classifier/SafeBrowsing.jsm
+++ b/toolkit/components/url-classifier/SafeBrowsing.jsm
@@ -110,27 +110,47 @@ const FEATURES = [
            "urlclassifier.flashSubDocExceptTable"],
     enabled() {
       return Services.prefs.getBoolPref("plugins.flashBlock.enabled");
     },
     update() {
       return Services.prefs.getBoolPref("browser.safebrowsing.features.flashBlock.update", this.enabled());
     },
   },
-  { name: "fingerprinting",
+  { name: "fingerprinting-annotation",
+    list: ["urlclassifier.features.fingerprinting.annotate.blacklistTables",
+           "urlclassifier.features.fingerprinting.annotate.whitelistTables"],
+    enabled() {
+      return Services.prefs.getBoolPref("privacy.trackingprotection.fingerprinting.annotate.enabled", false);
+    },
+    update() {
+      return Services.prefs.getBoolPref("browser.safebrowsing.features.fingerprinting.annotate.update", this.enabled());
+    },
+  },
+  { name: "fingerprinting-protection",
     list: ["urlclassifier.features.fingerprinting.blacklistTables",
            "urlclassifier.features.fingerprinting.whitelistTables"],
     enabled() {
       return Services.prefs.getBoolPref("privacy.trackingprotection.fingerprinting.enabled", false);
     },
     update() {
       return Services.prefs.getBoolPref("browser.safebrowsing.features.fingerprinting.update", this.enabled());
     },
   },
-  { name: "cryptomining",
+  { name: "cryptomining-annotation",
+    list: ["urlclassifier.features.cryptomining.annotate.blacklistTables",
+           "urlclassifier.features.cryptomining.annotate.whitelistTables"],
+    enabled() {
+      return Services.prefs.getBoolPref("privacy.trackingprotection.annotate.cryptomining.enabled", false);
+    },
+    update() {
+      return Services.prefs.getBoolPref("browser.safebrowsing.features.cryptomining.annotate.update", this.enabled());
+    },
+  },
+  { name: "cryptomining-protection",
     list: ["urlclassifier.features.cryptomining.blacklistTables",
            "urlclassifier.features.cryptomining.whitelistTables"],
     enabled() {
       return Services.prefs.getBoolPref("privacy.trackingprotection.cryptomining.enabled", false);
     },
     update() {
       return Services.prefs.getBoolPref("browser.safebrowsing.features.cryptomining.update", this.enabled());
     },
new file mode 100644
--- /dev/null
+++ b/toolkit/components/url-classifier/tests/mochitest/features.js
@@ -0,0 +1,156 @@
+var tests = [
+  // Config is an array with 4 elements:
+  // - annotation blacklist
+  // - annotation whitelist
+  // - tracking blacklist
+  // - tracking whitelist
+
+  // All disabled.
+  { config: [ false, false, false, false ], loadExpected: true,  annotationExpected: false },
+
+  // Just whitelisted.
+  { config: [ false, false, false, true  ], loadExpected: true,  annotationExpected: false },
+
+  // Just blacklisted.
+  { config: [ false, false, true,  false ], loadExpected: false, annotationExpected: false },
+
+  // whitelist + blacklist => whitelist wins
+  { config: [ false, false, true,  true  ], loadExpected: true,  annotationExpected: false },
+
+  // just annotated in whitelist.
+  { config: [ false, true,  false, false ], loadExpected: true,  annotationExpected: false },
+
+  // TP and annotation whitelisted.
+  { config: [ false, true,  false, true  ], loadExpected: true,  annotationExpected: false },
+
+  // Annotation whitelisted, but TP blacklisted.
+  { config: [ false, true,  true,  false ], loadExpected: false, annotationExpected: false },
+
+  // Annotation whitelisted. TP blacklisted and whitelisted: whitelist wins.
+  { config: [ false, true,  true,  true  ], loadExpected: true,  annotationExpected: false },
+
+  // Just blacklist annotated.
+  { config: [ true,  false, false, false ], loadExpected: true,  annotationExpected: true },
+
+  // annotated but TP whitelisted.
+  { config: [ true,  false, false, true  ], loadExpected: true,  annotationExpected: true },
+
+  // annotated and blacklisted.
+  { config: [ true,  false, true,  false ], loadExpected: false, annotationExpected: false },
+
+  // annotated, TP blacklisted and whitelisted: whitelist wins.
+  { config: [ true,  false, true,  true  ], loadExpected: true,  annotationExpected: true },
+
+  // annotated in white and blacklist.
+  { config: [ true,  true,  false, false ], loadExpected: true,  annotationExpected: false },
+
+  // annotated in white and blacklist. TP Whiteslited
+  { config: [ true,  true,  false, true  ], loadExpected: true,  annotationExpected: false },
+
+  // everywhere. TP whitelist wins.
+  { config: [ true,  true,  true,  true  ], loadExpected: true,  annotationExpected: false },
+];
+
+function prefBlacklistValue(value) {
+  return value ? "example.com" : "";
+}
+
+function prefWhitelistValue(value) {
+  return value ? "mochi.test" : "";
+}
+
+async function runTest(test, expectedFlag, expectedTrackingResource, prefs) {
+  let config = [
+    [ "urlclassifier.trackingAnnotationTable.testEntries", prefBlacklistValue(test.config[0]) ],
+    [ "urlclassifier.features.fingerprinting.annotate.blacklistHosts", prefBlacklistValue(test.config[0]) ],
+    [ "urlclassifier.features.cryptomining.annotate.blacklistHosts", prefBlacklistValue(test.config[0]) ],
+
+    [ "urlclassifier.trackingAnnotationWhitelistTable.testEntries", prefWhitelistValue(test.config[1]) ],
+    [ "urlclassifier.features.fingerprinting.annotate.whitelistHosts", prefWhitelistValue(test.config[1]) ],
+    [ "urlclassifier.features.cryptomining.annotate.whitelistHosts", prefWhitelistValue(test.config[1]) ],
+
+    [ "urlclassifier.trackingTable.testEntries", prefBlacklistValue(test.config[2]) ],
+    [ "urlclassifier.features.fingerprinting.blacklistHosts", prefBlacklistValue(test.config[2]) ],
+    [ "urlclassifier.features.cryptomining.blacklistHosts", prefBlacklistValue(test.config[2]) ],
+
+    [ "urlclassifier.trackingWhitelistTable.testEntries", prefWhitelistValue(test.config[3]) ],
+    [ "urlclassifier.features.fingerprinting.whitelistHosts", prefWhitelistValue(test.config[3]) ],
+    [ "urlclassifier.features.cryptomining.whitelistHosts", prefWhitelistValue(test.config[3]) ],
+  ];
+
+  info("Testing: " + config.toSource() + "\n");
+
+  await SpecialPowers.pushPrefEnv({set: config.concat(prefs) });
+
+  // This promise will be resolved when the chromeScript knows if the channel
+  // is annotated or not.
+  let annotationPromise;
+  if (test.loadExpected) {
+    info("We want to have annotation information");
+    annotationPromise = new Promise(resolve => {
+      chromeScript.addMessageListener("last-channel-flags",
+                                      data => resolve(data),
+                                      {once: true});
+    });
+  }
+
+  // Let's load an image with a random query string, just to avoid network cache.
+  let result = await new Promise(resolve => {
+    let image = new Image();
+    image.src = "http://example.com/tests/toolkit/components/url-classifier/tests/mochitest/raptor.jpg?" + Math.random();
+    image.onload = _ => resolve(true);
+    image.onerror = _ => resolve(false);
+  });
+
+  is(result, test.loadExpected, "The loading happened correctly");
+
+  if (annotationPromise) {
+    let data = await annotationPromise;
+    is(!!data.classificationFlags, test.annotationExpected, "The annotation happened correctly");
+    if (test.annotationExpected) {
+      is(data.classificationFlags, expectedFlag, "Correct flag");
+      is(data.isTrackingResource, expectedTrackingResource, "Tracking resource flag matches");
+    }
+  }
+}
+
+var chromeScript;
+
+function runTests(flag, prefs, trackingResource) {
+  chromeScript = SpecialPowers.loadChromeScript(_ => {
+    const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
+
+    function onExamResp(subject, topic, data) {
+      let channel = subject.QueryInterface(Ci.nsIHttpChannel);
+      if (!channel ||
+          !channel.URI.spec.startsWith("http://example.com/tests/toolkit/components/url-classifier/tests/mochitest/raptor.jpg")) {
+        return;
+      }
+
+      // eslint-disable-next-line no-undef
+      sendAsyncMessage("last-channel-flags", {
+        classificationFlags: channel.classificationFlags,
+        isTrackingResource: channel.isTrackingResource,
+      });
+    }
+
+    // eslint-disable-next-line no-undef
+    addMessageListener("done", __ => {
+      Services.obs.removeObserver(onExamResp, "http-on-examine-response");
+    });
+
+    Services.obs.addObserver(onExamResp, "http-on-examine-response");
+
+    // eslint-disable-next-line no-undef
+    sendAsyncMessage("start-test");
+  });
+
+  chromeScript.addMessageListener("start-test", async _ => {
+    for (let test in tests) {
+      await runTest(tests[test], flag, trackingResource, prefs);
+    }
+
+    chromeScript.sendAsyncMessage("done");
+    SimpleTest.finish();
+  }, {once: true});
+}
--- a/toolkit/components/url-classifier/tests/mochitest/mochitest.ini
+++ b/toolkit/components/url-classifier/tests/mochitest/mochitest.ini
@@ -27,23 +27,26 @@ support-files =
   dnt.sjs
   update.sjs
   bad.css
   bad.css^headers^
   gethash.sjs
   gethashFrame.html
   seek.webm
   cache.sjs
+  features.js
 
 [test_classifier.html]
 skip-if = (os == 'linux' && debug) #Bug 1199778
 [test_classifier_match.html]
 [test_classifier_worker.html]
 [test_classify_ping.html]
 skip-if = (verify && debug && (os == 'win' || os == 'mac'))
 [test_classify_track.html]
 [test_gethash.html]
 [test_bug1254766.html]
 [test_cachemiss.html]
 skip-if = verify
 [test_annotation_vs_TP.html]
 [test_fingerprinting.html]
+[test_fingerprinting_annotate.html]
 [test_cryptomining.html]
+[test_cryptomining_annotate.html]
--- a/toolkit/components/url-classifier/tests/mochitest/test_annotation_vs_TP.html
+++ b/toolkit/components/url-classifier/tests/mochitest/test_annotation_vs_TP.html
@@ -1,154 +1,27 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <title>Test the relationship between annotation vs TP</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="features.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 
 <body>
 <script class="testbody" type="text/javascript">
 
-var tests = [
-  // Config is an array with 4 elements:
-  // - annotation blacklist
-  // - annotation whitelist
-  // - tracking blacklist
-  // - tracking whitelist
-
-  // All disabled.
-  { config: [ false, false, false, false ], loadExpected: true,  annotationExpected: false },
-
-  // Just whitelisted.
-  { config: [ false, false, false, true  ], loadExpected: true,  annotationExpected: false },
-
-  // Just blacklisted.
-  { config: [ false, false, true,  false ], loadExpected: false, annotationExpected: false },
-
-  // whitelist + blacklist => whitelist wins
-  { config: [ false, false, true,  true  ], loadExpected: true,  annotationExpected: false },
-
-  // just annotated in whitelist.
-  { config: [ false, true,  false, false ], loadExpected: true,  annotationExpected: false },
-
-  // TP and annotation whitelisted.
-  { config: [ false, true,  false, true  ], loadExpected: true,  annotationExpected: false },
-
-  // Annotation whitelisted, but TP blacklisted.
-  { config: [ false, true,  true,  false ], loadExpected: false, annotationExpected: false },
-
-  // Annotation whitelisted. TP blacklisted and whitelisted: whitelist wins.
-  { config: [ false, true,  true,  true  ], loadExpected: true,  annotationExpected: false },
-
-  // Just blacklist annotated.
-  { config: [ true,  false, false, false ], loadExpected: true,  annotationExpected: true },
-
-  // annotated but TP whitelisted.
-  { config: [ true,  false, false, true  ], loadExpected: true,  annotationExpected: true },
-
-  // annotated and blacklisted.
-  { config: [ true,  false, true,  false ], loadExpected: false, annotationExpected: false },
-
-  // annotated, TP blacklisted and whitelisted: whitelist wins.
-  { config: [ true,  false, true,  true  ], loadExpected: true,  annotationExpected: true },
-
-  // annotated in white and blacklist.
-  { config: [ true,  true,  false, false ], loadExpected: true,  annotationExpected: false },
-
-  // annotated in white and blacklist. TP Whiteslited
-  { config: [ true,  true,  false, true  ], loadExpected: true,  annotationExpected: false },
-
-  // everywhere. TP whitelist wins.
-  { config: [ true,  true,  true,  true  ], loadExpected: true,  annotationExpected: false },
-];
-
-function prefBlacklistValue(value) {
-  return value ? "example.com" : "";
-}
-
-function prefWhitelistValue(value) {
-  return value ? "mochi.test" : "";
-}
-
-async function runTest(test) {
-  let config = [
-    [ "urlclassifier.trackingAnnotationTable.testEntries", prefBlacklistValue(test.config[0]) ],
-    [ "urlclassifier.trackingAnnotationWhitelistTable.testEntries", prefWhitelistValue(test.config[1]) ],
-    [ "urlclassifier.trackingTable.testEntries", prefBlacklistValue(test.config[2]) ],
-    [ "urlclassifier.trackingWhitelistTable.testEntries", prefWhitelistValue(test.config[3]) ],
-  ];
-
-  info("Testing: " + config.toSource() + "\n");
-
-  // Let's enable TP and annotation.
-  config.push(["privacy.trackingprotection.enabled", true]);
-  config.push(["privacy.trackingprotection.annotate_channels", true]);
-
-  await SpecialPowers.pushPrefEnv({set: config });
-
-  // This promise will be resolved when the chromeScript knows if the channel
-  // is annotated or not.
-  let annotationPromise;
-  if (test.loadExpected) {
-    info("We want to have annotation information");
-    annotationPromise = new Promise(resolve => {
-      chromeScript.addMessageListener("last-channel-status",
-                                      annotated => resolve(annotated),
-                                      {once: true});
-    });
-  }
-
-  // Let's load an image with a random query string, just to avoid network cache.
-  let result = await new Promise(resolve => {
-    let image = new Image();
-    image.src = "http://example.com/tests/toolkit/components/url-classifier/tests/mochitest/raptor.jpg?" + Math.random();
-    image.onload = _ => resolve(true);
-    image.onerror = _ => resolve(false);
-  });
-
-  is(result, test.loadExpected, "The loading happened correctly");
-
-  if (annotationPromise) {
-    is(await annotationPromise, test.annotationExpected, "The annotation happened correctly");
-  }
-}
-
-var chromeScript = SpecialPowers.loadChromeScript(_ => {
-  const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
-
-  function onExamResp(subject, topic, data) {
-    let channel = subject.QueryInterface(Ci.nsIHttpChannel);
-    if (!channel ||
-        !channel.URI.spec.startsWith("http://example.com/tests/toolkit/components/url-classifier/tests/mochitest/raptor.jpg")) {
-      return;
-    }
-
-    // eslint-disable-next-line no-undef
-    sendAsyncMessage("last-channel-status", channel.isTrackingResource);
-  }
-
-  // eslint-disable-next-line no-undef
-  addMessageListener("done", __ => {
-    Services.obs.removeObserver(onExamResp, "http-on-examine-response");
-  });
-
-  Services.obs.addObserver(onExamResp, "http-on-examine-response");
-
-  // eslint-disable-next-line no-undef
-  sendAsyncMessage("start-test");
-});
-
-chromeScript.addMessageListener("start-test", async _ => {
-  for (let test in tests) {
-    await runTest(tests[test]);
-  }
-
-  chromeScript.sendAsyncMessage("done");
-  SimpleTest.finish();
-}, {once: true});
-
+runTests(SpecialPowers.Ci.nsIHttpChannel.CLASSIFIED_TRACKING,
+         [
+           ["privacy.trackingprotection.enabled", true],
+           ["privacy.trackingprotection.annotate_channels", true],
+           ["privacy.trackingprotection.fingerprinting.annotate.enabled", false],
+           ["privacy.trackingprotection.fingerprinting.enabled", false],
+           ["privacy.trackingprotection.cryptomining.annotate.enabled", false],
+           ["privacy.trackingprotection.cryptomining.enabled", false],
+         ],
+         true /* a tracking resource */);
 SimpleTest.waitForExplicitFinish();
 
 </script>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/toolkit/components/url-classifier/tests/mochitest/test_cryptomining_annotate.html
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test the relationship between annotation vs blocking - cryptomining</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="features.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+
+<body>
+<script class="testbody" type="text/javascript">
+
+runTests(SpecialPowers.Ci.nsIHttpChannel.CLASSIFIED_CRYPTOMINING,
+         [
+           ["privacy.trackingprotection.enabled", false],
+           ["privacy.trackingprotection.annotate_channels", false],
+           ["privacy.trackingprotection.fingerprinting.annotate.enabled", false],
+           ["privacy.trackingprotection.fingerprinting.enabled", false],
+           ["privacy.trackingprotection.cryptomining.annotate.enabled", true],
+           ["privacy.trackingprotection.cryptomining.enabled", true],
+         ],
+         false /* a tracking resource */);
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/toolkit/components/url-classifier/tests/mochitest/test_fingerprinting_annotate.html
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test the relationship between annotation vs blocking - fingerprinting</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="features.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+
+<body>
+<script class="testbody" type="text/javascript">
+
+runTests(SpecialPowers.Ci.nsIHttpChannel.CLASSIFIED_FINGERPRINTING,
+         [
+           ["privacy.trackingprotection.enabled", false],
+           ["privacy.trackingprotection.annotate_channels", false],
+           ["privacy.trackingprotection.fingerprinting.annotate.enabled", true],
+           ["privacy.trackingprotection.fingerprinting.enabled", true],
+           ["privacy.trackingprotection.cryptomining.annotate.enabled", false],
+           ["privacy.trackingprotection.cryptomining.enabled", false],
+         ],
+         true /* a tracking resource */);
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</body>
+</html>
--- a/toolkit/content/widgets/tree.js
+++ b/toolkit/content/widgets/tree.js
@@ -507,17 +507,17 @@
   customElements.define("treecols", MozTreecols);
 
   class MozTree extends BaseControlMixin(MozElementMixin(XULTreeElement)) {
     constructor() {
       super();
 
       this.attachShadow({ mode: "open" });
       this.shadowRoot.appendChild(MozXULElement.parseXULToFragment(`
-        <html:link rel="stylesheet" href="chrome://global/skin/tree.css" />
+        <html:link rel="stylesheet" href="chrome://global/content/widgets.css" />
         <html:slot name="treecols"></html:slot>
         <stack class="tree-stack" flex="1">
           <hbox class="tree-rows" flex="1">
             <hbox flex="1" class="tree-bodybox">
               <html:slot name="treechildren"></html:slot>
             </hbox>
             <scrollbar height="0" minwidth="0" minheight="0" orient="vertical" inherits="collapsed=hidevscroll" style="position:relative; z-index:2147483647;" oncontextmenu="event.stopPropagation(); event.preventDefault();" onclick="event.stopPropagation(); event.preventDefault();" ondblclick="event.stopPropagation();" oncommand="event.stopPropagation();"></scrollbar>
           </hbox>
--- a/toolkit/mozapps/extensions/internal/AddonTestUtils.jsm
+++ b/toolkit/mozapps/extensions/internal/AddonTestUtils.jsm
@@ -410,16 +410,20 @@ var AddonTestUtils = {
 
     this.profileExtensions = FileUtils.getDir("ProfD", ["extensions"]);
 
     this.tempDir = FileUtils.getDir("TmpD", []);
     this.tempDir.append("addons-mochitest");
     this.tempDir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
 
     testScope.registerCleanupFunction(() => {
+      // Defer testScope cleanup until the last cleanup function has run.
+      testScope.registerCleanupFunction(() => {
+        this.testScope = null;
+      });
       this.cleanupTempXPIs();
       try {
         this.tempDir.remove(true);
       } catch (e) {
         Cu.reportError(e);
       }
     });
   },
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -2795,17 +2795,18 @@ bool fire_glxtest_process();
 // Encapsulates startup and shutdown state for XRE_main
 class XREMain {
  public:
   XREMain()
       : mStartOffline(false),
         mShuttingDown(false)
 #ifdef MOZ_HAS_REMOTE
         ,
-        mDisableRemote(false)
+        mDisableRemoteClient(false),
+        mDisableRemoteServer(false)
 #endif
 #if defined(MOZ_WIDGET_GTK)
         ,
         mGdkDisplay(nullptr)
 #endif
             {};
 
   ~XREMain() {
@@ -2833,17 +2834,18 @@ class XREMain {
   UniquePtr<XREAppData> mAppData;
 
   nsXREDirProvider mDirProvider;
   nsAutoCString mDesktopStartupID;
 
   bool mStartOffline;
   bool mShuttingDown;
 #if defined(MOZ_HAS_REMOTE)
-  bool mDisableRemote;
+  bool mDisableRemoteClient;
+  bool mDisableRemoteServer;
 #endif
 
 #if defined(MOZ_WIDGET_GTK)
   GdkDisplay* mGdkDisplay;
 #endif
 };
 
 #if defined(XP_UNIX) && !defined(ANDROID)
@@ -3347,33 +3349,34 @@ int XREMain::XRE_mainInit(bool* aExitFla
   ar = CheckArg("no-remote", nullptr,
                 CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg);
   if (ar == ARG_BAD) {
     PR_fprintf(PR_STDERR,
                "Error: argument --no-remote is invalid when argument --osint "
                "is specified\n");
     return 1;
   }
-  if (ar == ARG_FOUND) {
-    SaveToEnv("MOZ_NO_REMOTE=1");
-    mDisableRemote = true;
-  } else if (EnvHasValue("MOZ_NO_REMOTE")) {
-    mDisableRemote = true;
+  if (ar == ARG_FOUND || EnvHasValue("MOZ_NO_REMOTE")) {
+    mDisableRemoteClient = true;
+    mDisableRemoteServer = true;
+    if (!EnvHasValue("MOZ_NO_REMOTE")) {
+      SaveToEnv("MOZ_NO_REMOTE=1");
+    }
   }
 
   ar = CheckArg("new-instance", nullptr,
                 CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg);
   if (ar == ARG_BAD) {
     PR_fprintf(PR_STDERR,
                "Error: argument --new-instance is invalid when argument "
                "--osint is specified\n");
     return 1;
   }
   if (ar == ARG_FOUND || EnvHasValue("MOZ_NEW_INSTANCE")) {
-    mDisableRemote = true;
+    mDisableRemoteClient = true;
   }
 #else
   // These arguments do nothing in platforms with no remoting support but we
   // should remove them from the command line anyway.
   CheckArg("no-remote");
   CheckArg("new-instance");
 #endif
 
@@ -3769,17 +3772,18 @@ int XREMain::XRE_mainStartup(bool* aExit
       printf("TEST-UNEXPECTED-FAIL | gtest | Not compiled with enable-tests\n");
     }
     *aExitFlag = true;
     return result;
   }
 
 #ifdef MOZ_HAS_REMOTE
   if (gfxPlatform::IsHeadless()) {
-    mDisableRemote = true;
+    mDisableRemoteClient = true;
+    mDisableRemoteServer = true;
   }
 #endif
 
 #ifdef MOZ_X11
   // Init X11 in thread-safe mode. Must be called prior to the first call to
   // XOpenDisplay (called inside gdk_display_open). This is a requirement for
   // off main tread compositing.
   if (!gfxPlatform::IsHeadless()) {
@@ -3847,21 +3851,19 @@ int XREMain::XRE_mainStartup(bool* aExit
       mGdkDisplay =
           gdk_display_manager_open_display(gdk_display_manager_get(), nullptr);
     }
 #  endif
   }
 #endif
 #if defined(MOZ_HAS_REMOTE)
   // handle --remote now that xpcom is fired up
-  if (!mDisableRemote) {
-    mRemoteService = new nsRemoteService(gAppData->remotingName);
-    if (mRemoteService) {
-      mRemoteService->LockStartup();
-    }
+  mRemoteService = new nsRemoteService(gAppData->remotingName);
+  if (mRemoteService && !mDisableRemoteServer) {
+    mRemoteService->LockStartup();
   }
 #endif
 #if defined(MOZ_WIDGET_GTK)
   g_set_application_name(mAppData->name);
   gtk_window_set_auto_startup_notification(false);
 
 #endif /* defined(MOZ_WIDGET_GTK) */
 #ifdef MOZ_X11
@@ -3940,28 +3942,30 @@ int XREMain::XRE_mainStartup(bool* aExit
       rv = mProfD->GetLeafName(leafName);
       if (NS_SUCCEEDED(rv)) {
         profileName = NS_ConvertUTF16toUTF8(leafName);
       }
     }
 
     mRemoteService->SetProfile(profileName);
 
-    // Try to remote the entire command line. If this fails, start up
-    // normally.
-    const char* desktopStartupIDPtr =
-        mDesktopStartupID.IsEmpty() ? nullptr : mDesktopStartupID.get();
-
-    RemoteResult rr = mRemoteService->StartClient(desktopStartupIDPtr);
-    if (rr == REMOTE_FOUND) {
-      *aExitFlag = true;
-      return 0;
-    }
-    if (rr == REMOTE_ARG_BAD) {
-      return 1;
+    if (!mDisableRemoteClient) {
+      // Try to remote the entire command line. If this fails, start up
+      // normally.
+      const char* desktopStartupIDPtr =
+          mDesktopStartupID.IsEmpty() ? nullptr : mDesktopStartupID.get();
+
+      RemoteResult rr = mRemoteService->StartClient(desktopStartupIDPtr);
+      if (rr == REMOTE_FOUND) {
+        *aExitFlag = true;
+        return 0;
+      }
+      if (rr == REMOTE_ARG_BAD) {
+        return 1;
+      }
     }
   }
 #endif
 
 #if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID)
   // Check for and process any available updates
   nsCOMPtr<nsIFile> updRoot;
   bool persistent;
@@ -4507,17 +4511,17 @@ nsresult XREMain::XRE_mainRun() {
 
     appStartup->GetShuttingDown(&mShuttingDown);
   }
 
   if (!mShuttingDown) {
 #if defined(MOZ_HAS_REMOTE)
     // if we have X remote support, start listening for requests on the
     // proxy window.
-    if (mRemoteService) {
+    if (mRemoteService && !mDisableRemoteServer) {
       mRemoteService->StartupServer();
       mRemoteService->UnlockStartup();
     }
 #endif /* MOZ_WIDGET_GTK */
 
     mNativeApp->Enable();
   }
 
@@ -4715,17 +4719,17 @@ int XREMain::XRE_main(int argc, char* ar
     // In particular we don't want to poison IO for checking late-writes.
     gShutdownChecks = SCM_NOTHING;
   }
 
 #if defined(MOZ_HAS_REMOTE)
   // Shut down the remote service. We must do this before calling LaunchChild
   // if we're restarting because otherwise the new instance will attempt to
   // remote to this instance.
-  if (mRemoteService) {
+  if (mRemoteService && !mDisableRemoteServer) {
     mRemoteService->ShutdownServer();
   }
 #endif /* MOZ_WIDGET_GTK */
 
   mScopedXPCOM = nullptr;
 
 #if defined(XP_WIN)
   mozilla::widget::StopAudioSession();
--- a/tools/tryselect/mach_commands.py
+++ b/tools/tryselect/mach_commands.py
@@ -267,17 +267,18 @@ class TrySelect(MachCommandBase):
         """Push tasks selected from a web interface to try.
 
         This selector will build the taskgraph and spin up a dynamically
         created 'trychooser-like' web-page on the localhost. After a selection
         has been made, pressing the 'Push' button will automatically push the
         selection to try.
         """
         self._activate_virtualenv()
-        self.virtualenv_manager.install_pip_package('flask')
+        path = os.path.join('tools', 'tryselect', 'selectors', 'chooser', 'requirements.txt')
+        self.virtualenv_manager.install_pip_requirements(path, quiet=True)
 
         return self.run(**kwargs)
 
     @SubCommand('try',
                 'again',
                 description='Schedule a previously generated (non try syntax) '
                             'push again.',
                 parser=get_parser('again'))
--- a/tools/tryselect/selectors/chooser/app.py
+++ b/tools/tryselect/selectors/chooser/app.py
@@ -179,12 +179,13 @@ def create_application(tg):
         if request.method == 'GET':
             return render_template('chooser.html', **context)
 
         if request.form['action'] == 'Push':
             labels = request.form['selected-tasks'].splitlines()
             app.tasks.extend(labels)
 
         shutdown = request.environ.get('werkzeug.server.shutdown')
-        shutdown()
+        if shutdown:
+            shutdown()
         return render_template('close.html')
 
     return app
new file mode 100644
--- /dev/null
+++ b/tools/tryselect/selectors/chooser/requirements.txt
@@ -0,0 +1,44 @@
+Flask==1.0.2 \
+    --hash=sha256:2271c0070dbcb5275fad4a82e29f23ab92682dc45f9dfbc22c02ba9b9322ce48 \
+    --hash=sha256:a080b744b7e345ccfcbc77954861cb05b3c63786e93f2b3875e0913d44b43f05
+click==7.0 \
+    --hash=sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13 \
+    --hash=sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7
+Werkzeug==0.14.1 \
+    --hash=sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c \
+    --hash=sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b
+itsdangerous==1.1.0 \
+    --hash=sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19 \
+    --hash=sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749
+Jinja2==2.10 \
+    --hash=sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd \
+    --hash=sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4
+MarkupSafe==1.1.1 \
+    --hash=sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473 \
+    --hash=sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161 \
+    --hash=sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235 \
+    --hash=sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5 \
+    --hash=sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff \
+    --hash=sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b \
+    --hash=sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1 \
+    --hash=sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e \
+    --hash=sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183 \
+    --hash=sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66 \
+    --hash=sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1 \
+    --hash=sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1 \
+    --hash=sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e \
+    --hash=sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b \
+    --hash=sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905 \
+    --hash=sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735 \
+    --hash=sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d \
+    --hash=sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e \
+    --hash=sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d \
+    --hash=sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c \
+    --hash=sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21 \
+    --hash=sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2 \
+    --hash=sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5 \
+    --hash=sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b \
+    --hash=sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6 \
+    --hash=sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f \
+    --hash=sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f \
+    --hash=sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7
--- a/tools/tryselect/test/conftest.py
+++ b/tools/tryselect/test/conftest.py
@@ -5,21 +5,38 @@
 from __future__ import absolute_import, print_function, unicode_literals
 
 import os
 
 import pytest
 import yaml
 from mock import MagicMock
 from moztest.resolve import TestResolver
+from taskgraph.graph import Graph
+from taskgraph.task import Task
+from taskgraph.taskgraph import TaskGraph
 
 from tryselect import push
 
 
 @pytest.fixture
+def tg(request):
+    if not hasattr(request.module, 'TASKS'):
+        pytest.fail("'tg' fixture used from a module that didn't define the TASKS variable")
+
+    tasks = request.module.TASKS
+    for task in tasks:
+        task.setdefault('task', {})
+        task['task'].setdefault('tags', {})
+
+    tasks = {t['label']: Task(**t) for t in tasks}
+    return TaskGraph(tasks, Graph(tasks.keys(), set()))
+
+
+@pytest.fixture
 def patch_resolver(monkeypatch):
     def inner(suites, tests):
         def fake_test_metadata(*args, **kwargs):
             return suites, tests
         monkeypatch.setattr(TestResolver, 'resolve_metadata', fake_test_metadata)
     return inner
 
 
--- a/tools/tryselect/test/python.ini
+++ b/tools/tryselect/test/python.ini
@@ -1,9 +1,11 @@
 [DEFAULT]
 subsuite=try
 skip-if = python == 3
 
 [test_again.py]
+[test_chooser.py]
+requirements = tools/tryselect/selectors/chooser/requirements.txt
 [test_fuzzy.py]
 [test_presets.py]
 [test_tasks.py]
 [test_templates.py]
new file mode 100644
--- /dev/null
+++ b/tools/tryselect/test/test_chooser.py
@@ -0,0 +1,79 @@
+# 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/.
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+import mozunit
+import pytest
+
+from tryselect.selectors.chooser.app import create_application
+
+
+TASKS = [
+    {
+        'kind': 'build',
+        'label': 'build-windows',
+        'attributes': {
+            'build_platform': 'windows',
+        },
+    },
+    {
+        'kind': 'test',
+        'label': 'test-windows-mochitest-e10s',
+        'attributes': {
+            'unittest_suite': 'mochitest',
+            'unittest_flavor': 'browser-chrome',
+            'mochitest_try_name': 'mochitest',
+        },
+    },
+]
+
+
+@pytest.fixture
+def app(tg):
+    app = create_application(tg)
+    app.config['TESTING'] = True
+
+    ctx = app.app_context()
+    ctx.push()
+    yield app
+    ctx.pop()
+
+
+def test_try_chooser(app):
+    client = app.test_client()
+
+    response = client.get('/')
+    assert response.status_code == 200
+
+    expected_output = [
+        """<title>Try Chooser Enhanced</title>""",
+        """<input class="filter" type="checkbox" id=windows name="build" value='{"build_platform": ["windows"]}' onchange="console.log('checkbox onchange triggered');apply();">""",  # noqa
+        """<input class="filter" type="checkbox" id=mochitest-browser-chrome name="test" value='{"unittest_flavor": ["browser-chrome"], "unittest_suite": ["mochitest"]}' onchange="console.log('checkbox onchange triggered');apply();">""",  # noqa
+    ]
+
+    for expected in expected_output:
+        assert expected in response.data
+
+    response = client.post('/', data={'action': 'Cancel'})
+    assert response.status_code == 200
+    assert "You may now close this page" in response.data
+    assert app.tasks == []
+
+    response = client.post('/', data={'action': 'Push', 'selected-tasks': ''})
+    assert response.status_code == 200
+    assert "You may now close this page" in response.data
+    assert app.tasks == []
+
+    response = client.post('/', data={
+        'action': 'Push',
+        'selected-tasks': 'build-windows\ntest-windows-mochitest-e10s'
+    })
+    assert response.status_code == 200
+    assert "You may now close this page" in response.data
+    assert set(app.tasks) == set(['build-windows', 'test-windows-mochitest-e10s'])
+
+
+if __name__ == '__main__':
+    mozunit.main()
--- a/tools/tryselect/test/test_presets.py
+++ b/tools/tryselect/test/test_presets.py
@@ -1,15 +1,46 @@
 # 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/.
 
 from __future__ import absolute_import, print_function, unicode_literals
 
 import mozunit
+import pytest
+
+
+TASKS = [
+    {
+        'kind': 'build',
+        'label': 'build-windows',
+        'attributes': {
+            'build_platform': 'windows',
+        },
+    },
+    {
+        'kind': 'test',
+        'label': 'test-windows-mochitest-e10s',
+        'attributes': {
+            'unittest_suite': 'mochitest',
+            'unittest_flavor': 'browser-chrome',
+            'mochitest_try_name': 'mochitest',
+        },
+    },
+]
+
+
+@pytest.fixture(autouse=True)
+def skip_taskgraph_generation(monkeypatch, tg):
+
+    def fake_generate_tasks(*args, **kwargs):
+        return tg
+
+    from tryselect import tasks
+    monkeypatch.setattr(tasks, 'generate_tasks', fake_generate_tasks)
 
 
 def test_shared_presets(run_mach, shared_name, shared_preset):
     """This test makes sure that we don't break any of the in-tree presets when
     renaming/removing variables in any of the selectors.
     """
     assert 'description' in shared_preset
     assert 'selector' in shared_preset
--- a/tools/tryselect/try_presets.yml
+++ b/tools/tryselect/try_presets.yml
@@ -14,16 +14,27 @@ debugger-tests:
     query:
         - "'debugger"
         - "'mozlint-eslint"
         - "!asan !pgo 'devtools"
         - "!android !asan !pgo 'mochitest-chrome | 'mochitest-clipboard-e10s"
         - "!asan !pgo 'linux64/ 'xpcshell"
         - "!pgo !qr !macosx 'damp"
 
+perf:
+    selector: fuzzy
+    description: >-
+        Runs all performance (raptor and talos) tasks across all platforms.
+        This preset can be filtered down further (e.g to limit it to a specific
+        platform) via |mach try --preset perf -xq "'windows"|.
+
+        Android hardware platforms are excluded due to resource limitations.
+    query:
+        - "^test- !android-hw 'raptor | 'talos"
+
 sample-suites:
     selector: fuzzy
     description: >-
         Runs one chunk of every test suite plus all suites that aren't chunked.
         It is useful for testing infrastructure changes that can affect the
         harnesses themselves but are unlikely to break specific tests.
     query:
         - ^test- -1$
--- a/uriloader/exthandler/HandlerService.js
+++ b/uriloader/exthandler/HandlerService.js
@@ -24,17 +24,17 @@ function HandlerService() {
 }
 
 HandlerService.prototype = {
 
   classID: Components.ID("{220cc253-b60f-41f6-b9cf-fdcb325f970f}"),
   QueryInterface: ChromeUtils.generateQI([
     Ci.nsISupportsWeakReference,
     Ci.nsIHandlerService,
-    Ci.nsIObserver
+    Ci.nsIObserver,
   ]),
 
   __store: null,
   get _store() {
     if (!this.__store) {
       this.__store = new JSONFile({
         path: OS.Path.join(OS.Constants.Path.profileDir, "handlers.json"),
         dataPostProcessor: this._dataPostProcessor.bind(this),
@@ -106,17 +106,16 @@ HandlerService.prototype = {
   _injectDefaultProtocolHandlers() {
     let schemesPrefBranch = Services.prefs.getBranch("gecko.handlerService.schemes.");
     let schemePrefList = schemesPrefBranch.getChildList("");
 
     let schemes = {};
 
     // read all the scheme prefs into a hash
     for (let schemePrefName of schemePrefList) {
-
       let [scheme, handlerNumber, attribute] = schemePrefName.split(".");
 
       try {
         let attrData =
           schemesPrefBranch.getComplexValue(schemePrefName,
                                             Ci.nsIPrefLocalizedString).data;
         if (!(scheme in schemes)) {
           schemes[scheme] = {};
@@ -135,17 +134,17 @@ HandlerService.prototype = {
 
       // cache the possible handlers to avoid extra xpconnect traversals.
       let possibleHandlers = protoInfo.possibleApplicationHandlers;
 
       for (let handlerNumber of Object.keys(schemes[scheme])) {
         let handlerApp = this.handlerAppFromSerializable(schemes[scheme][handlerNumber]);
         // If there is already a handler registered with the same template
         // URL, the newly added one will be ignored when saving.
-        possibleHandlers.appendElement(handlerApp, false);
+        possibleHandlers.appendElement(handlerApp);
       }
 
       this.store(protoInfo);
     }
   },
 
   /**
    * Execute any migrations. Migrations are defined here for any changes or removals for
@@ -259,27 +258,27 @@ HandlerService.prototype = {
       //
       // Note: our caller still needs to yield periodically when iterating
       // the enumerator and accessing handler properties to avoid monopolizing
       // the main thread.
       //
       let handler = new Proxy(
         {
           QueryInterface: ChromeUtils.generateQI([Ci.nsIHandlerInfo]),
-          type: type,
+          type,
           get _handlerInfo() {
             delete this._handlerInfo;
             return this._handlerInfo = gExternalProtocolService.getProtocolHandlerInfo(type);
           },
         },
         {
-          get: function(target, name) {
+          get(target, name) {
             return target[name] || target._handlerInfo[name];
           },
-          set: function(target, name, value) {
+          set(target, name, value) {
             target._handlerInfo[name] = value;
           },
         },
       );
       handlers.appendElement(handler);
     }
     return handlers.enumerate(Ci.nsIHandlerInfo);
   },
--- a/uriloader/exthandler/nsExternalProtocolHandler.cpp
+++ b/uriloader/exthandler/nsExternalProtocolHandler.cpp
@@ -401,17 +401,18 @@ NS_IMETHODIMP nsExtProtocolChannel::Noti
 
 NS_IMETHODIMP nsExtProtocolChannel::SetClassifierMatchedInfo(
     const nsACString &aList, const nsACString &aProvider,
     const nsACString &aFullHash) {
   // nothing to do
   return NS_OK;
 }
 
-NS_IMETHODIMP nsExtProtocolChannel::NotifyTrackingResource(bool aIsThirdParty) {
+NS_IMETHODIMP nsExtProtocolChannel::NotifyClassificationFlags(
+    uint32_t aClassificationFlags, bool aIsThirdParty) {
   // nothing to do
   return NS_OK;
 }
 
 NS_IMETHODIMP nsExtProtocolChannel::NotifyFlashPluginStateChanged(
     nsIHttpChannel::FlashPluginState aState) {
   // nothing to do
   return NS_OK;
new file mode 100644
--- /dev/null
+++ b/uriloader/exthandler/tests/mochitest/.eslintrc.js
@@ -0,0 +1,8 @@
+"use strict";
+
+module.exports = {
+  "extends": [
+    "plugin:mozilla/browser-test",
+    "plugin:mozilla/mochitest-test",
+  ]
+};
--- a/uriloader/exthandler/tests/mochitest/browser_auto_close_window.js
+++ b/uriloader/exthandler/tests/mochitest/browser_auto_close_window.js
@@ -15,22 +15,22 @@ const MOCK_HELPERAPP_DIALOG_CID =
 let registrar = Components.manager
                           .QueryInterface(Ci.nsIComponentRegistrar);
 let curDialogResolve = null;
 
 function HelperAppLauncherDialog() {
 }
 
 HelperAppLauncherDialog.prototype = {
-  show: function(aLauncher, aWindowContext, aReason) {
+  show(aLauncher, aWindowContext, aReason) {
     ok(true, "Showing the helper app dialog");
     curDialogResolve(aWindowContext);
     executeSoon(() => { aLauncher.cancel(Cr.NS_ERROR_ABORT); });
   },
-  QueryInterface: ChromeUtils.generateQI([Ci.nsIHelperAppLauncherDialog])
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIHelperAppLauncherDialog]),
 };
 
 function promiseHelperAppDialog() {
   return new Promise((resolve) => {
     curDialogResolve = resolve;
   });
 }
 
@@ -55,17 +55,16 @@ add_task(async function simple_navigatio
     is(windowContext, browser.ownerGlobal, "got the right windowContext");
   });
 });
 
 // Given a browser pointing to download_page.html, clicks on the link that
 // opens with target="_blank" (i.e. a new tab) and ensures that we
 // automatically open and close that tab.
 async function testNewTab(browser) {
-  let targetURL = browser.currentURI.spec;
   let dialogAppeared = promiseHelperAppDialog();
   let tabOpened = BrowserTestUtils.waitForEvent(gBrowser.tabContainer, "TabOpen").then((event) => {
     return [ event.target, BrowserTestUtils.waitForTabClosing(event.target) ];
   });
 
   await BrowserTestUtils.synthesizeMouseAtCenter("#target_blank", {}, browser);
 
   let windowContext = await dialogAppeared;
--- a/uriloader/exthandler/tests/mochitest/browser_web_protocol_handlers.js
+++ b/uriloader/exthandler/tests/mochitest/browser_web_protocol_handlers.js
@@ -24,17 +24,17 @@ add_task(async function() {
   is(protoInfo.preferredAction, protoInfo.useHelperApp,
      "using a helper application is the preferred action");
   ok(!protoInfo.preferredApplicationHandler, "no preferred handler is set");
   let handlers = protoInfo.possibleApplicationHandlers;
   is(1, handlers.length, "only one handler registered for web+testprotocol");
   let handler = handlers.queryElementAt(0, Ci.nsIHandlerApp);
   ok(handler instanceof Ci.nsIWebHandlerApp, "the handler is a web handler");
   is(handler.uriTemplate, "https://example.com/foobar?uri=%s",
-     "correct url template")
+     "correct url template");
   protoInfo.preferredApplicationHandler = handler;
   protoInfo.alwaysAskBeforeHandling = false;
   const handlerSvc = Cc["@mozilla.org/uriloader/handler-service;1"].
                        getService(Ci.nsIHandlerService);
   handlerSvc.store(protoInfo);
 
   // Middle-click a testprotocol link and check the new tab is correct
   let link = "#link";
--- a/uriloader/exthandler/tests/mochitest/handlerApp.xhtml
+++ b/uriloader/exthandler/tests/mochitest/handlerApp.xhtml
@@ -5,25 +5,24 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body onload="onLoad()">
 Pseudo Web Handler App
 
 <script class="testbody" type="text/javascript">
 <![CDATA[
 function onLoad() {
-
   // if we have a window.opener, this must be the windowContext
   // instance of this test.  check that we got the URI right and clean up.
   if (window.opener) {
-    window.opener.is(location.search, 
-                     "?uri=" + encodeURIComponent(window.opener.testURI), 
+    window.opener.is(location.search,
+                     "?uri=" + encodeURIComponent(window.opener.testURI),
                      "uri passed to web-handler app");
     window.opener.SimpleTest.finish();
-  } 
+  }
 
   window.close();
 }
 ]]>
 </script>
 
 </body>
 </html>
--- a/uriloader/exthandler/tests/mochitest/handlerApps.js
+++ b/uriloader/exthandler/tests/mochitest/handlerApps.js
@@ -3,63 +3,66 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // handlerApp.xhtml grabs this for verification purposes via window.opener
 var testURI = "webcal://127.0.0.1/rheeeeet.html";
 
 const Cc = SpecialPowers.Cc;
 
 function test() {
-
   // set up the web handler object
   var webHandler = Cc["@mozilla.org/uriloader/web-handler-app;1"].
     createInstance(SpecialPowers.Ci.nsIWebHandlerApp);
   webHandler.name = "Test Web Handler App";
   webHandler.uriTemplate =
-      "https://example.com/tests/uriloader/exthandler/tests/mochitest/" + 
+      "https://example.com/tests/uriloader/exthandler/tests/mochitest/" +
       "handlerApp.xhtml?uri=%s";
-  
+
   // set up the uri to test with
+  /* eslint-disable mozilla/use-services */
+
   var ioService = Cc["@mozilla.org/network/io-service;1"].
     getService(SpecialPowers.Ci.nsIIOService);
+
   var uri = ioService.newURI(testURI);
 
   // create a window, and launch the handler in it
   var newWindow = window.open("", "handlerWindow", "height=300,width=300");
   var windowContext = SpecialPowers.wrap(newWindow).docShell;
- 
+
   webHandler.launchWithURI(uri, windowContext);
 
   // if we get this far without an exception, we've at least partly passed
   // (remaining check in handlerApp.xhtml)
   ok(true, "webHandler launchWithURI (existing window/tab) started");
 
   // make the web browser launch in its own window/tab
   webHandler.launchWithURI(uri);
-  
+
   // if we get this far without an exception, we've passed
   ok(true, "webHandler launchWithURI (new window/tab) test started");
 
   // set up the local handler object
   var localHandler = Cc["@mozilla.org/uriloader/local-handler-app;1"].
     createInstance(SpecialPowers.Ci.nsILocalHandlerApp);
   localHandler.name = "Test Local Handler App";
-  
+
   // get a local app that we know will be there and do something sane
+  /* eslint-disable mozilla/use-services */
+
   var osString = Cc["@mozilla.org/xre/app-info;1"].
                  getService(SpecialPowers.Ci.nsIXULRuntime).OS;
 
   var dirSvc = Cc["@mozilla.org/file/directory_service;1"].
                getService(SpecialPowers.Ci.nsIDirectoryServiceProvider);
   if (osString == "WINNT") {
     var windowsDir = dirSvc.getFile("WinD", {});
     var exe = windowsDir.clone().QueryInterface(SpecialPowers.Ci.nsIFile);
     exe.appendRelativePath("SYSTEM32\\HOSTNAME.EXE");
-
-  } else if (osString == "Darwin") { 
+  } else if (osString == "Darwin") {
     var localAppsDir = dirSvc.getFile("LocApp", {});
     exe = localAppsDir.clone();
     exe.append("iCal.app"); // lingers after the tests finish, but this seems
                             // seems better than explicitly killing it, since
                             // developers who run the tests locally may well
                             // information in their running copy of iCal
 
     if (navigator.userAgent.match(/ SeaMonkey\//)) {
@@ -80,28 +83,27 @@ function test() {
   }
 
   localHandler.executable = exe;
   localHandler.launchWithURI(ioService.newURI(testURI));
 
   // if we get this far without an exception, we've passed
   ok(true, "localHandler launchWithURI test");
 
-  // if we ever decide that killing iCal is the right thing to do, change 
+  // if we ever decide that killing iCal is the right thing to do, change
   // the if statement below from "NOTDarwin" to "Darwin"
   if (osString == "NOTDarwin") {
-
     var killall = Cc["@mozilla.org/file/local;1"].
                   createInstance(SpecialPowers.Ci.nsIFile);
     killall.initWithPath("/usr/bin/killall");
-  
+
     var process = Cc["@mozilla.org/process/util;1"].
                   createInstance(SpecialPowers.Ci.nsIProcess);
     process.init(killall);
-    
-    var args = ['iCal'];
+
+    var args = ["iCal"];
     process.run(false, args, args.length);
   }
 
   SimpleTest.waitForExplicitFinish();
 }
 
 test();
--- a/uriloader/exthandler/tests/mochitest/head.js
+++ b/uriloader/exthandler/tests/mochitest/head.js
@@ -36,17 +36,17 @@ function createMockedObjects(createHandl
     let mockedHandlerApp = createMockedHandlerApp();
     internalMockedMIME.description = mockedHandlerApp.detailedDescription;
     internalMockedMIME.possibleApplicationHandlers.appendElement(mockedHandlerApp);
     internalMockedMIME.preferredApplicationHandler = mockedHandlerApp;
   }
 
   // Proxy for the mocked MIME info for faking the read-only attributes
   let mockedMIME = new Proxy(internalMockedMIME, {
-    get: function (target, property) {
+    get(target, property) {
       switch (property) {
       case "hasDefaultHandler":
         return true;
       case "defaultDescription":
         return "Default description";
       default:
         return target[property];
       }
@@ -63,17 +63,17 @@ function createMockedObjects(createHandl
     cancel() {},
     launchWithApplication() {},
     setWebProgressListener() {},
     saveDestinationAvailable() {},
     contentLength: 42,
     targetFile: null, // never read
     // PRTime is microseconds since epoch, Date.now() returns milliseconds:
     timeDownloadStarted: Date.now() * 1000,
-    QueryInterface: ChromeUtils.generateQI([Ci.nsICancelable, Ci.nsIHelperAppLauncher])
+    QueryInterface: ChromeUtils.generateQI([Ci.nsICancelable, Ci.nsIHelperAppLauncher]),
   };
 
   registerCleanupFunction(function() {
     // remove the mocked mime info from database.
     let mockHandlerInfo = gMimeSvc.getFromTypeAndExtension("text/x-test-handler", null);
     if (gHandlerSvc.exists(mockHandlerInfo)) {
       gHandlerSvc.remove(mockHandlerInfo);
     }
--- a/uriloader/exthandler/tests/mochitest/test_unknown_ext_protocol_handlers.html
+++ b/uriloader/exthandler/tests/mochitest/test_unknown_ext_protocol_handlers.html
@@ -17,12 +17,12 @@ window.onload = () => {
   try {
     testFrame.contentWindow.location.href = "unknownextproto:";
     ok(true, "There is no error reporting for unknown external protocol navigation.");
   } catch (e) {
     ok(false, "There should be no error reporting for unknown external protocol navigation.");
   }
 
   SimpleTest.finish();
-}
+};
 </script>
 </body>
 </html>
--- a/uriloader/exthandler/tests/mochitest/test_unsafeBidiChars.xhtml
+++ b/uriloader/exthandler/tests/mochitest/test_unsafeBidiChars.xhtml
@@ -11,17 +11,17 @@
 <script type="text/javascript">
 <![CDATA[
 
 var unsafeBidiChars = [
   "\xe2\x80\xaa", // LRE
   "\xe2\x80\xab", // RLE
   "\xe2\x80\xac", // PDF
   "\xe2\x80\xad", // LRO
-  "\xe2\x80\xae"  // RLO
+  "\xe2\x80\xae",  // RLO
 ];
 
 var tests = [
   "{1}.test",
   "{1}File.test",
   "Fi{1}le.test",
   "File{1}.test",
   "File.{1}test",
@@ -30,17 +30,17 @@ var tests = [
   "File.{1}",
 ];
 
 function replace(name, x) {
   return name.replace(/\{1\}/, x);
 }
 
 function sanitize(name) {
-  return replace(name, '_');
+  return replace(name, "_");
 }
 
 const INSECURE_REGISTER_PREF = "dom.registerProtocolHandler.insecure.enabled";
 
 add_task(async function() {
   SpecialPowers.setBoolPref(INSECURE_REGISTER_PREF, false);
   let url = SimpleTest.getTestFileURL("unsafeBidi_chromeScript.js");
   let chromeScript = SpecialPowers.loadChromeScript(url);
--- a/uriloader/exthandler/tests/mochitest/test_web_protocol_handlers.html
+++ b/uriloader/exthandler/tests/mochitest/test_web_protocol_handlers.html
@@ -10,17 +10,17 @@
 <p id="display"></p>
 <iframe id="test"></iframe>
 <script type="text/javascript">
 add_task(async function() {
   await SpecialPowers.pushPrefEnv({
     set: [
       ["dom.registerContentHandler.enabled", true],
       ["dom.registerProtocolHandler.insecure.enabled", false],
-    ]
+    ],
   });
 
   let result = "registerProtocolHandler" in navigator;
   ok(!result, "Insecure registerProtocolHandler is undefined");
 });
 </script>
 </body>
 </html>
--- a/uriloader/exthandler/tests/mochitest/unsafeBidi_chromeScript.js
+++ b/uriloader/exthandler/tests/mochitest/unsafeBidi_chromeScript.js
@@ -1,23 +1,23 @@
 const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 const HELPERAPP_DIALOG_CONTRACT = "@mozilla.org/helperapplauncherdialog;1";
 const HELPERAPP_DIALOG_CID =
   Components.ID(Cc[HELPERAPP_DIALOG_CONTRACT].number);
 
 const FAKE_CID = Cc["@mozilla.org/uuid-generator;1"].
                    getService(Ci.nsIUUIDGenerator).generateUUID();
-
+/* eslint-env mozilla/frame-script */
 function HelperAppLauncherDialog() {}
 HelperAppLauncherDialog.prototype = {
-  show: function(aLauncher, aWindowContext, aReason) {
+  show(aLauncher, aWindowContext, aReason) {
     sendAsyncMessage("suggestedFileName", aLauncher.suggestedFileName);
   },
-  QueryInterface: ChromeUtils.generateQI([Ci.nsIHelperAppLauncherDialog])
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIHelperAppLauncherDialog]),
 };
 
 var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
 registrar.registerFactory(FAKE_CID, "", HELPERAPP_DIALOG_CONTRACT,
                           XPCOMUtils._getFactory(HelperAppLauncherDialog));
 
 addMessageListener("unregister", function() {
   registrar.registerFactory(HELPERAPP_DIALOG_CID, "",
--- a/uriloader/exthandler/tests/unit/head.js
+++ b/uriloader/exthandler/tests/unit/head.js
@@ -32,17 +32,17 @@ let jsonPath = OS.Path.join(OS.Constants
  */
 let unloadHandlerStore = async function() {
   // If this function is called before the nsIHandlerService instance has been
   // initialized for the first time, the observer below will not be registered.
   // We have to force initialization to prevent the function from stalling.
   gHandlerService;
 
   let promise = TestUtils.topicObserved("handlersvc-json-replace-complete");
-  Services.obs.notifyObservers(null, "handlersvc-json-replace", null);
+  Services.obs.notifyObservers(null, "handlersvc-json-replace");
   await promise;
 };
 
 /**
  * Unloads the data store and deletes it.
  */
 let deleteHandlerStore = async function() {
   await unloadHandlerStore();
--- a/uriloader/exthandler/tests/unit/test_badMIMEType.js
+++ b/uriloader/exthandler/tests/unit/test_badMIMEType.js
@@ -6,24 +6,22 @@
 function run_test() {
   // "text/plain" has an 0xFF character appended to it.  This means it's an
   // invalid string, which is tricky to enter using a text editor (I used
   // emacs' hexl-mode).  It also means an ordinary text editor might drop it
   // or convert it to something that *is* valid (in UTF8).  So we measure
   // its length to make sure this hasn't happened.
   var badMimeType = "text/plainÿ";
   Assert.equal(badMimeType.length, 11);
-
   try {
-    var type = Cc["@mozilla.org/mime;1"].
-               getService(Ci.nsIMIMEService).
-               getFromTypeAndExtension(badMimeType, "txt");
+    Cc["@mozilla.org/mime;1"].
+      getService(Ci.nsIMIMEService).
+      getFromTypeAndExtension(badMimeType, "txt");
   } catch (e) {
     if (!(e instanceof Ci.nsIException) ||
         e.result != Cr.NS_ERROR_NOT_AVAILABLE) {
       throw e;
     }
     // This is an expected exception, thrown if the type can't be determined
-  } finally {
   }
   // Not crashing is good enough
   Assert.equal(true, true);
 }
--- a/uriloader/exthandler/tests/unit/test_getTypeFromExtension_ext_to_type_mapping.js
+++ b/uriloader/exthandler/tests/unit/test_getTypeFromExtension_ext_to_type_mapping.js
@@ -9,18 +9,17 @@
  * "ext-to-type-mapping" category if the provided extension is not lowercase.
  */
 function run_test() {
   // --- Common services ---
 
   const mimeService = Cc["@mozilla.org/mime;1"].
                       getService(Ci.nsIMIMEService);
 
-  const categoryManager = Cc["@mozilla.org/categorymanager;1"].
-                          getService(Ci.nsICategoryManager);
+  const categoryManager = Services.catMan;
 
   // --- Test procedure ---
 
   const kTestExtension          = "testextension";
   const kTestExtensionMixedCase = "testExtensIon";
   const kTestMimeType           = "application/x-testextension";
 
   // Ensure that the test extension is not initially recognized by the operating
--- a/uriloader/exthandler/tests/unit/test_getTypeFromExtension_with_empty_Content_Type.js
+++ b/uriloader/exthandler/tests/unit/test_getTypeFromExtension_with_empty_Content_Type.js
@@ -32,17 +32,17 @@ function run_test() {
    */
   function MockWindowsRegKey(aWrappedObject) {
     this._wrappedObject = aWrappedObject;
 
     // This function creates a forwarding function for wrappedObject
     function makeForwardingFunction(functionName) {
       return function() {
         return aWrappedObject[functionName].apply(aWrappedObject, arguments);
-      }
+      };
     }
 
     // Forward all the functions that are not explicitly overridden
     for (var propertyName in aWrappedObject) {
       if (!(propertyName in this)) {
         if (typeof aWrappedObject[propertyName] == "function") {
           this[propertyName] = makeForwardingFunction(propertyName);
         } else {
@@ -54,37 +54,37 @@ function run_test() {
 
   MockWindowsRegKey.prototype = {
     // --- Overridden nsISupports interface functions ---
 
     QueryInterface: ChromeUtils.generateQI([Ci.nsIWindowsRegKey]),
 
     // --- Overridden nsIWindowsRegKey interface functions ---
 
-    open: function(aRootKey, aRelPath, aMode) {
+    open(aRootKey, aRelPath, aMode) {
       // Remember the provided root key and path
       this._rootKey = aRootKey;
       this._relPath = aRelPath;
 
       // Create the actual registry key
       return this._wrappedObject.open(aRootKey, aRelPath, aMode);
     },
 
-    openChild: function(aRelPath, aMode) {
+    openChild(aRelPath, aMode) {
       // Open the child key and wrap it
       var innerKey = this._wrappedObject.openChild(aRelPath, aMode);
       var key = new MockWindowsRegKey(innerKey);
 
       // Set the properties of the child key and return it
       key._rootKey = this._rootKey;
       key._relPath = this._relPath + aRelPath;
       return key;
     },
 
-    createChild: function(aRelPath, aMode) {
+    createChild(aRelPath, aMode) {
       // Create the child key and wrap it
       var innerKey = this._wrappedObject.createChild(aRelPath, aMode);
       var key = new MockWindowsRegKey(innerKey);
 
       // Set the properties of the child key and return it
       key._rootKey = this._rootKey;
       key._relPath = this._relPath + aRelPath;
       return key;
@@ -93,52 +93,52 @@ function run_test() {
     get childCount() {
       return this._wrappedObject.childCount;
     },
 
     get valueCount() {
       return this._wrappedObject.valueCount;
     },
 
-    readStringValue: function(aName) {
+    readStringValue(aName) {
       // If this is the key under test, return a fake value
       if (this._rootKey == Ci.nsIWindowsRegKey.ROOT_KEY_CLASSES_ROOT &&
           this._relPath.toLowerCase() == ".txt" &&
           aName.toLowerCase() == "content type") {
         return "";
       }
 
       // Return the real value in the registry
       return this._wrappedObject.readStringValue(aName);
-    }
+    },
   };
 
   // --- Mock nsIWindowsRegKey factory ---
 
   var componentRegistrar = Components.manager.
                            QueryInterface(Ci.nsIComponentRegistrar);
 
   var originalWindowsRegKeyCID;
   var mockWindowsRegKeyFactory;
 
   const kMockCID = Components.ID("{9b23dfe9-296b-4740-ba1c-d39c9a16e55e}");
   const kWindowsRegKeyContractID = "@mozilla.org/windows-registry-key;1";
-  const kWindowsRegKeyClassName = "nsWindowsRegKey";
 
   function registerMockWindowsRegKeyFactory() {
     mockWindowsRegKeyFactory = {
-      createInstance: function(aOuter, aIid) {
+      createInstance(aOuter, aIid) {
         if (aOuter != null)
           throw Cr.NS_ERROR_NO_AGGREGATION;
-
+        // XXX Bug 1533719 - originalWindowsRegKeyFactory is undefined.
+        // eslint-disable-next-line no-undef
         var innerKey = originalWindowsRegKeyFactory.createInstance(null, aIid);
         var key = new MockWindowsRegKey(innerKey);
 
         return key.QueryInterface(aIid);
-      }
+      },
     };
 
     // Preserve the original factory
     originalWindowsRegKeyCID = Cc[kWindowsRegKeyContractID].number;
 
     // Register the mock factory
     componentRegistrar.registerFactory(
       kMockCID,
@@ -166,19 +166,19 @@ function run_test() {
 
   // --- Test procedure ---
 
   // Activate the override of the ".txt" file association data in the registry
   registerMockWindowsRegKeyFactory();
   try {
     // Try and get the MIME type associated with the extension. If this
     // operation does not throw an unexpected exception, the test succeeds.
-    var type = Cc["@mozilla.org/mime;1"].
-               getService(Ci.nsIMIMEService).
-               getTypeFromExtension(".txt");
+    Cc["@mozilla.org/mime;1"].
+      getService(Ci.nsIMIMEService).
+      getTypeFromExtension(".txt");
   } catch (e) {
     if (!(e instanceof Ci.nsIException) ||
         e.result != Cr.NS_ERROR_NOT_AVAILABLE) {
       throw e;
     }
     // This is an expected exception, thrown if the type can't be determined
   } finally {
     // Ensure we restore the original factory when the test is finished
--- a/uriloader/exthandler/tests/unit/test_handlerService.js
+++ b/uriloader/exthandler/tests/unit/test_handlerService.js
@@ -1,36 +1,32 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 function run_test() {
-  //**************************************************************************//
+  //* *************************************************************************//
   // Constants
 
   const handlerSvc = Cc["@mozilla.org/uriloader/handler-service;1"].
                      getService(Ci.nsIHandlerService);
 
   const mimeSvc = Cc["@mozilla.org/mime;1"].
                   getService(Ci.nsIMIMEService);
 
   const protoSvc = Cc["@mozilla.org/uriloader/external-protocol-service;1"].
                    getService(Ci.nsIExternalProtocolService);
-  
-  const prefSvc = Cc["@mozilla.org/preferences-service;1"].
-                  getService(Ci.nsIPrefService);
-                  
-  const ioService = Cc["@mozilla.org/network/io-service;1"].
-                    getService(Ci.nsIIOService);
+
+  const prefSvc = Services.prefs;
 
   const env = Cc["@mozilla.org/process/environment;1"].
               getService(Ci.nsIEnvironment);
 
   const rootPrefBranch = prefSvc.getBranch("");
-  
+
   let noMailto = false;
   if (mozinfo.os == "win") {
     // Check mailto handler from registry.
     // If registry entry is nothing, no mailto handler
     let regSvc = Cc["@mozilla.org/windows-registry-key;1"].
                  createInstance(Ci.nsIWindowsRegKey);
     try {
       regSvc.open(regSvc.ROOT_KEY_CLASSES_ROOT,
@@ -51,28 +47,28 @@ function run_test() {
     try {
       gIOSvc.getAppForURIScheme("mailto");
       noMailto = false;
     } catch (ex) {
       noMailto = true;
     }
   }
 
-  //**************************************************************************//
+  //* *************************************************************************//
   // Sample Data
 
   // It doesn't matter whether or not this nsIFile is actually executable,
   // only that it has a path and exists.  Since we don't know any executable
   // that exists on all platforms (except possibly the application being
   // tested, but there doesn't seem to be a way to get a reference to that
   // from the directory service), we use the temporary directory itself.
   var executable = Services.dirsvc.get("TmpD", Ci.nsIFile);
   // XXX We could, of course, create an actual executable in the directory:
-  //executable.append("localhandler");
-  //if (!executable.exists())
+  // executable.append("localhandler");
+  // if (!executable.exists())
   //  executable.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o755);
 
   var localHandler = Cc["@mozilla.org/uriloader/local-handler-app;1"].
                      createInstance(Ci.nsILocalHandlerApp);
   localHandler.name = "Local Handler";
   localHandler.executable = executable;
 
   var webHandler = Cc["@mozilla.org/uriloader/web-handler-app;1"].
@@ -80,17 +76,17 @@ function run_test() {
   webHandler.name = "Web Handler";
   webHandler.uriTemplate = "http://www.example.com/?%s";
 
   // FIXME: these tests create and manipulate enough variables that it would
   // make sense to move each test into its own scope so we don't run the risk
   // of one test stomping on another's data.
 
 
-  //**************************************************************************//
+  //* *************************************************************************//
   // Test Default Properties
 
   // Get a handler info for a MIME type that neither the application nor
   // the OS knows about and make sure its properties are set to the proper
   // default values.
 
   var handlerInfo = mimeSvc.getFromTypeAndExtension("nonexistent/type", null);
 
@@ -111,46 +107,46 @@ function run_test() {
   // These properties are initialized to default values by the service,
   // so we might as well make sure they're initialized to the right defaults.
   Assert.equal(handlerInfo.description, "");
   Assert.equal(handlerInfo.hasDefaultHandler, false);
   Assert.equal(handlerInfo.defaultDescription, "");
 
   // test some default protocol info properties
   var haveDefaultHandlersVersion = false;
-  try { 
+  try {
     // If we have a defaultHandlersVersion pref, then assume that we're in the
     // firefox tree and that we'll also have default handlers.
     // Bug 395131 has been filed to make this test work more generically
     // by providing our own prefs for this test rather than this icky
     // special casing.
     rootPrefBranch.getCharPref("gecko.handlerService.defaultHandlersVersion");
     haveDefaultHandlersVersion = true;
   } catch (ex) {}
 
-  const kExternalWarningDefault = 
+  const kExternalWarningDefault =
     "network.protocol-handler.warn-external-default";
   prefSvc.setBoolPref(kExternalWarningDefault, true);
 
   // XXX add more thorough protocol info property checking
-  
+
   // no OS default handler exists
   var protoInfo = protoSvc.getProtocolHandlerInfo("x-moz-rheet");
   Assert.equal(protoInfo.preferredAction, protoInfo.alwaysAsk);
   Assert.ok(protoInfo.alwaysAskBeforeHandling);
-  
-  // OS default exists, injected default does not exist, 
+
+  // OS default exists, injected default does not exist,
   // explicit warning pref: false
   const kExternalWarningPrefPrefix = "network.protocol-handler.warn-external.";
   prefSvc.setBoolPref(kExternalWarningPrefPrefix + "http", false);
   protoInfo = protoSvc.getProtocolHandlerInfo("http");
   Assert.equal(0, protoInfo.possibleApplicationHandlers.length);
   Assert.ok(!protoInfo.alwaysAskBeforeHandling);
-  
-  // OS default exists, injected default does not exist, 
+
+  // OS default exists, injected default does not exist,
   // explicit warning pref: true
   prefSvc.setBoolPref(kExternalWarningPrefPrefix + "http", true);
   protoInfo = protoSvc.getProtocolHandlerInfo("http");
   // OS handler isn't included in possibleApplicationHandlers, so length is 0
   // Once they become instances of nsILocalHandlerApp, this number will need
   // to change.
   Assert.equal(0, protoInfo.possibleApplicationHandlers.length);
   Assert.ok(protoInfo.alwaysAskBeforeHandling);
@@ -178,17 +174,16 @@ function run_test() {
     // alwaysAskBeforeHandling is expected to be false here, because although
     // the pref is true, the value in RDF is false. The injected mailto handler
     // carried over the default pref value, and so when we set the pref above
     // to true it's ignored.
     if (noMailto)
       Assert.ok(protoInfo.alwaysAskBeforeHandling);
     else
       Assert.ok(!protoInfo.alwaysAskBeforeHandling);
-
   } else {
     Assert.equal(0, protoInfo.possibleApplicationHandlers.length);
     Assert.ok(protoInfo.alwaysAskBeforeHandling);
   }
 
   if (haveDefaultHandlersVersion) {
     // Now set the value stored in RDF to true, and the pref to false, to make
     // sure we still get the right value. (Basically, same thing as above but
@@ -197,17 +192,17 @@ function run_test() {
     protoInfo.alwaysAskBeforeHandling = true;
     handlerSvc.store(protoInfo);
     protoInfo = protoSvc.getProtocolHandlerInfo("mailto");
     Assert.equal(2, protoInfo.possibleApplicationHandlers.length);
     Assert.ok(protoInfo.alwaysAskBeforeHandling);
   }
 
 
-  //**************************************************************************//
+  //* *************************************************************************//
   // Test Round-Trip Data Integrity
 
   // Test round-trip data integrity by setting the properties of the handler
   // info object to different values, telling the handler service to store the
   // object, and then retrieving a new info object for the same type and making
   // sure its properties are identical.
 
   handlerInfo.preferredAction = Ci.nsIHandlerInfo.useHelperApp;
@@ -239,20 +234,19 @@ function run_test() {
     handlerTypes.push("irc");
     handlerTypes.push("ircs");
   }
   for (let handler of handlerSvc.enumerate()) {
     Assert.notEqual(handlerTypes.indexOf(handler.type), -1);
     handlerTypes.splice(handlerTypes.indexOf(handler.type), 1);
   }
   Assert.equal(handlerTypes.length, 0);
-
   // Make sure the handler service's remove method removes a handler record.
   handlerSvc.remove(handlerInfo2);
-  handlers = handlerSvc.enumerate();
+  let handlers = handlerSvc.enumerate();
   while (handlers.hasMoreElements())
     Assert.notEqual(handlers.getNext().QueryInterface(Ci.nsIHandlerInfo).type,
                     handlerInfo2.type);
 
   // Make sure we can store and retrieve a handler info object with no preferred
   // handler.
   var noPreferredHandlerInfo =
     mimeSvc.getFromTypeAndExtension("nonexistent/no-preferred-handler", null);
@@ -333,17 +327,17 @@ function run_test() {
   Assert.equal(possibleHandlersInfo.possibleApplicationHandlers.length, 1);
 
   // Make sure the handler is the one we didn't remove.
   webPossibleHandler = possibleHandlersInfo.possibleApplicationHandlers.
                        queryElementAt(0, Ci.nsIWebHandlerApp);
   Assert.equal(webPossibleHandler.name, webHandler.name);
   Assert.ok(webPossibleHandler.equals(webHandler));
 
-  //////////////////////////////////////////////////////
+  // ////////////////////////////////////////////////////
   // handler info command line parameters and equality
   var localApp = Cc["@mozilla.org/uriloader/local-handler-app;1"].
                  createInstance(Ci.nsILocalHandlerApp);
   var handlerApp = localApp.QueryInterface(Ci.nsIHandlerApp);
 
   Assert.ok(handlerApp.equals(localApp));
 
   localApp.executable = executable;
@@ -356,17 +350,17 @@ function run_test() {
   Assert.ok(localApp.parameterExists("-test1"));
   Assert.ok(localApp.parameterExists("-test2"));
   Assert.ok(!localApp.parameterExists("-false"));
   localApp.clearParameters();
   Assert.equal(0, localApp.parameterCount);
 
   var localApp2 = Cc["@mozilla.org/uriloader/local-handler-app;1"].
                   createInstance(Ci.nsILocalHandlerApp);
-  
+
   localApp2.executable = executable;
 
   localApp.clearParameters();
   Assert.ok(localApp.equals(localApp2));
 
   // equal:
   // cut -d 1 -f 2
   // cut -d 1 -f 2
@@ -390,27 +384,27 @@ function run_test() {
   localApp.appendParameter("-test2");
   localApp.appendParameter("-test3");
   localApp2.appendParameter("-test2");
   localApp2.appendParameter("-test1");
   localApp2.appendParameter("-test3");
   Assert.ok(!localApp2.equals(localApp));
 
   var str;
-  str = localApp.getParameter(0)
+  str = localApp.getParameter(0);
   Assert.equal(str, "-test1");
-  str = localApp.getParameter(1)
+  str = localApp.getParameter(1);
   Assert.equal(str, "-test2");
-  str = localApp.getParameter(2)
+  str = localApp.getParameter(2);
   Assert.equal(str, "-test3");
 
   // FIXME: test round trip integrity for a protocol.
   // FIXME: test round trip integrity for a handler info with a web handler.
 
-  //**************************************************************************//
+  //* *************************************************************************//
   // getTypeFromExtension tests
 
   // test nonexistent extension
   var lolType = handlerSvc.getTypeFromExtension("lolcat");
   Assert.equal(lolType, "");
 
 
   // add a handler for the extension
@@ -428,14 +422,14 @@ function run_test() {
   Assert.ok(handlerSvc.exists(lolHandler));
 
   // test now-existent extension
   lolType = handlerSvc.getTypeFromExtension("lolcat");
   Assert.equal(lolType, "application/lolcat");
 
   // test mailcap entries with needsterminal are ignored on non-Windows non-Mac.
   if (mozinfo.os != "win" && mozinfo.os != "mac") {
-    env.set('PERSONAL_MAILCAP', do_get_file('mailcap').path);
+    env.set("PERSONAL_MAILCAP", do_get_file("mailcap").path);
     handlerInfo = mimeSvc.getFromTypeAndExtension("text/plain", null);
     Assert.equal(handlerInfo.preferredAction, Ci.nsIHandlerInfo.useSystemDefault);
     Assert.equal(handlerInfo.defaultDescription, "sed");
   }
 }
--- a/uriloader/exthandler/tests/unit/test_handlerService_store.js
+++ b/uriloader/exthandler/tests/unit/test_handlerService_store.js
@@ -87,20 +87,20 @@ function assertAllHandlerInfosMatchTestD
     alwaysAskBeforeHandling: true,
     preferredApplicationHandler: {
       name: "Example Default Handler",
       uriTemplate: "https://www.example.com/?url=%s",
     },
     possibleApplicationHandlers: [{
       name: "Example Default Handler",
       uriTemplate: "https://www.example.com/?url=%s",
-    },{
+    }, {
       name: "Example Possible Handler One",
       uriTemplate: "http://www.example.com/?id=1&url=%s",
-    },{
+    }, {
       name: "Example Possible Handler Two",
       uriTemplate: "http://www.example.com/?id=2&url=%s",
     }],
     fileExtensions: [
       "example_two",
       "example_three",
     ],
   });
@@ -121,20 +121,20 @@ function assertAllHandlerInfosMatchTestD
     alwaysAskBeforeHandling: true,
     preferredApplicationHandler: {
       name: "Example Default Handler",
       uriTemplate: "https://www.example.com/?url=%s",
     },
     possibleApplicationHandlers: [{
       name: "Example Default Handler",
       uriTemplate: "https://www.example.com/?url=%s",
-    },{
+    }, {
       name: "Example Possible Handler One",
       uriTemplate: "http://www.example.com/?id=1&url=%s",
-    },{
+    }, {
       name: "Example Possible Handler Two",
       uriTemplate: "http://www.example.com/?id=2&url=%s",
     }],
   });
 
   HandlerServiceTestUtils.assertHandlerInfoMatches(handlerInfos.shift(), {
     type: "examplescheme.usesystemdefault",
     preferredAction: Ci.nsIHandlerInfo.useSystemDefault,
@@ -461,17 +461,17 @@ add_task(async function test_store_delet
   let actualHandlerInfo =
       HandlerServiceTestUtils.getHandlerInfo("example/type.savetodisk");
   HandlerServiceTestUtils.assertHandlerInfoMatches(actualHandlerInfo, {
     type: "example/type.savetodisk",
     preferredAction: Ci.nsIHandlerInfo.saveToDisk,
     alwaysAskBeforeHandling: false,
     fileExtensions: [
       "example_two",
-      "example_three"
+      "example_three",
     ],
   });
 });
 
 /**
  * Tests the "overrideType" argument of "fillHandlerInfo".
  */
 add_task(async function test_fillHandlerInfo_overrideType() {
@@ -532,17 +532,17 @@ function assertAllHandlerInfosMatchDefau
   }
 
   HandlerServiceTestUtils.assertHandlerInfoMatches(handlerInfos.shift(), {
     type: "mailto",
     preferredActionOSDependent: true,
     possibleApplicationHandlers: [{
       name: "Yahoo! Mail",
       uriTemplate: "https://compose.mail.yahoo.com/?To=%s",
-    },{
+    }, {
       name: "Gmail",
       uriTemplate: "https://mail.google.com/mail/?extsrc=mailto&url=%s",
     }],
   });
 
   Assert.equal(handlerInfos.length, 0);
 }
 
--- a/uriloader/exthandler/tests/unit/test_punycodeURIs.js
+++ b/uriloader/exthandler/tests/unit/test_punycodeURIs.js
@@ -17,18 +17,17 @@ function checkFile() {
   // This is where we expect the output
   var tempFile = tempDir.clone();
   tempFile.append(kOutputFile);
 
   if (!tempFile.exists()) {
     if (gCheckExistsAttempts >= kMaxCheckExistAttempts) {
       do_throw("Expected File " + tempFile.path + " does not exist after " +
                  kMaxCheckExistAttempts + " seconds");
-    }
-    else {
+    } else {
       ++gCheckExistsAttempts;
       // Wait a bit longer then try again
       do_timeout(1000, checkFile);
       return;
     }
   }
 
   // Now read it
@@ -59,24 +58,22 @@ function checkFile() {
   if (data.substring(0, 7) != "-psn_0_")
     Assert.equal(data, kExpectedURI);
 
   do_test_finished();
 }
 
 function run_test() {
   if (mozinfo.os == "mac") {
-    dump("INFO | test_punycodeURIs.js | Skipping test on mac, bug 599475")
+    dump("INFO | test_punycodeURIs.js | Skipping test on mac, bug 599475");
     return;
   }
 
   // set up the uri to test with
-  var ioService =
-    Cc["@mozilla.org/network/io-service;1"]
-      .getService(Ci.nsIIOService);
+  var ioService = Services.io;
 
   // set up the local handler object
   var localHandler =
     Cc["@mozilla.org/uriloader/local-handler-app;1"]
       .createInstance(Ci.nsILocalHandlerApp);
   localHandler.name = "Test Local Handler App";
 
   // WriteArgument will just dump its arguments to a file for us.
@@ -102,17 +99,17 @@ function run_test() {
   // The Write Argument file needs to know where its libraries are, so
   // just force the path variable
   // For mac
   var greDir = Services.dirsvc.get("GreD", Ci.nsIFile);
 
   envSvc.set("DYLD_LIBRARY_PATH", greDir.path);
   // For Linux
   envSvc.set("LD_LIBRARY_PATH", greDir.path);
-  //XXX: handle windows
+  // XXX: handle windows
 
   // Now tell it where we want the file.
   envSvc.set("WRITE_ARGUMENT_FILE", outFile.path);
 
   var uri = ioService.newURI(kTestURI);
 
   // Just check we've got these matching, if we haven't there's a problem
   // with ascii spec or our test case.