commit 65f4a6b2c8b6f00381c3158b4f18d767f2053498
parent dd3e28b5d60f6dfc2c2ab3c64c2aff3c8dae1948
Author: Emilio Cobos Álvarez <emilio@crisal.io>
Date: Thu, 16 Oct 2025 07:38:32 +0000
Bug 1986702 - Fix CSSOM tracking in shadow DOM. r=devtools-reviewers,nchevobbe
Bug 1933473 missed the shadow root style rule map, this is the
equivalent fix.
The test in D268698 covers this (now it shows the bug but it should be
adapted to expect the right behavior).
Co-authored-by: Nicolas Chevobbe <nchevobbe@mozilla.com>
Differential Revision: https://phabricator.services.mozilla.com/D268744
Diffstat:
3 files changed, 61 insertions(+), 3 deletions(-)
diff --git a/dom/base/ShadowRoot.cpp b/dom/base/ShadowRoot.cpp
@@ -7,6 +7,7 @@
#include "mozilla/dom/ShadowRoot.h"
#include "ChildIterator.h"
+#include "mozilla/DeclarationBlock.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/GlobalStyleSheetCache.h"
#include "mozilla/IdentifierMapEntry.h"
@@ -410,12 +411,15 @@ void ShadowRoot::RuleRemoved(StyleSheet& aSheet, css::Rule& aRule) {
ApplicableRulesChanged();
}
-void ShadowRoot::RuleChanged(StyleSheet& aSheet, css::Rule*,
- const StyleRuleChange&) {
+void ShadowRoot::RuleChanged(StyleSheet& aSheet, css::Rule* aRule,
+ const StyleRuleChange& aChange) {
if (!aSheet.IsApplicable()) {
return;
}
-
+ if (mStyleRuleMap && aChange.mOldBlock != aChange.mNewBlock) {
+ mStyleRuleMap->RuleDeclarationsChanged(*aRule, aChange.mOldBlock->Raw(),
+ aChange.mNewBlock->Raw());
+ }
MOZ_ASSERT(mServoStyles);
Servo_AuthorStyles_ForceDirty(mServoStyles.get());
ApplicableRulesChanged();
diff --git a/layout/inspector/tests/mochitest.toml b/layout/inspector/tests/mochitest.toml
@@ -56,6 +56,8 @@ support-files = [
["test_getMatchingCSSRules_pseudo.html"]
+["test_getMatchingCSSRules_shadow_dom.html"]
+
["test_getMatchingCSSRules_slotted.html"]
["test_getMatchingCSSRules_starting_style.html"]
diff --git a/layout/inspector/tests/test_getMatchingCSSRules_shadow_dom.html b/layout/inspector/tests/test_getMatchingCSSRules_shadow_dom.html
@@ -0,0 +1,52 @@
+<!DOCTYPE HTML>
+<title>Test for InspectorUtils.getMatchingCSSRules for starting style</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
+<pre id="log"></pre>
+<div id="host"></div>
+<script>
+ const sheet = new CSSStyleSheet();
+ sheet.replaceSync("unknowntagname { color: tomato; background-color: gold;}");
+ const shadow = host.attachShadow({ mode: "open" });
+ shadow.adoptedStyleSheets = [sheet];
+
+ const shadowEl = document.createElement("unknowntagname");
+ shadowEl.textContent = "Hello from the shadow DOM";
+ shadow.appendChild(shadowEl);
+</script>
+<script>
+/**
+ * This test checks that InspectorUtils.getMatchingCSSRules returns expected rules
+ * when passed a shadow dom element
+ * To avoid effects from UA sheets, we use an element with "unknowntagname".
+ */
+
+const InspectorUtils = SpecialPowers.InspectorUtils;
+
+add_task(async function() {
+ const shadowRoot = host.shadowRoot;
+ const shadowEl = shadowRoot.querySelector("unknowntagname")
+ const styleSheet = shadowRoot.adoptedStyleSheets[0]
+
+ let rules = InspectorUtils.getMatchingCSSRules(shadowEl);
+ is(rules.length, 1, "Got expected number of rule");
+
+ is(
+ rules[0].cssText,
+ styleSheet.cssRules[0].cssText,
+ "We're getting a CSSRule and it's the one from the adopted stylesheet"
+ );
+
+ info("Remove a property from the rule")
+ styleSheet.cssRules[0].style.removeProperty("color");
+
+ rules = InspectorUtils.getMatchingCSSRules(shadowEl);
+ is(rules.length, 1, "Got expected number of rule after removing a property from the rule");
+ is(
+ rules[0].cssText,
+ styleSheet.cssRules[0].cssText,
+ "We're still getting the adopted stylesheet CSSRule after removing a property"
+ );
+});
+
+</script>