Home | History | Annotate | Download | only in animation
      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 Computer, 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 "core/frame/animation/AnimationBase.h"
     31 
     32 #include "core/frame/animation/AnimationControllerPrivate.h"
     33 #include "core/frame/animation/CompositeAnimation.h"
     34 #include "core/platform/animation/TimingFunction.h"
     35 #include "core/rendering/RenderBox.h"
     36 #include "platform/animation/AnimationUtilities.h"
     37 #include <algorithm>
     38 
     39 using namespace std;
     40 
     41 namespace WebCore {
     42 
     43 AnimationBase::AnimationBase(const CSSAnimationData* transition, RenderObject& renderer, CompositeAnimation* compAnim)
     44     : m_animState(AnimationStateNew)
     45     , m_isAccelerated(false)
     46     , m_transformFunctionListValid(false)
     47     , m_filterFunctionListsMatch(false)
     48     , m_startTime(0)
     49     , m_pauseTime(-1)
     50     , m_requestedStartTime(0)
     51     , m_totalDuration(-1)
     52     , m_nextIterationDuration(-1)
     53     , m_object(&renderer)
     54     , m_animation(const_cast<CSSAnimationData*>(transition))
     55     , m_compAnim(compAnim)
     56 {
     57     // Compute the total duration
     58     if (m_animation->iterationCount() > 0)
     59         m_totalDuration = m_animation->duration() * m_animation->iterationCount();
     60 }
     61 
     62 void AnimationBase::setNeedsStyleRecalc(Node* node)
     63 {
     64     if (node)
     65         node->setNeedsStyleRecalc(LocalStyleChange);
     66 }
     67 
     68 double AnimationBase::duration() const
     69 {
     70     return m_animation->duration();
     71 }
     72 
     73 bool AnimationBase::playStatePlaying() const
     74 {
     75     return m_animation->playState() == AnimPlayStatePlaying;
     76 }
     77 
     78 void AnimationBase::updateStateMachine(AnimStateInput input, double param)
     79 {
     80     if (!m_compAnim)
     81         return;
     82 
     83     // If we get AnimationStateInputRestartAnimation then we force a new animation, regardless of state.
     84     if (input == AnimationStateInputMakeNew) {
     85         if (m_animState == AnimationStateStartWaitStyleAvailable)
     86             m_compAnim->animationController()->removeFromAnimationsWaitingForStyle(this);
     87         m_animState = AnimationStateNew;
     88         m_startTime = 0;
     89         m_pauseTime = -1;
     90         m_requestedStartTime = 0;
     91         m_nextIterationDuration = -1;
     92         endAnimation();
     93         return;
     94     }
     95 
     96     if (input == AnimationStateInputRestartAnimation) {
     97         if (m_animState == AnimationStateStartWaitStyleAvailable)
     98             m_compAnim->animationController()->removeFromAnimationsWaitingForStyle(this);
     99         m_animState = AnimationStateNew;
    100         m_startTime = 0;
    101         m_pauseTime = -1;
    102         m_requestedStartTime = 0;
    103         m_nextIterationDuration = -1;
    104         endAnimation();
    105 
    106         if (!paused())
    107             updateStateMachine(AnimationStateInputStartAnimation, -1);
    108         return;
    109     }
    110 
    111     if (input == AnimationStateInputEndAnimation) {
    112         if (m_animState == AnimationStateStartWaitStyleAvailable)
    113             m_compAnim->animationController()->removeFromAnimationsWaitingForStyle(this);
    114         m_animState = AnimationStateDone;
    115         endAnimation();
    116         return;
    117     }
    118 
    119     if (input == AnimationStateInputPauseOverride) {
    120         if (m_animState == AnimationStateStartWaitResponse) {
    121             // If we are in AnimationStateStartWaitResponse, the animation will get canceled before
    122             // we get a response, so move to the next state.
    123             endAnimation();
    124             updateStateMachine(AnimationStateInputStartTimeSet, beginAnimationUpdateTime());
    125         }
    126         return;
    127     }
    128 
    129     if (input == AnimationStateInputResumeOverride) {
    130         if (m_animState == AnimationStateLooping || m_animState == AnimationStateEnding) {
    131             // Start the animation
    132             startAnimation(beginAnimationUpdateTime() - m_startTime);
    133         }
    134         return;
    135     }
    136 
    137     // Execute state machine
    138     switch (m_animState) {
    139         case AnimationStateNew:
    140             ASSERT(input == AnimationStateInputStartAnimation || input == AnimationStateInputPlayStateRunning || input == AnimationStateInputPlayStatePaused);
    141             if (input == AnimationStateInputStartAnimation || input == AnimationStateInputPlayStateRunning) {
    142                 m_requestedStartTime = beginAnimationUpdateTime();
    143                 m_animState = AnimationStateStartWaitTimer;
    144             }
    145             break;
    146         case AnimationStateStartWaitTimer:
    147             ASSERT(input == AnimationStateInputStartTimerFired || input == AnimationStateInputPlayStatePaused);
    148 
    149             if (input == AnimationStateInputStartTimerFired) {
    150                 ASSERT(param >= 0);
    151                 // Start timer has fired, tell the animation to start and wait for it to respond with start time
    152                 m_animState = AnimationStateStartWaitStyleAvailable;
    153                 m_compAnim->animationController()->addToAnimationsWaitingForStyle(this);
    154 
    155                 // Trigger a render so we can start the animation
    156                 if (m_object)
    157                     m_compAnim->animationController()->addNodeChangeToDispatch(m_object->node());
    158             } else {
    159                 ASSERT(!paused());
    160                 // We're waiting for the start timer to fire and we got a pause. Cancel the timer, pause and wait
    161                 m_pauseTime = beginAnimationUpdateTime();
    162                 m_animState = AnimationStatePausedWaitTimer;
    163             }
    164             break;
    165         case AnimationStateStartWaitStyleAvailable:
    166             ASSERT(input == AnimationStateInputStyleAvailable || input == AnimationStateInputPlayStatePaused);
    167 
    168             if (input == AnimationStateInputStyleAvailable) {
    169                 // Start timer has fired, tell the animation to start and wait for it to respond with start time
    170                 m_animState = AnimationStateStartWaitResponse;
    171 
    172                 overrideAnimations();
    173 
    174                 // Start the animation
    175                 if (overridden()) {
    176                     m_animState = AnimationStateStartWaitResponse;
    177                     updateStateMachine(AnimationStateInputStartTimeSet, beginAnimationUpdateTime());
    178                 } else {
    179                     double timeOffset = 0;
    180                     // If the value for 'animation-delay' is negative then the animation appears to have started in the past.
    181                     if (m_animation->delay() < 0)
    182                         timeOffset = -m_animation->delay();
    183                     startAnimation(timeOffset);
    184                     m_compAnim->animationController()->addToAnimationsWaitingForStartTimeResponse(this, isAccelerated());
    185                 }
    186             } else {
    187                 // We're waiting for the style to be available and we got a pause. Pause and wait
    188                 m_pauseTime = beginAnimationUpdateTime();
    189                 m_animState = AnimationStatePausedWaitStyleAvailable;
    190             }
    191             break;
    192         case AnimationStateStartWaitResponse:
    193             ASSERT(input == AnimationStateInputStartTimeSet || input == AnimationStateInputPlayStatePaused);
    194 
    195             if (input == AnimationStateInputStartTimeSet) {
    196                 ASSERT(param >= 0);
    197                 // We have a start time, set it, unless the startTime is already set
    198                 if (m_startTime <= 0) {
    199                     m_startTime = param;
    200                     // If the value for 'animation-delay' is negative then the animation appears to have started in the past.
    201                     if (m_animation->delay() < 0)
    202                         m_startTime += m_animation->delay();
    203                 }
    204 
    205                 // Now that we know the start time, fire the start event.
    206                 onAnimationStart(0); // The elapsedTime is 0.
    207 
    208                 // Decide whether to go into looping or ending state
    209                 goIntoEndingOrLoopingState();
    210 
    211                 // Dispatch updateStyleIfNeeded so we can start the animation
    212                 if (m_object)
    213                     m_compAnim->animationController()->addNodeChangeToDispatch(m_object->node());
    214             } else {
    215                 // We are pausing while waiting for a start response. Cancel the animation and wait. When
    216                 // we unpause, we will act as though the start timer just fired
    217                 m_pauseTime = beginAnimationUpdateTime();
    218                 pauseAnimation(beginAnimationUpdateTime() - m_startTime);
    219                 m_animState = AnimationStatePausedWaitResponse;
    220             }
    221             break;
    222         case AnimationStateLooping:
    223             ASSERT(input == AnimationStateInputLoopTimerFired || input == AnimationStateInputPlayStatePaused);
    224 
    225             if (input == AnimationStateInputLoopTimerFired) {
    226                 ASSERT(param >= 0);
    227                 // Loop timer fired, loop again or end.
    228                 onAnimationIteration(param);
    229 
    230                 // Decide whether to go into looping or ending state
    231                 goIntoEndingOrLoopingState();
    232             } else {
    233                 // We are pausing while running. Cancel the animation and wait
    234                 m_pauseTime = beginAnimationUpdateTime();
    235                 pauseAnimation(beginAnimationUpdateTime() - m_startTime);
    236                 m_animState = AnimationStatePausedRun;
    237             }
    238             break;
    239         case AnimationStateEnding:
    240 #if !LOG_DISABLED
    241             if (input != AnimationStateInputEndTimerFired && input != AnimationStateInputPlayStatePaused)
    242                 WTF_LOG_ERROR("State is AnimationStateEnding, but input is not AnimationStateInputEndTimerFired or AnimationStateInputPlayStatePaused. It is %d.", input);
    243 #endif
    244             if (input == AnimationStateInputEndTimerFired) {
    245 
    246                 ASSERT(param >= 0);
    247                 // End timer fired, finish up
    248                 onAnimationEnd(param);
    249 
    250                 m_animState = AnimationStateDone;
    251 
    252                 if (m_object) {
    253                     if (m_animation->fillsForwards())
    254                         m_animState = AnimationStateFillingForwards;
    255                     else
    256                         resumeOverriddenAnimations();
    257 
    258                     // Fire off another style change so we can set the final value
    259                     m_compAnim->animationController()->addNodeChangeToDispatch(m_object->node());
    260                 }
    261             } else {
    262                 // We are pausing while running. Cancel the animation and wait
    263                 m_pauseTime = beginAnimationUpdateTime();
    264                 pauseAnimation(beginAnimationUpdateTime() - m_startTime);
    265                 m_animState = AnimationStatePausedRun;
    266             }
    267             // |this| may be deleted here
    268             break;
    269         case AnimationStatePausedWaitTimer:
    270             ASSERT(input == AnimationStateInputPlayStateRunning);
    271             ASSERT(paused());
    272             // Update the times
    273             m_startTime += beginAnimationUpdateTime() - m_pauseTime;
    274             m_pauseTime = -1;
    275 
    276             // we were waiting for the start timer to fire, go back and wait again
    277             m_animState = AnimationStateNew;
    278             updateStateMachine(AnimationStateInputStartAnimation, 0);
    279             break;
    280         case AnimationStatePausedWaitResponse:
    281         case AnimationStatePausedWaitStyleAvailable:
    282         case AnimationStatePausedRun:
    283             // We treat these two cases the same. The only difference is that, when we are in
    284             // AnimationStatePausedWaitResponse, we don't yet have a valid startTime, so we send 0 to startAnimation.
    285             // When the AnimationStateInputStartTimeSet comes in and we were in AnimationStatePausedRun, we will notice
    286             // that we have already set the startTime and will ignore it.
    287             ASSERT(input == AnimationStateInputPlayStateRunning || input == AnimationStateInputStartTimeSet || input == AnimationStateInputStyleAvailable);
    288             ASSERT(paused());
    289 
    290             if (input == AnimationStateInputPlayStateRunning) {
    291                 // Update the times
    292                 if (m_animState == AnimationStatePausedRun)
    293                     m_startTime += beginAnimationUpdateTime() - m_pauseTime;
    294                 else
    295                     m_startTime = 0;
    296                 m_pauseTime = -1;
    297 
    298                 if (m_animState == AnimationStatePausedWaitStyleAvailable)
    299                     m_animState = AnimationStateStartWaitStyleAvailable;
    300                 else {
    301                     // We were either running or waiting for a begin time response from the animation.
    302                     // Either way we need to restart the animation (possibly with an offset if we
    303                     // had already been running) and wait for it to start.
    304                     m_animState = AnimationStateStartWaitResponse;
    305 
    306                     // Start the animation
    307                     if (overridden()) {
    308                         updateStateMachine(AnimationStateInputStartTimeSet, beginAnimationUpdateTime());
    309                     } else {
    310                         startAnimation(beginAnimationUpdateTime() - m_startTime);
    311                         m_compAnim->animationController()->addToAnimationsWaitingForStartTimeResponse(this, isAccelerated());
    312                     }
    313                 }
    314                 break;
    315             }
    316 
    317             if (input == AnimationStateInputStartTimeSet) {
    318                 ASSERT(m_animState == AnimationStatePausedWaitResponse);
    319 
    320                 // We are paused but we got the callback that notifies us that an accelerated animation started.
    321                 // We ignore the start time and just move into the paused-run state.
    322                 m_animState = AnimationStatePausedRun;
    323                 ASSERT(m_startTime == 0);
    324                 m_startTime = param;
    325                 m_pauseTime += m_startTime;
    326                 break;
    327             }
    328 
    329             ASSERT(m_animState == AnimationStatePausedWaitStyleAvailable);
    330             // We are paused but we got the callback that notifies us that style has been updated.
    331             // We move to the AnimationStatePausedWaitResponse state
    332             m_animState = AnimationStatePausedWaitResponse;
    333             overrideAnimations();
    334             break;
    335         case AnimationStateFillingForwards:
    336         case AnimationStateDone:
    337             // We're done. Stay in this state until we are deleted
    338             break;
    339     }
    340 }
    341 
    342 void AnimationBase::fireAnimationEventsIfNeeded()
    343 {
    344     if (!m_compAnim)
    345         return;
    346 
    347     // If we are waiting for the delay time to expire and it has, go to the next state
    348     if (m_animState != AnimationStateStartWaitTimer && m_animState != AnimationStateLooping && m_animState != AnimationStateEnding)
    349         return;
    350 
    351     // We have to make sure to keep a ref to the this pointer, because it could get destroyed
    352     // during an animation callback that might get called. Since the owner is a CompositeAnimation
    353     // and it ref counts this object, we will keep a ref to that instead. That way the AnimationBase
    354     // can still access the resources of its CompositeAnimation as needed.
    355     RefPtr<AnimationBase> protector(this);
    356     RefPtr<CompositeAnimation> compProtector(m_compAnim);
    357 
    358     // Check for start timeout
    359     if (m_animState == AnimationStateStartWaitTimer) {
    360         if (beginAnimationUpdateTime() - m_requestedStartTime >= m_animation->delay())
    361             updateStateMachine(AnimationStateInputStartTimerFired, 0);
    362         return;
    363     }
    364 
    365     double elapsedDuration = getElapsedTime();
    366 
    367     // Check for end timeout
    368     if (m_totalDuration >= 0 && elapsedDuration >= m_totalDuration) {
    369         // We may still be in AnimationStateLooping if we've managed to skip a
    370         // whole iteration, in which case we should jump to the end state.
    371         m_animState = AnimationStateEnding;
    372 
    373         // Fire an end event
    374         updateStateMachine(AnimationStateInputEndTimerFired, m_totalDuration);
    375     } else {
    376         // Check for iteration timeout
    377         if (m_nextIterationDuration < 0) {
    378             // Hasn't been set yet, set it
    379             double durationLeft = m_animation->duration() - fmod(elapsedDuration, m_animation->duration());
    380             m_nextIterationDuration = elapsedDuration + durationLeft;
    381         }
    382 
    383         if (elapsedDuration >= m_nextIterationDuration) {
    384             // Set to the next iteration
    385             double previous = m_nextIterationDuration;
    386             double durationLeft = m_animation->duration() - fmod(elapsedDuration, m_animation->duration());
    387             m_nextIterationDuration = elapsedDuration + durationLeft;
    388 
    389             // Send the event
    390             updateStateMachine(AnimationStateInputLoopTimerFired, previous);
    391         }
    392     }
    393 }
    394 
    395 void AnimationBase::updatePlayState(EAnimPlayState playState)
    396 {
    397     if (!m_compAnim)
    398         return;
    399 
    400     // Set the state machine to the desired state.
    401     bool pause = playState == AnimPlayStatePaused;
    402 
    403     if (pause == paused() && !isNew())
    404         return;
    405 
    406     updateStateMachine(pause ?  AnimationStateInputPlayStatePaused : AnimationStateInputPlayStateRunning, -1);
    407 }
    408 
    409 double AnimationBase::timeToNextService()
    410 {
    411     // Returns the time at which next service is required. -1 means no service is required. 0 means
    412     // service is required now, and > 0 means service is required that many seconds in the future.
    413     if (paused() || isNew() || m_animState == AnimationStateFillingForwards)
    414         return -1;
    415 
    416     if (m_animState == AnimationStateStartWaitTimer) {
    417         double timeFromNow = m_animation->delay() - (beginAnimationUpdateTime() - m_requestedStartTime);
    418         return max(timeFromNow, 0.0);
    419     }
    420 
    421     fireAnimationEventsIfNeeded();
    422 
    423     // In all other cases, we need service right away.
    424     return 0;
    425 }
    426 
    427 // Compute the fractional time, taking into account direction.
    428 // There is no need to worry about iterations, we assume that we would have
    429 // short circuited above if we were done.
    430 
    431 double AnimationBase::fractionalTime(double scale, double elapsedTime, double offset) const
    432 {
    433     double fractionalTime = m_animation->duration() ? (elapsedTime / m_animation->duration()) : 1;
    434     // FIXME: startTime can be before the current animation "frame" time. This is to sync with the frame time
    435     // concept in AnimationTimeController. So we need to somehow sync the two. Until then, the possible
    436     // error is small and will probably not be noticeable. Until we fix this, remove the assert.
    437     // https://bugs.webkit.org/show_bug.cgi?id=52037
    438     // ASSERT(fractionalTime >= 0);
    439     if (fractionalTime < 0)
    440         fractionalTime = 0;
    441 
    442     int integralTime = static_cast<int>(fractionalTime);
    443     const int integralIterationCount = static_cast<int>(m_animation->iterationCount());
    444     const bool iterationCountHasFractional = m_animation->iterationCount() - integralIterationCount;
    445     if (m_animation->iterationCount() != CSSAnimationData::IterationCountInfinite && !iterationCountHasFractional)
    446         integralTime = min(integralTime, integralIterationCount - 1);
    447 
    448     fractionalTime -= integralTime;
    449 
    450     // Thie method can be called with an elapsedTime which very slightly
    451     // exceeds the end of the animation. In this case, clamp the
    452     // fractionalTime.
    453     if (fractionalTime > 1)
    454         fractionalTime = 1;
    455     ASSERT(fractionalTime >= 0 && fractionalTime <= 1);
    456 
    457     if (((m_animation->direction() == CSSAnimationData::AnimationDirectionAlternate) && (integralTime & 1))
    458         || ((m_animation->direction() == CSSAnimationData::AnimationDirectionAlternateReverse) && !(integralTime & 1))
    459         || m_animation->direction() == CSSAnimationData::AnimationDirectionReverse)
    460         fractionalTime = 1 - fractionalTime;
    461 
    462     fractionalTime -= offset;
    463     // Note that if fractionalTime == 0 here, scale may be infinity, but in
    464     // this case we don't need to apply scale anyway.
    465     if (scale != 1.0 && fractionalTime) {
    466         ASSERT(scale >= 0 && !std::isinf(scale));
    467         fractionalTime *= scale;
    468     }
    469 
    470     ASSERT(fractionalTime >= 0 && fractionalTime <= 1);
    471     return fractionalTime;
    472 }
    473 
    474 double AnimationBase::progress(double scale, double offset, const TimingFunction* timingFunction) const
    475 {
    476     if (preActive())
    477         return 0;
    478 
    479     double dur = m_animation->duration();
    480     if (m_animation->iterationCount() > 0)
    481         dur *= m_animation->iterationCount();
    482 
    483     if (postActive() || !m_animation->duration())
    484         return 1.0;
    485 
    486     double elapsedTime = getElapsedTime();
    487     if (m_animation->iterationCount() > 0 && elapsedTime >= dur) {
    488         const int integralIterationCount = static_cast<int>(m_animation->iterationCount());
    489         const bool iterationCountHasFractional = m_animation->iterationCount() - integralIterationCount;
    490         return (integralIterationCount % 2 || iterationCountHasFractional) ? 1.0 : 0.0;
    491     }
    492 
    493     const double fractionalTime = this->fractionalTime(scale, elapsedTime, offset);
    494 
    495     if (!timingFunction)
    496         timingFunction = m_animation->timingFunction();
    497 
    498     return timingFunction->evaluate(fractionalTime, accuracyForDuration(m_animation->duration()));
    499 }
    500 
    501 void AnimationBase::getTimeToNextEvent(double& time, bool& isLooping) const
    502 {
    503     if (postActive()) {
    504         time = -1;
    505         isLooping = false;
    506         return;
    507     }
    508 
    509     // Decide when the end or loop event needs to fire
    510     const double elapsedDuration = getElapsedTime();
    511     double durationLeft = 0;
    512     double nextIterationTime = m_totalDuration;
    513 
    514     if (m_totalDuration < 0 || elapsedDuration < m_totalDuration) {
    515         durationLeft = m_animation->duration() > 0 ? (m_animation->duration() - fmod(elapsedDuration, m_animation->duration())) : 0;
    516         nextIterationTime = elapsedDuration + durationLeft;
    517     }
    518 
    519     if (m_totalDuration < 0 || nextIterationTime < m_totalDuration) {
    520         // We are not at the end yet
    521         ASSERT(m_totalDuration < 0 || nextIterationTime > 0);
    522         isLooping = true;
    523     } else {
    524         // We are at the end
    525         isLooping = false;
    526     }
    527 
    528     time = durationLeft;
    529 }
    530 
    531 void AnimationBase::goIntoEndingOrLoopingState()
    532 {
    533     double t;
    534     bool isLooping;
    535     getTimeToNextEvent(t, isLooping);
    536     m_animState = isLooping ? AnimationStateLooping : AnimationStateEnding;
    537 }
    538 
    539 void AnimationBase::freezeAtTime(double t)
    540 {
    541     if (!m_compAnim)
    542         return;
    543 
    544     if (!m_startTime) {
    545         // If we haven't started yet, make it as if we started.
    546         m_animState = AnimationStateStartWaitResponse;
    547         onAnimationStartResponse(beginAnimationUpdateTime());
    548     }
    549 
    550     ASSERT(m_startTime);        // if m_startTime is zero, we haven't started yet, so we'll get a bad pause time.
    551     if (t <= m_animation->delay())
    552         m_pauseTime = m_startTime;
    553     else
    554         m_pauseTime = m_startTime + t - m_animation->delay();
    555 
    556     // It is possible that m_isAccelerated is true and m_object->compositingState() is NotComposited, because of style change.
    557     // So, both conditions need to be checked.
    558     if (m_object && m_object->compositingState() == PaintsIntoOwnBacking && isAccelerated())
    559         pauseAnimation(t);
    560 }
    561 
    562 double AnimationBase::beginAnimationUpdateTime() const
    563 {
    564     if (!m_compAnim)
    565         return 0;
    566 
    567     return m_compAnim->animationController()->beginAnimationUpdateTime();
    568 }
    569 
    570 double AnimationBase::getElapsedTime() const
    571 {
    572     ASSERT(!postActive());
    573     if (paused())
    574         return m_pauseTime - m_startTime;
    575     if (m_startTime <= 0)
    576         return 0;
    577 
    578     double elapsedTime = beginAnimationUpdateTime() - m_startTime;
    579     // It's possible for the start time to be ahead of the last update time
    580     // if the compositor has just sent notification for the start of an
    581     // accelerated animation.
    582     return max(elapsedTime, 0.0);
    583 }
    584 
    585 } // namespace WebCore
    586