diff options
author | Sam Atkins <atkinssj@gmail.com> | 2021-07-12 16:34:18 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-07-14 13:31:00 +0200 |
commit | 8cae79cc8de78c510f25a4f86ac4da00f5640590 (patch) | |
tree | aadb26fa32cb8694f86b8d38b6b73bac8d5487f7 | |
parent | 4af7d418795233e9457c12ab4fd674b445d35346 (diff) | |
download | serenity-8cae79cc8de78c510f25a4f86ac4da00f5640590.zip |
LibWeb: Add 'PseudoElement' as a CSS SimpleSelector::Type
Same reasoning again! This is the last one.
While I was at it, I added the two remaining CSS2.2 pseudo-elements,
::first-line and ::first-letter. All 4 are handled in the new CSS
parser, including with the compatibility single-colon syntax. I have
not added support to the old parser.
-rw-r--r-- | Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp | 38 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/CSS/Selector.h | 3 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp | 11 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/Dump.cpp | 26 |
4 files changed, 66 insertions, 12 deletions
diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp index 8c03bf3da0..bbf5e49cfb 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -363,10 +363,24 @@ Optional<Selector> Parser::parse_single_selector(TokenStream<T>& tokens, bool is return {}; } - // Ignore for now, otherwise we produce a "false positive" selector - // and apply styles to the element itself, not its pseudo element - if (is_pseudo) - return {}; + if (is_pseudo) { + auto pseudo_name = ((Token)current_value).ident(); + simple_selector.type = Selector::SimpleSelector::Type::PseudoElement; + + if (pseudo_name.equals_ignoring_case("before")) { + simple_selector.pseudo_element = Selector::SimpleSelector::PseudoElement::Before; + } else if (pseudo_name.equals_ignoring_case("after")) { + simple_selector.pseudo_element = Selector::SimpleSelector::PseudoElement::After; + } else if (pseudo_name.equals_ignoring_case("first-line")) { + simple_selector.pseudo_element = Selector::SimpleSelector::PseudoElement::FirstLine; + } else if (pseudo_name.equals_ignoring_case("first-letter")) { + simple_selector.pseudo_element = Selector::SimpleSelector::PseudoElement::FirstLetter; + } else { + return {}; + } + + return simple_selector; + } auto& pseudo_class = simple_selector.pseudo_class; @@ -411,6 +425,22 @@ Optional<Selector> Parser::parse_single_selector(TokenStream<T>& tokens, bool is pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::Enabled; } else if (pseudo_name.equals_ignoring_case("checked")) { pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::Checked; + } else if (pseudo_name.equals_ignoring_case("before")) { + // Single-colon syntax allowed for compatibility. https://www.w3.org/TR/selectors/#pseudo-element-syntax + simple_selector.type = Selector::SimpleSelector::Type::PseudoElement; + simple_selector.pseudo_element = Selector::SimpleSelector::PseudoElement::Before; + } else if (pseudo_name.equals_ignoring_case("after")) { + // See :before + simple_selector.type = Selector::SimpleSelector::Type::PseudoElement; + simple_selector.pseudo_element = Selector::SimpleSelector::PseudoElement::After; + } else if (pseudo_name.equals_ignoring_case("first-line")) { + // See :before + simple_selector.type = Selector::SimpleSelector::Type::PseudoElement; + simple_selector.pseudo_element = Selector::SimpleSelector::PseudoElement::FirstLine; + } else if (pseudo_name.equals_ignoring_case("first-letter")) { + // See :before + simple_selector.type = Selector::SimpleSelector::Type::PseudoElement; + simple_selector.pseudo_element = Selector::SimpleSelector::PseudoElement::FirstLetter; } else { dbgln("Unknown pseudo class: '{}'", pseudo_name); return simple_selector; diff --git a/Userland/Libraries/LibWeb/CSS/Selector.h b/Userland/Libraries/LibWeb/CSS/Selector.h index 2ad7177719..d9cb4c710b 100644 --- a/Userland/Libraries/LibWeb/CSS/Selector.h +++ b/Userland/Libraries/LibWeb/CSS/Selector.h @@ -24,6 +24,7 @@ public: Class, Attribute, PseudoClass, + PseudoElement, }; Type type { Type::Invalid }; @@ -71,6 +72,8 @@ public: None, Before, After, + FirstLine, + FirstLetter, }; PseudoElement pseudo_element { PseudoElement::None }; diff --git a/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp b/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp index 0296aba1d6..f94d8c425d 100644 --- a/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp +++ b/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp @@ -175,14 +175,6 @@ static bool matches_pseudo_class(CSS::Selector::SimpleSelector::PseudoClass cons static bool matches(CSS::Selector::SimpleSelector const& component, DOM::Element const& element) { - switch (component.pseudo_element) { - case CSS::Selector::SimpleSelector::PseudoElement::None: - break; - default: - // FIXME: Implement pseudo-elements. - return false; - } - switch (component.type) { case CSS::Selector::SimpleSelector::Type::Universal: return true; @@ -196,6 +188,9 @@ static bool matches(CSS::Selector::SimpleSelector const& component, DOM::Element return matches_attribute(component.attribute, element); case CSS::Selector::SimpleSelector::Type::PseudoClass: return matches_pseudo_class(component.pseudo_class, element); + case CSS::Selector::SimpleSelector::Type::PseudoElement: + // FIXME: Implement pseudo-elements. + return false; default: VERIFY_NOT_REACHED(); } diff --git a/Userland/Libraries/LibWeb/Dump.cpp b/Userland/Libraries/LibWeb/Dump.cpp index bcbb61ba02..1bb330dca6 100644 --- a/Userland/Libraries/LibWeb/Dump.cpp +++ b/Userland/Libraries/LibWeb/Dump.cpp @@ -320,6 +320,9 @@ void dump_selector(StringBuilder& builder, CSS::Selector const& selector) case CSS::Selector::SimpleSelector::Type::PseudoClass: type_description = "PseudoClass"; break; + case CSS::Selector::SimpleSelector::Type::PseudoElement: + type_description = "PseudoElement"; + break; } builder.appendff("{}:{}", type_description, simple_selector.value); @@ -397,6 +400,29 @@ void dump_selector(StringBuilder& builder, CSS::Selector const& selector) } } + if (simple_selector.type == CSS::Selector::SimpleSelector::Type::PseudoElement) { + char const* pseudo_element_description = ""; + switch (simple_selector.pseudo_element) { + case CSS::Selector::SimpleSelector::PseudoElement::None: + pseudo_element_description = "None"; + break; + case CSS::Selector::SimpleSelector::PseudoElement::Before: + pseudo_element_description = "before"; + break; + case CSS::Selector::SimpleSelector::PseudoElement::After: + pseudo_element_description = "after"; + break; + case CSS::Selector::SimpleSelector::PseudoElement::FirstLine: + pseudo_element_description = "first-line"; + break; + case CSS::Selector::SimpleSelector::PseudoElement::FirstLetter: + pseudo_element_description = "first-letter"; + break; + } + + builder.appendff(" pseudo_element={}", pseudo_element_description); + } + if (simple_selector.type == CSS::Selector::SimpleSelector::Type::Attribute) { char const* attribute_match_type_description = ""; |