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);
}));
}