From ed97946975e1c23ccc2e09dde6d0b0b3617fb2c0 Mon Sep 17 00:00:00 2001 From: Shannon Booth Date: Sun, 10 Dec 2023 22:06:55 +1300 Subject: [PATCH] LibWeb: Support obsolete but required -webkit- CSS parsing quirk As outlined in: https://www.w3.org/TR/selectors-4/#compat We now do not treat unknown webkit pseudo-elements as invalid at parse time, and also support serializing these elements. Fixes: #21959 --- ...ctional-unknown-webkit-pseudo-element.html | 12 ++++++++++++ .../css-unknown-webkit-pseudo-element.html | 12 ++++++++++++ ...wn-webkit-pseudo-element-serialization.txt | 1 + ...n-webkit-pseudo-element-serialization.html | 14 ++++++++++++++ .../LibWeb/CSS/Parser/SelectorParsing.cpp | 14 ++++++++++++++ Userland/Libraries/LibWeb/CSS/Selector.cpp | 4 +++- Userland/Libraries/LibWeb/CSS/Selector.h | 19 +++++++++++++++++-- Userland/Libraries/LibWeb/DOM/Element.h | 4 ++-- .../Libraries/LibWeb/Internals/Inspector.cpp | 2 +- 9 files changed, 76 insertions(+), 6 deletions(-) create mode 100644 Tests/LibWeb/Ref/css-functional-unknown-webkit-pseudo-element.html create mode 100644 Tests/LibWeb/Ref/css-unknown-webkit-pseudo-element.html create mode 100644 Tests/LibWeb/Text/expected/css/unknown-webkit-pseudo-element-serialization.txt create mode 100644 Tests/LibWeb/Text/input/css/unknown-webkit-pseudo-element-serialization.html diff --git a/Tests/LibWeb/Ref/css-functional-unknown-webkit-pseudo-element.html b/Tests/LibWeb/Ref/css-functional-unknown-webkit-pseudo-element.html new file mode 100644 index 0000000000..6d88d2cf0d --- /dev/null +++ b/Tests/LibWeb/Ref/css-functional-unknown-webkit-pseudo-element.html @@ -0,0 +1,12 @@ + + + +
Well, hello friends!
diff --git a/Tests/LibWeb/Ref/css-unknown-webkit-pseudo-element.html b/Tests/LibWeb/Ref/css-unknown-webkit-pseudo-element.html new file mode 100644 index 0000000000..792f7a82c3 --- /dev/null +++ b/Tests/LibWeb/Ref/css-unknown-webkit-pseudo-element.html @@ -0,0 +1,12 @@ + + + +
Well, hello friends!
diff --git a/Tests/LibWeb/Text/expected/css/unknown-webkit-pseudo-element-serialization.txt b/Tests/LibWeb/Text/expected/css/unknown-webkit-pseudo-element-serialization.txt new file mode 100644 index 0000000000..3e2e042e94 --- /dev/null +++ b/Tests/LibWeb/Text/expected/css/unknown-webkit-pseudo-element-serialization.txt @@ -0,0 +1 @@ + .d-none, .oops::-webkit-asdf diff --git a/Tests/LibWeb/Text/input/css/unknown-webkit-pseudo-element-serialization.html b/Tests/LibWeb/Text/input/css/unknown-webkit-pseudo-element-serialization.html new file mode 100644 index 0000000000..4c841656f7 --- /dev/null +++ b/Tests/LibWeb/Text/input/css/unknown-webkit-pseudo-element-serialization.html @@ -0,0 +1,14 @@ +
should not be displayed
+ + diff --git a/Userland/Libraries/LibWeb/CSS/Parser/SelectorParsing.cpp b/Userland/Libraries/LibWeb/CSS/Parser/SelectorParsing.cpp index 27cbf75b5f..053196a73e 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/SelectorParsing.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/SelectorParsing.cpp @@ -10,6 +10,7 @@ #include #include +#include namespace Web::CSS::Parser { @@ -361,6 +362,19 @@ Parser::ParseErrorOr Parser::parse_pseudo_simple_selec }; } + // https://www.w3.org/TR/selectors-4/#compat + // All other pseudo-elements whose names begin with the string “-webkit-” (matched ASCII case-insensitively) + // and that are not functional notations must be treated as valid at parse time. (That is, ::-webkit-asdf is + // valid at parse time, but ::-webkit-jkl() is not.) If they’re not otherwise recognized and supported, they + // must be treated as matching nothing, and are unknown -webkit- pseudo-elements. + if (pseudo_name.starts_with_bytes("-webkit-"sv, CaseSensitivity::CaseInsensitive)) { + return Selector::SimpleSelector { + .type = Selector::SimpleSelector::Type::PseudoElement, + // Unknown -webkit- pseudo-elements must be serialized in ASCII lowercase. + .value = Selector::PseudoElement { Selector::PseudoElement::Type::UnknownWebKit, MUST(Infra::to_ascii_lowercase(pseudo_name.to_string())) }, + }; + } + if (has_ignored_vendor_prefix(pseudo_name)) return ParseError::IncludesIgnoredVendorPrefix; diff --git a/Userland/Libraries/LibWeb/CSS/Selector.cpp b/Userland/Libraries/LibWeb/CSS/Selector.cpp index 48214b2e5a..764ca3fd1a 100644 --- a/Userland/Libraries/LibWeb/CSS/Selector.cpp +++ b/Userland/Libraries/LibWeb/CSS/Selector.cpp @@ -390,8 +390,10 @@ StringView Selector::PseudoElement::name(Selector::PseudoElement::Type pseudo_el return "placeholder"sv; case Selector::PseudoElement::Type::Selection: return "selection"sv; - case Selector::PseudoElement::Type::PseudoElementCount: + case Selector::PseudoElement::Type::KnownPseudoElementCount: break; + case Selector::PseudoElement::Type::UnknownWebKit: + VERIFY_NOT_REACHED(); } VERIFY_NOT_REACHED(); } diff --git a/Userland/Libraries/LibWeb/CSS/Selector.h b/Userland/Libraries/LibWeb/CSS/Selector.h index 15e71989e4..5490f3fd41 100644 --- a/Userland/Libraries/LibWeb/CSS/Selector.h +++ b/Userland/Libraries/LibWeb/CSS/Selector.h @@ -39,15 +39,26 @@ public: Selection, // Keep this last. - PseudoElementCount, + KnownPseudoElementCount, + + // https://www.w3.org/TR/selectors-4/#compat + // NOTE: This is not last as the 'unknown -webkit- pseudo-elements' are not stored as part of any Element. + UnknownWebKit, }; explicit PseudoElement(Type type) : m_type(type) { + VERIFY(type != Type::UnknownWebKit); } - constexpr bool operator==(PseudoElement const&) const = default; + PseudoElement(Type type, String name) + : m_type(type) + , m_name(move(name)) + { + } + + bool operator==(PseudoElement const&) const = default; static Optional from_string(FlyString const&); @@ -55,6 +66,9 @@ public: StringView name() const { + if (!m_name.is_empty()) + return m_name; + return name(m_type); } @@ -62,6 +76,7 @@ public: private: Type m_type; + String m_name; }; struct SimpleSelector { diff --git a/Userland/Libraries/LibWeb/DOM/Element.h b/Userland/Libraries/LibWeb/DOM/Element.h index 92e103913b..6105ccdd2f 100644 --- a/Userland/Libraries/LibWeb/DOM/Element.h +++ b/Userland/Libraries/LibWeb/DOM/Element.h @@ -410,7 +410,7 @@ private: RefPtr m_computed_css_values; HashMap m_custom_properties; - using PseudoElementCustomProperties = Array, to_underlying(CSS::Selector::PseudoElement::Type::PseudoElementCount)>; + using PseudoElementCustomProperties = Array, to_underlying(CSS::Selector::PseudoElement::Type::KnownPseudoElementCount)>; mutable OwnPtr m_pseudo_element_custom_properties; PseudoElementCustomProperties& pseudo_element_custom_properties() const; @@ -421,7 +421,7 @@ private: Optional m_id; - using PseudoElementLayoutNodes = Array, to_underlying(CSS::Selector::PseudoElement::Type::PseudoElementCount)>; + using PseudoElementLayoutNodes = Array, to_underlying(CSS::Selector::PseudoElement::Type::KnownPseudoElementCount)>; OwnPtr m_pseudo_element_nodes; // https://html.spec.whatwg.org/multipage/custom-elements.html#custom-element-reaction-queue diff --git a/Userland/Libraries/LibWeb/Internals/Inspector.cpp b/Userland/Libraries/LibWeb/Internals/Inspector.cpp index 3237234c2e..0b579f1e25 100644 --- a/Userland/Libraries/LibWeb/Internals/Inspector.cpp +++ b/Userland/Libraries/LibWeb/Internals/Inspector.cpp @@ -41,7 +41,7 @@ void Inspector::inspect_dom_node(i32 node_id, Optional const& pseudo_elemen { auto& page = global_object().browsing_context()->page(); page.client().inspector_did_select_dom_node(node_id, pseudo_element.map([](auto value) { - VERIFY(value < to_underlying(Web::CSS::Selector::PseudoElement::Type::PseudoElementCount)); + VERIFY(value < to_underlying(Web::CSS::Selector::PseudoElement::Type::KnownPseudoElementCount)); return static_cast(value); })); }