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