LibWeb/CSS: Simplify calculations after parsing them

If a calculation was simplified down to a single numeric node, then most
of the time we can instead return a regular StyleValue, for example
`calc(2px + 3px)` would be simplified down to a `5px` LengthStyleValue.
This means that parse_calculated_value() can't return a
CalculatedStyleValue directly, and its callers all have to handle
non-calculated values as well as calculated ones.

This simplification is reflected in the new test results. Serialization
is not yet correct in all cases but we're closer than we were. :^)
This commit is contained in:
Sam Atkins 2025-01-28 16:24:39 +00:00 committed by Andreas Kling
commit ee712bd98f
Notes: github-actions[bot] 2025-01-30 18:32:52 +00:00
15 changed files with 295 additions and 228 deletions

View file

@ -11,6 +11,15 @@
#include <AK/TypeCasts.h>
#include <LibWeb/CSS/Percentage.h>
#include <LibWeb/CSS/PropertyID.h>
#include <LibWeb/CSS/StyleValues/AngleStyleValue.h>
#include <LibWeb/CSS/StyleValues/FlexStyleValue.h>
#include <LibWeb/CSS/StyleValues/FrequencyStyleValue.h>
#include <LibWeb/CSS/StyleValues/IntegerStyleValue.h>
#include <LibWeb/CSS/StyleValues/LengthStyleValue.h>
#include <LibWeb/CSS/StyleValues/NumberStyleValue.h>
#include <LibWeb/CSS/StyleValues/PercentageStyleValue.h>
#include <LibWeb/CSS/StyleValues/ResolutionStyleValue.h>
#include <LibWeb/CSS/StyleValues/TimeStyleValue.h>
namespace Web::CSS {
@ -298,6 +307,30 @@ CalculatedStyleValue::CalculationResult NumericCalculationNode::resolve(Calculat
return CalculatedStyleValue::CalculationResult::from_value(m_value, context, numeric_type());
}
RefPtr<CSSStyleValue> NumericCalculationNode::to_style_value(CalculationContext const& context) const
{
// TODO: Clamp values to the range allowed by the context.
return m_value.visit(
[&](Number const& number) -> RefPtr<CSSStyleValue> {
// FIXME: Returning infinity or NaN as a NumberStyleValue isn't valid.
// This is a temporary fix until value-clamping is implemented here.
// In future, we can remove these two lines and return NonnullRefPtr again.
if (!isfinite(number.value()))
return nullptr;
if (context.resolve_numbers_as_integers)
return IntegerStyleValue::create(llround(number.value()));
return NumberStyleValue::create(number.value());
},
[](Angle const& angle) -> RefPtr<CSSStyleValue> { return AngleStyleValue::create(angle); },
[](Flex const& flex) -> RefPtr<CSSStyleValue> { return FlexStyleValue::create(flex); },
[](Frequency const& frequency) -> RefPtr<CSSStyleValue> { return FrequencyStyleValue::create(frequency); },
[](Length const& length) -> RefPtr<CSSStyleValue> { return LengthStyleValue::create(length); },
[](Percentage const& percentage) -> RefPtr<CSSStyleValue> { return PercentageStyleValue::create(percentage); },
[](Resolution const& resolution) -> RefPtr<CSSStyleValue> { return ResolutionStyleValue::create(resolution); },
[](Time const& time) -> RefPtr<CSSStyleValue> { return TimeStyleValue::create(time); });
}
void NumericCalculationNode::dump(StringBuilder& builder, int indent) const
{
builder.appendff("{: >{}}NUMERIC({})\n", "", indent, m_value.visit([](auto& it) { return it.to_string(); }));