| 
									
										
										
										
											2023-11-04 13:09:57 -07:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2023-11-04 13:20:35 -07:00
										 |  |  |  * Copyright (c) 2023-2024, Matthew Olsson <mattco@serenityos.org> | 
					
						
							| 
									
										
										
										
											2023-11-04 13:09:57 -07:00
										 |  |  |  * | 
					
						
							|  |  |  |  * SPDX-License-Identifier: BSD-2-Clause | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #pragma once
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <AK/Optional.h>
 | 
					
						
							| 
									
										
										
										
											2024-02-02 16:29:11 -07:00
										 |  |  | #include <AK/RedBlackTree.h>
 | 
					
						
							| 
									
										
										
										
											2023-11-04 13:09:57 -07:00
										 |  |  | #include <LibWeb/Animations/AnimationEffect.h>
 | 
					
						
							|  |  |  | #include <LibWeb/Bindings/KeyframeEffectPrototype.h>
 | 
					
						
							|  |  |  | #include <LibWeb/Bindings/PlatformObject.h>
 | 
					
						
							| 
									
										
										
										
											2024-08-14 11:10:54 +01:00
										 |  |  | #include <LibWeb/CSS/CSSStyleValue.h>
 | 
					
						
							| 
									
										
										
										
											2023-11-04 13:20:35 -07:00
										 |  |  | #include <LibWeb/CSS/PropertyID.h>
 | 
					
						
							| 
									
										
										
										
											2024-02-25 10:02:01 -07:00
										 |  |  | #include <LibWeb/CSS/Selector.h>
 | 
					
						
							| 
									
										
										
										
											2023-11-04 13:09:57 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace Web::Animations { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-14 11:10:54 +01:00
										 |  |  | using EasingValue = Variant<String, NonnullRefPtr<CSS::CSSStyleValue const>>; | 
					
						
							| 
									
										
										
										
											2023-11-04 13:20:35 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-04 13:09:57 -07:00
										 |  |  | // https://www.w3.org/TR/web-animations-1/#the-keyframeeffectoptions-dictionary
 | 
					
						
							|  |  |  | struct KeyframeEffectOptions : public EffectTiming { | 
					
						
							|  |  |  |     Bindings::CompositeOperation composite { Bindings::CompositeOperation::Replace }; | 
					
						
							|  |  |  |     Optional<String> pseudo_element {}; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // https://www.w3.org/TR/web-animations-1/#dictdef-basepropertyindexedkeyframe
 | 
					
						
							| 
									
										
										
										
											2023-11-04 13:20:35 -07:00
										 |  |  | // 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
 | 
					
						
							| 
									
										
										
										
											2023-11-04 13:09:57 -07:00
										 |  |  | struct BasePropertyIndexedKeyframe { | 
					
						
							|  |  |  |     Variant<Optional<double>, Vector<Optional<double>>> offset { Vector<Optional<double>> {} }; | 
					
						
							| 
									
										
										
										
											2023-11-04 13:20:35 -07:00
										 |  |  |     Variant<EasingValue, Vector<EasingValue>> easing { Vector<EasingValue> {} }; | 
					
						
							| 
									
										
										
										
											2023-11-04 13:09:57 -07:00
										 |  |  |     Variant<Bindings::CompositeOperationOrAuto, Vector<Bindings::CompositeOperationOrAuto>> composite { Vector<Bindings::CompositeOperationOrAuto> {} }; | 
					
						
							| 
									
										
										
										
											2023-11-04 13:20:35 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     HashMap<String, Vector<String>> properties {}; | 
					
						
							| 
									
										
										
										
											2023-11-04 13:09:57 -07:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // https://www.w3.org/TR/web-animations-1/#dictdef-basekeyframe
 | 
					
						
							|  |  |  | struct BaseKeyframe { | 
					
						
							| 
									
										
										
										
											2023-11-04 13:20:35 -07:00
										 |  |  |     using UnparsedProperties = HashMap<String, String>; | 
					
						
							| 
									
										
										
										
											2024-08-14 11:10:54 +01:00
										 |  |  |     using ParsedProperties = HashMap<CSS::PropertyID, NonnullRefPtr<CSS::CSSStyleValue const>>; | 
					
						
							| 
									
										
										
										
											2023-11-04 13:20:35 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-04 13:09:57 -07:00
										 |  |  |     Optional<double> offset {}; | 
					
						
							| 
									
										
										
										
											2023-11-04 13:20:35 -07:00
										 |  |  |     EasingValue easing { "linear"_string }; | 
					
						
							| 
									
										
										
										
											2023-11-04 13:09:57 -07:00
										 |  |  |     Bindings::CompositeOperationOrAuto composite { Bindings::CompositeOperationOrAuto::Auto }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Optional<double> computed_offset {}; | 
					
						
							| 
									
										
										
										
											2023-11-04 13:20:35 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     Variant<UnparsedProperties, ParsedProperties> properties { UnparsedProperties {} }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     UnparsedProperties& unparsed_properties() { return properties.get<UnparsedProperties>(); } | 
					
						
							|  |  |  |     ParsedProperties& parsed_properties() { return properties.get<ParsedProperties>(); } | 
					
						
							| 
									
										
										
										
											2023-11-04 13:09:57 -07:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // https://www.w3.org/TR/web-animations-1/#the-keyframeeffect-interface
 | 
					
						
							|  |  |  | class KeyframeEffect : public AnimationEffect { | 
					
						
							|  |  |  |     WEB_PLATFORM_OBJECT(KeyframeEffect, AnimationEffect); | 
					
						
							| 
									
										
										
										
											2024-11-15 04:01:23 +13:00
										 |  |  |     GC_DECLARE_ALLOCATOR(KeyframeEffect); | 
					
						
							| 
									
										
										
										
											2023-11-04 13:09:57 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2024-02-03 12:51:15 -07:00
										 |  |  |     constexpr static double AnimationKeyFrameKeyScaleFactor = 1000.0; // 0..100000
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-02 16:29:11 -07:00
										 |  |  |     struct KeyFrameSet : public RefCounted<KeyFrameSet> { | 
					
						
							|  |  |  |         struct UseInitial { }; | 
					
						
							|  |  |  |         struct ResolvedKeyFrame { | 
					
						
							| 
									
										
										
										
											2024-08-14 11:10:54 +01:00
										 |  |  |             // These CSSStyleValue properties can be unresolved, as they may be generated from a @keyframes rule, well
 | 
					
						
							| 
									
										
										
										
											2024-03-17 17:22:12 -07:00
										 |  |  |             // before they are applied to an element
 | 
					
						
							| 
									
										
										
										
											2024-08-14 11:10:54 +01:00
										 |  |  |             HashMap<CSS::PropertyID, Variant<UseInitial, NonnullRefPtr<CSS::CSSStyleValue const>>> properties {}; | 
					
						
							| 
									
										
										
										
											2024-02-02 16:29:11 -07:00
										 |  |  |         }; | 
					
						
							|  |  |  |         RedBlackTree<u64, ResolvedKeyFrame> keyframes_by_key; | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2024-02-03 12:51:15 -07:00
										 |  |  |     static void generate_initial_and_final_frames(RefPtr<KeyFrameSet>, HashTable<CSS::PropertyID> const& animated_properties); | 
					
						
							| 
									
										
										
										
											2024-02-02 16:29:11 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-15 04:01:23 +13:00
										 |  |  |     static int composite_order(GC::Ref<KeyframeEffect>, GC::Ref<KeyframeEffect>); | 
					
						
							| 
									
										
										
										
											2024-02-19 13:54:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-15 04:01:23 +13:00
										 |  |  |     static GC::Ref<KeyframeEffect> create(JS::Realm&); | 
					
						
							| 
									
										
										
										
											2023-11-04 13:09:57 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-15 04:01:23 +13:00
										 |  |  |     static WebIDL::ExceptionOr<GC::Ref<KeyframeEffect>> construct_impl( | 
					
						
							| 
									
										
										
										
											2023-11-04 13:09:57 -07:00
										 |  |  |         JS::Realm&, | 
					
						
							| 
									
										
										
										
											2024-11-15 04:01:23 +13:00
										 |  |  |         GC::Root<DOM::Element> const& target, | 
					
						
							|  |  |  |         Optional<GC::Root<JS::Object>> const& keyframes, | 
					
						
							| 
									
										
										
										
											2023-11-04 13:09:57 -07:00
										 |  |  |         Variant<double, KeyframeEffectOptions> options = KeyframeEffectOptions {}); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-15 04:01:23 +13:00
										 |  |  |     static WebIDL::ExceptionOr<GC::Ref<KeyframeEffect>> construct_impl(JS::Realm&, GC::Ref<KeyframeEffect> source); | 
					
						
							| 
									
										
										
										
											2023-11-04 13:09:57 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     DOM::Element* target() const override { return m_target_element; } | 
					
						
							| 
									
										
										
										
											2024-02-03 12:10:44 -07:00
										 |  |  |     void set_target(DOM::Element* target); | 
					
						
							| 
									
										
										
										
											2023-11-04 13:09:57 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-25 10:02:01 -07:00
										 |  |  |     // JS bindings
 | 
					
						
							| 
									
										
										
										
											2024-05-27 06:44:46 -07:00
										 |  |  |     Optional<String> pseudo_element() const; | 
					
						
							| 
									
										
										
										
											2024-02-25 10:02:01 -07:00
										 |  |  |     WebIDL::ExceptionOr<void> set_pseudo_element(Optional<String>); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Optional<CSS::Selector::PseudoElement::Type> pseudo_element_type() const; | 
					
						
							|  |  |  |     void set_pseudo_element(Optional<CSS::Selector::PseudoElement> pseudo_element) { m_target_pseudo_selector = pseudo_element; } | 
					
						
							| 
									
										
										
										
											2023-11-04 13:09:57 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     Bindings::CompositeOperation composite() const { return m_composite; } | 
					
						
							|  |  |  |     void set_composite(Bindings::CompositeOperation value) { m_composite = value; } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-26 14:32:52 +01:00
										 |  |  |     WebIDL::ExceptionOr<GC::RootVector<JS::Object*>> get_keyframes(); | 
					
						
							| 
									
										
										
										
											2024-11-15 04:01:23 +13:00
										 |  |  |     WebIDL::ExceptionOr<void> set_keyframes(Optional<GC::Root<JS::Object>> const&); | 
					
						
							| 
									
										
										
										
											2023-11-04 13:09:57 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-02 16:29:11 -07:00
										 |  |  |     KeyFrameSet const* key_frame_set() { return m_key_frame_set; } | 
					
						
							|  |  |  |     void set_key_frame_set(RefPtr<KeyFrameSet const> key_frame_set) { m_key_frame_set = key_frame_set; } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-03 18:21:29 -07:00
										 |  |  |     virtual bool is_keyframe_effect() const override { return true; } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-20 11:32:17 +01:00
										 |  |  |     virtual void update_computed_properties() override; | 
					
						
							| 
									
										
										
										
											2024-03-16 07:44:48 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-26 17:02:27 -07:00
										 |  |  |     Optional<CSS::AnimationPlayState> 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; } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-04 13:09:57 -07:00
										 |  |  | private: | 
					
						
							|  |  |  |     KeyframeEffect(JS::Realm&); | 
					
						
							| 
									
										
										
										
											2024-03-07 11:11:27 -07:00
										 |  |  |     virtual ~KeyframeEffect() override = default; | 
					
						
							| 
									
										
										
										
											2023-11-04 13:09:57 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     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
 | 
					
						
							| 
									
										
										
										
											2024-11-15 04:01:23 +13:00
										 |  |  |     GC::Ptr<DOM::Element> m_target_element {}; | 
					
						
							| 
									
										
										
										
											2023-11-04 13:09:57 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // https://www.w3.org/TR/web-animations-1/#dom-keyframeeffect-pseudoelement
 | 
					
						
							| 
									
										
										
										
											2024-02-25 10:02:01 -07:00
										 |  |  |     Optional<CSS::Selector::PseudoElement> m_target_pseudo_selector {}; | 
					
						
							| 
									
										
										
										
											2023-11-04 13:09:57 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // 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<BaseKeyframe> m_keyframes {}; | 
					
						
							| 
									
										
										
										
											2024-02-12 13:51:36 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // A cached version of m_keyframes suitable for returning from get_keyframes()
 | 
					
						
							| 
									
										
										
										
											2024-11-15 04:01:23 +13:00
										 |  |  |     Vector<GC::Ref<JS::Object>> m_keyframe_objects {}; | 
					
						
							| 
									
										
										
										
											2024-02-02 16:29:11 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     RefPtr<KeyFrameSet const> m_key_frame_set {}; | 
					
						
							| 
									
										
										
										
											2024-03-26 17:02:27 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     Optional<CSS::AnimationPlayState> m_last_css_animation_play_state; | 
					
						
							| 
									
										
										
										
											2023-11-04 13:09:57 -07:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } |