Backed out changeset 64eb902728bc (bug 1664156) for causing mochitest failures in test_meta_csp_self.html CLOSED TREE
authorNoemi Erli <nerli@mozilla.com>
Sat, 12 Sep 2020 22:56:18 +0300
changeset 548470 cdc242832bf4bf19927f18751353bda8a961021e
parent 548469 53fc2a01eecc712ab37ad93d7b7013584a8a3a8e
child 548471 4940cabe4676128f49a57e0e7a2cdd42b2eb4f57
push id126199
push usernerli@mozilla.com
push dateSat, 12 Sep 2020 19:56:52 +0000
treeherderautoland@cdc242832bf4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1664156
milestone82.0a1
backs out64eb902728bc7b1c2f8efbcf9c1004a48c1541bd
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
Backed out changeset 64eb902728bc (bug 1664156) for causing mochitest failures in test_meta_csp_self.html CLOSED TREE
dom/base/nsIObjectLoadingContent.idl
dom/base/nsImageLoadingContent.cpp
dom/base/nsImageLoadingContent.h
dom/base/nsObjectLoadingContent.cpp
dom/base/nsObjectLoadingContent.h
dom/base/test/test_blocking_image.html
dom/events/EventStates.h
dom/security/test/csp/test_docwrite_meta.html
dom/webidl/HTMLObjectElement.webidl
layout/base/RestyleManager.cpp
layout/base/nsCSSFrameConstructor.cpp
layout/generic/nsImageFrame.cpp
layout/style/res/html.css
layout/style/test/test_selectors.html
servo/components/style/element_state.rs
servo/components/style/gecko/non_ts_pseudo_class_list.rs
servo/components/style/gecko/wrapper.rs
testing/web-platform/tests/html/rendering/replaced-elements/images/blocked-by-csp-ref.html
testing/web-platform/tests/html/rendering/replaced-elements/images/blocked-by-csp.html
--- a/dom/base/nsIObjectLoadingContent.idl
+++ b/dom/base/nsIObjectLoadingContent.idl
@@ -48,16 +48,18 @@ interface nsIObjectLoadingContent : nsIS
   // The plugin exists, but is disabled
   const unsigned long PLUGIN_DISABLED             = 2;
   // The plugin is blocklisted and disabled
   const unsigned long PLUGIN_BLOCKLISTED          = 3;
   // The plugin is considered outdated, but not disabled
   const unsigned long PLUGIN_OUTDATED             = 4;
   // The plugin has crashed
   const unsigned long PLUGIN_CRASHED              = 5;
+  // Suppressed by security policy
+  const unsigned long PLUGIN_SUPPRESSED           = 6;
   /// ** All values >= PLUGIN_CLICK_TO_PLAY are plugin placeholder types that
   ///    would be replaced by a real plugin if activated (playPlugin())
   /// ** Furthermore, values >= PLUGIN_CLICK_TO_PLAY and
   ///    <= PLUGIN_CLICK_TO_PLAY_QUIET are click-to-play types.
   // The plugin is disabled until the user clicks on it
   const unsigned long PLUGIN_CLICK_TO_PLAY        = 8;
   // The plugin is vulnerable (update available)
   const unsigned long PLUGIN_VULNERABLE_UPDATABLE = 9;
--- a/dom/base/nsImageLoadingContent.cpp
+++ b/dom/base/nsImageLoadingContent.cpp
@@ -97,16 +97,17 @@ nsImageLoadingContent::nsImageLoadingCon
       mOutstandingDecodePromises(0),
       mRequestGeneration(0),
       mImageBlockingStatus(nsIContentPolicy::ACCEPT),
       mLoadingEnabled(true),
       mIsImageStateForced(false),
       mLoading(false),
       // mBroken starts out true, since an image without a URI is broken....
       mBroken(true),
+      mSuppressed(false),
       mNewRequestsWillNeedAnimationReset(false),
       mUseUrgentStartForChannel(false),
       mLazyLoading(false),
       mStateChangerDepth(0),
       mCurrentRequestRegistered(false),
       mPendingRequestRegistered(false),
       mIsStartingImageLoad(false),
       mSyncDecodingHint(false) {
@@ -1272,16 +1273,19 @@ EventStates nsImageLoadingContent::Image
     return mForcedImageState;
   }
 
   EventStates states;
 
   if (mBroken) {
     states |= NS_EVENT_STATE_BROKEN;
   }
