diff --git a/Libraries/LibWeb/CSS/PseudoElements.json b/Libraries/LibWeb/CSS/PseudoElements.json index 29a87a55389..f2847166fb6 100644 --- a/Libraries/LibWeb/CSS/PseudoElements.json +++ b/Libraries/LibWeb/CSS/PseudoElements.json @@ -50,19 +50,61 @@ "spec": "https://drafts.csswg.org/css-forms-1/#selectordef-fill" }, "first-letter": { - "spec": "https://drafts.csswg.org/css-pseudo-4/#selectordef-first-letter" + "spec": "https://drafts.csswg.org/css-pseudo-4/#selectordef-first-letter", + "property-whitelist": [ + "#font-properties", + "color", + "opacity", + "#background-properties", + "#inline-typesetting-properties", + "#text-decoration-properties", + "#inline-layout-properties", + "#margin-properties", + "#padding-properties", + "#border-properties", + "box-shadow" + ] }, "first-line": { - "spec": "https://drafts.csswg.org/css-pseudo-4/#selectordef-first-line" + "spec": "https://drafts.csswg.org/css-pseudo-4/#selectordef-first-line", + "property-whitelist": [ + "#font-properties", + "color", + "opacity", + "#background-properties", + "#inline-typesetting-properties", + "#text-decoration-properties", + "FIXME: ruby-position", + "#inline-layout-properties" + ] }, "marker": { "spec": "https://drafts.csswg.org/css-pseudo-4/#selectordef-marker" }, "placeholder": { - "spec": "https://drafts.csswg.org/css-pseudo-4/#selectordef-placeholder" + "spec": "https://drafts.csswg.org/css-pseudo-4/#selectordef-placeholder", + "property-whitelist": [ + "#font-properties", + "color", + "opacity", + "#background-properties", + "#inline-typesetting-properties", + "#text-decoration-properties", + "FIXME: ruby-position" + ] }, "selection": { - "spec": "https://drafts.csswg.org/css-pseudo-4/#selectordef-selection" + "spec": "https://drafts.csswg.org/css-pseudo-4/#selectordef-selection", + "property-whitelist": [ + "color", + "background-color", + "#text-decoration-properties", + "text-shadow", + "FIXME: stroke-color", + "FIXME: fill-color", + "stroke-width", + "#custom-properties" + ] }, "thumb": { "spec": "https://drafts.csswg.org/css-forms-1/#selectordef-thumb" diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateCSSPseudoElement.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateCSSPseudoElement.cpp index 49038b7df1b..2a1659ea498 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateCSSPseudoElement.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateCSSPseudoElement.cpp @@ -58,6 +58,7 @@ ErrorOr generate_header_file(JsonObject& pseudo_elements_data, Core::File& #include #include +#include namespace Web::CSS { @@ -85,6 +86,7 @@ Optional aliased_pseudo_element_from_string(StringView); StringView pseudo_element_name(PseudoElement); bool is_has_allowed_pseudo_element(PseudoElement); +bool pseudo_element_supports_property(PseudoElement, PropertyID); enum class GeneratedPseudoElement : @generated_pseudo_element_underlying_type@ { )~~~"); @@ -222,6 +224,245 @@ bool is_has_allowed_pseudo_element(PseudoElement pseudo_element) } } +bool pseudo_element_supports_property(PseudoElement pseudo_element, PropertyID property_id) +{ + switch (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; + auto property_whitelist = pseudo_element.get_array("property-whitelist"sv); + // No whitelist = accept everything, by falling back to the default case. + if (!property_whitelist.has_value()) + return; + + auto member_generator = generator.fork(); + member_generator.set("name:titlecase", title_casify(name)); + member_generator.append(R"~~~( + case PseudoElement::@name:titlecase@: + switch (property_id) { +)~~~"); + + property_whitelist->for_each([&](JsonValue const& entry) { + auto& property = entry.as_string(); + if (property.starts_with_bytes("FIXME:"sv)) + return; + + auto append_property = [&](StringView const& property_name) { + auto property_generator = member_generator.fork(); + property_generator.set("property:titlecase", title_casify(property_name)); + property_generator.appendln(" case PropertyID::@property:titlecase@:"); + }; + + if (!property.starts_with('#')) { + append_property(property); + return; + } + // Categories + // TODO: Maybe define these in data somewhere too? + if (property == "#background-properties"sv) { + // https://drafts.csswg.org/css-backgrounds/#property-index + append_property("background"sv); + append_property("background-attachment"sv); + append_property("background-clip"sv); + append_property("background-color"sv); + append_property("background-image"sv); + append_property("background-origin"sv); + append_property("background-position"sv); + append_property("background-position-x"sv); + append_property("background-position-y"sv); + append_property("background-repeat"sv); + append_property("background-size"sv); + return; + } + if (property == "#border-properties"sv) { + // https://drafts.csswg.org/css-backgrounds/#property-index + append_property("border"sv); + append_property("border-block-end"sv); + append_property("border-block-end-color"sv); + append_property("border-block-end-style"sv); + append_property("border-block-end-width"sv); + append_property("border-block-start"sv); + append_property("border-block-start-color"sv); + append_property("border-block-start-style"sv); + append_property("border-block-start-width"sv); + append_property("border-bottom"sv); + append_property("border-bottom-color"sv); + append_property("border-bottom-left-radius"sv); + append_property("border-bottom-right-radius"sv); + append_property("border-bottom-style"sv); + append_property("border-bottom-width"sv); + append_property("border-color"sv); + append_property("border-inline-end"sv); + append_property("border-inline-end-color"sv); + append_property("border-inline-end-style"sv); + append_property("border-inline-end-width"sv); + append_property("border-inline-start"sv); + append_property("border-inline-start-color"sv); + append_property("border-inline-start-style"sv); + append_property("border-inline-start-width"sv); + append_property("border-left"sv); + append_property("border-left-color"sv); + append_property("border-left-style"sv); + append_property("border-left-width"sv); + append_property("border-radius"sv); + append_property("border-right"sv); + append_property("border-right-color"sv); + append_property("border-right-style"sv); + append_property("border-right-width"sv); + append_property("border-style"sv); + append_property("border-top"sv); + append_property("border-top-color"sv); + append_property("border-top-left-radius"sv); + append_property("border-top-right-radius"sv); + append_property("border-top-style"sv); + append_property("border-top-width"sv); + append_property("border-width"sv); + return; + } + if (property == "#custom-properties"sv) { + append_property("custom"sv); + return; + } + if (property == "#font-properties"sv) { + // https://drafts.csswg.org/css-fonts/#property-index + append_property("font"sv); + append_property("font-family"sv); + append_property("font-feature-settings"sv); + // FIXME: font-kerning + append_property("font-language-override"sv); + // FIXME: font-optical-sizing + // FIXME: font-palette + append_property("font-size"sv); + // FIXME: font-size-adjust + append_property("font-style"sv); + // FIXME: font-synthesis and longhands + append_property("font-variant"sv); + append_property("font-variant-alternates"sv); + append_property("font-variant-caps"sv); + append_property("font-variant-east-asian"sv); + append_property("font-variant-emoji"sv); + append_property("font-variant-ligatures"sv); + append_property("font-variant-numeric"sv); + append_property("font-variant-position"sv); + append_property("font-variation-settings"sv); + append_property("font-weight"sv); + append_property("font-width"sv); + return; + } + if (property == "#inline-layout-properties"sv) { + // https://drafts.csswg.org/css-inline/#property-index + // FIXME: alignment-baseline + // FIXME: baseline-shift + // FIXME: baseline-source + // FIXME: dominant-baseline + // FIXME: initial-letter + // FIXME: initial-letter-align + // FIXME: initial-letter-wrap + // FIXME: inline-sizing + // FIXME: line-edge-fit + append_property("line-height"sv); + // FIXME: text-box + // FIXME: text-box-edge + // FIXME: text-box-trim + append_property("vertical-align"sv); + return; + } + if (property == "#inline-typesetting-properties"sv) { + // https://drafts.csswg.org/css-text-4/#property-index + // FIXME: hanging-punctuation + // FIXME: hyphenate-character + // FIXME: hyphenate-limit-chars + // FIXME: hyphenate-limit-last + // FIXME: hyphenate-limit-lines + // FIXME: hyphenate-limit-zone + // FIXME: hyphens + append_property("letter-spacing"sv); + // FIXME: line-break + // FIXME: line-padding + // FIXME: overflow-wrap + append_property("tab-size"sv); + append_property("text-align"sv); + // FIXME: text-align-all + // FIXME: text-align-last + // FIXME: text-autospace + // FIXME: text-group-align + append_property("text-indent"sv); + append_property("text-justify"sv); + // FIXME: text-spacing + // FIXME: text-spacing-trim + append_property("text-transform"sv); + // FIXME: text-wrap + // FIXME: text-wrap-mode + // FIXME: text-wrap-style + append_property("white-space"sv); + // FIXME: white-space-collapse + // FIXME: white-space-trim + append_property("word-break"sv); + // FIXME: word-space-transform + append_property("word-spacing"sv); + append_property("word-wrap"sv); + // FIXME: wrap-after + // FIXME: wrap-before + // FIXME: wrap-inside + return; + } + if (property == "#margin-properties"sv) { + append_property("margin"sv); + append_property("margin-block"sv); + append_property("margin-block-end"sv); + append_property("margin-block-start"sv); + append_property("margin-bottom"sv); + append_property("margin-inline"sv); + append_property("margin-inline-end"sv); + append_property("margin-inline-start"sv); + append_property("margin-left"sv); + append_property("margin-right"sv); + append_property("margin-top"sv); + return; + } + if (property == "#padding-properties"sv) { + append_property("padding"sv); + append_property("padding-block"sv); + append_property("padding-block-end"sv); + append_property("padding-block-start"sv); + append_property("padding-bottom"sv); + append_property("padding-inline"sv); + append_property("padding-inline-end"sv); + append_property("padding-inline-start"sv); + append_property("padding-left"sv); + append_property("padding-right"sv); + append_property("padding-top"sv); + return; + } + if (property == "#text-decoration-properties"sv) { + append_property("text-decoration"sv); + append_property("text-decoration-color"sv); + append_property("text-decoration-line"sv); + append_property("text-decoration-style"sv); + append_property("text-decoration-thickness"sv); + return; + } + outln("Error: Unrecognized property group name '{}' in {}", property, name); + exit(1); + }); + + member_generator.append(R"~~~( + return true; + default: + return false; + } +)~~~"); + }); + + generator.append(R"~~~( + default: + return true; + } +} + Optional to_generated_pseudo_element(PseudoElement pseudo_element) { switch (pseudo_element) {