Skip to content

Commit 8476202

Browse files
Calme1709AtkinsSJ
authored andcommitted
LibWeb: Support triggering multiple animations per animation property
We also now use the computed (rather than cascaded) values when triggering animations.
1 parent 18477b0 commit 8476202

File tree

11 files changed

+316
-225
lines changed

11 files changed

+316
-225
lines changed

Libraries/LibWeb/Animations/Animatable.cpp

Lines changed: 14 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -246,10 +246,11 @@ void Animatable::visit_edges(JS::Cell::Visitor& visitor)
246246
{
247247
auto& impl = ensure_impl();
248248
visitor.visit(impl.associated_animations);
249-
for (auto const& cached_animation_source : impl.cached_animation_name_source)
250-
visitor.visit(cached_animation_source);
251-
for (auto const& cached_animation_name : impl.cached_animation_name_animation)
252-
visitor.visit(cached_animation_name);
249+
for (auto const& css_animation : impl.css_defined_animations) {
250+
if (css_animation)
251+
visitor.visit(*css_animation);
252+
}
253+
253254
for (auto const& transition : impl.transitions) {
254255
if (transition) {
255256
visitor.visit(transition->cached_transition_property_source);
@@ -258,61 +259,21 @@ void Animatable::visit_edges(JS::Cell::Visitor& visitor)
258259
}
259260
}
260261

261-
GC::Ptr<CSS::CSSStyleDeclaration const> Animatable::cached_animation_name_source(Optional<CSS::PseudoElement> pseudo_element) const
262-
{
263-
if (!m_impl)
264-
return {};
265-
auto& impl = *m_impl;
266-
if (pseudo_element.has_value()) {
267-
if (!CSS::Selector::PseudoElementSelector::is_known_pseudo_element_type(pseudo_element.value())) {
268-
return {};
269-
}
270-
return impl.cached_animation_name_source[to_underlying(pseudo_element.value()) + 1];
271-
}
272-
return impl.cached_animation_name_source[0];
273-
}
274-
275-
void Animatable::set_cached_animation_name_source(GC::Ptr<CSS::CSSStyleDeclaration const> value, Optional<CSS::PseudoElement> pseudo_element)
262+
HashMap<FlyString, GC::Ref<Animation>>* Animatable::css_defined_animations(Optional<CSS::PseudoElement> pseudo_element)
276263
{
277264
auto& impl = ensure_impl();
278-
if (pseudo_element.has_value()) {
279-
if (!CSS::Selector::PseudoElementSelector::is_known_pseudo_element_type(pseudo_element.value())) {
280-
return;
281-
}
282-
impl.cached_animation_name_source[to_underlying(pseudo_element.value()) + 1] = value;
283-
} else {
284-
impl.cached_animation_name_source[0] = value;
285-
}
286-
}
287265

288-
GC::Ptr<Animations::Animation> Animatable::cached_animation_name_animation(Optional<CSS::PseudoElement> pseudo_element) const
289-
{
290-
if (!m_impl)
291-
return {};
292-
auto& impl = *m_impl;
293-
294-
if (pseudo_element.has_value()) {
295-
if (!CSS::Selector::PseudoElementSelector::is_known_pseudo_element_type(pseudo_element.value())) {
296-
return {};
297-
}
266+
if (pseudo_element.has_value() && !CSS::Selector::PseudoElementSelector::is_known_pseudo_element_type(pseudo_element.value()))
267+
return nullptr;
298268

299-
return impl.cached_animation_name_animation[to_underlying(pseudo_element.value()) + 1];
300-
}
301-
return impl.cached_animation_name_animation[0];
302-
}
269+
auto index = pseudo_element
270+
.map([](CSS::PseudoElement pseudo_element_value) { return to_underlying(pseudo_element_value) + 1; })
271+
.value_or(0);
303272

304-
void Animatable::set_cached_animation_name_animation(GC::Ptr<Animations::Animation> value, Optional<CSS::PseudoElement> pseudo_element)
305-
{
306-
auto& impl = ensure_impl();
307-
if (pseudo_element.has_value()) {
308-
if (!CSS::Selector::PseudoElementSelector::is_known_pseudo_element_type(pseudo_element.value())) {
309-
return;
310-
}
273+
if (!impl.css_defined_animations[index])
274+
impl.css_defined_animations[index] = make<HashMap<FlyString, GC::Ref<Animation>>>();
311275

312-
impl.cached_animation_name_animation[to_underlying(pseudo_element.value()) + 1] = value;
313-
} else {
314-
impl.cached_animation_name_animation[0] = value;
315-
}
276+
return impl.css_defined_animations[index];
316277
}
317278

318279
GC::Ptr<CSS::CSSStyleDeclaration const> Animatable::cached_transition_property_source(Optional<CSS::PseudoElement> pseudo_element) const

Libraries/LibWeb/Animations/Animatable.h

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,9 @@ class WEB_API Animatable {
5252
void associate_with_animation(GC::Ref<Animation>);
5353
void disassociate_with_animation(GC::Ref<Animation>);
5454

55-
GC::Ptr<CSS::CSSStyleDeclaration const> cached_animation_name_source(Optional<CSS::PseudoElement>) const;
56-
void set_cached_animation_name_source(GC::Ptr<CSS::CSSStyleDeclaration const> value, Optional<CSS::PseudoElement>);
57-
58-
GC::Ptr<Animations::Animation> cached_animation_name_animation(Optional<CSS::PseudoElement>) const;
59-
void set_cached_animation_name_animation(GC::Ptr<Animations::Animation> value, Optional<CSS::PseudoElement>);
55+
HashMap<FlyString, GC::Ref<Animation>>* css_defined_animations(Optional<CSS::PseudoElement>);
56+
void add_css_animation(FlyString name, Optional<CSS::PseudoElement>, GC::Ref<Animation>);
57+
void remove_css_animation(FlyString name, Optional<CSS::PseudoElement>);
6058

6159
GC::Ptr<CSS::CSSStyleDeclaration const> cached_transition_property_source(Optional<CSS::PseudoElement>) const;
6260
void set_cached_transition_property_source(Optional<CSS::PseudoElement>, GC::Ptr<CSS::CSSStyleDeclaration const> value);
@@ -80,9 +78,7 @@ class WEB_API Animatable {
8078
Vector<GC::Ref<Animation>> associated_animations;
8179
bool is_sorted_by_composite_order { true };
8280

83-
Array<GC::Ptr<CSS::CSSStyleDeclaration const>, to_underlying(CSS::PseudoElement::KnownPseudoElementCount) + 1> cached_animation_name_source;
84-
Array<GC::Ptr<Animation>, to_underlying(CSS::PseudoElement::KnownPseudoElementCount) + 1> cached_animation_name_animation;
85-
81+
mutable Array<OwnPtr<HashMap<FlyString, GC::Ref<Animation>>>, to_underlying(CSS::PseudoElement::KnownPseudoElementCount) + 1> css_defined_animations;
8682
mutable Array<OwnPtr<Transition>, to_underlying(CSS::PseudoElement::KnownPseudoElementCount) + 1> transitions;
8783

8884
~Impl();

Libraries/LibWeb/CSS/ComputedProperties.cpp

Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include <LibWeb/CSS/StyleValues/StringStyleValue.h>
3838
#include <LibWeb/CSS/StyleValues/StyleValueList.h>
3939
#include <LibWeb/CSS/StyleValues/TextUnderlinePositionStyleValue.h>
40+
#include <LibWeb/CSS/StyleValues/TimeStyleValue.h>
4041
#include <LibWeb/CSS/StyleValues/TransformationStyleValue.h>
4142
#include <LibWeb/Layout/BlockContainer.h>
4243
#include <LibWeb/Layout/Node.h>
@@ -53,7 +54,6 @@ ComputedProperties::~ComputedProperties() = default;
5354
void ComputedProperties::visit_edges(Visitor& visitor)
5455
{
5556
Base::visit_edges(visitor);
56-
visitor.visit(m_animation_name_source);
5757
visitor.visit(m_transition_property_source);
5858
}
5959

@@ -1934,6 +1934,108 @@ Optional<FlyString> ComputedProperties::view_transition_name() const
19341934
return {};
19351935
}
19361936

1937+
Vector<ComputedProperties::AnimationProperties> ComputedProperties::animations() const
1938+
{
1939+
// CSS Animations are defined by binding keyframes to an element using the animation-* properties. These list-valued
1940+
// properties, which are all longhands of the animation shorthand, form a coordinating list property group with
1941+
// animation-name as the coordinating list base property and each item in the coordinated value list defining the
1942+
// properties of a single animation effect.
1943+
auto const& coordinated_properties = assemble_coordinated_value_list(
1944+
PropertyID::AnimationName,
1945+
{ PropertyID::AnimationDuration,
1946+
PropertyID::AnimationTimingFunction,
1947+
PropertyID::AnimationIterationCount,
1948+
PropertyID::AnimationDirection,
1949+
PropertyID::AnimationPlayState,
1950+
PropertyID::AnimationDelay,
1951+
PropertyID::AnimationFillMode,
1952+
PropertyID::AnimationComposition,
1953+
PropertyID::AnimationName });
1954+
1955+
Vector<AnimationProperties> animations;
1956+
1957+
for (size_t i = 0; i < coordinated_properties.get(PropertyID::AnimationName)->size(); i++) {
1958+
// https://drafts.csswg.org/css-animations-1/#propdef-animation-name
1959+
// none: No keyframes are specified at all, so there will be no animation. Any other animations properties
1960+
// specified for this animation have no effect.
1961+
if (coordinated_properties.get(PropertyID::AnimationName).value()[i]->to_keyword() == Keyword::None)
1962+
continue;
1963+
1964+
auto animation_name_style_value = coordinated_properties.get(PropertyID::AnimationName).value()[i];
1965+
auto animation_duration_style_value = coordinated_properties.get(PropertyID::AnimationDuration).value()[i];
1966+
auto animation_timing_function_style_value = coordinated_properties.get(PropertyID::AnimationTimingFunction).value()[i];
1967+
auto animation_iteration_count_style_value = coordinated_properties.get(PropertyID::AnimationIterationCount).value()[i];
1968+
auto animation_direction_style_value = coordinated_properties.get(PropertyID::AnimationDirection).value()[i];
1969+
auto animation_play_state_style_value = coordinated_properties.get(PropertyID::AnimationPlayState).value()[i];
1970+
auto animation_delay_style_value = coordinated_properties.get(PropertyID::AnimationDelay).value()[i];
1971+
auto animation_fill_mode_style_value = coordinated_properties.get(PropertyID::AnimationFillMode).value()[i];
1972+
auto animation_composition_style_value = coordinated_properties.get(PropertyID::AnimationComposition).value()[i];
1973+
1974+
auto duration = [&] {
1975+
if (animation_duration_style_value->is_time())
1976+
return animation_duration_style_value->as_time().time().to_milliseconds();
1977+
1978+
if (animation_duration_style_value->is_calculated())
1979+
return animation_duration_style_value->as_calculated().resolve_time({}).value().to_milliseconds();
1980+
1981+
VERIFY_NOT_REACHED();
1982+
}();
1983+
1984+
auto timing_function = EasingFunction::from_style_value(animation_timing_function_style_value);
1985+
1986+
auto iteration_count = [&] {
1987+
if (animation_iteration_count_style_value->to_keyword() == Keyword::Infinite)
1988+
return AK::Infinity<double>;
1989+
1990+
if (animation_iteration_count_style_value->is_number())
1991+
return animation_iteration_count_style_value->as_number().number();
1992+
1993+
if (animation_iteration_count_style_value->is_calculated())
1994+
return animation_iteration_count_style_value->as_calculated().resolve_number({}).value();
1995+
1996+
VERIFY_NOT_REACHED();
1997+
}();
1998+
1999+
auto direction = keyword_to_animation_direction(animation_direction_style_value->to_keyword()).value();
2000+
auto play_state = keyword_to_animation_play_state(animation_play_state_style_value->to_keyword()).value();
2001+
auto delay = [&] {
2002+
if (animation_delay_style_value->is_time())
2003+
return animation_delay_style_value->as_time().time().to_milliseconds();
2004+
2005+
if (animation_delay_style_value->is_calculated())
2006+
return animation_delay_style_value->as_calculated().resolve_time({}).value().to_milliseconds();
2007+
2008+
VERIFY_NOT_REACHED();
2009+
}();
2010+
auto fill_mode = keyword_to_animation_fill_mode(animation_fill_mode_style_value->to_keyword()).value();
2011+
auto composition = keyword_to_animation_composition(animation_composition_style_value->to_keyword()).value();
2012+
2013+
auto name = [&] {
2014+
if (animation_name_style_value->is_custom_ident())
2015+
return animation_name_style_value->as_custom_ident().custom_ident();
2016+
2017+
if (animation_name_style_value->is_string())
2018+
return animation_name_style_value->as_string().string_value();
2019+
2020+
VERIFY_NOT_REACHED();
2021+
}();
2022+
2023+
animations.append(AnimationProperties {
2024+
.duration = duration,
2025+
.timing_function = timing_function,
2026+
.iteration_count = iteration_count,
2027+
.direction = direction,
2028+
.play_state = play_state,
2029+
.delay = delay,
2030+
.fill_mode = fill_mode,
2031+
.composition = composition,
2032+
.name = name,
2033+
});
2034+
}
2035+
2036+
return animations;
2037+
}
2038+
19372039
MaskType ComputedProperties::mask_type() const
19382040
{
19392041
auto const& value = property(PropertyID::MaskType);

Libraries/LibWeb/CSS/ComputedProperties.h

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <LibGfx/Forward.h>
1717
#include <LibJS/Heap/Cell.h>
1818
#include <LibWeb/CSS/ComputedValues.h>
19+
#include <LibWeb/CSS/EasingFunction.h>
1920
#include <LibWeb/CSS/LengthBox.h>
2021
#include <LibWeb/CSS/PropertyID.h>
2122
#include <LibWeb/CSS/PseudoClass.h>
@@ -68,9 +69,6 @@ class WEB_API ComputedProperties final : public JS::Cell {
6869
StyleValue const& property(PropertyID, WithAnimationsApplied = WithAnimationsApplied::Yes) const;
6970
void revert_property(PropertyID, ComputedProperties const& style_for_revert);
7071

71-
GC::Ptr<CSSStyleDeclaration const> animation_name_source() const { return m_animation_name_source; }
72-
void set_animation_name_source(GC::Ptr<CSSStyleDeclaration const> declaration) { m_animation_name_source = declaration; }
73-
7472
GC::Ptr<CSSStyleDeclaration const> transition_property_source() const { return m_transition_property_source; }
7573
void set_transition_property_source(GC::Ptr<CSSStyleDeclaration const> declaration) { m_transition_property_source = declaration; }
7674

@@ -187,6 +185,18 @@ class WEB_API ComputedProperties final : public JS::Cell {
187185
ContainerType container_type() const;
188186
MixBlendMode mix_blend_mode() const;
189187
Optional<FlyString> view_transition_name() const;
188+
struct AnimationProperties {
189+
Variant<double, String> duration;
190+
EasingFunction timing_function;
191+
double iteration_count;
192+
AnimationDirection direction;
193+
AnimationPlayState play_state;
194+
double delay;
195+
AnimationFillMode fill_mode;
196+
AnimationComposition composition;
197+
FlyString name;
198+
};
199+
Vector<AnimationProperties> animations() const;
190200

191201
Display display_before_box_type_transformation() const;
192202
void set_display_before_box_type_transformation(Display value);
@@ -274,7 +284,6 @@ class WEB_API ComputedProperties final : public JS::Cell {
274284
Overflow overflow(PropertyID) const;
275285
Vector<ShadowData> shadow(PropertyID, Layout::Node const&) const;
276286

277-
GC::Ptr<CSSStyleDeclaration const> m_animation_name_source;
278287
GC::Ptr<CSSStyleDeclaration const> m_transition_property_source;
279288

280289
Array<RefPtr<StyleValue const>, number_of_longhand_properties> m_property_values;

0 commit comments

Comments
 (0)