+  if (mSuppressed) {
+    states |= NS_EVENT_STATE_SUPPRESSED;
+  }
   if (mLoading) {
     states |= NS_EVENT_STATE_LOADING;
   }
 
   return states;
 }
 
 void nsImageLoadingContent::UpdateImageState(bool aNotify) {
@@ -1292,21 +1296,24 @@ void nsImageLoadingContent::UpdateImageS
     // we're still under LoadImage, and OnStopDecode doesn't know anything about
     // aNotify.
     // XXX - This machinery should be removed after bug 521604.
     return;
   }
 
   nsIContent* thisContent = AsContent();
 
-  mLoading = mBroken = false;
+  mLoading = mBroken = mSuppressed = false;
 
-  // If we were blocked, we're broken, so are we if we don't have an image
-  // request at all or the image has errored.
-  if (mImageBlockingStatus != nsIContentPolicy::ACCEPT) {
+  // If we were blocked by server-based content policy, we claim to be
+  // suppressed.  If we were blocked by type-based content policy, we claim to
+  // be user-disabled.  Otherwise, claim to be broken.
+  if (mImageBlockingStatus == nsIContentPolicy::REJECT_SERVER) {
+    mSuppressed = true;
+  } else if (mImageBlockingStatus == nsIContentPolicy::REJECT_TYPE) {
     mBroken = true;
   } else if (!mCurrentRequest) {
     if (!mLazyLoading) {
       // In case of non-lazy loading, no current request means error, since we
       // weren't disabled or suppressed
       mBroken = true;
       RejectDecodePromises(NS_ERROR_DOM_IMAGE_BROKEN);
     }
--- a/dom/base/nsImageLoadingContent.h
+++ b/dom/base/nsImageLoadingContent.h
@@ -115,17 +115,18 @@ class nsImageLoadingContent : public nsI
    *        principal to use for the image load
    */
   nsresult LoadImage(const nsAString& aNewURI, bool aForce, bool aNotify,
                      ImageLoadType aImageLoadType,
                      nsIPrincipal* aTriggeringPrincipal = nullptr);
 
   /**
    * ImageState is called by subclasses that are computing their content state.
-   * The return value will have the NS_EVENT_STATE_BROKEN bit set as needed.
+   * The return value will have the NS_EVENT_STATE_BROKEN, and
+   * NS_EVENT_STATE_SUPPRESSED bits set as needed.
    *
    * Note that this state assumes that this node is "trying" to be an
    * image (so for example complete lack of attempt to load an image will lead
    * to NS_EVENT_STATE_BROKEN being set).  Subclasses that are not "trying" to
    * be an image (eg an HTML <input> of type other than "image") should just
    * not call this method when computing their intrinsic state.
    */
   mozilla::EventStates ImageState() const;
@@ -570,16 +571,17 @@ class nsImageLoadingContent : public nsI
   bool mIsImageStateForced : 1;
 
   /**
    * The state we had the last time we checked whether we needed to notify the
    * document of a state change.  These are maintained by UpdateImageState.
    */
   bool mLoading : 1;
   bool mBroken : 1;
+  bool mSuppressed : 1;
 
  protected:
   /**
    * A hack to get animations to reset, see bug 594771. On requests
    * that originate from setting .src, we mark them for needing their animation
    * reset when they are ready. mNewRequestsWillNeedAnimationReset is set to
    * true while preparing such requests (as a hack around needing to change an
    * interface), and the other two booleans store which of the current
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -1269,16 +1269,18 @@ EventStates nsObjectLoadingContent::Obje
     case eType_FakePlugin:
     case eType_Document:
       // These are OK. If documents start to load successfully, they display
       // something, and are thus not broken in this sense. The same goes for
       // plugins.
       return EventStates();
     case eType_Null:
       switch (mFallbackType) {
+        case eFallbackSuppressed:
+          return NS_EVENT_STATE_SUPPRESSED;
         case eFallbackClickToPlay:
         case eFallbackClickToPlayQuiet:
           return NS_EVENT_STATE_TYPE_CLICK_TO_PLAY;
         case eFallbackDisabled:
           return NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_HANDLER_DISABLED;
         case eFallbackBlocklisted:
           return NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_HANDLER_BLOCKED;
         case eFallbackCrashed:
@@ -2033,21 +2035,25 @@ nsresult nsObjectLoadingContent::LoadObj
 
     // Content policy implementations can mutate the DOM, check for re-entry
     if (!mIsLoading) {
       LOG(("OBJLC [%p]: We re-entered in content policy, leaving original load",
            this));
       return NS_OK;
     }
 
-    // Load denied, switch to fallback and set disabled if applicable
+    // Load denied, switch to fallback and set disabled/suppressed if applicable
     if (!allowLoad) {
       LOG(("OBJLC [%p]: Load denied by policy", this));
       mType = eType_Null;
-      fallbackType = eFallbackDisabled;
+      if (contentPolicy == nsIContentPolicy::REJECT_TYPE) {
+        fallbackType = eFallbackDisabled;
+      } else {
+        fallbackType = eFallbackSuppressed;
+      }
     }
   }
 
   // Don't allow view-source scheme.
   // view-source is the only scheme to which this applies at the moment due to
   // potential timing attacks to read data from cross-origin documents. If this
   // widens we should add a protocol flag for whether the scheme is only allowed
   // in top and use something like nsNetUtil::NS_URIChainHasFlags.
@@ -3200,17 +3206,17 @@ bool nsObjectLoadingContent::ShouldPlay(
   NS_ENSURE_TRUE(topDoc, false);
 
   // Check the flash blocking status for this page (this applies to Flash only)
   FlashClassification documentClassification = FlashClassification::Unknown;
   if (IsFlashMIME(mContentType)) {
     documentClassification = ownerDoc->DocumentFlashClassification();
   }
   if (documentClassification == FlashClassification::Denied) {
-    aReason = eFallbackDisabled;
+    aReason = eFallbackSuppressed;
     return false;
   }
 
   // Check the permission manager for permission based on the principal of
   // the toplevel content.
   nsCOMPtr<nsIPermissionManager> permissionManager =
       services::GetPermissionManager();
   NS_ENSURE_TRUE(permissionManager, false);
--- a/dom/base/nsObjectLoadingContent.h
+++ b/dom/base/nsObjectLoadingContent.h
@@ -84,16 +84,18 @@ class nsObjectLoadingContent : public ns
     // The plugin exists, but is disabled
     eFallbackDisabled = nsIObjectLoadingContent::PLUGIN_DISABLED,
     // The plugin is blocklisted and disabled
     eFallbackBlocklisted = nsIObjectLoadingContent::PLUGIN_BLOCKLISTED,
     // The plugin is considered outdated, but not disabled
     eFallbackOutdated = nsIObjectLoadingContent::PLUGIN_OUTDATED,
     // The plugin has crashed
     eFallbackCrashed = nsIObjectLoadingContent::PLUGIN_CRASHED,
+    // Suppressed by security policy
+    eFallbackSuppressed = nsIObjectLoadingContent::PLUGIN_SUPPRESSED,
     /// ** All values >= eFallbackClickToPlay are plugin placeholder types
     ///    that would be replaced by a real plugin if activated (PlayPlugin())
     /// ** Furthermore, values >= eFallbackClickToPlay and
     ///    <= eFallbackClickToPlayQuiet are click-to-play types.
     // The plugin is disabled until the user clicks on it
     eFallbackClickToPlay = nsIObjectLoadingContent::PLUGIN_CLICK_TO_PLAY,
     // The plugin is vulnerable (update available)
     eFallbackVulnerableUpdatable =
--- a/dom/base/test/test_blocking_image.html
+++ b/dom/base/test/test_blocking_image.html
@@ -14,16 +14,29 @@ https://bugzilla.mozilla.org/show_bug.cg
 <pre id="test">
 <script class="testbody" type="text/javascript">
 SimpleTest.waitForExplicitFinish();
 
 function onLoad() {
   var iframe = document.createElement("iframe");
   iframe.onload = function () {
     info("iframe loaded");
+    var winUtils = iframe.contentWindow.windowUtils;
+    // load some styles at the agent level
+    var css = `
+      img:-moz-suppressed {
+        color: green
+      }
+      img:-moz-broken {
+       color: red
+      }
+    `;
+    var sheetURL = "data:text/css," + encodeURIComponent(css);
+    winUtils.loadSheetUsingURIString(sheetURL, winUtils.AGENT_SHEET);
+
     function imgListener(img) {
       return new Promise((resolve, reject) => {
         img.addEventListener("load", () => reject());
         img.addEventListener("error", () => resolve());
       });
     }
 
     var doc = iframe.contentDocument;
@@ -40,25 +53,30 @@ function onLoad() {
 
       // `iframe` is a content iframe, and thus not in the same docgroup with
       // us, which are a chrome-privileged test.
       //
       // Ensure the frame is laid out so that this cross-origin
       // getComputedStyle call is guaranteed to work after bug 1440537.
       iframe.getBoundingClientRect();
 
-      ok(img2.matches(":-moz-broken"), "should match ':-moz-broken' selector");
+      // We can't use matches(":-moz-suppressed") here, as -moz-suppressed is
+      // chrome-only, however now we are in a content iframe.
+      is(iframe.contentWindow.getComputedStyle(img).color, "rgb(0, 128, 0)",
+         "color of img should be green");
       is(img.imageBlockingStatus, Ci.nsIContentPolicy.REJECT_SERVER,
          "imageBlockingStatues should be REJECT_SERVER.");
 
       img2.src = "https://test.invalid";
       doc.body.appendChild(img2);
       return imgListener(img2);
     }).then(() => {
       ok(true, "img2 shouldn't be loaded");
+      is(iframe.contentWindow.getComputedStyle(img2).color, "rgb(255, 0, 0)",
+         "color of img2 should be red");
       ok(img2.matches(":-moz-broken"), "should match ':-moz-broken' selector");
 
       // Now prepare for the next test, deny image.
       return new Promise(resolve => {
           SpecialPowers.pushPrefEnv({"set": [["permissions.default.image", 2]]}, resolve)
       });
     }).then(() => {
       // Now image is denied, loading image will be rejected with REJECT_TYPE,
--- a/dom/events/EventStates.h
+++ b/dom/events/EventStates.h
@@ -195,18 +195,20 @@ class EventStates {
 #define NS_EVENT_STATE_INVALID NS_DEFINE_EVENT_STATE_MACRO(11)
 // UI friendly version of :valid pseudo-class.
 #define NS_EVENT_STATE_MOZ_UI_VALID NS_DEFINE_EVENT_STATE_MACRO(12)
 // UI friendly version of :invalid pseudo-class.
 #define NS_EVENT_STATE_MOZ_UI_INVALID NS_DEFINE_EVENT_STATE_MACRO(13)
 // Content could not be rendered (image/object/etc).
 #define NS_EVENT_STATE_BROKEN NS_DEFINE_EVENT_STATE_MACRO(14)
 
-// There are two free bits here.
+// There's a free bit here.
 
+// Content suppressed by the user (ad blocking, etc).
+#define NS_EVENT_STATE_SUPPRESSED NS_DEFINE_EVENT_STATE_MACRO(16)
 // Content is still loading such that there is nothing to show the
 // user (eg an image which hasn't started coming in yet).
 #define NS_EVENT_STATE_LOADING NS_DEFINE_EVENT_STATE_MACRO(17)
 // Handler for the content has been blocked.
 #define NS_EVENT_STATE_HANDLER_BLOCKED NS_DEFINE_EVENT_STATE_MACRO(18)
 // Handler for the content has been disabled.
 #define NS_EVENT_STATE_HANDLER_DISABLED NS_DEFINE_EVENT_STATE_MACRO(19)
 // Handler for the content has crashed
--- a/dom/security/test/csp/test_docwrite_meta.html
+++ b/dom/security/test/csp/test_docwrite_meta.html
@@ -40,18 +40,18 @@ function checkResultsBlocked() {
 
   // stylesheet: default background color within FF is transparent
   var bgcolor = window.getComputedStyle(writemetacspframe.contentDocument.body)
                       .getPropertyValue("background-color");
   is(bgcolor, "rgba(0, 0, 0, 0)", "inital background value in FF should be 'transparent'");
 
   // image: make sure image is blocked
   var img = writemetacspframe.contentDocument.getElementById("testimage");
-  is(img.naturalWidth, 0, "image width should be 0");
-  is(img.naturalHeight, 0, "image height should be 0");
+  is(img.width, 0, "image widht should be 0");
+  is(img.height, 0, "image widht should be 0");
 
   // script: make sure defined variable in external script is undefined
   is(writemetacspframe.contentDocument.myMetaCSPScript, undefined, "myMetaCSPScript should be 'undefined'");
 
   checkTestsDone();
 }
 
 // document.write(<--) to comment out meta csp should allow resources to be loaded
--- a/dom/webidl/HTMLObjectElement.webidl
+++ b/dom/webidl/HTMLObjectElement.webidl
@@ -109,16 +109,19 @@ interface mixin MozObjectLoadingContent 
   [ChromeOnly]
   const unsigned long PLUGIN_BLOCKLISTED          = 3;
   // The plugin is considered outdated, but not disabled
   [ChromeOnly]
   const unsigned long PLUGIN_OUTDATED             = 4;
   // The plugin has crashed
   [ChromeOnly]
   const unsigned long PLUGIN_CRASHED              = 5;
+  // Suppressed by security policy
+  [ChromeOnly]
+  const unsigned long PLUGIN_SUPPRESSED           = 6;
   /// ** All values >= PLUGIN_CLICK_TO_PLAY are plugin placeholder types that
   ///    would be replaced by a real plugin if activated (playPlugin())
   /// ** Furthermore, values >= PLUGIN_CLICK_TO_PLAY and
   ///    <= PLUGIN_VULNERABLE_NO_UPDATE are click-to-play types.
   // The plugin is disabled until the user clicks on it
   [ChromeOnly]
   const unsigned long PLUGIN_CLICK_TO_PLAY        = 8;
   // The plugin is vulnerable (update available)
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -463,18 +463,20 @@ void RestyleManager::ContentRemoved(nsIC
 static bool StateChangeMayAffectFrame(const Element& aElement,
                                       const nsIFrame& aFrame,
                                       EventStates aStates) {
   if (aFrame.IsGeneratedContentFrame()) {
     // If it's generated content, ignore LOADING/etc state changes on it.
     return false;
   }
 
-  const bool brokenChanged = aStates.HasState(NS_EVENT_STATE_BROKEN);
-  const bool loadingChanged = aStates.HasState(NS_EVENT_STATE_LOADING);
+  const bool brokenChanged = aStates.HasAtLeastOneOfStates(
+      NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_SUPPRESSED);
+  const bool loadingChanged =
+      aStates.HasAtLeastOneOfStates(NS_EVENT_STATE_LOADING);
 
   if (!brokenChanged && !loadingChanged) {
     return false;
   }
 
   if (aElement.IsHTMLElement(nsGkAtoms::img)) {
     // Loading state doesn't affect <img>, see
     // `nsImageFrame::ShouldCreateImageFrameFor`.
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -3498,17 +3498,18 @@ nsCSSFrameConstructor::FindInputData(con
 /* static */
 const nsCSSFrameConstructor::FrameConstructionData*
 nsCSSFrameConstructor::FindObjectData(const Element& aElement,
                                       ComputedStyle& aStyle) {
   // GetDisplayedType isn't necessarily nsIObjectLoadingContent::TYPE_NULL for
   // cases when the object is broken/suppressed/etc (e.g. a broken image), but
   // we want to treat those cases as TYPE_NULL
   uint32_t type;
-  if (aElement.State().HasState(NS_EVENT_STATE_BROKEN)) {
+  if (aElement.State().HasAtLeastOneOfStates(NS_EVENT_STATE_BROKEN |
+                                             NS_EVENT_STATE_SUPPRESSED)) {
     type = nsIObjectLoadingContent::TYPE_NULL;
   } else {
     nsCOMPtr<nsIObjectLoadingContent> objContent =
         do_QueryInterface(const_cast<Element*>(&aElement));
     NS_ASSERTION(objContent,
                  "embed and object must implement "
                  "nsIObjectLoadingContent!");
 
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -628,16 +628,20 @@ nsRect nsImageFrame::SourceRectToDest(co
   r.y -= (scale + (r.y % scale)) % scale;
   r.width = right + ((scale - (right % scale)) % scale) - r.x;
   r.height = bottom + ((scale - (bottom % scale)) % scale) - r.y;
 
   return r;
 }
 
 static bool ImageOk(EventStates aState) {
+  // Note that we treat NS_EVENT_STATE_SUPPRESSED images as "OK".  This means
+  // that we'll construct image frames for them as needed if their display is
+  // toggled from "none" (though we won't paint them, unless their visibility
+  // is changed too).
   return !aState.HasState(NS_EVENT_STATE_BROKEN);
 }
 
 static bool HasAltText(const Element& aElement) {
   // We always return some alternate text for <input>, see
   // nsCSSFrameConstructor::GetAlternateTextFor.
   if (aElement.IsHTMLElement(nsGkAtoms::input)) {
     return true;
--- a/layout/style/res/html.css
+++ b/layout/style/res/html.css
@@ -657,16 +657,31 @@ object:-moz-broken > *|* {
   /*
     Inherit in the object's alignment so that if we aren't aligned explicitly
     we'll end up in the right place vertically.  See bug 36997.  Note that this
     is not !important because we _might_ be aligned explicitly.
   */
   vertical-align: inherit;
 }
 
+img:-moz-suppressed,
+input:-moz-suppressed,
+object:-moz-suppressed,
+embed:-moz-suppressed {
+  /*
+    Set visibility too in case the page changes display.  Note that we _may_
+    want to just set visibility and not display, in general, if we find that
+    display:none breaks too many layouts.  And if we decide we really do want
+    people to be able to right-click blocked images, etc, we need to set
+    neither one, and hack the painting code.... :(
+   */
+  display: none !important;
+  visibility: hidden !important;
+}
+
 img[usemap], object[usemap] {
   color: blue;
 }
 
 frameset {
   display: block ! important;
   overflow: clip;
   position: static ! important;
--- a/layout/style/test/test_selectors.html
+++ b/layout/style/test/test_selectors.html
@@ -1120,16 +1120,18 @@ function runTests() {
     test_parseable(":-moz-window-inactive");
     test_parseable("div p:-moz-window-inactive:hover span");
 
     // Chrome-only
     test_unbalanced_unparseable(":-moz-browser-frame");
 
     // Plugin pseudoclasses are chrome-only:
     test_unbalanced_unparseable(":-moz-type-unsupported");
+    test_unbalanced_unparseable(":-moz-suppressed");
+    test_unbalanced_unparseable(":-moz-type-unsupported");
     test_unbalanced_unparseable(":-moz-type-unsupported-platform");
     test_unbalanced_unparseable(":-moz-handler-clicktoplay");
     test_unbalanced_unparseable(":-moz-handler-vulnerable-updatable");
     test_unbalanced_unparseable(":-moz-handler-vulnerable-no-update");
     test_unbalanced_unparseable(":-moz-handler-disabled");
     test_unbalanced_unparseable(":-moz-handler-blocked");
     test_unbalanced_unparseable(":-moz-handler-crashed");
 
--- a/servo/components/style/element_state.rs
+++ b/servo/components/style/element_state.rs
@@ -48,16 +48,18 @@ bitflags! {
         /// <https://html.spec.whatwg.org/multipage/#selector-invalid>
         const IN_INVALID_STATE = 1 << 11;
         /// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-ui-valid
         const IN_MOZ_UI_VALID_STATE = 1 << 12;
         /// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-ui-invalid
         const IN_MOZ_UI_INVALID_STATE = 1 << 13;
         /// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-broken
         const IN_BROKEN_STATE = 1 << 14;
+        /// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-suppressed
+        const IN_SUPPRESSED_STATE = 1 << 16;
         /// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-loading
         const IN_LOADING_STATE = 1 << 17;
         /// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-handler-blocked
         const IN_HANDLER_BLOCKED_STATE = 1 << 18;
         /// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-handler-disabled
         const IN_HANDLER_DISABLED_STATE = 1 << 19;
         /// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-handler-crashed
         const IN_HANDLER_CRASHED_STATE = 1 << 20;
--- a/servo/components/style/gecko/non_ts_pseudo_class_list.rs
+++ b/servo/components/style/gecko/non_ts_pseudo_class_list.rs
@@ -53,16 +53,17 @@ macro_rules! apply_non_ts_list {
                 ("-moz-styleeditor-transitioning", MozStyleeditorTransitioning, IN_STYLEEDITOR_TRANSITIONING_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS),
                 ("fullscreen", Fullscreen, IN_FULLSCREEN_STATE, _),
                 ("-moz-modal-dialog", MozModalDialog, IN_MODAL_DIALOG_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS),
                 ("-moz-topmost-modal-dialog", MozTopmostModalDialog, IN_TOPMOST_MODAL_DIALOG_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS),
                 // TODO(emilio): This is inconsistently named (the capital R).
                 ("-moz-focusring", MozFocusRing, IN_FOCUSRING_STATE, _),
                 ("-moz-broken", MozBroken, IN_BROKEN_STATE, _),
                 ("-moz-loading", MozLoading, IN_LOADING_STATE, _),
+                ("-moz-suppressed", MozSuppressed, IN_SUPPRESSED_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME),
                 ("-moz-has-dir-attr", MozHasDirAttr, IN_HAS_DIR_ATTR_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS),
                 ("-moz-dir-attr-ltr", MozDirAttrLTR, IN_HAS_DIR_ATTR_LTR_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS),
                 ("-moz-dir-attr-rtl", MozDirAttrRTL, IN_HAS_DIR_ATTR_RTL_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS),
                 ("-moz-dir-attr-like-auto", MozDirAttrLikeAuto, IN_HAS_DIR_ATTR_LIKE_AUTO_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS),
                 ("-moz-autofill", MozAutofill, IN_AUTOFILL_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME),
                 ("-moz-autofill-preview", MozAutofillPreview, IN_AUTOFILL_PREVIEW_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME),
 
                 ("-moz-handler-clicktoplay", MozHandlerClickToPlay, IN_HANDLER_CLICK_TO_PLAY_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME),
--- a/servo/components/style/gecko/wrapper.rs
+++ b/servo/components/style/gecko/wrapper.rs
@@ -2018,16 +2018,17 @@ impl<'le> ::selectors::Element for Gecko
             NonTSPseudoClass::Indeterminate |
             NonTSPseudoClass::MozInert |
             NonTSPseudoClass::PlaceholderShown |
             NonTSPseudoClass::Target |
             NonTSPseudoClass::Valid |
             NonTSPseudoClass::Invalid |
             NonTSPseudoClass::MozUIValid |
             NonTSPseudoClass::MozBroken |
+            NonTSPseudoClass::MozSuppressed |
             NonTSPseudoClass::MozLoading |
             NonTSPseudoClass::MozHandlerBlocked |
             NonTSPseudoClass::MozHandlerDisabled |
             NonTSPseudoClass::MozHandlerCrashed |
             NonTSPseudoClass::Required |
             NonTSPseudoClass::Optional |
             NonTSPseudoClass::ReadOnly |
             NonTSPseudoClass::ReadWrite |
deleted file mode 100644
--- a/testing/web-platform/tests/html/rendering/replaced-elements/images/blocked-by-csp-ref.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<!doctype html>
-<title>Test reference</title>
-<style>img { border: solid; }</style>
-It should say PASS below:<br>
-<img alt="PASS">
deleted file mode 100644
--- a/testing/web-platform/tests/html/rendering/replaced-elements/images/blocked-by-csp.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<!doctype html>
-<title>Images behave the same when blocked by CSP as when failing to load/broken</title>
-<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1664156">
-<link rel="match" href="blocked-by-csp-ref.html">
-<meta http-equiv=content-security-policy content="img-src 'none'">
-<style>img { border: solid; }</style>
-It should say PASS below:<br>
-<img src=image alt="PASS">