1/*
2 * Copyright (C) 2007 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#pragma once
30
31#include "Animation.h"
32#include "CSSPropertyBlendingClient.h"
33#include "CSSPropertyNames.h"
34#include "RenderStyleConstants.h"
35
36namespace WebCore {
37
38class CompositeAnimation;
39class Element;
40class FloatRect;
41class LayoutRect;
42class RenderElement;
43class RenderStyle;
44class TimingFunction;
45
46enum class AnimateChange {
47 StyleBlended = 1 << 0, // Style was changed.
48 StateChange = 1 << 1, // Animation state() changed.
49 RunningStateChange = 1 << 2, // Animation "running or paused" changed.
50};
51
52class AnimationBase : public RefCounted<AnimationBase>
53 , public CSSPropertyBlendingClient {
54 friend class CompositeAnimation;
55 friend class CSSPropertyAnimation;
56 WTF_MAKE_FAST_ALLOCATED;
57public:
58 AnimationBase(const Animation& transition, Element&, CompositeAnimation&);
59 virtual ~AnimationBase();
60
61 Element* element() const { return m_element.get(); }
62 const RenderStyle& currentStyle() const override;
63 RenderElement* renderer() const override;
64 virtual void clear();
65
66 double duration() const;
67
68 // Animations and Transitions go through the states below. When entering the STARTED state
69 // the animation is started. This may or may not require deferred response from the animator.
70 // If so, we stay in this state until that response is received (and it returns the start time).
71 // Otherwise, we use the current time as the start time and go immediately to AnimationState::Looping
72 // or AnimationState::Ending.
73 enum class AnimationState : uint8_t {
74 New, // animation just created, animation not running yet
75 StartWaitTimer, // start timer running, waiting for fire
76 StartWaitStyleAvailable, // waiting for style setup so we can start animations
77 StartWaitResponse, // animation started, waiting for response
78 Looping, // response received, animation running, loop timer running, waiting for fire
79 Ending, // received, animation running, end timer running, waiting for fire
80 PausedNew, // in pause mode when animation was created
81 PausedWaitTimer, // in pause mode when animation started
82 PausedWaitStyleAvailable, // in pause mode when waiting for style setup
83 PausedWaitResponse, // animation paused when in STARTING state
84 PausedRun, // animation paused when in LOOPING or ENDING state
85 Done, // end timer fired, animation finished and removed
86 FillingForwards // animation has ended and is retaining its final value
87 };
88
89 enum class AnimationStateInput : uint8_t {
90 MakeNew, // reset back to new from any state
91 StartAnimation, // animation requests a start
92 RestartAnimation, // force a restart from any state
93 StartTimerFired, // start timer fired
94 StyleAvailable, // style is setup, ready to start animating
95 StartTimeSet, // m_startTime was set
96 LoopTimerFired, // loop timer fired
97 EndTimerFired, // end timer fired
98 PauseOverride, // pause an animation due to override
99 ResumeOverride, // resume an overridden animation
100 PlayStateRunning, // play state paused -> running
101 PlayStatePaused, // play state running -> paused
102 EndAnimation // force an end from any state
103 };
104
105 // Called when animation is in AnimationState::New to start animation
106 void updateStateMachine(AnimationStateInput, double param);
107
108 // Animation has actually started, at passed time
109 void onAnimationStartResponse(MonotonicTime startTime)
110 {
111 updateStateMachine(AnimationStateInput::StartTimeSet, startTime.secondsSinceEpoch().seconds());
112 }
113
114 // Called to change to or from paused state
115 void updatePlayState(AnimationPlayState);
116 bool playStatePlaying() const;
117
118 bool waitingToStart() const { return m_animationState == AnimationState::New || m_animationState == AnimationState::StartWaitTimer || m_animationState == AnimationState::PausedNew; }
119 bool preActive() const
120 {
121 return m_animationState == AnimationState::New || m_animationState == AnimationState::StartWaitTimer || m_animationState == AnimationState::StartWaitStyleAvailable || m_animationState == AnimationState::StartWaitResponse;
122 }
123
124 bool postActive() const { return m_animationState == AnimationState::Done; }
125 bool fillingForwards() const { return m_animationState == AnimationState::FillingForwards; }
126 bool active() const { return !postActive() && !preActive(); }
127 bool running() const { return !isNew() && !postActive(); }
128 bool paused() const { return m_pauseTime || m_animationState == AnimationState::PausedNew; }
129
130 static bool isPausedState(AnimationState state) { return state >= AnimationState::PausedNew && state <= AnimationState::PausedRun; }
131 static bool isRunningState(AnimationState state) { return state >= AnimationState::StartWaitStyleAvailable && state < AnimationState::Done; }
132
133 bool inPausedState() const { return isPausedState(m_animationState); }
134 bool inRunningState() const { return isRunningState(m_animationState); }
135
136 bool isNew() const { return m_animationState == AnimationState::New || m_animationState == AnimationState::PausedNew; }
137 bool waitingForStartTime() const { return m_animationState == AnimationState::StartWaitResponse; }
138 bool waitingForStyleAvailable() const { return m_animationState == AnimationState::StartWaitStyleAvailable; }
139
140 bool isAccelerated() const override { return m_isAccelerated; }
141
142 virtual Optional<Seconds> timeToNextService();
143
144 double progress(double scale = 1, double offset = 0, const TimingFunction* = nullptr) const;
145
146 virtual void getAnimatedStyle(std::unique_ptr<RenderStyle>& /*animatedStyle*/) = 0;
147
148 virtual bool computeExtentOfTransformAnimation(LayoutRect&) const = 0;
149
150 virtual bool shouldFireEvents() const { return false; }
151
152 void fireAnimationEventsIfNeeded();
153
154 bool animationsMatch(const Animation&) const;
155
156 const Animation& animation() const { return m_animation; }
157 void setAnimation(const Animation& animation) { m_animation = const_cast<Animation&>(animation); }
158
159 // Return true if this animation is overridden. This will only be the case for
160 // ImplicitAnimations and is used to determine whether or not we should force
161 // set the start time. If an animation is overridden, it will probably not get
162 // back the AnimationStateInput::StartTimeSet input.
163 virtual bool overridden() const { return false; }
164
165 // Does this animation/transition involve the given property?
166 virtual bool affectsProperty(CSSPropertyID /*property*/) const { return false; }
167
168 bool isAnimatingProperty(CSSPropertyID property, bool acceleratedOnly) const
169 {
170 if (acceleratedOnly && !m_isAccelerated)
171 return false;
172
173 if (!affectsProperty(property))
174 return false;
175
176 return inRunningState() || inPausedState();
177 }
178
179 bool transformFunctionListsMatch() const override { return m_transformFunctionListsMatch; }
180 bool filterFunctionListsMatch() const override { return m_filterFunctionListsMatch; }
181#if ENABLE(FILTERS_LEVEL_2)
182 bool backdropFilterFunctionListsMatch() const override { return m_backdropFilterFunctionListsMatch; }
183#endif
184 bool colorFilterFunctionListsMatch() const override { return m_colorFilterFunctionListsMatch; }
185
186 // Freeze the animation; used by DumpRenderTree.
187 void freezeAtTime(double t);
188
189 // Play and pause API
190 void play();
191 void pause();
192
193 double beginAnimationUpdateTime() const;
194
195 double getElapsedTime() const;
196 // Setting the elapsed time will adjust the start time and possibly pause time.
197 void setElapsedTime(double);
198
199 void styleAvailable()
200 {
201 ASSERT(waitingForStyleAvailable());
202 updateStateMachine(AnimationStateInput::StyleAvailable, -1);
203 }
204
205protected:
206 virtual void overrideAnimations() { }
207 virtual void resumeOverriddenAnimations() { }
208
209 CompositeAnimation* compositeAnimation() { return m_compositeAnimation; }
210
211 // These are called when the corresponding timer fires so subclasses can do any extra work
212 virtual void onAnimationStart(double /*elapsedTime*/) { }
213 virtual void onAnimationIteration(double /*elapsedTime*/) { }
214 virtual void onAnimationEnd(double /*elapsedTime*/) { }
215
216 // timeOffset is an offset from the current time when the animation should start. Negative values are OK.
217 // Return value indicates whether to expect an asynchronous notifyAnimationStarted() callback.
218 virtual bool startAnimation(double /*timeOffset*/) { return false; }
219 // timeOffset is the time at which the animation is being paused.
220 virtual void pauseAnimation(double /*timeOffset*/) { }
221 virtual void endAnimation(bool /*fillingForwards*/ = false) { }
222
223 virtual const RenderStyle& unanimatedStyle() const = 0;
224
225 void goIntoEndingOrLoopingState();
226
227 AnimationState state() const { return m_animationState; }
228
229 static void setNeedsStyleRecalc(Element*);
230
231 void getTimeToNextEvent(Seconds& time, bool& isLooping) const;
232
233 double fractionalTime(double scale, double elapsedTime, double offset) const;
234
235 // These return true if we can easily compute a bounding box by applying the style's transform to the bounds rect.
236 bool computeTransformedExtentViaTransformList(const FloatRect& rendererBox, const RenderStyle&, LayoutRect& bounds) const;
237 bool computeTransformedExtentViaMatrix(const FloatRect& rendererBox, const RenderStyle&, LayoutRect& bounds) const;
238
239protected:
240 bool m_isAccelerated { false };
241 bool m_transformFunctionListsMatch { false };
242 bool m_filterFunctionListsMatch { false };
243#if ENABLE(FILTERS_LEVEL_2)
244 bool m_backdropFilterFunctionListsMatch { false };
245#endif
246
247private:
248 RefPtr<Element> m_element;
249
250protected:
251 CompositeAnimation* m_compositeAnimation; // Ideally this would be a reference, but it has to be cleared if an animation is destroyed inside an event callback.
252 Ref<Animation> m_animation;
253
254 Optional<double> m_startTime;
255 Optional<double> m_pauseTime;
256 double m_requestedStartTime { 0 };
257 Optional<double> m_totalDuration;
258 Optional<double> m_nextIterationDuration;
259
260 AnimationState m_animationState { AnimationState::New };
261 bool m_colorFilterFunctionListsMatch { false };
262};
263
264} // namespace WebCore
265