From 1858f0688162c26fff235277add702821b5fb961 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Tue, 8 Aug 2023 15:11:48 +0100 Subject: [PATCH] LibWeb: Add namespaces to Universal and TagName selectors --- .../css-namespace-tag-name-selector.txt | 41 ++++++++++ .../css-namespace-universal-selector.txt | 22 ++++++ .../css-namespace-tag-name-selector.html | 23 ++++++ .../css-namespace-universal-selector.html | 21 +++++ .../Libraries/LibWeb/CSS/Parser/Parser.cpp | 27 ++++--- Userland/Libraries/LibWeb/CSS/Selector.cpp | 44 ++++++++--- Userland/Libraries/LibWeb/CSS/Selector.h | 4 +- .../Libraries/LibWeb/CSS/SelectorEngine.cpp | 77 ++++++++++++++----- .../Libraries/LibWeb/CSS/SelectorEngine.h | 2 +- .../Libraries/LibWeb/CSS/StyleComputer.cpp | 4 +- Userland/Libraries/LibWeb/DOM/Element.cpp | 4 +- Userland/Libraries/LibWeb/DOM/ParentNode.cpp | 4 +- Userland/Libraries/LibWeb/Dump.cpp | 21 ++++- 13 files changed, 245 insertions(+), 49 deletions(-) create mode 100644 Tests/LibWeb/Layout/expected/css-namespace-tag-name-selector.txt create mode 100644 Tests/LibWeb/Layout/expected/css-namespace-universal-selector.txt create mode 100644 Tests/LibWeb/Layout/input/css-namespace-tag-name-selector.html create mode 100644 Tests/LibWeb/Layout/input/css-namespace-universal-selector.html diff --git a/Tests/LibWeb/Layout/expected/css-namespace-tag-name-selector.txt b/Tests/LibWeb/Layout/expected/css-namespace-tag-name-selector.txt new file mode 100644 index 0000000000..0c5b96578f --- /dev/null +++ b/Tests/LibWeb/Layout/expected/css-namespace-tag-name-selector.txt @@ -0,0 +1,41 @@ +Viewport <#document> at (0,0) content-size 800x600 children: not-inline + BlockContainer at (0,0) content-size 800x600 [BFC] children: not-inline + BlockContainer at (8,8) content-size 784x207.3125 children: not-inline + BlockContainer <(anonymous)> at (8,8) content-size 784x161.65625 children: inline + line 0 width: 413.453125, height: 161.65625, bottom: 161.65625, baseline: 152 + frag 0 from SVGSVGBox start: 0, length: 0, rect: [9,9 300x150] + frag 1 from TextNode start: 0, length: 1, rect: [310,146 8x17.46875] + " " + frag 2 from TextNode start: 0, length: 5, rect: [320,126 99.453125x43.671875] + "Hello" + SVGSVGBox at (9,9) content-size 300x150 [SVG] children: inline + InlineNode + SVGTextBox at (9,9) content-size 0x0 children: inline + TextNode <#text> + TextNode <#text> + InlineNode + InlineNode + TextNode <#text> + TextNode <#text> + BlockContainer
at (9,170.65625) content-size 782x43.65625 children: inline + line 0 width: 101.453125, height: 43.65625, bottom: 43.65625, baseline: 33.828125 + frag 0 from TextNode start: 0, length: 5, rect: [10,170.65625 99.453125x43.671875] + "Hello" + InlineNode + TextNode <#text> + BlockContainer <(anonymous)> at (8,215.3125) content-size 784x0 children: inline + TextNode <#text> + +PaintableWithLines (Viewport<#document>) [0,0 800x600] + PaintableWithLines (BlockContainer) [0,0 800x600] + PaintableWithLines (BlockContainer) [8,8 784x207.3125] + PaintableWithLines (BlockContainer(anonymous)) [8,8 784x161.65625] overflow: [8,8 784x161.671875] + SVGSVGPaintable (SVGSVGBox) [8,8 302x152] + TextPaintable (TextNode<#text>) + InlinePaintable (InlineNode) + InlinePaintable (InlineNode) + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
) [8,169.65625 784x45.65625] overflow: [9,170.65625 782x43.671875] + InlinePaintable (InlineNode) + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer(anonymous)) [8,215.3125 784x0] diff --git a/Tests/LibWeb/Layout/expected/css-namespace-universal-selector.txt b/Tests/LibWeb/Layout/expected/css-namespace-universal-selector.txt new file mode 100644 index 0000000000..f0f5922efb --- /dev/null +++ b/Tests/LibWeb/Layout/expected/css-namespace-universal-selector.txt @@ -0,0 +1,22 @@ +Viewport <#document> at (0,0) content-size 800x600 children: not-inline + BlockContainer at (0,0) content-size 800x600 [BFC] children: not-inline + BlockContainer at (8,8) content-size 784x324 children: not-inline + SVGSVGBox at (18,18) content-size 100x100 [SVG] children: not-inline + BlockContainer <(anonymous)> at (8,128) content-size 784x0 children: inline + TextNode <#text> + BlockContainer at (9,129) content-size 100x100 children: not-inline + BlockContainer <(anonymous)> at (8,230) content-size 784x0 children: inline + TextNode <#text> + BlockContainer
at (9,231) content-size 100x100 children: not-inline + BlockContainer <(anonymous)> at (8,332) content-size 784x0 children: inline + TextNode <#text> + +PaintableWithLines (Viewport<#document>) [0,0 800x600] + PaintableWithLines (BlockContainer) [0,0 800x600] + PaintableWithLines (BlockContainer) [8,8 784x324] + SVGSVGPaintable (SVGSVGBox) [8,8 120x120] + PaintableWithLines (BlockContainer(anonymous)) [8,128 784x0] + PaintableWithLines (BlockContainer) [8,128 102x102] + PaintableWithLines (BlockContainer(anonymous)) [8,230 784x0] + PaintableWithLines (BlockContainer
) [8,230 102x102] + PaintableWithLines (BlockContainer(anonymous)) [8,332 784x0] diff --git a/Tests/LibWeb/Layout/input/css-namespace-tag-name-selector.html b/Tests/LibWeb/Layout/input/css-namespace-tag-name-selector.html new file mode 100644 index 0000000000..3a5a1d17f8 --- /dev/null +++ b/Tests/LibWeb/Layout/input/css-namespace-tag-name-selector.html @@ -0,0 +1,23 @@ + +Hello +Hello + diff --git a/Tests/LibWeb/Layout/input/css-namespace-universal-selector.html b/Tests/LibWeb/Layout/input/css-namespace-universal-selector.html new file mode 100644 index 0000000000..3f1a5d352c --- /dev/null +++ b/Tests/LibWeb/Layout/input/css-namespace-universal-selector.html @@ -0,0 +1,21 @@ + + + +
diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp index 341bec0672..bfe9df5fe4 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -740,15 +740,28 @@ Parser::ParseErrorOr> Parser::parse_simple_se if (peek_token_ends_selector()) return Optional {}; + // Handle universal and tag-name types together, since both can be namespaced + if (auto qualified_name = parse_selector_qualified_name(tokens, AllowWildcardName::Yes); qualified_name.has_value()) { + if (qualified_name->name.name == "*"sv) { + return Selector::SimpleSelector { + .type = Selector::SimpleSelector::Type::Universal, + .value = qualified_name.release_value(), + }; + } + return Selector::SimpleSelector { + .type = Selector::SimpleSelector::Type::TagName, + .value = qualified_name.release_value(), + }; + } + auto const& first_value = tokens.next_token(); if (first_value.is(Token::Type::Delim)) { u32 delim = first_value.token().delim(); switch (delim) { case '*': - return Selector::SimpleSelector { - .type = Selector::SimpleSelector::Type::Universal - }; + // Handled already + VERIFY_NOT_REACHED(); case '.': { if (peek_token_ends_selector()) return ParseError::SyntaxError; @@ -787,13 +800,7 @@ Parser::ParseErrorOr> Parser::parse_simple_se .value = Selector::SimpleSelector::Name { FlyString::from_utf8(first_value.token().hash_value()).release_value_but_fixme_should_propagate_errors() } }; } - if (first_value.is(Token::Type::Ident)) { - return Selector::SimpleSelector { - .type = Selector::SimpleSelector::Type::TagName, - // FIXME: XML requires case-sensitivity for identifiers, while HTML does not. As such, this should be reworked if XML support is added. - .value = Selector::SimpleSelector::Name { FlyString::from_deprecated_fly_string(first_value.token().ident().to_lowercase_string()).release_value_but_fixme_should_propagate_errors() } - }; - } + if (first_value.is_block() && first_value.block().is_square()) return TRY(parse_attribute_simple_selector(first_value)); diff --git a/Userland/Libraries/LibWeb/CSS/Selector.cpp b/Userland/Libraries/LibWeb/CSS/Selector.cpp index d82f422e7d..1daa3fcc5a 100644 --- a/Userland/Libraries/LibWeb/CSS/Selector.cpp +++ b/Userland/Libraries/LibWeb/CSS/Selector.cpp @@ -124,17 +124,31 @@ ErrorOr Selector::SimpleSelector::serialize() const StringBuilder s; switch (type) { case Selector::SimpleSelector::Type::TagName: - case Selector::SimpleSelector::Type::Universal: - // FIXME: 1. If the namespace prefix maps to a namespace that is not the default namespace and is not the null namespace (not in a namespace) append the serialization of the namespace prefix as an identifier, followed by a "|" (U+007C) to s. - // FIXME: 2. If the namespace prefix maps to a namespace that is the null namespace (not in a namespace) append "|" (U+007C) to s. - // 3. If this is a type selector append the serialization of the element name as an identifier to s. - if (type == Selector::SimpleSelector::Type::TagName) { - TRY(serialize_an_identifier(s, name())); + case Selector::SimpleSelector::Type::Universal: { + auto qualified_name = this->qualified_name(); + // 1. If the namespace prefix maps to a namespace that is not the default namespace and is not the null + // namespace (not in a namespace) append the serialization of the namespace prefix as an identifier, + // followed by a "|" (U+007C) to s. + if (qualified_name.namespace_type == QualifiedName::NamespaceType::Named) { + TRY(serialize_an_identifier(s, qualified_name.namespace_)); + TRY(s.try_append('|')); } + + // 2. If the namespace prefix maps to a namespace that is the null namespace (not in a namespace) + // append "|" (U+007C) to s. + if (qualified_name.namespace_type == QualifiedName::NamespaceType::None) + TRY(s.try_append('|')); + + // 3. If this is a type selector append the serialization of the element name as an identifier to s. + if (type == Selector::SimpleSelector::Type::TagName) + TRY(serialize_an_identifier(s, qualified_name.name.name)); + // 4. If this is a universal selector append "*" (U+002A) to s. if (type == Selector::SimpleSelector::Type::Universal) TRY(s.try_append('*')); + break; + } case Selector::SimpleSelector::Type::Attribute: { auto& attribute = this->attribute(); @@ -300,11 +314,23 @@ ErrorOr Selector::serialize() const && compound_selector.simple_selectors.first().type == Selector::SimpleSelector::Type::Universal) { TRY(s.try_append(TRY(compound_selector.simple_selectors.first().serialize()))); } - // 2. Otherwise, for each simple selector in the compound selectors... - // FIXME: ...that is not a universal selector of which the namespace prefix maps to a namespace that is not the default namespace... - // ...serialize the simple selector and append the result to s. + // 2. Otherwise, for each simple selector in the compound selectors that is not a universal selector + // of which the namespace prefix maps to a namespace that is not the default namespace + // serialize the simple selector and append the result to s. else { for (auto& simple_selector : compound_selector.simple_selectors) { + if (simple_selector.type == SimpleSelector::Type::Universal) { + auto qualified_name = simple_selector.qualified_name(); + if (qualified_name.namespace_type == SimpleSelector::QualifiedName::NamespaceType::Default) + continue; + // FIXME: I *think* if we have a namespace prefix that happens to equal the same as the default namespace, + // we also should skip it. But we don't have access to that here. eg: + // + } TRY(s.try_append(TRY(simple_selector.serialize()))); } } diff --git a/Userland/Libraries/LibWeb/CSS/Selector.h b/Userland/Libraries/LibWeb/CSS/Selector.h index 0a4f92caa0..7460c0ec99 100644 --- a/Userland/Libraries/LibWeb/CSS/Selector.h +++ b/Userland/Libraries/LibWeb/CSS/Selector.h @@ -183,7 +183,7 @@ public: }; Type type; - Variant value {}; + Variant value {}; Attribute const& attribute() const { return value.get(); } Attribute& attribute() { return value.get(); } @@ -196,6 +196,8 @@ public: FlyString& name() { return value.get().name; } FlyString const& lowercase_name() const { return value.get().lowercase_name; } FlyString& lowercase_name() { return value.get().lowercase_name; } + QualifiedName const& qualified_name() const { return value.get(); } + QualifiedName& qualified_name() { return value.get(); } ErrorOr serialize() const; }; diff --git a/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp b/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp index 48a8065dd9..2e84bb70b3 100644 --- a/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp +++ b/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp @@ -203,7 +203,7 @@ static inline DOM::Element const* next_sibling_with_same_tag_name(DOM::Element c return nullptr; } -static inline bool matches_pseudo_class(CSS::Selector::SimpleSelector::PseudoClass const& pseudo_class, DOM::Element const& element, JS::GCPtr scope) +static inline bool matches_pseudo_class(CSS::Selector::SimpleSelector::PseudoClass const& pseudo_class, Optional style_sheet_for_rule, DOM::Element const& element, JS::GCPtr scope) { switch (pseudo_class.type) { case CSS::Selector::SimpleSelector::PseudoClass::Type::Link: @@ -280,13 +280,13 @@ static inline bool matches_pseudo_class(CSS::Selector::SimpleSelector::PseudoCla case CSS::Selector::SimpleSelector::PseudoClass::Type::Is: case CSS::Selector::SimpleSelector::PseudoClass::Type::Where: for (auto& selector : pseudo_class.argument_selector_list) { - if (matches(selector, element)) + if (matches(selector, style_sheet_for_rule, element)) return true; } return false; case CSS::Selector::SimpleSelector::PseudoClass::Type::Not: for (auto& selector : pseudo_class.argument_selector_list) { - if (matches(selector, element)) + if (matches(selector, style_sheet_for_rule, element)) return false; } return true; @@ -303,11 +303,11 @@ static inline bool matches_pseudo_class(CSS::Selector::SimpleSelector::PseudoCla if (!parent) return false; - auto matches_selector_list = [](CSS::SelectorList const& list, DOM::Element const& element) { + auto matches_selector_list = [&style_sheet_for_rule](CSS::SelectorList const& list, DOM::Element const& element) { if (list.is_empty()) return true; for (auto const& child_selector : list) { - if (matches(child_selector, element)) { + if (matches(child_selector, style_sheet_for_rule, element)) { return true; } } @@ -426,24 +426,59 @@ static inline bool matches_pseudo_class(CSS::Selector::SimpleSelector::PseudoCla return false; } -static inline bool matches(CSS::Selector::SimpleSelector const& component, DOM::Element const& element, JS::GCPtr scope) +static inline bool matches(CSS::Selector::SimpleSelector const& component, Optional style_sheet_for_rule, DOM::Element const& element, JS::GCPtr scope) { switch (component.type) { case CSS::Selector::SimpleSelector::Type::Universal: - return true; + case CSS::Selector::SimpleSelector::Type::TagName: { + auto qualified_name = component.qualified_name(); + + // Reject if the tag name doesn't match + if (component.type == CSS::Selector::SimpleSelector::Type::TagName) { + // See https://html.spec.whatwg.org/multipage/semantics-other.html#case-sensitivity-of-selectors + if (element.document().document_type() == DOM::Document::Type::HTML) { + if (qualified_name.name.lowercase_name != element.local_name().view()) + return false; + } else if (!Infra::is_ascii_case_insensitive_match(qualified_name.name.name, element.local_name())) { + return false; + } + } + + // Match the namespace + switch (qualified_name.namespace_type) { + case CSS::Selector::SimpleSelector::QualifiedName::NamespaceType::Default: + // "if no default namespace has been declared for selectors, this is equivalent to *|E." + if (!style_sheet_for_rule.has_value() || !style_sheet_for_rule->default_namespace().has_value()) + return true; + // "Otherwise it is equivalent to ns|E where ns is the default namespace." + return element.namespace_() == style_sheet_for_rule->default_namespace(); + case CSS::Selector::SimpleSelector::QualifiedName::NamespaceType::None: + // "elements with name E without a namespace" + return element.namespace_().is_empty(); + case CSS::Selector::SimpleSelector::QualifiedName::NamespaceType::Any: + // "elements with name E in any namespace, including those without a namespace" + return true; + case CSS::Selector::SimpleSelector::QualifiedName::NamespaceType::Named: + // "elements with name E in namespace ns" + // Unrecognized namespace prefixes are invalid, so don't match. + // (We can't detect this at parse time, since a namespace rule may be inserted later.) + // So, if we don't have a context to look up namespaces from, we fail to match. + if (!style_sheet_for_rule.has_value()) + return false; + + auto selector_namespace = style_sheet_for_rule->namespace_uri(qualified_name.namespace_); + return selector_namespace.has_value() && selector_namespace.value() == element.namespace_(); + } + VERIFY_NOT_REACHED(); + } case CSS::Selector::SimpleSelector::Type::Id: return component.name() == element.attribute(HTML::AttributeNames::id).view(); case CSS::Selector::SimpleSelector::Type::Class: return element.has_class(component.name()); - case CSS::Selector::SimpleSelector::Type::TagName: - // See https://html.spec.whatwg.org/multipage/semantics-other.html#case-sensitivity-of-selectors - if (element.document().document_type() == DOM::Document::Type::HTML) - return component.lowercase_name() == element.local_name().view(); - return Infra::is_ascii_case_insensitive_match(component.name(), element.local_name()); case CSS::Selector::SimpleSelector::Type::Attribute: return matches_attribute(component.attribute(), element); case CSS::Selector::SimpleSelector::Type::PseudoClass: - return matches_pseudo_class(component.pseudo_class(), element, scope); + return matches_pseudo_class(component.pseudo_class(), style_sheet_for_rule, element, scope); case CSS::Selector::SimpleSelector::Type::PseudoElement: // Pseudo-element matching/not-matching is handled in the top level matches(). return true; @@ -452,11 +487,11 @@ static inline bool matches(CSS::Selector::SimpleSelector const& component, DOM:: } } -static inline bool matches(CSS::Selector const& selector, int component_list_index, DOM::Element const& element, JS::GCPtr scope) +static inline bool matches(CSS::Selector const& selector, Optional style_sheet_for_rule, int component_list_index, DOM::Element const& element, JS::GCPtr scope) { auto& relative_selector = selector.compound_selectors()[component_list_index]; for (auto& simple_selector : relative_selector.simple_selectors) { - if (!matches(simple_selector, element, scope)) + if (!matches(simple_selector, style_sheet_for_rule, element, scope)) return false; } switch (relative_selector.combinator) { @@ -467,7 +502,7 @@ static inline bool matches(CSS::Selector const& selector, int component_list_ind for (auto* ancestor = element.parent(); ancestor; ancestor = ancestor->parent()) { if (!is(*ancestor)) continue; - if (matches(selector, component_list_index - 1, static_cast(*ancestor), scope)) + if (matches(selector, style_sheet_for_rule, component_list_index - 1, static_cast(*ancestor), scope)) return true; } return false; @@ -475,16 +510,16 @@ static inline bool matches(CSS::Selector const& selector, int component_list_ind VERIFY(component_list_index != 0); if (!element.parent() || !is(*element.parent())) return false; - return matches(selector, component_list_index - 1, static_cast(*element.parent()), scope); + return matches(selector, style_sheet_for_rule, component_list_index - 1, static_cast(*element.parent()), scope); case CSS::Selector::Combinator::NextSibling: VERIFY(component_list_index != 0); if (auto* sibling = element.previous_element_sibling()) - return matches(selector, component_list_index - 1, *sibling, scope); + return matches(selector, style_sheet_for_rule, component_list_index - 1, *sibling, scope); 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, component_list_index - 1, *sibling, scope)) + if (matches(selector, style_sheet_for_rule, component_list_index - 1, *sibling, scope)) return true; } return false; @@ -494,14 +529,14 @@ static inline bool matches(CSS::Selector const& selector, int component_list_ind VERIFY_NOT_REACHED(); } -bool matches(CSS::Selector const& selector, DOM::Element const& element, Optional pseudo_element, JS::GCPtr scope) +bool matches(CSS::Selector const& selector, Optional style_sheet_for_rule, DOM::Element const& element, Optional pseudo_element, JS::GCPtr scope) { VERIFY(!selector.compound_selectors().is_empty()); if (pseudo_element.has_value() && selector.pseudo_element() != pseudo_element) return false; if (!pseudo_element.has_value() && selector.pseudo_element().has_value()) return false; - return matches(selector, selector.compound_selectors().size() - 1, element, scope); + return matches(selector, style_sheet_for_rule, selector.compound_selectors().size() - 1, element, scope); } } diff --git a/Userland/Libraries/LibWeb/CSS/SelectorEngine.h b/Userland/Libraries/LibWeb/CSS/SelectorEngine.h index c92f06a684..7d94bb6e3f 100644 --- a/Userland/Libraries/LibWeb/CSS/SelectorEngine.h +++ b/Userland/Libraries/LibWeb/CSS/SelectorEngine.h @@ -11,6 +11,6 @@ namespace Web::SelectorEngine { -bool matches(CSS::Selector const&, DOM::Element const&, Optional = {}, JS::GCPtr scope = {}); +bool matches(CSS::Selector const&, Optional style_sheet_for_rule, DOM::Element const&, Optional = {}, JS::GCPtr scope = {}); } diff --git a/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp b/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp index 8f12b15924..b3a4687792 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp @@ -267,7 +267,7 @@ Vector StyleComputer::collect_matching_rules(DOM::Element const& e matching_rules.ensure_capacity(rules_to_run.size()); for (auto const& rule_to_run : rules_to_run) { auto const& selector = rule_to_run.rule->selectors()[rule_to_run.selector_index]; - if (SelectorEngine::matches(selector, element, pseudo_element)) + if (SelectorEngine::matches(selector, *rule_to_run.sheet, element, pseudo_element)) matching_rules.append(rule_to_run); } return matching_rules; @@ -2614,7 +2614,7 @@ NonnullOwnPtr StyleComputer::make_rule_cache_for_casca break; } if (simple_selector.type == CSS::Selector::SimpleSelector::Type::TagName) { - rule_cache->rules_by_tag_name.ensure(simple_selector.name()).append(move(matching_rule)); + rule_cache->rules_by_tag_name.ensure(simple_selector.qualified_name().name.lowercase_name).append(move(matching_rule)); ++num_tag_name_rules; added_to_bucket = true; break; diff --git a/Userland/Libraries/LibWeb/DOM/Element.cpp b/Userland/Libraries/LibWeb/DOM/Element.cpp index 7c6b908a24..b308b3b3ca 100644 --- a/Userland/Libraries/LibWeb/DOM/Element.cpp +++ b/Userland/Libraries/LibWeb/DOM/Element.cpp @@ -562,7 +562,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, {}, static_cast(this))) return true; } return false; @@ -581,7 +581,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& selector : selector_list) { - if (!SelectorEngine::matches(selector, *element, {}, this)) + if (!SelectorEngine::matches(selector, {}, *element, {}, this)) return false; } return true; diff --git a/Userland/Libraries/LibWeb/DOM/ParentNode.cpp b/Userland/Libraries/LibWeb/DOM/ParentNode.cpp index de799726fc..ff9acd9936 100644 --- a/Userland/Libraries/LibWeb/DOM/ParentNode.cpp +++ b/Userland/Libraries/LibWeb/DOM/ParentNode.cpp @@ -39,7 +39,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, {}, this)) { result = &element; return IterationDecision::Break; } @@ -71,7 +71,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, {}, this)) { elements.append(&element); } } diff --git a/Userland/Libraries/LibWeb/Dump.cpp b/Userland/Libraries/LibWeb/Dump.cpp index 2b17b67438..6486c017d9 100644 --- a/Userland/Libraries/LibWeb/Dump.cpp +++ b/Userland/Libraries/LibWeb/Dump.cpp @@ -447,8 +447,27 @@ void dump_selector(StringBuilder& builder, CSS::Selector const& selector) builder.appendff("{}:", type_description); // FIXME: This is goofy - if (simple_selector.value.has()) + if (simple_selector.value.has()) { builder.append(simple_selector.name()); + } else if (simple_selector.value.has()) { + auto qualified_name = simple_selector.qualified_name(); + StringView namespace_type; + switch (qualified_name.namespace_type) { + case CSS::Selector::SimpleSelector::QualifiedName::NamespaceType::Default: + namespace_type = "Default"sv; + break; + case CSS::Selector::SimpleSelector::QualifiedName::NamespaceType::None: + namespace_type = "None"sv; + break; + case CSS::Selector::SimpleSelector::QualifiedName::NamespaceType::Any: + namespace_type = "Any"sv; + break; + case CSS::Selector::SimpleSelector::QualifiedName::NamespaceType::Named: + namespace_type = "Named"sv; + break; + } + builder.appendff(" [NamespaceType={}, Namespace='{}', Name='{}']", namespace_type, qualified_name.namespace_, qualified_name.name.name); + } if (simple_selector.type == CSS::Selector::SimpleSelector::Type::PseudoClass) { auto const& pseudo_class = simple_selector.pseudo_class();