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