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 | |
36 | namespace WebCore { |
37 | |
38 | class CompositeAnimation; |
39 | class Element; |
40 | class FloatRect; |
41 | class LayoutRect; |
42 | class RenderElement; |
43 | class RenderStyle; |
44 | class TimingFunction; |
45 | |
46 | enum 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 | |
52 | class AnimationBase : public RefCounted<AnimationBase> |
53 | , public CSSPropertyBlendingClient { |
54 | friend class CompositeAnimation; |
55 | friend class CSSPropertyAnimation; |
56 | WTF_MAKE_FAST_ALLOCATED; |
57 | public: |
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 | |
205 | protected: |
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 | |
239 | protected: |
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 | |
247 | private: |
248 | RefPtr<Element> m_element; |
249 | |
250 | protected: |
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 | |