Bug 1514340 - Part 2: Break out the content blocking related notifications into nsIWebProgressListener.onContentBlockingEvent(); r=baku,johannh
authorEhsan Akhgari <ehsan@mozilla.com>
Sun, 06 Jan 2019 17:45:57 -0500
changeset 454745 f2b15591bb21fdf2eab19f347fe0fc1d135eab38
parent 454744 3b1381f652033d767f08494f68c8f74fe793b19d
child 454746 4bec91be9b748c8703f45c2de98dee29c6b89568
push id35412
push usercsabou@mozilla.com
push dateTue, 22 Jan 2019 03:56:27 +0000
treeherdermozilla-central@956bd26eec5a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku, johannh
bugs1514340
milestone66.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
Bug 1514340 - Part 2: Break out the content blocking related notifications into nsIWebProgressListener.onContentBlockingEvent(); r=baku,johannh Differential Revision: https://phabricator.services.mozilla.com/D16052
accessible/base/DocManager.cpp
browser/base/content/browser-contentblocking.js
browser/base/content/browser.js
browser/base/content/tabbrowser.js
browser/base/content/test/trackingUI/browser_trackingUI_animation_2.js
browser/base/content/test/trackingUI/browser_trackingUI_fetch.js
browser/base/content/test/trackingUI/browser_trackingUI_telemetry.js
browser/base/content/test/trackingUI/head.js
browser/components/extensions/parent/ext-tabs.js
browser/components/shell/nsMacShellService.cpp
browser/modules/test/browser/browser_UsageTelemetry_domains.js
devtools/client/responsive.html/browser/tunnel.js
docshell/base/nsDocShell.cpp
docshell/base/nsDocShellTreeOwner.cpp
docshell/test/browser/browser_onbeforeunload_navigation.js
dom/base/nsGlobalWindowOuter.cpp
dom/base/nsGlobalWindowOuter.h
dom/base/nsPIDOMWindow.h
dom/browser-element/BrowserElementChildPreload.js
dom/browser-element/mochitest/browserElement_SecurityChange.js
dom/browser-element/mochitest/file_browserElement_SecurityChange.html
dom/clients/manager/ClientNavigateOpChild.cpp
dom/clients/manager/ClientOpenWindowUtils.cpp
dom/html/HTMLFormElement.cpp
dom/html/nsHTMLDNSPrefetch.cpp
dom/presentation/PresentationCallbacks.cpp
editor/composer/nsEditingSession.cpp
editor/composer/test/test_bug434998.xul
editor/libeditor/tests/test_bug607584.xul
editor/libeditor/tests/test_bug616590.xul
editor/libeditor/tests/test_bug780908.xul
layout/base/tests/chrome/printpreview_bug396024_helper.xul
layout/base/tests/chrome/printpreview_bug482976_helper.xul
layout/base/tests/chrome/printpreview_helper.xul
layout/printing/ipc/RemotePrintJobChild.cpp
layout/printing/nsPrintJob.cpp
layout/tools/layout-debug/ui/content/layoutdebug.js
layout/tools/reftest/reftest-content.js
mobile/android/chrome/content/PrintHelper.js
mobile/android/modules/geckoview/GeckoViewTrackingProtection.jsm
netwerk/base/nsISecureBrowserUI.idl
netwerk/url-classifier/UrlClassifierCommon.cpp
security/manager/ssl/nsSecureBrowserUIImpl.cpp
security/manager/ssl/nsSecureBrowserUIImpl.h
testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm
toolkit/actors/PrintingChild.jsm
toolkit/components/antitracking/AntiTrackingCommon.cpp
toolkit/components/antitracking/test/browser/head.js
toolkit/components/browser/nsWebBrowser.cpp
toolkit/components/downloads/DownloadCore.jsm
toolkit/components/downloads/DownloadLegacy.js
toolkit/components/printing/content/printPreviewProgress.js
toolkit/components/printing/content/printProgress.js
toolkit/components/printingui/ipc/PrintProgressDialogChild.cpp
toolkit/components/printingui/nsPrintProgress.cpp
toolkit/components/printingui/nsPrintingPromptService.cpp
toolkit/components/statusfilter/nsBrowserStatusFilter.cpp
toolkit/components/url-classifier/tests/mochitest/test_threathit_report.html
toolkit/components/windowcreator/test/browser_bug1204626.js
toolkit/components/windowcreator/test/test_bug1170334_wbp_xmlstyle.html
toolkit/components/windowcreator/test/test_bug1192654.html
toolkit/content/tests/browser/common/mockTransfer.js
toolkit/modules/RemoteSecurityUI.jsm
toolkit/modules/RemoteWebProgress.jsm
toolkit/modules/WebProgressChild.jsm
toolkit/mozapps/downloads/nsHelperAppDlg.js
toolkit/mozapps/extensions/content/extensions.js
toolkit/mozapps/extensions/internal/LightweightThemePersister.jsm
toolkit/mozapps/extensions/test/browser/browser_bug562797.js
toolkit/mozapps/extensions/test/browser/browser_discovery.js
uriloader/base/nsDocLoader.cpp
uriloader/base/nsIWebProgress.idl
uriloader/base/nsIWebProgressListener.idl
uriloader/prefetch/nsOfflineCacheUpdateService.cpp
uriloader/prefetch/nsPrefetchService.cpp
xpfe/appshell/nsChromeTreeOwner.cpp
xpfe/appshell/nsWebShellWindow.cpp
--- a/accessible/base/DocManager.cpp
+++ b/accessible/base/DocManager.cpp
@@ -303,16 +303,23 @@ DocManager::OnStatusChange(nsIWebProgres
 
 NS_IMETHODIMP
 DocManager::OnSecurityChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest,
                              uint32_t aState) {
   MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
   return NS_OK;
 }
 
+NS_IMETHODIMP
+DocManager::OnContentBlockingEvent(nsIWebProgress* aWebProgress,
+                                   nsIRequest* aRequest, uint32_t aEvent) {
+  MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
+  return NS_OK;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // nsIDOMEventListener
 
 NS_IMETHODIMP
 DocManager::HandleEvent(Event* aEvent) {
   nsAutoString type;
   aEvent->GetType(type);
 
--- a/browser/base/content/browser-contentblocking.js
+++ b/browser/base/content/browser-contentblocking.js
@@ -807,17 +807,17 @@ var ContentBlocking = {
 
   shieldHistogramAdd(value) {
     if (PrivateBrowsingUtils.isWindowPrivate(window)) {
       return;
     }
     Services.telemetry.getHistogramById("TRACKING_PROTECTION_SHIELD").add(value);
   },
 
-  onSecurityChange(state, webProgress, isSimulated) {
+  onContentBlockingEvent(event, webProgress, isSimulated) {
     let baseURI = this._baseURIForChannelClassifier;
 
     // Don't deal with about:, file: etc.
     if (!baseURI) {
       this.iconBox.removeAttribute("animate");
       this.iconBox.removeAttribute("active");
       this.iconBox.removeAttribute("hasException");
       return;
@@ -826,19 +826,19 @@ var ContentBlocking = {
     let anyDetected = false;
     let anyBlocking = false;
 
     for (let blocker of this.blockers) {
       // Store data on whether the blocker is activated in the current document for
       // reporting it using the "report breakage" dialog. Under normal circumstances this
       // dialog should only be able to open in the currently selected tab and onSecurityChange
       // runs on tab switch, so we can avoid associating the data with the document directly.
-      blocker.activated = blocker.isBlocking(state);
+      blocker.activated = blocker.isBlocking(event);
       blocker.categoryItem.classList.toggle("blocked", blocker.enabled);
-      let detected = blocker.isDetected(state);
+      let detected = blocker.isDetected(event);
       blocker.categoryItem.hidden = !detected;
       anyDetected = anyDetected || detected;
       anyBlocking = anyBlocking || blocker.activated;
     }
 
     let isBrowserPrivate = PrivateBrowsingUtils.isBrowserPrivate(gBrowser.selectedBrowser);
 
     // Check whether the user has added an exception for this site.
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -4893,51 +4893,73 @@ var XULBrowserWindow = {
   onStatusChange(aWebProgress, aRequest, aStatus, aMessage) {
     this.status = aMessage;
     StatusPanel.update();
   },
 
   // Properties used to cache security state used to update the UI
   _state: null,
   _lastLocation: null,
+  _event: null,
+  _lastLocationForEvent: null,
+
+  // This is called in multiple ways:
+  //  1. Due to the nsIWebProgressListener.onContentBlockingEvent notification.
+  //  2. Called by tabbrowser.xml when updating the current browser.
+  //  3. Called directly during this object's initializations.
+  //  4. Due to the nsIWebProgressListener.onLocationChange notification.
+  // aRequest will be null always in case 2 and 3, and sometimes in case 1 (for
+  // instance, there won't be a request when STATE_BLOCKED_TRACKING_CONTENT is observed).
+  onContentBlockingEvent(aWebProgress, aRequest, aEvent, aIsSimulated) {
+    // Don't need to do anything if the data we use to update the UI hasn't
+    // changed
+    let uri = gBrowser.currentURI;
+    let spec = uri.spec;
+    if (this._event == aEvent &&
+        this._lastLocationForEvent == spec) {
+      return;
+    }
+    this._event = aEvent;
+    this._lastLocationForEvent = spec;
+
+    if (typeof(aIsSimulated) != "boolean" && typeof(aIsSimulated) != "undefined") {
+      throw "onContentBlockingEvent: aIsSimulated receieved an unexpected type";
+    }
+
+    ContentBlocking.onContentBlockingEvent(this._event, aWebProgress, aIsSimulated);
+  },
 
   // This is called in multiple ways:
   //  1. Due to the nsIWebProgressListener.onSecurityChange notification.
   //  2. Called by tabbrowser.xml when updating the current browser.
   //  3. Called directly during this object's initializations.
-  // aRequest will be null always in case 2 and 3, and sometimes in case 1 (for
-  // instance, there won't be a request when STATE_BLOCKED_TRACKING_CONTENT is observed).
+  // aRequest will be null always in case 2 and 3, and sometimes in case 1.
   onSecurityChange(aWebProgress, aRequest, aState, aIsSimulated) {
     // Don't need to do anything if the data we use to update the UI hasn't
     // changed
     let uri = gBrowser.currentURI;
     let spec = uri.spec;
     if (this._state == aState &&
         this._lastLocation == spec) {
       // Switching to a tab of the same URL doesn't change most security
       // information, but tab specific permissions may be different.
       gIdentityHandler.refreshIdentityBlock();
       return;
     }
     this._state = aState;
     this._lastLocation = spec;
 
-    if (typeof(aIsSimulated) != "boolean" && typeof(aIsSimulated) != "undefined") {
-      throw "onSecurityChange: aIsSimulated receieved an unexpected type";
-    }
-
     // Make sure the "https" part of the URL is striked out or not,
     // depending on the current mixed active content blocking state.
     gURLBar.formatValue();
 
     try {
       uri = Services.uriFixup.createExposableURI(uri);
     } catch (e) {}
     gIdentityHandler.updateIdentity(this._state, uri);
-    ContentBlocking.onSecurityChange(this._state, aWebProgress, aIsSimulated);
   },
 
   // simulate all change notifications after switching tabs
   onUpdateCurrentBrowser: function XWB_onUpdateCurrentBrowser(aStateFlags, aStatus, aMessage, aTotalProgress) {
     if (FullZoom.updateBackgroundTabs)
       FullZoom.onLocationChange(gBrowser.currentURI, true);
 
     CombinedStopReload.onTabSwitch();
--- a/browser/base/content/tabbrowser.js
+++ b/browser/base/content/tabbrowser.js
@@ -963,20 +963,23 @@ window._gBrowser = {
     // Update the URL bar.
     let webProgress = newBrowser.webProgress;
     this._callProgressListeners(null, "onLocationChange",
                                 [webProgress, null, newBrowser.currentURI, 0, true],
                                 true, false);
 
     let securityUI = newBrowser.securityUI;
     if (securityUI) {
+      this._callProgressListeners(null, "onSecurityChange",
+                                  [webProgress, null, securityUI.state],
+                                  true, false);
       // Include the true final argument to indicate that this event is
       // simulated (instead of being observed by the webProgressListener).
-      this._callProgressListeners(null, "onSecurityChange",
-                                  [webProgress, null, securityUI.state, true],
+      this._callProgressListeners(null, "onContentBlockingEvent",
+                                  [webProgress, null, securityUI.contentBlockingEvent, true],
                                   true, false);
     }
 
     let listener = this._tabListeners.get(newTab);
     if (listener && listener.mStateFlags) {
       this._callProgressListeners(null, "onUpdateCurrentBrowser",
                                   [listener.mStateFlags, listener.mStatus,
                                    listener.mMessage, listener.mTotalProgress],
@@ -1713,20 +1716,24 @@ window._gBrowser = {
 
     // Restore the progress listener.
     aBrowser.webProgress.addProgressListener(filter, Ci.nsIWebProgress.NOTIFY_ALL);
 
     // Restore the securityUI state.
     let securityUI = aBrowser.securityUI;
     let state = securityUI ? securityUI.state :
       Ci.nsIWebProgressListener.STATE_IS_INSECURE;
+    this._callProgressListeners(aBrowser, "onSecurityChange",
+                                [aBrowser.webProgress, null, state],
+                                true, false);
+    let event = securityUI ? securityUI.contentBlockingEvent : 0;
     // Include the true final argument to indicate that this event is
     // simulated (instead of being observed by the webProgressListener).
-    this._callProgressListeners(aBrowser, "onSecurityChange",
-                                [aBrowser.webProgress, null, state, true],
+    this._callProgressListeners(aBrowser, "onContentBlockingEvent",
+                                [aBrowser.webProgress, null, event, true],
                                 true, false);
 
     if (aShouldBeRemote) {
       // Switching the browser to be remote will connect to a new child
       // process so the browser can no longer be considered to be
       // crashed.
       tab.removeAttribute("crashed");
     } else {
@@ -5187,16 +5194,20 @@ class TabProgressListener {
           gBrowser._getSwitcher().cleanUpTabAfterEviction(this.mTab);
         }
       }
     }
 
     if (!this.mBlank) {
       this._callProgressListeners("onLocationChange",
                                   [aWebProgress, aRequest, aLocation, aFlags]);
+      // Include the true final argument to indicate that this event is
+      // simulated (instead of being observed by the webProgressListener).
+      this._callProgressListeners("onContentBlockingEvent",
+                                  [aWebProgress, null, 0, true]);
     }
 
     if (topLevel) {
       this.mBrowser.lastURI = aLocation;
       this.mBrowser.lastLocationChange = Date.now();
     }
   }
 
@@ -5210,16 +5221,21 @@ class TabProgressListener {
     this.mMessage = aMessage;
   }
 
   onSecurityChange(aWebProgress, aRequest, aState) {
     this._callProgressListeners("onSecurityChange",
                                 [aWebProgress, aRequest, aState]);
   }
 
+  onContentBlockingEvent(aWebProgress, aRequest, aEvent) {
+    this._callProgressListeners("onContentBlockingEvent",
+                                [aWebProgress, aRequest, aEvent]);
+  }
+
   onRefreshAttempted(aWebProgress, aURI, aDelay, aSameURI) {
     return this._callProgressListeners("onRefreshAttempted",
                                        [aWebProgress, aURI, aDelay, aSameURI]);
   }
 }
 TabProgressListener.prototype.QueryInterface = ChromeUtils.generateQI(
   ["nsIWebProgressListener",
    "nsIWebProgressListener2",
--- a/browser/base/content/test/trackingUI/browser_trackingUI_animation_2.js
+++ b/browser/base/content/test/trackingUI/browser_trackingUI_animation_2.js
@@ -64,29 +64,31 @@ async function testTrackingProtectionAni
   securityChanged = waitForSecurityChange(1, tabbrowser.ownerGlobal);
   tabbrowser.selectedTab = trackingCookiesTab;
   await securityChanged;
 
   ok(ContentBlocking.iconBox.hasAttribute("active"), "iconBox active");
   ok(!ContentBlocking.iconBox.hasAttribute("animate"), "iconBox not animating");
 
   info("Reload tracking cookies tab");
-  securityChanged = waitForSecurityChange(2, tabbrowser.ownerGlobal);
+  securityChanged = waitForSecurityChange(1, tabbrowser.ownerGlobal);
+  let contentBlockingEvent = waitForContentBlockingEvent(2, tabbrowser.ownerGlobal);
   tabbrowser.reload();
-  await securityChanged;
+  await Promise.all([securityChanged, contentBlockingEvent]);
 
   ok(ContentBlocking.iconBox.hasAttribute("active"), "iconBox active");
   ok(ContentBlocking.iconBox.hasAttribute("animate"), "iconBox animating");
   await BrowserTestUtils.waitForEvent(ContentBlocking.animatedIcon, "animationend");
 
   info("Reload tracking tab");
-  securityChanged = waitForSecurityChange(3, tabbrowser.ownerGlobal);
+  securityChanged = waitForSecurityChange(2, tabbrowser.ownerGlobal);
+  contentBlockingEvent = waitForContentBlockingEvent(3, tabbrowser.ownerGlobal);
   tabbrowser.selectedTab = trackingTab;
   tabbrowser.reload();
-  await securityChanged;
+  await Promise.all([securityChanged, contentBlockingEvent]);
 
   ok(ContentBlocking.iconBox.hasAttribute("active"), "iconBox active");
   ok(ContentBlocking.iconBox.hasAttribute("animate"), "iconBox animating");
   await BrowserTestUtils.waitForEvent(ContentBlocking.animatedIcon, "animationend");
 
   info("Inject tracking cookie inside tracking tab");
   securityChanged = waitForSecurityChange(1, tabbrowser.ownerGlobal);
   let timeoutPromise = new Promise(resolve => setTimeout(resolve, 500));
--- a/browser/base/content/test/trackingUI/browser_trackingUI_fetch.js
+++ b/browser/base/content/test/trackingUI/browser_trackingUI_fetch.js
@@ -1,23 +1,23 @@
 const URL = "http://mochi.test:8888/browser/browser/base/content/test/trackingUI/file_trackingUI_fetch.html";
 
 add_task(async function test_fetch() {
   await SpecialPowers.pushPrefEnv({ set: [
     ["privacy.trackingprotection.enabled", true],
   ]});
 
   await BrowserTestUtils.withNewTab({ gBrowser, url: URL }, async function(newTabBrowser) {
-    let securityChange = waitForSecurityChange();
+    let contentBlockingEvent = waitForContentBlockingEvent();
     await ContentTask.spawn(newTabBrowser, null, async function() {
       await content.wrappedJSObject.test_fetch()
                    .then(response => Assert.ok(false, "should have denied the request"))
                    .catch(e => Assert.ok(true, `Caught exception: ${e}`));
     });
-    await securityChange;
+    await contentBlockingEvent;
 
     let ContentBlocking = newTabBrowser.ownerGlobal.ContentBlocking;
     ok(ContentBlocking, "got CB object");
 
     ok(ContentBlocking.content.hasAttribute("detected"), "has detected content blocking");
     ok(ContentBlocking.iconBox.hasAttribute("active"), "icon box is active");
     is(ContentBlocking.iconBox.getAttribute("tooltiptext"),
        gNavigatorBundle.getString("trackingProtection.icon.activeTooltip"), "correct tooltip");
--- a/browser/base/content/test/trackingUI/browser_trackingUI_telemetry.js
+++ b/browser/base/content/test/trackingUI/browser_trackingUI_telemetry.js
@@ -49,17 +49,17 @@ add_task(async function testShieldHistog
   // Reset these to make counting easier
   getShieldHistogram().clear();
 
   await promiseTabLoadEvent(tab, BENIGN_PAGE);
   is(getShieldCounts()[0], 1, "Page loads without tracking");
 
   await promiseTabLoadEvent(tab, TRACKING_PAGE);
   // Note that right now the shield histogram is not measuring what
-  // you might think.  Since onSecurityChange fires twice for a tracking page,
+  // you might think.  Since onContentBlockingEvent fires twice for a tracking page,
   // the total page loads count is double counting, and the shield count
   // (which is meant to measure times when the shield wasn't shown) fires even
   // when tracking elements exist on the page.
   todo_is(getShieldCounts()[0], 1, "FIXME: TOTAL PAGE LOADS WITHOUT TRACKING IS DOUBLE COUNTING");
 
   info("Disable TP for the page (which reloads the page)");
   let tabReloadPromise = promiseTabLoadEvent(tab);
   document.querySelector("#tracking-action-unblock").doCommand();
--- a/browser/base/content/test/trackingUI/head.js
+++ b/browser/base/content/test/trackingUI/head.js
@@ -54,8 +54,28 @@ function waitForSecurityChange(numChange
           win.gBrowser.removeProgressListener(listener);
           resolve(n);
         }
       },
     };
     win.gBrowser.addProgressListener(listener);
   });
 }
+
+function waitForContentBlockingEvent(numChanges = 1, win = null) {
+  if (!win) {
+    win = window;
+  }
+  return new Promise(resolve => {
+    let n = 0;
+    let listener = {
+      onContentBlockingEvent() {
+        n = n + 1;
+        info("Received onContentBlockingEvent event " + n + " of " + numChanges);
+        if (n >= numChanges) {
+          win.gBrowser.removeProgressListener(listener);
+          resolve(n);
+        }
+      },
+    };
+    win.gBrowser.addProgressListener(listener);
+  });
+}
--- a/browser/components/extensions/parent/ext-tabs.js
+++ b/browser/components/extensions/parent/ext-tabs.js
@@ -1239,16 +1239,17 @@ this.tabs = class extends ExtensionAPI {
                 if (pageSettings.footerRight !== null) {
                   printSettings.footerStrRight = pageSettings.footerRight;
                 }
 
                 let printProgressListener = {
                   onLocationChange(webProgress, request, location, flags) { },
                   onProgressChange(webProgress, request, curSelfProgress, maxSelfProgress, curTotalProgress, maxTotalProgress) { },
                   onSecurityChange(webProgress, request, state) { },
+                  onContentBlockingEvent(webProgress, request, event) { },
                   onStateChange(webProgress, request, flags, status) {
                     if ((flags & Ci.nsIWebProgressListener.STATE_STOP) && (flags & Ci.nsIWebProgressListener.STATE_IS_DOCUMENT)) {
                       resolve(retval == 0 ? "saved" : "replaced");
                     }
                   },
                   onStatusChange: function(webProgress, request, status, message) {
                     if (status != 0) {
                       resolve(retval == 0 ? "not_saved" : "not_replaced");
--- a/browser/components/shell/nsMacShellService.cpp
+++ b/browser/components/shell/nsMacShellService.cpp
@@ -184,16 +184,23 @@ nsMacShellService::OnStatusChange(nsIWeb
 
 NS_IMETHODIMP
 nsMacShellService::OnSecurityChange(nsIWebProgress* aWebProgress,
                                     nsIRequest* aRequest, uint32_t aState) {
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsMacShellService::OnContentBlockingEvent(nsIWebProgress* aWebProgress,
+                                          nsIRequest* aRequest,
+                                          uint32_t aEvent) {
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsMacShellService::OnStateChange(nsIWebProgress* aWebProgress,
                                  nsIRequest* aRequest, uint32_t aStateFlags,
                                  nsresult aStatus) {
   if (aStateFlags & STATE_STOP) {
     nsCOMPtr<nsIObserverService> os(
         do_GetService("@mozilla.org/observer-service;1"));
     if (os)
       os->NotifyObservers(nullptr, "shell:desktop-background-changed", nullptr);
--- a/browser/modules/test/browser/browser_UsageTelemetry_domains.js
+++ b/browser/modules/test/browser/browser_UsageTelemetry_domains.js
@@ -19,16 +19,17 @@ Services.obs.notifyObservers(null, TELEM
  * @resolves When navigating to a non-error page.
  */
 function browserLocationChanged(browser) {
   return new Promise(resolve => {
     let wpl = {
       onStateChange() {},
       onSecurityChange() {},
       onStatusChange() {},
+      onContentBlockingEvent() {},
       onLocationChange(aWebProgress, aRequest, aURI, aFlags) {
         if (!(aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE)) {
           browser.webProgress.removeProgressListener(filter);
           filter.removeProgressListener(wpl);
           resolve();
         }
       },
       QueryInterface: ChromeUtils.generateQI([
--- a/devtools/client/responsive.html/browser/tunnel.js
+++ b/devtools/client/responsive.html/browser/tunnel.js
@@ -417,16 +417,17 @@ MessageManagerTunnel.prototype = {
     "PageStyle:StyleSheets",
     // Messages sent to RemoteWebProgress.jsm
     "Content:LoadURIResult",
     "Content:LocationChange",
     "Content:ProgressChange",
     "Content:SecurityChange",
     "Content:StateChange",
     "Content:StatusChange",
+    "Content:ContentBlockingEvent",
     // Messages sent to browser.js
     "DOMTitleChanged",
     "ImageDocumentLoaded",
     "Forms:ShowDropDown",
     "Forms:HideDropDown",
     "InPermitUnload",
     "PermitUnload",
     // Messages sent to tabbrowser.xml
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -6543,16 +6543,23 @@ nsDocShell::OnStatusChange(nsIWebProgres
 
 NS_IMETHODIMP
 nsDocShell::OnSecurityChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest,
                              uint32_t aState) {
   MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsDocShell::OnContentBlockingEvent(nsIWebProgress* aWebProgress,
+                                   nsIRequest* aRequest, uint32_t aEvent) {
+  MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
+  return NS_OK;
+}
+
 nsresult nsDocShell::EndPageLoad(nsIWebProgress* aProgress,
                                  nsIChannel* aChannel, nsresult aStatus) {
   if (!aChannel) {
     return NS_ERROR_NULL_POINTER;
   }
 
   // Make sure to discard the initial client if we never created the initial
   // about:blank document.  Do this before possibly returning from the method
--- a/docshell/base/nsDocShellTreeOwner.cpp
+++ b/docshell/base/nsDocShellTreeOwner.cpp
@@ -695,16 +695,23 @@ nsDocShellTreeOwner::OnStatusChange(nsIW
 }
 
 NS_IMETHODIMP
 nsDocShellTreeOwner::OnSecurityChange(nsIWebProgress* aWebProgress,
                                       nsIRequest* aRequest, uint32_t aState) {
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsDocShellTreeOwner::OnContentBlockingEvent(nsIWebProgress* aWebProgress,
+                                            nsIRequest* aRequest,
+                                            uint32_t aEvent) {
+  return NS_OK;
+}
+
 //*****************************************************************************
 // nsDocShellTreeOwner: Accessors
 //*****************************************************************************
 
 void nsDocShellTreeOwner::WebBrowser(nsWebBrowser* aWebBrowser) {
   if (!aWebBrowser) {
     RemoveChromeListeners();
   }
--- a/docshell/test/browser/browser_onbeforeunload_navigation.js
+++ b/docshell/test/browser/browser_onbeforeunload_navigation.js
@@ -150,16 +150,17 @@ var tabStateListener = {
     if ((stateFlags & startDocumentFlags) == startDocumentFlags) {
       loadStarted = true;
     }
   },
   onStatusChange: () => {},
   onLocationChange: () => {},
   onSecurityChange: () => {},
   onProgressChange: () => {},
+  onContentBlockingEvent: () => {},
   QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener])
 };
 
 function onTabModalDialogLoaded(node) {
   let mm = testTab.linkedBrowser.messageManager;
   mm.sendAsyncMessage("test-beforeunload:dialog");
 
   if (gMultiProcessBrowser) {
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -5034,17 +5034,17 @@ void nsGlobalWindowOuter::FirePopupBlock
   RefPtr<PopupBlockedEvent> event = PopupBlockedEvent::Constructor(
       aDoc, NS_LITERAL_STRING("DOMPopupBlocked"), init);
 
   event->SetTrusted(true);
 
   aDoc->DispatchEvent(*event);
 }
 
-void nsGlobalWindowOuter::NotifyContentBlockingState(unsigned aState,
+void nsGlobalWindowOuter::NotifyContentBlockingEvent(unsigned aEvent,
                                                      nsIChannel* aChannel,
                                                      bool aBlocked,
                                                      nsIURI* aURIHint) {
   MOZ_ASSERT(aURIHint);
 
   nsCOMPtr<nsIDocShell> docShell = GetDocShell();
   if (!docShell) {
     return;
@@ -5052,105 +5052,105 @@ void nsGlobalWindowOuter::NotifyContentB
   nsCOMPtr<Document> doc = docShell->GetDocument();
   NS_ENSURE_TRUE_VOID(doc);
 
   // This event might come after the user has navigated to another page.
   // To prevent showing the TrackingProtection UI on the wrong page, we need to
   // check that the loading URI for the channel is the same as the URI currently
   // loaded in the document.
   if (!SameLoadingURI(doc, aChannel) &&
-      aState == nsIWebProgressListener::STATE_BLOCKED_TRACKING_CONTENT) {
+      aEvent == nsIWebProgressListener::STATE_BLOCKED_TRACKING_CONTENT) {
     return;
   }
 
-  // Notify nsIWebProgressListeners of this security event.
+  // Notify nsIWebProgressListeners of this content blocking event.
   // Can be used to change the UI state.
   nsresult rv = NS_OK;
   nsCOMPtr<nsISecurityEventSink> eventSink = do_QueryInterface(docShell, &rv);
   NS_ENSURE_SUCCESS_VOID(rv);
-  uint32_t state = 0;
+  uint32_t event = 0;
   nsCOMPtr<nsISecureBrowserUI> securityUI;
   docShell->GetSecurityUI(getter_AddRefs(securityUI));
   if (!securityUI) {
     return;
   }
-  securityUI->GetState(&state);
+  securityUI->GetContentBlockingEvent(&event);
   nsAutoCString origin;
   nsContentUtils::GetASCIIOrigin(aURIHint, origin);
 
   bool blockedValue = aBlocked;
   bool unblocked = false;
-  if (aState == nsIWebProgressListener::STATE_BLOCKED_TRACKING_CONTENT) {
+  if (aEvent == nsIWebProgressListener::STATE_BLOCKED_TRACKING_CONTENT) {
     doc->SetHasTrackingContentBlocked(aBlocked, origin);
     if (!aBlocked) {
       unblocked = !doc->GetHasTrackingContentBlocked();
     }
-  } else if (aState == nsIWebProgressListener::STATE_LOADED_TRACKING_CONTENT) {
+  } else if (aEvent == nsIWebProgressListener::STATE_LOADED_TRACKING_CONTENT) {
     doc->SetHasTrackingContentLoaded(aBlocked, origin);
     if (!aBlocked) {
       unblocked = !doc->GetHasTrackingContentLoaded();
     }
-  } else if (aState ==
+  } else if (aEvent ==
              nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION) {
     doc->SetHasCookiesBlockedByPermission(aBlocked, origin);
     if (!aBlocked) {
       unblocked = !doc->GetHasCookiesBlockedByPermission();
     }
-  } else if (aState == nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER) {
+  } else if (aEvent == nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER) {
     doc->SetHasTrackingCookiesBlocked(aBlocked, origin);
     if (!aBlocked) {
       unblocked = !doc->GetHasTrackingCookiesBlocked();
     }
-  } else if (aState == nsIWebProgressListener::STATE_COOKIES_BLOCKED_ALL) {
+  } else if (aEvent == nsIWebProgressListener::STATE_COOKIES_BLOCKED_ALL) {
     doc->SetHasAllCookiesBlocked(aBlocked, origin);
     if (!aBlocked) {
       unblocked = !doc->GetHasAllCookiesBlocked();
     }
-  } else if (aState == nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN) {
+  } else if (aEvent == nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN) {
     doc->SetHasForeignCookiesBlocked(aBlocked, origin);
     if (!aBlocked) {
       unblocked = !doc->GetHasForeignCookiesBlocked();
     }
-  } else if (aState == nsIWebProgressListener::STATE_COOKIES_LOADED) {
+  } else if (aEvent == nsIWebProgressListener::STATE_COOKIES_LOADED) {
     MOZ_ASSERT(!aBlocked,
                "We don't expected to see blocked STATE_COOKIES_LOADED");
     // Note that the logic in this branch is the logical negation of the logic
     // in other branches, since the Document API we have is phrased in
     // "loaded" terms as opposed to "blocked" terms.
     blockedValue = !aBlocked;
     doc->SetHasCookiesLoaded(blockedValue, origin);
     if (!aBlocked) {
       unblocked = !doc->GetHasCookiesLoaded();
     }
   } else {
     // Ignore nsIWebProgressListener::STATE_BLOCKED_UNSAFE_CONTENT;
   }
-  const uint32_t oldState = state;
+  const uint32_t oldEvent = event;
   if (blockedValue) {
-    state |= aState;
+    event |= aEvent;
   } else if (unblocked) {
-    state &= ~aState;
-  }
-
-  if (state == oldState
+    event &= ~aEvent;
+  }
+
+  if (event == oldEvent
 #ifdef ANDROID
       // GeckoView always needs to notify about blocked trackers, since the
       // GeckoView API always needs to report the URI and type of any blocked
       // tracker.
       // We use a platform-dependent code path here because reporting this
       // notification on desktop platforms isn't necessary and doing so can have
       // a big performance cost.
-      && aState != nsIWebProgressListener::STATE_BLOCKED_TRACKING_CONTENT
+      && aEvent != nsIWebProgressListener::STATE_BLOCKED_TRACKING_CONTENT
 #endif
   ) {
     // Avoid dispatching repeated notifications when nothing has changed
     return;
   }
 
-  eventSink->OnContentBlockingEvent(aChannel, state);
+  eventSink->OnContentBlockingEvent(aChannel, event);
 }
 
 // static
 bool nsGlobalWindowOuter::SameLoadingURI(Document* aDoc, nsIChannel* aChannel) {
   nsCOMPtr<nsIURI> docURI = aDoc->GetDocumentURI();
   nsCOMPtr<nsILoadInfo> channelLoadInfo = aChannel->GetLoadInfo();
   if (!channelLoadInfo || !docURI) {
     return false;
--- a/dom/base/nsGlobalWindowOuter.h
+++ b/dom/base/nsGlobalWindowOuter.h
@@ -453,17 +453,17 @@ class nsGlobalWindowOuter final : public
   bool HadOriginalOpener() const { return mHadOriginalOpener; }
 
   bool IsTopLevelWindow();
 
   virtual void FirePopupBlockedEvent(
       Document* aDoc, nsIURI* aPopupURI, const nsAString& aPopupWindowName,
       const nsAString& aPopupWindowFeatures) override;
 
-  virtual void NotifyContentBlockingState(unsigned aState, nsIChannel* aChannel,
+  virtual void NotifyContentBlockingEvent(unsigned aEvent, nsIChannel* aChannel,
                                           bool aBlocked,
                                           nsIURI* aURIHint) override;
 
   void AddSizeOfIncludingThis(nsWindowSizes& aWindowSizes) const;
 
   void AllowScriptsToClose() { mAllowScriptsToClose = true; }
 
   // Outer windows only.
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -1018,17 +1018,17 @@ class nsPIDOMWindowOuter : public mozIDO
 
   /**
    * Fire a popup blocked event on the document.
    */
   virtual void FirePopupBlockedEvent(Document* aDoc, nsIURI* aPopupURI,
                                      const nsAString& aPopupWindowName,
                                      const nsAString& aPopupWindowFeatures) = 0;
 
-  virtual void NotifyContentBlockingState(unsigned aState, nsIChannel* aChannel,
+  virtual void NotifyContentBlockingEvent(unsigned aEvent, nsIChannel* aChannel,
                                           bool aBlocked, nsIURI* aURIHint) = 0;
 
   // WebIDL-ish APIs
   void MarkUncollectableForCCGeneration(uint32_t aGeneration) {
     mMarkedCCGeneration = aGeneration;
   }
 
   uint32_t GetMarkedCCGeneration() { return mMarkedCCGeneration; }
--- a/dom/browser-element/BrowserElementChildPreload.js
+++ b/dom/browser-element/BrowserElementChildPreload.js
@@ -1196,47 +1196,34 @@ BrowserElementChild.prototype = {
       else if (state & Ci.nsIWebProgressListener.STATE_IS_INSECURE) {
         securityStateDesc = 'insecure';
       }
       else {
         debug("Unexpected securitychange state!");
         securityStateDesc = '???';
       }
 
-      var trackingStateDesc;
-      if (state & Ci.nsIWebProgressListener.STATE_LOADED_TRACKING_CONTENT) {
-        trackingStateDesc = 'loaded_tracking_content';
-      }
-      else if (state & Ci.nsIWebProgressListener.STATE_BLOCKED_TRACKING_CONTENT) {
-        trackingStateDesc = 'blocked_tracking_content';
-      }
-
       var mixedStateDesc;
       if (state & Ci.nsIWebProgressListener.STATE_BLOCKED_MIXED_ACTIVE_CONTENT) {
         mixedStateDesc = 'blocked_mixed_active_content';
       }
       else if (state & Ci.nsIWebProgressListener.STATE_LOADED_MIXED_ACTIVE_CONTENT) {
         // Note that STATE_LOADED_MIXED_ACTIVE_CONTENT implies STATE_IS_BROKEN
         mixedStateDesc = 'loaded_mixed_active_content';
       }
 
       var isEV = !!(state & Ci.nsIWebProgressListener.STATE_IDENTITY_EV_TOPLEVEL);
-      var isTrackingContent = !!(state &
-        (Ci.nsIWebProgressListener.STATE_BLOCKED_TRACKING_CONTENT |
-        Ci.nsIWebProgressListener.STATE_LOADED_TRACKING_CONTENT));
       var isMixedContent = !!(state &
         (Ci.nsIWebProgressListener.STATE_BLOCKED_MIXED_ACTIVE_CONTENT |
         Ci.nsIWebProgressListener.STATE_LOADED_MIXED_ACTIVE_CONTENT));
 
       sendAsyncMsg('securitychange', {
         state: securityStateDesc,
-        trackingState: trackingStateDesc,
         mixedState: mixedStateDesc,
         extendedValidation: isEV,
-        trackingContent: isTrackingContent,
         mixedContent: isMixedContent,
       });
     },
   },
 
   // Expose the message manager for WebApps and others.
   _messageManagerPublic: {
     sendAsyncMessage: global.sendAsyncMessage.bind(global),
--- a/dom/browser-element/mochitest/browserElement_SecurityChange.js
+++ b/dom/browser-element/mochitest/browserElement_SecurityChange.js
@@ -4,19 +4,16 @@
 // Bug 763694 - Test that <iframe mozbrowser> delivers proper
 // mozbrowsersecuritychange events.
 
 "use strict";
 SimpleTest.waitForExplicitFinish();
 browserElementTestHelpers.setEnabledPref(true);
 browserElementTestHelpers.addPermission();
 
-const { Services } = SpecialPowers.Cu.import('resource://gre/modules/Services.jsm');
-const { UrlClassifierTestUtils } = SpecialPowers.Cu.import('resource://testing-common/UrlClassifierTestUtils.jsm', {});
-
 function runTest() {
   var iframe = document.createElement('iframe');
   iframe.setAttribute('mozbrowser', 'true');
 
   var lastSecurityState;
   iframe.addEventListener('mozbrowsersecuritychange', function(e) {
     lastSecurityState = e.detail;
   });
@@ -25,58 +22,37 @@ function runTest() {
 
   var count = 0;
   iframe.addEventListener('mozbrowserloadend', function(e) {
     count++;
     switch (count) {
     case 1:
       is(lastSecurityState.state, 'secure');
       is(lastSecurityState.extendedValidation, false);
-      is(lastSecurityState.trackingContent, false);
       is(lastSecurityState.mixedContent, false);
       iframe.src = "http://example.com/" + filepath;
       break;
     case 2:
       is(lastSecurityState.state, 'insecure');
       is(lastSecurityState.extendedValidation, false);
-      is(lastSecurityState.trackingContent, false);
       is(lastSecurityState.mixedContent, false);
       iframe.src = 'https://example.com:443/' + filepath + '?broken';
       break;
     case 3:
       is(lastSecurityState.state, 'broken');
       is(lastSecurityState.extendedValidation, false);
-      is(lastSecurityState.trackingContent, false);
       is(lastSecurityState.mixedContent, true);
-      iframe.src = "http://example.com/" + filepath + '?tracking';
+      SimpleTest.finish();
       break;
-    case 4:
-      is(lastSecurityState.state, 'insecure');
-      is(lastSecurityState.extendedValidation, false);
-      // TODO: I'm having trouble getting the tracking protection
-      // test changes to be enabled in the child process, so this
-      // isn't currently blocked in tests, but it works when
-      // manually testing.
-      // is(lastSecurityState.trackingContent, true);
-      is(lastSecurityState.mixedContent, false);
-      SimpleTest.finish();
     }
   });
 
   iframe.src = "https://example.com/" + filepath;
   document.body.appendChild(iframe);
 }
 
 addEventListener('testready', function() {
-  SimpleTest.registerCleanupFunction(UrlClassifierTestUtils.cleanupTestTrackers);
   SpecialPowers.pushPrefEnv({"set" : [
-    ["privacy.trackingprotection.enabled", true],
-    ["privacy.trackingprotection.pbmode.enabled", false],
     ["browser.safebrowsing.phishing.enabled", false],
     ["browser.safebrowsing.malware.enabled", false],
-  ]}, () => {
-     SimpleTest.registerCleanupFunction(UrlClassifierTestUtils.cleanupTestTrackers);
-     UrlClassifierTestUtils.addTestTrackers().then(() => {
-       runTest();
-     });
-  });
+  ]}, runTest);
 });
 
--- a/dom/browser-element/mochitest/file_browserElement_SecurityChange.html
+++ b/dom/browser-element/mochitest/file_browserElement_SecurityChange.html
@@ -2,20 +2,16 @@
 <head>
 
 <script>
 if (location.search === '?broken') {
   // Load something non-https.
   var s = document.createElement('script');
   s.src = 'http://example.com/dom/browser-element/mochitest/file_empty_script.js';
   document.head.appendChild(s);
-} else if (location.search === '?tracking') {
-  var img = document.createElement('img');
-  img.src = 'http://tracking.example.com/tests/toolkit/components/url-classifier/tests/mochitest/raptor.jpg';
-  document.body.appendChild(img);
 }
 </script>
 </head>
 
 <body>
 file_browserElement_SecurityChange.html.
 </body>
 </html>
--- a/dom/clients/manager/ClientNavigateOpChild.cpp
+++ b/dom/clients/manager/ClientNavigateOpChild.cpp
@@ -121,16 +121,23 @@ class NavigateLoadListener final : publi
 
   NS_IMETHOD
   OnSecurityChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest,
                    uint32_t aState) override {
     MOZ_CRASH("Unexpected notification.");
     return NS_OK;
   }
 
+  NS_IMETHOD
+  OnContentBlockingEvent(nsIWebProgress* aWebProgress, nsIRequest* aRequest,
+                         uint32_t aEvent) override {
+    MOZ_CRASH("Unexpected notification.");
+    return NS_OK;
+  }
+
   NS_DECL_ISUPPORTS
 };
 
 NS_IMPL_ISUPPORTS(NavigateLoadListener, nsIWebProgressListener,
                   nsISupportsWeakReference);
 
 }  // anonymous namespace
 
--- a/dom/clients/manager/ClientOpenWindowUtils.cpp
+++ b/dom/clients/manager/ClientOpenWindowUtils.cpp
@@ -117,16 +117,23 @@ class WebProgressListener final : public
 
   NS_IMETHOD
   OnSecurityChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest,
                    uint32_t aState) override {
     MOZ_ASSERT(false, "Unexpected notification.");
     return NS_OK;
   }
 
+  NS_IMETHOD
+  OnContentBlockingEvent(nsIWebProgress* aWebProgress, nsIRequest* aRequest,
+                         uint32_t aEvent) override {
+    MOZ_ASSERT(false, "Unexpected notification.");
+    return NS_OK;
+  }
+
  private:
   ~WebProgressListener() {
     if (mPromise) {
       mPromise->Reject(NS_ERROR_ABORT, __func__);
       mPromise = nullptr;
     }
   }
 
--- a/dom/html/HTMLFormElement.cpp
+++ b/dom/html/HTMLFormElement.cpp
@@ -1969,17 +1969,24 @@ HTMLFormElement::OnStatusChange(nsIWebPr
                                 nsIRequest* aRequest, nsresult aStatus,
                                 const char16_t* aMessage) {
   MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HTMLFormElement::OnSecurityChange(nsIWebProgress* aWebProgress,
-                                  nsIRequest* aRequest, uint32_t state) {
+                                  nsIRequest* aRequest, uint32_t aState) {
+  MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HTMLFormElement::OnContentBlockingEvent(nsIWebProgress* aWebProgress,
+                                        nsIRequest* aRequest, uint32_t aEvent) {
   MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
   return NS_OK;
 }
 
 NS_IMETHODIMP_(int32_t)
 HTMLFormElement::IndexOfControl(nsIFormControl* aControl) {
   int32_t index = 0;
   return mControls->IndexOfControl(aControl, &index) == NS_OK ? index : 0;
--- a/dom/html/nsHTMLDNSPrefetch.cpp
+++ b/dom/html/nsHTMLDNSPrefetch.cpp
@@ -501,17 +501,23 @@ nsHTMLDNSPrefetch::nsDeferrals::OnStatus
                                                nsresult aStatus,
                                                const char16_t *aMessage) {
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLDNSPrefetch::nsDeferrals::OnSecurityChange(nsIWebProgress *aWebProgress,
                                                  nsIRequest *aRequest,
-                                                 uint32_t state) {
+                                                 uint32_t aState) {
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsHTMLDNSPrefetch::nsDeferrals::OnContentBlockingEvent(
+    nsIWebProgress *aWebProgress, nsIRequest *aRequest, uint32_t aEvent) {
   return NS_OK;
 }
 
 //////////// nsIObserver method
 
 NS_IMETHODIMP
 nsHTMLDNSPrefetch::nsDeferrals::Observe(nsISupports *subject, const char *topic,
                                         const char16_t *data) {
--- a/dom/presentation/PresentationCallbacks.cpp
+++ b/dom/presentation/PresentationCallbacks.cpp
@@ -230,12 +230,19 @@ PresentationResponderLoadingCallback::On
     nsIWebProgress* aWebProgress, nsIRequest* aRequest, nsresult aStatus,
     const char16_t* aMessage) {
   // Do nothing.
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PresentationResponderLoadingCallback::OnSecurityChange(
-    nsIWebProgress* aWebProgress, nsIRequest* aRequest, uint32_t state) {
+    nsIWebProgress* aWebProgress, nsIRequest* aRequest, uint32_t aState) {
   // Do nothing.
   return NS_OK;
 }
+
+NS_IMETHODIMP
+PresentationResponderLoadingCallback::OnContentBlockingEvent(
+    nsIWebProgress* aWebProgress, nsIRequest* aRequest, uint32_t aEvent) {
+  // Do nothing.
+  return NS_OK;
+}
--- a/editor/composer/nsEditingSession.cpp
+++ b/editor/composer/nsEditingSession.cpp
@@ -783,17 +783,30 @@ nsEditingSession::OnStatusChange(nsIWebP
 
 /*---------------------------------------------------------------------------
 
   OnSecurityChange
 
 ----------------------------------------------------------------------------*/
 NS_IMETHODIMP
 nsEditingSession::OnSecurityChange(nsIWebProgress* aWebProgress,
-                                   nsIRequest* aRequest, uint32_t state) {
+                                   nsIRequest* aRequest, uint32_t aState) {
+  MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
+  return NS_OK;
+}
+
+/*---------------------------------------------------------------------------
+
+  OnContentBlockingEvent
+
+----------------------------------------------------------------------------*/
+NS_IMETHODIMP
+nsEditingSession::OnContentBlockingEvent(nsIWebProgress* aWebProgress,
+                                         nsIRequest* aRequest,
+                                         uint32_t aEvent) {
   MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
   return NS_OK;
 }
 
 /*---------------------------------------------------------------------------
 
   IsProgressForTargetDocument
 
--- a/editor/composer/test/test_bug434998.xul
+++ b/editor/composer/test/test_bug434998.xul
@@ -86,16 +86,20 @@ https://bugzilla.mozilla.org/show_bug.cg
     onStatusChange : function(aWebProgress, aRequest, aStatus, aMessage)
     {
     },
 
     onSecurityChange : function(aWebProgress, aRequest, aState)
     {
     },
 
+    onContentBlockingEvent : function(aWebProgress, aRequest, aEvent)
+    {
+    },
+
     mEditor: null
   };
 
   var progress, progressListener;
 
   function runTest() {
     var newEditorElement = document.getElementById("editor");
     newEditorElement.makeEditable("html", true);
--- a/editor/libeditor/tests/test_bug607584.xul
+++ b/editor/libeditor/tests/test_bug607584.xul
@@ -91,16 +91,20 @@ https://bugzilla.mozilla.org/show_bug.cg
   
     onStatusChange : function(aWebProgress, aRequest, aStatus, aMessage)
       {
       },
   
     onSecurityChange : function(aWebProgress, aRequest, aState)
       {
       },
+
+    onContentBlockingEvent : function(aWebProgress, aRequest, aEvent)
+      {
+      },
   
       mEditor: null
   };
 
   var progress, progressListener;
 
   function runTest() {
     var newEditorElement = document.getElementById("editor");
--- a/editor/libeditor/tests/test_bug616590.xul
+++ b/editor/libeditor/tests/test_bug616590.xul
@@ -81,16 +81,20 @@ https://bugzilla.mozilla.org/show_bug.cg
     onStatusChange : function(aWebProgress, aRequest, aStatus, aMessage)
     {
     },
 
     onSecurityChange : function(aWebProgress, aRequest, aState)
     {
     },
 
+    onContentBlockingEvent : function(aWebProgress, aRequest, aEvent)
+    {
+    },
+
     mEditor: null
   };
 
   var progress, progressListener;
 
   function runTest() {
     var editorElement = document.getElementById("editor");
     editorElement.makeEditable("htmlmail", true);
--- a/editor/libeditor/tests/test_bug780908.xul
+++ b/editor/libeditor/tests/test_bug780908.xul
@@ -90,16 +90,20 @@ adapted from test_bug607584.xul by Kent 
     onStatusChange : function(aWebProgress, aRequest, aStatus, aMessage)
       {
       },
   
     onSecurityChange : function(aWebProgress, aRequest, aState)
       {
       },
   
+    onContentBlockingEvent : function(aWebProgress, aRequest, aEvent)
+      {
+      },
+  
       mEditor: null
   };
 
   var progress, progressListener;
 
   function runTest() {
     var newEditorElement = document.getElementById("editor");
     newEditorElement.makeEditable("html", true);
--- a/layout/base/tests/chrome/printpreview_bug396024_helper.xul
+++ b/layout/base/tests/chrome/printpreview_bug396024_helper.xul
@@ -21,16 +21,17 @@ function printpreview() {
   var listener = {
     onLocationChange: function(webProgress, request, location, flags) { },
     onProgressChange: function(webProgress, request, curSelfProgress, 
                                maxSelfProgress, curTotalProgress,
                                maxTotalProgress) { },
     onSecurityChange: function(webProgress, request, state) { },
     onStateChange: function(webProgress, request, stateFlags, status) { },
     onStatusChange: function(webProgress, request, status, message) { },
+    onContentBlockingEvent: function(webProgress, request, event) { },
     QueryInterface: function(iid) {
       if (iid.equals(Ci.nsIWebProgressListener) ||
           iid.equals(Ci.nsISupportsWeakReference))
             return this;
       throw Cr.NS_NOINTERFACE;
     }
   }
   var prefs = Cc["@mozilla.org/preferences-service;1"]
--- a/layout/base/tests/chrome/printpreview_bug482976_helper.xul
+++ b/layout/base/tests/chrome/printpreview_bug482976_helper.xul
@@ -21,16 +21,17 @@ function printpreview() {
   var listener = {
     onLocationChange: function(webProgress, request, location, flags) { },
     onProgressChange: function(webProgress, request, curSelfProgress, 
                                maxSelfProgress, curTotalProgress,
                                maxTotalProgress) { },
     onSecurityChange: function(webProgress, request, state) { },
     onStateChange: function(webProgress, request, stateFlags, status) { },
     onStatusChange: function(webProgress, request, status, message) { },
+    onContentBlockingEvent: function(webProgress, request, event) { },
     QueryInterface: function(iid) {
       if (iid.equals(Ci.nsIWebProgessListener) ||
           iid.equals(Ci.nsISupportsWeakReference))
             return this;
       throw Cr.NS_NOINTERFACE;
     }
   }
   var prefs = Cc["@mozilla.org/preferences-service;1"]
--- a/layout/base/tests/chrome/printpreview_helper.xul
+++ b/layout/base/tests/chrome/printpreview_helper.xul
@@ -28,16 +28,17 @@ function printpreview() {
   var listener = {
     onLocationChange: function(webProgress, request, location, flags) { },
     onProgressChange: function(webProgress, request, curSelfProgress, 
                                maxSelfProgress, curTotalProgress,
                                maxTotalProgress) { },
     onSecurityChange: function(webProgress, request, state) { },
     onStateChange: function(webProgress, request, stateFlags, status) { },
     onStatusChange: function(webProgress, request, status, message) { },
+    onContentBlockingEvent: function(webProgress, request, event) { },
     QueryInterface: function(iid) {
       if (iid.equals(Ci.nsIWebProgressListener) ||
           iid.equals(Ci.nsISupportsWeakReference))
             return this;
       throw Cr.NS_NOINTERFACE;
     }
   }
   var prefs = Cc["@mozilla.org/preferences-service;1"]
--- a/layout/printing/ipc/RemotePrintJobChild.cpp
+++ b/layout/printing/ipc/RemotePrintJobChild.cpp
@@ -139,16 +139,23 @@ RemotePrintJobChild::OnStatusChange(nsIW
 }
 
 NS_IMETHODIMP
 RemotePrintJobChild::OnSecurityChange(nsIWebProgress* aProgress,
                                       nsIRequest* aRequest, uint32_t aState) {
   return NS_OK;
 }
 
+NS_IMETHODIMP
+RemotePrintJobChild::OnContentBlockingEvent(nsIWebProgress* aProgress,
+                                            nsIRequest* aRequest,
+                                            uint32_t aEvent) {
+  return NS_OK;
+}
+
 // End of nsIWebProgressListener
 
 RemotePrintJobChild::~RemotePrintJobChild() {}
 
 void RemotePrintJobChild::ActorDestroy(ActorDestroyReason aWhy) {
   mPagePrintTimer = nullptr;
   mPrintJob = nullptr;
 
--- a/layout/printing/nsPrintJob.cpp
+++ b/layout/printing/nsPrintJob.cpp
@@ -2016,16 +2016,23 @@ nsPrintJob::OnStatusChange(nsIWebProgres
 
 NS_IMETHODIMP
 nsPrintJob::OnSecurityChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest,
                              uint32_t aState) {
   MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsPrintJob::OnContentBlockingEvent(nsIWebProgress* aWebProgress,
+                                   nsIRequest* aRequest, uint32_t aEvent) {
+  MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
+  return NS_OK;
+}
+
 //-------------------------------------------------------
 
 void nsPrintJob::UpdateZoomRatio(nsPrintObject* aPO, bool aSetPixelScale) {
   // Here is where we set the shrinkage value into the DC
   // and this is what actually makes it shrink
   if (aSetPixelScale && aPO->mFrameType != eIFrame) {
     float ratio;
     if (mPrt->mPrintFrameType == nsIPrintSettings::kFramesAsIs ||
--- a/layout/tools/layout-debug/ui/content/layoutdebug.js
+++ b/layout/tools/layout-debug/ui/content/layoutdebug.js
@@ -76,16 +76,20 @@ nsLDBBrowserContentListener.prototype = 
     {
       this.mStatusText.value = aMessage;
     },
 
   onSecurityChange : function(aWebProgress, aRequest, aState)
     {
     },
 
+  onContentBlockingEvent : function(aWebProgress, aRequest, aEvent)
+    {
+    },
+
   // non-interface methods
   setButtonEnabled : function(aButtonElement, aEnabled)
     {
       if (aEnabled)
         aButtonElement.removeAttribute("disabled");
       else
         aButtonElement.setAttribute("disabled", "true");
     },
--- a/layout/tools/reftest/reftest-content.js
+++ b/layout/tools/reftest/reftest-content.js
@@ -272,16 +272,17 @@ function printToPdf(callback) {
                 stateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK) {
                 callback(status, file.path);
             }
         },
         onProgressChange: function () {},
         onLocationChange: function () {},
         onStatusChange: function () {},
         onSecurityChange: function () {},
+        onContentBlockingEvent: function () {},
     });
 }
 
 function attrOrDefault(element, attr, def) {
     return element.hasAttribute(attr) ? Number(element.getAttribute(attr)) : def;
 }
 
 function setupViewport(contentRootElement) {
--- a/mobile/android/chrome/content/PrintHelper.js
+++ b/mobile/android/chrome/content/PrintHelper.js
@@ -57,12 +57,13 @@ var PrintHelper = {
               reject();
             }
           }
         },
         onProgressChange: function() {},
         onLocationChange: function() {},
         onStatusChange: function() {},
         onSecurityChange: function() {},
+        onContentBlockingEvent: function() {},
       });
     });
   },
 };
--- a/mobile/android/modules/geckoview/GeckoViewTrackingProtection.jsm
+++ b/mobile/android/modules/geckoview/GeckoViewTrackingProtection.jsm
@@ -7,28 +7,28 @@
 var EXPORTED_SYMBOLS = ["GeckoViewTrackingProtection"];
 
 ChromeUtils.import("resource://gre/modules/GeckoViewModule.jsm");
 
 class GeckoViewTrackingProtection extends GeckoViewModule {
   onEnable() {
     debug `onEnable`;
 
-    const flags = Ci.nsIWebProgress.NOTIFY_SECURITY;
+    const flags = Ci.nsIWebProgress.NOTIFY_CONTENT_BLOCKING;
     this.progressFilter =
       Cc["@mozilla.org/appshell/component/browser-status-filter;1"]
       .createInstance(Ci.nsIWebProgress);
     this.progressFilter.addProgressListener(this, flags);
     this.browser.addProgressListener(this.progressFilter, flags);
   }
 
-  onSecurityChange(aWebProgress, aRequest, aState) {
-    debug `onSecurityChange`;
+  onContentBlockingEvent(aWebProgress, aRequest, aEvent) {
+    debug `onContentBlockingEvent`;
 
-    if (!(aState & Ci.nsIWebProgressListener.STATE_BLOCKED_TRACKING_CONTENT) ||
+    if (!(aEvent & Ci.nsIWebProgressListener.STATE_BLOCKED_TRACKING_CONTENT) ||
         !aRequest || !(aRequest instanceof Ci.nsIClassifiedChannel)) {
       return;
     }
 
     let channel = aRequest.QueryInterface(Ci.nsIChannel);
     let uri = channel.URI && channel.URI.spec;
     let classChannel = aRequest.QueryInterface(Ci.nsIClassifiedChannel);
 
--- a/netwerk/base/nsISecureBrowserUI.idl
+++ b/netwerk/base/nsISecureBrowserUI.idl
@@ -10,14 +10,15 @@ interface nsIDocShell;
 interface nsITransportSecurityInfo;
 
 [scriptable, uuid(718c662a-f810-4a80-a6c9-0b1810ecade2)]
 interface nsISecureBrowserUI : nsISupports
 {
     void init(in nsIDocShell docShell);
 
     readonly attribute unsigned long state;
+    readonly attribute unsigned long contentBlockingEvent;
     readonly attribute nsITransportSecurityInfo secInfo;
 };
 
 %{C++
 #define NS_SECURE_BROWSER_UI_CONTRACTID "@mozilla.org/secure_browser_ui;1"
 %}
--- a/netwerk/url-classifier/UrlClassifierCommon.cpp
+++ b/netwerk/url-classifier/UrlClassifierCommon.cpp
@@ -79,17 +79,17 @@ LazyLogModule UrlClassifierCommon::sLog(
   if (!docShell) {
     return;
   }
   RefPtr<dom::Document> doc = docShell->GetDocument();
   NS_ENSURE_TRUE_VOID(doc);
 
   nsCOMPtr<nsIURI> uri;
   aChannel->GetURI(getter_AddRefs(uri));
-  pwin->NotifyContentBlockingState(aBlockedReason, aChannel, true, uri);
+  pwin->NotifyContentBlockingEvent(aBlockedReason, aChannel, true, uri);
 }
 
 /* static */ bool UrlClassifierCommon::ShouldEnableClassifier(
     nsIChannel* aChannel,
     AntiTrackingCommon::ContentBlockingAllowListPurpose aBlockingPurpose) {
   MOZ_ASSERT(aChannel);
   MOZ_ASSERT(aBlockingPurpose == AntiTrackingCommon::eTrackingProtection ||
              aBlockingPurpose == AntiTrackingCommon::eTrackingAnnotations ||
--- a/security/manager/ssl/nsSecureBrowserUIImpl.cpp
+++ b/security/manager/ssl/nsSecureBrowserUIImpl.cpp
@@ -17,17 +17,17 @@
 #include "nsISecurityEventSink.h"
 #include "nsITransportSecurityInfo.h"
 #include "nsIWebProgress.h"
 
 using namespace mozilla;
 
 LazyLogModule gSecureBrowserUILog("nsSecureBrowserUI");
 
-nsSecureBrowserUIImpl::nsSecureBrowserUIImpl() : mState(0) {
+nsSecureBrowserUIImpl::nsSecureBrowserUIImpl() : mState(0), mEvent(0) {
   MOZ_ASSERT(NS_IsMainThread());
 }
 
 NS_IMPL_ISUPPORTS(nsSecureBrowserUIImpl, nsISecureBrowserUI,
                   nsIWebProgressListener, nsISupportsWeakReference)
 
 NS_IMETHODIMP
 nsSecureBrowserUIImpl::Init(nsIDocShell* aDocShell) {
@@ -62,58 +62,81 @@ NS_IMETHODIMP
 nsSecureBrowserUIImpl::GetState(uint32_t* aState) {
   MOZ_ASSERT(NS_IsMainThread());
   NS_ENSURE_ARG(aState);
 
   MOZ_LOG(gSecureBrowserUILog, LogLevel::Debug, ("GetState %p", this));
   // With respect to mixed content and tracking protection, we won't know when
   // the state of our document (or a subdocument) has changed, so we ask the
   // docShell.
-  CheckForBlockedContent();
+  CheckForMixedContent();
   MOZ_LOG(gSecureBrowserUILog, LogLevel::Debug, ("  mState: %x", mState));
 
   *aState = mState;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsSecureBrowserUIImpl::GetContentBlockingEvent(uint32_t* aEvent) {
+  MOZ_ASSERT(NS_IsMainThread());
+  NS_ENSURE_ARG(aEvent);
+
+  MOZ_LOG(gSecureBrowserUILog, LogLevel::Debug,
+          ("GetContentBlockingEvent %p", this));
+  // With respect to mixed content and tracking protection, we won't know when
+  // the state of our document (or a subdocument) has changed, so we ask the
+  // docShell.
+  CheckForContentBlockingEvents();
+  MOZ_LOG(gSecureBrowserUILog, LogLevel::Debug, ("  mEvent: %x", mEvent));
+
+  *aEvent = mEvent;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsSecureBrowserUIImpl::GetSecInfo(nsITransportSecurityInfo** result) {
   MOZ_ASSERT(NS_IsMainThread());
   NS_ENSURE_ARG_POINTER(result);
 
   *result = mTopLevelSecurityInfo;
   NS_IF_ADDREF(*result);
 
   return NS_OK;
 }
 
-// Ask the docShell if we've blocked or loaded any mixed or tracking content.
-void nsSecureBrowserUIImpl::CheckForBlockedContent() {
+already_AddRefed<dom::Document>
+nsSecureBrowserUIImpl::PrepareForContentChecks() {
   nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocShell);
   if (!docShell) {
-    return;
+    return nullptr;
   }
 
   // For content docShells, the mixed content security state is set on the root
   // docShell.
   if (docShell->ItemType() == nsIDocShellTreeItem::typeContent) {
     nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem(docShell);
     nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
     Unused << docShellTreeItem->GetSameTypeRootTreeItem(
         getter_AddRefs(sameTypeRoot));
     MOZ_ASSERT(
         sameTypeRoot,
         "No document shell root tree item from document shell tree item!");
     docShell = do_QueryInterface(sameTypeRoot);
     if (!docShell) {
-      return;
+      return nullptr;
     }
   }
 
   RefPtr<dom::Document> doc = docShell->GetDocument();
+  return doc.forget();
+}
+
+// Ask the docShell if we've blocked or loaded any mixed content.
+void nsSecureBrowserUIImpl::CheckForMixedContent() {
+  RefPtr<dom::Document> doc = PrepareForContentChecks();
   if (!doc) {
     // If the docshell has no document, then there is no need to update mState.
     return;
   }
 
   // Has mixed content been loaded or blocked in nsMixedContentBlocker?
   // This only applies to secure documents even if they're affected by mixed
   // content blocking in which case the STATE_IS_BROKEN bit would be set rather
@@ -132,44 +155,53 @@ void nsSecureBrowserUIImpl::CheckForBloc
     if (doc->GetHasMixedActiveContentBlocked()) {
       mState |= STATE_BLOCKED_MIXED_ACTIVE_CONTENT;
     }
 
     if (doc->GetHasMixedDisplayContentBlocked()) {
       mState |= STATE_BLOCKED_MIXED_DISPLAY_CONTENT;
     }
   }
+}
+
+// Ask the docShell if we have any content blocking events.
+void nsSecureBrowserUIImpl::CheckForContentBlockingEvents() {
+  RefPtr<dom::Document> doc = PrepareForContentChecks();
+  if (!doc) {
+    // If the docshell has no document, then there is no need to update mState.
+    return;
+  }
 
   // Has tracking content been blocked or loaded?
   if (doc->GetHasTrackingContentBlocked()) {
-    mState |= STATE_BLOCKED_TRACKING_CONTENT;
+    mEvent |= STATE_BLOCKED_TRACKING_CONTENT;
   }
 
   if (doc->GetHasTrackingContentLoaded()) {
-    mState |= STATE_LOADED_TRACKING_CONTENT;
+    mEvent |= STATE_LOADED_TRACKING_CONTENT;
   }
 
   if (doc->GetHasCookiesBlockedByPermission()) {
-    mState |= STATE_COOKIES_BLOCKED_BY_PERMISSION;
+    mEvent |= STATE_COOKIES_BLOCKED_BY_PERMISSION;
   }
 
   if (doc->GetHasTrackingCookiesBlocked()) {
-    mState |= STATE_COOKIES_BLOCKED_TRACKER;
+    mEvent |= STATE_COOKIES_BLOCKED_TRACKER;
   }
 
   if (doc->GetHasForeignCookiesBlocked()) {
-    mState |= STATE_COOKIES_BLOCKED_FOREIGN;
+    mEvent |= STATE_COOKIES_BLOCKED_FOREIGN;
   }
 
   if (doc->GetHasAllCookiesBlocked()) {
-    mState |= STATE_COOKIES_BLOCKED_ALL;
+    mEvent |= STATE_COOKIES_BLOCKED_ALL;
   }
 
   if (doc->GetHasCookiesLoaded()) {
-    mState |= STATE_COOKIES_LOADED;
+    mEvent |= STATE_COOKIES_LOADED;
   }
 }
 
 // Helper function to determine if the given URI can be considered secure.
 // Essentially, only "https" URIs can be considered secure. However, the URI we
 // have may be e.g. view-source:https://example.com or
 // wyciwyg://https://example.com, in which case we have to evaluate the
 // innermost URI.
@@ -316,17 +348,17 @@ nsresult nsSecureBrowserUIImpl::UpdateSt
 
 // We receive this notification for the nsIWebProgress we added ourselves to
 // (i.e. the window we were passed in Init, which should be the top-level
 // window or whatever corresponds to an <iframe mozbrowser> element). In some
 // cases, we also receive it from nsIWebProgress instances that are children of
 // that nsIWebProgress. We ignore notifications from children because they don't
 // change the top-level state (if children load mixed or tracking content, the
 // docShell will know and will tell us in GetState when we call
-// CheckForBlockedContent).
+// CheckForMixedContent).
 // When we receive a notification from the top-level nsIWebProgress, we extract
 // any relevant security information and set our state accordingly. We then call
 // OnSecurityChange on the docShell corresponding to the nsIWebProgress we were
 // initialized with to notify any downstream listeners of the security state.
 NS_IMETHODIMP
 nsSecureBrowserUIImpl::OnLocationChange(nsIWebProgress* aWebProgress,
                                         nsIRequest* aRequest, nsIURI* aLocation,
                                         uint32_t aFlags) {
@@ -352,16 +384,17 @@ nsSecureBrowserUIImpl::OnLocationChange(
 
   // If this is a same-document location change, we don't need to update our
   // state or notify anyone.
   if (aFlags & LOCATION_CHANGE_SAME_DOCUMENT) {
     return NS_OK;
   }
 
   mState = 0;
+  mEvent = 0;
   mTopLevelSecurityInfo = nullptr;
 
   if (aFlags & LOCATION_CHANGE_ERROR_PAGE) {
     mState = STATE_IS_INSECURE;
     mTopLevelSecurityInfo = nullptr;
   } else {
     // NB: aRequest may be null. It may also not be QI-able to nsIChannel.
     nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
@@ -417,8 +450,14 @@ nsSecureBrowserUIImpl::OnStatusChange(ns
   return NS_OK;
 }
 
 nsresult nsSecureBrowserUIImpl::OnSecurityChange(nsIWebProgress*, nsIRequest*,
                                                  uint32_t) {
   MOZ_ASSERT_UNREACHABLE("Should have been excluded in AddProgressListener()");
   return NS_OK;
 }
+
+nsresult nsSecureBrowserUIImpl::OnContentBlockingEvent(nsIWebProgress*,
+                                                       nsIRequest*, uint32_t) {
+  MOZ_ASSERT_UNREACHABLE("Should have been excluded in AddProgressListener()");
+  return NS_OK;
+}
--- a/security/manager/ssl/nsSecureBrowserUIImpl.h
+++ b/security/manager/ssl/nsSecureBrowserUIImpl.h
@@ -9,16 +9,22 @@
 #include "nsCOMPtr.h"
 #include "nsISecureBrowserUI.h"
 #include "nsIWebProgressListener.h"
 #include "nsWeakReference.h"
 
 class nsITransportSecurityInfo;
 class nsIChannel;
 
+namespace mozilla {
+namespace dom {
+class Document;
+}
+}  // namespace mozilla
+
 #define NS_SECURE_BROWSER_UI_CID                     \
   {                                                  \
     0xcc75499a, 0x1dd1, 0x11b2, {                    \
       0x8a, 0x82, 0xca, 0x41, 0x0a, 0xc9, 0x07, 0xb8 \
     }                                                \
   }
 
 class nsSecureBrowserUIImpl : public nsISecureBrowserUI,
@@ -29,21 +35,25 @@ class nsSecureBrowserUIImpl : public nsI
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIWEBPROGRESSLISTENER
   NS_DECL_NSISECUREBROWSERUI
 
  protected:
   virtual ~nsSecureBrowserUIImpl(){};
 
-  // Do mixed content and tracking protection checks. May update mState.
-  void CheckForBlockedContent();
+  already_AddRefed<mozilla::dom::Document> PrepareForContentChecks();
+  // Do mixed content checks. May update mState.
+  void CheckForMixedContent();
+  // Do Content Blocking checks. May update mEvent.
+  void CheckForContentBlockingEvents();
   // Given some information about a request from an OnLocationChange event,
   // update mState and mTopLevelSecurityInfo.
   nsresult UpdateStateAndSecurityInfo(nsIChannel* channel, nsIURI* uri);
 
   uint32_t mState;
+  uint32_t mEvent;
   nsWeakPtr mDocShell;
   nsWeakPtr mWebProgress;
   nsCOMPtr<nsITransportSecurityInfo> mTopLevelSecurityInfo;
 };
 
 #endif  // nsSecureBrowserUIImpl_h
--- a/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm
+++ b/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm
@@ -429,16 +429,17 @@ var BrowserTestUtils = {
               BrowserTestUtils._webProgressListeners.delete(wpl);
               resolve();
             }
           }
         },
         onSecurityChange() {},
         onStatusChange() {},
         onLocationChange() {},
+        onContentBlockingEvent() {},
         QueryInterface: ChromeUtils.generateQI([
           Ci.nsIWebProgressListener,
           Ci.nsIWebProgressListener2,
           Ci.nsISupportsWeakReference,
         ]),
       };
       browser.addProgressListener(wpl);
       this._webProgressListeners.add(wpl);
--- a/toolkit/actors/PrintingChild.jsm
+++ b/toolkit/actors/PrintingChild.jsm
@@ -417,9 +417,10 @@ PrintingListener.prototype = {
       curTotalProgress: aCurTotalProgress,
       maxTotalProgress: aMaxTotalProgress,
     });
   },
 
   onLocationChange(aWebProgress, aRequest, aLocation, aFlags) {},
   onStatusChange(aWebProgress, aRequest, aStatus, aMessage) {},
   onSecurityChange(aWebProgress, aRequest, aState) {},
+  onContentBlockingEvent(aWebProgress, aRequest, aEvent) {},
 };
--- a/toolkit/components/antitracking/AntiTrackingCommon.cpp
+++ b/toolkit/components/antitracking/AntiTrackingCommon.cpp
@@ -618,17 +618,17 @@ AntiTrackingCommon::AddFirstPartyStorage
     topInnerWindow->SaveStorageAccessGranted(permissionKey);
 
     // Let's inform the parent window.
     parentWindow->StorageAccessGranted();
 
     nsIChannel* channel =
         pwin->GetCurrentInnerWindow()->GetExtantDoc()->GetChannel();
 
-    pwin->NotifyContentBlockingState(blockReason, channel, false, trackingURI);
+    pwin->NotifyContentBlockingEvent(blockReason, channel, false, trackingURI);
 
     ReportUnblockingConsole(parentWindow, NS_ConvertUTF8toUTF16(trackingOrigin),
                             NS_ConvertUTF8toUTF16(origin), aReason);
 
     if (XRE_IsParentProcess()) {
       LOG(("Saving the permission: trackingOrigin=%s, grantedOrigin=%s",
            trackingOrigin.get(), origin.get()));
 
@@ -1478,22 +1478,22 @@ nsresult AntiTrackingCommon::IsOnContent
   if (!pwin) {
     return;
   }
 
   nsCOMPtr<nsIURI> uri;
   aChannel->GetURI(getter_AddRefs(uri));
 
   if (aDecision == BlockingDecision::eBlock) {
-    pwin->NotifyContentBlockingState(aRejectedReason, aChannel, true, uri);
+    pwin->NotifyContentBlockingEvent(aRejectedReason, aChannel, true, uri);
 
     ReportBlockingToConsole(pwin, uri, aRejectedReason);
   }
 
-  pwin->NotifyContentBlockingState(nsIWebProgressListener::STATE_COOKIES_LOADED,
+  pwin->NotifyContentBlockingEvent(nsIWebProgressListener::STATE_COOKIES_LOADED,
                                    aChannel, false, uri);
 }
 
 /* static */ void AntiTrackingCommon::NotifyBlockingDecision(
     nsPIDOMWindowInner* aWindow, BlockingDecision aDecision,
     uint32_t aRejectedReason) {
   MOZ_ASSERT(aWindow);
   MOZ_ASSERT(
@@ -1527,22 +1527,22 @@ nsresult AntiTrackingCommon::IsOnContent
 
   Document* document = aWindow->GetExtantDoc();
   if (!document) {
     return;
   }
   nsIURI* uri = document->GetDocumentURI();
 
   if (aDecision == BlockingDecision::eBlock) {
-    pwin->NotifyContentBlockingState(aRejectedReason, channel, true, uri);
+    pwin->NotifyContentBlockingEvent(aRejectedReason, channel, true, uri);
 
     ReportBlockingToConsole(pwin, uri, aRejectedReason);
   }
 
-  pwin->NotifyContentBlockingState(nsIWebProgressListener::STATE_COOKIES_LOADED,
+  pwin->NotifyContentBlockingEvent(nsIWebProgressListener::STATE_COOKIES_LOADED,
                                    channel, false, uri);
 }
 
 /* static */ void AntiTrackingCommon::StoreUserInteractionFor(
     nsIPrincipal* aPrincipal) {
   if (XRE_IsParentProcess()) {
     nsCOMPtr<nsIURI> uri;
     Unused << aPrincipal->GetURI(getter_AddRefs(uri));
--- a/toolkit/components/antitracking/test/browser/head.js
+++ b/toolkit/components/antitracking/test/browser/head.js
@@ -294,18 +294,18 @@ this.AntiTracking = {
       }
 
       await AntiTracking._setupTest(win, options.cookieBehavior,
                                     options.blockingByContentBlockingRTUI,
                                     options.extraPrefs);
 
       let cookieBlocked = 0;
       let listener = {
-        onSecurityChange(webProgress, request, state) {
-          if ((state & options.expectedBlockingNotifications)) {
+        onContentBlockingEvent(webProgress, request, event) {
+          if ((event & options.expectedBlockingNotifications)) {
             ++cookieBlocked;
           }
         },
       };
       win.gBrowser.addProgressListener(listener);
 
       info("Creating a new tab");
       let tab = BrowserTestUtils.addTab(win.gBrowser, TEST_TOP_PAGE);
--- a/toolkit/components/browser/nsWebBrowser.cpp
+++ b/toolkit/components/browser/nsWebBrowser.cpp
@@ -701,16 +701,26 @@ NS_IMETHODIMP
 nsWebBrowser::OnSecurityChange(nsIWebProgress* aWebProgress,
                                nsIRequest* aRequest, uint32_t aState) {
   if (mProgressListener) {
     return mProgressListener->OnSecurityChange(aWebProgress, aRequest, aState);
   }
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsWebBrowser::OnContentBlockingEvent(nsIWebProgress* aWebProgress,
+                                     nsIRequest* aRequest, uint32_t aEvent) {
+  if (mProgressListener) {
+    return mProgressListener->OnContentBlockingEvent(aWebProgress, aRequest,
+                                                     aEvent);
+  }
+  return NS_OK;
+}
+
 //*****************************************************************************
 // nsWebBrowser::nsIWebBrowserPersist
 //*****************************************************************************
 
 NS_IMETHODIMP
 nsWebBrowser::GetPersistFlags(uint32_t* aPersistFlags) {
   NS_ENSURE_ARG_POINTER(aPersistFlags);
   nsresult rv = NS_OK;
--- a/toolkit/components/downloads/DownloadCore.jsm
+++ b/toolkit/components/downloads/DownloadCore.jsm
@@ -2673,16 +2673,17 @@ this.DownloadPDFSaver.prototype = {
           onProgressChange(webProgress, request, curSelfProgress,
                                      maxSelfProgress, curTotalProgress,
                                      maxTotalProgress) {
             aSetProgressBytesFn(curTotalProgress, maxTotalProgress, false);
           },
           onLocationChange() {},
           onStatusChange() {},
           onSecurityChange() {},
+          onContentBlockingEvent() {},
         });
       });
     } finally {
       // Remove the print object to avoid leaks
       this._webBrowserPrint = null;
     }
 
     let fileInfo = await OS.File.stat(targetPath);
--- a/toolkit/components/downloads/DownloadLegacy.js
+++ b/toolkit/components/downloads/DownloadLegacy.js
@@ -162,16 +162,18 @@ DownloadLegacyTransfer.prototype = {
       this._promiseDownload.then(download => {
         download.saver.onTransferFinished(aStatus);
       }).catch(Cu.reportError);
     }
   },
 
   onSecurityChange() { },
 
+  onContentBlockingEvent() { },
+
   // nsIWebProgressListener2
   onProgressChange64: function DLT_onProgressChange64(aWebProgress, aRequest,
                                                       aCurSelfProgress,
                                                       aMaxSelfProgress,
                                                       aCurTotalProgress,
                                                       aMaxTotalProgress) {
     // Since this progress function is invoked frequently, we use a slightly
     // more complex solution that optimizes the case where we already have an
--- a/toolkit/components/printing/content/printPreviewProgress.js
+++ b/toolkit/components/printing/content/printPreviewProgress.js
@@ -55,16 +55,17 @@ var progressListener = {
       docURL = docURLStr;
       if (docTitle == "")
         dialog.title.value = docURLStr;
     }
   },
 
   onLocationChange(aWebProgress, aRequest, aLocation, aFlags) {},
   onSecurityChange(aWebProgress, aRequest, state) {},
+  onContentBlockingEvent(aWebProgress, aRequest, event) {},
 
   onStatusChange(aWebProgress, aRequest, aStatus, aMessage) {
     if (aMessage)
       dialog.title.setAttribute("value", aMessage);
   },
 
   QueryInterface: ChromeUtils.generateQI(["nsIWebProgressListener",
                                           "nsISupportsWeakReference"]),
--- a/toolkit/components/printing/content/printProgress.js
+++ b/toolkit/components/printing/content/printProgress.js
@@ -139,16 +139,20 @@ var progressListener = {
       if (aMessage != "")
         dialog.title.setAttribute("value", aMessage);
     },
 
     onSecurityChange(aWebProgress, aRequest, state) {
       // we can ignore this notification
     },
 
+    onContentBlockingEvent(aWebProgress, aRequest, event) {
+      // we can ignore this notification
+    },
+
     QueryInterface: ChromeUtils.generateQI(["nsIWebProgressListener",
                                             "nsISupportsWeakReference"]),
 };
 
 function getString( stringId ) {
    // Check if we've fetched this string already.
    if (!(stringId in dialog.strings)) {
       // Try to get it.
--- a/toolkit/components/printingui/ipc/PrintProgressDialogChild.cpp
+++ b/toolkit/components/printingui/ipc/PrintProgressDialogChild.cpp
@@ -83,16 +83,23 @@ PrintProgressDialogChild::OnStatusChange
 
 NS_IMETHODIMP
 PrintProgressDialogChild::OnSecurityChange(nsIWebProgress* aProgress,
                                            nsIRequest* aRequest,
                                            uint32_t aState) {
   return NS_OK;
 }
 
+NS_IMETHODIMP
+PrintProgressDialogChild::OnContentBlockingEvent(nsIWebProgress* aProgress,
+                                                 nsIRequest* aRequest,
+                                                 uint32_t aEvent) {
+  return NS_OK;
+}
+
 // nsIPrintProgressParams
 
 NS_IMETHODIMP
 PrintProgressDialogChild::GetDocTitle(nsAString& aDocTitle) {
   aDocTitle = mDocTitle;
   return NS_OK;
 }
 
--- a/toolkit/components/printingui/nsPrintProgress.cpp
+++ b/toolkit/components/printingui/nsPrintProgress.cpp
@@ -240,17 +240,22 @@ NS_IMETHODIMP nsPrintProgress::OnStatusC
                                        aMessage);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP nsPrintProgress::OnSecurityChange(nsIWebProgress *aWebProgress,
                                                 nsIRequest *aRequest,
-                                                uint32_t state) {
+                                                uint32_t aState) {
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsPrintProgress::OnContentBlockingEvent(
+    nsIWebProgress *aWebProgress, nsIRequest *aRequest, uint32_t aEvent) {
   return NS_OK;
 }
 
 nsresult nsPrintProgress::ReleaseListeners() {
   m_listenerList.Clear();
 
   return NS_OK;
 }
--- a/toolkit/components/printingui/nsPrintingPromptService.cpp
+++ b/toolkit/components/printingui/nsPrintingPromptService.cpp
@@ -200,17 +200,30 @@ nsPrintingPromptService::OnStatusChange(
   }
 #endif
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsPrintingPromptService::OnSecurityChange(nsIWebProgress* aWebProgress,
                                           nsIRequest* aRequest,
-                                          uint32_t state) {
+                                          uint32_t aState) {
 #if !defined(XP_MACOSX)
   if (mWebProgressListener) {
     return mWebProgressListener->OnSecurityChange(aWebProgress, aRequest,
-                                                  state);
+                                                  aState);
   }
 #endif
   return NS_OK;
 }
+
+NS_IMETHODIMP
+nsPrintingPromptService::OnContentBlockingEvent(nsIWebProgress* aWebProgress,
+                                                nsIRequest* aRequest,
+                                                uint32_t aEvent) {
+#if !defined(XP_MACOSX)
+  if (mWebProgressListener) {
+    return mWebProgressListener->OnContentBlockingEvent(aWebProgress, aRequest,
+                                                        aEvent);
+  }
+#endif
+  return NS_OK;
+}
--- a/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp
+++ b/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp
@@ -236,16 +236,25 @@ nsBrowserStatusFilter::OnStatusChange(ns
 NS_IMETHODIMP
 nsBrowserStatusFilter::OnSecurityChange(nsIWebProgress *aWebProgress,
                                         nsIRequest *aRequest, uint32_t aState) {
   if (!mListener) return NS_OK;
 
   return mListener->OnSecurityChange(aWebProgress, aRequest, aState);
 }
 
+NS_IMETHODIMP
+nsBrowserStatusFilter::OnContentBlockingEvent(nsIWebProgress *aWebProgress,
+                                              nsIRequest *aRequest,
+                                              uint32_t aEvent) {
+  if (!mListener) return NS_OK;
+
+  return mListener->OnContentBlockingEvent(aWebProgress, aRequest, aEvent);
+}
+
 //-----------------------------------------------------------------------------
 // nsBrowserStatusFilter::nsIWebProgressListener2
 //-----------------------------------------------------------------------------
 NS_IMETHODIMP
 nsBrowserStatusFilter::OnProgressChange64(nsIWebProgress *aWebProgress,
                                           nsIRequest *aRequest,
                                           int64_t aCurSelfProgress,
                                           int64_t aMaxSelfProgress,
--- a/toolkit/components/url-classifier/tests/mochitest/test_threathit_report.html
+++ b/toolkit/components/url-classifier/tests/mochitest/test_threathit_report.html
@@ -189,22 +189,22 @@ function testOnWindow(aTestData) {
 
     (async function() {
       await new Promise(rs => whenDelayedStartupFinished(win, rs));
 
       let expected;
       let browser = win.gBrowser.selectedBrowser;
       let wp = win.gBrowser.contentWindow.docShell.QueryInterface(Ci.nsIWebProgress);
       let progressListener = {
-        onSecurityChange(aWebProgress, aRequest, aState) {
+        onContentBlockingEvent(aWebProgress, aRequest, aEvent) {
           expected = aTestData.reportUrl;
         },
         QueryInterface: ChromeUtils.generateQI(["nsISupportsWeakReference"]),
       };
-      wp.addProgressListener(progressListener, wp.NOTIFY_SECURITY);
+      wp.addProgressListener(progressListener, wp.NOTIFY_CONTENT_BLOCKING);
 
       await BrowserTestUtils.loadURI(browser, aTestData.url);
       await BrowserTestUtils.waitForContentEvent(browser, "DOMContentLoaded");
       checkResults(aTestData, expected);
       win.close();
       resolve();
     })();
   });
--- a/toolkit/components/windowcreator/test/browser_bug1204626.js
+++ b/toolkit/components/windowcreator/test/browser_bug1204626.js
@@ -40,16 +40,17 @@ function one_test(delay, continuation) {
       }
     });
 
     wbp.progressListener = {
       onProgressChange() {},
       onLocationChange() {},
       onStatusChange() {},
       onSecurityChange() {},
+      onContentBlockingEvent() {},
       onStateChange(_wbp, _req, state, _status) {
         if ((state & Ci.nsIWebProgressListener.STATE_STOP) == 0) {
           return;
         }
         ok(true, "Finished save (" + delayStr + ") but might have crashed.");
         continuation();
       },
     };
--- a/toolkit/components/windowcreator/test/test_bug1170334_wbp_xmlstyle.html
+++ b/toolkit/components/windowcreator/test/test_bug1170334_wbp_xmlstyle.html
@@ -36,16 +36,17 @@ iframe.onload = function iframe_onload1(
   tmpDir.append(nameStem + "_files");
 
   // When the document in the iframe is saved, try to load the result.
   wbp.progressListener = {
     onProgressChange() {},
     onLocationChange() {},
     onStatusChange() {},
     onSecurityChange() {},
+    onContentBlockingEvent() {},
     onStateChange: function wbp_stateChange(_wbp, _req, state, status) {
       if ((state & Ci.nsIWebProgressListener.STATE_STOP) == 0) {
         return;
       }
       is(status, Cr.NS_OK, "nsWebBrowserPersist status");
       iframe.onload = function iframe_onload2() {
         let elem = iframe.contentDocument.documentElement;
         is(elem && elem.tagName, "thing", "document element tag");
--- a/toolkit/components/windowcreator/test/test_bug1192654.html
+++ b/toolkit/components/windowcreator/test/test_bug1192654.html
@@ -42,16 +42,17 @@ iframe.onload = function iframe_onload1(
   let tmpDir = tmp.clone();
   tmpDir.append(nameStem + "_files");
 
   wbp.progressListener = {
     onProgressChange() {},
     onLocationChange() {},
     onStatusChange() {},
     onSecurityChange() {},
+    onContentBlockingEvent() {},
     onStateChange: wbp_stateChange,
   };
   SimpleTest.registerCleanupFunction(cleanUp);
 
   wbp.saveDocument(doc, tmpFile, tmpDir, null, 0, 0);
 
   function wbp_stateChange(_wbp, _req, state, status) {
     if ((state & Ci.nsIWebProgressListener.STATE_STOP) == 0) {
--- a/toolkit/content/tests/browser/common/mockTransfer.js
+++ b/toolkit/content/tests/browser/common/mockTransfer.js
@@ -39,16 +39,17 @@ MockTransfer.prototype = {
   onLocationChange() {},
   onStatusChange: function MTFC_onStatusChange(aWebProgress, aRequest, aStatus,
                                                aMessage) {
     // If at least one notification reported an error, the download failed.
     if (!Components.isSuccessCode(aStatus))
       this._downloadIsSuccessful = false;
   },
   onSecurityChange() {},
+  onContentBlockingEvent() {},
 
   /* nsIWebProgressListener2 */
   onProgressChange64() {},
   onRefreshAttempted() {},
 
   /* nsITransfer */
   init() {},
   setSha256Hash() {},
--- a/toolkit/modules/RemoteSecurityUI.jsm
+++ b/toolkit/modules/RemoteSecurityUI.jsm
@@ -3,23 +3,27 @@
 // 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/.
 
 var EXPORTED_SYMBOLS = ["RemoteSecurityUI"];
 
 function RemoteSecurityUI() {
     this._secInfo = null;
     this._state = 0;
+    this._event = 0;
 }
 
 RemoteSecurityUI.prototype = {
   QueryInterface: ChromeUtils.generateQI([Ci.nsISecureBrowserUI]),
 
   // nsISecureBrowserUI
   get state() { return this._state; },
-  get tooltipText() { return ""; },
+  get contentBlockingEvent() { return this._event; },
   get secInfo() { return this._secInfo; },
 
   _update(aSecInfo, aState) {
     this._secInfo = aSecInfo;
     this._state = aState;
   },
+  _updateContentBlockingEvent(aEvent) {
+    this._event = aEvent;
+  },
 };
--- a/toolkit/modules/RemoteWebProgress.jsm
+++ b/toolkit/modules/RemoteWebProgress.jsm
@@ -30,27 +30,28 @@ function RemoteWebProgress(aManager, aIs
 
   this._isLoadingDocument = false;
   this._DOMWindowID = 0;
   this._isTopLevel = aIsTopLevel;
   this._loadType = 0;
 }
 
 RemoteWebProgress.prototype = {
-  NOTIFY_STATE_REQUEST:  0x00000001,
-  NOTIFY_STATE_DOCUMENT: 0x00000002,
-  NOTIFY_STATE_NETWORK:  0x00000004,
-  NOTIFY_STATE_WINDOW:   0x00000008,
-  NOTIFY_STATE_ALL:      0x0000000f,
-  NOTIFY_PROGRESS:       0x00000010,
-  NOTIFY_STATUS:         0x00000020,
-  NOTIFY_SECURITY:       0x00000040,
-  NOTIFY_LOCATION:       0x00000080,
-  NOTIFY_REFRESH:        0x00000100,
-  NOTIFY_ALL:            0x000001ff,
+  NOTIFY_STATE_REQUEST:    0x00000001,
+  NOTIFY_STATE_DOCUMENT:   0x00000002,
+  NOTIFY_STATE_NETWORK:    0x00000004,
+  NOTIFY_STATE_WINDOW:     0x00000008,
+  NOTIFY_STATE_ALL:        0x0000000f,
+  NOTIFY_PROGRESS:         0x00000010,
+  NOTIFY_STATUS:           0x00000020,
+  NOTIFY_SECURITY:         0x00000040,
+  NOTIFY_LOCATION:         0x00000080,
+  NOTIFY_REFRESH:          0x00000100,
+  NOTIFY_CONTENT_BLOCKING: 0x00000200,
+  NOTIFY_ALL:              0x000003ff,
 
   get isLoadingDocument() { return this._isLoadingDocument; },
   get DOMWindow() {
     throw Cr.NS_ERROR_NOT_AVAILABLE;
   },
   get DOMWindowID() { return this._DOMWindowID; },
   get isTopLevel() { return this._isTopLevel; },
   get loadType() { return this._loadType; },
@@ -75,26 +76,28 @@ RemoteWebProgressManager.prototype = {
   swapBrowser(aBrowser) {
     if (this._messageManager) {
       this._messageManager.removeMessageListener("Content:StateChange", this);
       this._messageManager.removeMessageListener("Content:LocationChange", this);
       this._messageManager.removeMessageListener("Content:SecurityChange", this);
       this._messageManager.removeMessageListener("Content:StatusChange", this);
       this._messageManager.removeMessageListener("Content:ProgressChange", this);
       this._messageManager.removeMessageListener("Content:LoadURIResult", this);
+      this._messageManager.removeMessageListener("Content:ContentBlockingEvent", this);
     }
 
     this._browser = aBrowser;
     this._messageManager = aBrowser.messageManager;
     this._messageManager.addMessageListener("Content:StateChange", this);
     this._messageManager.addMessageListener("Content:LocationChange", this);
     this._messageManager.addMessageListener("Content:SecurityChange", this);
     this._messageManager.addMessageListener("Content:StatusChange", this);
     this._messageManager.addMessageListener("Content:ProgressChange", this);
     this._messageManager.addMessageListener("Content:LoadURIResult", this);
+    this._messageManager.addMessageListener("Content:ContentBlockingEvent", this);
   },
 
   swapListeners(aOtherRemoteWebProgressManager) {
     let temp = aOtherRemoteWebProgressManager.progressListeners;
     aOtherRemoteWebProgressManager._progressListeners = this._progressListeners;
     this._progressListeners = temp;
   },
 
@@ -255,16 +258,31 @@ RemoteWebProgressManager.prototype = {
       }
 
       this._callProgressListeners(
         Ci.nsIWebProgress.NOTIFY_SECURITY, "onSecurityChange", webProgress,
         request, state
       );
       break;
 
+    case "Content:ContentBlockingEvent":
+      if (isTopLevel) {
+        // Invoking this getter triggers the generation of the underlying object,
+        // which we need to access with ._securityUI, because .securityUI returns
+        // a wrapper that makes _update inaccessible.
+        void this._browser.securityUI;
+        this._browser._securityUI._updateContentBlockingEvent(json.event);
+      }
+
+      this._callProgressListeners(
+        Ci.nsIWebProgress.NOTIFY_CONTENT_BLOCKING, "onContentBlockingEvent",
+        webProgress, request, json.event
+      );
+      break;
+
     case "Content:StatusChange":
       this._callProgressListeners(
         Ci.nsIWebProgress.NOTIFY_STATUS, "onStatusChange", webProgress, request,
         json.status, json.message
       );
       break;
 
     case "Content:ProgressChange":
--- a/toolkit/modules/WebProgressChild.jsm
+++ b/toolkit/modules/WebProgressChild.jsm
@@ -189,22 +189,29 @@ class WebProgressChild {
   }
 
   onSecurityChange(aWebProgress, aRequest, aState) {
     let json = this._setupJSON(aWebProgress, aRequest);
 
     json.state = aState;
     json.secInfo = this.getSecInfoAsString();
 
+    this._send("Content:SecurityChange", json);
+  }
+
+  onContentBlockingEvent(aWebProgress, aRequest, aEvent) {
+    let json = this._setupJSON(aWebProgress, aRequest);
+
+    json.event = aEvent;
     json.matchedList = null;
     if (aRequest && aRequest instanceof Ci.nsIClassifiedChannel) {
       json.matchedList = aRequest.matchedList;
     }
 
-    this._send("Content:SecurityChange", json);
+    this._send("Content:ContentBlockingEvent", json);
   }
 
   onRefreshAttempted(aWebProgress, aURI, aDelay, aSameURI) {
     return true;
   }
 
   sendLoadCallResult() {
     this.mm.sendAsyncMessage("Content:LoadURIResult");
--- a/toolkit/mozapps/downloads/nsHelperAppDlg.js
+++ b/toolkit/mozapps/downloads/nsHelperAppDlg.js
@@ -40,17 +40,17 @@ nsUnknownContentTypeDialogProgressListen
       // Close the dialog.
       this.helperAppDlg.onCancel();
       if ( this.helperAppDlg.mDialog ) {
         this.helperAppDlg.mDialog.close();
       }
     }
   },
 
-  // Ignore onProgressChange, onProgressChange64, onStateChange, onLocationChange, onSecurityChange, and onRefreshAttempted notifications.
+  // Ignore onProgressChange, onProgressChange64, onStateChange, onLocationChange, onSecurityChange, onContentBlockingEvent and onRefreshAttempted notifications.
   onProgressChange(aWebProgress,
                    aRequest,
                    aCurSelfProgress,
                    aMaxSelfProgress,
                    aCurTotalProgress,
                    aMaxTotalProgress) {
   },
 
@@ -65,17 +65,20 @@ nsUnknownContentTypeDialogProgressListen
 
 
   onStateChange(aWebProgress, aRequest, aStateFlags, aStatus) {
   },
 
   onLocationChange(aWebProgress, aRequest, aLocation, aFlags) {
   },
 
-  onSecurityChange(aWebProgress, aRequest, state) {
+  onSecurityChange(aWebProgress, aRequest, aState) {
+  },
+
+  onContentBlockingEvent(aWebProgress, aRequest, aEvent) {
   },
 
   onRefreshAttempted(aWebProgress, aURI, aDelay, aSameURI) {
     return true;
   },
 };
 
 // /////////////////////////////////////////////////////////////////////////////
--- a/toolkit/mozapps/extensions/content/extensions.js
+++ b/toolkit/mozapps/extensions/content/extensions.js
@@ -2220,16 +2220,18 @@ var gDiscoverView = {
     if (aState & Ci.nsIWebProgressListener.STATE_IS_SECURE)
       return;
 
     // Canceling the request will send an error to onStateChange which will show
     // the error page
     aRequest.cancel(Cr.NS_BINDING_ABORTED);
   },
 
+  onContentBlockingEvent(aWebProgress, aRequest, aEvent) {},
+
   onStateChange(aWebProgress, aRequest, aStateFlags, aStatus) {
     let transferStart = Ci.nsIWebProgressListener.STATE_IS_DOCUMENT |
                         Ci.nsIWebProgressListener.STATE_IS_REQUEST |
                         Ci.nsIWebProgressListener.STATE_TRANSFERRING;
     // Once transferring begins show the content
     if ((aStateFlags & transferStart) === transferStart)
       this.node.selectedPanel = this._browser;
 
--- a/toolkit/mozapps/extensions/internal/LightweightThemePersister.jsm
+++ b/toolkit/mozapps/extensions/internal/LightweightThemePersister.jsm
@@ -105,19 +105,20 @@ function _persistImage(sourceURL, localF
   persist.saveURI(sourceURI, sourcePrincipal, 0,
                   null, Ci.nsIHttpChannel.REFERRER_POLICY_UNSET,
                   null, null, targetURI, null);
 }
 
 function _persistProgressListener(successCallback) {
   this.onLocationChange = function() {};
   this.onProgressChange = function() {};
-  this.onStatusChange   = function() {};
+  this.onStatusChange = function() {};
   this.onSecurityChange = function() {};
-  this.onStateChange    = function(aWebProgress, aRequest, aStateFlags, aStatus) {
+  this.onContentBlockingEvent = function() {};
+  this.onStateChange = function(aWebProgress, aRequest, aStateFlags, aStatus) {
     if (aRequest &&
         aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK &&
         aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) {
       // LWTs used to get their image files from the network…
       if (aRequest instanceof Ci.nsIHttpChannel &&
           aRequest.QueryInterface(Ci.nsIHttpChannel).requestSucceeded ||
           // … but static themes usually include the image data inside the
           // extension package.
--- a/toolkit/mozapps/extensions/test/browser/browser_bug562797.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_bug562797.js
@@ -24,16 +24,17 @@ var gProgressListener = {
       executeSoon(gLoadCompleteCallback);
     gLoadCompleteCallback = null;
   },
 
   onLocationChange() { },
   onSecurityChange() { },
   onProgressChange() { },
   onStatusChange() { },
+  onContentBlockingEvent() { },
 
   QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener,
                                           Ci.nsISupportsWeakReference]),
 };
 
 function waitForLoad(aManager, aCallback) {
   let promise = new Promise(resolve => {
     var browser = aManager.document.getElementById("discover-browser");
--- a/toolkit/mozapps/extensions/test/browser/browser_discovery.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_discovery.js
@@ -23,16 +23,17 @@ var gProgressListener = {
       executeSoon(gLoadCompleteCallback);
     gLoadCompleteCallback = null;
   },
 
   onLocationChange() { },
   onSecurityChange() { },
   onProgressChange() { },
   onStatusChange() { },
+  onContentBlockingEvent() { },
 
   QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener,
                                           Ci.nsISupportsWeakReference]),
 };
 
 function test() {
   // Switch to a known url
   Services.prefs.setCharPref(PREF_DISCOVERURL, MAIN_URL);
--- a/uriloader/base/nsDocLoader.cpp
+++ b/uriloader/base/nsDocLoader.cpp
@@ -1416,18 +1416,19 @@ NS_IMETHODIMP nsDocLoader::OnContentBloc
                                                   uint32_t aEvent) {
   //
   // Fire progress notifications out to any registered nsIWebProgressListeners.
   //
 
   nsCOMPtr<nsIRequest> request = do_QueryInterface(aContext);
   nsIWebProgress* webProgress = static_cast<nsIWebProgress*>(this);
 
-  NOTIFY_LISTENERS(nsIWebProgress::NOTIFY_SECURITY,
-                   listener->OnSecurityChange(webProgress, request, aEvent););
+  NOTIFY_LISTENERS(
+      nsIWebProgress::NOTIFY_CONTENT_BLOCKING,
+      listener->OnContentBlockingEvent(webProgress, request, aEvent););
 
   // Pass the notification up to the parent...
   if (mParent) {
     mParent->OnContentBlockingEvent(aContext, aEvent);
   }
   return NS_OK;
 }
 
--- a/uriloader/base/nsIWebProgress.idl
+++ b/uriloader/base/nsIWebProgress.idl
@@ -76,30 +76,34 @@ interface nsIWebProgress : nsISupports
    *   Receive onStatusChange events.
    *
    * NOTIFY_SECURITY
    *   Receive onSecurityChange events.
    *
    * NOTIFY_LOCATION
    *   Receive onLocationChange events.
    *
+   * NOTIFY_CONTENT_BLOCKING
+   *   Receive onContentBlockingEvent events.
+   *
    * NOTIFY_REFRESH
    *   Receive onRefreshAttempted events.
    *   This is defined on nsIWebProgressListener2.
    */
-  const unsigned long NOTIFY_PROGRESS       = 0x00000010;
-  const unsigned long NOTIFY_STATUS         = 0x00000020;
-  const unsigned long NOTIFY_SECURITY       = 0x00000040;
-  const unsigned long NOTIFY_LOCATION       = 0x00000080;
-  const unsigned long NOTIFY_REFRESH        = 0x00000100;
+  const unsigned long NOTIFY_PROGRESS         = 0x00000010;
+  const unsigned long NOTIFY_STATUS           = 0x00000020;
+  const unsigned long NOTIFY_SECURITY         = 0x00000040;
+  const unsigned long NOTIFY_LOCATION         = 0x00000080;
+  const unsigned long NOTIFY_REFRESH          = 0x00000100;
+  const unsigned long NOTIFY_CONTENT_BLOCKING = 0x00000200;
 
   /**
    * This flag enables all notifications.
    */
-  const unsigned long NOTIFY_ALL            = 0x000001ff;
+  const unsigned long NOTIFY_ALL              = 0x000003ff;
 
   /**
    * Registers a listener to receive web progress events.
    *
    * @param aListener
    *        The listener interface to be called when a progress event occurs.
    *        This object must also implement nsISupportsWeakReference.
    * @param aNotifyMask
--- a/uriloader/base/nsIWebProgressListener.idl
+++ b/uriloader/base/nsIWebProgressListener.idl
@@ -205,38 +205,16 @@ interface nsIWebProgressListener : nsISu
    *   Mixed display content has been blocked from loading.
    *
    * STATE_LOADED_MIXED_DISPLAY_CONTENT
    *   Mixed display content has been loaded. State should be STATE_IS_BROKEN.
    */
   const unsigned long STATE_BLOCKED_MIXED_DISPLAY_CONTENT = 0x00000100;
   const unsigned long STATE_LOADED_MIXED_DISPLAY_CONTENT  = 0x00000200;
 
-   /**
-   *  Safe Browsing blocking content flags
-   *
-   * NOTE: IF YOU ARE ADDING MORE OF THESE FLAGS, MAKE SURE TO EDIT
-   * nsSecureBrowserUIImpl::CheckForBlockedContent().
-   *
-   * May be set in addition to the State security Flags, to indicate that
-   * tracking or unsafe content has been encountered.
-   *
-   * STATE_BLOCKED_TRACKING_CONTENT
-   *   Tracking content has been blocked from loading.
-   *
-   * STATE_LOADED_TRACKING_CONTENT
-   *   Tracking content has been loaded.
-   *
-   * STATE_BLOCKED_UNSAFE_CONTENT
-   *   Content which againts SafeBrowsing list has been blocked from loading.
-   */
-  const unsigned long STATE_BLOCKED_TRACKING_CONTENT         = 0x00001000;
-  const unsigned long STATE_LOADED_TRACKING_CONTENT          = 0x00002000;
-  const unsigned long STATE_BLOCKED_UNSAFE_CONTENT           = 0x00004000;
-
   /**
    * Diagnostic flags
    *
    * NOTE: IF YOU ARE ADDING MORE OF THESE FLAGS, MAKE SURE TO EDIT
    * nsSecureBrowserUIImpl::CheckForBlockedContent().
    *
    * May be set in addition to other security state flags to indicate that
    * some state is countered that deserves a warning or error, but does not
@@ -274,36 +252,48 @@ interface nsIWebProgressListener : nsISu
     * STATE_CERT_USER_OVERRIDDEN
     *   The user has added a security exception for the site.
     */
   const unsigned long STATE_USES_SSL_3                = 0x01000000;
   const unsigned long STATE_USES_WEAK_CRYPTO          = 0x02000000;
   const unsigned long STATE_CERT_USER_OVERRIDDEN      = 0x04000000;
 
   /**
-   * Cookie Jar blocking
+   * Content Blocking Event flags
    *
    * NOTE: IF YOU ARE ADDING MORE OF THESE FLAGS, MAKE SURE TO EDIT
    * nsSecureBrowserUIImpl::CheckForBlockedContent().
    *
    * These flags describe the reason of cookie jar rejection.
    *
+   * STATE_BLOCKED_TRACKING_CONTENT
+   *   Tracking content has been blocked from loading.
+   *
+   * STATE_LOADED_TRACKING_CONTENT
+   *   Tracking content has been loaded.
+   *
+   * STATE_BLOCKED_UNSAFE_CONTENT
+   *   Content which againts SafeBrowsing list has been blocked from loading.
+   *
    * STATE_COOKIES_BLOCKED_BY_PERMISSION
    *   Rejected for custom site permission.
    *
    * STATE_COOKIES_BLOCKED_TRACKER
    *   Rejected because the resource is a tracker and cookie policy doesn't
    *   allow its loading.
    *
    * STATE_COOKIES_BLOCKED_ALL
    *   Rejected because cookie policy blocks all cookies.
    *
    * STATE_COOKIES_BLOCKED_FOREIGN
    *   Rejected because cookie policy blocks 3rd party cookies.
    */
+  const unsigned long STATE_BLOCKED_TRACKING_CONTENT      = 0x00001000;
+  const unsigned long STATE_LOADED_TRACKING_CONTENT       = 0x00002000;
+  const unsigned long STATE_BLOCKED_UNSAFE_CONTENT        = 0x00004000;
   const unsigned long STATE_COOKIES_LOADED                = 0x00008000;
   const unsigned long STATE_COOKIES_BLOCKED_BY_PERMISSION = 0x10000000;
   const unsigned long STATE_COOKIES_BLOCKED_TRACKER       = 0x20000000;
   const unsigned long STATE_COOKIES_BLOCKED_ALL           = 0x40000000;
   const unsigned long STATE_COOKIES_BLOCKED_FOREIGN       = 0x00000080;
 
   /**
    * Notification indicating the state has changed for one of the requests
@@ -457,9 +447,26 @@ interface nsIWebProgressListener : nsISu
    *        future use.
    *
    * NOTE: These notifications will only occur if a security package is
    * installed.
    */
   void onSecurityChange(in nsIWebProgress aWebProgress,
                         in nsIRequest aRequest,
                         in unsigned long aState);
+
+  /**
+   * Notification called for content blocking events.  This method will be
+   * called when content gets allowed/blocked for various reasons per the
+   * Content Blocking rules.
+   *
+   * @param aWebProgress
+   *        The nsIWebProgress instance that fired the notification.
+   * @param aRequest
+   *        The nsIRequest that has new security state.
+   * @param aEvent
+   *        A value composed of the Content Blocking Event Flags listed above.
+   *        Any undefined bits are reserved for future use.
+   */
+  void onContentBlockingEvent(in nsIWebProgress aWebProgress,
+                              in nsIRequest aRequest,
+                              in unsigned long aEvent);
 };
--- a/uriloader/prefetch/nsOfflineCacheUpdateService.cpp
+++ b/uriloader/prefetch/nsOfflineCacheUpdateService.cpp
@@ -207,17 +207,24 @@ nsOfflineCachePendingUpdate::OnStatusCha
                                             const char16_t *aMessage) {
   MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsOfflineCachePendingUpdate::OnSecurityChange(nsIWebProgress *aWebProgress,
                                               nsIRequest *aRequest,
-                                              uint32_t state) {
+                                              uint32_t aState) {
+  MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsOfflineCachePendingUpdate::OnContentBlockingEvent(
+    nsIWebProgress *aWebProgress, nsIRequest *aRequest, uint32_t aEvent) {
   MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
   return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 // nsOfflineCacheUpdateService::nsISupports
 //-----------------------------------------------------------------------------
 
--- a/uriloader/prefetch/nsPrefetchService.cpp
+++ b/uriloader/prefetch/nsPrefetchService.cpp
@@ -914,17 +914,25 @@ nsPrefetchService::OnStatusChange(nsIWeb
                                   nsIRequest *aRequest, nsresult aStatus,
                                   const char16_t *aMessage) {
   MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsPrefetchService::OnSecurityChange(nsIWebProgress *aWebProgress,
-                                    nsIRequest *aRequest, uint32_t state) {
+                                    nsIRequest *aRequest, uint32_t aState) {
+  MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPrefetchService::OnContentBlockingEvent(nsIWebProgress *aWebProgress,
+                                          nsIRequest *aRequest,
+                                          uint32_t aEvent) {
   MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
   return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 // nsPrefetchService::nsIObserver
 //-----------------------------------------------------------------------------
 
--- a/xpfe/appshell/nsChromeTreeOwner.cpp
+++ b/xpfe/appshell/nsChromeTreeOwner.cpp
@@ -440,17 +440,24 @@ NS_IMETHODIMP
 nsChromeTreeOwner::OnStatusChange(nsIWebProgress* aWebProgress,
                                   nsIRequest* aRequest, nsresult aStatus,
                                   const char16_t* aMessage) {
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsChromeTreeOwner::OnSecurityChange(nsIWebProgress* aWebProgress,
-                                    nsIRequest* aRequest, uint32_t state) {
+                                    nsIRequest* aRequest, uint32_t aState) {
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsChromeTreeOwner::OnContentBlockingEvent(nsIWebProgress* aWebProgress,
+                                          nsIRequest* aRequest,
+                                          uint32_t aEvent) {
   return NS_OK;
 }
 
 //*****************************************************************************
 // nsChromeTreeOwner: Helpers
 //*****************************************************************************
 
 //*****************************************************************************
--- a/xpfe/appshell/nsWebShellWindow.cpp
+++ b/xpfe/appshell/nsWebShellWindow.cpp
@@ -628,17 +628,25 @@ nsWebShellWindow::OnStatusChange(nsIWebP
                                  nsIRequest* aRequest, nsresult aStatus,
                                  const char16_t* aMessage) {
   MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWebShellWindow::OnSecurityChange(nsIWebProgress* aWebProgress,
-                                   nsIRequest* aRequest, uint32_t state) {
+                                   nsIRequest* aRequest, uint32_t aState) {
+  MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWebShellWindow::OnContentBlockingEvent(nsIWebProgress* aWebProgress,
+                                         nsIRequest* aRequest,
+                                         uint32_t aEvent) {
   MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
   return NS_OK;
 }
 
 /**
  * ExecuteCloseHandler - Run the close handler, if any.
  * @return true iff we found a close handler to run.
  */