mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 13:32:45 +00:00 
			
		
		
		
	LibWeb: Transition StyleComputer to Web Animations
With this commit, we are finally running animations off of the web animations spec! A lot of the work StyleComputer is doing is now done elsewhere. For example, fill-forward animations are handled by Animation::is_relevant() returning true in the after phase, meaning the "active_state_if_fill_forward" map is no longer needed.
This commit is contained in:
		
							parent
							
								
									b258ba2767
								
							
						
					
					
						commit
						ae3326a447
					
				
					 7 changed files with 270 additions and 647 deletions
				
			
		|  | @ -10,7 +10,7 @@ | |||
| #include <AK/HashMap.h> | ||||
| #include <AK/Optional.h> | ||||
| #include <AK/OwnPtr.h> | ||||
| #include <AK/RedBlackTree.h> | ||||
| #include <LibWeb/Animations/KeyframeEffect.h> | ||||
| #include <LibWeb/CSS/CSSFontFaceRule.h> | ||||
| #include <LibWeb/CSS/CSSKeyframesRule.h> | ||||
| #include <LibWeb/CSS/CSSStyleDeclaration.h> | ||||
|  | @ -73,42 +73,6 @@ public: | |||
| 
 | ||||
|     RefPtr<Gfx::FontCascadeList const> compute_font_for_style_values(DOM::Element const* element, Optional<CSS::Selector::PseudoElement::Type> pseudo_element, StyleValue const& font_family, StyleValue const& font_size, StyleValue const& font_style, StyleValue const& font_weight, StyleValue const& font_stretch, int math_depth = 0) const; | ||||
| 
 | ||||
|     struct AnimationKey { | ||||
|         CSS::CSSStyleDeclaration const* source_declaration; | ||||
|         DOM::Element const* element; | ||||
|     }; | ||||
| 
 | ||||
|     struct AnimationTiming { | ||||
|         struct Linear { }; | ||||
|         struct CubicBezier { | ||||
|             // Regular parameters
 | ||||
|             double x1; | ||||
|             double y1; | ||||
|             double x2; | ||||
|             double y2; | ||||
| 
 | ||||
|             struct CachedSample { | ||||
|                 double x; | ||||
|                 double y; | ||||
|                 double t; | ||||
|             }; | ||||
|             mutable Vector<CachedSample, 64> m_cached_x_samples = {}; | ||||
| 
 | ||||
|             CachedSample sample_around(double x) const; | ||||
|             bool operator==(CubicBezier const& other) const | ||||
|             { | ||||
|                 return x1 == other.x1 && y1 == other.y1 && x2 == other.x2 && y2 == other.y2; | ||||
|             } | ||||
|         }; | ||||
|         struct Steps { | ||||
|             size_t number_of_steps; | ||||
|             bool jump_at_start; | ||||
|             bool jump_at_end; | ||||
|         }; | ||||
| 
 | ||||
|         Variant<Linear, CubicBezier, Steps> timing_function; | ||||
|     }; | ||||
| 
 | ||||
|     void set_viewport_rect(Badge<DOM::Document>, CSSPixelRect const& viewport_rect) { m_viewport_rect = viewport_rect; } | ||||
| 
 | ||||
| private: | ||||
|  | @ -156,28 +120,20 @@ private: | |||
| 
 | ||||
|     JS::NonnullGCPtr<DOM::Document> m_document; | ||||
| 
 | ||||
|     struct AnimationKeyFrameSet { | ||||
|         struct ResolvedKeyFrame { | ||||
|             struct UseInitial { }; | ||||
|             Array<Variant<Empty, UseInitial, NonnullRefPtr<StyleValue const>>, to_underlying(last_property_id) + 1> resolved_properties {}; | ||||
|         }; | ||||
|         RedBlackTree<u64, ResolvedKeyFrame> keyframes_by_key; | ||||
|     }; | ||||
| 
 | ||||
|     struct RuleCache { | ||||
|         HashMap<FlyString, Vector<MatchingRule>> rules_by_id; | ||||
|         HashMap<FlyString, Vector<MatchingRule>> rules_by_class; | ||||
|         HashMap<FlyString, Vector<MatchingRule>> rules_by_tag_name; | ||||
|         Vector<MatchingRule> other_rules; | ||||
| 
 | ||||
|         HashMap<FlyString, NonnullOwnPtr<AnimationKeyFrameSet>> rules_by_animation_keyframes; | ||||
|         HashMap<FlyString, NonnullRefPtr<Animations::KeyframeEffect::KeyFrameSet>> rules_by_animation_keyframes; | ||||
|     }; | ||||
| 
 | ||||
