| 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 | |