From 33294aea862ede5c880a7a9ea447e38446656df6 Mon Sep 17 00:00:00 2001 From: Aliaksandr Kalenik Date: Sun, 19 Mar 2023 17:01:26 +0100 Subject: [PATCH] LibWeb: Apply shadow root style sheets in StyleComputer Now, if an element belongs to a shadow tree, we use only the style sheets from the corresponding shadow root during style computation, instead of using all available style sheets as was the case previously. The only exception is the user agent style sheets, which are still taken into account for all elements. Tests/LibWeb/Layout/input/input-element-with-display-inline.html is affected because style of document no longer affects shadow tree of input element, like it is supposed to be. Co-authored-by: Simon Wanner --- .../input-element-with-display-inline.txt | 22 +++++------ .../shadow-root-adopted-style-sheets.txt | 1 + .../shadow-root-adopted-style-sheets.html | 37 +++++++++++++++++++ .../Libraries/LibWeb/CSS/StyleComputer.cpp | 32 ++++++++++++---- Userland/Libraries/LibWeb/CSS/StyleComputer.h | 20 +++++----- Userland/Libraries/LibWeb/DOM/ShadowRoot.cpp | 12 ++++++ Userland/Libraries/LibWeb/DOM/ShadowRoot.h | 2 + 7 files changed, 99 insertions(+), 27 deletions(-) create mode 100644 Tests/LibWeb/Text/expected/shadow-root-adopted-style-sheets.txt create mode 100644 Tests/LibWeb/Text/input/shadow-root-adopted-style-sheets.html diff --git a/Tests/LibWeb/Layout/expected/input-element-with-display-inline.txt b/Tests/LibWeb/Layout/expected/input-element-with-display-inline.txt index 26cadcefc5..8571526d23 100644 --- a/Tests/LibWeb/Layout/expected/input-element-with-display-inline.txt +++ b/Tests/LibWeb/Layout/expected/input-element-with-display-inline.txt @@ -1,15 +1,15 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline - BlockContainer at (1,1) content-size 798x46 [BFC] children: not-inline - BlockContainer at (10,10) content-size 780x28 children: inline - frag 0 from BlockContainer start: 0, length: 0, rect: [11,11 200x26] baseline: 28 - BlockContainer at (11,11) content-size 200x26 inline-block [BFC] children: not-inline - Box
at (13,12) content-size 196x24 flex-container(row) [FFC] children: not-inline - BlockContainer
at (14,13) content-size 194x22 flex-item [BFC] children: inline + BlockContainer at (1,1) content-size 798x44 [BFC] children: not-inline + BlockContainer at (10,10) content-size 780x26 children: inline + frag 0 from BlockContainer start: 0, length: 0, rect: [11,11 200x24] baseline: 26 + BlockContainer at (11,11) content-size 200x24 inline-block [BFC] children: not-inline + Box
at (13,12) content-size 196x22 flex-container(row) [FFC] children: not-inline + BlockContainer
at (13,12) content-size 196x22 flex-item [BFC] children: inline TextNode <#text> ViewportPaintable (Viewport<#document>) [0,0 800x600] - PaintableWithLines (BlockContainer) [0,0 800x48] - PaintableWithLines (BlockContainer) [9,9 782x30] - PaintableWithLines (BlockContainer) [10,10 202x28] - PaintableBox (Box
) [11,11 200x26] - PaintableWithLines (BlockContainer
) [13,12 196x24] + PaintableWithLines (BlockContainer) [0,0 800x46] + PaintableWithLines (BlockContainer) [9,9 782x28] + PaintableWithLines (BlockContainer) [10,10 202x26] + PaintableBox (Box
) [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: