Skip to content

Commit cb61371

Browse files
committed
LibWeb: Interpolate currentColor in CSS animations
currentColor survives into the computed style, and is stored as a KeywordStyleValue, so interpolation previously treated it as a different type from other colors. Handle this specifically in interpolate_value_impl(), by interpolating it like any other color.
1 parent 614353a commit cb61371

6 files changed

Lines changed: 79 additions & 68 deletions

File tree

Libraries/LibWeb/CSS/Interpolation.cpp

Lines changed: 41 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -581,7 +581,7 @@ static Optional<GridTrackSizeList> interpolate_grid_track_size_list(DOM::Element
581581
return result;
582582
}
583583

584-
ValueComparingRefPtr<StyleValue const> interpolate_property(DOM::Element& element, PropertyID property_id, StyleValue const& a_from, StyleValue const& a_to, float delta, AllowDiscrete allow_discrete)
584+
ValueComparingRefPtr<StyleValue const> interpolate_property(DOM::Element& element, PropertyID property_id, StyleValue const& a_from, StyleValue const& a_to, float delta, AllowDiscrete allow_discrete, ColorResolutionContext const* color_resolution_context)
585585
{
586586
auto from = with_keyword_values_resolved(element, property_id, a_from);
587587
auto to = with_keyword_values_resolved(element, property_id, a_to);
@@ -591,11 +591,11 @@ ValueComparingRefPtr<StyleValue const> interpolate_property(DOM::Element& elemen
591591
auto animation_type = animation_type_from_longhand_property(property_id);
592592
switch (animation_type) {
593593
case AnimationType::ByComputedValue:
594-
return interpolate_value(element, calculation_context, from, to, delta, allow_discrete);
594+
return interpolate_value(element, calculation_context, from, to, delta, allow_discrete, color_resolution_context);
595595
case AnimationType::None:
596596
return to;
597597
case AnimationType::RepeatableList:
598-
return interpolate_repeatable_list(element, calculation_context, from, to, delta, allow_discrete);
598+
return interpolate_repeatable_list(element, calculation_context, from, to, delta, allow_discrete, color_resolution_context);
599599
case AnimationType::Custom: {
600600
if (property_id == PropertyID::Transform) {
601601
if (auto interpolated_transform = interpolate_transform(element, calculation_context, from, to, delta, allow_discrete))
@@ -617,7 +617,7 @@ ValueComparingRefPtr<StyleValue const> interpolate_property(DOM::Element& elemen
617617
static auto const& oblique_0deg_value = FontStyleStyleValue::create(FontStyleKeyword::Oblique, AngleStyleValue::create(Angle::make_degrees(0))).leak_ref();
618618
auto from_value = from->as_font_style().font_style() == FontStyleKeyword::Normal ? ValueComparingNonnullRefPtr<StyleValue const> { oblique_0deg_value } : from;
619619
auto to_value = to->as_font_style().font_style() == FontStyleKeyword::Normal ? ValueComparingNonnullRefPtr<StyleValue const> { oblique_0deg_value } : to;
620-
return interpolate_value(element, calculation_context, from_value, to_value, delta, allow_discrete);
620+
return interpolate_value(element, calculation_context, from_value, to_value, delta, allow_discrete, color_resolution_context);
621621
}
622622

623623
if (property_id == PropertyID::FontVariationSettings) {
@@ -632,7 +632,7 @@ ValueComparingRefPtr<StyleValue const> interpolate_property(DOM::Element& elemen
632632

633633
// The values in these lists have already been deduplicated and sorted at this point, so we can use
634634
// interpolate_value() to interpolate them pairwise.
635-
return interpolate_value(element, calculation_context, from, to, delta, allow_discrete);
635+
return interpolate_value(element, calculation_context, from, to, delta, allow_discrete, color_resolution_context);
636636
}
637637

638638
// https://drafts.csswg.org/web-animations-1/#animating-visibility
@@ -754,7 +754,7 @@ ValueComparingRefPtr<StyleValue const> interpolate_property(DOM::Element& elemen
754754

755755
// Otherwise, repeat both dash patterns of start and end value list until the length of elements in
756756
// both value lists match. Each item is then combined by computed value.
757-
if (auto result = interpolate_repeatable_list(element, calculation_context, from, to, delta, allow_discrete))
757+
if (auto result = interpolate_repeatable_list(element, calculation_context, from, to, delta, allow_discrete, color_resolution_context))
758758
return result.release_nonnull();
759759
return interpolate_discrete(from, to, delta, allow_discrete);
760760
}
@@ -1507,8 +1507,21 @@ static NonnullRefPtr<StyleValue const> length_percentage_or_auto_to_style_value(
15071507
VERIFY_NOT_REACHED();
15081508
}
15091509

1510-
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)
1510+
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, ColorResolutionContext const* color_resolution_context)
15111511
{
1512+
ColorResolutionContext fallback_color_resolution_context {};
1513+
if (from.has_color() && to.has_color()) {
1514+
if (!color_resolution_context) {
1515+
if (auto* node = element.unsafe_layout_node())
1516+
fallback_color_resolution_context = ColorResolutionContext::for_layout_node_with_style(*node);
1517+
color_resolution_context = &fallback_color_resolution_context;
1518+
}
1519+
if (auto interpolated = interpolate_color(from, to, delta, {}, *color_resolution_context))
1520+
return interpolated;
1521+
if (from.type() == StyleValue::Type::Color && to.type() == StyleValue::Type::Color)
1522+
return ColorStyleValue::create_from_color(Color::Black, ColorSyntax::Modern);
1523+
}
1524+
15121525
if (from.type() != to.type() || from.is_calculated() || to.is_calculated()) {
15131526
// Handle mixed percentage and dimension types, as well as CalculatedStyleValues
15141527
// https://www.w3.org/TR/css-values-4/#mixed-percentages
@@ -1594,7 +1607,7 @@ static RefPtr<StyleValue const> interpolate_value_impl(DOM::Element& element, Ca
15941607
// If both shapes are the same type, that type is ellipse() or circle(), and the radiuses are specified
15951608
// as <length-percentage> (rather than keywords), interpolate between each value in the shape functions.
15961609
auto const& to_circle = to_shape.get<Circle>();
1597-
auto interpolated_radius = interpolate_value_impl(element, basic_shape_calculation_context, from_circle.radius, to_circle.radius, delta, AllowDiscrete::No);
1610+
auto interpolated_radius = interpolate_value_impl(element, basic_shape_calculation_context, from_circle.radius, to_circle.radius, delta, AllowDiscrete::No, color_resolution_context);
15981611
auto interpolated_position = interpolate_optional_position(from_circle.position, to_circle.position);
15991612
if (!interpolated_radius || !interpolated_position.has_value())
16001613
return {};
@@ -1603,7 +1616,7 @@ static RefPtr<StyleValue const> interpolate_value_impl(DOM::Element& element, Ca
16031616
},
16041617
[&](Ellipse const& from_ellipse) -> Optional<BasicShape> {
16051618
auto const& to_ellipse = to_shape.get<Ellipse>();
1606-
auto interpolated_radius = interpolate_value_impl(element, basic_shape_calculation_context, from_ellipse.radius, to_ellipse.radius, delta, AllowDiscrete::No);
1619+
auto interpolated_radius = interpolate_value_impl(element, basic_shape_calculation_context, from_ellipse.radius, to_ellipse.radius, delta, AllowDiscrete::No, color_resolution_context);
16071620
auto interpolated_position = interpolate_optional_position(from_ellipse.position, to_ellipse.position);
16081621
if (!interpolated_radius || !interpolated_position.has_value())
16091622
return {};
@@ -1646,8 +1659,8 @@ static RefPtr<StyleValue const> interpolate_value_impl(DOM::Element& element, Ca
16461659
auto const& to_horizontal_radius = to.as_border_radius().horizontal_radius();
16471660
auto const& from_vertical_radius = from.as_border_radius().vertical_radius();
16481661
auto const& to_vertical_radius = to.as_border_radius().vertical_radius();
1649-
auto interpolated_horizontal_radius = interpolate_value_impl(element, calculation_context, from_horizontal_radius, to_horizontal_radius, delta, allow_discrete);
1650-
auto interpolated_vertical_radius = interpolate_value_impl(element, calculation_context, from_vertical_radius, to_vertical_radius, delta, allow_discrete);
1662+
auto interpolated_horizontal_radius = interpolate_value_impl(element, calculation_context, from_horizontal_radius, to_horizontal_radius, delta, allow_discrete, color_resolution_context);
1663+
auto interpolated_vertical_radius = interpolate_value_impl(element, calculation_context, from_vertical_radius, to_vertical_radius, delta, allow_discrete, color_resolution_context);
16511664
if (!interpolated_horizontal_radius || !interpolated_vertical_radius)
16521665
return {};
16531666
return BorderRadiusStyleValue::create(interpolated_horizontal_radius.release_nonnull(), interpolated_vertical_radius.release_nonnull());
@@ -1670,31 +1683,23 @@ static RefPtr<StyleValue const> interpolate_value_impl(DOM::Element& element, Ca
16701683
auto const& from_bottom_left = from.as_border_radius_rect().bottom_left();
16711684
auto const& to_bottom_left = to.as_border_radius_rect().bottom_left();
16721685

1673-
auto interpolated_top_left = interpolate_value_impl(element, border_radius_rect_computation_context, from_top_left, to_top_left, delta, allow_discrete);
1674-
auto interpolated_top_right = interpolate_value_impl(element, border_radius_rect_computation_context, from_top_right, to_top_right, delta, allow_discrete);
1675-
auto interpolated_bottom_right = interpolate_value_impl(element, border_radius_rect_computation_context, from_bottom_right, to_bottom_right, delta, allow_discrete);
1676-
auto interpolated_bottom_left = interpolate_value_impl(element, border_radius_rect_computation_context, from_bottom_left, to_bottom_left, delta, allow_discrete);
1686+
auto interpolated_top_left = interpolate_value_impl(element, border_radius_rect_computation_context, from_top_left, to_top_left, delta, allow_discrete, color_resolution_context);
1687+
auto interpolated_top_right = interpolate_value_impl(element, border_radius_rect_computation_context, from_top_right, to_top_right, delta, allow_discrete, color_resolution_context);
1688+
auto interpolated_bottom_right = interpolate_value_impl(element, border_radius_rect_computation_context, from_bottom_right, to_bottom_right, delta, allow_discrete, color_resolution_context);
1689+
auto interpolated_bottom_left = interpolate_value_impl(element, border_radius_rect_computation_context, from_bottom_left, to_bottom_left, delta, allow_discrete, color_resolution_context);
16771690

16781691
if (!interpolated_top_left || !interpolated_top_right || !interpolated_bottom_right || !interpolated_bottom_left)
16791692
return {};
16801693

16811694
return BorderRadiusRectStyleValue::create(interpolated_top_left.release_nonnull(), interpolated_top_right.release_nonnull(), interpolated_bottom_right.release_nonnull(), interpolated_bottom_left.release_nonnull());
16821695
}
1683-
case StyleValue::Type::Color: {
1684-
// NB: Called during style interpolation.
1685-
ColorResolutionContext color_resolution_context {};
1686-
if (auto* node = element.unsafe_layout_node())
1687-
color_resolution_context = ColorResolutionContext::for_layout_node_with_style(*node);
1688-
1689-
if (auto interpolated = interpolate_color(from, to, delta, {}, color_resolution_context))
1690-
return interpolated;
1691-
return ColorStyleValue::create_from_color(Color::Black, ColorSyntax::Modern);
1692-
}
1696+
case StyleValue::Type::Color:
1697+
VERIFY_NOT_REACHED();
16931698
case StyleValue::Type::Edge: {
16941699
auto const& from_offset = from.as_edge().offset();
16951700
auto const& to_offset = to.as_edge().offset();
16961701

1697-
if (auto interpolated_value = interpolate_value_impl(element, calculation_context, from_offset, to_offset, delta, allow_discrete))
1702+
if (auto interpolated_value = interpolate_value_impl(element, calculation_context, from_offset, to_offset, delta, allow_discrete, color_resolution_context))
16981703
return EdgeStyleValue::create({}, interpolated_value);
16991704

17001705
return {};
@@ -1846,10 +1851,10 @@ static RefPtr<StyleValue const> interpolate_value_impl(DOM::Element& element, Ca
18461851
auto const& from_rect = from.as_rect();
18471852
auto const& to_rect = to.as_rect();
18481853

1849-
auto interpolated_top = interpolate_value_impl(element, calculation_context, from_rect.top(), to_rect.top(), delta, allow_discrete);
1850-
auto interpolated_right = interpolate_value_impl(element, calculation_context, from_rect.right(), to_rect.right(), delta, allow_discrete);
1851-
auto interpolated_bottom = interpolate_value_impl(element, calculation_context, from_rect.bottom(), to_rect.bottom(), delta, allow_discrete);
1852-
auto interpolated_left = interpolate_value_impl(element, calculation_context, from_rect.left(), to_rect.left(), delta, allow_discrete);
1854+
auto interpolated_top = interpolate_value_impl(element, calculation_context, from_rect.top(), to_rect.top(), delta, allow_discrete, color_resolution_context);
1855+
auto interpolated_right = interpolate_value_impl(element, calculation_context, from_rect.right(), to_rect.right(), delta, allow_discrete, color_resolution_context);
1856+
auto interpolated_bottom = interpolate_value_impl(element, calculation_context, from_rect.bottom(), to_rect.bottom(), delta, allow_discrete, color_resolution_context);
1857+
auto interpolated_left = interpolate_value_impl(element, calculation_context, from_rect.left(), to_rect.left(), delta, allow_discrete, color_resolution_context);
18531858

18541859
if (!interpolated_top || !interpolated_right || !interpolated_bottom || !interpolated_left)
18551860
return {};
@@ -1966,7 +1971,7 @@ static RefPtr<StyleValue const> interpolate_value_impl(DOM::Element& element, Ca
19661971
StyleValueVector interpolated_values;
19671972
interpolated_values.ensure_capacity(from_list.size());
19681973
for (size_t i = 0; i < from_list.size(); ++i) {
1969-
auto interpolated = interpolate_value(element, calculation_context, from_list.values()[i], to_list.values()[i], delta, AllowDiscrete::No);
1974+
auto interpolated = interpolate_value(element, calculation_context, from_list.values()[i], to_list.values()[i], delta, AllowDiscrete::No, color_resolution_context);
19701975
if (!interpolated)
19711976
return {};
19721977

@@ -1980,7 +1985,7 @@ static RefPtr<StyleValue const> interpolate_value_impl(DOM::Element& element, Ca
19801985
}
19811986
}
19821987

1983-
RefPtr<StyleValue const> interpolate_repeatable_list(DOM::Element& element, CalculationContext const& calculation_context, StyleValue const& from, StyleValue const& to, float delta, AllowDiscrete allow_discrete)
1988+
RefPtr<StyleValue const> interpolate_repeatable_list(DOM::Element& element, CalculationContext const& calculation_context, StyleValue const& from, StyleValue const& to, float delta, AllowDiscrete allow_discrete, ColorResolutionContext const* color_resolution_context)
19841989
{
19851990
// https://www.w3.org/TR/web-animations/#repeatable-list
19861991
// Same as by computed value except that if the two lists have differing numbers of items, they are first repeated to the least common multiple number of items.
@@ -1993,7 +1998,7 @@ RefPtr<StyleValue const> interpolate_repeatable_list(DOM::Element& element, Calc
19931998
// then the property values combine as discrete
19941999
auto list_size = AK::lcm(from_list.size(), to_list.size());
19952000
for (size_t i = 0; i < list_size; ++i) {
1996-
auto value = interpolate_value(element, calculation_context, from_list.value_at(i, true), to_list.value_at(i, true), delta, AllowDiscrete::No);
2001+
auto value = interpolate_value(element, calculation_context, from_list.value_at(i, true), to_list.value_at(i, true), delta, AllowDiscrete::No, color_resolution_context);
19972002
if (!value)
19982003
return false;
19992004
append_callback(*value);
@@ -2017,7 +2022,7 @@ RefPtr<StyleValue const> interpolate_repeatable_list(DOM::Element& element, Calc
20172022
else if (!to.is_value_list() && from.is_value_list())
20182023
to_list = make_single_value_list(to, from.as_value_list().size(), from.as_value_list().separator());
20192024
else if (!from.is_value_list() && !to.is_value_list())
2020-
return interpolate_value(element, calculation_context, from, to, delta, allow_discrete);
2025+
return interpolate_value(element, calculation_context, from, to, delta, allow_discrete, color_resolution_context);
20212026

20222027
StyleValueVector interpolated_values;
20232028
if (!make_repeatable_list(from_list->as_value_list(), to_list->as_value_list(), [&](auto const& value) { interpolated_values.append(value); }))
@@ -2153,9 +2158,9 @@ static StyleValueVector accumulate_filter_function(StyleValueList const& underly
21532158
return result;
21542159
}
21552160

2156-
RefPtr<StyleValue const> interpolate_value(DOM::Element& element, CalculationContext const& calculation_context, StyleValue const& from, StyleValue const& to, float delta, AllowDiscrete allow_discrete)
2161+
RefPtr<StyleValue const> interpolate_value(DOM::Element& element, CalculationContext const& calculation_context, StyleValue const& from, StyleValue const& to, float delta, AllowDiscrete allow_discrete, ColorResolutionContext const* color_resolution_context)
21572162
{
2158-
if (auto result = interpolate_value_impl(element, calculation_context, from, to, delta, allow_discrete))
2163+
if (auto result = interpolate_value_impl(element, calculation_context, from, to, delta, allow_discrete, color_resolution_context))
21592164
return result;
21602165
return interpolate_discrete(from, to, delta, allow_discrete);
21612166
}

Libraries/LibWeb/CSS/Interpolation.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ enum class AllowDiscrete {
1818
Yes,
1919
No,
2020
};
21-
ValueComparingRefPtr<StyleValue const> interpolate_property(DOM::Element&, PropertyID, StyleValue const& from, StyleValue const& to, float delta, AllowDiscrete);
21+
ValueComparingRefPtr<StyleValue const> interpolate_property(DOM::Element&, PropertyID, StyleValue const& from, StyleValue const& to, float delta, AllowDiscrete, ColorResolutionContext const* = nullptr);
2222

2323
// https://drafts.csswg.org/css-transitions/#transitionable
2424
bool property_values_are_transitionable(PropertyID, StyleValue const& old_value, StyleValue const& new_value, DOM::Element&, TransitionBehavior);
2525

26-
RefPtr<StyleValue const> interpolate_value(DOM::Element&, CalculationContext const&, StyleValue const& from, StyleValue const& to, float delta, AllowDiscrete);
27-
RefPtr<StyleValue const> interpolate_repeatable_list(DOM::Element&, CalculationContext const&, StyleValue const& from, StyleValue const& to, float delta, AllowDiscrete);
26+
RefPtr<StyleValue const> interpolate_value(DOM::Element&, CalculationContext const&, StyleValue const& from, StyleValue const& to, float delta, AllowDiscrete, ColorResolutionContext const* = nullptr);
27+
RefPtr<StyleValue const> interpolate_repeatable_list(DOM::Element&, CalculationContext const&, StyleValue const& from, StyleValue const& to, float delta, AllowDiscrete, ColorResolutionContext const* = nullptr);
2828
RefPtr<StyleValue const> interpolate_box_shadow(DOM::Element&, CalculationContext const&, StyleValue const& from, StyleValue const& to, float delta, AllowDiscrete);
2929
RefPtr<StyleValue const> interpolate_transform(DOM::Element&, CalculationContext const&, StyleValue const& from, StyleValue const& to, float delta, AllowDiscrete);
3030

0 commit comments

Comments
 (0)