diff options
author | Sam Atkins <atkinssj@serenityos.org> | 2022-03-17 15:28:42 +0000 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-03-18 11:34:02 +0100 |
commit | c148ed50bb61df0d5109a91fb6a9de03631d3e88 (patch) | |
tree | 73cbb21c38a4561f84f9f525c75ca714cc5c2611 /Userland | |
parent | 88d218721b90db13bed3b6ac3a79f689da8b3c2d (diff) | |
download | serenity-c148ed50bb61df0d5109a91fb6a9de03631d3e88.zip |
LibWeb: Implement the :is() selector
This lets us finally get rid of a FIXME in the default style sheet. :^)
Diffstat (limited to 'Userland')
-rw-r--r-- | Userland/Libraries/LibWeb/CSS/Default.css | 11 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp | 19 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/CSS/Selector.cpp | 7 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/CSS/Selector.h | 5 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp | 8 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/Dump.cpp | 8 |
6 files changed, 37 insertions, 21 deletions
diff --git a/Userland/Libraries/LibWeb/CSS/Default.css b/Userland/Libraries/LibWeb/CSS/Default.css index fbdfff0386..f66dc9f372 100644 --- a/Userland/Libraries/LibWeb/CSS/Default.css +++ b/Userland/Libraries/LibWeb/CSS/Default.css @@ -213,18 +213,11 @@ ol { list-style-type: decimal; } -/* FIXME: Implement these using :is() :^) */ -/* :is(ul, ol) ul */ -ul ul, -ol ul { +:is(ul, ol) ul { list-style-type: circle; } -/* :is(ul, ol) :is(ul, ol) ul */ -ul ul ul, -ol ul ul, -ul ol ul, -ol ol ul { +:is(ul, ol) :is(ul, ol) ul { list-style-type: square; } diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp index 411dcb7e1e..134228c16b 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -584,7 +584,14 @@ Result<Selector::SimpleSelector, Parser::ParsingResult> Parser::parse_simple_sel }; auto& pseudo_function = pseudo_class_token.function(); - if (pseudo_function.name().equals_ignoring_case("not")) { + if (pseudo_function.name().equals_ignoring_case("is"sv)) { + simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::Is; + auto function_token_stream = TokenStream(pseudo_function.values()); + auto is_selector = 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(); + } 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()); auto not_selector = parse_a_selector_list(function_token_stream); @@ -592,20 +599,20 @@ Result<Selector::SimpleSelector, Parser::ParsingResult> Parser::parse_simple_sel dbgln_if(CSS_PARSER_DEBUG, "Invalid selector in :not() clause"); return ParsingResult::SyntaxError; } - simple_selector.pseudo_class.not_selector = not_selector.release_value(); - } else if (pseudo_function.name().equals_ignoring_case("nth-child")) { + simple_selector.pseudo_class.argument_selector_list = not_selector.release_value(); + } else if (pseudo_function.name().equals_ignoring_case("nth-child"sv)) { simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::NthChild; if (!parse_nth_child_pattern(simple_selector, pseudo_function)) return ParsingResult::SyntaxError; - } else if (pseudo_function.name().equals_ignoring_case("nth-last-child")) { + } else if (pseudo_function.name().equals_ignoring_case("nth-last-child"sv)) { simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::NthLastChild; if (!parse_nth_child_pattern(simple_selector, pseudo_function)) return ParsingResult::SyntaxError; - } else if (pseudo_function.name().equals_ignoring_case("nth-of-type")) { + } else if (pseudo_function.name().equals_ignoring_case("nth-of-type"sv)) { simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::NthOfType; if (!parse_nth_child_pattern(simple_selector, pseudo_function)) return ParsingResult::SyntaxError; - } else if (pseudo_function.name().equals_ignoring_case("nth-last-of-type")) { + } else if (pseudo_function.name().equals_ignoring_case("nth-last-of-type"sv)) { simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::NthLastOfType; if (!parse_nth_child_pattern(simple_selector, pseudo_function)) return ParsingResult::SyntaxError; diff --git a/Userland/Libraries/LibWeb/CSS/Selector.cpp b/Userland/Libraries/LibWeb/CSS/Selector.cpp index c2e7a8ca2e..85dc1a3b07 100644 --- a/Userland/Libraries/LibWeb/CSS/Selector.cpp +++ b/Userland/Libraries/LibWeb/CSS/Selector.cpp @@ -158,6 +158,7 @@ String Selector::SimpleSelector::serialize() const case Selector::SimpleSelector::PseudoClass::Type::NthChild: case Selector::SimpleSelector::PseudoClass::Type::NthLastChild: case Selector::SimpleSelector::PseudoClass::Type::Not: + case Selector::SimpleSelector::PseudoClass::Type::Is: // 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(':'); @@ -167,9 +168,11 @@ String Selector::SimpleSelector::serialize() const || pseudo_class.type == Selector::SimpleSelector::PseudoClass::Type::NthLastChild) { // The result of serializing the value using the rules to serialize an <an+b> value. s.append(pseudo_class.nth_child_pattern.serialize()); - } else if (pseudo_class.type == Selector::SimpleSelector::PseudoClass::Type::Not) { + } else if (pseudo_class.type == Selector::SimpleSelector::PseudoClass::Type::Not + || pseudo_class.type == Selector::SimpleSelector::PseudoClass::Type::Is) { // The result of serializing the value using the rules for serializing a group of selectors. - s.append(serialize_a_group_of_selectors(pseudo_class.not_selector)); + // NOTE: `:is()` isn'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(')'); break; diff --git a/Userland/Libraries/LibWeb/CSS/Selector.h b/Userland/Libraries/LibWeb/CSS/Selector.h index cbc8a874f0..57a2ee4827 100644 --- a/Userland/Libraries/LibWeb/CSS/Selector.h +++ b/Userland/Libraries/LibWeb/CSS/Selector.h @@ -75,6 +75,7 @@ public: Disabled, Enabled, Checked, + Is, Not, Active, }; @@ -84,7 +85,7 @@ public: // Only used when "pseudo_class" is "NthChild" or "NthLastChild". ANPlusBPattern nth_child_pattern; - SelectorList not_selector {}; + SelectorList argument_selector_list {}; }; PseudoClass pseudo_class {}; PseudoElement pseudo_element { PseudoElement::None }; @@ -211,6 +212,8 @@ constexpr StringView pseudo_class_name(Selector::SimpleSelector::PseudoClass::Ty return "nth-child"sv; case Selector::SimpleSelector::PseudoClass::Type::NthLastChild: return "nth-last-child"sv; + case Selector::SimpleSelector::PseudoClass::Type::Is: + return "is"sv; case Selector::SimpleSelector::PseudoClass::Type::Not: return "not"sv; case Selector::SimpleSelector::PseudoClass::Type::None: diff --git a/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp b/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp index ad031dd614..c841aa4f6a 100644 --- a/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp +++ b/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp @@ -154,8 +154,14 @@ static inline bool matches_pseudo_class(CSS::Selector::SimpleSelector::PseudoCla return true; case CSS::Selector::SimpleSelector::PseudoClass::Type::Checked: return matches_checked_pseudo_class(element); + case CSS::Selector::SimpleSelector::PseudoClass::Type::Is: + for (auto& selector : pseudo_class.argument_selector_list) { + if (matches(selector, element)) + return true; + } + return false; case CSS::Selector::SimpleSelector::PseudoClass::Type::Not: - for (auto& selector : pseudo_class.not_selector) { + for (auto& selector : pseudo_class.argument_selector_list) { if (matches(selector, element)) return false; } diff --git a/Userland/Libraries/LibWeb/Dump.cpp b/Userland/Libraries/LibWeb/Dump.cpp index b7c2c61ab8..62d68c231a 100644 --- a/Userland/Libraries/LibWeb/Dump.cpp +++ b/Userland/Libraries/LibWeb/Dump.cpp @@ -430,12 +430,16 @@ void dump_selector(StringBuilder& builder, CSS::Selector const& selector) case CSS::Selector::SimpleSelector::PseudoClass::Type::Not: pseudo_class_description = "Not"; break; + case CSS::Selector::SimpleSelector::PseudoClass::Type::Is: + pseudo_class_description = "Is"; + break; } builder.appendff(" pseudo_class={}", pseudo_class_description); - if (pseudo_class.type == CSS::Selector::SimpleSelector::PseudoClass::Type::Not) { + if (pseudo_class.type == CSS::Selector::SimpleSelector::PseudoClass::Type::Not + || pseudo_class.type == CSS::Selector::SimpleSelector::PseudoClass::Type::Is) { builder.append("(["); - for (auto& selector : pseudo_class.not_selector) + for (auto& selector : pseudo_class.argument_selector_list) dump_selector(builder, selector); builder.append("])"); } else if ((pseudo_class.type == CSS::Selector::SimpleSelector::PseudoClass::Type::NthChild) |