diff --git a/Documentation/Browser/CSSGeneratedFiles.md b/Documentation/Browser/CSSGeneratedFiles.md new file mode 100644 index 00000000000..e92e7348a94 --- /dev/null +++ b/Documentation/Browser/CSSGeneratedFiles.md @@ -0,0 +1,170 @@ +# CSS Generated Files + +We generate a significant amount of CSS-related code, taking in one or more .json files in +[`Userland/Libraries/LibWeb/CSS`](../../Userland/Libraries/LibWeb/CSS) and producing C++ code from them, located in +`Build//Lagom/Userland/Libraries/LibWeb/CSS/`. +It's likely that you'll need to work with these if you add or modify a CSS property or its values. + +The generators are found in [`Meta/Lagom/Tools/CodeGenerators/LibWeb`](../../Meta/Lagom/Tools/CodeGenerators/LibWeb). +They are run automatically as part of the build, and most of the time you can ignore them. + +## Properties.json + +Each CSS property has an entry here, which describes what values it accepts, whether it's inherited, and similar data. +This generates `PropertyID.h` and `PropertyID.cpp`. +Most of this data is found in the information box for that property in the relevant CSS spec. + +The file is organized as a single JSON object, with keys being property names, and the values being the data for that property. +Each property will have some set of these fields on it: + +| 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-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)` | +| `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 property_initial_value(JS::Realm&, PropertyID)` | +| `logical-alias-for` | No | Nothing | String. The name of a property this is an alias for. | | +| `longhands` | No | `[]` | Array of strings. If this is a shorthand, these are the property names that it expands out into. | `Vector longhands_for_shorthand(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 property_resolves_percentages_relative_to(PropertyID)` | +| `quirks` | No | `[]` | Array of strings. Some properties have special behavior in "quirks mode", which are listed here. See below. | `bool property_has_quirk(PropertyID, Quirk)` | +| `valid-identifiers` | No | `[]` | Array of strings. Which keywords the property accepts. Consider defining an enum instead and putting its name in the `valid-types` array. | `bool property_accepts_keyword(PropertyID, Keyword)` | +| `valid-types` | No | `[]` | Array of strings. Which value types the property accepts. See below. | `bool property_accepts_type(PropertyID, ValueType)` | + +### `animation-type` + +The [Web Animations spec](https://www.w3.org/TR/web-animations/#animation-type) defines the valid values here: + +| Spec term | JSON value | +|-------------------|---------------------| +| not animatable | `none` | +| discrete | `discrete` | +| by computed value | `by-computed-value` | +| repeatable list | `repeatable-list` | +| (See prose) | `custom` | + +### `quirks` + +The [Quirks spec](https://quirks.spec.whatwg.org/#css) defines these. + +| Spec term | JSON value | +|------------------------------|----------------------| +| The hashless hex color quirk | `hashless-hex-color` | +| The unitless length quirk | `unitless-length` | + +### `valid-types` + +The `valid-types` array lists the names of CSS value types, as defined in the latest +[CSS Values and Units spec](https://www.w3.org/TR/css-values/), without the `<>` around them. +For numeric types, we use the [bracketed range notation](https://www.w3.org/TR/css-values-4/#css-bracketed-range-notation), +for example `width` can take any non-negative length, so it has `"length [0,∞]"` in its `valid-types` array. + +## Keywords.json + +This is a single JSON array of strings, each of which is a CSS keyword, for example `auto`, `none`, `medium`, or `currentcolor`. +This generates `Keyword.h` and `Keyword.cpp`. +All keyword values used by any property or media-feature need to be defined here. + +The generated code provides: +- A `Keyword` enum as used by `CSSKeywordValue` +- `Optional keyword_from_string(StringView)` to attempt to convert a string into a Keyword +- `StringView string_from_keyword(Keyword)` to convert a Keyword back into a string +- `bool is_css_wide_keyword(StringView)` which returns whether the string is one of the special "CSS-wide keywords" + +## Enums.json + +This is a single JSON object, with enum names as keys and the values being arrays of keyword names. +This generates `Enums.h` and `Enums.cpp`. + +We often want to define an enum that's a set of a few keywords. +`Enums.json` allows you to generate these enums automatically, along with functions to convert them to and from a Keyword, +or convert them to a string. +These enums also can be used in property definitions in `Properties.json` by putting their name in the `valid-types` array. +This helps reduce repetition, for example the `border-*-style` properties all accept the same set of keywords, so they +are implemented as a `line-style` enum. + +The generated code provides these for each enum, using "foo" as an example: +- A `Foo` enum for its values +- `Optional keyword_to_foo(Keyword)` to convert a `Keyword` to a `Foo` +- `Keyword to_keyword(Foo)` to convert the `Foo` back to a `Keyword` +- `StringView to_string(Foo)` to convert the `Foo` directly to a string + +## PseudoClasses.json + +This is a single JSON object, with selector pseudo-class names as keys and the values being objects with fields for the pseudo-class. +This generates `PseudoClass.h` and `PseudoClass.cpp`. + +Each entry has a single required property, `argument`, which is a string containing the grammar for the pseudo-class's +function parameters - for identifier-style pseudo-classes it is left blank. +The grammar is taken directly from the spec. + +The generated code provides: +- A `PseudoClass` enum listing every pseudo-class name +- `Optional pseudo_class_from_string(StringView)` to parse a string as a `PseudoClass` name +- `StringView pseudo_class_name(PseudoClass)` to convert a `PseudoClass` back into a string +- The `PseudoClassMetadata` struct which holds a representation of the data from the JSON file +- `PseudoClassMetadata pseudo_class_metadata(PseudoClass)` to retrieve that data + +## MediaFeatures.json + +This is a single JSON object, with media-feature names as keys and the values being objects with fields for the media-feature. +This generates `MediaFeatureID.h` and `MediaFeatureID.cpp`. + +A `` is a value that a media query can inspect. +They are listed in the [`@media` descriptor table](https://www.w3.org/TR/mediaqueries-5/#media-descriptor-table) in the latest Media Queries spec. + +The definitions here are like a simplified version of the `Properties.json` definitions. + +| Field | Description | +|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `type` | String. How the media-feature is evaluated, either `discrete` or `range`. | +| `values` | Array of strings. These are directly taken from the spec, with keywords as they are, and `<>` around type names. Types may be ``, ``, ``, ``, or ``. | + +The generated code provides: +- A `MediaFeatureValueType` enum listing the possible value types +- A `MediaFeatureID` enum, listing each media-feature +- `Optional media_feature_id_from_string(StringView)` to convert a string to a `MediaFeatureID` +- `StringView string_from_media_feature_id(MediaFeatureID)` to convert a `MediaFeatureID` back to a string +- `bool media_feature_type_is_range(MediaFeatureID)` returns whether the media feature is a `range` type, as opposed to a `discrete` type +- `bool media_feature_accepts_type(MediaFeatureID, MediaFeatureValueType)` returns whether the media feature will accept values of this type +- `bool media_feature_accepts_keyword(MediaFeatureID, Keyword)` returns whether the media feature accepts this keyword + +## MathFunctions.json + +This is a single JSON object, describing each [CSS math function](https://www.w3.org/TR/css-values/#math-function), +with the keys being the function name and the values being objects describing that function's properties. +This generates `MathFunctions.h` and `MathFunctions.cpp`. + +Each entry currently has a single property, `parameters`, which is an array of parameter definition objects. +Parameter definitions have the following properties: + +| Field | Description | +|------------|----------------------------------------------------------------------------------| +| `name` | String. Name of the parameter, as given in the spec. | +| `type` | String. Accepted types for the parameter, as a single string, separated by `\|`. | +| `required` | Boolean. Whether this parameter is required. | + +The generated code provides: +- A `MathFunction` enum listing the math functions +- The implementation of the CSS Parser's `parse_math_function()` method + +## TransformFunctions.json + +This is a single JSON object, describing each [CSS transform function](https://www.w3.org/TR/css-transforms/#transform-functions), +with the keys being the function name and the values being objects describing that function's properties. +This generates `TransformFunctions.h` and `TransformFunctions.cpp`. + +Each entry currently has a single property, `parameters`, which is an array of parameter definition objects. +Parameter definitions have the following properties: + +| Field | Description | +|------------|----------------------------------------------| +| `type` | String. Accepted type for the parameter. | +| `required` | Boolean. Whether this parameter is required. | + +The generated code provides: +- A `TransformFunction` enum listing the transform functions +- `Optional transform_function_from_string(StringView)` to parse a string as a `TransformFunction` +- `StringView to_string(TransformFunction)` to convert a `TransformFunction` back to a string +- `TransformFunctionMetadata transform_function_metadata(TransformFunction)` to obtain metadata about the transform function, such as its parameter list diff --git a/Documentation/README.md b/Documentation/README.md index 59f8c52b13e..2c70a046e97 100644 --- a/Documentation/README.md +++ b/Documentation/README.md @@ -36,4 +36,4 @@ you are welcome to ask on [Discord](../README.md#get-in-touch-and-participate). * [LibWeb: From Loading to Painting](Browser/LibWebFromLoadingToPainting.md) * [How to Add an IDL File](Browser/AddNewIDLFile.md) * [LibWeb Code Style & Patterns](Browser/Patterns.md) - +* [CSS Generated Files](Browser/CSSGeneratedFiles.md)