LibWeb/CSS: Use CSSNumericType for CalculationResult's numeric type

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.
This commit is contained in:
Sam Atkins 2024-12-18 13:15:26 +00:00 committed by Andreas Kling
commit eb11c35640
Notes: github-actions[bot] 2024-12-21 17:15:19 +00:00
7 changed files with 446 additions and 1168 deletions

View file

@ -1,7 +1,7 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <andreas@ladybird.org>
* Copyright (c) 2021, Tobias Christiansen <tobyase@serenityos.org>
* Copyright (c) 2021-2023, Sam Atkins <atkinssj@serenityos.org>
* Copyright (c) 2021-2024, Sam Atkins <sam@ladybird.org>
* Copyright (c) 2022-2023, MacDue <macdue@dueutil.tech>
*
* SPDX-License-Identifier: BSD-2-Clause
@ -26,32 +26,19 @@ class CalculationNode;
class CalculatedStyleValue : public CSSStyleValue {
public:
enum class ResolvedType {
Angle,
Flex,
Frequency,
Integer,
Length,
Number,
Percentage,
Resolution,
Time,
};
enum class SumOperation {
Add,
Subtract,
};
using PercentageBasis = Variant<Empty, Angle, Flex, Frequency, Length, Time>;
class CalculationResult {
public:
using Value = Variant<Number, Angle, Flex, Frequency, Length, Percentage, Resolution, Time>;
CalculationResult(Value value)
: m_value(move(value))
static CalculationResult from_value(Value const&, Optional<Length::ResolutionContext const&>, Optional<CSSNumericType>);
CalculationResult(double value, Optional<CSSNumericType> type)
: m_value(value)
, m_type(move(type))
{
}
void add(CalculationResult const& other, Optional<Length::ResolutionContext const&>, PercentageBasis const& percentage_basis);
void subtract(CalculationResult const& other, Optional<Length::ResolutionContext const&>, PercentageBasis const& percentage_basis);
void multiply_by(CalculationResult const& other, Optional<Length::ResolutionContext const&>);
@ -59,15 +46,14 @@ public:
void negate();
void invert();
Value const& value() const { return m_value; }
ResolvedType resolved_type() const;
double value() const { return m_value; }
Optional<CSSNumericType> const& type() const { return m_type; }
[[nodiscard]] bool operator==(CalculationResult const&) const = default;
private:
void add_or_subtract_internal(SumOperation op, CalculationResult const& other, Optional<Length::ResolutionContext const&>, PercentageBasis const& percentage_basis);
Value m_value;
double m_value;
Optional<CSSNumericType> m_type;
};
static ValueComparingNonnullRefPtr<CalculatedStyleValue> create(NonnullOwnPtr<CalculationNode> calculation, CSSNumericType resolved_type)
@ -256,37 +242,35 @@ public:
}
virtual String to_string() const = 0;
virtual Optional<CalculatedStyleValue::ResolvedType> resolved_type() const = 0;
virtual Optional<CSSNumericType> determine_type(PropertyID) const = 0;
Optional<CSSNumericType> const& numeric_type() const { return m_numeric_type; }
virtual bool contains_percentage() const = 0;
virtual CalculatedStyleValue::CalculationResult resolve(Optional<Length::ResolutionContext const&>, CalculatedStyleValue::PercentageBasis const&) const = 0;
virtual void dump(StringBuilder&, int indent) const = 0;
virtual bool equals(CalculationNode const&) const = 0;
protected:
explicit CalculationNode(Type);
CalculationNode(Type, Optional<CSSNumericType>);
private:
Type m_type;
Optional<CSSNumericType> m_numeric_type;
};
class NumericCalculationNode final : public CalculationNode {
public:
static NonnullOwnPtr<NumericCalculationNode> create(NumericValue);
static NonnullOwnPtr<NumericCalculationNode> create(NumericValue, Optional<ValueType> percentage_resolved_type = {});
~NumericCalculationNode();
virtual String to_string() const override;
virtual Optional<CalculatedStyleValue::ResolvedType> resolved_type() const override;
virtual Optional<CSSNumericType> determine_type(PropertyID) const override;
virtual bool contains_percentage() const override;
virtual CalculatedStyleValue::CalculationResult resolve(Optional<Length::ResolutionContext const&>, CalculatedStyleValue::PercentageBasis const&) const override;
virtual void dump(StringBuilder&, int indent) const override;
virtual bool equals(CalculationNode const&) const override;
private:
explicit NumericCalculationNode(NumericValue);
NumericCalculationNode(NumericValue, CSSNumericType);
NumericValue m_value;
};
@ -296,16 +280,14 @@ public:
~SumCalculationNode();
virtual String to_string() const override;
virtual Optional<CalculatedStyleValue::ResolvedType> resolved_type() const override;
virtual Optional<CSSNumericType> determine_type(PropertyID) const override;
virtual bool contains_percentage() const override;
virtual CalculatedStyleValue::CalculationResult resolve(Optional<Length::ResolutionContext const&>, CalculatedStyleValue::PercentageBasis const&) const override;
virtual void dump(StringBuilder&, int indent) const override;
virtual bool equals(CalculationNode const&) const override;
private:
explicit SumCalculationNode(Vector<NonnullOwnPtr<CalculationNode>>);
SumCalculationNode(Vector<NonnullOwnPtr<CalculationNode>>, Optional<CSSNumericType>);
Vector<NonnullOwnPtr<CalculationNode>> m_values;
};
@ -315,16 +297,14 @@ public:
~ProductCalculationNode();
virtual String to_string() const override;
virtual Optional<CalculatedStyleValue::ResolvedType> resolved_type() const override;
virtual Optional<CSSNumericType> determine_type(PropertyID) const override;
virtual bool contains_percentage() const override;
virtual CalculatedStyleValue::CalculationResult resolve(Optional<Length::ResolutionContext const&>, CalculatedStyleValue::PercentageBasis const&) const override;
virtual void dump(StringBuilder&, int indent) const override;
virtual bool equals(CalculationNode const&) const override;
private:
explicit ProductCalculationNode(Vector<NonnullOwnPtr<CalculationNode>>);
ProductCalculationNode(Vector<NonnullOwnPtr<CalculationNode>>, Optional<CSSNumericType>);
Vector<NonnullOwnPtr<CalculationNode>> m_values;
};
@ -334,16 +314,14 @@ public:
~NegateCalculationNode();
virtual String to_string() const override;
virtual Optional<CalculatedStyleValue::ResolvedType> resolved_type() const override;
virtual Optional<CSSNumericType> determine_type(PropertyID) const override;
virtual bool contains_percentage() const override;
virtual CalculatedStyleValue::CalculationResult resolve(Optional<Length::ResolutionContext const&>, CalculatedStyleValue::PercentageBasis const&) const override;
virtual void dump(StringBuilder&, int indent) const override;
virtual bool equals(CalculationNode const&) const override;
private:
explicit NegateCalculationNode(NonnullOwnPtr<CalculationNode>);
NegateCalculationNode(NonnullOwnPtr<CalculationNode>);
NonnullOwnPtr<CalculationNode> m_value;
};
@ -353,16 +331,14 @@ public:
~InvertCalculationNode();
virtual String to_string() const override;
virtual Optional<CalculatedStyleValue::ResolvedType> resolved_type() const override;
virtual Optional<CSSNumericType> determine_type(PropertyID) const override;
virtual bool contains_percentage() const override;
virtual CalculatedStyleValue::CalculationResult resolve(Optional<Length::ResolutionContext const&>, CalculatedStyleValue::PercentageBasis const&) const override;
virtual void dump(StringBuilder&, int indent) const override;
virtual bool equals(CalculationNode const&) const override;
private:
explicit InvertCalculationNode(NonnullOwnPtr<CalculationNode>);
InvertCalculationNode(NonnullOwnPtr<CalculationNode>, Optional<CSSNumericType>);
NonnullOwnPtr<CalculationNode> m_value;
};
@ -372,8 +348,6 @@ public:
~MinCalculationNode();
virtual String to_string() const override;
virtual Optional<CalculatedStyleValue::ResolvedType> resolved_type() const override;
virtual Optional<CSSNumericType> determine_type(PropertyID) const override;
virtual bool contains_percentage() const override;
virtual CalculatedStyleValue::CalculationResult resolve(Optional<Length::ResolutionContext const&>, CalculatedStyleValue::PercentageBasis const&) const override;
@ -381,7 +355,7 @@ public:
virtual bool equals(CalculationNode const&) const override;
private:
explicit MinCalculationNode(Vector<NonnullOwnPtr<CalculationNode>>);
MinCalculationNode(Vector<NonnullOwnPtr<CalculationNode>>, Optional<CSSNumericType>);
Vector<NonnullOwnPtr<CalculationNode>> m_values;
};
@ -391,16 +365,14 @@ public:
~MaxCalculationNode();
virtual String to_string() const override;
virtual Optional<CalculatedStyleValue::ResolvedType> resolved_type() const override;
virtual Optional<CSSNumericType> determine_type(PropertyID) const override;
virtual bool contains_percentage() const override;
virtual CalculatedStyleValue::CalculationResult resolve(Optional<Length::ResolutionContext const&>, CalculatedStyleValue::PercentageBasis const&) const override;
virtual void dump(StringBuilder&, int indent) const override;
virtual bool equals(CalculationNode const&) const override;
private:
explicit MaxCalculationNode(Vector<NonnullOwnPtr<CalculationNode>>);
MaxCalculationNode(Vector<NonnullOwnPtr<CalculationNode>>, Optional<CSSNumericType>);
Vector<NonnullOwnPtr<CalculationNode>> m_values;
};
@ -410,8 +382,6 @@ public:
~ClampCalculationNode();
virtual String to_string() const override;
virtual Optional<CalculatedStyleValue::ResolvedType> resolved_type() const override;
virtual Optional<CSSNumericType> determine_type(PropertyID) const override;
virtual bool contains_percentage() const override;
virtual CalculatedStyleValue::CalculationResult resolve(Optional<Length::ResolutionContext const&>, CalculatedStyleValue::PercentageBasis const&) const override;
@ -419,7 +389,7 @@ public:
virtual bool equals(CalculationNode const&) const override;
private:
explicit ClampCalculationNode(NonnullOwnPtr<CalculationNode>, NonnullOwnPtr<CalculationNode>, NonnullOwnPtr<CalculationNode>);
ClampCalculationNode(NonnullOwnPtr<CalculationNode>, NonnullOwnPtr<CalculationNode>, NonnullOwnPtr<CalculationNode>, Optional<CSSNumericType>);
NonnullOwnPtr<CalculationNode> m_min_value;
NonnullOwnPtr<CalculationNode> m_center_value;
NonnullOwnPtr<CalculationNode> m_max_value;
@ -431,8 +401,6 @@ public:
~AbsCalculationNode();
virtual String to_string() const override;
virtual Optional<CalculatedStyleValue::ResolvedType> resolved_type() const override;
virtual Optional<CSSNumericType> determine_type(PropertyID) const override;
virtual bool contains_percentage() const override;
virtual CalculatedStyleValue::CalculationResult resolve(Optional<Length::ResolutionContext const&>, CalculatedStyleValue::PercentageBasis const&) const override;
@ -450,8 +418,6 @@ public:
~SignCalculationNode();
virtual String to_string() const override;
virtual Optional<CalculatedStyleValue::ResolvedType> resolved_type() const override;
virtual Optional<CSSNumericType> determine_type(PropertyID) const override;
virtual bool contains_percentage() const override;
virtual CalculatedStyleValue::CalculationResult resolve(Optional<Length::ResolutionContext const&>, CalculatedStyleValue::PercentageBasis const&) const override;
@ -469,8 +435,6 @@ public:
~ConstantCalculationNode();
virtual String to_string() const override;
virtual Optional<CalculatedStyleValue::ResolvedType> resolved_type() const override;
virtual Optional<CSSNumericType> determine_type(PropertyID) const override;
virtual bool contains_percentage() const override { return false; }
virtual CalculatedStyleValue::CalculationResult resolve(Optional<Length::ResolutionContext const&> context, CalculatedStyleValue::PercentageBasis const&) const override;
@ -488,8 +452,6 @@ public:
~SinCalculationNode();
virtual String to_string() const override;
virtual Optional<CalculatedStyleValue::ResolvedType> resolved_type() const override;
virtual Optional<CSSNumericType> determine_type(PropertyID) const override;
virtual bool contains_percentage() const override;
virtual CalculatedStyleValue::CalculationResult resolve(Optional<Length::ResolutionContext const&>, CalculatedStyleValue::PercentageBasis const&) const override;
@ -507,8 +469,6 @@ public:
~CosCalculationNode();
virtual String to_string() const override;
virtual Optional<CalculatedStyleValue::ResolvedType> resolved_type() const override;
virtual Optional<CSSNumericType> determine_type(PropertyID) const override;
virtual bool contains_percentage() const override;
virtual CalculatedStyleValue::CalculationResult resolve(Optional<Length::ResolutionContext const&>, CalculatedStyleValue::PercentageBasis const&) const override;
@ -526,8 +486,6 @@ public:
~TanCalculationNode();
virtual String to_string() const override;
virtual Optional<CalculatedStyleValue::ResolvedType> resolved_type() const override;
virtual Optional<CSSNumericType> determine_type(PropertyID) const override;
virtual bool contains_percentage() const override;
virtual CalculatedStyleValue::CalculationResult resolve(Optional<Length::ResolutionContext const&>, CalculatedStyleValue::PercentageBasis const&) const override;
@ -545,8 +503,6 @@ public:
~AsinCalculationNode();
virtual String to_string() const override;
virtual Optional<CalculatedStyleValue::ResolvedType> resolved_type() const override;
virtual Optional<CSSNumericType> determine_type(PropertyID) const override;
virtual bool contains_percentage() const override;
virtual CalculatedStyleValue::CalculationResult resolve(Optional<Length::ResolutionContext const&>, CalculatedStyleValue::PercentageBasis const&) const override;
@ -564,8 +520,6 @@ public:
~AcosCalculationNode();
virtual String to_string() const override;
virtual Optional<CalculatedStyleValue::ResolvedType> resolved_type() const override;
virtual Optional<CSSNumericType> determine_type(PropertyID) const override;
virtual bool contains_percentage() const override;
virtual CalculatedStyleValue::CalculationResult resolve(Optional<Length::ResolutionContext const&>, CalculatedStyleValue::PercentageBasis const&) const override;
@ -583,8 +537,6 @@ public:
~AtanCalculationNode();
virtual String to_string() const override;
virtual Optional<CalculatedStyleValue::ResolvedType> resolved_type() const override;
virtual Optional<CSSNumericType> determine_type(PropertyID) const override;
virtual bool contains_percentage() const override;
virtual CalculatedStyleValue::CalculationResult resolve(Optional<Length::ResolutionContext const&>, CalculatedStyleValue::PercentageBasis const&) const override;
@ -602,8 +554,6 @@ public:
~Atan2CalculationNode();
virtual String to_string() const override;
virtual Optional<CalculatedStyleValue::ResolvedType> resolved_type() const override;
virtual Optional<CSSNumericType> determine_type(PropertyID) const override;
virtual bool contains_percentage() const override;
virtual CalculatedStyleValue::CalculationResult resolve(Optional<Length::ResolutionContext const&>, CalculatedStyleValue::PercentageBasis const&) const override;
@ -622,8 +572,6 @@ public:
~PowCalculationNode();
virtual String to_string() const override;
virtual Optional<CalculatedStyleValue::ResolvedType> resolved_type() const override;
virtual Optional<CSSNumericType> determine_type(PropertyID) const override;
virtual bool contains_percentage() const override { return false; }
virtual CalculatedStyleValue::CalculationResult resolve(Optional<Length::ResolutionContext const&>, CalculatedStyleValue::PercentageBasis const&) const override;
@ -631,7 +579,7 @@ public:
virtual bool equals(CalculationNode const&) const override;
private:
explicit PowCalculationNode(NonnullOwnPtr<CalculationNode>, NonnullOwnPtr<CalculationNode>);
PowCalculationNode(NonnullOwnPtr<CalculationNode>, NonnullOwnPtr<CalculationNode>);
NonnullOwnPtr<CalculationNode> m_x;
NonnullOwnPtr<CalculationNode> m_y;
};
@ -642,8 +590,6 @@ public:
~SqrtCalculationNode();
virtual String to_string() const override;
virtual Optional<CalculatedStyleValue::ResolvedType> resolved_type() const override;
virtual Optional<CSSNumericType> determine_type(PropertyID) const override;
virtual bool contains_percentage() const override { return false; }
virtual CalculatedStyleValue::CalculationResult resolve(Optional<Length::ResolutionContext const&>, CalculatedStyleValue::PercentageBasis const&) const override;
@ -661,8 +607,6 @@ public:
~HypotCalculationNode();
virtual String to_string() const override;
virtual Optional<CalculatedStyleValue::ResolvedType> resolved_type() const override;
virtual Optional<CSSNumericType> determine_type(PropertyID) const override;
virtual bool contains_percentage() const override;
virtual CalculatedStyleValue::CalculationResult resolve(Optional<Length::ResolutionContext const&>, CalculatedStyleValue::PercentageBasis const&) const override;
@ -670,7 +614,7 @@ public:
virtual bool equals(CalculationNode const&) const override;
private:
explicit HypotCalculationNode(Vector<NonnullOwnPtr<CalculationNode>>);
HypotCalculationNode(Vector<NonnullOwnPtr<CalculationNode>>, Optional<CSSNumericType>);
Vector<NonnullOwnPtr<CalculationNode>> m_values;
};
@ -680,8 +624,6 @@ public:
~LogCalculationNode();
virtual String to_string() const override;
virtual Optional<CalculatedStyleValue::ResolvedType> resolved_type() const override;
virtual Optional<CSSNumericType> determine_type(PropertyID) const override;
virtual bool contains_percentage() const override { return false; }
virtual CalculatedStyleValue::CalculationResult resolve(Optional<Length::ResolutionContext const&>, CalculatedStyleValue::PercentageBasis const&) const override;
@ -700,8 +642,6 @@ public:
~ExpCalculationNode();
virtual String to_string() const override;
virtual Optional<CalculatedStyleValue::ResolvedType> resolved_type() const override;
virtual Optional<CSSNumericType> determine_type(PropertyID) const override;
virtual bool contains_percentage() const override { return false; }
virtual CalculatedStyleValue::CalculationResult resolve(Optional<Length::ResolutionContext const&>, CalculatedStyleValue::PercentageBasis const&) const override;
@ -719,8 +659,6 @@ public:
~RoundCalculationNode();
virtual String to_string() const override;
virtual Optional<CalculatedStyleValue::ResolvedType> resolved_type() const override;
virtual Optional<CSSNumericType> determine_type(PropertyID) const override;
virtual bool contains_percentage() const override;
virtual CalculatedStyleValue::CalculationResult resolve(Optional<Length::ResolutionContext const&>, CalculatedStyleValue::PercentageBasis const&) const override;
@ -728,7 +666,7 @@ public:
virtual bool equals(CalculationNode const&) const override;
private:
RoundCalculationNode(RoundingStrategy, NonnullOwnPtr<CalculationNode>, NonnullOwnPtr<CalculationNode>);
RoundCalculationNode(RoundingStrategy, NonnullOwnPtr<CalculationNode>, NonnullOwnPtr<CalculationNode>, Optional<CSSNumericType>);
RoundingStrategy m_strategy;
NonnullOwnPtr<CalculationNode> m_x;
NonnullOwnPtr<CalculationNode> m_y;
@ -740,8 +678,6 @@ public:
~ModCalculationNode();
virtual String to_string() const override;
virtual Optional<CalculatedStyleValue::ResolvedType> resolved_type() const override;
virtual Optional<CSSNumericType> determine_type(PropertyID) const override;
virtual bool contains_percentage() const override;
virtual CalculatedStyleValue::CalculationResult resolve(Optional<Length::ResolutionContext const&>, CalculatedStyleValue::PercentageBasis const&) const override;
@ -749,7 +685,7 @@ public:
virtual bool equals(CalculationNode const&) const override;
private:
ModCalculationNode(NonnullOwnPtr<CalculationNode>, NonnullOwnPtr<CalculationNode>);
ModCalculationNode(NonnullOwnPtr<CalculationNode>, NonnullOwnPtr<CalculationNode>, Optional<CSSNumericType>);
NonnullOwnPtr<CalculationNode> m_x;
NonnullOwnPtr<CalculationNode> m_y;
};
@ -760,8 +696,6 @@ public:
~RemCalculationNode();
virtual String to_string() const override;
virtual Optional<CalculatedStyleValue::ResolvedType> resolved_type() const override;
virtual Optional<CSSNumericType> determine_type(PropertyID) const override;
virtual bool contains_percentage() const override;
virtual CalculatedStyleValue::CalculationResult resolve(Optional<Length::ResolutionContext const&>, CalculatedStyleValue::PercentageBasis const&) const override;
@ -769,7 +703,7 @@ public:
virtual bool equals(CalculationNode const&) const override;
private:
RemCalculationNode(NonnullOwnPtr<CalculationNode>, NonnullOwnPtr<CalculationNode>);
RemCalculationNode(NonnullOwnPtr<CalculationNode>, NonnullOwnPtr<CalculationNode>, Optional<CSSNumericType>);
NonnullOwnPtr<CalculationNode> m_x;
NonnullOwnPtr<CalculationNode> m_y;
};