summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
authorSam Atkins <atkinssj@serenityos.org>2022-03-17 15:28:42 +0000
committerAndreas Kling <kling@serenityos.org>2022-03-18 11:34:02 +0100
commitc148ed50bb61df0d5109a91fb6a9de03631d3e88 (patch)
tree73cbb21c38a4561f84f9f525c75ca714cc5c2611 /Userland
parent88d218721b90db13bed3b6ac3a79f689da8b3c2d (diff)
downloadserenity-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.css11
-rw-r--r--Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp19
-rw-r--r--Userland/Libraries/LibWeb/CSS/Selector.cpp7
-rw-r--r--Userland/Libraries/LibWeb/CSS/Selector.h5
-rw-r--r--Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp8
-rw-r--r--Userland/Libraries/LibWeb/Dump.cpp8
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)