mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-08 01:00:05 +00:00
LibWeb: Generate logical property mappings
To support this, how we declare logical property aliases has changed. Instead of `logical-alias-for` being a list of properties, it's now an object with a `group` and `mapping`. The group is the name of a logical property group in LogicalPropertyGroups.json. The mapping is which side/dimension/corner this property is. Hopefully it's self-explanatory enough. The generated code is very much a copy of what was previously in `StyleComputer::map_logical_alias_to_physical_property_id()`, so there should be no behaviour change.
This commit is contained in:
parent
4c48a51860
commit
69d4811ef7
Notes:
github-actions[bot]
2025-07-08 17:46:32 +00:00
Author: https://github.com/AtkinsSJ
Commit: 69d4811ef7
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/5287
Reviewed-by: https://github.com/ADKaster
Reviewed-by: https://github.com/tcl3 ✅
9 changed files with 561 additions and 646 deletions
|
@ -20,14 +20,14 @@ Each property will have some set of these fields on it:
|
||||||
(Note that required fields are not required on properties with `legacy-alias-for` or `logical-alias-for` set.)
|
(Note that required fields are not required on properties with `legacy-alias-for` or `logical-alias-for` set.)
|
||||||
|
|
||||||
| Field | Required | Default | Description | Generated functions |
|
| Field | Required | Default | Description | Generated functions |
|
||||||
|----------------------------|----------|---------|-------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------|
|
|----------------------------|----------|---------|-------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `affects-layout` | No | `true` | Boolean. Whether changing this property will invalidate the element's layout. | `bool property_affects_layout(PropertyID)` |
|
| `affects-layout` | No | `true` | Boolean. Whether changing this property will invalidate the element's layout. | `bool property_affects_layout(PropertyID)` |
|
||||||
| `affects-stacking-context` | No | `false` | Boolean. Whether this property can cause a new stacking context for the element. | `bool property_affects_stacking_context(PropertyID)` |
|
| `affects-stacking-context` | No | `false` | Boolean. Whether this property can cause a new stacking context for the element. | `bool property_affects_stacking_context(PropertyID)` |
|
||||||
| `animation-type` | Yes | | String. How the property should be animated. Defined by the spec. See below. | `AnimationType animation_type_from_longhand_property(PropertyID)` |
|
| `animation-type` | Yes | | String. How the property should be animated. Defined by the spec. See below. | `AnimationType animation_type_from_longhand_property(PropertyID)` |
|
||||||
| `inherited` | Yes | | Boolean. Whether the property is inherited by its child elements. | `bool is_inherited_property(PropertyID)` |
|
| `inherited` | Yes | | Boolean. Whether the property is inherited by its child elements. | `bool is_inherited_property(PropertyID)` |
|
||||||
| `initial` | Yes | | String. The property's initial value if it is not specified. | `NonnullRefPtr<CSSStyleValue const> property_initial_value(PropertyID)` |
|
| `initial` | Yes | | String. The property's initial value if it is not specified. | `NonnullRefPtr<CSSStyleValue const> property_initial_value(PropertyID)` |
|
||||||
| `legacy-alias-for` | No | Nothing | String. The name of a property this is an alias for. See below. | |
|
| `legacy-alias-for` | No | Nothing | String. The name of a property this is an alias for. See below. | |
|
||||||
| `logical-alias-for` | No | Nothing | Array of strings. The name of a property this is an alias for. See below. | `bool property_is_logical_alias(PropertyID);` |
|
| `logical-alias-for` | No | Nothing | An object. See below. | `bool property_is_logical_alias(PropertyID);`<br/>`PropertyID map_logical_alias_to_physical_property(PropertyID, LogicalAliasMappingContext const&)` |
|
||||||
| `longhands` | No | `[]` | Array of strings. If this is a shorthand, these are the property names that it expands out into. | `Vector<PropertyID> longhands_for_shorthand(PropertyID)`<br/>`Vector<PropertyID> expanded_longhands_for_shorthand(PropertyID)`<br/>`Vector<PropertyID> shorthands_for_longhand(PropertyID)` |
|
| `longhands` | No | `[]` | Array of strings. If this is a shorthand, these are the property names that it expands out into. | `Vector<PropertyID> longhands_for_shorthand(PropertyID)`<br/>`Vector<PropertyID> expanded_longhands_for_shorthand(PropertyID)`<br/>`Vector<PropertyID> shorthands_for_longhand(PropertyID)` |
|
||||||
| `max-values` | No | `1` | Integer. How many values can be parsed for this property. eg, `margin` can have up to 4 values. | `size_t property_maximum_value_count(PropertyID)` |
|
| `max-values` | No | `1` | Integer. How many values can be parsed for this property. eg, `margin` can have up to 4 values. | `size_t property_maximum_value_count(PropertyID)` |
|
||||||
| `percentages-resolve-to` | No | Nothing | String. What type percentages get resolved to. eg, for `width` percentages are resolved to `length` values. | `Optional<ValueType> property_resolves_percentages_relative_to(PropertyID)` |
|
| `percentages-resolve-to` | No | Nothing | String. What type percentages get resolved to. eg, for `width` percentages are resolved to `length` values. | `Optional<ValueType> property_resolves_percentages_relative_to(PropertyID)` |
|
||||||
|
@ -47,15 +47,25 @@ The [Web Animations spec](https://www.w3.org/TR/web-animations/#animation-type)
|
||||||
| repeatable list | `repeatable-list` |
|
| repeatable list | `repeatable-list` |
|
||||||
| (See prose) | `custom` |
|
| (See prose) | `custom` |
|
||||||
|
|
||||||
### `legacy-alias-for` and `logical-alias-for`
|
### `legacy-alias-for`
|
||||||
|
(Not to be confused with `logical-alias-for` below.)
|
||||||
|
|
||||||
These are two separate concepts, with unfortunately similar names:
|
[Legacy name aliases](https://drafts.csswg.org/css-cascade-5/#legacy-name-alias) are properties whose spec names have changed,
|
||||||
- [Legacy name aliases](https://drafts.csswg.org/css-cascade-5/#legacy-name-alias) are properties whose spec names have changed,
|
|
||||||
but the syntax has not, so setting the old one is defined as setting the new one directly.
|
but the syntax has not, so setting the old one is defined as setting the new one directly.
|
||||||
For example, `font-stretch` was renamed to `font-width`, so `font-stretch` is now a legacy name alias for `font-width`.
|
For example, `font-stretch` was renamed to `font-width`, so `font-stretch` is now a legacy name alias for `font-width`.
|
||||||
- Logical aliases are properties like `margin-block-start`, which may assign a value to one of several other properties
|
|
||||||
|
### `logical-alias-for`
|
||||||
|
(Not to be confused with `legacy-alias-for` above.)
|
||||||
|
|
||||||
|
Logical aliases are properties like `margin-block-start`, which may assign a value to one of several other properties
|
||||||
(`margin-top`, `margin-bottom`, `margin-left`, or `margin-right`) depending on the element they are applied to.
|
(`margin-top`, `margin-bottom`, `margin-left`, or `margin-right`) depending on the element they are applied to.
|
||||||
List all the properties that they can alias.
|
|
||||||
|
`logical-alias-for` should be an object with two fields, both of which are required:
|
||||||
|
|
||||||
|
| Field | Description |
|
||||||
|
|-----------|-------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| `group` | String. Name of the logical property group this is associated with. (See [LogicalPropertyGroups.json](#logicalpropertygroupsjson).) |
|
||||||
|
| `mapping` | String. How this relates to the group. eg, if it's the block end value, `block-end`. |
|
||||||
|
|
||||||
### `quirks`
|
### `quirks`
|
||||||
|
|
||||||
|
@ -74,6 +84,20 @@ For numeric types, we use the [bracketed range notation](https://www.w3.org/TR/c
|
||||||
for example `width` can take any non-negative length, so it has `"length [0,∞]"` in its `valid-types` array.
|
for example `width` can take any non-negative length, so it has `"length [0,∞]"` in its `valid-types` array.
|
||||||
For `<custom-ident>`s, the excluded identifiers are placed within `![]`, for example `"custom-ident ![all,none]"`.
|
For `<custom-ident>`s, the excluded identifiers are placed within `![]`, for example `"custom-ident ![all,none]"`.
|
||||||
|
|
||||||
|
## LogicalPropertyGroups.json
|
||||||
|
|
||||||
|
A set of matching CSS properties can be grouped together in what's called a
|
||||||
|
["logical property group"](https://drafts.csswg.org/css-logical-1/#logical-property-group).
|
||||||
|
For example, all of the `margin-*` properties are in the `margin` group.
|
||||||
|
|
||||||
|
This data is used to map logical properties (such as `margin-block-start`) into their physical counterparts (like
|
||||||
|
`margin-top`) at runtime, depending on the writing direction. We don't generate any code directly from this file.
|
||||||
|
Instead, it's used as part of generating the PropertyID code.
|
||||||
|
|
||||||
|
The file is a single object where the keys are the names of the logical property groups, and their values are objects
|
||||||
|
mapping physical dimensions, sides, or corners to the relevant property. Which keys are there depends on the group - for
|
||||||
|
example the `size` group has `width` and `height`.
|
||||||
|
|
||||||
## Descriptors.json
|
## Descriptors.json
|
||||||
|
|
||||||
Descriptors are basically properties, but for at-rules instead of style. The overall structure is a JSON object, with
|
Descriptors are basically properties, but for at-rules instead of style. The overall structure is a JSON object, with
|
||||||
|
|
|
@ -7,7 +7,8 @@ These are listed below in the order that Ladybird deals with them, starting at p
|
||||||
|
|
||||||
The first place you will need to go to is `CSS/Properties.json`. This file contains the definition for each
|
The first place you will need to go to is `CSS/Properties.json`. This file contains the definition for each
|
||||||
property, and is used to generate the `PropertyID` enum and a selection of functions. You may also need to
|
property, and is used to generate the `PropertyID` enum and a selection of functions. You may also need to
|
||||||
modify `CSS/Keywords.json` and `CSS/Enums.json`. See [CSSGeneratedFiles.md](CSSGeneratedFiles.md) for details.
|
modify `CSS/Keywords.json`, `CSS/Enums.json`, and `CSS/LogicalPropertyGroups.json`.
|
||||||
|
See [CSSGeneratedFiles.md](CSSGeneratedFiles.md) for details.
|
||||||
|
|
||||||
## Parsing
|
## Parsing
|
||||||
|
|
||||||
|
|
|
@ -700,7 +700,7 @@ RefPtr<CSSStyleValue const> CSSStyleProperties::style_value_for_computed_propert
|
||||||
|
|
||||||
return style_value_for_computed_property(
|
return style_value_for_computed_property(
|
||||||
layout_node,
|
layout_node,
|
||||||
StyleComputer::map_logical_alias_to_physical_property_id(property_id, StyleComputer::LogicalAliasMappingContext { computed_properties->writing_mode(), computed_properties->direction() }));
|
map_logical_alias_to_physical_property(property_id, LogicalAliasMappingContext { computed_properties->writing_mode(), computed_properties->direction() }));
|
||||||
}
|
}
|
||||||
|
|
||||||
// A limited number of properties have special rules for producing their "resolved value".
|
// A limited number of properties have special rules for producing their "resolved value".
|
||||||
|
|
56
Libraries/LibWeb/CSS/LogicalPropertyGroups.json
Normal file
56
Libraries/LibWeb/CSS/LogicalPropertyGroups.json
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
{
|
||||||
|
"border-color": {
|
||||||
|
"top": "border-top-color",
|
||||||
|
"right": "border-right-color",
|
||||||
|
"bottom": "border-bottom-color",
|
||||||
|
"left": "border-left-color"
|
||||||
|
},
|
||||||
|
"border-radius": {
|
||||||
|
"top-left": "border-top-left-radius",
|
||||||
|
"bottom-left": "border-bottom-left-radius",
|
||||||
|
"top-right": "border-top-right-radius",
|
||||||
|
"bottom-right": "border-bottom-right-radius"
|
||||||
|
},
|
||||||
|
"border-style": {
|
||||||
|
"top": "border-top-style",
|
||||||
|
"right": "border-right-style",
|
||||||
|
"bottom": "border-bottom-style",
|
||||||
|
"left": "border-left-style"
|
||||||
|
},
|
||||||
|
"border-width": {
|
||||||
|
"top": "border-top-width",
|
||||||
|
"right": "border-right-width",
|
||||||
|
"bottom": "border-bottom-width",
|
||||||
|
"left": "border-left-width"
|
||||||
|
},
|
||||||
|
"inset": {
|
||||||
|
"top": "top",
|
||||||
|
"right": "right",
|
||||||
|
"bottom": "bottom",
|
||||||
|
"left": "left"
|
||||||
|
},
|
||||||
|
"margin": {
|
||||||
|
"top": "margin-top",
|
||||||
|
"right": "margin-right",
|
||||||
|
"bottom": "margin-bottom",
|
||||||
|
"left": "margin-left"
|
||||||
|
},
|
||||||
|
"max-size": {
|
||||||
|
"width": "max-width",
|
||||||
|
"height": "max-height"
|
||||||
|
},
|
||||||
|
"min-size": {
|
||||||
|
"width": "min-width",
|
||||||
|
"height": "min-height"
|
||||||
|
},
|
||||||
|
"padding": {
|
||||||
|
"top": "padding-top",
|
||||||
|
"right": "padding-right",
|
||||||
|
"bottom": "padding-bottom",
|
||||||
|
"left": "padding-left"
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
"width": "width",
|
||||||
|
"height": "height"
|
||||||
|
}
|
||||||
|
}
|
|
@ -481,10 +481,10 @@
|
||||||
"percentages-resolve-to": "length"
|
"percentages-resolve-to": "length"
|
||||||
},
|
},
|
||||||
"block-size": {
|
"block-size": {
|
||||||
"logical-alias-for": [
|
"logical-alias-for": {
|
||||||
"height",
|
"group": "size",
|
||||||
"width"
|
"mapping": "block-size"
|
||||||
],
|
},
|
||||||
"initial": "auto",
|
"initial": "auto",
|
||||||
"max-values": 1
|
"max-values": 1
|
||||||
},
|
},
|
||||||
|
@ -515,30 +515,24 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"border-block-end-color": {
|
"border-block-end-color": {
|
||||||
"logical-alias-for": [
|
"logical-alias-for": {
|
||||||
"border-top-color",
|
"group": "border-color",
|
||||||
"border-right-color",
|
"mapping": "block-end"
|
||||||
"border-bottom-color",
|
},
|
||||||
"border-left-color"
|
|
||||||
],
|
|
||||||
"max-values": 1
|
"max-values": 1
|
||||||
},
|
},
|
||||||
"border-block-end-style": {
|
"border-block-end-style": {
|
||||||
"logical-alias-for": [
|
"logical-alias-for": {
|
||||||
"border-top-style",
|
"group": "border-style",
|
||||||
"border-right-style",
|
"mapping": "block-end"
|
||||||
"border-bottom-style",
|
},
|
||||||
"border-left-style"
|
|
||||||
],
|
|
||||||
"max-values": 1
|
"max-values": 1
|
||||||
},
|
},
|
||||||
"border-block-end-width": {
|
"border-block-end-width": {
|
||||||
"logical-alias-for": [
|
"logical-alias-for": {
|
||||||
"border-top-width",
|
"group": "border-width",
|
||||||
"border-right-width",
|
"mapping": "block-end"
|
||||||
"border-bottom-width",
|
},
|
||||||
"border-left-width"
|
|
||||||
],
|
|
||||||
"max-values": 1
|
"max-values": 1
|
||||||
},
|
},
|
||||||
"border-block-start": {
|
"border-block-start": {
|
||||||
|
@ -551,30 +545,24 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"border-block-start-color": {
|
"border-block-start-color": {
|
||||||
"logical-alias-for": [
|
"logical-alias-for": {
|
||||||
"border-top-color",
|
"group": "border-color",
|
||||||
"border-right-color",
|
"mapping": "block-start"
|
||||||
"border-bottom-color",
|
},
|
||||||
"border-left-color"
|
|
||||||
],
|
|
||||||
"max-values": 1
|
"max-values": 1
|
||||||
},
|
},
|
||||||
"border-block-start-style": {
|
"border-block-start-style": {
|
||||||
"logical-alias-for": [
|
"logical-alias-for": {
|
||||||
"border-top-style",
|
"group": "border-style",
|
||||||
"border-right-style",
|
"mapping": "block-start"
|
||||||
"border-bottom-style",
|
},
|
||||||
"border-left-style"
|
|
||||||
],
|
|
||||||
"max-values": 1
|
"max-values": 1
|
||||||
},
|
},
|
||||||
"border-block-start-width": {
|
"border-block-start-width": {
|
||||||
"logical-alias-for": [
|
"logical-alias-for": {
|
||||||
"border-top-width",
|
"group": "border-width",
|
||||||
"border-right-width",
|
"mapping": "block-start"
|
||||||
"border-bottom-width",
|
},
|
||||||
"border-left-width"
|
|
||||||
],
|
|
||||||
"max-values": 1
|
"max-values": 1
|
||||||
},
|
},
|
||||||
"border-block-style": {
|
"border-block-style": {
|
||||||
|
@ -688,21 +676,17 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"border-end-end-radius": {
|
"border-end-end-radius": {
|
||||||
"logical-alias-for": [
|
"logical-alias-for": {
|
||||||
"border-top-left-radius",
|
"group": "border-radius",
|
||||||
"border-bottom-left-radius",
|
"mapping": "end-end"
|
||||||
"border-top-right-radius",
|
},
|
||||||
"border-bottom-right-radius"
|
|
||||||
],
|
|
||||||
"max-values": 1
|
"max-values": 1
|
||||||
},
|
},
|
||||||
"border-end-start-radius": {
|
"border-end-start-radius": {
|
||||||
"logical-alias-for": [
|
"logical-alias-for": {
|
||||||
"border-top-left-radius",
|
"group": "border-radius",
|
||||||
"border-bottom-left-radius",
|
"mapping": "end-start"
|
||||||
"border-top-right-radius",
|
},
|
||||||
"border-bottom-right-radius"
|
|
||||||
],
|
|
||||||
"max-values": 1
|
"max-values": 1
|
||||||
},
|
},
|
||||||
"border-image": {
|
"border-image": {
|
||||||
|
@ -795,30 +779,24 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"border-inline-end-color": {
|
"border-inline-end-color": {
|
||||||
"logical-alias-for": [
|
"logical-alias-for": {
|
||||||
"border-top-color",
|
"group": "border-color",
|
||||||
"border-right-color",
|
"mapping": "inline-end"
|
||||||
"border-bottom-color",
|
},
|
||||||
"border-left-color"
|
|
||||||
],
|
|
||||||
"max-values": 1
|
"max-values": 1
|
||||||
},
|
},
|
||||||
"border-inline-end-style": {
|
"border-inline-end-style": {
|
||||||
"logical-alias-for": [
|
"logical-alias-for": {
|
||||||
"border-top-style",
|
"group": "border-style",
|
||||||
"border-right-style",
|
"mapping": "inline-end"
|
||||||
"border-bottom-style",
|
},
|
||||||
"border-left-style"
|
|
||||||
],
|
|
||||||
"max-values": 1
|
"max-values": 1
|
||||||
},
|
},
|
||||||
"border-inline-end-width": {
|
"border-inline-end-width": {
|
||||||
"logical-alias-for": [
|
"logical-alias-for": {
|
||||||
"border-top-width",
|
"group": "border-width",
|
||||||
"border-right-width",
|
"mapping": "inline-end"
|
||||||
"border-bottom-width",
|
},
|
||||||
"border-left-width"
|
|
||||||
],
|
|
||||||
"max-values": 1
|
"max-values": 1
|
||||||
},
|
},
|
||||||
"border-inline-start": {
|
"border-inline-start": {
|
||||||
|
@ -831,30 +809,24 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"border-inline-start-color": {
|
"border-inline-start-color": {
|
||||||
"logical-alias-for": [
|
"logical-alias-for": {
|
||||||
"border-top-color",
|
"group": "border-color",
|
||||||
"border-right-color",
|
"mapping": "inline-start"
|
||||||
"border-bottom-color",
|
},
|
||||||
"border-left-color"
|
|
||||||
],
|
|
||||||
"max-values": 1
|
"max-values": 1
|
||||||
},
|
},
|
||||||
"border-inline-start-style": {
|
"border-inline-start-style": {
|
||||||
"logical-alias-for": [
|
"logical-alias-for": {
|
||||||
"border-top-style",
|
"group": "border-style",
|
||||||
"border-right-style",
|
"mapping": "inline-start"
|
||||||
"border-bottom-style",
|
},
|
||||||
"border-left-style"
|
|
||||||
],
|
|
||||||
"max-values": 1
|
"max-values": 1
|
||||||
},
|
},
|
||||||
"border-inline-start-width": {
|
"border-inline-start-width": {
|
||||||
"logical-alias-for": [
|
"logical-alias-for": {
|
||||||
"border-top-width",
|
"group": "border-width",
|
||||||
"border-right-width",
|
"mapping": "inline-start"
|
||||||
"border-bottom-width",
|
},
|
||||||
"border-left-width"
|
|
||||||
],
|
|
||||||
"max-values": 1
|
"max-values": 1
|
||||||
},
|
},
|
||||||
"border-inline-style": {
|
"border-inline-style": {
|
||||||
|
@ -992,21 +964,17 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"border-start-end-radius": {
|
"border-start-end-radius": {
|
||||||
"logical-alias-for": [
|
"logical-alias-for": {
|
||||||
"border-top-left-radius",
|
"group": "border-radius",
|
||||||
"border-bottom-left-radius",
|
"mapping": "start-end"
|
||||||
"border-top-right-radius",
|
},
|
||||||
"border-bottom-right-radius"
|
|
||||||
],
|
|
||||||
"max-values": 1
|
"max-values": 1
|
||||||
},
|
},
|
||||||
"border-start-start-radius": {
|
"border-start-start-radius": {
|
||||||
"logical-alias-for": [
|
"logical-alias-for": {
|
||||||
"border-top-left-radius",
|
"group": "border-radius",
|
||||||
"border-bottom-left-radius",
|
"mapping": "start-start"
|
||||||
"border-top-right-radius",
|
},
|
||||||
"border-bottom-right-radius"
|
|
||||||
],
|
|
||||||
"max-values": 1
|
"max-values": 1
|
||||||
},
|
},
|
||||||
"border-style": {
|
"border-style": {
|
||||||
|
@ -1997,10 +1965,10 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"inline-size": {
|
"inline-size": {
|
||||||
"logical-alias-for": [
|
"logical-alias-for": {
|
||||||
"width",
|
"group": "size",
|
||||||
"height"
|
"mapping": "inline-size"
|
||||||
],
|
},
|
||||||
"initial": "auto",
|
"initial": "auto",
|
||||||
"max-values": 1
|
"max-values": 1
|
||||||
},
|
},
|
||||||
|
@ -2040,21 +2008,17 @@
|
||||||
"percentages-resolve-to": "length"
|
"percentages-resolve-to": "length"
|
||||||
},
|
},
|
||||||
"inset-block-end": {
|
"inset-block-end": {
|
||||||
"logical-alias-for": [
|
"logical-alias-for": {
|
||||||
"top",
|
"group": "inset",
|
||||||
"right",
|
"mapping": "block-end"
|
||||||
"bottom",
|
},
|
||||||
"left"
|
|
||||||
],
|
|
||||||
"max-values": 1
|
"max-values": 1
|
||||||
},
|
},
|
||||||
"inset-block-start": {
|
"inset-block-start": {
|
||||||
"logical-alias-for": [
|
"logical-alias-for": {
|
||||||
"top",
|
"group": "inset",
|
||||||
"right",
|
"mapping": "block-start"
|
||||||
"bottom",
|
},
|
||||||
"left"
|
|
||||||
],
|
|
||||||
"max-values": 1
|
"max-values": 1
|
||||||
},
|
},
|
||||||
"inset-inline": {
|
"inset-inline": {
|
||||||
|
@ -2074,21 +2038,17 @@
|
||||||
"percentages-resolve-to": "length"
|
"percentages-resolve-to": "length"
|
||||||
},
|
},
|
||||||
"inset-inline-end": {
|
"inset-inline-end": {
|
||||||
"logical-alias-for": [
|
"logical-alias-for": {
|
||||||
"top",
|
"group": "inset",
|
||||||
"right",
|
"mapping": "inline-end"
|
||||||
"bottom",
|
},
|
||||||
"left"
|
|
||||||
],
|
|
||||||
"max-values": 1
|
"max-values": 1
|
||||||
},
|
},
|
||||||
"inset-inline-start": {
|
"inset-inline-start": {
|
||||||
"logical-alias-for": [
|
"logical-alias-for": {
|
||||||
"top",
|
"group": "inset",
|
||||||
"right",
|
"mapping": "inline-start"
|
||||||
"bottom",
|
},
|
||||||
"left"
|
|
||||||
],
|
|
||||||
"max-values": 1
|
"max-values": 1
|
||||||
},
|
},
|
||||||
"isolation": {
|
"isolation": {
|
||||||
|
@ -2245,20 +2205,16 @@
|
||||||
"percentages-resolve-to": "length"
|
"percentages-resolve-to": "length"
|
||||||
},
|
},
|
||||||
"margin-block-end": {
|
"margin-block-end": {
|
||||||
"logical-alias-for": [
|
"logical-alias-for": {
|
||||||
"margin-top",
|
"group": "margin",
|
||||||
"margin-right",
|
"mapping": "block-end"
|
||||||
"margin-bottom",
|
}
|
||||||
"margin-left"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"margin-block-start": {
|
"margin-block-start": {
|
||||||
"logical-alias-for": [
|
"logical-alias-for": {
|
||||||
"margin-top",
|
"group": "margin",
|
||||||
"margin-right",
|
"mapping": "block-start"
|
||||||
"margin-bottom",
|
}
|
||||||
"margin-left"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"margin-bottom": {
|
"margin-bottom": {
|
||||||
"animation-type": "by-computed-value",
|
"animation-type": "by-computed-value",
|
||||||
|
@ -2293,20 +2249,16 @@
|
||||||
"percentages-resolve-to": "length"
|
"percentages-resolve-to": "length"
|
||||||
},
|
},
|
||||||
"margin-inline-end": {
|
"margin-inline-end": {
|
||||||
"logical-alias-for": [
|
"logical-alias-for": {
|
||||||
"margin-top",
|
"group": "margin",
|
||||||
"margin-right",
|
"mapping": "inline-end"
|
||||||
"margin-bottom",
|
}
|
||||||
"margin-left"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"margin-inline-start": {
|
"margin-inline-start": {
|
||||||
"logical-alias-for": [
|
"logical-alias-for": {
|
||||||
"margin-top",
|
"group": "margin",
|
||||||
"margin-right",
|
"mapping": "inline-start"
|
||||||
"margin-bottom",
|
}
|
||||||
"margin-left"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"margin-left": {
|
"margin-left": {
|
||||||
"animation-type": "by-computed-value",
|
"animation-type": "by-computed-value",
|
||||||
|
@ -2416,10 +2368,10 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"max-block-size": {
|
"max-block-size": {
|
||||||
"logical-alias-for": [
|
"logical-alias-for": {
|
||||||
"max-height",
|
"group": "max-size",
|
||||||
"max-width"
|
"mapping": "block-size"
|
||||||
],
|
},
|
||||||
"initial": "none"
|
"initial": "none"
|
||||||
},
|
},
|
||||||
"max-height": {
|
"max-height": {
|
||||||
|
@ -2442,10 +2394,10 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"max-inline-size": {
|
"max-inline-size": {
|
||||||
"logical-alias-for": [
|
"logical-alias-for": {
|
||||||
"max-width",
|
"group": "max-size",
|
||||||
"max-height"
|
"mapping": "inline-size"
|
||||||
],
|
},
|
||||||
"initial": "none"
|
"initial": "none"
|
||||||
},
|
},
|
||||||
"max-width": {
|
"max-width": {
|
||||||
|
@ -2468,10 +2420,10 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"min-block-size": {
|
"min-block-size": {
|
||||||
"logical-alias-for": [
|
"logical-alias-for": {
|
||||||
"min-height",
|
"group": "min-size",
|
||||||
"min-width"
|
"mapping": "block-size"
|
||||||
],
|
},
|
||||||
"initial": "0"
|
"initial": "0"
|
||||||
},
|
},
|
||||||
"min-height": {
|
"min-height": {
|
||||||
|
@ -2494,10 +2446,10 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"min-inline-size": {
|
"min-inline-size": {
|
||||||
"logical-alias-for": [
|
"logical-alias-for": {
|
||||||
"min-width",
|
"group": "min-size",
|
||||||
"min-height"
|
"mapping": "inline-size"
|
||||||
],
|
},
|
||||||
"initial": "0"
|
"initial": "0"
|
||||||
},
|
},
|
||||||
"min-width": {
|
"min-width": {
|
||||||
|
@ -2678,20 +2630,16 @@
|
||||||
"percentages-resolve-to": "length"
|
"percentages-resolve-to": "length"
|
||||||
},
|
},
|
||||||
"padding-block-end": {
|
"padding-block-end": {
|
||||||
"logical-alias-for": [
|
"logical-alias-for": {
|
||||||
"padding-top",
|
"group": "padding",
|
||||||
"padding-right",
|
"mapping": "block-end"
|
||||||
"padding-bottom",
|
}
|
||||||
"padding-left"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"padding-block-start": {
|
"padding-block-start": {
|
||||||
"logical-alias-for": [
|
"logical-alias-for": {
|
||||||
"padding-top",
|
"group": "padding",
|
||||||
"padding-right",
|
"mapping": "block-start"
|
||||||
"padding-bottom",
|
}
|
||||||
"padding-left"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"padding-bottom": {
|
"padding-bottom": {
|
||||||
"animation-type": "by-computed-value",
|
"animation-type": "by-computed-value",
|
||||||
|
@ -2720,20 +2668,16 @@
|
||||||
"percentages-resolve-to": "length"
|
"percentages-resolve-to": "length"
|
||||||
},
|
},
|
||||||
"padding-inline-end": {
|
"padding-inline-end": {
|
||||||
"logical-alias-for": [
|
"logical-alias-for": {
|
||||||
"padding-top",
|
"group": "padding",
|
||||||
"padding-right",
|
"mapping": "inline-end"
|
||||||
"padding-bottom",
|
}
|
||||||
"padding-left"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"padding-inline-start": {
|
"padding-inline-start": {
|
||||||
"logical-alias-for": [
|
"logical-alias-for": {
|
||||||
"padding-top",
|
"group": "padding",
|
||||||
"padding-right",
|
"mapping": "inline-start"
|
||||||
"padding-bottom",
|
}
|
||||||
"padding-left"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"padding-left": {
|
"padding-left": {
|
||||||
"animation-type": "by-computed-value",
|
"animation-type": "by-computed-value",
|
||||||
|
|
|
@ -888,395 +888,6 @@ void StyleComputer::for_each_property_expanding_shorthands(PropertyID property_i
|
||||||
set_longhand_property(property_id, value);
|
set_longhand_property(property_id, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://drafts.csswg.org/css-writing-modes-4/#logical-to-physical
|
|
||||||
PropertyID StyleComputer::map_logical_alias_to_physical_property_id(PropertyID property_id, LogicalAliasMappingContext mapping_context)
|
|
||||||
{
|
|
||||||
// FIXME: Note: The used direction depends on the computed writing-mode and text-orientation: in vertical writing
|
|
||||||
// modes, a text-orientation value of upright forces the used direction to ltr.
|
|
||||||
auto used_direction = mapping_context.direction;
|
|
||||||
switch (property_id) {
|
|
||||||
case PropertyID::BlockSize:
|
|
||||||
if (mapping_context.writing_mode == WritingMode::HorizontalTb)
|
|
||||||
return PropertyID::Height;
|
|
||||||
return PropertyID::Width;
|
|
||||||
case PropertyID::BorderBlockEndColor:
|
|
||||||
if (mapping_context.writing_mode == WritingMode::HorizontalTb)
|
|
||||||
return PropertyID::BorderBottomColor;
|
|
||||||
if (first_is_one_of(mapping_context.writing_mode, WritingMode::VerticalRl, WritingMode::SidewaysRl))
|
|
||||||
return PropertyID::BorderLeftColor;
|
|
||||||
return PropertyID::BorderRightColor;
|
|
||||||
case PropertyID::BorderBlockEndStyle:
|
|
||||||
if (mapping_context.writing_mode == WritingMode::HorizontalTb)
|
|
||||||
return PropertyID::BorderBottomStyle;
|
|
||||||
if (first_is_one_of(mapping_context.writing_mode, WritingMode::VerticalRl, WritingMode::SidewaysRl))
|
|
||||||
return PropertyID::BorderLeftStyle;
|
|
||||||
return PropertyID::BorderRightStyle;
|
|
||||||
case PropertyID::BorderBlockEndWidth:
|
|
||||||
if (mapping_context.writing_mode == WritingMode::HorizontalTb)
|
|
||||||
return PropertyID::BorderBottomWidth;
|
|
||||||
if (first_is_one_of(mapping_context.writing_mode, WritingMode::VerticalRl, WritingMode::SidewaysRl))
|
|
||||||
return PropertyID::BorderLeftWidth;
|
|
||||||
return PropertyID::BorderRightWidth;
|
|
||||||
case PropertyID::BorderBlockStartColor:
|
|
||||||
if (mapping_context.writing_mode == WritingMode::HorizontalTb)
|
|
||||||
return PropertyID::BorderTopColor;
|
|
||||||
if (first_is_one_of(mapping_context.writing_mode, WritingMode::VerticalRl, WritingMode::SidewaysRl))
|
|
||||||
return PropertyID::BorderRightColor;
|
|
||||||
return PropertyID::BorderLeftColor;
|
|
||||||
case PropertyID::BorderBlockStartStyle:
|
|
||||||
if (mapping_context.writing_mode == WritingMode::HorizontalTb)
|
|
||||||
return PropertyID::BorderTopStyle;
|
|
||||||
if (first_is_one_of(mapping_context.writing_mode, WritingMode::VerticalRl, WritingMode::SidewaysRl))
|
|
||||||
return PropertyID::BorderRightStyle;
|
|
||||||
return PropertyID::BorderLeftStyle;
|
|
||||||
case PropertyID::BorderBlockStartWidth:
|
|
||||||
if (mapping_context.writing_mode == WritingMode::HorizontalTb)
|
|
||||||
return PropertyID::BorderTopWidth;
|
|
||||||
if (first_is_one_of(mapping_context.writing_mode, WritingMode::VerticalRl, WritingMode::SidewaysRl))
|
|
||||||
return PropertyID::BorderRightWidth;
|
|
||||||
return PropertyID::BorderLeftWidth;
|
|
||||||
case PropertyID::BorderEndEndRadius:
|
|
||||||
if (mapping_context.writing_mode == WritingMode::HorizontalTb) {
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::BorderBottomRightRadius;
|
|
||||||
return PropertyID::BorderBottomLeftRadius;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (first_is_one_of(mapping_context.writing_mode, WritingMode::VerticalRl, WritingMode::SidewaysRl)) {
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::BorderBottomLeftRadius;
|
|
||||||
return PropertyID::BorderTopLeftRadius;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mapping_context.writing_mode == WritingMode::VerticalLr) {
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::BorderBottomRightRadius;
|
|
||||||
return PropertyID::BorderTopRightRadius;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::BorderTopRightRadius;
|
|
||||||
return PropertyID::BorderBottomRightRadius;
|
|
||||||
case PropertyID::BorderEndStartRadius:
|
|
||||||
if (mapping_context.writing_mode == WritingMode::HorizontalTb) {
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::BorderBottomLeftRadius;
|
|
||||||
return PropertyID::BorderBottomRightRadius;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (first_is_one_of(mapping_context.writing_mode, WritingMode::VerticalRl, WritingMode::SidewaysRl)) {
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::BorderTopLeftRadius;
|
|
||||||
return PropertyID::BorderBottomLeftRadius;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mapping_context.writing_mode == WritingMode::VerticalLr) {
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::BorderTopRightRadius;
|
|
||||||
return PropertyID::BorderBottomRightRadius;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::BorderBottomRightRadius;
|
|
||||||
return PropertyID::BorderTopRightRadius;
|
|
||||||
case PropertyID::BorderInlineStartColor:
|
|
||||||
if (mapping_context.writing_mode == WritingMode::HorizontalTb) {
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::BorderLeftColor;
|
|
||||||
return PropertyID::BorderRightColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (first_is_one_of(mapping_context.writing_mode, WritingMode::VerticalRl, WritingMode::SidewaysRl, WritingMode::VerticalLr)) {
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::BorderTopColor;
|
|
||||||
return PropertyID::BorderBottomColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::BorderBottomColor;
|
|
||||||
return PropertyID::BorderTopColor;
|
|
||||||
case PropertyID::BorderInlineStartStyle:
|
|
||||||
if (mapping_context.writing_mode == WritingMode::HorizontalTb) {
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::BorderLeftStyle;
|
|
||||||
return PropertyID::BorderRightStyle;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (first_is_one_of(mapping_context.writing_mode, WritingMode::VerticalRl, WritingMode::SidewaysRl, WritingMode::VerticalLr)) {
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::BorderTopStyle;
|
|
||||||
return PropertyID::BorderBottomStyle;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::BorderBottomStyle;
|
|
||||||
return PropertyID::BorderTopStyle;
|
|
||||||
|
|
||||||
case PropertyID::BorderInlineStartWidth:
|
|
||||||
if (mapping_context.writing_mode == WritingMode::HorizontalTb) {
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::BorderLeftWidth;
|
|
||||||
return PropertyID::BorderRightWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (first_is_one_of(mapping_context.writing_mode, WritingMode::VerticalRl, WritingMode::SidewaysRl, WritingMode::VerticalLr)) {
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::BorderTopWidth;
|
|
||||||
return PropertyID::BorderBottomWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::BorderBottomWidth;
|
|
||||||
return PropertyID::BorderTopWidth;
|
|
||||||
case PropertyID::BorderInlineEndColor:
|
|
||||||
if (mapping_context.writing_mode == WritingMode::HorizontalTb) {
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::BorderRightColor;
|
|
||||||
return PropertyID::BorderLeftColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (first_is_one_of(mapping_context.writing_mode, WritingMode::VerticalRl, WritingMode::SidewaysRl, WritingMode::VerticalLr)) {
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::BorderBottomColor;
|
|
||||||
return PropertyID::BorderTopColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::BorderTopColor;
|
|
||||||
return PropertyID::BorderBottomColor;
|
|
||||||
case PropertyID::BorderInlineEndStyle:
|
|
||||||
if (mapping_context.writing_mode == WritingMode::HorizontalTb) {
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::BorderRightStyle;
|
|
||||||
return PropertyID::BorderLeftStyle;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (first_is_one_of(mapping_context.writing_mode, WritingMode::VerticalRl, WritingMode::SidewaysRl, WritingMode::VerticalLr)) {
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::BorderBottomStyle;
|
|
||||||
return PropertyID::BorderTopStyle;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::BorderTopStyle;
|
|
||||||
return PropertyID::BorderBottomStyle;
|
|
||||||
case PropertyID::BorderInlineEndWidth:
|
|
||||||
if (mapping_context.writing_mode == WritingMode::HorizontalTb) {
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::BorderRightWidth;
|
|
||||||
return PropertyID::BorderLeftWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (first_is_one_of(mapping_context.writing_mode, WritingMode::VerticalRl, WritingMode::SidewaysRl, WritingMode::VerticalLr)) {
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::BorderBottomWidth;
|
|
||||||
return PropertyID::BorderTopWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::BorderTopWidth;
|
|
||||||
return PropertyID::BorderBottomWidth;
|
|
||||||
case PropertyID::BorderStartEndRadius:
|
|
||||||
if (mapping_context.writing_mode == WritingMode::HorizontalTb) {
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::BorderTopRightRadius;
|
|
||||||
return PropertyID::BorderTopLeftRadius;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (first_is_one_of(mapping_context.writing_mode, WritingMode::VerticalRl, WritingMode::SidewaysRl)) {
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::BorderBottomRightRadius;
|
|
||||||
return PropertyID::BorderTopRightRadius;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mapping_context.writing_mode == WritingMode::VerticalLr) {
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::BorderBottomLeftRadius;
|
|
||||||
return PropertyID::BorderTopLeftRadius;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::BorderTopLeftRadius;
|
|
||||||
return PropertyID::BorderBottomLeftRadius;
|
|
||||||
case PropertyID::BorderStartStartRadius:
|
|
||||||
if (mapping_context.writing_mode == WritingMode::HorizontalTb) {
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::BorderTopLeftRadius;
|
|
||||||
return PropertyID::BorderTopRightRadius;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (first_is_one_of(mapping_context.writing_mode, WritingMode::VerticalRl, WritingMode::SidewaysRl)) {
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::BorderTopRightRadius;
|
|
||||||
return PropertyID::BorderBottomRightRadius;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mapping_context.writing_mode == WritingMode::VerticalLr) {
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::BorderTopLeftRadius;
|
|
||||||
return PropertyID::BorderBottomLeftRadius;
|
|
||||||
}
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::BorderBottomLeftRadius;
|
|
||||||
return PropertyID::BorderTopLeftRadius;
|
|
||||||
case PropertyID::MarginBlockStart:
|
|
||||||
if (mapping_context.writing_mode == WritingMode::HorizontalTb)
|
|
||||||
return PropertyID::MarginTop;
|
|
||||||
if (first_is_one_of(mapping_context.writing_mode, WritingMode::VerticalRl, WritingMode::SidewaysRl))
|
|
||||||
return PropertyID::MarginRight;
|
|
||||||
return PropertyID::MarginLeft;
|
|
||||||
case PropertyID::MarginBlockEnd:
|
|
||||||
if (mapping_context.writing_mode == WritingMode::HorizontalTb)
|
|
||||||
return PropertyID::MarginBottom;
|
|
||||||
if (first_is_one_of(mapping_context.writing_mode, WritingMode::VerticalRl, WritingMode::SidewaysRl))
|
|
||||||
return PropertyID::MarginLeft;
|
|
||||||
return PropertyID::MarginRight;
|
|
||||||
case PropertyID::MarginInlineStart:
|
|
||||||
if (mapping_context.writing_mode == WritingMode::HorizontalTb) {
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::MarginLeft;
|
|
||||||
return PropertyID::MarginRight;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (first_is_one_of(mapping_context.writing_mode, WritingMode::VerticalRl, WritingMode::SidewaysRl, WritingMode::VerticalLr)) {
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::MarginTop;
|
|
||||||
return PropertyID::MarginBottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::MarginBottom;
|
|
||||||
return PropertyID::MarginTop;
|
|
||||||
case PropertyID::MarginInlineEnd:
|
|
||||||
if (mapping_context.writing_mode == WritingMode::HorizontalTb) {
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::MarginRight;
|
|
||||||
return PropertyID::MarginLeft;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (first_is_one_of(mapping_context.writing_mode, WritingMode::VerticalRl, WritingMode::SidewaysRl, WritingMode::VerticalLr)) {
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::MarginBottom;
|
|
||||||
return PropertyID::MarginTop;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::MarginTop;
|
|
||||||
return PropertyID::MarginBottom;
|
|
||||||
case PropertyID::MaxBlockSize:
|
|
||||||
if (mapping_context.writing_mode == WritingMode::HorizontalTb)
|
|
||||||
return PropertyID::MaxHeight;
|
|
||||||
return PropertyID::MaxWidth;
|
|
||||||
case PropertyID::MaxInlineSize:
|
|
||||||
if (mapping_context.writing_mode == WritingMode::HorizontalTb)
|
|
||||||
return PropertyID::MaxWidth;
|
|
||||||
return PropertyID::MaxHeight;
|
|
||||||
case PropertyID::MinBlockSize:
|
|
||||||
if (mapping_context.writing_mode == WritingMode::HorizontalTb)
|
|
||||||
return PropertyID::MinHeight;
|
|
||||||
return PropertyID::MinWidth;
|
|
||||||
case PropertyID::MinInlineSize:
|
|
||||||
if (mapping_context.writing_mode == WritingMode::HorizontalTb)
|
|
||||||
return PropertyID::MinWidth;
|
|
||||||
return PropertyID::MinHeight;
|
|
||||||
case PropertyID::PaddingBlockStart:
|
|
||||||
if (mapping_context.writing_mode == WritingMode::HorizontalTb)
|
|
||||||
return PropertyID::PaddingTop;
|
|
||||||
if (first_is_one_of(mapping_context.writing_mode, WritingMode::VerticalRl, WritingMode::SidewaysRl))
|
|
||||||
return PropertyID::PaddingRight;
|
|
||||||
return PropertyID::PaddingLeft;
|
|
||||||
case PropertyID::PaddingBlockEnd:
|
|
||||||
if (mapping_context.writing_mode == WritingMode::HorizontalTb)
|
|
||||||
return PropertyID::PaddingBottom;
|
|
||||||
if (first_is_one_of(mapping_context.writing_mode, WritingMode::VerticalRl, WritingMode::SidewaysRl))
|
|
||||||
return PropertyID::PaddingLeft;
|
|
||||||
return PropertyID::PaddingRight;
|
|
||||||
case PropertyID::PaddingInlineStart:
|
|
||||||
if (mapping_context.writing_mode == WritingMode::HorizontalTb) {
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::PaddingLeft;
|
|
||||||
return PropertyID::PaddingRight;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (first_is_one_of(mapping_context.writing_mode, WritingMode::VerticalRl, WritingMode::SidewaysRl, WritingMode::VerticalLr)) {
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::PaddingTop;
|
|
||||||
return PropertyID::PaddingBottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::PaddingBottom;
|
|
||||||
return PropertyID::PaddingTop;
|
|
||||||
case PropertyID::PaddingInlineEnd:
|
|
||||||
if (mapping_context.writing_mode == WritingMode::HorizontalTb) {
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::PaddingRight;
|
|
||||||
return PropertyID::PaddingLeft;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (first_is_one_of(mapping_context.writing_mode, WritingMode::VerticalRl, WritingMode::SidewaysRl, WritingMode::VerticalLr)) {
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::PaddingBottom;
|
|
||||||
return PropertyID::PaddingTop;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::PaddingTop;
|
|
||||||
return PropertyID::PaddingBottom;
|
|
||||||
case PropertyID::InlineSize:
|
|
||||||
if (mapping_context.writing_mode == WritingMode::HorizontalTb)
|
|
||||||
return PropertyID::Width;
|
|
||||||
return PropertyID::Height;
|
|
||||||
case PropertyID::InsetBlockStart:
|
|
||||||
if (mapping_context.writing_mode == WritingMode::HorizontalTb)
|
|
||||||
return PropertyID::Top;
|
|
||||||
if (first_is_one_of(mapping_context.writing_mode, WritingMode::VerticalRl, WritingMode::SidewaysRl))
|
|
||||||
return PropertyID::Right;
|
|
||||||
return PropertyID::Left;
|
|
||||||
case PropertyID::InsetBlockEnd:
|
|
||||||
if (mapping_context.writing_mode == WritingMode::HorizontalTb)
|
|
||||||
return PropertyID::Bottom;
|
|
||||||
if (first_is_one_of(mapping_context.writing_mode, WritingMode::VerticalRl, WritingMode::SidewaysRl))
|
|
||||||
return PropertyID::Left;
|
|
||||||
return PropertyID::Right;
|
|
||||||
case PropertyID::InsetInlineStart:
|
|
||||||
if (mapping_context.writing_mode == WritingMode::HorizontalTb) {
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::Left;
|
|
||||||
return PropertyID::Right;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (first_is_one_of(mapping_context.writing_mode, WritingMode::VerticalRl, WritingMode::SidewaysRl, WritingMode::VerticalLr)) {
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::Top;
|
|
||||||
return PropertyID::Bottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::Bottom;
|
|
||||||
return PropertyID::Top;
|
|
||||||
case PropertyID::InsetInlineEnd:
|
|
||||||
if (mapping_context.writing_mode == WritingMode::HorizontalTb) {
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::Right;
|
|
||||||
return PropertyID::Left;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (first_is_one_of(mapping_context.writing_mode, WritingMode::VerticalRl, WritingMode::SidewaysRl, WritingMode::VerticalLr)) {
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::Bottom;
|
|
||||||
return PropertyID::Top;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (used_direction == Direction::Ltr)
|
|
||||||
return PropertyID::Top;
|
|
||||||
return PropertyID::Bottom;
|
|
||||||
default:
|
|
||||||
VERIFY(!property_is_logical_alias(property_id));
|
|
||||||
return property_id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StyleComputer::cascade_declarations(
|
void StyleComputer::cascade_declarations(
|
||||||
CascadedProperties& cascaded_properties,
|
CascadedProperties& cascaded_properties,
|
||||||
DOM::Element& element,
|
DOM::Element& element,
|
||||||
|
@ -1334,7 +945,7 @@ void StyleComputer::cascade_declarations(
|
||||||
if (property_is_logical_alias(longhand_id)) {
|
if (property_is_logical_alias(longhand_id)) {
|
||||||
if (!logical_alias_mapping_context.has_value())
|
if (!logical_alias_mapping_context.has_value())
|
||||||
return;
|
return;
|
||||||
physical_property_id = map_logical_alias_to_physical_property_id(longhand_id, logical_alias_mapping_context.value());
|
physical_property_id = map_logical_alias_to_physical_property(longhand_id, logical_alias_mapping_context.value());
|
||||||
} else {
|
} else {
|
||||||
physical_property_id = longhand_id;
|
physical_property_id = longhand_id;
|
||||||
}
|
}
|
||||||
|
@ -1523,7 +1134,7 @@ void StyleComputer::collect_animation_into(DOM::Element& element, Optional<CSS::
|
||||||
style_value = Parser::Parser::resolve_unresolved_style_value(Parser::ParsingParams { element.document() }, element, pseudo_element, property_id, style_value->as_unresolved());
|
style_value = Parser::Parser::resolve_unresolved_style_value(Parser::ParsingParams { element.document() }, element, pseudo_element, property_id, style_value->as_unresolved());
|
||||||
|
|
||||||
for_each_property_expanding_shorthands(property_id, *style_value, [&](PropertyID longhand_id, CSSStyleValue const& longhand_value) {
|
for_each_property_expanding_shorthands(property_id, *style_value, [&](PropertyID longhand_id, CSSStyleValue const& longhand_value) {
|
||||||
auto physical_longhand_id = map_logical_alias_to_physical_property_id(longhand_id, LogicalAliasMappingContext { computed_properties.writing_mode(), computed_properties.direction() });
|
auto physical_longhand_id = map_logical_alias_to_physical_property(longhand_id, LogicalAliasMappingContext { computed_properties.writing_mode(), computed_properties.direction() });
|
||||||
auto physical_longhand_id_bitmap_index = to_underlying(physical_longhand_id) - to_underlying(first_longhand_property_id);
|
auto physical_longhand_id_bitmap_index = to_underlying(physical_longhand_id) - to_underlying(first_longhand_property_id);
|
||||||
|
|
||||||
// Don't overwrite values if this is the result of a UseInitial
|
// Don't overwrite values if this is the result of a UseInitial
|
||||||
|
@ -2532,7 +2143,7 @@ void StyleComputer::compute_font(ComputedProperties& style, DOM::Element const*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StyleComputer::LogicalAliasMappingContext StyleComputer::compute_logical_alias_mapping_context(DOM::Element& element, Optional<CSS::PseudoElement> pseudo_element, ComputeStyleMode mode) const
|
LogicalAliasMappingContext StyleComputer::compute_logical_alias_mapping_context(DOM::Element& element, Optional<PseudoElement> pseudo_element, ComputeStyleMode mode) const
|
||||||
{
|
{
|
||||||
auto normalize_value = [&](auto property_id, auto value) {
|
auto normalize_value = [&](auto property_id, auto value) {
|
||||||
if (!value || value->is_inherit() || value->is_unset()) {
|
if (!value || value->is_inherit() || value->is_unset()) {
|
||||||
|
|
|
@ -131,13 +131,6 @@ public:
|
||||||
static void for_each_property_expanding_shorthands(PropertyID, CSSStyleValue const&, Function<void(PropertyID, CSSStyleValue const&)> const& set_longhand_property);
|
static void for_each_property_expanding_shorthands(PropertyID, CSSStyleValue const&, Function<void(PropertyID, CSSStyleValue const&)> const& set_longhand_property);
|
||||||
static NonnullRefPtr<CSSStyleValue const> get_inherit_value(CSS::PropertyID, DOM::Element const*, Optional<CSS::PseudoElement> = {});
|
static NonnullRefPtr<CSSStyleValue const> get_inherit_value(CSS::PropertyID, DOM::Element const*, Optional<CSS::PseudoElement> = {});
|
||||||
|
|
||||||
struct LogicalAliasMappingContext {
|
|
||||||
CSS::WritingMode writing_mode;
|
|
||||||
CSS::Direction direction;
|
|
||||||
// TODO: text-orientation
|
|
||||||
};
|
|
||||||
static PropertyID map_logical_alias_to_physical_property_id(PropertyID, LogicalAliasMappingContext);
|
|
||||||
|
|
||||||
static Optional<String> user_agent_style_sheet_source(StringView name);
|
static Optional<String> user_agent_style_sheet_source(StringView name);
|
||||||
|
|
||||||
explicit StyleComputer(DOM::Document&);
|
explicit StyleComputer(DOM::Document&);
|
||||||
|
|
|
@ -44,7 +44,8 @@ function (generate_css_implementation)
|
||||||
"${LIBWEB_INPUT_FOLDER}/CSS/Properties.json"
|
"${LIBWEB_INPUT_FOLDER}/CSS/Properties.json"
|
||||||
"CSS/PropertyID.h"
|
"CSS/PropertyID.h"
|
||||||
"CSS/PropertyID.cpp"
|
"CSS/PropertyID.cpp"
|
||||||
arguments -j "${LIBWEB_INPUT_FOLDER}/CSS/Properties.json"
|
arguments -j "${LIBWEB_INPUT_FOLDER}/CSS/Properties.json" -g "${LIBWEB_INPUT_FOLDER}/CSS/LogicalPropertyGroups.json"
|
||||||
|
dependencies "${LIBWEB_INPUT_FOLDER}/CSS/LogicalPropertyGroups.json"
|
||||||
)
|
)
|
||||||
|
|
||||||
invoke_cpp_generator(
|
invoke_cpp_generator(
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018-2020, Andreas Kling <andreas@ladybird.org>
|
* Copyright (c) 2018-2020, Andreas Kling <andreas@ladybird.org>
|
||||||
* Copyright (c) 2021-2023, Sam Atkins <atkinssj@serenityos.org>
|
* Copyright (c) 2021-2025, Sam Atkins <sam@ladybird.org>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -14,10 +14,10 @@
|
||||||
#include <LibCore/ArgsParser.h>
|
#include <LibCore/ArgsParser.h>
|
||||||
#include <LibMain/Main.h>
|
#include <LibMain/Main.h>
|
||||||
|
|
||||||
void replace_logical_aliases(JsonObject& properties);
|
void replace_logical_aliases(JsonObject& properties, JsonObject& logical_property_groups);
|
||||||
void populate_all_property_longhands(JsonObject& properties);
|
void populate_all_property_longhands(JsonObject& properties);
|
||||||
ErrorOr<void> generate_header_file(JsonObject& properties, Core::File& file);
|
ErrorOr<void> generate_header_file(JsonObject& properties, JsonObject& logical_property_groups, Core::File& file);
|
||||||
ErrorOr<void> generate_implementation_file(JsonObject& properties, Core::File& file);
|
ErrorOr<void> generate_implementation_file(JsonObject& properties, JsonObject& logical_property_groups, Core::File& file);
|
||||||
void generate_bounds_checking_function(JsonObject& properties, SourceGenerator& parent_generator, StringView css_type_name, StringView type_name, Optional<StringView> default_unit_name = {}, Optional<StringView> value_getter = {});
|
void generate_bounds_checking_function(JsonObject& properties, SourceGenerator& parent_generator, StringView css_type_name, StringView type_name, Optional<StringView> default_unit_name = {}, Optional<StringView> value_getter = {});
|
||||||
bool is_animatable_property(JsonObject& properties, StringView property_name);
|
bool is_animatable_property(JsonObject& properties, StringView property_name);
|
||||||
|
|
||||||
|
@ -60,50 +60,79 @@ ErrorOr<int> ladybird_main(Main::Arguments arguments)
|
||||||
StringView generated_header_path;
|
StringView generated_header_path;
|
||||||
StringView generated_implementation_path;
|
StringView generated_implementation_path;
|
||||||
StringView properties_json_path;
|
StringView properties_json_path;
|
||||||
|
StringView groups_json_path;
|
||||||
|
|
||||||
Core::ArgsParser args_parser;
|
Core::ArgsParser args_parser;
|
||||||
args_parser.add_option(generated_header_path, "Path to the PropertyID header file to generate", "generated-header-path", 'h', "generated-header-path");
|
args_parser.add_option(generated_header_path, "Path to the PropertyID header file to generate", "generated-header-path", 'h', "generated-header-path");
|
||||||
args_parser.add_option(generated_implementation_path, "Path to the PropertyID implementation file to generate", "generated-implementation-path", 'c', "generated-implementation-path");
|
args_parser.add_option(generated_implementation_path, "Path to the PropertyID implementation file to generate", "generated-implementation-path", 'c', "generated-implementation-path");
|
||||||
args_parser.add_option(properties_json_path, "Path to the JSON file to read from", "json-path", 'j', "json-path");
|
args_parser.add_option(properties_json_path, "Path to the properties JSON file to read from", "properties-json-path", 'j', "properties-json-path");
|
||||||
|
args_parser.add_option(groups_json_path, "Path to the logical property groups JSON file to read from", "groups-json-path", 'g', "groups-json-path");
|
||||||
args_parser.parse(arguments);
|
args_parser.parse(arguments);
|
||||||
|
|
||||||
auto json = TRY(read_entire_file_as_json(properties_json_path));
|
auto read_json_object = [](auto& path) -> ErrorOr<JsonObject> {
|
||||||
|
auto json = TRY(read_entire_file_as_json(path));
|
||||||
VERIFY(json.is_object());
|
VERIFY(json.is_object());
|
||||||
auto properties = json.as_object();
|
|
||||||
|
|
||||||
// Check we're in alphabetical order
|
// Check we're in alphabetical order
|
||||||
String most_recent_name;
|
String most_recent_name;
|
||||||
properties.for_each_member([&](auto& name, auto&) {
|
json.as_object().for_each_member([&](auto& name, auto&) {
|
||||||
if (name < most_recent_name) {
|
if (name < most_recent_name) {
|
||||||
warnln("`{}` is in the wrong position in `{}`. Please keep this list alphabetical!", name, properties_json_path);
|
warnln("`{}` is in the wrong position in `{}`. Please keep this list alphabetical!", name, path);
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
most_recent_name = name;
|
most_recent_name = name;
|
||||||
});
|
});
|
||||||
|
|
||||||
replace_logical_aliases(properties);
|
return json.as_object();
|
||||||
|
};
|
||||||
|
|
||||||
|
auto properties = TRY(read_json_object(properties_json_path));
|
||||||
|
auto logical_property_groups = TRY(read_json_object(groups_json_path));
|
||||||
|
|
||||||
|
replace_logical_aliases(properties, logical_property_groups);
|
||||||
populate_all_property_longhands(properties);
|
populate_all_property_longhands(properties);
|
||||||
|
|
||||||
auto generated_header_file = TRY(Core::File::open(generated_header_path, Core::File::OpenMode::Write));
|
auto generated_header_file = TRY(Core::File::open(generated_header_path, Core::File::OpenMode::Write));
|
||||||
auto generated_implementation_file = TRY(Core::File::open(generated_implementation_path, Core::File::OpenMode::Write));
|
auto generated_implementation_file = TRY(Core::File::open(generated_implementation_path, Core::File::OpenMode::Write));
|
||||||
|
|
||||||
TRY(generate_header_file(properties, *generated_header_file));
|
TRY(generate_header_file(properties, logical_property_groups, *generated_header_file));
|
||||||
TRY(generate_implementation_file(properties, *generated_implementation_file));
|
TRY(generate_implementation_file(properties, logical_property_groups, *generated_implementation_file));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void replace_logical_aliases(JsonObject& properties)
|
void replace_logical_aliases(JsonObject& properties, JsonObject& logical_property_groups)
|
||||||
{
|
{
|
||||||
AK::HashMap<String, String> logical_aliases;
|
// Grab the first property in each logical group, to use as the template
|
||||||
properties.for_each_member([&](auto& name, auto& value) {
|
HashMap<String, String> first_property_in_logical_group;
|
||||||
|
logical_property_groups.for_each_member([&first_property_in_logical_group](String const& name, JsonValue const& value) {
|
||||||
|
bool found = false;
|
||||||
|
value.as_object().for_each_member([&](String const&, JsonValue const& member_value) {
|
||||||
|
if (found)
|
||||||
|
return;
|
||||||
|
first_property_in_logical_group.set(name, member_value.as_string());
|
||||||
|
found = true;
|
||||||
|
});
|
||||||
|
VERIFY(found);
|
||||||
|
});
|
||||||
|
|
||||||
|
HashMap<String, String> logical_aliases;
|
||||||
|
properties.for_each_member([&](String const& name, JsonValue const& value) {
|
||||||
VERIFY(value.is_object());
|
VERIFY(value.is_object());
|
||||||
auto const& value_as_object = value.as_object();
|
auto const& value_as_object = value.as_object();
|
||||||
auto const logical_alias_for = value_as_object.get_array("logical-alias-for"sv);
|
auto const logical_alias_for = value_as_object.get_object("logical-alias-for"sv);
|
||||||
if (logical_alias_for.has_value()) {
|
if (logical_alias_for.has_value()) {
|
||||||
auto const& aliased_properties = logical_alias_for.value();
|
auto const& group_name = logical_alias_for->get_string("group"sv);
|
||||||
for (auto const& aliased_property : aliased_properties.values()) {
|
if (!group_name.has_value()) {
|
||||||
logical_aliases.set(name, aliased_property.as_string());
|
dbgln("Logical alias '{}' is missing its group", name);
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto physical_property_name = first_property_in_logical_group.get(group_name.value()); physical_property_name.has_value()) {
|
||||||
|
logical_aliases.set(name, physical_property_name.value());
|
||||||
|
} else {
|
||||||
|
dbgln("Logical property group '{}' not found! (Property: '{}')", group_name.value(), name);
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -142,7 +171,7 @@ void populate_all_property_longhands(JsonObject& properties)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<void> generate_header_file(JsonObject& properties, Core::File& file)
|
ErrorOr<void> generate_header_file(JsonObject& properties, JsonObject&, Core::File& file)
|
||||||
{
|
{
|
||||||
StringBuilder builder;
|
StringBuilder builder;
|
||||||
SourceGenerator generator { builder };
|
SourceGenerator generator { builder };
|
||||||
|
@ -154,6 +183,7 @@ ErrorOr<void> generate_header_file(JsonObject& properties, Core::File& file)
|
||||||
#include <AK/StringView.h>
|
#include <AK/StringView.h>
|
||||||
#include <AK/Traits.h>
|
#include <AK/Traits.h>
|
||||||
#include <LibJS/Forward.h>
|
#include <LibJS/Forward.h>
|
||||||
|
#include <LibWeb/CSS/Enums.h>
|
||||||
#include <LibWeb/Forward.h>
|
#include <LibWeb/Forward.h>
|
||||||
|
|
||||||
namespace Web::CSS {
|
namespace Web::CSS {
|
||||||
|
@ -313,7 +343,13 @@ enum class Quirk {
|
||||||
};
|
};
|
||||||
bool property_has_quirk(PropertyID, Quirk);
|
bool property_has_quirk(PropertyID, Quirk);
|
||||||
|
|
||||||
|
struct LogicalAliasMappingContext {
|
||||||
|
WritingMode writing_mode;
|
||||||
|
Direction direction;
|
||||||
|
// TODO: text-orientation
|
||||||
|
};
|
||||||
bool property_is_logical_alias(PropertyID);
|
bool property_is_logical_alias(PropertyID);
|
||||||
|
PropertyID map_logical_alias_to_physical_property(PropertyID logical_property_id, LogicalAliasMappingContext const&);
|
||||||
|
|
||||||
} // namespace Web::CSS
|
} // namespace Web::CSS
|
||||||
|
|
||||||
|
@ -428,7 +464,7 @@ bool property_accepts_@css_type_name@(PropertyID property_id, [[maybe_unused]] @
|
||||||
)~~~");
|
)~~~");
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<void> generate_implementation_file(JsonObject& properties, Core::File& file)
|
ErrorOr<void> generate_implementation_file(JsonObject& properties, JsonObject& logical_property_groups, Core::File& file)
|
||||||
{
|
{
|
||||||
StringBuilder builder;
|
StringBuilder builder;
|
||||||
SourceGenerator generator { builder };
|
SourceGenerator generator { builder };
|
||||||
|
@ -1315,6 +1351,255 @@ bool property_is_logical_alias(PropertyID property_id)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
)~~~");
|
||||||
|
generator.append(R"~~~(
|
||||||
|
PropertyID map_logical_alias_to_physical_property(PropertyID property_id, LogicalAliasMappingContext const& mapping_context)
|
||||||
|
{
|
||||||
|
// https://drafts.csswg.org/css-writing-modes-4/#logical-to-physical
|
||||||
|
// FIXME: Note: The used direction depends on the computed writing-mode and text-orientation: in vertical writing
|
||||||
|
// modes, a text-orientation value of upright forces the used direction to ltr.
|
||||||
|
auto used_direction = mapping_context.direction;
|
||||||
|
switch(property_id) {
|
||||||
|
)~~~");
|
||||||
|
|
||||||
|
properties.for_each_member([&](auto& property_name, JsonValue const& value) {
|
||||||
|
auto& property = value.as_object();
|
||||||
|
if (is_legacy_alias(property))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (auto logical_alias_for = property.get_object("logical-alias-for"sv); logical_alias_for.has_value()) {
|
||||||
|
auto group_name = logical_alias_for->get_string("group"sv);
|
||||||
|
auto mapping = logical_alias_for->get_string("mapping"sv);
|
||||||
|
if (!group_name.has_value() || !mapping.has_value()) {
|
||||||
|
dbgln("Logical alias '{}' is missing either its group or its mapping!", property_name);
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto maybe_group = logical_property_groups.get_object(group_name.value());
|
||||||
|
if (!maybe_group.has_value()) {
|
||||||
|
dbgln("Logical alias '{}' has unrecognized group '{}'", property_name, group_name.value());
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
}
|
||||||
|
auto const& group = maybe_group.value();
|
||||||
|
auto mapped_property = [&](StringView entry_name) {
|
||||||
|
if (auto maybe_string = group.get_string(entry_name); maybe_string.has_value()) {
|
||||||
|
return title_casify(maybe_string.value());
|
||||||
|
}
|
||||||
|
dbgln("Logical property group '{}' is missing entry for '{}', requested by property '{}'.", group_name.value(), entry_name, property_name);
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
};
|
||||||
|
|
||||||
|
auto property_generator = generator.fork();
|
||||||
|
property_generator.set("name:titlecase", title_casify(property_name));
|
||||||
|
property_generator.append(R"~~~(
|
||||||
|
case PropertyID::@name:titlecase@:
|
||||||
|
)~~~");
|
||||||
|
if (mapping == "block-end"sv) {
|
||||||
|
property_generator.set("left:titlecase", mapped_property("left"sv));
|
||||||
|
property_generator.set("right:titlecase", mapped_property("right"sv));
|
||||||
|
property_generator.set("bottom:titlecase", mapped_property("bottom"sv));
|
||||||
|
property_generator.append(R"~~~(
|
||||||
|
if (mapping_context.writing_mode == WritingMode::HorizontalTb)
|
||||||
|
return PropertyID::@bottom:titlecase@;
|
||||||
|
if (first_is_one_of(mapping_context.writing_mode, WritingMode::VerticalRl, WritingMode::SidewaysRl))
|
||||||
|
return PropertyID::@left:titlecase@;
|
||||||
|
return PropertyID::@right:titlecase@;
|
||||||
|
)~~~");
|
||||||
|
} else if (mapping == "block-size"sv) {
|
||||||
|
property_generator.set("height:titlecase", mapped_property("height"sv));
|
||||||
|
property_generator.set("width:titlecase", mapped_property("width"sv));
|
||||||
|
property_generator.append(R"~~~(
|
||||||
|
if (mapping_context.writing_mode == WritingMode::HorizontalTb)
|
||||||
|
return PropertyID::@height:titlecase@;
|
||||||
|
return PropertyID::@width:titlecase@;
|
||||||
|
)~~~");
|
||||||
|
} else if (mapping == "block-start"sv) {
|
||||||
|
property_generator.set("left:titlecase", mapped_property("left"sv));
|
||||||
|
property_generator.set("right:titlecase", mapped_property("right"sv));
|
||||||
|
property_generator.set("top:titlecase", mapped_property("top"sv));
|
||||||
|
property_generator.append(R"~~~(
|
||||||
|
if (mapping_context.writing_mode == WritingMode::HorizontalTb)
|
||||||
|
return PropertyID::@top:titlecase@;
|
||||||
|
if (first_is_one_of(mapping_context.writing_mode, WritingMode::VerticalRl, WritingMode::SidewaysRl))
|
||||||
|
return PropertyID::@right:titlecase@;
|
||||||
|
return PropertyID::@left:titlecase@;
|
||||||
|
)~~~");
|
||||||
|
} else if (mapping == "end-end"sv) {
|
||||||
|
property_generator.set("top-left:titlecase", mapped_property("top-left"sv));
|
||||||
|
property_generator.set("bottom-left:titlecase", mapped_property("bottom-left"sv));
|
||||||
|
property_generator.set("top-right:titlecase", mapped_property("top-right"sv));
|
||||||
|
property_generator.set("bottom-right:titlecase", mapped_property("bottom-right"sv));
|
||||||
|
property_generator.append(R"~~~(
|
||||||
|
if (mapping_context.writing_mode == WritingMode::HorizontalTb) {
|
||||||
|
if (used_direction == Direction::Ltr)
|
||||||
|
return PropertyID::@bottom-right:titlecase@;
|
||||||
|
return PropertyID::@bottom-left:titlecase@;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (first_is_one_of(mapping_context.writing_mode, WritingMode::VerticalRl, WritingMode::SidewaysRl)) {
|
||||||
|
if (used_direction == Direction::Ltr)
|
||||||
|
return PropertyID::@bottom-left:titlecase@;
|
||||||
|
return PropertyID::@top-left:titlecase@;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mapping_context.writing_mode == WritingMode::VerticalLr) {
|
||||||
|
if (used_direction == Direction::Ltr)
|
||||||
|
return PropertyID::@bottom-right:titlecase@;
|
||||||
|
return PropertyID::@top-right:titlecase@;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (used_direction == Direction::Ltr)
|
||||||
|
return PropertyID::@top-right:titlecase@;
|
||||||
|
return PropertyID::@bottom-right:titlecase@;
|
||||||
|
)~~~");
|
||||||
|
} else if (mapping == "end-start"sv) {
|
||||||
|
property_generator.set("top-left:titlecase", mapped_property("top-left"sv));
|
||||||
|
property_generator.set("bottom-left:titlecase", mapped_property("bottom-left"sv));
|
||||||
|
property_generator.set("top-right:titlecase", mapped_property("top-right"sv));
|
||||||
|
property_generator.set("bottom-right:titlecase", mapped_property("bottom-right"sv));
|
||||||
|
property_generator.append(R"~~~(
|
||||||
|
if (mapping_context.writing_mode == WritingMode::HorizontalTb) {
|
||||||
|
if (used_direction == Direction::Ltr)
|
||||||
|
return PropertyID::@bottom-left:titlecase@;
|
||||||
|
return PropertyID::@bottom-right:titlecase@;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (first_is_one_of(mapping_context.writing_mode, WritingMode::VerticalRl, WritingMode::SidewaysRl)) {
|
||||||
|
if (used_direction == Direction::Ltr)
|
||||||
|
return PropertyID::@top-left:titlecase@;
|
||||||
|
return PropertyID::@bottom-left:titlecase@;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mapping_context.writing_mode == WritingMode::VerticalLr) {
|
||||||
|
if (used_direction == Direction::Ltr)
|
||||||
|
return PropertyID::@top-right:titlecase@;
|
||||||
|
return PropertyID::@bottom-right:titlecase@;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (used_direction == Direction::Ltr)
|
||||||
|
return PropertyID::@bottom-right:titlecase@;
|
||||||
|
return PropertyID::@top-right:titlecase@;
|
||||||
|
)~~~");
|
||||||
|
} else if (mapping == "inline-end"sv) {
|
||||||
|
property_generator.set("left:titlecase", mapped_property("left"sv));
|
||||||
|
property_generator.set("right:titlecase", mapped_property("right"sv));
|
||||||
|
property_generator.set("top:titlecase", mapped_property("top"sv));
|
||||||
|
property_generator.set("bottom:titlecase", mapped_property("bottom"sv));
|
||||||
|
property_generator.append(R"~~~(
|
||||||
|
if (mapping_context.writing_mode == WritingMode::HorizontalTb) {
|
||||||
|
if (used_direction == Direction::Ltr)
|
||||||
|
return PropertyID::@right:titlecase@;
|
||||||
|
return PropertyID::@left:titlecase@;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (first_is_one_of(mapping_context.writing_mode, WritingMode::VerticalRl, WritingMode::SidewaysRl, WritingMode::VerticalLr)) {
|
||||||
|
if (used_direction == Direction::Ltr)
|
||||||
|
return PropertyID::@bottom:titlecase@;
|
||||||
|
return PropertyID::@top:titlecase@;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (used_direction == Direction::Ltr)
|
||||||
|
return PropertyID::@top:titlecase@;
|
||||||
|
return PropertyID::@bottom:titlecase@;
|
||||||
|
)~~~");
|
||||||
|
} else if (mapping == "inline-size"sv) {
|
||||||
|
property_generator.set("height:titlecase", mapped_property("height"sv));
|
||||||
|
property_generator.set("width:titlecase", mapped_property("width"sv));
|
||||||
|
property_generator.append(R"~~~(
|
||||||
|
if (mapping_context.writing_mode == WritingMode::HorizontalTb)
|
||||||
|
return PropertyID::@width:titlecase@;
|
||||||
|
return PropertyID::@height:titlecase@;
|
||||||
|
)~~~");
|
||||||
|
} else if (mapping == "inline-start"sv) {
|
||||||
|
property_generator.set("left:titlecase", mapped_property("left"sv));
|
||||||
|
property_generator.set("right:titlecase", mapped_property("right"sv));
|
||||||
|
property_generator.set("top:titlecase", mapped_property("top"sv));
|
||||||
|
property_generator.set("bottom:titlecase", mapped_property("bottom"sv));
|
||||||
|
property_generator.append(R"~~~(
|
||||||
|
if (mapping_context.writing_mode == WritingMode::HorizontalTb) {
|
||||||
|
if (used_direction == Direction::Ltr)
|
||||||
|
return PropertyID::@left:titlecase@;
|
||||||
|
return PropertyID::@right:titlecase@;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (first_is_one_of(mapping_context.writing_mode, WritingMode::VerticalRl, WritingMode::SidewaysRl, WritingMode::VerticalLr)) {
|
||||||
|
if (used_direction == Direction::Ltr)
|
||||||
|
return PropertyID::@top:titlecase@;
|
||||||
|
return PropertyID::@bottom:titlecase@;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (used_direction == Direction::Ltr)
|
||||||
|
return PropertyID::@bottom:titlecase@;
|
||||||
|
return PropertyID::@top:titlecase@;
|
||||||
|
)~~~");
|
||||||
|
} else if (mapping == "start-end"sv) {
|
||||||
|
property_generator.set("top-left:titlecase", mapped_property("top-left"sv));
|
||||||
|
property_generator.set("bottom-left:titlecase", mapped_property("bottom-left"sv));
|
||||||
|
property_generator.set("top-right:titlecase", mapped_property("top-right"sv));
|
||||||
|
property_generator.set("bottom-right:titlecase", mapped_property("bottom-right"sv));
|
||||||
|
property_generator.append(R"~~~(
|
||||||
|
if (mapping_context.writing_mode == WritingMode::HorizontalTb) {
|
||||||
|
if (used_direction == Direction::Ltr)
|
||||||
|
return PropertyID::@top-right:titlecase@;
|
||||||
|
return PropertyID::@top-left:titlecase@;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (first_is_one_of(mapping_context.writing_mode, WritingMode::VerticalRl, WritingMode::SidewaysRl)) {
|
||||||
|
if (used_direction == Direction::Ltr)
|
||||||
|
return PropertyID::@bottom-right:titlecase@;
|
||||||
|
return PropertyID::@top-right:titlecase@;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mapping_context.writing_mode == WritingMode::VerticalLr) {
|
||||||
|
if (used_direction == Direction::Ltr)
|
||||||
|
return PropertyID::@bottom-left:titlecase@;
|
||||||
|
return PropertyID::@top-left:titlecase@;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (used_direction == Direction::Ltr)
|
||||||
|
return PropertyID::@top-left:titlecase@;
|
||||||
|
return PropertyID::@bottom-left:titlecase@;
|
||||||
|
)~~~");
|
||||||
|
} else if (mapping == "start-start"sv) {
|
||||||
|
property_generator.set("top-left:titlecase", mapped_property("top-left"sv));
|
||||||
|
property_generator.set("bottom-left:titlecase", mapped_property("bottom-left"sv));
|
||||||
|
property_generator.set("top-right:titlecase", mapped_property("top-right"sv));
|
||||||
|
property_generator.set("bottom-right:titlecase", mapped_property("bottom-right"sv));
|
||||||
|
property_generator.append(R"~~~(
|
||||||
|
if (mapping_context.writing_mode == WritingMode::HorizontalTb) {
|
||||||
|
if (used_direction == Direction::Ltr)
|
||||||
|
return PropertyID::@top-left:titlecase@;
|
||||||
|
return PropertyID::@top-right:titlecase@;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (first_is_one_of(mapping_context.writing_mode, WritingMode::VerticalRl, WritingMode::SidewaysRl)) {
|
||||||
|
if (used_direction == Direction::Ltr)
|
||||||
|
return PropertyID::@top-right:titlecase@;
|
||||||
|
return PropertyID::@bottom-right:titlecase@;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mapping_context.writing_mode == WritingMode::VerticalLr) {
|
||||||
|
if (used_direction == Direction::Ltr)
|
||||||
|
return PropertyID::@top-left:titlecase@;
|
||||||
|
return PropertyID::@bottom-left:titlecase@;
|
||||||
|
}
|
||||||
|
if (used_direction == Direction::Ltr)
|
||||||
|
return PropertyID::@bottom-left:titlecase@;
|
||||||
|
return PropertyID::@top-left:titlecase@;
|
||||||
|
)~~~");
|
||||||
|
} else {
|
||||||
|
dbgln("Logical alias '{}' has unrecognized mapping '{}'", property_name, mapping.value());
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
generator.append(R"~~~(
|
||||||
|
default:
|
||||||
|
VERIFY(!property_is_logical_alias(property_id));
|
||||||
|
return property_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
)~~~");
|
)~~~");
|
||||||
|
|
||||||
generator.append(R"~~~(
|
generator.append(R"~~~(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue