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