/* * Copyright (c) 2023-2024, Matthew Olsson * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include #include #include namespace Web::Animations { using EasingValue = Variant>; // https://www.w3.org/TR/web-animations-1/#the-keyframeeffectoptions-dictionary struct KeyframeEffectOptions : public EffectTiming { Bindings::CompositeOperation composite { Bindings::CompositeOperation::Replace }; Optional pseudo_element {}; }; // https://www.w3.org/TR/web-animations-1/#dictdef-basepropertyindexedkeyframe // Note: This is an intermediate structure used only when parsing Keyframes provided by the caller in a slightly // different format. It is converted to BaseKeyframe, which is why it doesn't need to store the parsed properties struct BasePropertyIndexedKeyframe { Variant, Vector>> offset { Vector> {} }; Variant> easing { Vector {} }; Variant> composite { Vector {} }; HashMap> properties {}; }; // https://www.w3.org/TR/web-animations-1/#dictdef-basekeyframe struct BaseKeyframe { using UnparsedProperties = HashMap; using ParsedProperties = HashMap>; Optional offset {}; EasingValue easing { "linear"_string }; Bindings::CompositeOperationOrAuto composite { Bindings::CompositeOperationOrAuto::Auto }; Optional computed_offset {}; Variant properties { UnparsedProperties {} }; UnparsedProperties& unparsed_properties() { return properties.get(); } ParsedProperties& parsed_properties() { return properties.get(); } }; // https://www.w3.org/TR/web-animations-1/#the-keyframeeffect-interface class KeyframeEffect : public AnimationEffect { WEB_PLATFORM_OBJECT(KeyframeEffect, AnimationEffect); GC_DECLARE_ALLOCATOR(KeyframeEffect); public: constexpr static double AnimationKeyFrameKeyScaleFactor = 1000.0; // 0..100000 struct KeyFrameSet : public RefCounted { struct UseInitial { }; struct ResolvedKeyFrame { // These CSSStyleValue properties can be unresolved, as they may be generated from a @keyframes rule, well // before they are applied to an element HashMap>> properties {}; }; RedBlackTree keyframes_by_key; }; static void generate_initial_and_final_frames(RefPtr, HashTable const& animated_properties); static int composite_order(GC::Ref, GC::Ref); static GC::Ref create(JS::Realm&); static WebIDL::ExceptionOr> construct_impl( JS::Realm&, GC::Root const& target, Optional> const& keyframes, Variant options = KeyframeEffectOptions {}); static WebIDL::ExceptionOr> construct_impl(JS::Realm&, GC::Ref source); DOM::Element* target() const override { return m_target_element; } void set_target(DOM::Element* target); // JS bindings Optional pseudo_element() const; WebIDL::ExceptionOr set_pseudo_element(Optional); Optional pseudo_element_type() const; void set_pseudo_element(Optional pseudo_element) { m_target_pseudo_selector = pseudo_element; } Bindings::CompositeOperation composite() const { return m_composite; } void set_composite(Bindings::CompositeOperation value) { m_composite = value; } WebIDL::ExceptionOr> get_keyframes(); WebIDL::ExceptionOr set_keyframes(Optional> const&); KeyFrameSet const* key_frame_set() { return m_key_frame_set; } void set_key_frame_set(RefPtr key_frame_set) { m_key_frame_set = key_frame_set; } virtual bool is_keyframe_effect() const override { return true; } virtual void update_computed_properties() override; Optional last_css_animation_play_state() const { return m_last_css_animation_play_state; } void set_last_css_animation_play_state(CSS::AnimationPlayState state) { m_last_css_animation_play_state = state; } private: KeyframeEffect(JS::Realm&); virtual ~KeyframeEffect() override = default; virtual void initialize(JS::Realm&) override; virtual void visit_edges(Cell::Visitor&) override; // https://www.w3.org/TR/web-animations-1/#effect-target-target-element GC::Ptr m_target_element {}; // https://www.w3.org/TR/web-animations-1/#dom-keyframeeffect-pseudoelement Optional m_target_pseudo_selector {}; // https://www.w3.org/TR/web-animations-1/#dom-keyframeeffect-composite Bindings::CompositeOperation m_composite { Bindings::CompositeOperation::Replace }; // https://www.w3.org/TR/web-animations-1/#keyframe Vector m_keyframes {}; // A cached version of m_keyframes suitable for returning from get_keyframes() Vector> m_keyframe_objects {}; RefPtr m_key_frame_set {}; Optional m_last_css_animation_play_state; }; }