at (23,23) content-size 343.96875x17 inline-block [BFC] children: inline
+ InlineNode
+ frag 0 from TextNode start: 0, length: 42, rect: [23,23 343.96875x17] baseline: 13.296875
+ "hello :host and :host()"
+ TextNode <#text>
+ TextNode <#text>
+
+ViewportPaintable (Viewport<#document>) [0,0 800x600]
+ PaintableWithLines (BlockContainer) [0,0 800x63]
+ PaintableWithLines (BlockContainer) [8,8 784x47]
+ PaintableWithLines (BlockContainer) [8,8 784x47]
+ PaintableWithLines (BlockContainer
) [8,8 373.96875x47]
+ InlinePaintable (InlineNode)
+ TextPaintable (TextNode<#text>)
diff --git a/Tests/LibWeb/Layout/input/host-pseudo-class-basic.html b/Tests/LibWeb/Layout/input/host-pseudo-class-basic.html
new file mode 100644
index 00000000000..14a079cd4a3
--- /dev/null
+++ b/Tests/LibWeb/Layout/input/host-pseudo-class-basic.html
@@ -0,0 +1,4 @@
+
hello :host and :host(<compound-selector>)
diff --git a/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp b/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp
index 5afed33922a..403ad1fc39f 100644
--- a/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp
+++ b/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp
@@ -34,6 +34,24 @@
namespace Web::SelectorEngine {
+// Upward traversal for descendant (' ') and immediate child combinator ('>')
+// If we're starting inside a shadow tree, traversal stops at the nearest shadow host.
+// This is an implementation detail of the :host selector. Otherwise we would just traverse up to the document root.
+static inline JS::GCPtr traverse_up(JS::GCPtr node, JS::GCPtr shadow_host)
+{
+ if (!node)
+ return nullptr;
+
+ if (shadow_host) {
+ // NOTE: We only traverse up to the shadow host, not beyond.
+ if (node == shadow_host)
+ return nullptr;
+
+ return node->parent_or_shadow_host_element();
+ }
+ return node->parent();
+}
+
// https://drafts.csswg.org/selectors-4/#the-lang-pseudo
static inline bool matches_lang_pseudo_class(DOM::Element const& element, Vector const& languages)
{
@@ -64,7 +82,7 @@ static inline bool matches_lang_pseudo_class(DOM::Element const& element, Vector
}
// https://drafts.csswg.org/selectors-4/#relational
-static inline bool matches_has_pseudo_class(CSS::Selector const& selector, Optional style_sheet_for_rule, DOM::Element const& anchor)
+static inline bool matches_has_pseudo_class(CSS::Selector const& selector, Optional style_sheet_for_rule, DOM::Element const& anchor, JS::GCPtr shadow_host)
{
switch (selector.compound_selectors()[0].combinator) {
// Shouldn't be possible because we've parsed relative selectors, which always have a combinator, implicitly or explicitly.
@@ -76,7 +94,7 @@ static inline bool matches_has_pseudo_class(CSS::Selector const& selector, Optio
if (!descendant.is_element())
return TraversalDecision::Continue;
auto const& descendant_element = static_cast(descendant);
- if (matches(selector, style_sheet_for_rule, descendant_element, {}, {}, SelectorKind::Relative)) {
+ if (matches(selector, style_sheet_for_rule, descendant_element, shadow_host, {}, {}, SelectorKind::Relative)) {
has = true;
return TraversalDecision::Break;
}
@@ -90,7 +108,7 @@ static inline bool matches_has_pseudo_class(CSS::Selector const& selector, Optio
if (!child.is_element())
return IterationDecision::Continue;
auto const& child_element = static_cast(child);
- if (matches(selector, style_sheet_for_rule, child_element, {}, {}, SelectorKind::Relative)) {
+ if (matches(selector, style_sheet_for_rule, child_element, shadow_host, {}, {}, SelectorKind::Relative)) {
has = true;
return IterationDecision::Break;
}
@@ -99,10 +117,10 @@ static inline bool matches_has_pseudo_class(CSS::Selector const& selector, Optio
return has;
}
case CSS::Selector::Combinator::NextSibling:
- return anchor.next_element_sibling() != nullptr && matches(selector, style_sheet_for_rule, *anchor.next_element_sibling(), {}, {}, SelectorKind::Relative);
+ return anchor.next_element_sibling() != nullptr && matches(selector, style_sheet_for_rule, *anchor.next_element_sibling(), shadow_host, {}, {}, SelectorKind::Relative);
case CSS::Selector::Combinator::SubsequentSibling: {
for (auto* sibling = anchor.next_element_sibling(); sibling; sibling = sibling->next_element_sibling()) {
- if (matches(selector, style_sheet_for_rule, *sibling, {}, {}, SelectorKind::Relative))
+ if (matches(selector, style_sheet_for_rule, *sibling, shadow_host, {}, {}, SelectorKind::Relative))
return true;
}
return false;
@@ -318,7 +336,22 @@ static bool matches_open_state_pseudo_class(DOM::Element const& element, bool op
return false;
}
-static inline bool matches_pseudo_class(CSS::Selector::SimpleSelector::PseudoClassSelector const& pseudo_class, Optional style_sheet_for_rule, DOM::Element const& element, JS::GCPtr scope, SelectorKind selector_kind)
+// https://drafts.csswg.org/css-scoping/#host-selector
+static inline bool matches_host_pseudo_class(JS::NonnullGCPtr element, JS::GCPtr shadow_host, CSS::SelectorList const& argument_selector_list, Optional style_sheet_for_rule)
+{
+ // When evaluated in the context of a shadow tree, it matches the shadow tree’s shadow host if the shadow host,
+ // in its normal context, matches the selector argument. In any other context, it matches nothing.
+ if (!shadow_host || element != shadow_host)
+ return false;
+
+ // NOTE: There's either 0 or 1 argument selector, since the syntax is :host or :host()
+ if (!argument_selector_list.is_empty())
+ return matches(argument_selector_list.first(), style_sheet_for_rule, element, nullptr);
+
+ return true;
+}
+
+static inline bool matches_pseudo_class(CSS::Selector::SimpleSelector::PseudoClassSelector const& pseudo_class, Optional style_sheet_for_rule, DOM::Element const& element, JS::GCPtr shadow_host, JS::GCPtr scope, SelectorKind selector_kind)
{
switch (pseudo_class.type) {
case CSS::PseudoClass::Link:
@@ -382,8 +415,7 @@ static inline bool matches_pseudo_class(CSS::Selector::SimpleSelector::PseudoCla
case CSS::PseudoClass::Root:
return is(element);
case CSS::PseudoClass::Host:
- // FIXME: Implement :host selector.
- return false;
+ return matches_host_pseudo_class(element, shadow_host, pseudo_class.argument_selector_list, style_sheet_for_rule);
case CSS::PseudoClass::Scope:
return scope ? &element == scope : is(element);
case CSS::PseudoClass::FirstOfType:
@@ -415,20 +447,20 @@ static inline bool matches_pseudo_class(CSS::Selector::SimpleSelector::PseudoCla
return false;
// These selectors should be relative selectors (https://drafts.csswg.org/selectors-4/#relative-selector)
for (auto& selector : pseudo_class.argument_selector_list) {
- if (matches_has_pseudo_class(selector, style_sheet_for_rule, element))
+ if (matches_has_pseudo_class(selector, style_sheet_for_rule, element, shadow_host))
return true;
}
return false;
case CSS::PseudoClass::Is:
case CSS::PseudoClass::Where:
for (auto& selector : pseudo_class.argument_selector_list) {
- if (matches(selector, style_sheet_for_rule, element))
+ if (matches(selector, style_sheet_for_rule, element, shadow_host))
return true;
}
return false;
case CSS::PseudoClass::Not:
for (auto& selector : pseudo_class.argument_selector_list) {
- if (matches(selector, style_sheet_for_rule, element))
+ if (matches(selector, style_sheet_for_rule, element, shadow_host))
return false;
}
return true;
@@ -445,11 +477,11 @@ static inline bool matches_pseudo_class(CSS::Selector::SimpleSelector::PseudoCla
if (!parent)
return false;
- auto matches_selector_list = [&style_sheet_for_rule](CSS::SelectorList const& list, DOM::Element const& element) {
+ auto matches_selector_list = [&style_sheet_for_rule, shadow_host](CSS::SelectorList const& list, DOM::Element const& element) {
if (list.is_empty())
return true;
for (auto const& child_selector : list) {
- if (matches(child_selector, style_sheet_for_rule, element)) {
+ if (matches(child_selector, style_sheet_for_rule, element, shadow_host)) {
return true;
}
}
@@ -648,7 +680,7 @@ static ALWAYS_INLINE bool matches_namespace(
VERIFY_NOT_REACHED();
}
-static inline bool matches(CSS::Selector::SimpleSelector const& component, Optional style_sheet_for_rule, DOM::Element const& element, JS::GCPtr scope, SelectorKind selector_kind)
+static inline bool matches(CSS::Selector::SimpleSelector const& component, Optional style_sheet_for_rule, DOM::Element const& element, JS::GCPtr shadow_host, JS::GCPtr scope, SelectorKind selector_kind)
{
switch (component.type) {
case CSS::Selector::SimpleSelector::Type::Universal:
@@ -675,7 +707,7 @@ static inline bool matches(CSS::Selector::SimpleSelector const& component, Optio
case CSS::Selector::SimpleSelector::Type::Attribute:
return matches_attribute(component.attribute(), style_sheet_for_rule, element);
case CSS::Selector::SimpleSelector::Type::PseudoClass:
- return matches_pseudo_class(component.pseudo_class(), style_sheet_for_rule, element, scope, selector_kind);
+ return matches_pseudo_class(component.pseudo_class(), style_sheet_for_rule, element, shadow_host, scope, selector_kind);
case CSS::Selector::SimpleSelector::Type::PseudoElement:
// Pseudo-element matching/not-matching is handled in the top level matches().
return true;
@@ -684,12 +716,13 @@ static inline bool matches(CSS::Selector::SimpleSelector const& component, Optio
}
}
-static inline bool matches(CSS::Selector const& selector, Optional style_sheet_for_rule, int component_list_index, DOM::Element const& element, JS::GCPtr scope, SelectorKind selector_kind)
+static inline bool matches(CSS::Selector const& selector, Optional style_sheet_for_rule, int component_list_index, DOM::Element const& element, JS::GCPtr shadow_host, JS::GCPtr scope, SelectorKind selector_kind)
{
auto& compound_selector = selector.compound_selectors()[component_list_index];
for (auto& simple_selector : compound_selector.simple_selectors) {
- if (!matches(simple_selector, style_sheet_for_rule, element, scope, selector_kind))
+ if (!matches(simple_selector, style_sheet_for_rule, element, shadow_host, scope, selector_kind)) {
return false;
+ }
}
// Always matches because we assume that element is already relative to its anchor
if (selector_kind == SelectorKind::Relative && component_list_index == 0)
@@ -700,27 +733,29 @@ static inline bool matches(CSS::Selector const& selector, Optionalparent()) {
+ for (auto ancestor = traverse_up(element, shadow_host); ancestor; ancestor = traverse_up(ancestor, shadow_host)) {
if (!is(*ancestor))
continue;
- if (matches(selector, style_sheet_for_rule, component_list_index - 1, static_cast(*ancestor), scope, selector_kind))
+ if (matches(selector, style_sheet_for_rule, component_list_index - 1, static_cast(*ancestor), shadow_host, scope, selector_kind))
return true;
}
return false;
- case CSS::Selector::Combinator::ImmediateChild:
+ case CSS::Selector::Combinator::ImmediateChild: {
VERIFY(component_list_index != 0);
- if (!element.parent() || !is(*element.parent()))
+ auto parent = traverse_up(element, shadow_host);
+ if (!parent || !parent->is_element())
return false;
- return matches(selector, style_sheet_for_rule, component_list_index - 1, static_cast(*element.parent()), scope, selector_kind);
+ return matches(selector, style_sheet_for_rule, component_list_index - 1, static_cast(*parent), shadow_host, scope, selector_kind);
+ }
case CSS::Selector::Combinator::NextSibling:
VERIFY(component_list_index != 0);
if (auto* sibling = element.previous_element_sibling())
- return matches(selector, style_sheet_for_rule, component_list_index - 1, *sibling, scope, selector_kind);
+ return matches(selector, style_sheet_for_rule, component_list_index - 1, *sibling, shadow_host, scope, selector_kind);
return false;
case CSS::Selector::Combinator::SubsequentSibling:
VERIFY(component_list_index != 0);
for (auto* sibling = element.previous_element_sibling(); sibling; sibling = sibling->previous_element_sibling()) {
- if (matches(selector, style_sheet_for_rule, component_list_index - 1, *sibling, scope, selector_kind))
+ if (matches(selector, style_sheet_for_rule, component_list_index - 1, *sibling, shadow_host, scope, selector_kind))
return true;
}
return false;
@@ -730,17 +765,17 @@ static inline bool matches(CSS::Selector const& selector, Optional style_sheet_for_rule, DOM::Element const& element, Optional pseudo_element, JS::GCPtr scope, SelectorKind selector_kind)
+bool matches(CSS::Selector const& selector, Optional style_sheet_for_rule, DOM::Element const& element, JS::GCPtr shadow_host, Optional pseudo_element, JS::GCPtr scope, SelectorKind selector_kind)
{
VERIFY(!selector.compound_selectors().is_empty());
if (pseudo_element.has_value() && selector.pseudo_element().has_value() && selector.pseudo_element().value().type() != pseudo_element)
return false;
if (!pseudo_element.has_value() && selector.pseudo_element().has_value())
return false;
- return matches(selector, style_sheet_for_rule, selector.compound_selectors().size() - 1, element, scope, selector_kind);
+ return matches(selector, style_sheet_for_rule, selector.compound_selectors().size() - 1, element, shadow_host, scope, selector_kind);
}
-static bool fast_matches_simple_selector(CSS::Selector::SimpleSelector const& simple_selector, Optional style_sheet_for_rule, DOM::Element const& element)
+static bool fast_matches_simple_selector(CSS::Selector::SimpleSelector const& simple_selector, Optional style_sheet_for_rule, DOM::Element const& element, JS::GCPtr shadow_host)
{
switch (simple_selector.type) {
case CSS::Selector::SimpleSelector::Type::Universal:
@@ -760,28 +795,28 @@ static bool fast_matches_simple_selector(CSS::Selector::SimpleSelector const& si
case CSS::Selector::SimpleSelector::Type::Attribute:
return matches_attribute(simple_selector.attribute(), style_sheet_for_rule, element);
case CSS::Selector::SimpleSelector::Type::PseudoClass:
- return matches_pseudo_class(simple_selector.pseudo_class(), style_sheet_for_rule, element, nullptr, SelectorKind::Normal);
+ return matches_pseudo_class(simple_selector.pseudo_class(), style_sheet_for_rule, element, shadow_host, nullptr, SelectorKind::Normal);
default:
VERIFY_NOT_REACHED();
}
}
-static bool fast_matches_compound_selector(CSS::Selector::CompoundSelector const& compound_selector, Optional style_sheet_for_rule, DOM::Element const& element)
+static bool fast_matches_compound_selector(CSS::Selector::CompoundSelector const& compound_selector, Optional style_sheet_for_rule, DOM::Element const& element, JS::GCPtr shadow_host)
{
for (auto const& simple_selector : compound_selector.simple_selectors) {
- if (!fast_matches_simple_selector(simple_selector, style_sheet_for_rule, element))
+ if (!fast_matches_simple_selector(simple_selector, style_sheet_for_rule, element, shadow_host))
return false;
}
return true;
}
-bool fast_matches(CSS::Selector const& selector, Optional style_sheet_for_rule, DOM::Element const& element_to_match)
+bool fast_matches(CSS::Selector const& selector, Optional style_sheet_for_rule, DOM::Element const& element_to_match, JS::GCPtr shadow_host)
{
DOM::Element const* current = &element_to_match;
ssize_t compound_selector_index = selector.compound_selectors().size() - 1;
- if (!fast_matches_compound_selector(selector.compound_selectors().last(), style_sheet_for_rule, *current))
+ if (!fast_matches_compound_selector(selector.compound_selectors().last(), style_sheet_for_rule, *current, shadow_host))
return false;
// NOTE: If we fail after following a child combinator, we may need to backtrack
@@ -804,7 +839,7 @@ bool fast_matches(CSS::Selector const& selector, Optionalparent_element(), compound_selector_index };
compound_selector = &selector.compound_selectors()[--compound_selector_index];
for (current = current->parent_element(); current; current = current->parent_element()) {
- if (fast_matches_compound_selector(*compound_selector, style_sheet_for_rule, *current))
+ if (fast_matches_compound_selector(*compound_selector, style_sheet_for_rule, *current, shadow_host))
break;
}
if (!current)
@@ -815,7 +850,7 @@ bool fast_matches(CSS::Selector const& selector, Optionalparent_element();
if (!current)
return false;
- if (!fast_matches_compound_selector(*compound_selector, style_sheet_for_rule, *current)) {
+ if (!fast_matches_compound_selector(*compound_selector, style_sheet_for_rule, *current, shadow_host)) {
if (backtrack_state.element) {
current = backtrack_state.element;
compound_selector_index = backtrack_state.compound_selector_index;
diff --git a/Userland/Libraries/LibWeb/CSS/SelectorEngine.h b/Userland/Libraries/LibWeb/CSS/SelectorEngine.h
index 0235b4b2c60..28f1e07d74d 100644
--- a/Userland/Libraries/LibWeb/CSS/SelectorEngine.h
+++ b/Userland/Libraries/LibWeb/CSS/SelectorEngine.h
@@ -16,9 +16,9 @@ enum class SelectorKind {
Relative,
};
-bool matches(CSS::Selector const&, Optional style_sheet_for_rule, DOM::Element const&, Optional = {}, JS::GCPtr scope = {}, SelectorKind selector_kind = SelectorKind::Normal);
+bool matches(CSS::Selector const&, Optional style_sheet_for_rule, DOM::Element const&, JS::GCPtr shadow_host, Optional = {}, JS::GCPtr scope = {}, SelectorKind selector_kind = SelectorKind::Normal);
-[[nodiscard]] bool fast_matches(CSS::Selector const&, Optional style_sheet_for_rule, DOM::Element const&);
+[[nodiscard]] bool fast_matches(CSS::Selector const&, Optional style_sheet_for_rule, DOM::Element const&, JS::GCPtr shadow_host);
[[nodiscard]] bool can_use_fast_matches(CSS::Selector const&);
}
diff --git a/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp b/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp
index 8d199871ff4..d6ddfb53bc0 100644
--- a/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp
+++ b/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp
@@ -322,6 +322,12 @@ Vector StyleComputer::collect_matching_rules(DOM::Element const& e
auto const& root_node = element.root();
auto shadow_root = is(root_node) ? static_cast(&root_node) : nullptr;
+ JS::GCPtr shadow_host;
+ if (element.is_shadow_host())
+ shadow_host = element;
+ else if (shadow_root)
+ shadow_host = shadow_root->host();
+
auto const& rule_cache = rule_cache_for_cascade_origin(cascade_origin);
Vector rules_to_run;
@@ -366,22 +372,40 @@ 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
+ // FIXME: This needs to be revised when adding support for the ::shadow selector, as it needs to cross shadow 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)
+
+ // NOTE: Inside shadow trees, we only match rules that are defined in the shadow tree's style sheets.
+ // The key exception is the shadow tree's *shadow host*, which needs to match :host rules from inside the shadow root.
+ // Also note that UA or User style sheets don't have a scope, so they are always relevant.
+ // FIXME: We should reorganize the data so that the document-level StyleComputer doesn't cache *all* rules,
+ // but instead we'd have some kind of "style scope" at the document level, and also one for each shadow root.
+ // Then we could only evaluate rules from the current style scope.
+ bool rule_is_relevant_for_current_scope = rule_root == shadow_root
+ || (element.is_shadow_host() && rule_root == element.shadow_root())
+ || from_user_agent_or_user_stylesheet;
+
+ if (!rule_is_relevant_for_current_scope)
continue;
+ // NOTE: When matching an element against a rule from outside the shadow root's style scope,
+ // we have to pass in null for the shadow host, otherwise combinator traversal will
+ // be confined to the element itself (since it refuses to cross the shadow boundary).
+ auto shadow_host_to_use = shadow_host;
+ if (element.is_shadow_host() && rule_root != element.shadow_root())
+ shadow_host_to_use = nullptr;
+
auto const& selector = rule_to_run.rule->selectors()[rule_to_run.selector_index];
if (should_reject_with_ancestor_filter(*selector))
continue;
if (rule_to_run.can_use_fast_matches) {
- if (!SelectorEngine::fast_matches(selector, *rule_to_run.sheet, element))
+ if (!SelectorEngine::fast_matches(selector, *rule_to_run.sheet, element, shadow_host_to_use))
continue;
} else {
- if (!SelectorEngine::matches(selector, *rule_to_run.sheet, element, pseudo_element))
+ if (!SelectorEngine::matches(selector, *rule_to_run.sheet, element, shadow_host_to_use, pseudo_element))
continue;
}
matching_rules.append(rule_to_run);
diff --git a/Userland/Libraries/LibWeb/DOM/Element.cpp b/Userland/Libraries/LibWeb/DOM/Element.cpp
index e9ae8fd2ce1..6b416fd75b0 100644
--- a/Userland/Libraries/LibWeb/DOM/Element.cpp
+++ b/Userland/Libraries/LibWeb/DOM/Element.cpp
@@ -720,7 +720,7 @@ WebIDL::ExceptionOr Element::matches(StringView selectors) const
// 3. If the result of match a selector against an element, using s, this, and scoping root this, returns success, then return true; otherwise, return false.
auto sel = maybe_selectors.value();
for (auto& s : sel) {
- if (SelectorEngine::matches(s, {}, *this, {}, static_cast(this)))
+ if (SelectorEngine::matches(s, {}, *this, nullptr, {}, static_cast(this)))
return true;
}
return false;
@@ -739,7 +739,7 @@ WebIDL::ExceptionOr Element::closest(StringView selectors)
auto matches_selectors = [this](CSS::SelectorList const& selector_list, Element const* element) {
// 4. For each element in elements, if match a selector against an element, using s, element, and scoping root this, returns success, return element.
for (auto const& selector : selector_list) {
- if (SelectorEngine::matches(selector, {}, *element, {}, this))
+ if (SelectorEngine::matches(selector, {}, *element, nullptr, {}, this))
return true;
}
return false;
diff --git a/Userland/Libraries/LibWeb/DOM/ParentNode.cpp b/Userland/Libraries/LibWeb/DOM/ParentNode.cpp
index 8a017eed4f3..e92fd231282 100644
--- a/Userland/Libraries/LibWeb/DOM/ParentNode.cpp
+++ b/Userland/Libraries/LibWeb/DOM/ParentNode.cpp
@@ -12,6 +12,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -44,7 +45,7 @@ WebIDL::ExceptionOr> ParentNode::query_selector(StringView se
// FIXME: This should be shadow-including. https://drafts.csswg.org/selectors-4/#match-a-selector-against-a-tree
for_each_in_subtree_of_type([&](auto& element) {
for (auto& selector : selectors) {
- if (SelectorEngine::matches(selector, {}, element, {}, this)) {
+ if (SelectorEngine::matches(selector, {}, element, nullptr, {}, this)) {
result = &element;
return TraversalDecision::Break;
}
@@ -76,7 +77,7 @@ WebIDL::ExceptionOr> ParentNode::query_selector_all(S
// FIXME: This should be shadow-including. https://drafts.csswg.org/selectors-4/#match-a-selector-against-a-tree
for_each_in_subtree_of_type([&](auto& element) {
for (auto& selector : selectors) {
- if (SelectorEngine::matches(selector, {}, element, {}, this)) {
+ if (SelectorEngine::matches(selector, {}, element, nullptr, {}, this)) {
elements.append(&element);
}
}