Merge mozilla-central to inbound. a=merge CLOSED TREE
authorGurzau Raul <rgurzau@mozilla.com>
Sat, 08 Dec 2018 23:38:27 +0200
changeset 508911 e9ea0dbc015be66d996deeb7c6e71088488dcea1
parent 508910 387f770bf58c175b69b5803b3c0d4a7ea55d18c4 (current diff)
parent 508879 09493e80dbe7c1486eb3c93960cc81f73c8c5356 (diff)
child 508912 a24d661d8362f388f002a47b3a0d18a265590b65
push id1905
push userffxbld-merge
push dateMon, 21 Jan 2019 12:33:13 +0000
treeherdermozilla-release@c2fca1944d8c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone65.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 inbound. a=merge CLOSED TREE
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1516,16 +1516,17 @@ pref("dom.storage_access.enabled", true)
 
 pref("dom.storage_access.auto_grants", true);
 pref("dom.storage_access.max_concurrent_auto_grants", 5);
 
 // Define a set of default features for the Content Blocking UI.
 pref("browser.contentblocking.trackingprotection.control-center.ui.enabled", true);
 pref("browser.contentblocking.rejecttrackers.control-center.ui.enabled", true);
 
+pref("browser.contentblocking.control-center.ui.showBlockedLabels", false);
 pref("browser.contentblocking.control-center.ui.showAllowedLabels", false);
 
 // Enable the Report Breakage UI on Nightly and Beta but not on Release yet.
 #ifdef EARLY_BETA_OR_EARLIER
 pref("browser.contentblocking.reportBreakage.enabled", true);
 #else
 pref("browser.contentblocking.reportBreakage.enabled", false);
 #endif
--- a/browser/base/content/browser-contentblocking.js
+++ b/browser/base/content/browser-contentblocking.js
@@ -73,17 +73,17 @@ var TrackingProtection = {
     this.enabledInPrivateWindows =
       Services.prefs.getBoolPref(this.PREF_ENABLED_IN_PRIVATE_WINDOWS);
     this.updateCategoryLabel();
   },
 
   updateCategoryLabel() {
     let label;
     if (this.enabled) {
-      label = "contentBlocking.trackers.blocked.label";
+      label = ContentBlocking.showBlockedLabels ? "contentBlocking.trackers.blocking.label" : null;
     } else {
       label = ContentBlocking.showAllowedLabels ? "contentBlocking.trackers.allowed.label" : null;
     }
     this.categoryLabel.textContent = label ? gNavigatorBundle.getString(label) : "";
   },
 
   isBlocking(state) {
     return (state & Ci.nsIWebProgressListener.STATE_BLOCKED_TRACKING_CONTENT) != 0;
@@ -110,16 +110,41 @@ var TrackingProtection = {
     let fragment = document.createDocumentFragment();
     for (let [origin, actions] of Object.entries(contentBlockingLog)) {
       let listItem = await this._createListItem(origin, actions);
       if (listItem) {
         fragment.appendChild(listItem);
       }
     }
 
+    // If we don't have trackers we would usually not show the menu item
+    // allowing the user to show the sub-panel. However, in the edge case
+    // that we annotated trackers on the page using the strict list but did
+    // not detect trackers on the page using the basic list, we currently
+    // still show the panel. To reduce the confusion, tell the user that we have
+    // not detected any tracker.
+    if (fragment.childNodes.length == 0) {
+      let emptyBox = document.createXULElement("vbox");
+      let emptyImage = document.createXULElement("image");
+      emptyImage.classList.add("identity-popup-content-blocking-trackersView-empty-image");
+      emptyImage.classList.add("tracking-protection-icon");
+
+      let emptyLabel = document.createXULElement("label");
+      emptyLabel.classList.add("identity-popup-content-blocking-empty-label");
+      emptyLabel.textContent = gNavigatorBundle.getString("contentBlocking.trackersView.empty.label");
+
+      emptyBox.appendChild(emptyImage);
+      emptyBox.appendChild(emptyLabel);
+      fragment.appendChild(emptyBox);
+
+      this.subViewList.classList.add("empty");
+    } else {
+      this.subViewList.classList.remove("empty");
+    }
+
     // This might have taken a while. Only update the list if we're still on the same page.
     if (previousURI == gBrowser.currentURI.spec &&
         previousWindow == gBrowser.selectedBrowser.innerWindowID) {
       this.subViewList.textContent = "";
       this.subViewList.append(fragment);
     }
   },
 
@@ -246,26 +271,26 @@ var ThirdPartyCookies = {
       return "cookierestrictions";
     }
   },
 
   updateCategoryLabel() {
     let label;
     switch (this.behaviorPref) {
     case Ci.nsICookieService.BEHAVIOR_REJECT_FOREIGN:
-      label = "contentBlocking.cookies.3rdPartyBlocked.label";
+      label = ContentBlocking.showBlockedLabels ? "contentBlocking.cookies.blocking3rdParty.label" : null;
       break;
     case Ci.nsICookieService.BEHAVIOR_REJECT:
-      label = "contentBlocking.cookies.allBlocked.label";
+      label = ContentBlocking.showBlockedLabels ? "contentBlocking.cookies.blockingAll.label" : null;
       break;
     case Ci.nsICookieService.BEHAVIOR_LIMIT_FOREIGN:
-      label = "contentBlocking.cookies.unvisitedBlocked.label";
+      label = ContentBlocking.showBlockedLabels ? "contentBlocking.cookies.blockingUnvisited.label" : null;
       break;
     case Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER:
-      label = "contentBlocking.cookies.trackersBlocked.label";
+      label = ContentBlocking.showBlockedLabels ? "contentBlocking.cookies.blockingTrackers.label" : null;
       break;
     default:
       Cu.reportError(`Error: Unknown cookieBehavior pref observed: ${this.behaviorPref}`);
       // fall through
     case Ci.nsICookieService.BEHAVIOR_ACCEPT:
       label = ContentBlocking.showAllowedLabels ? "contentBlocking.cookies.allowed.label" : null;
       break;
     }
@@ -299,27 +324,36 @@ var ThirdPartyCookies = {
     let contentBlockingLogJSON = await gBrowser.selectedBrowser.getContentBlockingLog();
     let contentBlockingLog = JSON.parse(contentBlockingLogJSON);
 
     let categories = this._processContentBlockingLog(contentBlockingLog);
 
     this.subViewList.textContent = "";
 
     for (let category of ["firstParty", "trackers", "thirdParty"]) {
-      if (categories[category].length) {
-        let box = document.createXULElement("vbox");
-        let label = document.createXULElement("label");
-        label.className = "identity-popup-cookiesView-list-header";
-        label.textContent = gNavigatorBundle.getString(`contentBlocking.cookiesView.${category}.label`);
-        box.appendChild(label);
-        for (let info of categories[category]) {
-          box.appendChild(this._createListItem(info));
-        }
-        this.subViewList.appendChild(box);
+      let box = document.createXULElement("vbox");
+      let label = document.createXULElement("label");
+      label.className = "identity-popup-cookiesView-list-header";
+      label.textContent = gNavigatorBundle.getString(`contentBlocking.cookiesView.${category}.label`);
+      box.appendChild(label);
+
+      for (let info of categories[category]) {
+        box.appendChild(this._createListItem(info));
       }
+
+      // If the category is empty, add a label noting that to the user.
+      if (categories[category].length == 0) {
+        let emptyLabel = document.createXULElement("label");
+        emptyLabel.classList.add("identity-popup-content-blocking-empty-label");
+        emptyLabel.textContent =
+          gNavigatorBundle.getString(`contentBlocking.cookiesView.${category}.empty.label`);
+        box.appendChild(emptyLabel);
+      }
+
+      this.subViewList.appendChild(box);
     }
   },
 
   _hasException(origin) {
     for (let perm of Services.perms.getAllForPrincipal(gBrowser.contentPrincipal)) {
       if (perm.type == "3rdPartyStorage^" + origin || perm.type.startsWith("3rdPartyStorage^" + origin + "^")) {
         return true;
       }
@@ -484,16 +518,17 @@ var ContentBlocking = {
   // If the user ignores the doorhanger, we stop showing it after some time.
   MAX_INTROS: 20,
   PREF_ANIMATIONS_ENABLED: "toolkit.cosmeticAnimations.enabled",
   PREF_REPORT_BREAKAGE_ENABLED: "browser.contentblocking.reportBreakage.enabled",
   PREF_REPORT_BREAKAGE_URL: "browser.contentblocking.reportBreakage.url",
   PREF_INTRO_COUNT_CB: "browser.contentblocking.introCount",
   PREF_CB_CATEGORY: "browser.contentblocking.category",
   PREF_SHOW_ALLOWED_LABELS: "browser.contentblocking.control-center.ui.showAllowedLabels",
+  PREF_SHOW_BLOCKED_LABELS: "browser.contentblocking.control-center.ui.showBlockedLabels",
   content: null,
   icon: null,
   activeTooltipText: null,
   disabledTooltipText: null,
 
   get prefIntroCount() {
     return this.PREF_INTRO_COUNT_CB;
   },
@@ -541,27 +576,27 @@ var ContentBlocking = {
     } catch (e) {
       // Getting the hostPort for about: and file: URIs fails, but TP doesn't work with
       // these URIs anyway, so just return null here.
       return null;
     }
   },
 
   init() {
-    let $ = selector => document.querySelector(selector);
-    this.content = $("#identity-popup-content-blocking-content");
-    this.icon = $("#tracking-protection-icon");
-    this.iconBox = $("#tracking-protection-icon-box");
-    this.animatedIcon = $("#tracking-protection-icon-animatable-image");
+    let $ = id => document.getElementById(id);
+    this.content = $("identity-popup-content-blocking-content");
+    this.icon = $("tracking-protection-icon");
+    this.iconBox = $("tracking-protection-icon-box");
+    this.animatedIcon = $("tracking-protection-icon-animatable-image");
     this.animatedIcon.addEventListener("animationend", () => this.iconBox.removeAttribute("animate"));
 
-    this.identityPopupMultiView = $("#identity-popup-multiView");
-    this.reportBreakageButton = $("#identity-popup-content-blocking-report-breakage");
-    this.reportBreakageURL = $("#identity-popup-breakageReportView-collection-url");
-    this.reportBreakageLearnMore = $("#identity-popup-breakageReportView-learn-more");
+    this.identityPopupMultiView = $("identity-popup-multiView");
+    this.reportBreakageButton = $("identity-popup-content-blocking-report-breakage");
+    this.reportBreakageURL = $("identity-popup-breakageReportView-collection-url");
+    this.reportBreakageLearnMore = $("identity-popup-breakageReportView-learn-more");
 
     let baseURL = Services.urlFormatter.formatURLPref("app.support.baseURL");
     this.reportBreakageLearnMore.href = baseURL + "blocking-breakage";
 
     this.updateAnimationsEnabled = () => {
       this.iconBox.toggleAttribute("animationsenabled",
         Services.prefs.getBoolPref(this.PREF_ANIMATIONS_ENABLED, false));
     };
@@ -571,16 +606,22 @@ var ContentBlocking = {
         blocker.init();
       }
     }
 
     this.updateAnimationsEnabled();
 
     Services.prefs.addObserver(this.PREF_ANIMATIONS_ENABLED, this.updateAnimationsEnabled);
 
+    XPCOMUtils.defineLazyPreferenceGetter(this, "showBlockedLabels",
+      this.PREF_SHOW_BLOCKED_LABELS, false, () => {
+        for (let blocker of this.blockers) {
+          blocker.updateCategoryLabel();
+        }
+    });
     XPCOMUtils.defineLazyPreferenceGetter(this, "showAllowedLabels",
       this.PREF_SHOW_ALLOWED_LABELS, false, () => {
         for (let blocker of this.blockers) {
           blocker.updateCategoryLabel();
         }
     });
     XPCOMUtils.defineLazyPreferenceGetter(this, "reportBreakageEnabled",
       this.PREF_REPORT_BREAKAGE_ENABLED, false);
--- a/browser/base/content/test/trackingUI/browser_trackingUI_categories.js
+++ b/browser/base/content/test/trackingUI/browser_trackingUI_categories.js
@@ -65,27 +65,30 @@ add_task(async function testCategoryLabe
     await TestUtils.waitForCondition(() => appMenuCategoryLabel.value ==
       gNavigatorBundle.getString("contentBlocking.category.custom"));
     is(appMenuCategoryLabel.value, gNavigatorBundle.getString("contentBlocking.category.custom"),
       "The appMenuCategory label has been changed to custom");
   });
 });
 
 add_task(async function testSubcategoryLabels() {
-  SpecialPowers.pushPrefEnv({set: [["browser.contentblocking.control-center.ui.showAllowedLabels", true]]});
+  SpecialPowers.pushPrefEnv({set: [
+    ["browser.contentblocking.control-center.ui.showAllowedLabels", true],
+    ["browser.contentblocking.control-center.ui.showBlockedLabels", true],
+  ]});
 
   await BrowserTestUtils.withNewTab("http://www.example.com", async function() {
     let categoryLabel =
       document.getElementById("identity-popup-content-blocking-tracking-protection-state-label");
 
     Services.prefs.setBoolPref(TP_PREF, true);
     await TestUtils.waitForCondition(() => categoryLabel.textContent ==
-      gNavigatorBundle.getString("contentBlocking.trackers.blocked.label"),
+      gNavigatorBundle.getString("contentBlocking.trackers.blocking.label"),
       "The category label has updated correctly");
-    is(categoryLabel.textContent, gNavigatorBundle.getString("contentBlocking.trackers.blocked.label"));
+    is(categoryLabel.textContent, gNavigatorBundle.getString("contentBlocking.trackers.blocking.label"));
 
     Services.prefs.setBoolPref(TP_PREF, false);
     await TestUtils.waitForCondition(() => categoryLabel.textContent ==
       gNavigatorBundle.getString("contentBlocking.trackers.allowed.label"),
       "The category label has updated correctly");
     is(categoryLabel.textContent, gNavigatorBundle.getString("contentBlocking.trackers.allowed.label"));
 
     categoryLabel =
@@ -94,31 +97,31 @@ add_task(async function testSubcategoryL
     Services.prefs.setIntPref(TPC_PREF, Ci.nsICookieService.BEHAVIOR_ACCEPT);
     await TestUtils.waitForCondition(() => categoryLabel.textContent ==
       gNavigatorBundle.getString("contentBlocking.cookies.allowed.label"),
       "The category label has updated correctly");
     is(categoryLabel.textContent, gNavigatorBundle.getString("contentBlocking.cookies.allowed.label"));
 
     Services.prefs.setIntPref(TPC_PREF, Ci.nsICookieService.BEHAVIOR_REJECT);
     await TestUtils.waitForCondition(() => categoryLabel.textContent ==
-      gNavigatorBundle.getString("contentBlocking.cookies.allBlocked.label"),
+      gNavigatorBundle.getString("contentBlocking.cookies.blockingAll.label"),
       "The category label has updated correctly");
-    is(categoryLabel.textContent, gNavigatorBundle.getString("contentBlocking.cookies.allBlocked.label"));
+    is(categoryLabel.textContent, gNavigatorBundle.getString("contentBlocking.cookies.blockingAll.label"));
 
     Services.prefs.setIntPref(TPC_PREF, Ci.nsICookieService.BEHAVIOR_REJECT_FOREIGN);
     await TestUtils.waitForCondition(() => categoryLabel.textContent ==
-      gNavigatorBundle.getString("contentBlocking.cookies.3rdPartyBlocked.label"),
+      gNavigatorBundle.getString("contentBlocking.cookies.blocking3rdParty.label"),
       "The category label has updated correctly");
-    is(categoryLabel.textContent, gNavigatorBundle.getString("contentBlocking.cookies.3rdPartyBlocked.label"));
+    is(categoryLabel.textContent, gNavigatorBundle.getString("contentBlocking.cookies.blocking3rdParty.label"));
 
     Services.prefs.setIntPref(TPC_PREF, Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER);
     await TestUtils.waitForCondition(() => categoryLabel.textContent ==
-      gNavigatorBundle.getString("contentBlocking.cookies.trackersBlocked.label"),
+      gNavigatorBundle.getString("contentBlocking.cookies.blockingTrackers.label"),
       "The category label has updated correctly");
-    is(categoryLabel.textContent, gNavigatorBundle.getString("contentBlocking.cookies.trackersBlocked.label"));
+    is(categoryLabel.textContent, gNavigatorBundle.getString("contentBlocking.cookies.blockingTrackers.label"));
 
     Services.prefs.setIntPref(TPC_PREF, Ci.nsICookieService.BEHAVIOR_LIMIT_FOREIGN);
     await TestUtils.waitForCondition(() => categoryLabel.textContent ==
-      gNavigatorBundle.getString("contentBlocking.cookies.unvisitedBlocked.label"),
+      gNavigatorBundle.getString("contentBlocking.cookies.blockingUnvisited.label"),
       "The category label has updated correctly");
-    is(categoryLabel.textContent, gNavigatorBundle.getString("contentBlocking.cookies.unvisitedBlocked.label"));
+    is(categoryLabel.textContent, gNavigatorBundle.getString("contentBlocking.cookies.blockingUnvisited.label"));
   });
 });
--- a/browser/base/content/test/trackingUI/browser_trackingUI_cookies_subview.js
+++ b/browser/base/content/test/trackingUI/browser_trackingUI_cookies_subview.js
@@ -29,20 +29,20 @@ async function assertSitesListed(tracker
     let cookiesView = document.getElementById("identity-popup-cookiesView");
     let viewShown = BrowserTestUtils.waitForEvent(cookiesView, "ViewShown");
     categoryItem.click();
     await viewShown;
 
     ok(true, "Cookies view was shown");
 
     let listHeaders = cookiesView.querySelectorAll(".identity-popup-cookiesView-list-header");
-    is(listHeaders.length, 1, "We have 1 list header");
-    is(listHeaders[0].textContent,
-       gNavigatorBundle.getString(`contentBlocking.cookiesView.trackers.label`),
-       "The list header is for tracking cookies.");
+    is(listHeaders.length, 3, "We have 3 list headers");
+
+    let emptyLabels = cookiesView.querySelectorAll(".identity-popup-content-blocking-empty-label");
+    is(emptyLabels.length, 2, "We have 2 empty labels");
 
     let listItems = cookiesView.querySelectorAll(".identity-popup-content-blocking-list-item");
     is(listItems.length, 1, "We have 1 cookie in the list");
 
     let listItem = listItems[0];
     let label = listItem.querySelector(".identity-popup-content-blocking-list-host-label");
     is(label.value, "http://trackertest.org", "Has an item for trackertest.org");
     ok(BrowserTestUtils.is_visible(listItem), "List item is visible");
@@ -68,21 +68,18 @@ async function assertSitesListed(tracker
     is(result, undefined, "No securityChange events should be received");
 
     viewShown = BrowserTestUtils.waitForEvent(cookiesView, "ViewShown");
     categoryItem.click();
     await viewShown;
 
     ok(true, "Cookies view was shown");
 
-    listHeaders = cookiesView.querySelectorAll(".identity-popup-cookiesView-list-header");
-    is(listHeaders.length, 2, "We now have 2 list headers");
-    is(listHeaders[1].textContent,
-       gNavigatorBundle.getString(`contentBlocking.cookiesView.thirdParty.label`),
-       "The new list header is for third party cookies.");
+    emptyLabels = cookiesView.querySelectorAll(".identity-popup-content-blocking-empty-label");
+    is(emptyLabels.length, 1, "We have 1 empty label");
 
     listItems = cookiesView.querySelectorAll(".identity-popup-content-blocking-list-item");
     is(listItems.length, 2, "We have 2 cookies in the list");
 
     listItem = listItems[1];
     label = listItem.querySelector(".identity-popup-content-blocking-list-host-label");
     is(label.value, "https://test1.example.org", "Has an item for test1.example.org");
     ok(BrowserTestUtils.is_visible(listItem), "List item is visible");
@@ -106,21 +103,18 @@ async function assertSitesListed(tracker
     is(result, undefined, "No securityChange events should be received");
 
     viewShown = BrowserTestUtils.waitForEvent(cookiesView, "ViewShown");
     categoryItem.click();
     await viewShown;
 
     ok(true, "Cookies view was shown");
 
-    listHeaders = cookiesView.querySelectorAll(".identity-popup-cookiesView-list-header");
-    is(listHeaders.length, 3, "We now have 3 list headers");
-    is(listHeaders[0].textContent,
-       gNavigatorBundle.getString(`contentBlocking.cookiesView.firstParty.label`),
-       "The new list header is for first party cookies.");
+    emptyLabels = cookiesView.querySelectorAll(".identity-popup-content-blocking-empty-label");
+    is(emptyLabels.length, 0, "We have 0 empty label");
 
     listItems = cookiesView.querySelectorAll(".identity-popup-content-blocking-list-item");
     is(listItems.length, 3, "We have 2 cookies in the list");
 
     listItem = listItems[0];
     label = listItem.querySelector(".identity-popup-content-blocking-list-host-label");
     is(label.value, "http://not-tracking.example.com", "Has an item for the first party");
     ok(BrowserTestUtils.is_visible(listItem), "List item is visible");
@@ -159,22 +153,16 @@ add_task(async function testCookiesSubVi
     ok(BrowserTestUtils.is_visible(categoryItem), "TP category item is visible");
     let cookiesView = document.getElementById("identity-popup-cookiesView");
     let viewShown = BrowserTestUtils.waitForEvent(cookiesView, "ViewShown");
     categoryItem.click();
     await viewShown;
 
     ok(true, "Cookies view was shown");
 
-    let listHeaders = cookiesView.querySelectorAll(".identity-popup-cookiesView-list-header");
-    is(listHeaders.length, 1, "We have 1 list header");
-    is(listHeaders[0].textContent,
-       gNavigatorBundle.getString(`contentBlocking.cookiesView.trackers.label`),
-       "The list header is for tracking cookies.");
-
     let listItems = cookiesView.querySelectorAll(".identity-popup-content-blocking-list-item");
     is(listItems.length, 1, "We have 1 cookie in the list");
 
     let listItem = listItems[0];
     let label = listItem.querySelector(".identity-popup-content-blocking-list-host-label");
     is(label.value, "http://trackertest.org", "Has an item for trackertest.org");
     ok(BrowserTestUtils.is_visible(listItem), "List item is visible");
     ok(listItem.classList.contains("allowed"), "Indicates whether the cookie was blocked or allowed");
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -490,42 +490,70 @@ contentBlocking.category.strict=Strict
 contentBlocking.category.custom=Custom
 
 # LOCALIZATION NOTE (contentBlocking.trackers.allowed.label):
 #   This label signals that this type of content blocking is turned
 #   OFF and is not blocking tracker content, so this is not
 #   a positive thing. It forms the end of the (imaginary) sentence
 #   "Trackers [are] Allowed"
 contentBlocking.trackers.allowed.label=Allowed
-# LOCALIZATION NOTE (contentBlocking.trackers.blocked.label):
+# LOCALIZATION NOTE (contentBlocking.trackers.blocking.label):
 #   This label signals that this type of content blocking is turned
 #   ON and is successfully blocking tracker content, so this is
-#   a positive thing. It forms the end of the (imaginary) sentence
-#   "Trackers [are] Blocked"
-contentBlocking.trackers.blocked.label=Blocked
+#   a positive thing. However, it is important to note that there is no
+#   guarantee that we _actually_ blocked anything, hence we present it
+#   in the present tense, not the past tense in English. The idea is that
+#   past tense would imply that something was blocked, while present
+#   tense expresses that we are waiting for trackers to load
+#   and will block them as appropriate. This concept may not directly
+#   translate to your language, but it is still preferable if the translation
+#   would not make it seem like the blocking had already happened.
+#   So in full context this word could be part of the sentence:
+#   "[Firefox is] Blocking [trackers when they get loaded.]"
+contentBlocking.trackers.blocking.label=Blocking
 
 # LOCALIZATION NOTE (contentBlocking.trackersView.blocked.label):
 #   This label is shown next to a tracker in the trackers subview.
 #   It forms the end of the (imaginary) sentence "www.example.com [was] Blocked"
 contentBlocking.trackersView.blocked.label=Blocked
 
+contentBlocking.trackersView.empty.label=None detected on this site
+
 # LOCALIZATION NOTE (contentBlocking.cookies.allowed.label):
 #   This label signals that this type of content blocking is turned
 #   OFF and is not blocking tracker content, so this is not
 #   a positive thing. It forms the end of the (imaginary) sentence
 #   "Cookies [are] Allowed"
 contentBlocking.cookies.allowed.label=Allowed
-contentBlocking.cookies.trackersBlocked.label=Tracking Cookies Blocked
-contentBlocking.cookies.3rdPartyBlocked.label=Third-Party Cookies Blocked
-contentBlocking.cookies.unvisitedBlocked.label=Unvisited Site Cookies Blocked
-contentBlocking.cookies.allBlocked.label=All Cookies Blocked
+# LOCALIZATION NOTE (contentBlocking.cookies.blockingTrackers.label, contentBlocking.cookies.blocking3rdParty.label,
+#   contentBlocking.cookies.blockingUnvisited.label,contentBlocking.cookies.blockingAll.label):
+# See localization note for contentBlocking.trackers.blocking.label to get recommendations on translating "Blocking".
+contentBlocking.cookies.blockingTrackers.label=Blocking Tracking Cookies
+contentBlocking.cookies.blocking3rdParty.label=Blocking Third-Party Cookies
+contentBlocking.cookies.blockingUnvisited.label=Blocking Unvisited Site Cookies
+contentBlocking.cookies.blockingAll.label=Blocking All Cookies
 
 contentBlocking.cookiesView.firstParty.label=From This Site
+# LOCALIZATION NOTE (contentBlocking.cookiesView.firstParty.empty.label):
+#  This references the header from contentBlocking.cookiesView.firstParty.label:
+#  "[Cookies] From This Site: None detected on this site".
+contentBlocking.cookiesView.firstParty.empty.label=None detected on this site
+
 contentBlocking.cookiesView.trackers.label=Tracking Cookies
+# LOCALIZATION NOTE (contentBlocking.cookiesView.trackers.empty.label):
+#  This references the header from contentBlocking.cookiesView.trackers.label:
+#  "Tracking Cookies: None detected on this site".
+contentBlocking.cookiesView.trackers.empty.label=None detected on this site
+
 contentBlocking.cookiesView.thirdParty.label=Third-Party Cookies
+# LOCALIZATION NOTE (contentBlocking.cookiesView.thirdParty.empty.label):
+#  This references the header from contentBlocking.cookiesView.thirdParty.label:
+#  "Third-Party Cookies: None detected on this site".
+contentBlocking.cookiesView.thirdParty.empty.label=None detected on this site
+
 # LOCALIZATION NOTE (contentBlocking.cookiesView.allowed.label):
 #   This label is shown next to a cookie origin in the cookies subview.
 #   It forms the end of the (imaginary) sentence "www.example.com [was] Allowed"
 contentBlocking.cookiesView.allowed.label=Allowed
 # LOCALIZATION NOTE (contentBlocking.cookiesView.blocked.label):
 #   This label is shown next to a cookie origin in the cookies subview.
 #   It forms the end of the (imaginary) sentence "www.example.com [was] Blocked"
 contentBlocking.cookiesView.blocked.label=Blocked
--- a/browser/themes/shared/controlcenter/panel.inc.css
+++ b/browser/themes/shared/controlcenter/panel.inc.css
@@ -156,16 +156,17 @@
   display: inline;
   padding-inline-end: 25px;
   padding-inline-start: 0px;
   color: var(--panel-disabled-color);
 }
 
 /* CONTENT */
 
+.identity-popup-content-blocking-empty-label,
 #tracking-protection-preferences-button > .toolbarbutton-text,
 .identity-popup-footer,
 .tracking-protection-button,
 #identity-popup-trackersView-strict-info > label,
 .identity-popup-cookiesView-list-header,
 .identity-popup-content-blocking-list-item > label,
 #identity-popup-mainView-panel-header > label,
 #identity-popup-trackersView > .panel-header,
@@ -434,16 +435,39 @@ description#identity-popup-content-verif
 
 /* This subview could get filled with a lot of trackers, set a maximum size
  * and allow it to scroll vertically.*/
 #identity-popup-cookiesView,
 #identity-popup-trackersView {
   max-height: 600px;
 }
 
+#identity-popup-trackersView-list.empty {
+  -moz-box-align: center;
+  -moz-box-pack: center;
+}
+
+.identity-popup-content-blocking-empty-label {
+  margin-inline-start: 0;
+  color: var(--panel-disabled-color);
+}
+
+.identity-popup-content-blocking-trackersView-empty-image {
+  width: 48px;
+  height: 48px;
+  -moz-context-properties: fill, fill-opacity;
+  margin-bottom: 16px;
+}
+
+#identity-popup-cookiesView .identity-popup-content-blocking-empty-label {
+  margin-inline-start: 24px;
+  margin-top: 2px;
+  margin-bottom: 4px;
+}
+
 .identity-popup-cookiesView-list-header {
   color: var(--panel-disabled-color);
   margin: 5px 0;
 }
 
 .identity-popup-content-blocking-list {
   padding: 5px 20px;
   -moz-box-flex: 1;
--- a/js/src/jit-test/tests/realms/basic.js
+++ b/js/src/jit-test/tests/realms/basic.js
@@ -38,8 +38,19 @@ function testSystemNonSystemRealms() {
     try {
         systemRealm = newGlobal({systemPrincipal: true, sameCompartmentAs: this});
     } catch(e) {
         ex = e;
     }
     assertEq(ex.toString().includes("non-system realms"), true);
 }
 testSystemNonSystemRealms();
+
+function testNewObjectCache() {
+    // NewObjectCache lookup based on the proto should not return a cross-realm
+    // object.
+    var g = newGlobal({sameCompartmentAs: this});
+    var o1 = g.evaluate("Object.create(Math)");
+    var o2 = Object.create(g.Math);
+    assertEq(objectGlobal(o1), g);
+    assertEq(objectGlobal(o2), this);
+}
+testNewObjectCache();
--- a/js/src/vm/Caches-inl.h
+++ b/js/src/vm/Caches-inl.h
@@ -48,16 +48,22 @@ inline NativeObject* NewObjectCache::new
   NativeObject* templateObj =
       reinterpret_cast<NativeObject*>(&entry->templateObject);
 
   // Do an end run around JSObject::group() to avoid doing AutoUnprotectCell
   // on the templateObj, which is not a GC thing and can't use
   // runtimeFromAnyThread.
   ObjectGroup* group = templateObj->group_;
 
+  // If we did the lookup based on the proto we might have a group/object from a
+  // different (same-compartment) realm, so we have to do a realm check.
+  if (group->realm() != cx->realm()) {
+    return nullptr;
+  }
+
   MOZ_ASSERT(!group->hasUnanalyzedPreliminaryObjects());
 
   {
     AutoSweepObjectGroup sweepGroup(group);
     if (group->shouldPreTenure(sweepGroup)) {
       heap = gc::TenuredHeap;
     }
   }
--- a/js/src/vm/JSFunction.cpp
+++ b/js/src/vm/JSFunction.cpp
@@ -2343,16 +2343,17 @@ static inline JSFunction* NewFunctionClo
   return clone;
 }
 
 JSFunction* js::CloneFunctionReuseScript(
     JSContext* cx, HandleFunction fun, HandleObject enclosingEnv,
     gc::AllocKind allocKind /* = FUNCTION */,
     NewObjectKind newKind /* = GenericObject */,
     HandleObject proto /* = nullptr */) {
+  MOZ_ASSERT(cx->realm() == fun->realm());
   MOZ_ASSERT(NewFunctionEnvironmentIsWellFormed(cx, enclosingEnv));
   MOZ_ASSERT(fun->isInterpreted());
   MOZ_ASSERT(!fun->isBoundFunction());
   MOZ_ASSERT(CanReuseScriptForClone(cx->realm(), fun, enclosingEnv));
 
   RootedFunction clone(cx,
                        NewFunctionClone(cx, fun, newKind, allocKind, proto));
   if (!clone) {
--- a/js/src/vm/JSFunction.h
+++ b/js/src/vm/JSFunction.h
@@ -643,19 +643,25 @@ class JSFunction : public js::NativeObje
       return lazyScript()->isAsync();
     }
     if (hasScript()) {
       return nonLazyScript()->isAsync();
     }
     return false;
   }
 
-  void setScript(JSScript* script_) { mutableScript() = script_; }
+  void setScript(JSScript* script) {
+    MOZ_ASSERT(realm() == script->realm());
+    mutableScript() = script;
+  }
 
-  void initScript(JSScript* script_) { mutableScript().init(script_); }
+  void initScript(JSScript* script) {
+    MOZ_ASSERT_IF(script, realm() == script->realm());
+    mutableScript().init(script);
+  }
 
   void setUnlazifiedScript(JSScript* script) {
     MOZ_ASSERT(isInterpretedLazy());
     if (lazyScriptOrNull()) {
       // Trigger a pre barrier on the lazy script being overwritten.
       js::LazyScript::writeBarrierPre(lazyScriptOrNull());
       if (!lazyScript()->maybeScript()) {
         lazyScript()->initScript(script);
--- a/js/src/vm/ObjectGroup.cpp
+++ b/js/src/vm/ObjectGroup.cpp
@@ -497,18 +497,20 @@ MOZ_ALWAYS_INLINE ObjectGroup* ObjectGro
   if (associated && !associated->is<TypeDescr>()) {
     MOZ_ASSERT(!clasp);
     if (associated->is<JSFunction>()) {
       // Canonicalize new functions to use the original one associated with its
       // script.
       associated = associated->as<JSFunction>().maybeCanonicalFunction();
 
       // If we have previously cleared the 'new' script information for this
-      // function, don't try to construct another one.
-      if (associated && associated->as<JSFunction>().wasNewScriptCleared()) {
+      // function, don't try to construct another one. Also, for simplicity,
+      // don't bother optimizing cross-realm constructors.
+      if (associated && (associated->as<JSFunction>().wasNewScriptCleared() ||
+                         associated->as<JSFunction>().realm() != cx->realm())) {
         associated = nullptr;
       }
 
     } else {
       associated = nullptr;
     }
 
     if (!associated) {
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -3839,16 +3839,18 @@ void PreliminaryObjectArrayWithTemplate:
 // Make a TypeNewScript for |group|, and set it up to hold the preliminary
 // objects created with the group.
 /* static */ bool TypeNewScript::make(JSContext* cx, ObjectGroup* group,
                                       JSFunction* fun) {
   AutoSweepObjectGroup sweep(group);
   MOZ_ASSERT(cx->zone()->types.activeAnalysis);
   MOZ_ASSERT(!group->newScript(sweep));
   MOZ_ASSERT(!group->maybeUnboxedLayout(sweep));
+  MOZ_ASSERT(cx->realm() == group->realm());
+  MOZ_ASSERT(cx->realm() == fun->realm());
 
   // rollbackPartiallyInitializedObjects expects function_ to be
   // canonicalized.
   MOZ_ASSERT(fun->maybeCanonicalFunction() == fun);
 
   if (group->unknownProperties(sweep)) {
     return true;
   }
--- a/js/xpconnect/loader/mozJSSubScriptLoader.cpp
+++ b/js/xpconnect/loader/mozJSSubScriptLoader.cpp
@@ -181,19 +181,19 @@ static bool EvalScript(JSContext* cx, Ha
     }
     retval.setUndefined();
   } else {
     JS::AutoObjectVector envChain(cx);
     if (!envChain.append(targetObj)) {
       return false;
     }
     if (!loadScope) {
-      // A null loadScope means we are cross-compartment. In this case, we
-      // should check the target isn't in the JSM loader shared-global or
-      // we will contaiminate all JSMs in the compartment.
+      // A null loadScope means we are cross-realm. In this case, we should
+      // check the target isn't in the JSM loader shared-global or we will
+      // contaminate all JSMs in the realm.
       //
       // NOTE: If loadScope is already a shared-global JSM, we can't
       // determine which JSM the target belongs to and have to assume it
       // is in our JSM.
 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
       JSObject* targetGlobal = JS::GetNonCCWObjectGlobal(targetObj);
       MOZ_DIAGNOSTIC_ASSERT(
           !mozJSComponentLoader::Get()->IsLoaderGlobal(targetGlobal),
@@ -577,18 +577,18 @@ nsresult mozJSSubScriptLoader::DoLoadSub
 
   targetObj = JS_FindCompilationScope(cx, targetObj);
   if (!targetObj || !loadScope) {
     return NS_ERROR_FAILURE;
   }
 
   MOZ_ASSERT(!js::IsWrapper(targetObj), "JS_FindCompilationScope must unwrap");
 
-  if (js::GetObjectCompartment(loadScope) !=
-      js::GetObjectCompartment(targetObj)) {
+  if (js::GetNonCCWObjectRealm(loadScope) !=
+      js::GetNonCCWObjectRealm(targetObj)) {
     loadScope = nullptr;
   }
 
   /* load up the url.  From here on, failures are reflected as ``custom''
    * js exceptions */
   nsCOMPtr<nsIURI> uri;
   nsAutoCString uriStr;
   nsAutoCString scheme;
--- a/toolkit/themes/linux/global/in-content/common.css
+++ b/toolkit/themes/linux/global/in-content/common.css
@@ -5,22 +5,16 @@
 %include ../../../shared/in-content/common.inc.css
 
 xul|tab[visuallyselected] {
   /* Override styles for tab[selected] from
      toolkit/themes/linux/global/tabbox.css */
   margin-bottom: 0;
 }
 
-*|button.primary:focus,
-xul|button:-moz-focusring {
-  outline: 1px dotted;
-  outline-offset: -2px;
-}
-
 xul|button > xul|*.button-box,
 xul|menulist > xul|*.menulist-label-box {
   -moz-appearance: none;
 }
 
 xul|button[type="menu"] > xul|*.button-box > xul|*.button-menu-dropmarker {
   -moz-appearance: none !important;
 }
--- a/toolkit/themes/osx/global/in-content/common.css
+++ b/toolkit/themes/osx/global/in-content/common.css
@@ -52,20 +52,18 @@ xul|*.radio-icon {
 }
 
 xul|*.text-link:-moz-focusring {
   color: var(--in-content-link-highlight);
   text-decoration: underline;
   box-shadow: none;
 }
 
-xul|button:-moz-focusring,
 xul|menulist:-moz-focusring,
 xul|checkbox:-moz-focusring > .checkbox-check,
-*|button.primary:focus,
 html|input[type="checkbox"]:-moz-focusring + html|label:before,
 xul|radio[focused="true"] > .radio-check,
 xul|tab:-moz-focusring > .tab-middle > .tab-text {
   outline: 2px solid rgba(0,149,221,0.5);
   outline-offset: 1px;
   -moz-outline-radius: 2px;
 }
 
--- a/toolkit/themes/shared/in-content/common.inc.css
+++ b/toolkit/themes/shared/in-content/common.inc.css
@@ -4,17 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 %endif
 @namespace html "http://www.w3.org/1999/xhtml";
 @namespace xul "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
 *|*:root {
   --in-content-page-color: #0c0c0d;
   --in-content-page-background: #f9f9fa;
-  --in-content-text-color: #0c0c0d;
+  --in-content-text-color: var(--grey-90);
   --in-content-selected-text: #fff;
   --in-content-box-background: #fff;
   --in-content-box-background-odd: rgba(12, 12, 13, 0.05); /* grey 90 a05 */
   --in-content-box-background-hover: #ededf0; /* grey 20 */
   --in-content-box-background-active: #d7d7db; /* grey 30 */
   --in-content-box-border-color: var(--grey-90-a30);
   --in-content-item-hover: rgba(69, 161, 255, 0.2); /* blue 40 a20 */
   --in-content-item-selected: #0a84ff;
@@ -34,16 +34,19 @@
   --in-content-category-background-active: rgba(12,12,13,0.15);
   --in-content-category-background-selected-hover: rgba(12,12,13,0.15);
   --in-content-category-background-selected-active: rgba(12,12,13,0.2);
   --in-content-tab-color: #424f5a;
   --in-content-link-color: #0a8dff;
   --in-content-link-color-hover: #0060df;
   --in-content-link-color-active: #003eaa;
   --in-content-link-color-visited: #0a8dff;
+  --in-content-button-background: var(--grey-90-a10);
+  --in-content-button-background-hover: var(--grey-90-a20);
+  --in-content-button-background-active: var(--grey-30);
   --in-content-primary-button-background: var(--blue-60);
   --in-content-primary-button-background-hover: var(--blue-70);
   --in-content-primary-button-background-active: var(--blue-80);
   --in-content-table-background: #ebebeb;
   --in-content-table-border-dark-color: #d1d1d1;
   --in-content-table-header-background: #0a84ff;
 
   --blue-50: #0a84ff;
@@ -158,34 +161,48 @@ html|button {
 
 *|button,
 html|select,
 html|input[type="color"],
 xul|menulist,
 html|*.numberbox-input::-moz-number-spin-up,
 html|*.numberbox-input::-moz-number-spin-down {
   -moz-appearance: none;
-  min-height: 30px;
+  min-height: 32px;
   /* !important overrides button.css for disabled and default XUL buttons: */
   color: var(--in-content-text-color) !important;
-  border: 1px solid var(--in-content-box-border-color);
+  border: none;
   border-radius: 2px;
-  background-color: var(--in-content-page-background);
+  background-color: var(--in-content-button-background);
+  font-weight: 400;
+  padding: 0 8px;
+  text-align: center;
+  text-decoration: none;
   margin: 4px 8px;
   /* Ensure font-size isn't overridden by widget styling (e.g. in forms.css) */
   font-size: 1em;
 }
 
 xul|button,
 html|button {
   /* use the same margin of other elements for the alignment */
   margin-left: 4px;
   margin-right: 4px;
 }
 
+*|button::-moz-focus-inner {
+  border: none;
+}
+
+*|button:-moz-focusring {
+  box-shadow: 0 0 0 1px var(--in-content-border-active) inset,
+    0 0 0 1px var(--in-content-border-active),
+    0 0 0 4px var(--in-content-border-active-shadow);
+}
+
 html|select:not([size]):not([multiple]) {
   background-image: url("chrome://global/skin/in-content/dropdown.svg#dropdown");
   background-position: right 3px center;
   background-repeat: no-repeat;
   background-size: auto 18px;
   font-size: inherit;
   padding-inline-start: 5px;
   padding-inline-end: 24px;
@@ -198,41 +215,40 @@ html|select:not([size]):not([multiple]):
 
 html|button:enabled:hover,
 html|select:not([size]):not([multiple]):enabled:hover,
 html|*.numberbox-input::-moz-number-spin-up:hover,
 html|*.numberbox-input::-moz-number-spin-down:hover,
 html|input[type="color"]:hover,
 xul|button:not([disabled="true"]):hover,
 xul|menulist:not([disabled="true"]):hover {
-  background-color: var(--in-content-box-background-hover);
+  background-color: var(--in-content-button-background-hover);
 }
 
 html|button:enabled:hover:active,
 html|select:not([size]):not([multiple]):enabled:hover:active,
 html|*.numberbox-input::-moz-number-spin-up:hover:active,
 html|*.numberbox-input::-moz-number-spin-down:hover:active,
 html|input[type="color"]:enabled:hover:active,
 xul|button:not([disabled="true"]):hover:active,
 xul|menulist[open="true"]:not([disabled="true"]) {
-  background-color: var(--in-content-box-background-active);
+  background-color: var(--in-content-button-background-active);
 }
 
 html|button:disabled,
 html|select:disabled,
 html|*.numberbox-input:disabled::-moz-number-spin-box,
 html|input[type="color"]:disabled,
 xul|button[disabled="true"],
 xul|menulist[disabled="true"] {
-  opacity: 0.5;
+  opacity: 0.4;
 }
 
 *|button.primary {
   background-color: var(--in-content-primary-button-background);
-  border-color: transparent;
   color: var(--in-content-selected-text) !important;
 }
 
 html|button.primary:enabled:hover,
 xul|button.primary:not([disabled="true"]):hover {
   background-color: var(--in-content-primary-button-background-hover);
 }
 
@@ -431,17 +447,18 @@ xul|textbox:not([disabled="true"]):not([
 }
 
 html|input[type="email"]:focus,
 html|input[type="tel"]:focus,
 html|input[type="text"]:focus,
 html|textarea:focus,
 xul|textbox[focused] {
   border-color: var(--in-content-border-active);
-  box-shadow: 0 0 0 3px var(--in-content-border-active-shadow);
+  box-shadow: 0 0 0 1px var(--in-content-border-active),
+    0 0 0 4px var(--in-content-border-active-shadow);
 }
 
 html|input[type="email"]:-moz-ui-invalid,
 html|input[type="tel"]:-moz-ui-invalid,
 html|input[type="text"]:-moz-ui-invalid,
 html|textarea:-moz-ui-invalid {
   border-color: var(--in-content-border-invalid);
 }
--- a/toolkit/themes/windows/global/in-content/common.css
+++ b/toolkit/themes/windows/global/in-content/common.css
@@ -27,21 +27,16 @@ xul|*.menulist-label-box {
   border-style: none;
 }
 
 xul|menulist:-moz-focusring > xul|*.menulist-label-box,
 html|input[type="checkbox"]:-moz-focusring + html|label:before {
   outline: 1px dotted;
 }
 
-*|button.primary:focus {
-  outline: 1px dotted;
-  outline-offset: -3px;
-}
-
 /* Use a 2px border so that selected row highlight is still visible behind
     an existing high-contrast border that uses the background color */
 @media (-moz-windows-default-theme: 0) {
   xul|treechildren::-moz-tree-row(selected) {
      border: 2px dotted Highlight;
   }
 }