OLD | NEW |
| (Empty) |
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/frame/animation/CompositeAnimation.h" | |
31 | |
32 #include "CSSPropertyNames.h" | |
33 #include "core/frame/animation/AnimationControllerPrivate.h" | |
34 #include "core/frame/animation/CSSPropertyAnimation.h" | |
35 #include "core/rendering/style/RenderStyle.h" | |
36 | |
37 namespace WebCore { | |
38 | |
39 CompositeAnimation::~CompositeAnimation() | |
40 { | |
41 // Toss the refs to all animations, but make sure we remove them from | |
42 // any waiting lists first. | |
43 | |
44 clearRenderer(); | |
45 m_transitions.clear(); | |
46 m_keyframeAnimations.clear(); | |
47 } | |
48 | |
49 void CompositeAnimation::clearRenderer() | |
50 { | |
51 if (!m_transitions.isEmpty()) { | |
52 // Clear the renderers from all running animations, in case we are in th
e middle of | |
53 // an animation callback (see https://bugs.webkit.org/show_bug.cgi?id=22
052) | |
54 CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions
.end(); | |
55 for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(
); it != transitionsEnd; ++it) { | |
56 ImplicitAnimation* transition = it->value.get(); | |
57 animationController()->animationWillBeRemoved(transition); | |
58 transition->clear(); | |
59 } | |
60 } | |
61 if (!m_keyframeAnimations.isEmpty()) { | |
62 AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.en
d(); | |
63 for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin();
it != animationsEnd; ++it) { | |
64 KeyframeAnimation* anim = it->value.get(); | |
65 animationController()->animationWillBeRemoved(anim); | |
66 anim->clear(); | |
67 } | |
68 } | |
69 } | |
70 | |
71 void CompositeAnimation::updateTransitions(RenderObject& renderer, RenderStyle*
currentStyle, RenderStyle& targetStyle) | |
72 { | |
73 // If currentStyle is null or there are no old or new transitions, just skip
it | |
74 if (!currentStyle || (!targetStyle.transitions() && m_transitions.isEmpty())
) | |
75 return; | |
76 | |
77 // Mark all existing transitions as no longer active. We will mark the still
active ones | |
78 // in the next loop and then toss the ones that didn't get marked. | |
79 CSSPropertyTransitionsMap::const_iterator end = m_transitions.end(); | |
80 for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); i
t != end; ++it) | |
81 it->value->setActive(false); | |
82 | |
83 RefPtr<RenderStyle> modifiedCurrentStyle; | |
84 | |
85 // Check to see if we need to update the active transitions | |
86 if (targetStyle.transitions()) { | |
87 for (size_t i = 0; i < targetStyle.transitions()->size(); ++i) { | |
88 const CSSAnimationData* anim = targetStyle.transitions()->animation(
i); | |
89 bool isActiveTransition = anim->duration() || anim->delay() > 0; | |
90 | |
91 CSSAnimationData::AnimationMode mode = anim->animationMode(); | |
92 if (mode == CSSAnimationData::AnimateNone) | |
93 continue; | |
94 | |
95 CSSPropertyID prop = anim->property(); | |
96 | |
97 bool all = mode == CSSAnimationData::AnimateAll; | |
98 | |
99 // Handle both the 'all' and single property cases. For the single p
rop case, we make only one pass | |
100 // through the loop. | |
101 for (int propertyIndex = 0; propertyIndex < CSSPropertyAnimation::ge
tNumProperties(); ++propertyIndex) { | |
102 if (all) { | |
103 // Get the next property which is not a shorthand. | |
104 bool isShorthand; | |
105 prop = CSSPropertyAnimation::getPropertyAtIndex(propertyInde
x, isShorthand); | |
106 if (isShorthand) | |
107 continue; | |
108 } | |
109 | |
110 // ImplicitAnimations are always hashed by actual properties, ne
ver animateAll. | |
111 ASSERT(prop >= firstCSSProperty && prop < (firstCSSProperty + nu
mCSSProperties)); | |
112 | |
113 // If there is a running animation for this property, the transi
tion is overridden | |
114 // and we have to use the unanimatedStyle from the animation. We
do the test | |
115 // against the unanimated style here, but we "override" the tran
sition later. | |
116 RefPtr<KeyframeAnimation> keyframeAnim = getAnimationForProperty
(prop); | |
117 RenderStyle* fromStyle = keyframeAnim ? keyframeAnim->unanimated
Style() : currentStyle; | |
118 | |
119 // See if there is a current transition for this prop | |
120 ImplicitAnimation* implAnim = m_transitions.get(prop); | |
121 bool equal = true; | |
122 | |
123 if (implAnim) { | |
124 // If we are post active don't bother setting the active fla
g. This will cause | |
125 // this animation to get removed at the end of this function
. | |
126 if (!implAnim->postActive()) | |
127 implAnim->setActive(true); | |
128 | |
129 // This might be a transition that is just finishing. That w
ould be the case | |
130 // if it were postActive. But we still need to check for equ
ality because | |
131 // it could be just finishing AND changing to a new goal sta
te. | |
132 // | |
133 // This implAnim might also not be an already running transi
tion. It might be | |
134 // newly added to the list in a previous iteration. This wou
ld happen if | |
135 // you have both an explicit transition-property and 'all' i
n the same | |
136 // list. In this case, the latter one overrides the earlier
one, so we | |
137 // behave as though this is a running animation being replac
ed. | |
138 if (!implAnim->isTargetPropertyEqual(prop, &targetStyle)) { | |
139 // For accelerated animations we need to return a new Re
nderStyle with the _current_ value | |
140 // of the property, so that restarted transitions use th
e correct starting point. | |
141 if (CSSPropertyAnimation::animationOfPropertyIsAccelerat
ed(prop) && implAnim->isAccelerated()) { | |
142 if (!modifiedCurrentStyle) | |
143 modifiedCurrentStyle = RenderStyle::clone(curren
tStyle); | |
144 | |
145 implAnim->blendPropertyValueInStyle(prop, modifiedCu
rrentStyle.get()); | |
146 } | |
147 animationController()->animationWillBeRemoved(implAnim); | |
148 m_transitions.remove(prop); | |
149 equal = false; | |
150 } | |
151 } else { | |
152 // We need to start a transition if it is active and the pro
perties don't match | |
153 equal = !isActiveTransition || CSSPropertyAnimation::propert
iesEqual(prop, fromStyle, &targetStyle); | |
154 } | |
155 | |
156 // We can be in this loop with an inactive transition (!isActive
Transition). We need | |
157 // to do that to check to see if we are canceling a transition.
But we don't want to | |
158 // start one of the inactive transitions. So short circuit that
here. (See | |
159 // <https://bugs.webkit.org/show_bug.cgi?id=24787> | |
160 if (!equal && isActiveTransition) { | |
161 // Add the new transition | |
162 m_transitions.set(prop, ImplicitAnimation::create(const_cast
<CSSAnimationData*>(anim), prop, renderer, this, modifiedCurrentStyle ? modified
CurrentStyle.get() : fromStyle)); | |
163 } | |
164 | |
165 // We only need one pass for the single prop case | |
166 if (!all) | |
167 break; | |
168 } | |
169 } | |
170 } | |
171 | |
172 // Make a list of transitions to be removed | |
173 Vector<int> toBeRemoved; | |
174 end = m_transitions.end(); | |
175 for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); i
t != end; ++it) { | |
176 ImplicitAnimation* anim = it->value.get(); | |
177 if (!anim->active()) { | |
178 animationController()->animationWillBeRemoved(anim); | |
179 toBeRemoved.append(anim->animatingProperty()); | |
180 } | |
181 } | |
182 | |
183 // Now remove the transitions from the list | |
184 for (size_t j = 0; j < toBeRemoved.size(); ++j) | |
185 m_transitions.remove(toBeRemoved[j]); | |
186 } | |
187 | |
188 void CompositeAnimation::updateKeyframeAnimations(RenderObject& renderer, Render
Style* currentStyle, RenderStyle& targetStyle) | |
189 { | |
190 // Nothing to do if we don't have any animations, and didn't have any before | |
191 if (m_keyframeAnimations.isEmpty() && !targetStyle.hasAnimations()) | |
192 return; | |
193 | |
194 AnimationNameMap::const_iterator kfend = m_keyframeAnimations.end(); | |
195 | |
196 if (currentStyle && currentStyle->hasAnimations() && targetStyle.hasAnimatio
ns() && *(currentStyle->animations()) == *(targetStyle.animations())) { | |
197 // The current and target animations are the same so we just need to tos
s any | |
198 // animation which is finished (postActive). | |
199 for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin();
it != kfend; ++it) { | |
200 if (it->value->postActive()) | |
201 it->value->setIndex(-1); | |
202 } | |
203 } else { | |
204 // Mark all existing animations as no longer active. | |
205 for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin();
it != kfend; ++it) | |
206 it->value->setIndex(-1); | |
207 | |
208 // Toss the animation order map. | |
209 m_keyframeAnimationOrderList.clear(); | |
210 | |
211 DEFINE_STATIC_LOCAL(const AtomicString, none, ("none", AtomicString::Con
structFromLiteral)); | |
212 | |
213 // Now mark any still active animations as active and add any new animat
ions. | |
214 if (targetStyle.animations()) { | |
215 int numAnims = targetStyle.animations()->size(); | |
216 for (int i = 0; i < numAnims; ++i) { | |
217 const CSSAnimationData* anim = targetStyle.animations()->animati
on(i); | |
218 if (!anim->isValidAnimation()) | |
219 continue; | |
220 | |
221 // See if there is a current animation for this name. | |
222 AtomicString name(anim->name()); | |
223 RefPtr<KeyframeAnimation> keyframeAnim = m_keyframeAnimations.ge
t(name); | |
224 if (keyframeAnim) { | |
225 // If this animation is postActive, skip it so it gets remov
ed at the end of this function. | |
226 if (keyframeAnim->postActive()) | |
227 continue; | |
228 | |
229 // This one is still active. | |
230 | |
231 // Animations match, but play states may differ. Update if n
eeded. | |
232 keyframeAnim->updatePlayState(anim->playState()); | |
233 | |
234 // Set the saved animation to this new one, just in case the
play state has changed. | |
235 keyframeAnim->setAnimation(anim); | |
236 keyframeAnim->setIndex(i); | |
237 } else if ((anim->duration() || anim->delay()) && anim->iteratio
nCount() && name != none) { | |
238 keyframeAnim = KeyframeAnimation::create(const_cast<CSSAnima
tionData*>(anim), renderer, i, this, targetStyle); | |
239 m_keyframeAnimations.set(name, keyframeAnim); | |
240 } | |
241 | |
242 // Add this to the animation order map. | |
243 if (keyframeAnim) | |
244 m_keyframeAnimationOrderList.append(name); | |
245 } | |
246 } | |
247 } | |
248 | |
249 // Make a list of animations to be removed. | |
250 Vector<AtomicString> animsToBeRemoved; | |
251 kfend = m_keyframeAnimations.end(); | |
252 for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it
!= kfend; ++it) { | |
253 KeyframeAnimation* keyframeAnim = it->value.get(); | |
254 if (keyframeAnim->index() < 0) { | |
255 animsToBeRemoved.append(keyframeAnim->name()); | |
256 animationController()->animationWillBeRemoved(keyframeAnim); | |
257 keyframeAnim->clear(); | |
258 } | |
259 } | |
260 | |
261 // Now remove the animations from the list, and keep stale keys out of the o
rder list. | |
262 if (animsToBeRemoved.size()) { | |
263 for (size_t j = 0; j < animsToBeRemoved.size(); ++j) { | |
264 ASSERT(m_keyframeAnimations.contains(animsToBeRemoved[j])); | |
265 m_keyframeAnimations.remove(animsToBeRemoved[j]); | |
266 } | |
267 Vector<AtomicString> newOrderList; | |
268 for (size_t j = 0; j < m_keyframeAnimationOrderList.size(); ++j) { | |
269 AtomicString key = m_keyframeAnimationOrderList[j]; | |
270 if (m_keyframeAnimations.contains(key)) | |
271 newOrderList.append(key); | |
272 } | |
273 m_keyframeAnimationOrderList.swap(newOrderList); | |
274 } | |
275 } | |
276 | |
277 PassRefPtr<RenderStyle> CompositeAnimation::animate(RenderObject& renderer, Rend
erStyle* 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 | |
285 if (currentStyle) { | |
286 // Now that we have transition objects ready, let them know about the ne
w goal state. We want them | |
287 // to fill in a RenderStyle*& only if needed. | |
288 if (!m_transitions.isEmpty()) { | |
289 CSSPropertyTransitionsMap::const_iterator end = m_transitions.end(); | |
290 for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.be
gin(); it != end; ++it) { | |
291 if (ImplicitAnimation* anim = it->value.get()) | |
292 anim->animate(this, &renderer, currentStyle, &targetStyle, r
esultStyle); | |
293 } | |
294 } | |
295 } | |
296 | |
297 // Now that we have animation objects ready, let them know about the new goa
l state. We want them | |
298 // to fill in a RenderStyle*& only if needed. | |
299 for (Vector<AtomicString>::const_iterator it = m_keyframeAnimationOrderList.
begin(); it != m_keyframeAnimationOrderList.end(); ++it) { | |
300 RefPtr<KeyframeAnimation> keyframeAnim = m_keyframeAnimations.get(*it); | |
301 ASSERT(keyframeAnim); | |
302 keyframeAnim->animate(this, &renderer, currentStyle, &targetStyle, resul
tStyle); | |
303 } | |
304 | |
305 return resultStyle ? resultStyle.release() : PassRefPtr<RenderStyle>(targetS
tyle); | |
306 } | |
307 | |
308 PassRefPtr<RenderStyle> CompositeAnimation::getAnimatedStyle() const | |
309 { | |
310 RefPtr<RenderStyle> resultStyle; | |
311 CSSPropertyTransitionsMap::const_iterator end = m_transitions.end(); | |
312 for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); i
t != end; ++it) { | |
313 if (ImplicitAnimation* implicitAnimation = it->value.get()) | |
314 implicitAnimation->getAnimatedStyle(resultStyle); | |
315 } | |
316 | |
317 for (Vector<AtomicString>::const_iterator it = m_keyframeAnimationOrderList.
begin(); it != m_keyframeAnimationOrderList.end(); ++it) { | |
318 RefPtr<KeyframeAnimation> keyframeAnimation = m_keyframeAnimations.get(*
it); | |
319 ASSERT(keyframeAnimation); | |
320 keyframeAnimation->getAnimatedStyle(resultStyle); | |
321 } | |
322 | |
323 return resultStyle; | |
324 } | |
325 | |
326 double CompositeAnimation::timeToNextService() const | |
327 { | |
328 // Returns the time at which next service is required. -1 means no service i
s required. 0 means | |
329 // service is required now, and > 0 means service is required that many seco
nds in the future. | |
330 double minT = -1; | |
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->value.get(); | |
336 double t = transition ? transition->timeToNextService() : -1; | |
337 if (t < minT || minT == -1) | |
338 minT = t; | |
339 if (minT == 0) | |
340 return 0; | |
341 } | |
342 } | |
343 if (!m_keyframeAnimations.isEmpty()) { | |
344 AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.en
d(); | |
345 for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin();
it != animationsEnd; ++it) { | |
346 KeyframeAnimation* animation = it->value.get(); | |
347 double t = animation ? animation->timeToNextService() : -1; | |
348 if (t < minT || minT == -1) | |
349 minT = t; | |
350 if (minT == 0) | |
351 return 0; | |
352 } | |
353 } | |
354 | |
355 return minT; | |
356 } | |
357 | |
358 double CompositeAnimation::timeToNextEvent() const | |
359 { | |
360 // Returns the time at which next service to trigger events is required. -1
means no service is required. 0 means | |
361 // service is required now, and > 0 means service is required that many seco
nds in the future. | |
362 double minT = -1; | |
363 | |
364 if (!m_transitions.isEmpty()) { | |
365 CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions
.end(); | |
366 for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(
); it != transitionsEnd; ++it) { | |
367 ImplicitAnimation* transition = it->value.get(); | |
368 double t = -1; | |
369 bool isLooping; | |
370 if (transition) | |
371 transition->getTimeToNextEvent(t, isLooping); | |
372 if (t < minT || minT == -1) | |
373 minT = t; | |
374 if (!minT) | |
375 return 0; | |
376 } | |
377 } | |
378 if (!m_keyframeAnimations.isEmpty()) { | |
379 AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.en
d(); | |
380 for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin();
it != animationsEnd; ++it) { | |
381 KeyframeAnimation* animation = it->value.get(); | |
382 double t = -1; | |
383 bool isLooping; | |
384 if (animation) | |
385 animation->getTimeToNextEvent(t, isLooping); | |
386 if (t < minT || minT == -1) | |
387 minT = t; | |
388 if (!minT) | |
389 return 0; | |
390 } | |
391 } | |
392 | |
393 return minT; | |
394 } | |
395 | |
396 PassRefPtr<KeyframeAnimation> CompositeAnimation::getAnimationForProperty(CSSPro
pertyID property) const | |
397 { | |
398 RefPtr<KeyframeAnimation> retval; | |
399 | |
400 // We want to send back the last animation with the property if there are mu
ltiples. | |
401 // So we need to iterate through all animations | |
402 if (!m_keyframeAnimations.isEmpty()) { | |
403 AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.en
d(); | |
404 for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin();
it != animationsEnd; ++it) { | |
405 RefPtr<KeyframeAnimation> anim = it->value; | |
406 if (anim->hasAnimationForProperty(property)) | |
407 retval = anim; | |
408 } | |
409 } | |
410 | |
411 return retval; | |
412 } | |
413 | |
414 void CompositeAnimation::overrideImplicitAnimations(CSSPropertyID property) | |
415 { | |
416 CSSPropertyTransitionsMap::const_iterator end = m_transitions.end(); | |
417 if (!m_transitions.isEmpty()) { | |
418 for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(
); it != end; ++it) { | |
419 ImplicitAnimation* anim = it->value.get(); | |
420 if (anim && anim->animatingProperty() == property) | |
421 anim->setOverridden(true); | |
422 } | |
423 } | |
424 } | |
425 | |
426 void CompositeAnimation::resumeOverriddenImplicitAnimations(CSSPropertyID proper
ty) | |
427 { | |
428 if (!m_transitions.isEmpty()) { | |
429 CSSPropertyTransitionsMap::const_iterator end = m_transitions.end(); | |
430 for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(
); it != end; ++it) { | |
431 ImplicitAnimation* anim = it->value.get(); | |
432 if (anim && anim->animatingProperty() == property) | |
433 anim->setOverridden(false); | |
434 } | |
435 } | |
436 } | |
437 | |
438 bool CompositeAnimation::isAnimatingProperty(CSSPropertyID property, bool accele
ratedOnly, bool isRunningNow) const | |
439 { | |
440 if (!m_keyframeAnimations.isEmpty()) { | |
441 AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.en
d(); | |
442 for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin();
it != animationsEnd; ++it) { | |
443 KeyframeAnimation* anim = it->value.get(); | |
444 if (anim && anim->isAnimatingProperty(property, acceleratedOnly, isR
unningNow)) | |
445 return true; | |
446 } | |
447 } | |
448 | |
449 if (!m_transitions.isEmpty()) { | |
450 CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions
.end(); | |
451 for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(
); it != transitionsEnd; ++it) { | |
452 ImplicitAnimation* anim = it->value.get(); | |
453 if (anim && anim->isAnimatingProperty(property, acceleratedOnly, isR
unningNow)) | |
454 return true; | |
455 } | |
456 } | |
457 return false; | |
458 } | |
459 | |
460 void CompositeAnimation::pauseAnimationsForTesting(double t) | |
461 { | |
462 AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end(); | |
463 for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it
!= animationsEnd; ++it) { | |
464 RefPtr<KeyframeAnimation> keyframeAnim = it->value; | |
465 if (!keyframeAnim || !keyframeAnim->running()) | |
466 continue; | |
467 | |
468 double count = keyframeAnim->m_animation->iterationCount(); | |
469 if ((t >= 0.0) && ((count == CSSAnimationData::IterationCountInfinite) |
| (t <= count * keyframeAnim->duration()))) | |
470 keyframeAnim->freezeAtTime(t); | |
471 } | |
472 | |
473 CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end
(); | |
474 for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); i
t != transitionsEnd; ++it) { | |
475 RefPtr<ImplicitAnimation> implAnim = it->value; | |
476 | |
477 if (!implAnim->running()) | |
478 continue; | |
479 | |
480 if ((t >= 0.0) && (t <= implAnim->duration())) | |
481 implAnim->freezeAtTime(t); | |
482 } | |
483 } | |
484 | |
485 unsigned CompositeAnimation::numberOfActiveAnimations() const | |
486 { | |
487 unsigned count = 0; | |
488 | |
489 if (!m_keyframeAnimations.isEmpty()) { | |
490 AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.en
d(); | |
491 for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin();
it != animationsEnd; ++it) { | |
492 KeyframeAnimation* anim = it->value.get(); | |
493 if (anim->running()) | |
494 ++count; | |
495 } | |
496 } | |
497 | |
498 if (!m_transitions.isEmpty()) { | |
499 CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions
.end(); | |
500 for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(
); it != transitionsEnd; ++it) { | |
501 ImplicitAnimation* anim = it->value.get(); | |
502 if (anim->running()) | |
503 ++count; | |
504 } | |
505 } | |
506 | |
507 return count; | |
508 } | |
509 | |
510 } // namespace WebCore | |
OLD | NEW |