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