) [13,12 196x24]
+ PaintableWithLines (BlockContainer) [0,0 800x46]
+ PaintableWithLines (BlockContainer) [9,9 782x28]
+ PaintableWithLines (BlockContainer
) [11,11 200x24]
+ PaintableWithLines (BlockContainer
) [13,12 196x22]
diff --git a/Tests/LibWeb/Text/expected/shadow-root-adopted-style-sheets.txt b/Tests/LibWeb/Text/expected/shadow-root-adopted-style-sheets.txt
new file mode 100644
index 0000000000..2f0a8b4968
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/shadow-root-adopted-style-sheets.txt
@@ -0,0 +1 @@
+ border of #test = (2px solid rgb(173, 255, 47))
diff --git a/Tests/LibWeb/Text/input/shadow-root-adopted-style-sheets.html b/Tests/LibWeb/Text/input/shadow-root-adopted-style-sheets.html
new file mode 100644
index 0000000000..492f2d9a92
--- /dev/null
+++ b/Tests/LibWeb/Text/input/shadow-root-adopted-style-sheets.html
@@ -0,0 +1,37 @@
+
+
+
+
diff --git a/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp b/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp
index 71b79a720b..d7af0637bc 100644
--- a/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp
+++ b/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp
@@ -63,6 +63,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -255,19 +256,25 @@ template
void StyleComputer::for_each_stylesheet(CascadeOrigin cascade_origin, Callback callback) const
{
if (cascade_origin == CascadeOrigin::UserAgent) {
- callback(default_stylesheet(document()));
+ callback(default_stylesheet(document()), {});
if (document().in_quirks_mode())
- callback(quirks_mode_stylesheet(document()));
- callback(mathml_stylesheet(document()));
- callback(svg_stylesheet(document()));
+ callback(quirks_mode_stylesheet(document()), {});
+ callback(mathml_stylesheet(document()), {});
+ callback(svg_stylesheet(document()), {});
}
if (cascade_origin == CascadeOrigin::User) {
if (m_user_style_sheet)
- callback(*m_user_style_sheet);
+ callback(*m_user_style_sheet, {});
}
if (cascade_origin == CascadeOrigin::Author) {
document().for_each_css_style_sheet([&](CSSStyleSheet& sheet) {
- callback(sheet);
+ callback(sheet, {});
+ });
+
+ const_cast(document()).for_each_shadow_root([&](DOM::ShadowRoot& shadow_root) {
+ shadow_root.for_each_css_style_sheet([&](CSSStyleSheet& sheet) {
+ callback(sheet, &shadow_root);
+ });
});
}
}
@@ -298,6 +305,9 @@ StyleComputer::RuleCache const& StyleComputer::rule_cache_for_cascade_origin(Cas
Vector StyleComputer::collect_matching_rules(DOM::Element const& element, CascadeOrigin cascade_origin, Optional pseudo_element) const
{
+ auto const& root_node = element.root();
+ auto shadow_root = is(root_node) ? static_cast(&root_node) : nullptr;
+
auto const& rule_cache = rule_cache_for_cascade_origin(cascade_origin);
Vector rules_to_run;
@@ -331,6 +341,12 @@ Vector StyleComputer::collect_matching_rules(DOM::Element const& e
Vector matching_rules;
matching_rules.ensure_capacity(rules_to_run.size());
for (auto const& rule_to_run : rules_to_run) {
+ // FIXME: This needs to be revised when adding support for the :host and ::shadow selectors, which transition shadow tree boundaries
+ auto rule_root = rule_to_run.shadow_root;
+ auto from_user_agent_or_user_stylesheet = rule_to_run.cascade_origin == CascadeOrigin::UserAgent || rule_to_run.cascade_origin == CascadeOrigin::User;
+ if (rule_root != shadow_root && !from_user_agent_or_user_stylesheet)
+ continue;
+
auto const& selector = rule_to_run.rule->selectors()[rule_to_run.selector_index];
if (SelectorEngine::matches(selector, *rule_to_run.sheet, element, pseudo_element))
matching_rules.append(rule_to_run);
@@ -2277,12 +2293,14 @@ NonnullOwnPtr StyleComputer::make_rule_cache_for_casca
Vector matching_rules;
size_t style_sheet_index = 0;
- for_each_stylesheet(cascade_origin, [&](auto& sheet) {
+ for_each_stylesheet(cascade_origin, [&](auto& sheet, JS::GCPtr shadow_root) {
size_t rule_index = 0;
sheet.for_each_effective_style_rule([&](auto const& rule) {
size_t selector_index = 0;
for (CSS::Selector const& selector : rule.selectors()) {
MatchingRule matching_rule {
+ cascade_origin,
+ shadow_root,
&rule,
sheet,
style_sheet_index,
diff --git a/Userland/Libraries/LibWeb/CSS/StyleComputer.h b/Userland/Libraries/LibWeb/CSS/StyleComputer.h
index 31c2be6016..bd15fec532 100644
--- a/Userland/Libraries/LibWeb/CSS/StyleComputer.h
+++ b/Userland/Libraries/LibWeb/CSS/StyleComputer.h
@@ -20,7 +20,18 @@
namespace Web::CSS {
+// https://www.w3.org/TR/css-cascade/#origin
+enum class CascadeOrigin {
+ Author,
+ User,
+ UserAgent,
+ Animation,
+ Transition,
+};
+
struct MatchingRule {
+ CascadeOrigin cascade_origin;
+ JS::GCPtr shadow_root;
JS::GCPtr rule;
JS::GCPtr sheet;
size_t style_sheet_index { 0 };
@@ -55,15 +66,6 @@ public:
NonnullRefPtr compute_style(DOM::Element&, Optional = {}) const;
RefPtr compute_pseudo_element_style_if_needed(DOM::Element&, Optional) const;
- // https://www.w3.org/TR/css-cascade/#origin
- enum class CascadeOrigin {
- Author,
- User,
- UserAgent,
- Animation,
- Transition,
- };
-
Vector collect_matching_rules(DOM::Element const&, CascadeOrigin, Optional) const;
void invalidate_rule_cache();
diff --git a/Userland/Libraries/LibWeb/DOM/ShadowRoot.cpp b/Userland/Libraries/LibWeb/DOM/ShadowRoot.cpp
index 48323f990d..9de779f366 100644
--- a/Userland/Libraries/LibWeb/DOM/ShadowRoot.cpp
+++ b/Userland/Libraries/LibWeb/DOM/ShadowRoot.cpp
@@ -105,4 +105,16 @@ WebIDL::ExceptionOr ShadowRoot::set_adopted_style_sheets(JS::Value new_val
return {};
}
+void ShadowRoot::for_each_css_style_sheet(Function&& callback) const
+{
+ for (auto& style_sheet : style_sheets().sheets())
+ callback(*style_sheet);
+
+ if (m_adopted_style_sheets) {
+ m_adopted_style_sheets->for_each([&](auto& style_sheet) {
+ callback(style_sheet);
+ });
+ }
+}
+
}
diff --git a/Userland/Libraries/LibWeb/DOM/ShadowRoot.h b/Userland/Libraries/LibWeb/DOM/ShadowRoot.h
index 532f99985b..f1d2c01149 100644
--- a/Userland/Libraries/LibWeb/DOM/ShadowRoot.h
+++ b/Userland/Libraries/LibWeb/DOM/ShadowRoot.h
@@ -42,6 +42,8 @@ public:
JS::NonnullGCPtr adopted_style_sheets() const;
WebIDL::ExceptionOr set_adopted_style_sheets(JS::Value);
+ void for_each_css_style_sheet(Function&& callback) const;
+
virtual void finalize() override;
protected: