diff --git a/Documentation/CSSGeneratedFiles.md b/Documentation/CSSGeneratedFiles.md index 6034386ead8..ee5557aacad 100644 --- a/Documentation/CSSGeneratedFiles.md +++ b/Documentation/CSSGeneratedFiles.md @@ -262,7 +262,9 @@ Each entry has the following properties: | `alias-for` | No | Nothing | Use to specify that this should be treated as an alias for the named pseudo-element. | | `function-syntax` | No | Nothing | Syntax for the function arguments if this is a function-type pseudo-element. Copied directly from the spec. | | `is-allowed-in-has` | No | `false` | Whether this is a [`:has`-allowed pseudo-element](https://drafts.csswg.org/selectors/#has-allowed-pseudo-element). | +| `is-element-backed` | No | `false` | Whether this is an [element-backed pseudo-element](https://drafts.csswg.org/css-pseudo-4/#element-backed). | | `is-pseudo-root` | No | `false` | Whether this is a [pseudo-element root](https://drafts.csswg.org/css-view-transitions/#pseudo-element-root). | +| `is-tree-abiding` | No | `false` | Whether this is a [tree-abiding pseudo-element](https://drafts.csswg.org/css-pseudo-4/#tree-abiding). | | `property-whitelist` | No | Nothing | Some pseudo-elements only permit certain properties. If so, name them in an array here. Some special values are allowed here for categories of properties - see below. | | `spec` | No | Nothing | Link to the spec definition, for reference. Not used in generated code. | | `type` | No | `"identifier"` | What type of pseudo-element is this. Either "identifier", "function", or "both". | @@ -273,6 +275,8 @@ The generated code provides: - `Optional aliased_pseudo_element_from_string(StringView)` is similar, but returns the `PseudoElement` this name is an alias for - `StringView pseudo_element_name(PseudoElement)` to convert a `PseudoElement` back into a string - `bool is_has_allowed_pseudo_element(PseudoElement)` returns whether the pseudo-element is valid inside `:has()` +- `bool is_element_backed_pseudo_element(PseudoElement)` returns whether the pseudo-element is element-backed +- `bool is_tree_abiding_pseudo_element(PseudoElement)` returns whether the pseudo-element is tree-abiding - `bool is_pseudo_element_root(PseudoElement)` returns whether the pseudo-element is a [pseudo-element root](https://drafts.csswg.org/css-view-transitions/#pseudo-element-root) - `bool pseudo_element_supports_property(PseudoElement, PropertyID)` returns whether the property can be applied to this pseudo-element diff --git a/Libraries/LibWeb/CSS/PseudoElements.json b/Libraries/LibWeb/CSS/PseudoElements.json index be4eb9183c9..8c09b78c1e2 100644 --- a/Libraries/LibWeb/CSS/PseudoElements.json +++ b/Libraries/LibWeb/CSS/PseudoElements.json @@ -36,19 +36,23 @@ "alias-for": "slider-thumb" }, "after": { - "spec": "https://drafts.csswg.org/css-pseudo-4/#selectordef-after" + "spec": "https://drafts.csswg.org/css-pseudo-4/#selectordef-after", + "is-tree-abiding": true }, "backdrop": { "spec": "https://drafts.csswg.org/css-position-4/#selectordef-backdrop" }, "before": { - "spec": "https://drafts.csswg.org/css-pseudo-4/#selectordef-before" + "spec": "https://drafts.csswg.org/css-pseudo-4/#selectordef-before", + "is-tree-abiding": true }, "details-content": { - "spec": "https://drafts.csswg.org/css-pseudo-4/#selectordef-details-content" + "spec": "https://drafts.csswg.org/css-pseudo-4/#selectordef-details-content", + "is-element-backed": true }, "file-selector-button": { - "spec": "https://drafts.csswg.org/css-pseudo-4/#selectordef-file-selector-button" + "spec": "https://drafts.csswg.org/css-pseudo-4/#selectordef-file-selector-button", + "is-element-backed": true }, "first-letter": { "spec": "https://drafts.csswg.org/css-pseudo-4/#selectordef-first-letter", @@ -82,15 +86,18 @@ ] }, "marker": { - "spec": "https://drafts.csswg.org/css-pseudo-4/#selectordef-marker" + "spec": "https://drafts.csswg.org/css-pseudo-4/#selectordef-marker", + "is-tree-abiding": true }, "part": { "spec": "https://drafts.csswg.org/css-shadow-1/#selectordef-part", "type": "function", - "function-syntax": "+" + "function-syntax": "+", + "is-element-backed": true }, "placeholder": { "spec": "https://drafts.csswg.org/css-pseudo-4/#selectordef-placeholder", + "is-tree-abiding": true, "property-whitelist": [ "#font-properties", "color", @@ -127,7 +134,8 @@ "slotted": { "spec": "https://drafts.csswg.org/css-shadow-1/#slotted-pseudo", "type": "function", - "function-syntax": "" + "function-syntax": "", + "is-element-backed": true }, "view-transition": { "spec": "https://drafts.csswg.org/css-view-transitions-1/#selectordef-view-transition", diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateCSSPseudoElement.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateCSSPseudoElement.cpp index ef35b3f96c7..30f48803272 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateCSSPseudoElement.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateCSSPseudoElement.cpp @@ -87,6 +87,8 @@ Optional aliased_pseudo_element_from_string(StringView); WEB_API StringView pseudo_element_name(PseudoElement); bool is_has_allowed_pseudo_element(PseudoElement); +bool is_tree_abiding_pseudo_element(PseudoElement); +bool is_element_backed_pseudo_element(PseudoElement); bool is_pseudo_element_root(PseudoElement); bool pseudo_element_supports_property(PseudoElement, PropertyID); @@ -222,6 +224,65 @@ bool is_has_allowed_pseudo_element(PseudoElement pseudo_element) } } +bool is_tree_abiding_pseudo_element(PseudoElement pseudo_element) +{ + // Element-backed pseudo-elements are always tree-abiding. + // https://drafts.csswg.org/css-pseudo-4/#element-backed + if (is_element_backed_pseudo_element(pseudo_element)) + return true; + + 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; + if (!pseudo_element.get_bool("is-tree-abiding"sv).value_or(false)) + return; + + auto member_generator = generator.fork(); + member_generator.set("name:titlecase", title_casify(name)); + + member_generator.append(R"~~~( + case PseudoElement::@name:titlecase@: + return true; +)~~~"); + }); + + generator.append(R"~~~( + default: + return false; + } +} + +bool is_element_backed_pseudo_element(PseudoElement pseudo_element) +{ + 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; + if (!pseudo_element.get_bool("is-element-backed"sv).value_or(false)) + return; + + auto member_generator = generator.fork(); + member_generator.set("name:titlecase", title_casify(name)); + + member_generator.append(R"~~~( + case PseudoElement::@name:titlecase@: + return true; +)~~~"); + }); + + generator.append(R"~~~( + default: + return false; + } +} + bool is_pseudo_element_root(PseudoElement pseudo_element) { switch (pseudo_element) {