OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
184 } | 184 } |
185 | 185 |
186 } // namespace | 186 } // namespace |
187 | 187 |
188 CSSAnimations::CSSAnimations() | 188 CSSAnimations::CSSAnimations() |
189 { | 189 { |
190 } | 190 } |
191 | 191 |
192 bool CSSAnimations::isAnimationForInspector(const Animation& animation) | 192 bool CSSAnimations::isAnimationForInspector(const Animation& animation) |
193 { | 193 { |
194 for (const auto& it : m_animations) { | 194 for (const auto& runningAnimation : m_runningAnimations) { |
195 if (it.value->animation->sequenceNumber() == animation.sequenceNumber()) | 195 if (runningAnimation->animation->sequenceNumber() == animation.sequenceN
umber()) |
196 return true; | 196 return true; |
197 } | 197 } |
198 return false; | 198 return false; |
199 } | 199 } |
200 | 200 |
201 bool CSSAnimations::isTransitionAnimationForInspector(const Animation& animation
) const | 201 bool CSSAnimations::isTransitionAnimationForInspector(const Animation& animation
) const |
202 { | 202 { |
203 for (const auto& it : m_transitions) { | 203 for (const auto& it : m_transitions) { |
204 if (it.value.animation->sequenceNumber() == animation.sequenceNumber()) | 204 if (it.value.animation->sequenceNumber() == animation.sequenceNumber()) |
205 return true; | 205 return true; |
(...skipping 19 matching lines...) Expand all Loading... |
225 return; | 225 return; |
226 | 226 |
227 if (!animatingElement->layoutObject() || !animatingElement->layoutObject()->
style()) | 227 if (!animatingElement->layoutObject() || !animatingElement->layoutObject()->
style()) |
228 return; | 228 return; |
229 | 229 |
230 const ComputedStyle& oldStyle = *animatingElement->layoutObject()->style(); | 230 const ComputedStyle& oldStyle = *animatingElement->layoutObject()->style(); |
231 if (!oldStyle.shouldCompositeForCurrentAnimations()) | 231 if (!oldStyle.shouldCompositeForCurrentAnimations()) |
232 return; | 232 return; |
233 | 233 |
234 CSSAnimations& cssAnimations = elementAnimations->cssAnimations(); | 234 CSSAnimations& cssAnimations = elementAnimations->cssAnimations(); |
235 for (auto& runningAnimation : cssAnimations.m_animations.values()) { | 235 for (auto& runningAnimation : cssAnimations.m_runningAnimations) { |
236 Animation& animation = *runningAnimation->animation; | 236 Animation& animation = *runningAnimation->animation; |
237 if (animation.effect() && animation.effect()->isKeyframeEffect()) { | 237 if (animation.effect() && animation.effect()->isKeyframeEffect()) { |
238 EffectModel* model = toKeyframeEffect(animation.effect())->model(); | 238 EffectModel* model = toKeyframeEffect(animation.effect())->model(); |
239 if (model && model->isKeyframeEffectModel()) { | 239 if (model && model->isKeyframeEffectModel()) { |
240 KeyframeEffectModelBase* keyframeEffect = toKeyframeEffectModelB
ase(model); | 240 KeyframeEffectModelBase* keyframeEffect = toKeyframeEffectModelB
ase(model); |
241 if (keyframeEffect->hasSyntheticKeyframes() && keyframeEffect->s
napshotNeutralCompositorKeyframes(element, oldStyle, style)) | 241 if (keyframeEffect->hasSyntheticKeyframes() && keyframeEffect->s
napshotNeutralCompositorKeyframes(element, oldStyle, style)) |
242 update.updateCompositorKeyframes(&animation); | 242 update.updateCompositorKeyframes(&animation); |
243 } | 243 } |
244 } | 244 } |
245 } | 245 } |
(...skipping 23 matching lines...) Expand all Loading... |
269 // If we're in an animation style change, no animations can have started, be
en cancelled or changed play state. | 269 // If we're in an animation style change, no animations can have started, be
en cancelled or changed play state. |
270 // When ASSERT is enabled, we verify this optimization. | 270 // When ASSERT is enabled, we verify this optimization. |
271 if (isAnimationStyleChange) | 271 if (isAnimationStyleChange) |
272 return; | 272 return; |
273 #endif | 273 #endif |
274 | 274 |
275 const CSSAnimationData* animationData = style.animations(); | 275 const CSSAnimationData* animationData = style.animations(); |
276 const CSSAnimations* cssAnimations = elementAnimations ? &elementAnimations-
>cssAnimations() : nullptr; | 276 const CSSAnimations* cssAnimations = elementAnimations ? &elementAnimations-
>cssAnimations() : nullptr; |
277 const Element* elementForScoping = animatingElement ? animatingElement : &el
ement; | 277 const Element* elementForScoping = animatingElement ? animatingElement : &el
ement; |
278 | 278 |
279 HashSet<AtomicString> inactive; | 279 Vector<bool> cancelRunningAnimationFlags(cssAnimations ? cssAnimations->m_ru
nningAnimations.size() : 0); |
280 if (cssAnimations) { | 280 for (bool& flag : cancelRunningAnimationFlags) |
281 for (const auto& entry : cssAnimations->m_animations) | 281 flag = true; |
282 inactive.add(entry.key); | |
283 } | |
284 | 282 |
285 if (style.display() != NONE) { | 283 if (animationData && style.display() != NONE) { |
286 for (size_t i = 0; animationData && i < animationData->nameList().size()
; ++i) { | 284 const Vector<AtomicString>& nameList = animationData->nameList(); |
287 AtomicString animationName(animationData->nameList()[i]); | 285 for (size_t i = 0; i < nameList.size(); ++i) { |
288 if (animationName == CSSAnimationData::initialName()) | 286 AtomicString name = nameList[i]; |
| 287 if (name == CSSAnimationData::initialName()) |
289 continue; | 288 continue; |
290 | 289 |
| 290 // Find n where this is the nth occurence of this animation name. |
| 291 size_t nameIndex = 0; |
| 292 for (size_t j = 0; j < i; j++) { |
| 293 if (nameList[j] == name) |
| 294 nameIndex++; |
| 295 } |
| 296 |
291 const bool isPaused = CSSTimingData::getRepeated(animationData->play
StateList(), i) == AnimPlayStatePaused; | 297 const bool isPaused = CSSTimingData::getRepeated(animationData->play
StateList(), i) == AnimPlayStatePaused; |
292 | 298 |
293 Timing timing = animationData->convertToTiming(i); | 299 Timing timing = animationData->convertToTiming(i); |
294 Timing specifiedTiming = timing; | 300 Timing specifiedTiming = timing; |
295 RefPtr<TimingFunction> keyframeTimingFunction = timing.timingFunctio
n; | 301 RefPtr<TimingFunction> keyframeTimingFunction = timing.timingFunctio
n; |
296 timing.timingFunction = Timing::defaults().timingFunction; | 302 timing.timingFunction = Timing::defaults().timingFunction; |
297 | 303 |
298 RefPtrWillBeRawPtr<StyleRuleKeyframes> keyframesRule = resolver->fin
dKeyframesRule(elementForScoping, animationName); | 304 RefPtrWillBeRawPtr<StyleRuleKeyframes> keyframesRule = resolver->fin
dKeyframesRule(elementForScoping, name); |
299 if (!keyframesRule) | 305 if (!keyframesRule) |
300 continue; // Cancel the animation if there's no style rule for i
t. | 306 continue; // Cancel the animation if there's no style rule for i
t. |
301 | 307 |
| 308 const RunningAnimation* existingAnimation = nullptr; |
| 309 size_t existingAnimationIndex = 0; |
| 310 |
302 if (cssAnimations) { | 311 if (cssAnimations) { |
303 AnimationMap::const_iterator existing(cssAnimations->m_animation
s.find(animationName)); | 312 for (size_t i = 0; i < cssAnimations->m_runningAnimations.size()
; i++) { |
304 if (existing != cssAnimations->m_animations.end()) { | 313 const RunningAnimation& runningAnimation = *cssAnimations->m
_runningAnimations[i]; |
305 inactive.remove(animationName); | 314 if (runningAnimation.name == name && runningAnimation.nameIn
dex == nameIndex) { |
306 | 315 existingAnimation = &runningAnimation; |
307 const RunningAnimation* runningAnimation = existing->value.g
et(); | 316 existingAnimationIndex = i; |
308 Animation* animation = runningAnimation->animation.get(); | 317 break; |
309 | |
310 if (keyframesRule != runningAnimation->styleRule || keyframe
sRule->version() != runningAnimation->styleRuleVersion || runningAnimation->spec
ifiedTiming != specifiedTiming) { | |
311 ASSERT(!isAnimationStyleChange); | |
312 update.updateAnimation(animationName, animation, InertEf
fect::create( | |
313 createKeyframeEffectModel(resolver, animatingElement
, element, &style, parentStyle, animationName, keyframeTimingFunction.get(), i), | |
314 timing, isPaused, animation->unlimitedCurrentTimeInt
ernal()), specifiedTiming, keyframesRule); | |
315 } | 318 } |
316 | |
317 if (isPaused != animation->paused()) { | |
318 ASSERT(!isAnimationStyleChange); | |
319 update.toggleAnimationPaused(animationName); | |
320 } | |
321 | |
322 continue; | |
323 } | 319 } |
324 } | 320 } |
325 | 321 |
326 ASSERT(!isAnimationStyleChange); | 322 if (existingAnimation) { |
327 update.startAnimation(animationName, InertEffect::create( | 323 cancelRunningAnimationFlags[existingAnimationIndex] = false; |
328 createKeyframeEffectModel(resolver, animatingElement, element, &
style, parentStyle, animationName, keyframeTimingFunction.get(), i), | 324 |
329 timing, isPaused, 0), specifiedTiming, keyframesRule); | 325 Animation* animation = existingAnimation->animation.get(); |
| 326 |
| 327 if (keyframesRule != existingAnimation->styleRule || keyframesRu
le->version() != existingAnimation->styleRuleVersion || existingAnimation->speci
fiedTiming != specifiedTiming) { |
| 328 ASSERT(!isAnimationStyleChange); |
| 329 update.updateAnimation(existingAnimationIndex, animation, In
ertEffect::create( |
| 330 createKeyframeEffectModel(resolver, animatingElement, el
ement, &style, parentStyle, name, keyframeTimingFunction.get(), i), |
| 331 timing, isPaused, animation->unlimitedCurrentTimeInterna
l()), specifiedTiming, keyframesRule); |
| 332 } |
| 333 |
| 334 if (isPaused != animation->paused()) { |
| 335 ASSERT(!isAnimationStyleChange); |
| 336 update.toggleAnimationIndexPaused(existingAnimationIndex); |
| 337 } |
| 338 } else { |
| 339 ASSERT(!isAnimationStyleChange); |
| 340 update.startAnimation(name, nameIndex, InertEffect::create( |
| 341 createKeyframeEffectModel(resolver, animatingElement, elemen
t, &style, parentStyle, name, keyframeTimingFunction.get(), i), |
| 342 timing, isPaused, 0), specifiedTiming, keyframesRule); |
| 343 } |
330 } | 344 } |
331 } | 345 } |
332 | 346 |
333 ASSERT(inactive.isEmpty() || cssAnimations); | 347 for (size_t i = 0; i < cancelRunningAnimationFlags.size(); i++) { |
334 for (const AtomicString& animationName : inactive) { | 348 if (cancelRunningAnimationFlags[i]) { |
335 ASSERT(!isAnimationStyleChange); | 349 ASSERT(cssAnimations && !isAnimationStyleChange); |
336 update.cancelAnimation(animationName, *cssAnimations->m_animations.get(a
nimationName)->animation); | 350 update.cancelAnimation(i, *cssAnimations->m_runningAnimations[i]->an
imation); |
| 351 } |
337 } | 352 } |
338 } | 353 } |
339 | 354 |
340 void CSSAnimations::maybeApplyPendingUpdate(Element* element) | 355 void CSSAnimations::maybeApplyPendingUpdate(Element* element) |
341 { | 356 { |
342 m_previousActiveInterpolationsForAnimations.clear(); | 357 m_previousActiveInterpolationsForAnimations.clear(); |
343 if (m_pendingUpdate.isEmpty()) | 358 if (m_pendingUpdate.isEmpty()) |
344 return; | 359 return; |
345 | 360 |
346 m_previousActiveInterpolationsForAnimations.swap(m_pendingUpdate.activeInter
polationsForAnimations()); | 361 m_previousActiveInterpolationsForAnimations.swap(m_pendingUpdate.activeInter
polationsForAnimations()); |
347 | 362 |
348 // FIXME: cancelling, pausing, unpausing animations all query compositingSta
te, which is not necessarily up to date here | 363 // FIXME: cancelling, pausing, unpausing animations all query compositingSta
te, which is not necessarily up to date here |
349 // since we call this from recalc style. | 364 // since we call this from recalc style. |
350 // https://code.google.com/p/chromium/issues/detail?id=339847 | 365 // https://code.google.com/p/chromium/issues/detail?id=339847 |
351 DisableCompositingQueryAsserts disabler; | 366 DisableCompositingQueryAsserts disabler; |
352 | 367 |
353 for (const AtomicString& animationName : m_pendingUpdate.cancelledAnimationN
ames()) { | 368 const Vector<size_t>& cancelledIndices = m_pendingUpdate.cancelledAnimationI
ndices(); |
354 Animation* animation = m_animations.take(animationName)->animation; | 369 for (size_t i = cancelledIndices.size(); i-- > 0;) { |
355 animation->cancel(); | 370 ASSERT(i == cancelledIndices.size() - 1 || cancelledIndices[i] < cancell
edIndices[i + 1]); |
356 animation->update(TimingUpdateOnDemand); | 371 Animation& animation = *m_runningAnimations[cancelledIndices[i]]->animat
ion; |
| 372 animation.cancel(); |
| 373 animation.update(TimingUpdateOnDemand); |
| 374 m_runningAnimations.remove(cancelledIndices[i]); |
357 } | 375 } |
358 | 376 |
359 for (const AtomicString& animationName : m_pendingUpdate.animationsWithPause
Toggled()) { | 377 for (size_t pausedIndex : m_pendingUpdate.animationIndicesWithPauseToggled()
) { |
360 Animation* animation = m_animations.get(animationName)->animation.get(); | 378 Animation& animation = *m_runningAnimations[pausedIndex]->animation; |
361 if (animation->paused()) | 379 if (animation.paused()) |
362 animation->unpause(); | 380 animation.unpause(); |
363 else | 381 else |
364 animation->pause(); | 382 animation.pause(); |
365 if (animation->outdated()) | 383 if (animation.outdated()) |
366 animation->update(TimingUpdateOnDemand); | 384 animation.update(TimingUpdateOnDemand); |
367 } | 385 } |
368 | 386 |
369 for (const auto& animation : m_pendingUpdate.updatedCompositorKeyframes()) | 387 for (const auto& animation : m_pendingUpdate.updatedCompositorKeyframes()) |
370 animation->setCompositorPending(true); | 388 animation->setCompositorPending(true); |
371 | 389 |
372 for (const auto& entry : m_pendingUpdate.animationsWithUpdates()) { | 390 for (const auto& entry : m_pendingUpdate.animationsWithUpdates()) { |
373 KeyframeEffect* effect = toKeyframeEffect(entry.animation->effect()); | 391 KeyframeEffect* effect = toKeyframeEffect(entry.animation->effect()); |
374 | 392 |
375 effect->setModel(entry.effect->model()); | 393 effect->setModel(entry.effect->model()); |
376 effect->updateSpecifiedTiming(entry.effect->specifiedTiming()); | 394 effect->updateSpecifiedTiming(entry.effect->specifiedTiming()); |
377 | 395 |
378 m_animations.find(entry.name)->value->update(entry); | 396 m_runningAnimations[entry.index]->update(entry); |
379 } | 397 } |
380 | 398 |
381 for (const auto& entry : m_pendingUpdate.newAnimations()) { | 399 for (const auto& entry : m_pendingUpdate.newAnimations()) { |
382 const InertEffect* inertAnimation = entry.effect.get(); | 400 const InertEffect* inertAnimation = entry.effect.get(); |
383 AnimationEventDelegate* eventDelegate = new AnimationEventDelegate(eleme
nt, entry.name); | 401 AnimationEventDelegate* eventDelegate = new AnimationEventDelegate(eleme
nt, entry.name); |
384 KeyframeEffect* effect = KeyframeEffect::create(element, inertAnimation-
>model(), inertAnimation->specifiedTiming(), KeyframeEffect::DefaultPriority, ev
entDelegate); | 402 KeyframeEffect* effect = KeyframeEffect::create(element, inertAnimation-
>model(), inertAnimation->specifiedTiming(), KeyframeEffect::DefaultPriority, ev
entDelegate); |
385 effect->setName(inertAnimation->name()); | 403 effect->setName(inertAnimation->name()); |
386 Animation* animation = element->document().timeline().play(effect); | 404 Animation* animation = element->document().timeline().play(effect); |
387 if (inertAnimation->paused()) | 405 if (inertAnimation->paused()) |
388 animation->pause(); | 406 animation->pause(); |
389 animation->update(TimingUpdateOnDemand); | 407 animation->update(TimingUpdateOnDemand); |
390 | 408 |
391 m_animations.set(entry.name, new RunningAnimation(animation, entry)); | 409 m_runningAnimations.append(new RunningAnimation(animation, entry)); |
392 } | 410 } |
393 | 411 |
394 // Transitions that are run on the compositor only update main-thread state | 412 // Transitions that are run on the compositor only update main-thread state |
395 // lazily. However, we need the new state to know what the from state shoud | 413 // lazily. However, we need the new state to know what the from state shoud |
396 // be when transitions are retargeted. Instead of triggering complete style | 414 // be when transitions are retargeted. Instead of triggering complete style |
397 // recalculation, we find these cases by searching for new transitions that | 415 // recalculation, we find these cases by searching for new transitions that |
398 // have matching cancelled animation property IDs on the compositor. | 416 // have matching cancelled animation property IDs on the compositor. |
399 HeapHashMap<CSSPropertyID, std::pair<Member<KeyframeEffect>, double>> retarg
etedCompositorTransitions; | 417 HeapHashMap<CSSPropertyID, std::pair<Member<KeyframeEffect>, double>> retarg
etedCompositorTransitions; |
400 for (CSSPropertyID id : m_pendingUpdate.cancelledTransitions()) { | 418 for (CSSPropertyID id : m_pendingUpdate.cancelledTransitions()) { |
401 ASSERT(m_transitions.contains(id)); | 419 ASSERT(m_transitions.contains(id)); |
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
606 update.cancelTransition(id); | 624 update.cancelTransition(id); |
607 } else if (entry.value.animation->finishedInternal()) { | 625 } else if (entry.value.animation->finishedInternal()) { |
608 update.finishTransition(id); | 626 update.finishTransition(id); |
609 } | 627 } |
610 } | 628 } |
611 } | 629 } |
612 } | 630 } |
613 | 631 |
614 void CSSAnimations::cancel() | 632 void CSSAnimations::cancel() |
615 { | 633 { |
616 for (const auto& entry : m_animations) { | 634 for (const auto& runningAnimation : m_runningAnimations) { |
617 entry.value->animation->cancel(); | 635 runningAnimation->animation->cancel(); |
618 entry.value->animation->update(TimingUpdateOnDemand); | 636 runningAnimation->animation->update(TimingUpdateOnDemand); |
619 } | 637 } |
620 | 638 |
621 for (const auto& entry : m_transitions) { | 639 for (const auto& entry : m_transitions) { |
622 entry.value.animation->cancel(); | 640 entry.value.animation->cancel(); |
623 entry.value.animation->update(TimingUpdateOnDemand); | 641 entry.value.animation->update(TimingUpdateOnDemand); |
624 } | 642 } |
625 | 643 |
626 m_animations.clear(); | 644 m_runningAnimations.clear(); |
627 m_transitions.clear(); | 645 m_transitions.clear(); |
628 clearPendingUpdate(); | 646 clearPendingUpdate(); |
629 } | 647 } |
630 | 648 |
631 void CSSAnimations::calculateAnimationActiveInterpolations(CSSAnimationUpdate& u
pdate, const Element* animatingElement, double timelineCurrentTime) | 649 void CSSAnimations::calculateAnimationActiveInterpolations(CSSAnimationUpdate& u
pdate, const Element* animatingElement, double timelineCurrentTime) |
632 { | 650 { |
633 ElementAnimations* elementAnimations = animatingElement ? animatingElement->
elementAnimations() : nullptr; | 651 ElementAnimations* elementAnimations = animatingElement ? animatingElement->
elementAnimations() : nullptr; |
634 AnimationStack* animationStack = elementAnimations ? &elementAnimations->def
aultStack() : nullptr; | 652 AnimationStack* animationStack = elementAnimations ? &elementAnimations->def
aultStack() : nullptr; |
635 | 653 |
636 if (update.newAnimations().isEmpty() && update.suppressedAnimations().isEmpt
y()) { | 654 if (update.newAnimations().isEmpty() && update.suppressedAnimations().isEmpt
y()) { |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
811 return false; | 829 return false; |
812 default: | 830 default: |
813 return true; | 831 return true; |
814 } | 832 } |
815 } | 833 } |
816 | 834 |
817 DEFINE_TRACE(CSSAnimations) | 835 DEFINE_TRACE(CSSAnimations) |
818 { | 836 { |
819 visitor->trace(m_transitions); | 837 visitor->trace(m_transitions); |
820 visitor->trace(m_pendingUpdate); | 838 visitor->trace(m_pendingUpdate); |
821 visitor->trace(m_animations); | 839 visitor->trace(m_runningAnimations); |
822 } | 840 } |
823 | 841 |
824 } // namespace blink | 842 } // namespace blink |
OLD | NEW |