eb4c424547997bf9b75047ee56e2d526ac5ab9ce
[WebKit-https.git] / Source / WebCore / page / animation / AnimationBase.cpp
1 /*
2  * Copyright (C) 2007, 2008, 2009 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 #include "config.h"
30 #include "AnimationBase.h"
31
32 #include "AnimationControllerPrivate.h"
33 #include "CSSPrimitiveValue.h"
34 #include "CSSPropertyAnimation.h"
35 #include "CompositeAnimation.h"
36 #include "Document.h"
37 #include "EventNames.h"
38 #include "FloatConversion.h"
39 #include "GeometryUtilities.h"
40 #include "Logging.h"
41 #include "RenderBox.h"
42 #include "RenderStyle.h"
43 #include "RenderView.h"
44 #include "UnitBezier.h"
45 #include <algorithm>
46 #include <wtf/CurrentTime.h>
47 #include <wtf/Ref.h>
48
49 namespace WebCore {
50
51 // The epsilon value we pass to UnitBezier::solve given that the animation is going to run over |dur| seconds. The longer the
52 // animation, the more precision we need in the timing function result to avoid ugly discontinuities.
53 static inline double solveEpsilon(double duration)
54 {
55     return 1.0 / (200.0 * duration);
56 }
57
58 static inline double solveCubicBezierFunction(double p1x, double p1y, double p2x, double p2y, double t, double duration)
59 {
60     // Convert from input time to parametric value in curve, then from
61     // that to output time.
62     UnitBezier bezier(p1x, p1y, p2x, p2y);
63     return bezier.solve(t, solveEpsilon(duration));
64 }
65
66 static inline double solveStepsFunction(int numSteps, bool stepAtStart, double t)
67 {
68     if (stepAtStart)
69         return std::min(1.0, (floor(numSteps * t) + 1) / numSteps);
70     return floor(numSteps * t) / numSteps;
71 }
72
73 AnimationBase::AnimationBase(const Animation& transition, RenderElement* renderer, CompositeAnimation* compositeAnimation)
74     : m_animationState(AnimationState::New)
75     , m_isAccelerated(false)
76     , m_transformFunctionListValid(false)
77     , m_filterFunctionListsMatch(false)
78     , m_startTime(0)
79     , m_pauseTime(-1)
80     , m_requestedStartTime(0)
81     , m_totalDuration(-1)
82     , m_nextIterationDuration(-1)
83     , m_object(renderer)
84     , m_animation(const_cast<Animation*>(&transition))
85     , m_compositeAnimation(compositeAnimation)
86 {
87     // Compute the total duration
88     if (m_animation->iterationCount() > 0)
89         m_totalDuration = m_animation->duration() * m_animation->iterationCount();
90 }
91
92 void AnimationBase::setNeedsStyleRecalc(Element* element)
93 {
94     ASSERT(!element || !element->document().inPageCache());
95     if (element)
96         element->setNeedsStyleRecalc(SyntheticStyleChange);
97 }
98
99 double AnimationBase::duration() const
100 {
101     return m_animation->duration();
102 }
103
104 bool AnimationBase::playStatePlaying() const
105 {
106     return m_animation->playState() == AnimPlayStatePlaying;
107 }
108
109 bool AnimationBase::animationsMatch(const Animation* anim) const
110 {
111     return m_animation->animationsMatch(anim);
112 }
113
114 #if !LOG_DISABLED
115 static const char* nameForState(AnimationBase::AnimationState state)
116 {
117     switch (state) {
118     case AnimationBase::AnimationState::New: return "New";
119     case AnimationBase::AnimationState::StartWaitTimer: return "StartWaitTimer";
120     case AnimationBase::AnimationState::StartWaitStyleAvailable: return "StartWaitStyleAvailable";
121     case AnimationBase::AnimationState::StartWaitResponse: return "StartWaitResponse";
122     case AnimationBase::AnimationState::Looping: return "Looping";
123     case AnimationBase::AnimationState::Ending: return "Ending";
124     case AnimationBase::AnimationState::PausedNew: return "PausedNew";
125     case AnimationBase::AnimationState::PausedWaitTimer: return "PausedWaitTimer";
126     case AnimationBase::AnimationState::PausedWaitStyleAvailable: return "PausedWaitStyleAvailable";
127     case AnimationBase::AnimationState::PausedWaitResponse: return "PausedWaitResponse";
128     case AnimationBase::AnimationState::PausedRun: return "PausedRun";
129     case AnimationBase::AnimationState::Done: return "Done";
130     case AnimationBase::AnimationState::FillingForwards: return "FillingForwards";
131     }
132     return "";
133 }
134 #endif
135
136 void AnimationBase::updateStateMachine(AnimationStateInput input, double param)
137 {
138     if (!m_compositeAnimation)
139         return;
140
141     // If we get AnimationStateInput::RestartAnimation then we force a new animation, regardless of state.
142     if (input == AnimationStateInput::MakeNew) {
143         if (m_animationState == AnimationState::StartWaitStyleAvailable)
144             m_compositeAnimation->animationController()->removeFromAnimationsWaitingForStyle(this);
145         LOG(Animations, "%p AnimationState %s -> New", this, nameForState(m_animationState));
146         m_animationState = AnimationState::New;
147         m_startTime = 0;
148         m_pauseTime = -1;
149         m_requestedStartTime = 0;
150         m_nextIterationDuration = -1;
151         endAnimation();
152         return;
153     }
154
155     if (input == AnimationStateInput::RestartAnimation) {
156         if (m_animationState == AnimationState::StartWaitStyleAvailable)
157             m_compositeAnimation->animationController()->removeFromAnimationsWaitingForStyle(this);
158         LOG(Animations, "%p AnimationState %s -> New", this, nameForState(m_animationState));
159         m_animationState = AnimationState::New;
160         m_startTime = 0;
161         m_pauseTime = -1;
162         m_requestedStartTime = 0;
163         m_nextIterationDuration = -1;
164         endAnimation();
165
166         if (!paused())
167             updateStateMachine(AnimationStateInput::StartAnimation, -1);
168         return;
169     }
170
171     if (input == AnimationStateInput::EndAnimation) {
172         if (m_animationState == AnimationState::StartWaitStyleAvailable)
173             m_compositeAnimation->animationController()->removeFromAnimationsWaitingForStyle(this);
174         LOG(Animations, "%p AnimationState %s -> Done", this, nameForState(m_animationState));
175         m_animationState = AnimationState::Done;
176         endAnimation();
177         return;
178     }
179
180     if (input == AnimationStateInput::PauseOverride) {
181         if (m_animationState == AnimationState::StartWaitResponse) {
182             // If we are in AnimationState::StartWaitResponse, the animation will get canceled before 
183             // we get a response, so move to the next state.
184             endAnimation();
185             updateStateMachine(AnimationStateInput::StartTimeSet, beginAnimationUpdateTime());
186         }
187         return;
188     }
189
190     if (input == AnimationStateInput::ResumeOverride) {
191         if (m_animationState == AnimationState::Looping || m_animationState == AnimationState::Ending) {
192             // Start the animation
193             startAnimation(beginAnimationUpdateTime() - m_startTime);
194         }
195         return;
196     }
197
198     // Execute state machine
199     switch (m_animationState) {
200         case AnimationState::New:
201             ASSERT(input == AnimationStateInput::StartAnimation || input == AnimationStateInput::PlayStateRunning || input == AnimationStateInput::PlayStatePaused);
202
203             if (input == AnimationStateInput::StartAnimation || input == AnimationStateInput::PlayStateRunning) {
204                 m_requestedStartTime = beginAnimationUpdateTime();
205                 LOG(Animations, "%p AnimationState %s -> StartWaitTimer", this, nameForState(m_animationState));
206                 m_animationState = AnimationState::StartWaitTimer;
207             } else {
208                 // We are pausing before we even started.
209                 LOG(Animations, "%p AnimationState %s -> AnimationState::PausedNew", this, nameForState(m_animationState));
210                 m_animationState = AnimationState::PausedNew;
211             }
212             break;
213         case AnimationState::StartWaitTimer:
214             ASSERT(input == AnimationStateInput::StartTimerFired || input == AnimationStateInput::PlayStatePaused);
215
216             if (input == AnimationStateInput::StartTimerFired) {
217                 ASSERT(param >= 0);
218                 // Start timer has fired, tell the animation to start and wait for it to respond with start time
219                 LOG(Animations, "%p AnimationState %s -> StartWaitStyleAvailable", this, nameForState(m_animationState));
220                 m_animationState = AnimationState::StartWaitStyleAvailable;
221                 m_compositeAnimation->animationController()->addToAnimationsWaitingForStyle(this);
222
223                 // Trigger a render so we can start the animation
224                 if (m_object && m_object->element())
225                     m_compositeAnimation->animationController()->addElementChangeToDispatch(*m_object->element());
226             } else {
227                 ASSERT(!paused());
228                 // We're waiting for the start timer to fire and we got a pause. Cancel the timer, pause and wait
229                 m_pauseTime = beginAnimationUpdateTime();
230                 LOG(Animations, "%p AnimationState %s -> PausedWaitTimer", this, nameForState(m_animationState));
231                 m_animationState = AnimationState::PausedWaitTimer;
232             }
233             break;
234         case AnimationState::StartWaitStyleAvailable:
235             ASSERT(input == AnimationStateInput::StyleAvailable || input == AnimationStateInput::PlayStatePaused);
236
237             if (input == AnimationStateInput::StyleAvailable) {
238                 // Start timer has fired, tell the animation to start and wait for it to respond with start time
239                 LOG(Animations, "%p AnimationState %s -> StartWaitResponse", this, nameForState(m_animationState));
240                 m_animationState = AnimationState::StartWaitResponse;
241
242                 overrideAnimations();
243
244                 // Start the animation
245                 if (overridden()) {
246                     // We won't try to start accelerated animations if we are overridden and
247                     // just move on to the next state.
248                     LOG(Animations, "%p AnimationState %s -> StartWaitResponse", this, nameForState(m_animationState));
249                     m_animationState = AnimationState::StartWaitResponse;
250                     m_isAccelerated = false;
251                     updateStateMachine(AnimationStateInput::StartTimeSet, beginAnimationUpdateTime());
252                 } else {
253                     double timeOffset = 0;
254                     // If the value for 'animation-delay' is negative then the animation appears to have started in the past.
255                     if (m_animation->delay() < 0)
256                         timeOffset = -m_animation->delay();
257                     bool started = startAnimation(timeOffset);
258
259                     m_compositeAnimation->animationController()->addToAnimationsWaitingForStartTimeResponse(this, started);
260                     m_isAccelerated = started;
261                 }
262             } else {
263                 // We're waiting for the style to be available and we got a pause. Pause and wait
264                 m_pauseTime = beginAnimationUpdateTime();
265                 LOG(Animations, "%p AnimationState %s -> PausedWaitStyleAvailable", this, nameForState(m_animationState));
266                 m_animationState = AnimationState::PausedWaitStyleAvailable;
267             }
268             break;
269         case AnimationState::StartWaitResponse:
270             ASSERT(input == AnimationStateInput::StartTimeSet || input == AnimationStateInput::PlayStatePaused);
271
272             if (input == AnimationStateInput::StartTimeSet) {
273                 ASSERT(param >= 0);
274                 // We have a start time, set it, unless the startTime is already set
275                 if (m_startTime <= 0) {
276                     m_startTime = param;
277                     // If the value for 'animation-delay' is negative then the animation appears to have started in the past.
278                     if (m_animation->delay() < 0)
279                         m_startTime += m_animation->delay();
280                 }
281
282                 // Now that we know the start time, fire the start event.
283                 onAnimationStart(0); // The elapsedTime is 0.
284
285                 // Decide whether to go into looping or ending state
286                 goIntoEndingOrLoopingState();
287
288                 // Dispatch updateStyleIfNeeded so we can start the animation
289                 if (m_object && m_object->element())
290                     m_compositeAnimation->animationController()->addElementChangeToDispatch(*m_object->element());
291             } else {
292                 // We are pausing while waiting for a start response. Cancel the animation and wait. When 
293                 // we unpause, we will act as though the start timer just fired
294                 m_pauseTime = beginAnimationUpdateTime();
295                 pauseAnimation(beginAnimationUpdateTime() - m_startTime);
296                 LOG(Animations, "%p AnimationState %s -> PausedWaitResponse", this, nameForState(m_animationState));
297                 m_animationState = AnimationState::PausedWaitResponse;
298             }
299             break;
300         case AnimationState::Looping:
301             ASSERT(input == AnimationStateInput::LoopTimerFired || input == AnimationStateInput::PlayStatePaused);
302
303             if (input == AnimationStateInput::LoopTimerFired) {
304                 ASSERT(param >= 0);
305                 // Loop timer fired, loop again or end.
306                 onAnimationIteration(param);
307
308                 // Decide whether to go into looping or ending state
309                 goIntoEndingOrLoopingState();
310             } else {
311                 // We are pausing while running. Cancel the animation and wait
312                 m_pauseTime = beginAnimationUpdateTime();
313                 pauseAnimation(beginAnimationUpdateTime() - m_startTime);
314                 LOG(Animations, "%p AnimationState %s -> PausedRun", this, nameForState(m_animationState));
315                 m_animationState = AnimationState::PausedRun;
316             }
317             break;
318         case AnimationState::Ending:
319 #if !LOG_DISABLED
320             if (input != AnimationStateInput::EndTimerFired && input != AnimationStateInput::PlayStatePaused)
321                 LOG_ERROR("State is AnimationState::Ending, but input is not AnimationStateInput::EndTimerFired or AnimationStateInput::PlayStatePaused. It is %d.", input);
322 #endif
323             if (input == AnimationStateInput::EndTimerFired) {
324
325                 ASSERT(param >= 0);
326                 // End timer fired, finish up
327                 onAnimationEnd(param);
328
329                 LOG(Animations, "%p AnimationState %s -> Done", this, nameForState(m_animationState));
330                 m_animationState = AnimationState::Done;
331                 
332                 if (m_object) {
333                     if (m_animation->fillsForwards()) {
334                         LOG(Animations, "%p AnimationState %s -> FillingForwards", this, nameForState(m_animationState));
335                         m_animationState = AnimationState::FillingForwards;
336                     } else
337                         resumeOverriddenAnimations();
338
339                     // Fire off another style change so we can set the final value
340                     if (m_object->element())
341                         m_compositeAnimation->animationController()->addElementChangeToDispatch(*m_object->element());
342                 }
343             } else {
344                 // We are pausing while running. Cancel the animation and wait
345                 m_pauseTime = beginAnimationUpdateTime();
346                 pauseAnimation(beginAnimationUpdateTime() - m_startTime);
347                 LOG(Animations, "%p AnimationState %s -> PausedRun", this, nameForState(m_animationState));
348                 m_animationState = AnimationState::PausedRun;
349             }
350             // |this| may be deleted here
351             break;
352         case AnimationState::PausedWaitTimer:
353             ASSERT(input == AnimationStateInput::PlayStateRunning);
354             ASSERT(paused());
355             // Update the times
356             m_startTime += beginAnimationUpdateTime() - m_pauseTime;
357             m_pauseTime = -1;
358
359             // we were waiting for the start timer to fire, go back and wait again
360             LOG(Animations, "%p AnimationState %s -> New", this, nameForState(m_animationState));
361             m_animationState = AnimationState::New;
362             updateStateMachine(AnimationStateInput::StartAnimation, 0);
363             break;
364         case AnimationState::PausedNew:
365         case AnimationState::PausedWaitResponse:
366         case AnimationState::PausedWaitStyleAvailable:
367         case AnimationState::PausedRun:
368             // We treat these two cases the same. The only difference is that, when we are in
369             // AnimationState::PausedWaitResponse, we don't yet have a valid startTime, so we send 0 to startAnimation.
370             // When the AnimationStateInput::StartTimeSet comes in and we were in AnimationState::PausedRun, we will notice
371             // that we have already set the startTime and will ignore it.
372             ASSERT(input == AnimationStateInput::PlayStateRunning || input == AnimationStateInput::StartTimeSet || input == AnimationStateInput::StyleAvailable || input == AnimationStateInput::StartAnimation);
373             ASSERT(paused());
374
375             if (input == AnimationStateInput::PlayStateRunning) {
376                 if (m_animationState == AnimationState::PausedNew) {
377                     // We were paused before we even started, and now we're supposed
378                     // to start, so jump back to the New state and reset.
379                     LOG(Animations, "%p AnimationState %s -> AnimationState::New", this, nameForState(m_animationState));
380                     m_animationState = AnimationState::New;
381                     updateStateMachine(input, param);
382                     break;
383                 }
384
385                 // Update the times
386                 if (m_animationState == AnimationState::PausedRun)
387                     m_startTime += beginAnimationUpdateTime() - m_pauseTime;
388                 else
389                     m_startTime = 0;
390                 m_pauseTime = -1;
391
392                 if (m_animationState == AnimationState::PausedWaitStyleAvailable) {
393                     LOG(Animations, "%p AnimationState %s -> StartWaitStyleAvailable", this, nameForState(m_animationState));
394                     m_animationState = AnimationState::StartWaitStyleAvailable;
395                 } else {
396                     // We were either running or waiting for a begin time response from the animation.
397                     // Either way we need to restart the animation (possibly with an offset if we
398                     // had already been running) and wait for it to start.
399                     LOG(Animations, "%p AnimationState %s -> StartWaitResponse", this, nameForState(m_animationState));
400                     m_animationState = AnimationState::StartWaitResponse;
401
402                     // Start the animation
403                     if (overridden()) {
404                         // We won't try to start accelerated animations if we are overridden and
405                         // just move on to the next state.
406                         updateStateMachine(AnimationStateInput::StartTimeSet, beginAnimationUpdateTime());
407                         m_isAccelerated = true;
408                     } else {
409                         bool started = startAnimation(beginAnimationUpdateTime() - m_startTime);
410                         m_compositeAnimation->animationController()->addToAnimationsWaitingForStartTimeResponse(this, started);
411                         m_isAccelerated = started;
412                     }
413                 }
414                 break;
415             }
416             
417             if (input == AnimationStateInput::StartTimeSet) {
418                 ASSERT(m_animationState == AnimationState::PausedWaitResponse);
419                 
420                 // We are paused but we got the callback that notifies us that an accelerated animation started.
421                 // We ignore the start time and just move into the paused-run state.
422                 LOG(Animations, "%p AnimationState %s -> PausedRun", this, nameForState(m_animationState));
423                 m_animationState = AnimationState::PausedRun;
424                 ASSERT(m_startTime == 0);
425                 m_startTime = param;
426                 m_pauseTime += m_startTime;
427                 break;
428             }
429
430             ASSERT(m_animationState == AnimationState::PausedWaitStyleAvailable);
431             // We are paused but we got the callback that notifies us that style has been updated.
432             // We move to the AnimationState::PausedWaitResponse state
433             LOG(Animations, "%p AnimationState %s -> PausedWaitResponse", this, nameForState(m_animationState));
434             m_animationState = AnimationState::PausedWaitResponse;
435             overrideAnimations();
436             break;
437         case AnimationState::FillingForwards:
438         case AnimationState::Done:
439             // We're done. Stay in this state until we are deleted
440             break;
441     }
442 }
443     
444 void AnimationBase::fireAnimationEventsIfNeeded()
445 {
446     if (!m_compositeAnimation)
447         return;
448
449     // If we are waiting for the delay time to expire and it has, go to the next state
450     if (m_animationState != AnimationState::StartWaitTimer && m_animationState != AnimationState::Looping && m_animationState != AnimationState::Ending)
451         return;
452
453     // We have to make sure to keep a ref to the this pointer, because it could get destroyed
454     // during an animation callback that might get called. Since the owner is a CompositeAnimation
455     // and it ref counts this object, we will keep a ref to that instead. That way the AnimationBase
456     // can still access the resources of its CompositeAnimation as needed.
457     Ref<AnimationBase> protect(*this);
458     Ref<CompositeAnimation> protectCompositeAnimation(*m_compositeAnimation);
459     
460     // Check for start timeout
461     if (m_animationState == AnimationState::StartWaitTimer) {
462 #if ENABLE(CSS_ANIMATIONS_LEVEL_2)
463         if (m_animation->trigger() && m_animation->trigger()->isScrollAnimationTrigger()) {
464             if (m_object) {
465                 LayoutSize offset = m_object->view().frameView().scrollOffsetForFixedPosition();
466                 ScrollAnimationTrigger* scrollTrigger = static_cast<ScrollAnimationTrigger*>(m_animation->trigger().get());
467                 if (offset.height().toFloat() > scrollTrigger->startValue().value())
468                     updateStateMachine(AnimationStateInput::StartTimerFired, 0);
469             }
470
471             return;
472         }
473 #endif
474         if (beginAnimationUpdateTime() - m_requestedStartTime >= m_animation->delay())
475             updateStateMachine(AnimationStateInput::StartTimerFired, 0);
476         return;
477     }
478     
479     double elapsedDuration = beginAnimationUpdateTime() - m_startTime;
480 #if ENABLE(CSS_ANIMATIONS_LEVEL_2)
481     if (m_animation->trigger() && m_animation->trigger()->isScrollAnimationTrigger())
482         elapsedDuration = getElapsedTime();
483 #endif
484
485     // FIXME: we need to ensure that elapsedDuration is never < 0. If it is, this suggests that
486     // we had a recalcStyle() outside of beginAnimationUpdate()/endAnimationUpdate().
487     // Also check in getTimeToNextEvent().
488     elapsedDuration = std::max(elapsedDuration, 0.0);
489     
490     // Check for end timeout
491     if (m_totalDuration >= 0 && elapsedDuration >= m_totalDuration) {
492         // We may still be in AnimationState::Looping if we've managed to skip a
493         // whole iteration, in which case we should jump to the end state.
494         LOG(Animations, "%p AnimationState %s -> Ending", this, nameForState(m_animationState));
495         m_animationState = AnimationState::Ending;
496
497         // Fire an end event
498         updateStateMachine(AnimationStateInput::EndTimerFired, m_totalDuration);
499     } else {
500         // Check for iteration timeout
501         if (m_nextIterationDuration < 0) {
502             // Hasn't been set yet, set it
503             double durationLeft = m_animation->duration() - fmod(elapsedDuration, m_animation->duration());
504             m_nextIterationDuration = elapsedDuration + durationLeft;
505         }
506         
507         if (elapsedDuration >= m_nextIterationDuration) {
508             // Set to the next iteration
509             double previous = m_nextIterationDuration;
510             double durationLeft = m_animation->duration() - fmod(elapsedDuration, m_animation->duration());
511             m_nextIterationDuration = elapsedDuration + durationLeft;
512             
513             // Send the event
514             updateStateMachine(AnimationStateInput::LoopTimerFired, previous);
515         }
516     }
517 }
518
519 void AnimationBase::updatePlayState(EAnimPlayState playState)
520 {
521     if (!m_compositeAnimation)
522         return;
523
524     // When we get here, we can have one of 4 desired states: running, paused, suspended, paused & suspended.
525     // The state machine can be in one of two states: running, paused.
526     // Set the state machine to the desired state.
527     bool pause = playState == AnimPlayStatePaused || m_compositeAnimation->isSuspended();
528
529     if (pause == paused() && !isNew())
530         return;
531
532     updateStateMachine(pause ?  AnimationStateInput::PlayStatePaused : AnimationStateInput::PlayStateRunning, -1);
533 }
534
535 double AnimationBase::timeToNextService()
536 {
537     // Returns the time at which next service is required. -1 means no service is required. 0 means 
538     // service is required now, and > 0 means service is required that many seconds in the future.
539     if (paused() || isNew() || m_animationState == AnimationState::FillingForwards)
540         return -1;
541     
542     if (m_animationState == AnimationState::StartWaitTimer) {
543 #if ENABLE(CSS_ANIMATIONS_LEVEL_2)
544         if (m_animation->trigger()->isScrollAnimationTrigger()) {
545             if (m_object) {
546                 float currentScrollOffset = m_object->view().frameView().scrollOffsetForFixedPosition().height().toFloat();
547                 ScrollAnimationTrigger* scrollTrigger = static_cast<ScrollAnimationTrigger*>(m_animation->trigger().get());
548                 if (currentScrollOffset >= scrollTrigger->startValue().value() && (!scrollTrigger->hasEndValue() || currentScrollOffset <= scrollTrigger->endValue().value()))
549                     return 0;
550             }
551             return -1;
552         }
553 #endif
554         double timeFromNow = m_animation->delay() - (beginAnimationUpdateTime() - m_requestedStartTime);
555         return std::max(timeFromNow, 0.0);
556     }
557     
558     fireAnimationEventsIfNeeded();
559         
560     // In all other cases, we need service right away.
561     return 0;
562 }
563
564 // Compute the fractional time, taking into account direction.
565 // There is no need to worry about iterations, we assume that we would have
566 // short circuited above if we were done.
567
568 double AnimationBase::fractionalTime(double scale, double elapsedTime, double offset) const
569 {
570     double fractionalTime = m_animation->duration() ? (elapsedTime / m_animation->duration()) : 1;
571     // FIXME: startTime can be before the current animation "frame" time. This is to sync with the frame time
572     // concept in AnimationTimeController. So we need to somehow sync the two. Until then, the possible
573     // error is small and will probably not be noticeable. Until we fix this, remove the assert.
574     // https://bugs.webkit.org/show_bug.cgi?id=52037
575     // ASSERT(fractionalTime >= 0);
576     if (fractionalTime < 0)
577         fractionalTime = 0;
578
579     int integralTime = static_cast<int>(fractionalTime);
580     const int integralIterationCount = static_cast<int>(m_animation->iterationCount());
581     const bool iterationCountHasFractional = m_animation->iterationCount() - integralIterationCount;
582     if (m_animation->iterationCount() != Animation::IterationCountInfinite && !iterationCountHasFractional)
583         integralTime = std::min(integralTime, integralIterationCount - 1);
584
585     fractionalTime -= integralTime;
586
587     if (((m_animation->direction() == Animation::AnimationDirectionAlternate) && (integralTime & 1))
588         || ((m_animation->direction() == Animation::AnimationDirectionAlternateReverse) && !(integralTime & 1))
589         || m_animation->direction() == Animation::AnimationDirectionReverse)
590         fractionalTime = 1 - fractionalTime;
591
592     if (scale != 1 || offset)
593         fractionalTime = (fractionalTime - offset) * scale;
594
595     return fractionalTime;
596 }
597
598 double AnimationBase::progress(double scale, double offset, const TimingFunction* tf) const
599 {
600     if (preActive())
601         return 0;
602
603     double elapsedTime = getElapsedTime();
604
605     double dur = m_animation->duration();
606     if (m_animation->iterationCount() > 0)
607         dur *= m_animation->iterationCount();
608
609     if (postActive() || !m_animation->duration())
610         return 1.0;
611
612     if (m_animation->iterationCount() > 0 && elapsedTime >= dur) {
613         const int integralIterationCount = static_cast<int>(m_animation->iterationCount());
614         const bool iterationCountHasFractional = m_animation->iterationCount() - integralIterationCount;
615         return (integralIterationCount % 2 || iterationCountHasFractional) ? 1.0 : 0.0;
616     }
617
618     const double fractionalTime = this->fractionalTime(scale, elapsedTime, offset);
619
620     if (!tf)
621         tf = m_animation->timingFunction().get();
622
623     switch (tf->type()) {
624     case TimingFunction::CubicBezierFunction: {
625         const CubicBezierTimingFunction* function = static_cast<const CubicBezierTimingFunction*>(tf);
626         return solveCubicBezierFunction(function->x1(), function->y1(), function->x2(), function->y2(), fractionalTime, m_animation->duration());
627     }
628     case TimingFunction::StepsFunction: {
629         const StepsTimingFunction* stepsTimingFunction = static_cast<const StepsTimingFunction*>(tf);
630         return solveStepsFunction(stepsTimingFunction->numberOfSteps(), stepsTimingFunction->stepAtStart(), fractionalTime);
631     }
632     case TimingFunction::LinearFunction:
633         return fractionalTime;
634     }
635
636     ASSERT_NOT_REACHED();
637     return 0;
638 }
639
640 void AnimationBase::getTimeToNextEvent(double& time, bool& isLooping) const
641 {
642     // Decide when the end or loop event needs to fire
643     const double elapsedDuration = std::max(beginAnimationUpdateTime() - m_startTime, 0.0);
644     double durationLeft = 0;
645     double nextIterationTime = m_totalDuration;
646
647     if (m_totalDuration < 0 || elapsedDuration < m_totalDuration) {
648         durationLeft = m_animation->duration() > 0 ? (m_animation->duration() - fmod(elapsedDuration, m_animation->duration())) : 0;
649         nextIterationTime = elapsedDuration + durationLeft;
650     }
651     
652     if (m_totalDuration < 0 || nextIterationTime < m_totalDuration) {
653         // We are not at the end yet
654         ASSERT(nextIterationTime > 0);
655         isLooping = true;
656     } else {
657         // We are at the end
658         isLooping = false;
659     }
660     
661     time = durationLeft;
662 }
663
664 void AnimationBase::goIntoEndingOrLoopingState()
665 {
666     double t;
667     bool isLooping;
668     getTimeToNextEvent(t, isLooping);
669     LOG(Animations, "%p AnimationState %s -> %s", this, nameForState(m_animationState), isLooping ? "Looping" : "Ending");
670     m_animationState = isLooping ? AnimationState::Looping : AnimationState::Ending;
671 }
672   
673 void AnimationBase::freezeAtTime(double t)
674 {
675     if (!m_compositeAnimation)
676         return;
677
678     if (!m_startTime) {
679         // If we haven't started yet, make it as if we started.
680         LOG(Animations, "%p AnimationState %s -> StartWaitResponse", this, nameForState(m_animationState));
681         m_animationState = AnimationState::StartWaitResponse;
682         onAnimationStartResponse(monotonicallyIncreasingTime());
683     }
684
685     ASSERT(m_startTime);        // if m_startTime is zero, we haven't started yet, so we'll get a bad pause time.
686     if (t <= m_animation->delay())
687         m_pauseTime = m_startTime;
688     else
689         m_pauseTime = m_startTime + t - m_animation->delay();
690
691     if (m_object && m_object->isComposited())
692         downcast<RenderBoxModelObject>(*m_object).suspendAnimations(m_pauseTime);
693 }
694
695 double AnimationBase::beginAnimationUpdateTime() const
696 {
697     if (!m_compositeAnimation)
698         return 0;
699
700     return m_compositeAnimation->animationController()->beginAnimationUpdateTime();
701 }
702
703 double AnimationBase::getElapsedTime() const
704 {
705     if (paused())
706         return m_pauseTime - m_startTime;
707     if (m_startTime <= 0)
708         return 0;
709     if (postActive())
710         return 1;
711
712     return beginAnimationUpdateTime() - m_startTime;
713 }
714
715 void AnimationBase::setElapsedTime(double time)
716 {
717     // FIXME: implement this method
718     UNUSED_PARAM(time);
719 }
720
721 void AnimationBase::play()
722 {
723     // FIXME: implement this method
724 }
725
726 void AnimationBase::pause()
727 {
728     // FIXME: implement this method
729 }
730
731 static bool containsRotation(const Vector<RefPtr<TransformOperation>>& operations)
732 {
733     for (const auto& operation : operations) {
734         if (operation->type() == TransformOperation::ROTATE)
735             return true;
736     }
737     return false;
738 }
739
740 bool AnimationBase::computeTransformedExtentViaTransformList(const FloatRect& rendererBox, const RenderStyle& style, LayoutRect& bounds) const
741 {
742     FloatRect floatBounds = bounds;
743     FloatPoint transformOrigin;
744     
745     bool applyTransformOrigin = containsRotation(style.transform().operations()) || style.transform().affectedByTransformOrigin();
746     if (applyTransformOrigin) {
747         float offsetX = style.transformOriginX().isPercentNotCalculated() ? rendererBox.x() : 0;
748         float offsetY = style.transformOriginY().isPercentNotCalculated() ? rendererBox.y() : 0;
749
750         transformOrigin.setX(floatValueForLength(style.transformOriginX(), rendererBox.width()) + offsetX);
751         transformOrigin.setY(floatValueForLength(style.transformOriginY(), rendererBox.height()) + offsetY);
752         // Ignore transformOriginZ because we'll bail if we encounter any 3D transforms.
753         
754         floatBounds.moveBy(-transformOrigin);
755     }
756
757     for (const auto& operation : style.transform().operations()) {
758         if (operation->type() == TransformOperation::ROTATE) {
759             // For now, just treat this as a full rotation. This could take angle into account to reduce inflation.
760             floatBounds = boundsOfRotatingRect(floatBounds);
761         } else {
762             TransformationMatrix transform;
763             operation->apply(transform, rendererBox.size());
764             if (!transform.isAffine())
765                 return false;
766
767             if (operation->type() == TransformOperation::MATRIX || operation->type() == TransformOperation::MATRIX_3D) {
768                 TransformationMatrix::Decomposed2Type toDecomp;
769                 transform.decompose2(toDecomp);
770                 // Any rotation prevents us from using a simple start/end rect union.
771                 if (toDecomp.angle)
772                     return false;
773             }
774
775             floatBounds = transform.mapRect(floatBounds);
776         }
777     }
778
779     if (applyTransformOrigin)
780         floatBounds.moveBy(transformOrigin);
781
782     bounds = LayoutRect(floatBounds);
783     return true;
784 }
785
786 bool AnimationBase::computeTransformedExtentViaMatrix(const FloatRect& rendererBox, const RenderStyle& style, LayoutRect& bounds) const
787 {
788     TransformationMatrix transform;
789     style.applyTransform(transform, rendererBox, RenderStyle::IncludeTransformOrigin);
790     if (!transform.isAffine())
791         return false;
792
793     TransformationMatrix::Decomposed2Type fromDecomp;
794     transform.decompose2(fromDecomp);
795     // Any rotation prevents us from using a simple start/end rect union.
796     if (fromDecomp.angle)
797         return false;
798
799     bounds = LayoutRect(transform.mapRect(bounds));
800     return true;
801
802 }
803
804 } // namespace WebCore