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#ifndef AnimationBase_h
30#define AnimationBase_h
31
32#include "Animation.h"
33#include "CSSPropertyNames.h"
34#include "RenderStyleConstants.h"
35#include <wtf/HashMap.h>
36#include <wtf/HashSet.h>
37#include <wtf/RefCounted.h>
38#include <wtf/text/AtomicString.h>
39
40namespace WebCore {
41
42class AnimationController;
43class CompositeAnimation;
44class Element;
45class RenderElement;
46class RenderStyle;
47class TimingFunction;
48class AnimationBase : public RefCounted<AnimationBase> {
49    friend class CompositeAnimation;
50    friend class CSSPropertyAnimation;
51
52public:
53    AnimationBase(const Animation& transition, RenderElement*, CompositeAnimation*);
54    virtual ~AnimationBase() { }
55
56    RenderElement* renderer() const { return m_object; }
57    void clear()
58    {
59        endAnimation();
60        m_object = nullptr;
61        m_compositeAnimation = nullptr;
62    }
63
64    double duration() const;
65
66    // Animations and Transitions go through the states below. When entering the STARTED state
67    // the animation is started. This may or may not require deferred response from the animator.
68    // If so, we stay in this state until that response is received (and it returns the start time).
69    // Otherwise, we use the current time as the start time and go immediately to AnimationState::Looping
70    // or AnimationState::Ending.
71    enum class AnimationState {
72        New,                        // animation just created, animation not running yet
73        StartWaitTimer,             // start timer running, waiting for fire
74        StartWaitStyleAvailable,    // waiting for style setup so we can start animations
75        StartWaitResponse,          // animation started, waiting for response
76        Looping,                    // response received, animation running, loop timer running, waiting for fire
77        Ending,                     // received, animation running, end timer running, waiting for fire
78        PausedNew,                  // in pause mode when animation was created
79        PausedWaitTimer,            // in pause mode when animation started
80        PausedWaitStyleAvailable,   // in pause mode when waiting for style setup
81        PausedWaitResponse,         // animation paused when in STARTING state
82        PausedRun,                  // animation paused when in LOOPING or ENDING state
83        Done,                       // end timer fired, animation finished and removed
84        FillingForwards             // animation has ended and is retaining its final value
85    };
86
87    enum class AnimationStateInput {
88        MakeNew,           // reset back to new from any state
89        StartAnimation,    // animation requests a start
90        RestartAnimation,  // force a restart from any state
91        StartTimerFired,   // start timer fired
92        StyleAvailable,    // style is setup, ready to start animating
93        StartTimeSet,      // m_startTime was set
94        LoopTimerFired,    // loop timer fired
95        EndTimerFired,     // end timer fired
96        PauseOverride,     // pause an animation due to override
97        ResumeOverride,    // resume an overridden animation
98        PlayStateRunning,  // play state paused -> running
99        PlayStatePaused,   // play state running -> paused
100        EndAnimation       // force an end from any state
101    };
102
103    // Called when animation is in AnimationState::New to start animation
104    void updateStateMachine(AnimationStateInput, double param);
105
106    // Animation has actually started, at passed time
107    void onAnimationStartResponse(double startTime)
108    {
109        updateStateMachine(AnimationStateInput::StartTimeSet, startTime);
110    }
111
112    // Called to change to or from paused state
113    void updatePlayState(EAnimPlayState);
114    bool playStatePlaying() const;
115
116    bool waitingToStart() const { return m_animationState == AnimationState::New || m_animationState == AnimationState::StartWaitTimer || m_animationState == AnimationState::PausedNew; }
117    bool preActive() const
118    {
119        return m_animationState == AnimationState::New || m_animationState == AnimationState::StartWaitTimer || m_animationState == AnimationState::StartWaitStyleAvailable || m_animationState == AnimationState::StartWaitResponse;
120    }
121
122    bool postActive() const { return m_animationState == AnimationState::Done; }
123    bool fillingForwards() const { return m_animationState == AnimationState::FillingForwards; }
124    bool active() const { return !postActive() && !preActive(); }
125    bool running() const { return !isNew() && !postActive(); }
126    bool paused() const { return m_pauseTime >= 0 || m_animationState == AnimationState::PausedNew; }
127    bool inPausedState() const { return m_animationState >= AnimationState::PausedNew && m_animationState <= AnimationState::PausedRun; }
128    bool isNew() const { return m_animationState == AnimationState::New || m_animationState == AnimationState::PausedNew; }
129    bool waitingForStartTime() const { return m_animationState == AnimationState::StartWaitResponse; }
130    bool waitingForStyleAvailable() const { return m_animationState == AnimationState::StartWaitStyleAvailable; }
131
132    virtual double timeToNextService();
133
134    double progress(double scale, double offset, const TimingFunction*) const;
135
136    virtual void animate(CompositeAnimation*, RenderElement*, const RenderStyle* /*currentStyle*/, RenderStyle* /*targetStyle*/, RefPtr<RenderStyle>& /*animatedStyle*/) = 0;
137    virtual void getAnimatedStyle(RefPtr<RenderStyle>& /*animatedStyle*/) = 0;
138
139    virtual bool shouldFireEvents() const { return false; }
140
141    void fireAnimationEventsIfNeeded();
142
143    bool animationsMatch(const Animation*) const;
144
145    void setAnimation(const Animation& animation) { m_animation = const_cast<Animation*>(&animation); }
146
147    // Return true if this animation is overridden. This will only be the case for
148    // ImplicitAnimations and is used to determine whether or not we should force
149    // set the start time. If an animation is overridden, it will probably not get
150    // back the AnimationStateInput::StartTimeSet input.
151    virtual bool overridden() const { return false; }
152
153    // Does this animation/transition involve the given property?
154    virtual bool affectsProperty(CSSPropertyID /*property*/) const { return false; }
155
156    enum RunningStates {
157        Delaying = 1 << 0,
158        Paused = 1 << 1,
159        Running = 1 << 2,
160        FillingFowards = 1 << 3
161    };
162    typedef unsigned RunningState;
163    bool isAnimatingProperty(CSSPropertyID property, bool acceleratedOnly, RunningState runningState) const
164    {
165        if (acceleratedOnly && !m_isAccelerated)
166            return false;
167
168        if (!affectsProperty(property))
169            return false;
170
171        if ((runningState & Delaying) && preActive())
172            return true;
173
174        if ((runningState & Paused) && inPausedState())
175            return true;
176
177        if ((runningState & Running) && !inPausedState() && (m_animationState >= AnimationState::StartWaitStyleAvailable && m_animationState <= AnimationState::Done))
178            return true;
179
180        if ((runningState & FillingFowards) && m_animationState == AnimationState::FillingForwards)
181            return true;
182
183        return false;
184    }
185
186    // FIXME: rename this using the "lists match" terminology.
187    bool isTransformFunctionListValid() const { return m_transformFunctionListValid; }
188#if ENABLE(CSS_FILTERS)
189    bool filterFunctionListsMatch() const { return m_filterFunctionListsMatch; }
190#endif
191
192    // Freeze the animation; used by DumpRenderTree.
193    void freezeAtTime(double t);
194
195    // Play and pause API
196    void play();
197    void pause();
198
199    double beginAnimationUpdateTime() const;
200
201    double getElapsedTime() const;
202    // Setting the elapsed time will adjust the start time and possibly pause time.
203    void setElapsedTime(double);
204
205    void styleAvailable()
206    {
207        ASSERT(waitingForStyleAvailable());
208        updateStateMachine(AnimationStateInput::StyleAvailable, -1);
209    }
210
211    const Animation& animation() const { return *m_animation; }
212
213protected:
214    virtual void overrideAnimations() { }
215    virtual void resumeOverriddenAnimations() { }
216
217    CompositeAnimation* compositeAnimation() { return m_compositeAnimation; }
218
219    // These are called when the corresponding timer fires so subclasses can do any extra work
220    virtual void onAnimationStart(double /*elapsedTime*/) { }
221    virtual void onAnimationIteration(double /*elapsedTime*/) { }
222    virtual void onAnimationEnd(double /*elapsedTime*/) { }
223
224    // timeOffset is an offset from the current time when the animation should start. Negative values are OK.
225    // Return value indicates whether to expect an asynchronous notifyAnimationStarted() callback.
226    virtual bool startAnimation(double /*timeOffset*/) { return false; }
227    // timeOffset is the time at which the animation is being paused.
228    virtual void pauseAnimation(double /*timeOffset*/) { }
229    virtual void endAnimation() { }
230
231    void goIntoEndingOrLoopingState();
232
233    bool isAccelerated() const { return m_isAccelerated; }
234
235    static void setNeedsStyleRecalc(Element*);
236
237    void getTimeToNextEvent(double& time, bool& isLooping) const;
238
239    double fractionalTime(double scale, double elapsedTime, double offset) const;
240
241    AnimationState m_animationState;
242
243    bool m_isAccelerated;
244    bool m_transformFunctionListValid;
245#if ENABLE(CSS_FILTERS)
246    bool m_filterFunctionListsMatch;
247#endif
248    double m_startTime;
249    double m_pauseTime;
250    double m_requestedStartTime;
251
252    double m_totalDuration;
253    double m_nextIterationDuration;
254
255    RenderElement* m_object;
256
257    RefPtr<Animation> m_animation;
258    CompositeAnimation* m_compositeAnimation;
259};
260
261} // namespace WebCore
262
263#endif // AnimationBase_h
264