From 993653317c14f3c6bbf02b70b710658a90e1ab27 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Thu, 17 Mar 2022 16:13:13 +0000 Subject: [PATCH] LibWeb: Implement the :where() selector This is identical to :is() except for specificity, so we can use the same code paths. :^) --- Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp | 14 +++++++++----- Userland/Libraries/LibWeb/CSS/Selector.cpp | 6 ++++-- Userland/Libraries/LibWeb/CSS/Selector.h | 3 +++ Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp | 1 + Userland/Libraries/LibWeb/Dump.cpp | 6 +++++- 5 files changed, 22 insertions(+), 8 deletions(-) diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp index 134228c16b..73a1a46fe3 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -584,13 +584,17 @@ Result Parser::parse_simple_sel }; auto& pseudo_function = pseudo_class_token.function(); - if (pseudo_function.name().equals_ignoring_case("is"sv)) { - simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::Is; + if (pseudo_function.name().equals_ignoring_case("is"sv) + || pseudo_function.name().equals_ignoring_case("where"sv)) { + + simple_selector.pseudo_class.type = pseudo_function.name().equals_ignoring_case("is"sv) + ? Selector::SimpleSelector::PseudoClass::Type::Is + : Selector::SimpleSelector::PseudoClass::Type::Where; auto function_token_stream = TokenStream(pseudo_function.values()); - auto is_selector = parse_a_selector_list(function_token_stream, SelectorParsingMode::Forgiving); + auto argument_selector_list = parse_a_selector_list(function_token_stream, SelectorParsingMode::Forgiving); // NOTE: Because it's forgiving, even complete garbage will parse OK as an empty selector-list. - VERIFY(!is_selector.is_error()); - simple_selector.pseudo_class.argument_selector_list = is_selector.release_value(); + VERIFY(!argument_selector_list.is_error()); + simple_selector.pseudo_class.argument_selector_list = argument_selector_list.release_value(); } else if (pseudo_function.name().equals_ignoring_case("not"sv)) { simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::Not; auto function_token_stream = TokenStream(pseudo_function.values()); diff --git a/Userland/Libraries/LibWeb/CSS/Selector.cpp b/Userland/Libraries/LibWeb/CSS/Selector.cpp index 85dc1a3b07..24e7ed97c8 100644 --- a/Userland/Libraries/LibWeb/CSS/Selector.cpp +++ b/Userland/Libraries/LibWeb/CSS/Selector.cpp @@ -159,6 +159,7 @@ String Selector::SimpleSelector::serialize() const case Selector::SimpleSelector::PseudoClass::Type::NthLastChild: case Selector::SimpleSelector::PseudoClass::Type::Not: case Selector::SimpleSelector::PseudoClass::Type::Is: + case Selector::SimpleSelector::PseudoClass::Type::Where: // Otherwise, append ":" (U+003A), followed by the name of the pseudo-class, followed by "(" (U+0028), // followed by the value of the pseudo-class argument(s) determined as per below, followed by ")" (U+0029), to s. s.append(':'); @@ -169,9 +170,10 @@ String Selector::SimpleSelector::serialize() const // The result of serializing the value using the rules to serialize an value. s.append(pseudo_class.nth_child_pattern.serialize()); } else if (pseudo_class.type == Selector::SimpleSelector::PseudoClass::Type::Not - || pseudo_class.type == Selector::SimpleSelector::PseudoClass::Type::Is) { + || pseudo_class.type == Selector::SimpleSelector::PseudoClass::Type::Is + || pseudo_class.type == Selector::SimpleSelector::PseudoClass::Type::Where) { // The result of serializing the value using the rules for serializing a group of selectors. - // NOTE: `:is()` isn't in the spec for this yet, but it should be! + // NOTE: `:is()` and `:where()` aren't in the spec for this yet, but it should be! s.append(serialize_a_group_of_selectors(pseudo_class.argument_selector_list)); } s.append(')'); diff --git a/Userland/Libraries/LibWeb/CSS/Selector.h b/Userland/Libraries/LibWeb/CSS/Selector.h index 57a2ee4827..773b37f8cc 100644 --- a/Userland/Libraries/LibWeb/CSS/Selector.h +++ b/Userland/Libraries/LibWeb/CSS/Selector.h @@ -77,6 +77,7 @@ public: Checked, Is, Not, + Where, Active, }; Type type { Type::None }; @@ -216,6 +217,8 @@ constexpr StringView pseudo_class_name(Selector::SimpleSelector::PseudoClass::Ty return "is"sv; case Selector::SimpleSelector::PseudoClass::Type::Not: return "not"sv; + case Selector::SimpleSelector::PseudoClass::Type::Where: + return "where"sv; case Selector::SimpleSelector::PseudoClass::Type::None: break; } diff --git a/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp b/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp index c841aa4f6a..bcd0707e2f 100644 --- a/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp +++ b/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp @@ -155,6 +155,7 @@ static inline bool matches_pseudo_class(CSS::Selector::SimpleSelector::PseudoCla case CSS::Selector::SimpleSelector::PseudoClass::Type::Checked: return matches_checked_pseudo_class(element); 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)) return true; diff --git a/Userland/Libraries/LibWeb/Dump.cpp b/Userland/Libraries/LibWeb/Dump.cpp index 62d68c231a..7916a996d3 100644 --- a/Userland/Libraries/LibWeb/Dump.cpp +++ b/Userland/Libraries/LibWeb/Dump.cpp @@ -433,11 +433,15 @@ void dump_selector(StringBuilder& builder, CSS::Selector const& selector) case CSS::Selector::SimpleSelector::PseudoClass::Type::Is: pseudo_class_description = "Is"; break; + case CSS::Selector::SimpleSelector::PseudoClass::Type::Where: + pseudo_class_description = "Where"; + break; } builder.appendff(" pseudo_class={}", pseudo_class_description); if (pseudo_class.type == CSS::Selector::SimpleSelector::PseudoClass::Type::Not - || pseudo_class.type == CSS::Selector::SimpleSelector::PseudoClass::Type::Is) { + || pseudo_class.type == CSS::Selector::SimpleSelector::PseudoClass::Type::Is + || pseudo_class.type == CSS::Selector::SimpleSelector::PseudoClass::Type::Where) { builder.append("(["); for (auto& selector : pseudo_class.argument_selector_list) dump_selector(builder, selector);