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

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: Semilcelon 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 = 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
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
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
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