Home | History | Annotate | Download | only in animation
      1 /*
      2  * Copyright (C) 2007 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  *
      8  * 1.  Redistributions of source code must retain the above copyright
      9  *     notice, this list of conditions and the following disclaimer.
     10  * 2.  Redistributions in binary form must reproduce the above copyright
     11  *     notice, this list of conditions and the following disclaimer in the
     12  *     documentation and/or other materials provided with the distribution.
     13  * 3.  Neither the name of Apple 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/CompositeAnimation.h"
     31 
     32 #include "CSSPropertyNames.h"
     33 #include "core/page/animation/AnimationControllerPrivate.h"
     34 #include "core/page/animation/CSSPropertyAnimation.h"
     35 #include "core/page/animation/ImplicitAnimation.h"
     36 #include "core/page/animation/KeyframeAnimation.h"
     37 #include "core/rendering/style/RenderStyle.h"
     38 
     39 namespace WebCore {
     40 
     41 CompositeAnimation::~CompositeAnimation()
     42 {
     43     // Toss the refs to all animations, but make sure we remove them from
     44     // any waiting lists first.
     45 
     46     clearRenderer();
     47     m_transitions.clear();
     48     m_keyframeAnimations.clear();
     49 }
     50 
     51 void CompositeAnimation::clearRenderer()
     52 {
     53     if (!m_transitions.isEmpty()) {
     54         // Clear the renderers from all running animations, in case we are in the middle of
     55         // an animation callback (see https://bugs.webkit.org/show_bug.cgi?id=22052)
     56         CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end();
     57         for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) {
     58             ImplicitAnimation* transition = it->value.get();
     59             animationController()->animationWillBeRemoved(transition);
     60             transition->clear();
     61         }
     62     }
     63     if (!m_keyframeAnimations.isEmpty()) {
     64         AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end();
     65         for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) {
     66             KeyframeAnimation* anim = it->value.get();
     67             animationController()->animationWillBeRemoved(anim);
     68             anim->clear();
     69         }
     70     }
     71 }
     72 
     73 void CompositeAnimation::updateTransitions(RenderObject* renderer, RenderStyle* currentStyle, RenderStyle* targetStyle)
     74 {
     75     // If currentStyle is null or there are no old or new transitions, just skip it
     76     if (!currentStyle || (!targetStyle->transitions() && m_transitions.isEmpty()))
     77         return;
     78 
     79     // Mark all existing transitions as no longer active. We will mark the still active ones
     80     // in the next loop and then toss the ones that didn't get marked.
     81     CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
     82     for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it)
     83         it->value->setActive(false);
     84 
     85     RefPtr<RenderStyle> modifiedCurrentStyle;
     86 
     87     // Check to see if we need to update the active transitions
     88     if (targetStyle->transitions()) {
     89         for (size_t i = 0; i < targetStyle->transitions()->size(); ++i) {
     90             const CSSAnimationData* anim = targetStyle->transitions()->animation(i);
     91             bool isActiveTransition = anim->duration() || anim->delay() > 0;
     92 
     93             CSSAnimationData::AnimationMode mode = anim->animationMode();
     94             if (mode == CSSAnimationData::AnimateNone)
     95                 continue;
     96 
     97             CSSPropertyID prop = anim->property();
     98 
     99             bool all = mode == CSSAnimationData::AnimateAll;
    100 
    101             // Handle both the 'all' and single property cases. For the single prop case, we make only one pass
    102             // through the loop.
    103             for (int propertyIndex = 0; propertyIndex < CSSPropertyAnimation::getNumProperties(); ++propertyIndex) {
    104                 if (all) {
    105                     // Get the next property which is not a shorthand.
    106                     bool isShorthand;
    107                     prop = CSSPropertyAnimation::getPropertyAtIndex(propertyIndex, isShorthand);
    108                     if (isShorthand)
    109                         continue;
    110                 }
    111 
    112                 // ImplicitAnimations are always hashed by actual properties, never animateAll.
    113                 ASSERT(prop >= firstCSSProperty && prop < (firstCSSProperty + numCSSProperties));
    114 
    115                 // If there is a running animation for this property, the transition is overridden
    116                 // and we have to use the unanimatedStyle from the animation. We do the test
    117                 // against the unanimated style here, but we "override" the transition later.
    118                 RefPtr<KeyframeAnimation> keyframeAnim = getAnimationForProperty(prop);
    119                 RenderStyle* fromStyle = keyframeAnim ? keyframeAnim->unanimatedStyle() : currentStyle;
    120 
    121                 // See if there is a current transition for this prop
    122                 ImplicitAnimation* implAnim = m_transitions.get(prop);
    123                 bool equal = true;
    124 
    125                 if (implAnim) {
    126                     // If we are post active don't bother setting the active flag. This will cause
    127                     // this animation to get removed at the end of this function.
    128                     if (!implAnim->postActive())
    129                         implAnim->setActive(true);
    130 
    131                     // This might be a transition that is just finishing. That would be the case
    132                     // if it were postActive. But we still need to check for equality because
    133                     // it could be just finishing AND changing to a new goal state.
    134                     //
    135                     // This implAnim might also not be an already running transition. It might be
    136                     // newly added to the list in a previous iteration. This would happen if
    137                     // you have both an explicit transition-property and 'all' in the same
    138                     // list. In this case, the latter one overrides the earlier one, so we
    139                     // behave as though this is a running animation being replaced.
    140                     if (!implAnim->isTargetPropertyEqual(prop, targetStyle)) {
    141                         // For accelerated animations we need to return a new RenderStyle with the _current_ value
    142                         // of the property, so that restarted transitions use the correct starting point.
    143                         if (CSSPropertyAnimation::animationOfPropertyIsAccelerated(prop) && implAnim->isAccelerated()) {
    144                             if (!modifiedCurrentStyle)
    145                                 modifiedCurrentStyle = RenderStyle::clone(currentStyle);
    146 
    147                             implAnim->blendPropertyValueInStyle(prop, modifiedCurrentStyle.get());
    148                         }
    149                         animationController()->animationWillBeRemoved(implAnim);
    150                         m_transitions.remove(prop);
    151                         equal = false;
    152                     }
    153                 } else {
    154                     // We need to start a transition if it is active and the properties don't match
    155                     equal = !isActiveTransition || CSSPropertyAnimation::propertiesEqual(prop, fromStyle, targetStyle);
    156                 }
    157 
    158                 // We can be in this loop with an inactive transition (!isActiveTransition). We need
    159                 // to do that to check to see if we are canceling a transition. But we don't want to
    160                 // start one of the inactive transitions. So short circuit that here. (See
    161                 // <https://bugs.webkit.org/show_bug.cgi?id=24787>
    162                 if (!equal && isActiveTransition) {
    163                     // Add the new transition
    164                     m_transitions.set(prop, ImplicitAnimation::create(const_cast<CSSAnimationData*>(anim), prop, renderer, this, modifiedCurrentStyle ? modifiedCurrentStyle.get() : fromStyle));
    165                 }
    166 
    167                 // We only need one pass for the single prop case
    168                 if (!all)
    169                     break;
    170             }
    171         }
    172     }
    173 
    174     // Make a list of transitions to be removed
    175     Vector<int> toBeRemoved;
    176     end = m_transitions.end();
    177     for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
    178         ImplicitAnimation* anim = it->value.get();
    179         if (!anim->active()) {
    180             animationController()->animationWillBeRemoved(anim);
    181             toBeRemoved.append(anim->animatingProperty());
    182         }
    183     }
    184 
    185     // Now remove the transitions from the list
    186     for (size_t j = 0; j < toBeRemoved.size(); ++j)
    187         m_transitions.remove(toBeRemoved[j]);
    188 }
    189 
    190 void CompositeAnimation::updateKeyframeAnimations(RenderObject* renderer, RenderStyle* currentStyle, RenderStyle* targetStyle)
    191 {
    192     // Nothing to do if we don't have any animations, and didn't have any before
    193     if (m_keyframeAnimations.isEmpty() && !targetStyle->hasAnimations())
    194         return;
    195 
    196     AnimationNameMap::const_iterator kfend = m_keyframeAnimations.end();
    197 
    198     if (currentStyle && currentStyle->hasAnimations() && targetStyle->hasAnimations() && *(currentStyle->animations()) == *(targetStyle->animations())) {
    199         // The current and target animations are the same so we just need to toss any
    200         // animation which is finished (postActive).
    201         for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != kfend; ++it) {
    202             if (it->value->postActive())
    203                 it->value->setIndex(-1);
    204         }
    205     } else {
    206         // Mark all existing animations as no longer active.
    207         for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != kfend; ++it)
    208             it->value->setIndex(-1);
    209 
    210         // Toss the animation order map.
    211         m_keyframeAnimationOrderList.clear();
    212 
    213         DEFINE_STATIC_LOCAL(const AtomicString, none, ("none", AtomicString::ConstructFromLiteral));
    214 
    215         // Now mark any still active animations as active and add any new animations.
    216         if (targetStyle->animations()) {
    217             int numAnims = targetStyle->animations()->size();
    218             for (int i = 0; i < numAnims; ++i) {
    219                 const CSSAnimationData* anim = targetStyle->animations()->animation(i);
    220                 if (!anim->isValidAnimation())
    221                     continue;
    222 
    223                 // See if there is a current animation for this name.
    224                 AtomicString name(anim->name());
    225                 RefPtr<KeyframeAnimation> keyframeAnim = m_keyframeAnimations.get(name);
    226                 if (keyframeAnim) {
    227                     // If this animation is postActive, skip it so it gets removed at the end of this function.
    228                     if (keyframeAnim->postActive())
    229                         continue;
    230 
    231                     // This one is still active.
    232 
    233                     // Animations match, but play states may differ. Update if needed.
    234                     keyframeAnim->updatePlayState(anim->playState());
    235 
    236                     // Set the saved animation to this new one, just in case the play state has changed.
    237                     keyframeAnim->setAnimation(anim);
    238                     keyframeAnim->setIndex(i);
    239                 } else if ((anim->duration() || anim->delay()) && anim->iterationCount() && name != none) {
    240                     keyframeAnim = KeyframeAnimation::create(const_cast<CSSAnimationData*>(anim), renderer, i, this, targetStyle);
    241                     m_keyframeAnimations.set(name, keyframeAnim);
    242                 }
    243 
    244                 // Add this to the animation order map.
    245                 if (keyframeAnim)
    246                     m_keyframeAnimationOrderList.append(name);
    247             }
    248         }
    249     }
    250 
    251     // Make a list of animations to be removed.
    252     Vector<AtomicString> animsToBeRemoved;
    253     kfend = m_keyframeAnimations.end();
    254     for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != kfend; ++it) {
    255         KeyframeAnimation* keyframeAnim = it->value.get();
    256         if (keyframeAnim->index() < 0) {
    257             animsToBeRemoved.append(keyframeAnim->name());
    258             animationController()->animationWillBeRemoved(keyframeAnim);
    259             keyframeAnim->clear();
    260         }
    261     }
    262 
    263     // Now remove the animations from the list, and keep stale keys out of the order list.
    264     if (animsToBeRemoved.size()) {
    265         for (size_t j = 0; j < animsToBeRemoved.size(); ++j) {
    266             ASSERT(m_keyframeAnimations.contains(animsToBeRemoved[j]));
    267             m_keyframeAnimations.remove(animsToBeRemoved[j]);
    268         }
    269         Vector<AtomicString> newOrderList;
    270         for (size_t j = 0; j < m_keyframeAnimationOrderList.size(); ++j) {
    271             AtomicString key = m_keyframeAnimationOrderList[j];
    272             if (m_keyframeAnimations.contains(key))
    273                 newOrderList.append(key);
    274         }
    275         m_keyframeAnimationOrderList.swap(newOrderList);
    276     }
    277 }
    278 
    279 PassRefPtr<RenderStyle> CompositeAnimation::animate(RenderObject* renderer, RenderStyle* currentStyle, RenderStyle* targetStyle)
    280 {
    281     RefPtr<RenderStyle> resultStyle;
    282 
    283     // We don't do any transitions if we don't have a currentStyle (on startup).
    284     updateTransitions(renderer, currentStyle, targetStyle);
    285     updateKeyframeAnimations(renderer, currentStyle, targetStyle);
    286 
    287     if (currentStyle) {
    288         // Now that we have transition objects ready, let them know about the new goal state.  We want them
    289         // to fill in a RenderStyle*& only if needed.
    290         if (!m_transitions.isEmpty()) {
    291             CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
    292             for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
    293                 if (ImplicitAnimation* anim = it->value.get())
    294                     anim->animate(this, renderer, currentStyle, targetStyle, resultStyle);
    295             }
    296         }
    297     }
    298 
    299     // Now that we have animation objects ready, let them know about the new goal state.  We want them
    300     // to fill in a RenderStyle*& only if needed.
    301     for (Vector<AtomicString>::const_iterator it = m_keyframeAnimationOrderList.begin(); it != m_keyframeAnimationOrderList.end(); ++it) {
    302         RefPtr<KeyframeAnimation> keyframeAnim = m_keyframeAnimations.get(*it);
    303         ASSERT(keyframeAnim);
    304         keyframeAnim->animate(this, renderer, currentStyle, targetStyle, resultStyle);
    305     }
    306 
    307     return resultStyle ? resultStyle.release() : targetStyle;
    308 }
    309 
    310 PassRefPtr<RenderStyle> CompositeAnimation::getAnimatedStyle() const
    311 {
    312     RefPtr<RenderStyle> resultStyle;
    313     CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
    314     for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
    315         if (ImplicitAnimation* implicitAnimation = it->value.get())
    316             implicitAnimation->getAnimatedStyle(resultStyle);
    317     }
    318 
    319     for (Vector<AtomicString>::const_iterator it = m_keyframeAnimationOrderList.begin(); it != m_keyframeAnimationOrderList.end(); ++it) {
    320         RefPtr<KeyframeAnimation> keyframeAnimation = m_keyframeAnimations.get(*it);
    321         ASSERT(keyframeAnimation);
    322         keyframeAnimation->getAnimatedStyle(resultStyle);
    323     }
    324 
    325     return resultStyle;
    326 }
    327 
    328 double CompositeAnimation::timeToNextService() const
    329 {
    330     // Returns the time at which next service is required. -1 means no service is required. 0 means
    331     // service is required now, and > 0 means service is required that many seconds in the future.
    332     double minT = -1;
    333 
    334     if (!m_transitions.isEmpty()) {
    335         CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end();
    336         for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) {
    337             ImplicitAnimation* transition = it->value.get();
    338             double t = transition ? transition->timeToNextService() : -1;
    339             if (t < minT || minT == -1)
    340                 minT = t;
    341             if (minT == 0)
    342                 return 0;
    343         }
    344     }
    345     if (!m_keyframeAnimations.isEmpty()) {
    346         AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end();
    347         for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) {
    348             KeyframeAnimation* animation = it->value.get();
    349             double t = animation ? animation->timeToNextService() : -1;
    350             if (t < minT || minT == -1)
    351                 minT = t;
    352             if (minT == 0)
    353                 return 0;
    354         }
    355     }
    356 
    357     return minT;
    358 }
    359 
    360 double CompositeAnimation::timeToNextEvent() const
    361 {
    362     // Returns the time at which next service to trigger events is required. -1 means no service is required. 0 means
    363     // service is required now, and > 0 means service is required that many seconds in the future.
    364     double minT = -1;
    365 
    366     if (!m_transitions.isEmpty()) {
    367         CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end();
    368         for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) {
    369             ImplicitAnimation* transition = it->value.get();
    370             double t = -1;
    371             bool isLooping;
    372             if (transition)
    373                 transition->getTimeToNextEvent(t, isLooping);
    374             if (t < minT || minT == -1)
    375                 minT = t;
    376             if (!minT)
    377                 return 0;
    378         }
    379     }
    380     if (!m_keyframeAnimations.isEmpty()) {
    381         AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end();
    382         for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) {
    383             KeyframeAnimation* animation = it->value.get();
    384             double t = -1;
    385             bool isLooping;
    386             if (animation)
    387                 animation->getTimeToNextEvent(t, isLooping);
    388             if (t < minT || minT == -1)
    389                 minT = t;
    390             if (!minT)
    391                 return 0;
    392         }
    393     }
    394 
    395     return minT;
    396 }
    397 
    398 PassRefPtr<KeyframeAnimation> CompositeAnimation::getAnimationForProperty(CSSPropertyID property) const
    399 {
    400     RefPtr<KeyframeAnimation> retval;
    401 
    402     // We want to send back the last animation with the property if there are multiples.
    403     // So we need to iterate through all animations
    404     if (!m_keyframeAnimations.isEmpty()) {
    405         AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end();
    406         for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) {
    407             RefPtr<KeyframeAnimation> anim = it->value;
    408             if (anim->hasAnimationForProperty(property))
    409                 retval = anim;
    410         }
    411     }
    412 
    413     return retval;
    414 }
    415 
    416 void CompositeAnimation::suspendAnimations()
    417 {
    418     if (m_suspended)
    419         return;
    420 
    421     m_suspended = true;
    422 
    423     if (!m_keyframeAnimations.isEmpty()) {
    424         AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end();
    425         for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) {
    426             if (KeyframeAnimation* anim = it->value.get())
    427                 anim->updatePlayState(AnimPlayStatePaused);
    428         }
    429     }
    430     if (!m_transitions.isEmpty()) {
    431         CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end();
    432         for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) {
    433             ImplicitAnimation* anim = it->value.get();
    434             if (anim && anim->hasStyle())
    435                 anim->updatePlayState(AnimPlayStatePaused);
    436         }
    437     }
    438 }
    439 
    440 void CompositeAnimation::resumeAnimations()
    441 {
    442     if (!m_suspended)
    443         return;
    444 
    445     m_suspended = false;
    446 
    447     if (!m_keyframeAnimations.isEmpty()) {
    448         AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end();
    449         for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) {
    450             KeyframeAnimation* anim = it->value.get();
    451             if (anim && anim->playStatePlaying())
    452                 anim->updatePlayState(AnimPlayStatePlaying);
    453         }
    454     }
    455 
    456     if (!m_transitions.isEmpty()) {
    457         CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end();
    458         for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) {
    459             ImplicitAnimation* anim = it->value.get();
    460             if (anim && anim->hasStyle())
    461                 anim->updatePlayState(AnimPlayStatePlaying);
    462         }
    463     }
    464 }
    465 
    466 void CompositeAnimation::overrideImplicitAnimations(CSSPropertyID property)
    467 {
    468     CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
    469     if (!m_transitions.isEmpty()) {
    470         for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
    471             ImplicitAnimation* anim = it->value.get();
    472             if (anim && anim->animatingProperty() == property)
    473                 anim->setOverridden(true);
    474         }
    475     }
    476 }
    477 
    478 void CompositeAnimation::resumeOverriddenImplicitAnimations(CSSPropertyID property)
    479 {
    480     if (!m_transitions.isEmpty()) {
    481         CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
    482         for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
    483             ImplicitAnimation* anim = it->value.get();
    484             if (anim && anim->animatingProperty() == property)
    485                 anim->setOverridden(false);
    486         }
    487     }
    488 }
    489 
    490 bool CompositeAnimation::isAnimatingProperty(CSSPropertyID property, bool acceleratedOnly, bool isRunningNow) const
    491 {
    492     if (!m_keyframeAnimations.isEmpty()) {
    493         AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end();
    494         for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) {
    495             KeyframeAnimation* anim = it->value.get();
    496             if (anim && anim->isAnimatingProperty(property, acceleratedOnly, isRunningNow))
    497                 return true;
    498         }
    499     }
    500 
    501     if (!m_transitions.isEmpty()) {
    502         CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end();
    503         for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) {
    504             ImplicitAnimation* anim = it->value.get();
    505             if (anim && anim->isAnimatingProperty(property, acceleratedOnly, isRunningNow))
    506                 return true;
    507         }
    508     }
    509     return false;
    510 }
    511 
    512 void CompositeAnimation::pauseAnimationsForTesting(double t)
    513 {
    514     AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end();
    515     for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) {
    516         RefPtr<KeyframeAnimation> keyframeAnim = it->value;
    517         if (!keyframeAnim || !keyframeAnim->running())
    518             continue;
    519 
    520         double count = keyframeAnim->m_animation->iterationCount();
    521         if ((t >= 0.0) && ((count == CSSAnimationData::IterationCountInfinite) || (t <= count * keyframeAnim->duration())))
    522             keyframeAnim->freezeAtTime(t);
    523     }
    524 
    525     CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end();
    526     for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) {
    527         RefPtr<ImplicitAnimation> implAnim = it->value;
    528 
    529         if (!implAnim->running())
    530             continue;
    531 
    532         if ((t >= 0.0) && (t <= implAnim->duration()))
    533             implAnim->freezeAtTime(t);
    534     }
    535 }
    536 
    537 unsigned CompositeAnimation::numberOfActiveAnimations() const
    538 {
    539     unsigned count = 0;
    540 
    541     if (!m_keyframeAnimations.isEmpty()) {
    542         AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end();
    543         for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) {
    544             KeyframeAnimation* anim = it->value.get();
    545             if (anim->running())
    546                 ++count;
    547         }
    548     }
    549 
    550     if (!m_transitions.isEmpty()) {
    551         CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end();
    552         for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) {
    553             ImplicitAnimation* anim = it->value.get();
    554             if (anim->running())
    555                 ++count;
    556         }
    557     }
    558 
    559     return count;
    560 }
    561 
    562 } // namespace WebCore
    563