diff --git a/Libraries/LibWeb/CSS/Parser/SelectorParsing.cpp b/Libraries/LibWeb/CSS/Parser/SelectorParsing.cpp index 7db637b1286..02bd813e04b 100644 --- a/Libraries/LibWeb/CSS/Parser/SelectorParsing.cpp +++ b/Libraries/LibWeb/CSS/Parser/SelectorParsing.cpp @@ -430,6 +430,20 @@ Parser::ParseErrorOr Parser::parse_pseudo_simple_selec }; } + // Aliased pseudo-elements behave like their target pseudo-element, but serialize as themselves. So store their + // name like we do for unknown -webkit pseudos below. + if (auto pseudo_element = aliased_pseudo_element_from_string(pseudo_name); pseudo_element.has_value()) { + // :has() is fussy about pseudo-elements inside it + if (m_pseudo_class_context.contains_slow(PseudoClass::Has) && !is_has_allowed_pseudo_element(*pseudo_element)) { + return ParseError::SyntaxError; + } + + return Selector::SimpleSelector { + .type = Selector::SimpleSelector::Type::PseudoElement, + .value = Selector::PseudoElementSelector { pseudo_element.release_value(), pseudo_name.to_string().to_ascii_lowercase() } + }; + } + // 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 diff --git a/Libraries/LibWeb/CSS/PseudoElements.json b/Libraries/LibWeb/CSS/PseudoElements.json index a2ee9eca0c9..29a87a55389 100644 --- a/Libraries/LibWeb/CSS/PseudoElements.json +++ b/Libraries/LibWeb/CSS/PseudoElements.json @@ -1,4 +1,34 @@ { + "-moz-meter-bar": { + "alias-for": "fill" + }, + "-moz-progress-bar": { + "alias-for": "fill" + }, + "-moz-range-progress": { + "alias-for": "fill" + }, + "-moz-range-track": { + "alias-for": "track" + }, + "-moz-range-thumb": { + "alias-for": "thumb" + }, + "-webkit-meter-bar": { + "alias-for": "track" + }, + "-webkit-progress-bar": { + "alias-for": "track" + }, + "-webkit-progress-value": { + "alias-for": "fill" + }, + "-webkit-slider-runnable-track": { + "alias-for": "track" + }, + "-webkit-slider-thumb": { + "alias-for": "thumb" + }, "after": { "spec": "https://drafts.csswg.org/css-pseudo-4/#selectordef-after", "is-generated": true diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateCSSPseudoElement.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateCSSPseudoElement.cpp index 0ad57b7caf1..49038b7df1b 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateCSSPseudoElement.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateCSSPseudoElement.cpp @@ -64,7 +64,11 @@ namespace Web::CSS { enum class PseudoElement : @pseudo_element_underlying_type@ { )~~~"); - pseudo_elements_data.for_each_member([&](auto& name, auto&) { + pseudo_elements_data.for_each_member([&](auto& name, JsonValue const& value) { + auto& pseudo_element = value.as_object(); + if (pseudo_element.has("alias-for"sv)) + return; + auto member_generator = generator.fork(); member_generator.set("name:titlecase", title_casify(name)); @@ -77,6 +81,7 @@ enum class PseudoElement : @pseudo_element_underlying_type@ { }; Optional pseudo_element_from_string(StringView); +Optional aliased_pseudo_element_from_string(StringView); StringView pseudo_element_name(PseudoElement); bool is_has_allowed_pseudo_element(PseudoElement); @@ -119,7 +124,10 @@ Optional pseudo_element_from_string(StringView string) { )~~~"); - pseudo_elements_data.for_each_member([&](auto& name, auto&) { + pseudo_elements_data.for_each_member([&](auto& name, JsonValue const& value) { + auto& pseudo_element = value.as_object(); + if (pseudo_element.has("alias-for"sv)) + return; auto member_generator = generator.fork(); member_generator.set("name", name); member_generator.set("name:titlecase", title_casify(name)); @@ -135,12 +143,40 @@ Optional pseudo_element_from_string(StringView string) return {}; } +Optional aliased_pseudo_element_from_string(StringView string) +{ +)~~~"); + + pseudo_elements_data.for_each_member([&](auto& name, JsonValue const& value) { + auto& pseudo_element = value.as_object(); + auto alias_for = pseudo_element.get_string("alias-for"sv); + if (!alias_for.has_value()) + return; + + auto member_generator = generator.fork(); + member_generator.set("name", name); + member_generator.set("alias:titlecase", title_casify(alias_for.value())); + + member_generator.append(R"~~~( + if (string.equals_ignoring_ascii_case("@name@"sv)) + return PseudoElement::@alias:titlecase@; +)~~~"); + }); + + generator.append(R"~~~( + + return {}; +} + StringView pseudo_element_name(PseudoElement pseudo_element) { switch (pseudo_element) { )~~~"); - pseudo_elements_data.for_each_member([&](auto& name, auto&) { + pseudo_elements_data.for_each_member([&](auto& name, JsonValue const& value) { + auto& pseudo_element = value.as_object(); + if (pseudo_element.has("alias-for"sv)) + return; auto member_generator = generator.fork(); member_generator.set("name", name); member_generator.set("name:titlecase", title_casify(name)); @@ -166,6 +202,8 @@ bool is_has_allowed_pseudo_element(PseudoElement pseudo_element) pseudo_elements_data.for_each_member([&](auto& name, JsonValue const& value) { auto& pseudo_element = value.as_object(); + if (pseudo_element.has("alias-for"sv)) + return; if (!pseudo_element.get_bool("is-allowed-in-has"sv).value_or(false)) return; @@ -191,6 +229,8 @@ Optional to_generated_pseudo_element(PseudoElement pseud pseudo_elements_data.for_each_member([&](auto& name, JsonValue const& value) { auto& pseudo_element = value.as_object(); + if (pseudo_element.has("alias-for"sv)) + return; if (!pseudo_element.get_bool("is-generated"sv).value_or(false)) return; @@ -215,6 +255,8 @@ PseudoElement to_pseudo_element(GeneratedPseudoElement generated_pseudo_element) pseudo_elements_data.for_each_member([&](auto& name, JsonValue const& value) { auto& pseudo_element = value.as_object(); + if (pseudo_element.has("alias-for"sv)) + return; if (!pseudo_element.get_bool("is-generated"sv).value_or(false)) return;