LibWeb/CSS: Extract CSSUnitValue -> CSS Value code

create_numeric_value() will be used next to create a CalculationNode,
and I didn't want to have to duplicate the "create a value based on the
unit name" code.

No behaviour change.
This commit is contained in:
Sam Atkins 2025-10-10 16:39:26 +01:00
commit df7abe1dc2
Notes: github-actions[bot] 2025-10-13 09:01:18 +00:00

View file

@ -297,6 +297,34 @@ Optional<SumValue> CSSUnitValue::create_a_sum_value() const
return SumValue { SumValueItem { value, { { unit, 1 } } } }; return SumValue { SumValueItem { value, { { unit, 1 } } } };
} }
static Optional<CalculationNode::NumericValue> create_numeric_value(double value, FlyString const& unit)
{
if (unit == "number"_fly_string)
return Number { Number::Type::Number, value };
if (unit == "percent"_fly_string)
return Percentage { value };
if (auto dimension_type = dimension_for_unit(unit); dimension_type.has_value()) {
switch (*dimension_type) {
case DimensionType::Angle:
return Angle { value, string_to_angle_unit(unit).release_value() };
case DimensionType::Flex:
return Flex { value, string_to_flex_unit(unit).release_value() };
case DimensionType::Frequency:
return Frequency { value, string_to_frequency_unit(unit).release_value() };
case DimensionType::Length:
return Length { value, string_to_length_unit(unit).release_value() };
case DimensionType::Resolution:
return Resolution { value, string_to_resolution_unit(unit).release_value() };
case DimensionType::Time:
return Time { value, string_to_time_unit(unit).release_value() };
}
}
return {};
}
// https://drafts.css-houdini.org/css-typed-om-1/#create-an-internal-representation // https://drafts.css-houdini.org/css-typed-om-1/#create-an-internal-representation
WebIDL::ExceptionOr<NonnullRefPtr<StyleValue const>> CSSUnitValue::create_an_internal_representation(PropertyNameAndID const& property) const WebIDL::ExceptionOr<NonnullRefPtr<StyleValue const>> CSSUnitValue::create_an_internal_representation(PropertyNameAndID const& property) const
{ {
@ -328,92 +356,92 @@ WebIDL::ExceptionOr<NonnullRefPtr<StyleValue const>> CSSUnitValue::create_an_int
return CalculatedStyleValue::create(move(math_sum_node), NumericType::create_from_unit(m_unit).release_value(), context); return CalculatedStyleValue::create(move(math_sum_node), NumericType::create_from_unit(m_unit).release_value(), context);
}; };
if (m_unit == "number"_fly_string) { auto value = create_numeric_value(m_value, m_unit);
if (!value.has_value()) {
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, MUST(String::formatted("Unrecognized unit '{}'.", m_unit)) };
}
// FIXME: Check types allowed by registered custom properties.
auto style_value = value->visit(
[&](Number const& number) -> RefPtr<StyleValue const> {
// NB: Number before Integer, because a custom property accepts either and we want to avoid rounding in that case. // NB: Number before Integer, because a custom property accepts either and we want to avoid rounding in that case.
if (property_accepts_type(property.id(), ValueType::Number)) { if (property_accepts_type(property.id(), ValueType::Number)) {
if (property_accepts_number(property.id(), m_value)) if (property_accepts_number(property.id(), number.value()))
return NumberStyleValue::create(m_value); return NumberStyleValue::create(number.value());
return wrap_in_math_sum(Number { Number::Type::Number, m_value }); return wrap_in_math_sum(number);
} }
if (property_accepts_type(property.id(), ValueType::Integer)) { if (property_accepts_type(property.id(), ValueType::Integer)) {
// NB: Same rounding as CalculatedStyleValue::resolve_integer(). Maybe this should go somewhere central? // NB: Same rounding as CalculatedStyleValue::resolve_integer(). Maybe this should go somewhere central?
auto integer = llround(m_value); auto integer = llround(number.value());
if (property_accepts_integer(property.id(), integer)) if (property_accepts_integer(property.id(), integer))
return IntegerStyleValue::create(integer); return IntegerStyleValue::create(integer);
return wrap_in_math_sum(Number { Number::Type::Number, m_value }); return wrap_in_math_sum(number);
} }
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Property does not accept values of this type."sv }; return {};
} },
[&](Percentage const& percentage) -> RefPtr<StyleValue const> {
if (m_unit == "percent"_fly_string) {
if (property_accepts_type(property.id(), ValueType::Percentage)) { if (property_accepts_type(property.id(), ValueType::Percentage)) {
Percentage percentage { m_value };
if (property_accepts_percentage(property.id(), percentage)) if (property_accepts_percentage(property.id(), percentage))
return PercentageStyleValue::create(percentage); return PercentageStyleValue::create(percentage);
return wrap_in_math_sum(percentage); return wrap_in_math_sum(percentage);
} }
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Property does not accept values of this type."sv }; return {};
} },
[&](Angle const& angle) -> RefPtr<StyleValue const> {
auto dimension_type = dimension_for_unit(m_unit);
if (!dimension_type.has_value())
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, MUST(String::formatted("Unrecognized unit '{}'.", m_unit)) };
switch (*dimension_type) {
case DimensionType::Angle:
if (property_accepts_type(property.id(), ValueType::Angle)) { if (property_accepts_type(property.id(), ValueType::Angle)) {
Angle value { m_value, string_to_angle_unit(m_unit).release_value() }; if (property_accepts_angle(property.id(), angle))
if (property_accepts_angle(property.id(), value)) return AngleStyleValue::create(angle);
return AngleStyleValue::create(value); return wrap_in_math_sum(angle);
return wrap_in_math_sum(value);
} }
break; return {};
case DimensionType::Flex: },
[&](Flex const& flex) -> RefPtr<StyleValue const> {
if (property_accepts_type(property.id(), ValueType::Flex)) { if (property_accepts_type(property.id(), ValueType::Flex)) {
Flex value { m_value, string_to_flex_unit(m_unit).release_value() }; if (property_accepts_flex(property.id(), flex))
if (property_accepts_flex(property.id(), value)) return FlexStyleValue::create(flex);
return FlexStyleValue::create(value); return wrap_in_math_sum(flex);
return wrap_in_math_sum(value);
} }
break; return {};
case DimensionType::Frequency: },
[&](Frequency const& frequency) -> RefPtr<StyleValue const> {
if (property_accepts_type(property.id(), ValueType::Frequency)) { if (property_accepts_type(property.id(), ValueType::Frequency)) {
Frequency value { m_value, string_to_frequency_unit(m_unit).release_value() }; if (property_accepts_frequency(property.id(), frequency))
if (property_accepts_frequency(property.id(), value)) return FrequencyStyleValue::create(frequency);
return FrequencyStyleValue::create(value); return wrap_in_math_sum(frequency);
return wrap_in_math_sum(value);
} }
break; return {};
case DimensionType::Length: },
[&](Length const& length) -> RefPtr<StyleValue const> {
if (property_accepts_type(property.id(), ValueType::Length)) { if (property_accepts_type(property.id(), ValueType::Length)) {
Length value { m_value, string_to_length_unit(m_unit).release_value() }; if (property_accepts_length(property.id(), length))
if (property_accepts_length(property.id(), value)) return LengthStyleValue::create(length);
return LengthStyleValue::create(value); return wrap_in_math_sum(length);
return wrap_in_math_sum(value);
} }
break; return {};
case DimensionType::Resolution: },
[&](Resolution const& resolution) -> RefPtr<StyleValue const> {
if (property_accepts_type(property.id(), ValueType::Resolution)) { if (property_accepts_type(property.id(), ValueType::Resolution)) {
Resolution value { m_value, string_to_resolution_unit(m_unit).release_value() }; if (property_accepts_resolution(property.id(), resolution))
if (property_accepts_resolution(property.id(), value)) return ResolutionStyleValue::create(resolution);
return ResolutionStyleValue::create(value); return wrap_in_math_sum(resolution);
return wrap_in_math_sum(value);
} }
break; return {};
case DimensionType::Time: },
[&](Time const& time) -> RefPtr<StyleValue const> {
if (property_accepts_type(property.id(), ValueType::Time)) { if (property_accepts_type(property.id(), ValueType::Time)) {
Time value { m_value, string_to_time_unit(m_unit).release_value() }; if (property_accepts_time(property.id(), time))
if (property_accepts_time(property.id(), value)) return TimeStyleValue::create(time);
return TimeStyleValue::create(value); return wrap_in_math_sum(time);
return wrap_in_math_sum(value);
}
break;
} }
return {};
});
if (!style_value)
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Property does not accept values of this type."sv }; return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Property does not accept values of this type."sv };
return style_value.release_nonnull();
} }
} }