mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-09-21 16:58:58 +00:00
LibWeb: Extract mixed-type interpolation to a separate method
This commit is contained in:
parent
b19fee9962
commit
7409c564d7
Notes:
github-actions[bot]
2025-09-15 09:42:10 +00:00
Author: https://github.com/tcl3
Commit: 7409c564d7
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/6194
Reviewed-by: https://github.com/AtkinsSJ ✅
1 changed files with 117 additions and 112 deletions
|
@ -1024,123 +1024,128 @@ RefPtr<StyleValue const> interpolate_box_shadow(DOM::Element& element, Calculati
|
||||||
return StyleValueList::create(move(result_shadows), StyleValueList::Separator::Comma);
|
return StyleValueList::create(move(result_shadows), StyleValueList::Separator::Comma);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static RefPtr<StyleValue const> interpolate_mixed_value(CalculationContext const& calculation_context, StyleValue const& from, StyleValue const& to, float delta)
|
||||||
|
{
|
||||||
|
auto get_value_type_of_numeric_style_value = [&calculation_context](StyleValue const& value) -> Optional<ValueType> {
|
||||||
|
switch (value.type()) {
|
||||||
|
case StyleValue::Type::Angle:
|
||||||
|
return ValueType::Angle;
|
||||||
|
case StyleValue::Type::Frequency:
|
||||||
|
return ValueType::Frequency;
|
||||||
|
case StyleValue::Type::Integer:
|
||||||
|
return ValueType::Integer;
|
||||||
|
case StyleValue::Type::Length:
|
||||||
|
return ValueType::Length;
|
||||||
|
case StyleValue::Type::Number:
|
||||||
|
return ValueType::Number;
|
||||||
|
case StyleValue::Type::Percentage:
|
||||||
|
return calculation_context.percentages_resolve_as.value_or(ValueType::Percentage);
|
||||||
|
case StyleValue::Type::Resolution:
|
||||||
|
return ValueType::Resolution;
|
||||||
|
case StyleValue::Type::Time:
|
||||||
|
return ValueType::Time;
|
||||||
|
case StyleValue::Type::Calculated: {
|
||||||
|
auto const& calculated = value.as_calculated();
|
||||||
|
if (calculated.resolves_to_angle_percentage())
|
||||||
|
return ValueType::Angle;
|
||||||
|
if (calculated.resolves_to_frequency_percentage())
|
||||||
|
return ValueType::Frequency;
|
||||||
|
if (calculated.resolves_to_length_percentage())
|
||||||
|
return ValueType::Length;
|
||||||
|
if (calculated.resolves_to_resolution())
|
||||||
|
return ValueType::Resolution;
|
||||||
|
if (calculated.resolves_to_number())
|
||||||
|
return calculation_context.resolve_numbers_as_integers ? ValueType::Integer : ValueType::Number;
|
||||||
|
if (calculated.resolves_to_percentage())
|
||||||
|
return calculation_context.percentages_resolve_as.value_or(ValueType::Percentage);
|
||||||
|
if (calculated.resolves_to_time_percentage())
|
||||||
|
return ValueType::Time;
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto from_value_type = get_value_type_of_numeric_style_value(from);
|
||||||
|
auto to_value_type = get_value_type_of_numeric_style_value(to);
|
||||||
|
|
||||||
|
if (from_value_type.has_value() && from_value_type == to_value_type) {
|
||||||
|
auto to_calculation_node = [&calculation_context](StyleValue const& value) -> NonnullRefPtr<CalculationNode const> {
|
||||||
|
switch (value.type()) {
|
||||||
|
case StyleValue::Type::Angle:
|
||||||
|
return NumericCalculationNode::create(value.as_angle().angle(), calculation_context);
|
||||||
|
case StyleValue::Type::Frequency:
|
||||||
|
return NumericCalculationNode::create(value.as_frequency().frequency(), calculation_context);
|
||||||
|
case StyleValue::Type::Integer:
|
||||||
|
// https://drafts.csswg.org/css-values-4/#combine-integers
|
||||||
|
// Interpolation of <integer> is defined as Vresult = round((1 - p) × VA + p × VB); that is,
|
||||||
|
// interpolation happens in the real number space as for <number>s, and the result is converted to an
|
||||||
|
// <integer> by rounding to the nearest integer.
|
||||||
|
return NumericCalculationNode::create(Number { Number::Type::Number, static_cast<double>(value.as_integer().integer()) }, calculation_context);
|
||||||
|
case StyleValue::Type::Length:
|
||||||
|
return NumericCalculationNode::create(value.as_length().length(), calculation_context);
|
||||||
|
case StyleValue::Type::Number:
|
||||||
|
return NumericCalculationNode::create(Number { Number::Type::Number, value.as_number().number() }, calculation_context);
|
||||||
|
case StyleValue::Type::Percentage:
|
||||||
|
return NumericCalculationNode::create(value.as_percentage().percentage(), calculation_context);
|
||||||
|
case StyleValue::Type::Time:
|
||||||
|
return NumericCalculationNode::create(value.as_time().time(), calculation_context);
|
||||||
|
case StyleValue::Type::Calculated:
|
||||||
|
return value.as_calculated().calculation();
|
||||||
|
default:
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://drafts.csswg.org/css-values-4/#combine-mixed
|
||||||
|
// The computed value of a percentage-dimension mix is defined as
|
||||||
|
// FIXME: a computed dimension if the percentage component is zero or is defined specifically to compute to a dimension value
|
||||||
|
// a computed percentage if the dimension component is zero
|
||||||
|
// a computed calc() expression otherwise
|
||||||
|
if (auto const* from_dimension_value = as_if<DimensionStyleValue>(from); from_dimension_value && to.type() == StyleValue::Type::Percentage) {
|
||||||
|
auto dimension_component = from_dimension_value->raw_value() * (1.f - delta);
|
||||||
|
auto percentage_component = to.as_percentage().raw_value() * delta;
|
||||||
|
if (dimension_component == 0.f)
|
||||||
|
return PercentageStyleValue::create(Percentage { percentage_component });
|
||||||
|
} else if (auto const* to_dimension_value = as_if<DimensionStyleValue>(to); to_dimension_value && from.type() == StyleValue::Type::Percentage) {
|
||||||
|
auto dimension_component = to_dimension_value->raw_value() * delta;
|
||||||
|
auto percentage_component = from.as_percentage().raw_value() * (1.f - delta);
|
||||||
|
if (dimension_component == 0)
|
||||||
|
return PercentageStyleValue::create(Percentage { percentage_component });
|
||||||
|
}
|
||||||
|
|
||||||
|
auto from_node = to_calculation_node(from);
|
||||||
|
auto to_node = to_calculation_node(to);
|
||||||
|
|
||||||
|
// https://drafts.csswg.org/css-values-4/#combine-math
|
||||||
|
// Interpolation of math functions, with each other or with numeric values and other numeric-valued functions, is defined as Vresult = calc((1 - p) * VA + p * VB).
|
||||||
|
auto from_contribution = ProductCalculationNode::create({
|
||||||
|
from_node,
|
||||||
|
NumericCalculationNode::create(Number { Number::Type::Number, 1.f - delta }, calculation_context),
|
||||||
|
});
|
||||||
|
|
||||||
|
auto to_contribution = ProductCalculationNode::create({
|
||||||
|
to_node,
|
||||||
|
NumericCalculationNode::create(Number { Number::Type::Number, delta }, calculation_context),
|
||||||
|
});
|
||||||
|
|
||||||
|
return CalculatedStyleValue::create(
|
||||||
|
simplify_a_calculation_tree(SumCalculationNode::create({ from_contribution, to_contribution }), calculation_context, {}),
|
||||||
|
*from_node->numeric_type()->added_to(*to_node->numeric_type()),
|
||||||
|
calculation_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
static RefPtr<StyleValue const> interpolate_value_impl(DOM::Element& element, CalculationContext const& calculation_context, StyleValue const& from, StyleValue const& to, float delta, AllowDiscrete allow_discrete)
|
static RefPtr<StyleValue const> interpolate_value_impl(DOM::Element& element, CalculationContext const& calculation_context, StyleValue const& from, StyleValue const& to, float delta, AllowDiscrete allow_discrete)
|
||||||
{
|
{
|
||||||
if (from.type() != to.type() || from.is_calculated() || to.is_calculated()) {
|
if (from.type() != to.type() || from.is_calculated() || to.is_calculated()) {
|
||||||
// Handle mixed percentage and dimension types, as well as CalculatedStyleValues
|
// Handle mixed percentage and dimension types, as well as CalculatedStyleValues
|
||||||
// https://www.w3.org/TR/css-values-4/#mixed-percentages
|
// https://www.w3.org/TR/css-values-4/#mixed-percentages
|
||||||
auto get_value_type_of_numeric_style_value = [&calculation_context](StyleValue const& value) -> Optional<ValueType> {
|
return interpolate_mixed_value(calculation_context, from, to, delta);
|
||||||
switch (value.type()) {
|
|
||||||
case StyleValue::Type::Angle:
|
|
||||||
return ValueType::Angle;
|
|
||||||
case StyleValue::Type::Frequency:
|
|
||||||
return ValueType::Frequency;
|
|
||||||
case StyleValue::Type::Integer:
|
|
||||||
return ValueType::Integer;
|
|
||||||
case StyleValue::Type::Length:
|
|
||||||
return ValueType::Length;
|
|
||||||
case StyleValue::Type::Number:
|
|
||||||
return ValueType::Number;
|
|
||||||
case StyleValue::Type::Percentage:
|
|
||||||
return calculation_context.percentages_resolve_as.value_or(ValueType::Percentage);
|
|
||||||
case StyleValue::Type::Resolution:
|
|
||||||
return ValueType::Resolution;
|
|
||||||
case StyleValue::Type::Time:
|
|
||||||
return ValueType::Time;
|
|
||||||
case StyleValue::Type::Calculated: {
|
|
||||||
auto const& calculated = value.as_calculated();
|
|
||||||
if (calculated.resolves_to_angle_percentage())
|
|
||||||
return ValueType::Angle;
|
|
||||||
if (calculated.resolves_to_frequency_percentage())
|
|
||||||
return ValueType::Frequency;
|
|
||||||
if (calculated.resolves_to_length_percentage())
|
|
||||||
return ValueType::Length;
|
|
||||||
if (calculated.resolves_to_resolution())
|
|
||||||
return ValueType::Resolution;
|
|
||||||
if (calculated.resolves_to_number())
|
|
||||||
return calculation_context.resolve_numbers_as_integers ? ValueType::Integer : ValueType::Number;
|
|
||||||
if (calculated.resolves_to_percentage())
|
|
||||||
return calculation_context.percentages_resolve_as.value_or(ValueType::Percentage);
|
|
||||||
if (calculated.resolves_to_time_percentage())
|
|
||||||
return ValueType::Time;
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
auto from_value_type = get_value_type_of_numeric_style_value(from);
|
|
||||||
auto to_value_type = get_value_type_of_numeric_style_value(to);
|
|
||||||
|
|
||||||
if (from_value_type.has_value() && from_value_type == to_value_type) {
|
|
||||||
auto to_calculation_node = [&calculation_context](StyleValue const& value) -> NonnullRefPtr<CalculationNode const> {
|
|
||||||
switch (value.type()) {
|
|
||||||
case StyleValue::Type::Angle:
|
|
||||||
return NumericCalculationNode::create(value.as_angle().angle(), calculation_context);
|
|
||||||
case StyleValue::Type::Frequency:
|
|
||||||
return NumericCalculationNode::create(value.as_frequency().frequency(), calculation_context);
|
|
||||||
case StyleValue::Type::Integer:
|
|
||||||
// https://drafts.csswg.org/css-values-4/#combine-integers
|
|
||||||
// Interpolation of <integer> is defined as Vresult = round((1 - p) × VA + p × VB); that is,
|
|
||||||
// interpolation happens in the real number space as for <number>s, and the result is converted to an
|
|
||||||
// <integer> by rounding to the nearest integer.
|
|
||||||
return NumericCalculationNode::create(Number { Number::Type::Number, static_cast<double>(value.as_integer().integer()) }, calculation_context);
|
|
||||||
case StyleValue::Type::Length:
|
|
||||||
return NumericCalculationNode::create(value.as_length().length(), calculation_context);
|
|
||||||
case StyleValue::Type::Number:
|
|
||||||
return NumericCalculationNode::create(Number { Number::Type::Number, value.as_number().number() }, calculation_context);
|
|
||||||
case StyleValue::Type::Percentage:
|
|
||||||
return NumericCalculationNode::create(value.as_percentage().percentage(), calculation_context);
|
|
||||||
case StyleValue::Type::Time:
|
|
||||||
return NumericCalculationNode::create(value.as_time().time(), calculation_context);
|
|
||||||
case StyleValue::Type::Calculated:
|
|
||||||
return value.as_calculated().calculation();
|
|
||||||
default:
|
|
||||||
VERIFY_NOT_REACHED();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// https://drafts.csswg.org/css-values-4/#combine-mixed
|
|
||||||
// The computed value of a percentage-dimension mix is defined as
|
|
||||||
// FIXME: a computed dimension if the percentage component is zero or is defined specifically to compute to a dimension value
|
|
||||||
// a computed percentage if the dimension component is zero
|
|
||||||
// a computed calc() expression otherwise
|
|
||||||
if (auto const* from_dimension_value = as_if<DimensionStyleValue>(from); from_dimension_value && to.type() == StyleValue::Type::Percentage) {
|
|
||||||
auto dimension_component = from_dimension_value->raw_value() * (1.f - delta);
|
|
||||||
auto percentage_component = to.as_percentage().raw_value() * delta;
|
|
||||||
if (dimension_component == 0.f)
|
|
||||||
return PercentageStyleValue::create(Percentage { percentage_component });
|
|
||||||
} else if (auto const* to_dimension_value = as_if<DimensionStyleValue>(to); to_dimension_value && from.type() == StyleValue::Type::Percentage) {
|
|
||||||
auto dimension_component = to_dimension_value->raw_value() * delta;
|
|
||||||
auto percentage_component = from.as_percentage().raw_value() * (1.f - delta);
|
|
||||||
if (dimension_component == 0)
|
|
||||||
return PercentageStyleValue::create(Percentage { percentage_component });
|
|
||||||
}
|
|
||||||
|
|
||||||
auto from_node = to_calculation_node(from);
|
|
||||||
auto to_node = to_calculation_node(to);
|
|
||||||
|
|
||||||
// https://drafts.csswg.org/css-values-4/#combine-math
|
|
||||||
// Interpolation of math functions, with each other or with numeric values and other numeric-valued functions, is defined as Vresult = calc((1 - p) * VA + p * VB).
|
|
||||||
auto from_contribution = ProductCalculationNode::create({
|
|
||||||
from_node,
|
|
||||||
NumericCalculationNode::create(Number { Number::Type::Number, 1.f - delta }, calculation_context),
|
|
||||||
});
|
|
||||||
|
|
||||||
auto to_contribution = ProductCalculationNode::create({
|
|
||||||
to_node,
|
|
||||||
NumericCalculationNode::create(Number { Number::Type::Number, delta }, calculation_context),
|
|
||||||
});
|
|
||||||
|
|
||||||
return CalculatedStyleValue::create(
|
|
||||||
simplify_a_calculation_tree(SumCalculationNode::create({ from_contribution, to_contribution }), calculation_context, {}),
|
|
||||||
*from_node->numeric_type()->added_to(*to_node->numeric_type()),
|
|
||||||
calculation_context);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static auto interpolate_length_percentage = [](CalculationContext const& calculation_context, LengthPercentage const& from, LengthPercentage const& to, float delta) -> Optional<LengthPercentage> {
|
static auto interpolate_length_percentage = [](CalculationContext const& calculation_context, LengthPercentage const& from, LengthPercentage const& to, float delta) -> Optional<LengthPercentage> {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue