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/page/animation/AnimationController.h"
     31 
     32 #include "core/dom/AnimationEvent.h"
     33 #include "core/dom/EventNames.h"
     34 #include "core/dom/PseudoElement.h"
     35 #include "core/dom/TransitionEvent.h"
     36 #include "core/page/Frame.h"
     37 #include "core/page/FrameView.h"
     38 #include "core/page/Page.h"
     39 #include "core/page/animation/AnimationBase.h"
     40 #include "core/page/animation/AnimationControllerPrivate.h"
     41 #include "core/page/animation/CSSPropertyAnimation.h"
     42 #include "core/page/animation/CompositeAnimation.h"
     43 #include "core/rendering/RenderView.h"
     44 #include "wtf/CurrentTime.h"
     45 
     46 namespace WebCore {
     47 
     48 static const double cBeginAnimationUpdateTimeNotSet = -1;
     49 
     50 AnimationControllerPrivate::AnimationControllerPrivate(Frame* frame)
     51     : m_animationTimer(this, &AnimationControllerPrivate::animationTimerFired)
     52     , m_updateStyleIfNeededDispatcher(this, &AnimationControllerPrivate::updateStyleIfNeededDispatcherFired)
     53     , m_frame(frame)
     54     , m_beginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet)
     55     , m_animationsWaitingForStyle()
     56     , m_animationsWaitingForStartTimeResponse()
     57     , m_waitingForAsyncStartNotification(false)
     58 {
     59 }
     60 
     61 AnimationControllerPrivate::~AnimationControllerPrivate()
     62 {
     63 }
     64 
     65 PassRefPtr<CompositeAnimation> AnimationControllerPrivate::accessCompositeAnimation(RenderObject* renderer)
     66 {
     67     RefPtr<CompositeAnimation> animation = m_compositeAnimations.get(renderer);
     68     if (!animation) {
     69         animation = CompositeAnimation::create(this);
     70         m_compositeAnimations.set(renderer, animation);
     71     }
     72     return animation;
     73 }
     74 
     75 bool AnimationControllerPrivate::clear(RenderObject* renderer)
     76 {
     77     // Return false if we didn't do anything OR we are suspended (so we don't try to
     78     // do a setNeedsStyleRecalc() when suspended).
     79     PassRefPtr<CompositeAnimation> animation = m_compositeAnimations.take(renderer);
     80     if (!animation)
     81         return false;
     82     animation->clearRenderer();
     83     return animation->suspended();
     84 }
     85 
     86 void AnimationControllerPrivate::updateAnimations(double& timeToNextService, double& timeToNextEvent, SetNeedsStyleRecalc callSetNeedsStyleRecalc/* = DoNotCallSetNeedsStyleRecalc*/)
     87 {
     88     double minTimeToNextService = -1;
     89     double minTimeToNextEvent = -1;
     90     bool updateStyleNeeded = false;
     91 
     92     RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end();
     93     for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) {
     94         CompositeAnimation* compAnim = it->value.get();
     95         if (!compAnim->suspended() && compAnim->hasAnimations()) {
     96             double t = compAnim->timeToNextService();
     97             if (t != -1 && (t < minTimeToNextService || minTimeToNextService == -1))
     98                 minTimeToNextService = t;
     99             double nextEvent = compAnim->timeToNextEvent();
    100             if (nextEvent != -1 && (nextEvent < minTimeToNextEvent || minTimeToNextEvent == -1))
    101                 minTimeToNextEvent = nextEvent;
    102             if (callSetNeedsStyleRecalc == CallSetNeedsStyleRecalc) {
    103                 if (!t) {
    104                     Node* node = it->key->node();
    105                     node->setNeedsStyleRecalc(LocalStyleChange, StyleChangeFromRenderer);
    106                     updateStyleNeeded = true;
    107                 }
    108             } else if (!minTimeToNextService && !minTimeToNextEvent) {
    109                 // Found the minimum values and do not need to mark for style recalc.
    110                 break;
    111             }
    112         }
    113     }
    114 
    115     if (updateStyleNeeded)
    116         m_frame->document()->updateStyleIfNeeded();
    117 
    118     timeToNextService = minTimeToNextService;
    119     timeToNextEvent = minTimeToNextEvent;
    120 }
    121 
    122 void AnimationControllerPrivate::scheduleServiceForRenderer(RenderObject* renderer)
    123 {
    124     double timeToNextService = -1;
    125     double timeToNextEvent = -1;
    126 
    127     RefPtr<CompositeAnimation> compAnim = m_compositeAnimations.get(renderer);
    128     if (!compAnim->suspended() && compAnim->hasAnimations()) {
    129         timeToNextService = compAnim->timeToNextService();
    130         timeToNextEvent = compAnim->timeToNextEvent();
    131     }
    132 
    133     if (timeToNextService >= 0)
    134         scheduleService(timeToNextService, timeToNextEvent);
    135 }
    136 
    137 void AnimationControllerPrivate::scheduleService()
    138 {
    139     double timeToNextService = -1;
    140     double timeToNextEvent = -1;
    141     updateAnimations(timeToNextService, timeToNextEvent, DoNotCallSetNeedsStyleRecalc);
    142     scheduleService(timeToNextService, timeToNextEvent);
    143 }
    144 
    145 void AnimationControllerPrivate::scheduleService(double timeToNextService, double timeToNextEvent)
    146 {
    147     if (!m_frame->page())
    148         return;
    149 
    150     bool visible = m_frame->page()->visibilityState() == WebCore::PageVisibilityStateVisible;
    151 
    152     if (!visible)
    153         timeToNextService = timeToNextEvent;
    154 
    155     if (visible && !timeToNextService) {
    156         m_frame->document()->view()->scheduleAnimation();
    157         if (m_animationTimer.isActive())
    158             m_animationTimer.stop();
    159         return;
    160     }
    161 
    162     if (timeToNextService < 0) {
    163         if (m_animationTimer.isActive())
    164             m_animationTimer.stop();
    165         return;
    166     }
    167 
    168     if (m_animationTimer.isActive() && m_animationTimer.nextFireInterval() <= timeToNextService)
    169         return;
    170 
    171     m_animationTimer.startOneShot(timeToNextService);
    172 }
    173 
    174 void AnimationControllerPrivate::updateStyleIfNeededDispatcherFired(Timer<AnimationControllerPrivate>*)
    175 {
    176     fireEventsAndUpdateStyle();
    177 }
    178 
    179 void AnimationControllerPrivate::fireEventsAndUpdateStyle()
    180 {
    181     // Protect the frame from getting destroyed in the event handler
    182     RefPtr<Frame> protector = m_frame;
    183 
    184     bool updateStyle = !m_eventsToDispatch.isEmpty() || !m_nodeChangesToDispatch.isEmpty();
    185 
    186     // fire all the events
    187     Vector<EventToDispatch> eventsToDispatch = m_eventsToDispatch;
    188     m_eventsToDispatch.clear();
    189     Vector<EventToDispatch>::const_iterator eventsToDispatchEnd = eventsToDispatch.end();
    190     for (Vector<EventToDispatch>::const_iterator it = eventsToDispatch.begin(); it != eventsToDispatchEnd; ++it) {
    191         Element* element = it->element.get();
    192         if (it->eventType == eventNames().transitionendEvent)
    193             element->dispatchEvent(TransitionEvent::create(it->eventType, it->name, it->elapsedTime, PseudoElement::pseudoElementNameForEvents(element->pseudoId())));
    194         else
    195             element->dispatchEvent(AnimationEvent::create(it->eventType, it->name, it->elapsedTime));
    196     }
    197 
    198     // call setChanged on all the elements
    199     Vector<RefPtr<Node> >::const_iterator nodeChangesToDispatchEnd = m_nodeChangesToDispatch.end();
    200     for (Vector<RefPtr<Node> >::const_iterator it = m_nodeChangesToDispatch.begin(); it != nodeChangesToDispatchEnd; ++it)
    201         (*it)->setNeedsStyleRecalc(LocalStyleChange, StyleChangeFromRenderer);
    202 
    203     m_nodeChangesToDispatch.clear();
    204 
    205     if (updateStyle && m_frame)
    206         m_frame->document()->updateStyleIfNeeded();
    207 }
    208 
    209 void AnimationControllerPrivate::startUpdateStyleIfNeededDispatcher()
    210 {
    211     if (!m_updateStyleIfNeededDispatcher.isActive())
    212         m_updateStyleIfNeededDispatcher.startOneShot(0);
    213 }
    214 
    215 void AnimationControllerPrivate::addEventToDispatch(PassRefPtr<Element> element, const AtomicString& eventType, const String& name, double elapsedTime)
    216 {
    217     m_eventsToDispatch.grow(m_eventsToDispatch.size()+1);
    218     EventToDispatch& event = m_eventsToDispatch[m_eventsToDispatch.size()-1];
    219     event.element = element;
    220     event.eventType = eventType;
    221     event.name = name;
    222     event.elapsedTime = elapsedTime;
    223 
    224     startUpdateStyleIfNeededDispatcher();
    225 }
    226 
    227 void AnimationControllerPrivate::addNodeChangeToDispatch(PassRefPtr<Node> node)
    228 {
    229     if (!node)
    230         return;
    231 
    232     m_nodeChangesToDispatch.append(node);
    233     startUpdateStyleIfNeededDispatcher();
    234 }
    235 
    236 void AnimationControllerPrivate::serviceAnimations()
    237 {
    238     double timeToNextService = -1;
    239     double timeToNextEvent = -1;
    240     updateAnimations(timeToNextService, timeToNextEvent, CallSetNeedsStyleRecalc);
    241     scheduleService(timeToNextService, timeToNextEvent);
    242 
    243     // Fire events right away, to avoid a flash of unanimated style after an animation completes, and before
    244     // the 'end' event fires.
    245     fireEventsAndUpdateStyle();
    246 }
    247 
    248 void AnimationControllerPrivate::animationTimerFired(Timer<AnimationControllerPrivate>*)
    249 {
    250     // Make sure animationUpdateTime is updated, so that it is current even if no
    251     // styleChange has happened (e.g. accelerated animations)
    252     setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet);
    253     serviceAnimations();
    254 }
    255 
    256 bool AnimationControllerPrivate::isRunningAnimationOnRenderer(RenderObject* renderer, CSSPropertyID property, bool isRunningNow) const
    257 {
    258     RefPtr<CompositeAnimation> animation = m_compositeAnimations.get(renderer);
    259     if (!animation)
    260         return false;
    261 
    262     return animation->isAnimatingProperty(property, false, isRunningNow);
    263 }
    264 
    265 bool AnimationControllerPrivate::isRunningAcceleratableAnimationOnRenderer(RenderObject *renderer) const
    266 {
    267     RefPtr<CompositeAnimation> animation = m_compositeAnimations.get(renderer);
    268     if (!animation)
    269         return false;
    270 
    271     bool acceleratedOnly = false;
    272     bool isRunningNow = true;
    273     return animation->isAnimatingProperty(CSSPropertyOpacity, acceleratedOnly, isRunningNow)
    274         || animation->isAnimatingProperty(CSSPropertyWebkitTransform, acceleratedOnly, isRunningNow)
    275         || animation->isAnimatingProperty(CSSPropertyWebkitFilter, acceleratedOnly, isRunningNow);
    276 }
    277 
    278 bool AnimationControllerPrivate::isRunningAcceleratedAnimationOnRenderer(RenderObject* renderer, CSSPropertyID property, bool isRunningNow) const
    279 {
    280     RefPtr<CompositeAnimation> animation = m_compositeAnimations.get(renderer);
    281     if (!animation)
    282         return false;
    283 
    284     return animation->isAnimatingProperty(property, true, isRunningNow);
    285 }
    286 
    287 void AnimationControllerPrivate::suspendAnimations()
    288 {
    289     suspendAnimationsForDocument(m_frame->document());
    290 
    291     // Traverse subframes
    292     for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
    293         child->animation()->suspendAnimations();
    294 }
    295 
    296 void AnimationControllerPrivate::resumeAnimations()
    297 {
    298     resumeAnimationsForDocument(m_frame->document());
    299 
    300     // Traverse subframes
    301     for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
    302         child->animation()->resumeAnimations();
    303 }
    304 
    305 void AnimationControllerPrivate::suspendAnimationsForDocument(Document* document)
    306 {
    307     setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet);
    308 
    309     RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end();
    310     for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) {
    311         RenderObject* renderer = it->key;
    312         if (renderer->document() == document) {
    313             CompositeAnimation* compAnim = it->value.get();
    314             compAnim->suspendAnimations();
    315         }
    316     }
    317 
    318     scheduleService();
    319 }
    320 
    321 void AnimationControllerPrivate::resumeAnimationsForDocument(Document* document)
    322 {
    323     setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet);
    324 
    325     RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end();
    326     for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) {
    327         RenderObject* renderer = it->key;
    328         if (renderer->document() == document) {
    329             CompositeAnimation* compAnim = it->value.get();
    330             compAnim->resumeAnimations();
    331         }
    332     }
    333 
    334     scheduleService();
    335 }
    336 
    337 void AnimationControllerPrivate::pauseAnimationsForTesting(double t)
    338 {
    339     RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end();
    340     for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) {
    341         it->value->pauseAnimationsForTesting(t);
    342         it->key->node()->setNeedsStyleRecalc(LocalStyleChange, StyleChangeFromRenderer);
    343     }
    344 }
    345 
    346 double AnimationControllerPrivate::beginAnimationUpdateTime()
    347 {
    348     if (m_beginAnimationUpdateTime == cBeginAnimationUpdateTimeNotSet)
    349         m_beginAnimationUpdateTime = currentTime();
    350     return m_beginAnimationUpdateTime;
    351 }
    352 
    353 void AnimationControllerPrivate::endAnimationUpdate()
    354 {
    355     styleAvailable();
    356     if (!m_waitingForAsyncStartNotification)
    357         startTimeResponse(beginAnimationUpdateTime());
    358 }
    359 
    360 void AnimationControllerPrivate::receivedStartTimeResponse(double time)
    361 {
    362     m_waitingForAsyncStartNotification = false;
    363     startTimeResponse(time);
    364 }
    365 
    366 PassRefPtr<RenderStyle> AnimationControllerPrivate::getAnimatedStyleForRenderer(RenderObject* renderer)
    367 {
    368     if (!renderer)
    369         return 0;
    370 
    371     RefPtr<CompositeAnimation> rendererAnimations = m_compositeAnimations.get(renderer);
    372     if (!rendererAnimations)
    373         return renderer->style();
    374 
    375     RefPtr<RenderStyle> animatingStyle = rendererAnimations->getAnimatedStyle();
    376     if (!animatingStyle)
    377         animatingStyle = renderer->style();
    378 
    379     return animatingStyle.release();
    380 }
    381 
    382 unsigned AnimationControllerPrivate::numberOfActiveAnimations(Document* document) const
    383 {
    384     unsigned count = 0;
    385 
    386     RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end();
    387     for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) {
    388         RenderObject* renderer = it->key;
    389         CompositeAnimation* compAnim = it->value.get();
    390         if (renderer->document() == document)
    391             count += compAnim->numberOfActiveAnimations();
    392     }
    393 
    394     return count;
    395 }
    396 
    397 void AnimationControllerPrivate::addToAnimationsWaitingForStyle(AnimationBase* animation)
    398 {
    399     // Make sure this animation is not in the start time waiters
    400     m_animationsWaitingForStartTimeResponse.remove(animation);
    401 
    402     m_animationsWaitingForStyle.add(animation);
    403 }
    404 
    405 void AnimationControllerPrivate::removeFromAnimationsWaitingForStyle(AnimationBase* animationToRemove)
    406 {
    407     m_animationsWaitingForStyle.remove(animationToRemove);
    408 }
    409 
    410 void AnimationControllerPrivate::styleAvailable()
    411 {
    412     // Go through list of waiters and send them on their way
    413     WaitingAnimationsSet::const_iterator it = m_animationsWaitingForStyle.begin();
    414     WaitingAnimationsSet::const_iterator end = m_animationsWaitingForStyle.end();
    415     for (; it != end; ++it)
    416         (*it)->styleAvailable();
    417 
    418     m_animationsWaitingForStyle.clear();
    419 }
    420 
    421 void AnimationControllerPrivate::addToAnimationsWaitingForStartTimeResponse(AnimationBase* animation, bool willGetResponse)
    422 {
    423     // If willGetResponse is true, it means this animation is actually waiting for a response
    424     // (which will come in as a call to notifyAnimationStarted()).
    425     // In that case we don't need to add it to this list. We just set a waitingForAResponse flag
    426     // which says we are waiting for the response. If willGetResponse is false, this animation
    427     // is not waiting for a response for itself, but rather for a notifyXXXStarted() call for
    428     // another animation to which it will sync.
    429     //
    430     // When endAnimationUpdate() is called we check to see if the waitingForAResponse flag is
    431     // true. If so, we just return and will do our work when the first notifyXXXStarted() call
    432     // comes in. If it is false, we will not be getting a notifyXXXStarted() call, so we will
    433     // do our work right away. In both cases we call the onAnimationStartResponse() method
    434     // on each animation. In the first case we send in the time we got from notifyXXXStarted().
    435     // In the second case, we just pass in the beginAnimationUpdateTime().
    436     //
    437     // This will synchronize all software and accelerated animations started in the same
    438     // updateStyleIfNeeded cycle.
    439     //
    440 
    441     if (willGetResponse)
    442         m_waitingForAsyncStartNotification = true;
    443 
    444     m_animationsWaitingForStartTimeResponse.add(animation);
    445 }
    446 
    447 void AnimationControllerPrivate::removeFromAnimationsWaitingForStartTimeResponse(AnimationBase* animationToRemove)
    448 {
    449     m_animationsWaitingForStartTimeResponse.remove(animationToRemove);
    450 
    451     if (m_animationsWaitingForStartTimeResponse.isEmpty())
    452         m_waitingForAsyncStartNotification = false;
    453 }
    454 
    455 void AnimationControllerPrivate::startTimeResponse(double time)
    456 {
    457     // Go through list of waiters and send them on their way
    458 
    459     WaitingAnimationsSet::const_iterator it = m_animationsWaitingForStartTimeResponse.begin();
    460     WaitingAnimationsSet::const_iterator end = m_animationsWaitingForStartTimeResponse.end();
    461     for (; it != end; ++it)
    462         (*it)->onAnimationStartResponse(time);
    463 
    464     m_animationsWaitingForStartTimeResponse.clear();
    465     m_waitingForAsyncStartNotification = false;
    466 }
    467 
    468 void AnimationControllerPrivate::animationWillBeRemoved(AnimationBase* animation)
    469 {
    470     removeFromAnimationsWaitingForStyle(animation);
    471     removeFromAnimationsWaitingForStartTimeResponse(animation);
    472 }
    473 
    474 AnimationController::AnimationController(Frame* frame)
    475     : m_data(adoptPtr(new AnimationControllerPrivate(frame)))
    476     , m_beginAnimationUpdateCount(0)
    477 {
    478 }
    479 
    480 AnimationController::~AnimationController()
    481 {
    482 }
    483 
    484 void AnimationController::cancelAnimations(RenderObject* renderer)
    485 {
    486     if (!m_data->hasAnimations())
    487         return;
    488 
    489     if (m_data->clear(renderer)) {
    490         if (Node* node = renderer->node())
    491             node->setNeedsStyleRecalc(LocalStyleChange, StyleChangeFromRenderer);
    492     }
    493 }
    494 
    495 PassRefPtr<RenderStyle> AnimationController::updateAnimations(RenderObject* renderer, RenderStyle* newStyle)
    496 {
    497     if (!renderer->document())
    498         return newStyle;
    499 
    500     RenderStyle* oldStyle = renderer->style();
    501 
    502     if ((!oldStyle || (!oldStyle->animations() && !oldStyle->transitions())) && (!newStyle->animations() && !newStyle->transitions()))
    503         return newStyle;
    504 
    505     // Don't run transitions when printing.
    506     if (renderer->view()->printing())
    507         return newStyle;
    508 
    509     // Fetch our current set of implicit animations from a hashtable.  We then compare them
    510     // against the animations in the style and make sure we're in sync.  If destination values
    511     // have changed, we reset the animation.  We then do a blend to get new values and we return
    512     // a new style.
    513 
    514     // We don't support anonymous pseudo elements like :first-line or :first-letter.
    515     ASSERT(renderer->node());
    516 
    517     RefPtr<CompositeAnimation> rendererAnimations = m_data->accessCompositeAnimation(renderer);
    518     RefPtr<RenderStyle> blendedStyle = rendererAnimations->animate(renderer, oldStyle, newStyle);
    519 
    520     if (renderer->parent() || newStyle->animations() || (oldStyle && oldStyle->animations())) {
    521         m_data->scheduleServiceForRenderer(renderer);
    522     }
    523 
    524     if (blendedStyle != newStyle) {
    525         // If the animations/transitions change opacity or transform, we need to update
    526         // the style to impose the stacking rules. Note that this is also
    527         // done in StyleResolver::adjustRenderStyle().
    528         if (blendedStyle->hasAutoZIndex() && (blendedStyle->opacity() < 1.0f || blendedStyle->hasTransform()))
    529             blendedStyle->setZIndex(0);
    530     }
    531     return blendedStyle.release();
    532 }
    533 
    534 PassRefPtr<RenderStyle> AnimationController::getAnimatedStyleForRenderer(RenderObject* renderer)
    535 {
    536     return m_data->getAnimatedStyleForRenderer(renderer);
    537 }
    538 
    539 void AnimationController::notifyAnimationStarted(RenderObject*, double startTime)
    540 {
    541     m_data->receivedStartTimeResponse(startTime);
    542 }
    543 
    544 void AnimationController::pauseAnimationsForTesting(double t)
    545 {
    546     m_data->pauseAnimationsForTesting(t);
    547 }
    548 
    549 unsigned AnimationController::numberOfActiveAnimations(Document* document) const
    550 {
    551     return m_data->numberOfActiveAnimations(document);
    552 }
    553 
    554 bool AnimationController::isRunningAnimationOnRenderer(RenderObject* renderer, CSSPropertyID property, bool isRunningNow) const
    555 {
    556     return m_data->isRunningAnimationOnRenderer(renderer, property, isRunningNow);
    557 }
    558 
    559 bool AnimationController::isRunningAcceleratableAnimationOnRenderer(RenderObject* renderer) const
    560 {
    561     return m_data->isRunningAcceleratableAnimationOnRenderer(renderer);
    562 }
    563 
    564 bool AnimationController::isRunningAcceleratedAnimationOnRenderer(RenderObject* renderer, CSSPropertyID property, bool isRunningNow) const
    565 {
    566     return m_data->isRunningAcceleratedAnimationOnRenderer(renderer, property, isRunningNow);
    567 }
    568 
    569 void AnimationController::suspendAnimations()
    570 {
    571     m_data->suspendAnimations();
    572 }
    573 
    574 void AnimationController::resumeAnimations()
    575 {
    576     m_data->resumeAnimations();
    577 }
    578 
    579 void AnimationController::serviceAnimations()
    580 {
    581     m_data->serviceAnimations();
    582 }
    583 
    584 void AnimationController::suspendAnimationsForDocument(Document* document)
    585 {
    586     m_data->suspendAnimationsForDocument(document);
    587 }
    588 
    589 void AnimationController::resumeAnimationsForDocument(Document* document)
    590 {
    591     m_data->resumeAnimationsForDocument(document);
    592 }
    593 
    594 void AnimationController::beginAnimationUpdate()
    595 {
    596     if (!m_beginAnimationUpdateCount)
    597         m_data->setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet);
    598     ++m_beginAnimationUpdateCount;
    599 }
    600 
    601 void AnimationController::endAnimationUpdate()
    602 {
    603     ASSERT(m_beginAnimationUpdateCount > 0);
    604     --m_beginAnimationUpdateCount;
    605     if (!m_beginAnimationUpdateCount)
    606         m_data->endAnimationUpdate();
    607 }
    608 
    609 bool AnimationController::supportsAcceleratedAnimationOfProperty(CSSPropertyID property)
    610 {
    611     return CSSPropertyAnimation::animationOfPropertyIsAccelerated(property);
    612 }
    613 
    614 } // namespace WebCore
    615