|     NonnullOwnPtr<RuleCache> make_rule_cache_for_cascade_origin(CascadeOrigin); | ||||
| 
 | ||||
|     RuleCache const& rule_cache_for_cascade_origin(CascadeOrigin) const; | ||||
| 
 | ||||
|     void ensure_animation_timer() const; | ||||
|     ErrorOr<void> collect_animation_into(JS::NonnullGCPtr<Animations::KeyframeEffect> animation, StyleProperties& style_properties) const; | ||||
| 
 | ||||
|     OwnPtr<RuleCache> m_author_rule_cache; | ||||
|     OwnPtr<RuleCache> m_user_rule_cache; | ||||
|  | @ -190,71 +146,7 @@ private: | |||
|     Length::FontMetrics m_default_font_metrics; | ||||
|     Length::FontMetrics m_root_element_font_metrics; | ||||
| 
 | ||||
|     constexpr static u64 AnimationKeyFrameKeyScaleFactor = 1000; // 0..100000
 | ||||
| 
 | ||||
|     enum class AnimationStepTransition { | ||||
|         NoTransition, | ||||
|         IdleOrBeforeToActive, | ||||
|         IdleOrBeforeToAfter, | ||||
|         ActiveToBefore, | ||||
|         ActiveToActiveChangingTheIteration, | ||||
|         ActiveToAfter, | ||||
|         AfterToActive, | ||||
|         AfterToBefore, | ||||
|         Cancelled, | ||||
|     }; | ||||
|     enum class AnimationState { | ||||
|         Before, | ||||
|         After, | ||||
|         Idle, | ||||
|         Active, | ||||
|     }; | ||||
| 
 | ||||
|     struct AnimationStateSnapshot { | ||||
|         Array<RefPtr<StyleValue const>, to_underlying(last_property_id) + 1> state; | ||||
|     }; | ||||
| 
 | ||||
|     struct Animation { | ||||
|         String name; | ||||
|         Optional<CSS::Time> duration; // "auto" if not set.
 | ||||
|         CSS::Time delay; | ||||
|         Optional<size_t> iteration_count; // Infinite if not set.
 | ||||
|         AnimationTiming timing_function; | ||||
|         CSS::AnimationDirection direction; | ||||
|         CSS::AnimationFillMode fill_mode; | ||||
|         WeakPtr<DOM::Element> owning_element; | ||||
| 
 | ||||
|         CSS::Percentage progress { 0 }; | ||||
|         CSS::Time remaining_delay { 0, CSS::Time::Type::Ms }; | ||||
|         AnimationState current_state { AnimationState::Before }; | ||||
|         size_t current_iteration { 1 }; | ||||
| 
 | ||||
|         mutable AnimationStateSnapshot initial_state {}; | ||||
|         mutable OwnPtr<AnimationStateSnapshot> active_state_if_fill_forward {}; | ||||
| 
 | ||||
|         AnimationStepTransition step(CSS::Time const& time_step); | ||||
|         ErrorOr<void> collect_into(StyleProperties&, RuleCache const&) const; | ||||
|         bool is_done() const; | ||||
| 
 | ||||
|     private: | ||||
|         float compute_output_progress(float input_progress) const; | ||||
|         bool is_animating_backwards() const; | ||||
|     }; | ||||
| 
 | ||||
|     mutable HashMap<AnimationKey, NonnullOwnPtr<Animation>> m_active_animations; | ||||
|     mutable HashMap<AnimationKey, OwnPtr<AnimationStateSnapshot>> m_finished_animations; // If fill-mode is forward/both, this is non-null and contains the final state.
 | ||||
|     mutable RefPtr<Platform::Timer> m_animation_driver_timer; | ||||
| 
 | ||||
|     CSSPixelRect m_viewport_rect; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| template<> | ||||
| struct AK::Traits<Web::CSS::StyleComputer::AnimationKey> : public AK::DefaultTraits<Web::CSS::StyleComputer::AnimationKey> { | ||||
|     static unsigned hash(Web::CSS::StyleComputer::AnimationKey const& k) { return pair_int_hash(ptr_hash(k.source_declaration), ptr_hash(k.element)); } | ||||
|     static bool equals(Web::CSS::StyleComputer::AnimationKey const& a, Web::CSS::StyleComputer::AnimationKey const& b) | ||||
|     { | ||||
|         return a.element == b.element && a.source_declaration == b.source_declaration; | ||||
|     } | ||||
| }; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Matthew Olsson
						Matthew Olsson