Chromium Code Reviews| 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 = i; j > 0;) | |
| 293 nameIndex += (nameList[--j] == name); | |
|
dstockwell
2015/10/16 01:51:37
This code is a bit...smelly.
for (...)
if (...)
alancutter (OOO until 2018)
2015/10/16 01:56:19
Much better, done.
| |
| 294 | |
| 291 const bool isPaused = CSSTimingData::getRepeated(animationData->play StateList(), i) == AnimPlayStatePaused; | 295 const bool isPaused = CSSTimingData::getRepeated(animationData->play StateList(), i) == AnimPlayStatePaused; |
| 292 | 296 |
| 293 Timing timing = animationData->convertToTiming(i); | 297 Timing timing = animationData->convertToTiming(i); |
| 294 Timing specifiedTiming = timing; | 298 Timing specifiedTiming = timing; |
| 295 RefPtr<TimingFunction> keyframeTimingFunction = timing.timingFunctio n; | 299 RefPtr<TimingFunction> keyframeTimingFunction = timing.timingFunctio n; |
| 296 timing.timingFunction = Timing::defaults().timingFunction; | 300 timing.timingFunction = Timing::defaults().timingFunction; |
| 297 | 301 |
| 298 RefPtrWillBeRawPtr<StyleRuleKeyframes> keyframesRule = resolver->fin dKeyframesRule(elementForScoping, animationName); | 302 RefPtrWillBeRawPtr<StyleRuleKeyframes> keyframesRule = resolver->fin dKeyframesRule(elementForScoping, name); |
| 299 if (!keyframesRule) | 303 if (!keyframesRule) |
| 300 continue; // Cancel the animation if there's no style rule for i t. | 304 continue; // Cancel the animation if there's no style rule for i t. |
| 301 | 305 |
| 306 const RunningAnimation* existingAnimation = nullptr; | |
| 307 size_t existingAnimationIndex = 0; | |
| 308 | |
| 302 if (cssAnimations) { | 309 if (cssAnimations) { |
| 303 AnimationMap::const_iterator existing(cssAnimations->m_animation s.find(animationName)); | 310 for (size_t i = 0; i < cssAnimations->m_runningAnimations.size() ; i++) { |
| 304 if (existing != cssAnimations->m_animations.end()) { | 311 const RunningAnimation& runningAnimation = *cssAnimations->m _runningAnimations[i]; |
| 305 inactive.remove(animationName); | 312 if (runningAnimation.name == name && runningAnimation.nameIn dex == nameIndex) { |
| 306 | 313 existingAnimation = &runningAnimation; |
| 307 const RunningAnimation* runningAnimation = existing->value.g et(); | 314 existingAnimationIndex = i; |
| 308 Animation* animation = runningAnimation->animation.get(); | 315 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 } | 316 } |
| 316 | |
| 317 if (isPaused != animation->paused()) { | |
| 318 ASSERT(!isAnimationStyleChange); | |
| 319 update.toggleAnimationPaused(animationName); | |
| 320 } | |
| 321 | |
| 322 continue; | |
| 323 } | 317 } |
| 324 } | 318 } |
| 325 | 319 |
| 326 ASSERT(!isAnimationStyleChange); | 320 if (existingAnimation) { |
| 327 update.startAnimation(animationName, InertEffect::create( | 321 cancelRunningAnimationFlags[existingAnimationIndex] = false; |
| 328 createKeyframeEffectModel(resolver, animatingElement, element, & style, parentStyle, animationName, keyframeTimingFunction.get(), i), | 322 |
| 329 timing, isPaused, 0), specifiedTiming, keyframesRule); | 323 Animation* animation = existingAnimation->animation.get(); |
| 324 | |
| 325 if (keyframesRule != existingAnimation->styleRule || keyframesRu le->version() != existingAnimation->styleRuleVersion || existingAnimation->speci fiedTiming != specifiedTiming) { | |
| 326 ASSERT(!isAnimationStyleChange); | |
| 327 update.updateAnimation(existingAnimationIndex, animation, In ertEffect::create( | |
| 328 createKeyframeEffectModel(resolver, animatingElement, el ement, &style, parentStyle, name, keyframeTimingFunction.get(), i), | |
| 329 timing, isPaused, animation->unlimitedCurrentTimeInterna l()), specifiedTiming, keyframesRule); | |
| 330 } | |
| 331 | |
| 332 if (isPaused != animation->paused()) { | |
| 333 ASSERT(!isAnimationStyleChange); | |
| 334 update.toggleAnimationIndexPaused(existingAnimationIndex); | |
| 335 } | |
| 336 } else { | |
| 337 ASSERT(!isAnimationStyleChange); | |
| 338 update.startAnimation(name, nameIndex, InertEffect::create( | |
| 339 createKeyframeEffectModel(resolver, animatingElement, elemen t, &style, parentStyle, name, keyframeTimingFunction.get(), i), | |
| 340 timing, isPaused, 0), specifiedTiming, keyframesRule); | |
| 341 } | |
| 330 } | 342 } |
| 331 } | 343 } |
| 332 | 344 |
| 333 ASSERT(inactive.isEmpty() || cssAnimations); | 345 for (size_t i = 0; i < cancelRunningAnimationFlags.size(); i++) { |
| 334 for (const AtomicString& animationName : inactive) { | 346 if (cancelRunningAnimationFlags[i]) { |
| 335 ASSERT(!isAnimationStyleChange); | 347 ASSERT(cssAnimations && !isAnimationStyleChange); |
| 336 update.cancelAnimation(animationName, *cssAnimations->m_animations.get(a nimationName)->animation); | 348 update.cancelAnimation(i, *cssAnimations->m_runningAnimations[i]->an imation); |
| 349 } | |
| 337 } | 350 } |
| 338 } | 351 } |
| 339 | 352 |
| 340 void CSSAnimations::maybeApplyPendingUpdate(Element* element) | 353 void CSSAnimations::maybeApplyPendingUpdate(Element* element) |
| 341 { | 354 { |
| 342 m_previousActiveInterpolationsForAnimations.clear(); | 355 m_previousActiveInterpolationsForAnimations.clear(); |
| 343 if (m_pendingUpdate.isEmpty()) | 356 if (m_pendingUpdate.isEmpty()) |
| 344 return; | 357 return; |
| 345 | 358 |
| 346 m_previousActiveInterpolationsForAnimations.swap(m_pendingUpdate.activeInter polationsForAnimations()); | 359 m_previousActiveInterpolationsForAnimations.swap(m_pendingUpdate.activeInter polationsForAnimations()); |
| 347 | 360 |
| 348 // FIXME: cancelling, pausing, unpausing animations all query compositingSta te, which is not necessarily up to date here | 361 // 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. | 362 // since we call this from recalc style. |
| 350 // https://code.google.com/p/chromium/issues/detail?id=339847 | 363 // https://code.google.com/p/chromium/issues/detail?id=339847 |
| 351 DisableCompositingQueryAsserts disabler; | 364 DisableCompositingQueryAsserts disabler; |
| 352 | 365 |
| 353 for (const AtomicString& animationName : m_pendingUpdate.cancelledAnimationN ames()) { | 366 const Vector<size_t>& cancelledIndices = m_pendingUpdate.cancelledAnimationI ndices(); |
| 354 Animation* animation = m_animations.take(animationName)->animation; | 367 for (size_t i = cancelledIndices.size(); i-- > 0;) { |
| 355 animation->cancel(); | 368 ASSERT(i == cancelledIndices.size() - 1 || cancelledIndices[i] < cancell edIndices[i + 1]); |
| 356 animation->update(TimingUpdateOnDemand); | 369 Animation& animation = *m_runningAnimations[cancelledIndices[i]]->animat ion; |
| 370 animation.cancel(); | |
| 371 animation.update(TimingUpdateOnDemand); | |
| 372 m_runningAnimations.remove(cancelledIndices[i]); | |
| 357 } | 373 } |
| 358 | 374 |
| 359 for (const AtomicString& animationName : m_pendingUpdate.animationsWithPause Toggled()) { | 375 for (size_t pausedIndex : m_pendingUpdate.animationIndicesWithPauseToggled() ) { |
| 360 Animation* animation = m_animations.get(animationName)->animation.get(); | 376 Animation& animation = *m_runningAnimations[pausedIndex]->animation; |
| 361 if (animation->paused()) | 377 if (animation.paused()) |
| 362 animation->unpause(); | 378 animation.unpause(); |
| 363 else | 379 else |
| 364 animation->pause(); | 380 animation.pause(); |
| 365 if (animation->outdated()) | 381 if (animation.outdated()) |
| 366 animation->update(TimingUpdateOnDemand); | 382 animation.update(TimingUpdateOnDemand); |
| 367 } | 383 } |
| 368 | 384 |
| 369 for (const auto& animation : m_pendingUpdate.updatedCompositorKeyframes()) | 385 for (const auto& animation : m_pendingUpdate.updatedCompositorKeyframes()) |
| 370 animation->setCompositorPending(true); | 386 animation->setCompositorPending(true); |
| 371 | 387 |
| 372 for (const auto& entry : m_pendingUpdate.animationsWithUpdates()) { | 388 for (const auto& entry : m_pendingUpdate.animationsWithUpdates()) { |
| 373 KeyframeEffect* effect = toKeyframeEffect(entry.animation->effect()); | 389 KeyframeEffect* effect = toKeyframeEffect(entry.animation->effect()); |
| 374 | 390 |
| 375 effect->setModel(entry.effect->model()); | 391 effect->setModel(entry.effect->model()); |
| 376 effect->updateSpecifiedTiming(entry.effect->specifiedTiming()); | 392 effect->updateSpecifiedTiming(entry.effect->specifiedTiming()); |
| 377 | 393 |
| 378 m_animations.find(entry.name)->value->update(entry); | 394 m_runningAnimations[entry.index]->update(entry); |
| 379 } | 395 } |
| 380 | 396 |
| 381 for (const auto& entry : m_pendingUpdate.newAnimations()) { | 397 for (const auto& entry : m_pendingUpdate.newAnimations()) { |
| 382 const InertEffect* inertAnimation = entry.effect.get(); | 398 const InertEffect* inertAnimation = entry.effect.get(); |
| 383 AnimationEventDelegate* eventDelegate = new AnimationEventDelegate(eleme nt, entry.name); | 399 AnimationEventDelegate* eventDelegate = new AnimationEventDelegate(eleme nt, entry.name); |
| 384 KeyframeEffect* effect = KeyframeEffect::create(element, inertAnimation- >model(), inertAnimation->specifiedTiming(), KeyframeEffect::DefaultPriority, ev entDelegate); | 400 KeyframeEffect* effect = KeyframeEffect::create(element, inertAnimation- >model(), inertAnimation->specifiedTiming(), KeyframeEffect::DefaultPriority, ev entDelegate); |
| 385 effect->setName(inertAnimation->name()); | 401 effect->setName(inertAnimation->name()); |
| 386 Animation* animation = element->document().timeline().play(effect); | 402 Animation* animation = element->document().timeline().play(effect); |
| 387 if (inertAnimation->paused()) | 403 if (inertAnimation->paused()) |
| 388 animation->pause(); | 404 animation->pause(); |
| 389 animation->update(TimingUpdateOnDemand); | 405 animation->update(TimingUpdateOnDemand); |
| 390 | 406 |
| 391 m_animations.set(entry.name, new RunningAnimation(animation, entry)); | 407 m_runningAnimations.append(new RunningAnimation(animation, entry)); |
| 392 } | 408 } |
| 393 | 409 |
| 394 // Transitions that are run on the compositor only update main-thread state | 410 // 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 | 411 // 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 | 412 // be when transitions are retargeted. Instead of triggering complete style |
| 397 // recalculation, we find these cases by searching for new transitions that | 413 // recalculation, we find these cases by searching for new transitions that |
| 398 // have matching cancelled animation property IDs on the compositor. | 414 // have matching cancelled animation property IDs on the compositor. |
| 399 HeapHashMap<CSSPropertyID, std::pair<Member<KeyframeEffect>, double>> retarg etedCompositorTransitions; | 415 HeapHashMap<CSSPropertyID, std::pair<Member<KeyframeEffect>, double>> retarg etedCompositorTransitions; |
| 400 for (CSSPropertyID id : m_pendingUpdate.cancelledTransitions()) { | 416 for (CSSPropertyID id : m_pendingUpdate.cancelledTransitions()) { |
| 401 ASSERT(m_transitions.contains(id)); | 417 ASSERT(m_transitions.contains(id)); |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 606 update.cancelTransition(id); | 622 update.cancelTransition(id); |
| 607 } else if (entry.value.animation->finishedInternal()) { | 623 } else if (entry.value.animation->finishedInternal()) { |
| 608 update.finishTransition(id); | 624 update.finishTransition(id); |
| 609 } | 625 } |
| 610 } | 626 } |
| 611 } | 627 } |
| 612 } | 628 } |
| 613 | 629 |
| 614 void CSSAnimations::cancel() | 630 void CSSAnimations::cancel() |
| 615 { | 631 { |
| 616 for (const auto& entry : m_animations) { | 632 for (const auto& runningAnimation : m_runningAnimations) { |
| 617 entry.value->animation->cancel(); | 633 runningAnimation->animation->cancel(); |
| 618 entry.value->animation->update(TimingUpdateOnDemand); | 634 runningAnimation->animation->update(TimingUpdateOnDemand); |
| 619 } | 635 } |
| 620 | 636 |
| 621 for (const auto& entry : m_transitions) { | 637 for (const auto& entry : m_transitions) { |
| 622 entry.value.animation->cancel(); | 638 entry.value.animation->cancel(); |
| 623 entry.value.animation->update(TimingUpdateOnDemand); | 639 entry.value.animation->update(TimingUpdateOnDemand); |
| 624 } | 640 } |
| 625 | 641 |
| 626 m_animations.clear(); | 642 m_runningAnimations.clear(); |
| 627 m_transitions.clear(); | 643 m_transitions.clear(); |
| 628 clearPendingUpdate(); | 644 clearPendingUpdate(); |
| 629 } | 645 } |
| 630 | 646 |
| 631 void CSSAnimations::calculateAnimationActiveInterpolations(CSSAnimationUpdate& u pdate, const Element* animatingElement, double timelineCurrentTime) | 647 void CSSAnimations::calculateAnimationActiveInterpolations(CSSAnimationUpdate& u pdate, const Element* animatingElement, double timelineCurrentTime) |
| 632 { | 648 { |
| 633 ElementAnimations* elementAnimations = animatingElement ? animatingElement-> elementAnimations() : nullptr; | 649 ElementAnimations* elementAnimations = animatingElement ? animatingElement-> elementAnimations() : nullptr; |
| 634 AnimationStack* animationStack = elementAnimations ? &elementAnimations->def aultStack() : nullptr; | 650 AnimationStack* animationStack = elementAnimations ? &elementAnimations->def aultStack() : nullptr; |
| 635 | 651 |
| 636 if (update.newAnimations().isEmpty() && update.suppressedAnimations().isEmpt y()) { | 652 if (update.newAnimations().isEmpty() && update.suppressedAnimations().isEmpt y()) { |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 811 return false; | 827 return false; |
| 812 default: | 828 default: |
| 813 return true; | 829 return true; |
| 814 } | 830 } |
| 815 } | 831 } |
| 816 | 832 |
| 817 DEFINE_TRACE(CSSAnimations) | 833 DEFINE_TRACE(CSSAnimations) |
| 818 { | 834 { |
| 819 visitor->trace(m_transitions); | 835 visitor->trace(m_transitions); |
| 820 visitor->trace(m_pendingUpdate); | 836 visitor->trace(m_pendingUpdate); |
| 821 visitor->trace(m_animations); | 837 visitor->trace(m_runningAnimations); |
| 822 } | 838 } |
| 823 | 839 |
| 824 } // namespace blink | 840 } // namespace blink |
| OLD | NEW |