Skip to content

Commit

Permalink
LibWeb/CSS: Use CSSNumericType for CalculationResult's numeric type
Browse files Browse the repository at this point in the history
When we originally implemented calc(), the result of a calculation was
guaranteed to be a single CSS type like a Length or Angle. However, CSS
Values 4 now allows more complex type arithmetic, which is represented
by the CSSNumericType class. Using that directly makes us more correct,
and allows us to remove a large amount of now ad-hoc code.

Unfortunately this is a large commit but the changes it makes are
interconnected enough that doing one at a time causes test
regressions.

In no particular order:

- Update our "determine the type of a calculation" code to match the
  newest spec, which sets percent hints in a couple more cases. (One of
  these we're skipping for now, I think it fails because of the FIXMEs
  in CSSNumericType::matches_foo().)
- Make the generated math-function-parsing code aware of the difference
  between arguments being the same type, and being "consistent" types,
  for each function. Otherwise those extra percent hints would cause
  them to fail validation incorrectly.
- Use the CSSNumericType as the type for the CalculationResult.
- Calculate and assign each math function's type in its constructor,
  instead of calculating it repeatedly on-demand.

The `CalculationNode::resolved_type()` method is now entirely unused and
has been removed.
  • Loading branch information
AtkinsSJ authored and awesomekling committed Dec 21, 2024
1 parent 8d40550 commit eb11c35
Show file tree
Hide file tree
Showing 7 changed files with 439 additions and 1,161 deletions.
8 changes: 7 additions & 1 deletion Documentation/CSSGeneratedFiles.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,13 @@ This is a single JSON object, describing each [CSS math function](https://www.w3
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.
Each entry has two properties:

| Field | Description |
|------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `parameter-validation` | Optional string. Either "same" or "consistent", depending on whether the spec says the input calculations should be the same type or consistent types. Defaults to "same". Ignore this if there is only one parameter. |
| `parameters` | An array of parameter definition objects, see below. |

Parameter definitions have the following properties:

| Field | Description |
Expand Down
10 changes: 10 additions & 0 deletions Libraries/LibWeb/CSS/MathFunctions.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
]
},
"atan2": {
"parameter-validation": "consistent",
"parameters": [
{
"name": "y",
Expand All @@ -50,6 +51,7 @@
]
},
"clamp": {
"parameter-validation": "consistent",
"parameters": [
{
"name": "min",
Expand Down Expand Up @@ -87,6 +89,7 @@
]
},
"hypot": {
"parameter-validation": "consistent",
"is-variadic": true,
"parameters": [
{
Expand All @@ -97,6 +100,7 @@
]
},
"log": {
"parameter-validation": "same",
"parameters": [
{
"name": "value",
Expand All @@ -112,6 +116,7 @@
]
},
"max": {
"parameter-validation": "consistent",
"is-variadic": true,
"parameters": [
{
Expand All @@ -122,6 +127,7 @@
]
},
"min": {
"parameter-validation": "consistent",
"is-variadic": true,
"parameters": [
{
Expand All @@ -132,6 +138,7 @@
]
},
"mod": {
"parameter-validation": "same",
"parameters": [
{
"name": "value",
Expand All @@ -146,6 +153,7 @@
]
},
"pow": {
"parameter-validation": "consistent",
"parameters": [
{
"name": "value",
Expand All @@ -160,6 +168,7 @@
]
},
"rem": {
"parameter-validation": "same",
"parameters": [
{
"name": "value",
Expand All @@ -174,6 +183,7 @@
]
},
"round": {
"parameter-validation": "consistent",
"parameters": [
{
"name": "strategy",
Expand Down
13 changes: 8 additions & 5 deletions Libraries/LibWeb/CSS/Parser/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1924,7 +1924,7 @@ RefPtr<CalculatedStyleValue> Parser::parse_calculated_value(ComponentValue const
if (!function_node)
return nullptr;

auto function_type = function_node->determine_type(m_context.current_property_id());
auto function_type = function_node->numeric_type();
if (!function_type.has_value())
return nullptr;

Expand All @@ -1936,7 +1936,7 @@ OwnPtr<CalculationNode> Parser::parse_a_calc_function_node(Function const& funct
if (function.name.equals_ignoring_ascii_case("calc"sv))
return parse_a_calculation(function.value);

if (auto maybe_function = parse_math_function(m_context.current_property_id(), function))
if (auto maybe_function = parse_math_function(function))
return maybe_function;

return nullptr;
Expand Down Expand Up @@ -9158,15 +9158,18 @@ OwnPtr<CalculationNode> Parser::convert_to_calculation_node(CalcParsing::Node co
[](Number const& number) -> OwnPtr<CalculationNode> {
return NumericCalculationNode::create(number);
},
[](Dimension const& dimension) -> OwnPtr<CalculationNode> {
[this](Dimension const& dimension) -> OwnPtr<CalculationNode> {
if (dimension.is_angle())
return NumericCalculationNode::create(dimension.angle());
if (dimension.is_frequency())
return NumericCalculationNode::create(dimension.frequency());
if (dimension.is_length())
return NumericCalculationNode::create(dimension.length());
if (dimension.is_percentage())
return NumericCalculationNode::create(dimension.percentage());
if (dimension.is_percentage()) {
// FIXME: Figure this out in non-property contexts
auto percentage_resolved_type = property_resolves_percentages_relative_to(m_context.current_property_id());
return NumericCalculationNode::create(dimension.percentage(), percentage_resolved_type);
}
if (dimension.is_resolution())
return NumericCalculationNode::create(dimension.resolution());
if (dimension.is_time())
Expand Down
2 changes: 1 addition & 1 deletion Libraries/LibWeb/CSS/Parser/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ class Parser {
RefPtr<CalculatedStyleValue> parse_calculated_value(ComponentValue const&);
RefPtr<CustomIdentStyleValue> parse_custom_ident_value(TokenStream<ComponentValue>&, std::initializer_list<StringView> blacklist);
// NOTE: Implemented in generated code. (GenerateCSSMathFunctions.cpp)
OwnPtr<CalculationNode> parse_math_function(PropertyID, Function const&);
OwnPtr<CalculationNode> parse_math_function(Function const&);
OwnPtr<CalculationNode> parse_a_calc_function_node(Function const&);
RefPtr<CSSStyleValue> parse_keyword_value(TokenStream<ComponentValue>&);
RefPtr<CSSStyleValue> parse_hue_none_value(TokenStream<ComponentValue>&);
Expand Down
Loading

0 comments on commit eb11c35

Please sign in to comment.