LibWeb: Store property transitions in Animatable

Co-authored-by: Sam Atkins <sam@ladybird.org>
This commit is contained in:
Matthew Olsson 2024-07-03 14:21:19 +00:00 committed by Andreas Kling
parent 815a87100e
commit 392510c631
Notes: github-actions[bot] 2024-09-22 04:42:58 +00:00
2 changed files with 86 additions and 2 deletions

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2024, Matthew Olsson <mattco@serenityos.org>. * Copyright (c) 2024, Matthew Olsson <mattco@serenityos.org>
* Copyright (c) 2024, Sam Atkins <sam@ladybird.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -8,6 +9,9 @@
#include <LibWeb/Animations/Animatable.h> #include <LibWeb/Animations/Animatable.h>
#include <LibWeb/Animations/Animation.h> #include <LibWeb/Animations/Animation.h>
#include <LibWeb/Animations/DocumentTimeline.h> #include <LibWeb/Animations/DocumentTimeline.h>
#include <LibWeb/CSS/CSSTransition.h>
#include <LibWeb/CSS/StyleValues/EasingStyleValue.h>
#include <LibWeb/CSS/StyleValues/TimeStyleValue.h>
#include <LibWeb/DOM/Document.h> #include <LibWeb/DOM/Document.h>
#include <LibWeb/DOM/Element.h> #include <LibWeb/DOM/Element.h>
@ -99,6 +103,57 @@ void Animatable::disassociate_with_animation(JS::NonnullGCPtr<Animation> animati
m_associated_animations.remove_first_matching([&](auto element) { return animation == element; }); m_associated_animations.remove_first_matching([&](auto element) { return animation == element; });
} }
void Animatable::add_transitioned_properties(Vector<Vector<CSS::PropertyID>> properties, CSS::StyleValueVector delays, CSS::StyleValueVector durations, CSS::StyleValueVector timing_functions)
{
VERIFY(properties.size() == delays.size());
VERIFY(properties.size() == durations.size());
VERIFY(properties.size() == timing_functions.size());
for (size_t i = 0; i < properties.size(); i++) {
size_t index_of_this_transition = m_transition_attributes.size();
auto delay = delays[i]->is_time() ? delays[i]->as_time().time().to_milliseconds() : 0;
auto duration = durations[i]->is_time() ? durations[i]->as_time().time().to_milliseconds() : 0;
auto timing_function = timing_functions[i]->is_easing() ? timing_functions[i]->as_easing().function() : CSS::EasingStyleValue::CubicBezier::ease();
VERIFY(timing_functions[i]->is_easing());
m_transition_attributes.empend(delay, duration, timing_function);
for (auto const& property : properties[i])
m_transition_attribute_indices.set(property, index_of_this_transition);
}
}
Optional<Animatable::TransitionAttributes const&> Animatable::property_transition_attributes(CSS::PropertyID property) const
{
if (auto maybe_index = m_transition_attribute_indices.get(property); maybe_index.has_value())
return m_transition_attributes[maybe_index.value()];
return {};
}
JS::GCPtr<CSS::CSSTransition> Animatable::property_transition(CSS::PropertyID property) const
{
if (auto maybe_animation = m_associated_transitions.get(property); maybe_animation.has_value())
return maybe_animation.value();
return {};
}
void Animatable::set_transition(CSS::PropertyID property, JS::NonnullGCPtr<CSS::CSSTransition> animation)
{
VERIFY(!m_associated_transitions.contains(property));
m_associated_transitions.set(property, animation);
}
void Animatable::remove_transition(CSS::PropertyID property_id)
{
VERIFY(m_associated_transitions.contains(property_id));
m_associated_transitions.remove(property_id);
}
void Animatable::clear_transitions()
{
m_transition_attribute_indices.clear();
m_transition_attributes.clear();
}
void Animatable::visit_edges(JS::Cell::Visitor& visitor) void Animatable::visit_edges(JS::Cell::Visitor& visitor)
{ {
visitor.visit(m_associated_animations); visitor.visit(m_associated_animations);
@ -106,6 +161,8 @@ void Animatable::visit_edges(JS::Cell::Visitor& visitor)
visitor.visit(cached_animation_source); visitor.visit(cached_animation_source);
for (auto const& cached_animation_name : m_cached_animation_name_animation) for (auto const& cached_animation_name : m_cached_animation_name_animation)
visitor.visit(cached_animation_name); visitor.visit(cached_animation_name);
visitor.visit(m_cached_transition_property_source);
visitor.visit(m_associated_transitions);
} }
JS::GCPtr<CSS::CSSStyleDeclaration const> Animatable::cached_animation_name_source(Optional<CSS::Selector::PseudoElement::Type> pseudo_element) const JS::GCPtr<CSS::CSSStyleDeclaration const> Animatable::cached_animation_name_source(Optional<CSS::Selector::PseudoElement::Type> pseudo_element) const

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2024, Matthew Olsson <mattco@serenityos.org>. * Copyright (c) 2024, Matthew Olsson <mattco@serenityos.org>
* Copyright (c) 2024, Sam Atkins <sam@ladybird.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -7,8 +8,13 @@
#pragma once #pragma once
#include <AK/FlyString.h> #include <AK/FlyString.h>
#include <AK/HashMap.h>
#include <LibWeb/Animations/KeyframeEffect.h> #include <LibWeb/Animations/KeyframeEffect.h>
namespace Web::CSS {
class CSSTransition;
}
namespace Web::Animations { namespace Web::Animations {
// https://www.w3.org/TR/web-animations-1/#dictdef-keyframeanimationoptions // https://www.w3.org/TR/web-animations-1/#dictdef-keyframeanimationoptions
@ -25,6 +31,12 @@ struct GetAnimationsOptions {
// https://www.w3.org/TR/web-animations-1/#animatable // https://www.w3.org/TR/web-animations-1/#animatable
class Animatable { class Animatable {
public: public:
struct TransitionAttributes {
double delay;
double duration;
CSS::EasingStyleValue::Function timing_function;
};
virtual ~Animatable() = default; virtual ~Animatable() = default;
WebIDL::ExceptionOr<JS::NonnullGCPtr<Animation>> animate(Optional<JS::Handle<JS::Object>> keyframes, Variant<Empty, double, KeyframeAnimationOptions> options = {}); WebIDL::ExceptionOr<JS::NonnullGCPtr<Animation>> animate(Optional<JS::Handle<JS::Object>> keyframes, Variant<Empty, double, KeyframeAnimationOptions> options = {});
@ -39,6 +51,16 @@ public:
JS::GCPtr<Animations::Animation> cached_animation_name_animation(Optional<CSS::Selector::PseudoElement::Type>) const; JS::GCPtr<Animations::Animation> cached_animation_name_animation(Optional<CSS::Selector::PseudoElement::Type>) const;
void set_cached_animation_name_animation(JS::GCPtr<Animations::Animation> value, Optional<CSS::Selector::PseudoElement::Type>); void set_cached_animation_name_animation(JS::GCPtr<Animations::Animation> value, Optional<CSS::Selector::PseudoElement::Type>);
JS::GCPtr<CSS::CSSStyleDeclaration const> cached_transition_property_source() const { return m_cached_transition_property_source; }
void set_cached_transition_property_source(JS::GCPtr<CSS::CSSStyleDeclaration const> value) { m_cached_transition_property_source = value; }
void add_transitioned_properties(Vector<Vector<CSS::PropertyID>> properties, CSS::StyleValueVector delays, CSS::StyleValueVector durations, CSS::StyleValueVector timing_functions);
Optional<TransitionAttributes const&> property_transition_attributes(CSS::PropertyID) const;
void set_transition(CSS::PropertyID, JS::NonnullGCPtr<CSS::CSSTransition>);
void remove_transition(CSS::PropertyID);
JS::GCPtr<CSS::CSSTransition> property_transition(CSS::PropertyID) const;
void clear_transitions();
protected: protected:
void visit_edges(JS::Cell::Visitor&); void visit_edges(JS::Cell::Visitor&);
@ -48,6 +70,11 @@ private:
Array<JS::GCPtr<CSS::CSSStyleDeclaration const>, to_underlying(CSS::Selector::PseudoElement::Type::KnownPseudoElementCount) + 1> m_cached_animation_name_source; Array<JS::GCPtr<CSS::CSSStyleDeclaration const>, to_underlying(CSS::Selector::PseudoElement::Type::KnownPseudoElementCount) + 1> m_cached_animation_name_source;
Array<JS::GCPtr<Animations::Animation>, to_underlying(CSS::Selector::PseudoElement::Type::KnownPseudoElementCount) + 1> m_cached_animation_name_animation; Array<JS::GCPtr<Animations::Animation>, to_underlying(CSS::Selector::PseudoElement::Type::KnownPseudoElementCount) + 1> m_cached_animation_name_animation;
HashMap<CSS::PropertyID, size_t> m_transition_attribute_indices;
Vector<TransitionAttributes> m_transition_attributes;
JS::GCPtr<CSS::CSSStyleDeclaration const> m_cached_transition_property_source;
HashMap<CSS::PropertyID, JS::NonnullGCPtr<CSS::CSSTransition>> m_associated_transitions;
}; };
} }