Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(301)

Side by Side Diff: third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp

Issue 1402143004: Preserve running CSS Animations across changes to animation styles according to same name index (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Added test Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/WebKit/Source/core/animation/css/CSSAnimations.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/animation/css/CSSAnimations.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698