1 /* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsAnimationManager.h"
7 #include "nsTransitionManager.h"
9 #include "mozilla/EventDispatcher.h"
10 #include "mozilla/MemoryReporting.h"
11 #include "mozilla/StyleAnimationValue.h"
13 #include "nsPresContext.h"
14 #include "nsStyleSet.h"
15 #include "nsStyleChangeList.h"
16 #include "nsCSSRules.h"
17 #include "RestyleManager.h"
18 #include "nsLayoutUtils.h"
20 #include "nsIDocument.h"
23 using namespace mozilla
;
24 using namespace mozilla::css
;
25 using mozilla::dom::Animation
;
26 using mozilla::dom::AnimationPlayer
;
27 using mozilla::CSSAnimationPlayer
;
29 mozilla::dom::Promise
*
30 CSSAnimationPlayer::GetReady(ErrorResult
& aRv
)
33 return AnimationPlayer::GetReady(aRv
);
37 CSSAnimationPlayer::Play()
39 mPauseShouldStick
= false;
40 AnimationPlayer::Play();
44 CSSAnimationPlayer::Pause()
46 mPauseShouldStick
= true;
47 AnimationPlayer::Pause();
50 mozilla::dom::AnimationPlayState
51 CSSAnimationPlayer::PlayStateFromJS() const
53 // Flush style to ensure that any properties controlling animation state
54 // (e.g. animation-play-state) are fully updated.
56 return AnimationPlayer::PlayStateFromJS();
60 CSSAnimationPlayer::PlayFromJS()
62 // Note that flushing style below might trigger calls to
63 // PlayFromStyle()/PauseFromStyle() on this object.
65 AnimationPlayer::PlayFromJS();
69 CSSAnimationPlayer::PlayFromStyle()
71 mIsStylePaused
= false;
72 if (!mPauseShouldStick
) {
78 CSSAnimationPlayer::PauseFromStyle()
80 // Check if the pause state is being overridden
85 mIsStylePaused
= true;
90 CSSAnimationPlayer::QueueEvents(EventArray
& aEventsToDispatch
)
96 ComputedTiming computedTiming
= mSource
->GetComputedTiming();
99 nsCSSPseudoElements::Type targetPseudoType
;
100 mSource
->GetTarget(target
, targetPseudoType
);
102 switch (computedTiming
.mPhase
) {
103 case ComputedTiming::AnimationPhase_Null
:
104 case ComputedTiming::AnimationPhase_Before
:
108 case ComputedTiming::AnimationPhase_Active
:
109 // Dispatch 'animationstart' or 'animationiteration' when needed.
110 if (computedTiming
.mCurrentIteration
!= mLastNotification
) {
111 // Notify 'animationstart' even if a negative delay puts us
112 // past the first iteration.
113 // Note that when somebody changes the animation-duration
114 // dynamically, this will fire an extra iteration event
115 // immediately in many cases. It's not clear to me if that's the
116 // right thing to do.
117 uint32_t message
= mLastNotification
== LAST_NOTIFICATION_NONE
119 : NS_ANIMATION_ITERATION
;
120 mLastNotification
= computedTiming
.mCurrentIteration
;
121 TimeDuration iterationStart
=
122 mSource
->Timing().mIterationDuration
*
123 computedTiming
.mCurrentIteration
;
124 TimeDuration elapsedTime
=
125 std::max(iterationStart
, mSource
->InitialAdvance());
126 AnimationEventInfo
ei(target
, Name(), message
,
127 StickyTimeDuration(elapsedTime
),
128 PseudoTypeAsString(targetPseudoType
));
129 aEventsToDispatch
.AppendElement(ei
);
133 case ComputedTiming::AnimationPhase_After
:
134 // If we skipped the animation interval entirely, dispatch
135 // 'animationstart' first
136 if (mLastNotification
== LAST_NOTIFICATION_NONE
) {
137 // Notifying for start of 0th iteration.
138 // (This is overwritten below but we set it here to maintain
139 // internal consistency.)
140 mLastNotification
= 0;
141 StickyTimeDuration elapsedTime
=
142 std::min(StickyTimeDuration(mSource
->InitialAdvance()),
143 computedTiming
.mActiveDuration
);
144 AnimationEventInfo
ei(target
, Name(), NS_ANIMATION_START
,
146 PseudoTypeAsString(targetPseudoType
));
147 aEventsToDispatch
.AppendElement(ei
);
149 // Dispatch 'animationend' when needed.
150 if (mLastNotification
!= LAST_NOTIFICATION_END
) {
151 mLastNotification
= LAST_NOTIFICATION_END
;
152 AnimationEventInfo
ei(target
, Name(), NS_ANIMATION_END
,
153 computedTiming
.mActiveDuration
,
154 PseudoTypeAsString(targetPseudoType
));
155 aEventsToDispatch
.AppendElement(ei
);
161 CommonAnimationManager
*
162 CSSAnimationPlayer::GetAnimationManager() const
164 nsPresContext
* context
= GetPresContext();
169 return context
->AnimationManager();
172 /* static */ nsString
173 CSSAnimationPlayer::PseudoTypeAsString(nsCSSPseudoElements::Type aPseudoType
)
175 switch (aPseudoType
) {
176 case nsCSSPseudoElements::ePseudo_before
:
177 return NS_LITERAL_STRING("::before");
178 case nsCSSPseudoElements::ePseudo_after
:
179 return NS_LITERAL_STRING("::after");
181 return EmptyString();
186 nsAnimationManager::UpdateStyleAndEvents(AnimationPlayerCollection
*
188 TimeStamp aRefreshTime
,
189 EnsureStyleRuleFlags aFlags
)
191 aCollection
->EnsureStyleRuleFor(aRefreshTime
, aFlags
);
192 QueueEvents(aCollection
, mPendingEvents
);
196 nsAnimationManager::QueueEvents(AnimationPlayerCollection
* aCollection
,
197 EventArray
& aEventsToDispatch
)
199 for (size_t playerIdx
= aCollection
->mPlayers
.Length(); playerIdx
-- != 0; ) {
200 CSSAnimationPlayer
* player
=
201 aCollection
->mPlayers
[playerIdx
]->AsCSSAnimationPlayer();
202 MOZ_ASSERT(player
, "Expected a collection of CSS Animation players");
203 player
->QueueEvents(aEventsToDispatch
);
208 nsAnimationManager::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf
) const
210 return CommonAnimationManager::SizeOfExcludingThis(aMallocSizeOf
);
212 // Measurement of the following members may be added later if DMD finds it is
218 nsAnimationManager::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf
) const
220 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf
);
224 nsAnimationManager::CheckAnimationRule(nsStyleContext
* aStyleContext
,
225 mozilla::dom::Element
* aElement
)
227 // FIXME (bug 960465): This test should go away.
228 if (!mPresContext
->RestyleManager()->IsProcessingAnimationStyleChange()) {
229 if (!mPresContext
->IsDynamic()) {
230 // For print or print preview, ignore animations.
234 // Everything that causes our animation data to change triggers a
235 // style change, which in turn triggers a non-animation restyle.
236 // Likewise, when we initially construct frames, we're not in a
237 // style change, but also not in an animation restyle.
239 const nsStyleDisplay
* disp
= aStyleContext
->StyleDisplay();
240 AnimationPlayerCollection
* collection
=
241 GetAnimationPlayers(aElement
, aStyleContext
->GetPseudoType(), false);
243 disp
->mAnimationNameCount
== 1 &&
244 disp
->mAnimations
[0].GetName().IsEmpty()) {
248 // build the animations list
249 dom::AnimationTimeline
* timeline
= aElement
->OwnerDoc()->Timeline();
250 AnimationPlayerPtrArray newPlayers
;
251 BuildAnimations(aStyleContext
, aElement
, timeline
, newPlayers
);
253 if (newPlayers
.IsEmpty()) {
255 collection
->Destroy();
261 collection
->mStyleRule
= nullptr;
262 collection
->mStyleRuleRefreshTime
= TimeStamp();
263 collection
->UpdateAnimationGeneration(mPresContext
);
265 // Copy over the start times and (if still paused) pause starts
266 // for each animation (matching on name only) that was also in the
267 // old list of animations.
268 // This means that we honor dynamic changes, which isn't what the
269 // spec says to do, but WebKit seems to honor at least some of
271 // http://lists.w3.org/Archives/Public/www-style/2011Apr/0079.html
272 // In order to honor what the spec said, we'd copy more data over
273 // (or potentially optimize BuildAnimations to avoid rebuilding it
274 // in the first place).
275 if (!collection
->mPlayers
.IsEmpty()) {
277 for (size_t newIdx
= newPlayers
.Length(); newIdx
-- != 0;) {
278 AnimationPlayer
* newPlayer
= newPlayers
[newIdx
];
280 // Find the matching animation with this name in the old list
281 // of animations. We iterate through both lists in a backwards
282 // direction which means that if there are more animations in
283 // the new list of animations with a given name than in the old
284 // list, it will be the animations towards the of the beginning of
285 // the list that do not match and are treated as new animations.
286 nsRefPtr
<CSSAnimationPlayer
> oldPlayer
;
287 size_t oldIdx
= collection
->mPlayers
.Length();
288 while (oldIdx
-- != 0) {
289 CSSAnimationPlayer
* a
=
290 collection
->mPlayers
[oldIdx
]->AsCSSAnimationPlayer();
291 MOZ_ASSERT(a
, "All players in the CSS Animation collection should"
292 " be CSSAnimationPlayer objects");
293 if (a
->Name() == newPlayer
->Name()) {
302 // Update the old from the new so we can keep the original object
303 // identity (and any expando properties attached to it).
304 if (oldPlayer
->GetSource() && newPlayer
->GetSource()) {
305 Animation
* oldAnim
= oldPlayer
->GetSource();
306 Animation
* newAnim
= newPlayer
->GetSource();
307 oldAnim
->Timing() = newAnim
->Timing();
308 oldAnim
->Properties() = newAnim
->Properties();
311 // Reset compositor state so animation will be re-synchronized.
312 oldPlayer
->ClearIsRunningOnCompositor();
314 // Handle changes in play state.
315 // CSSAnimationPlayer takes care of override behavior so that,
316 // for example, if the author has called pause(), that will
317 // override the animation-play-state.
318 // (We should check newPlayer->IsStylePaused() but that requires
319 // downcasting to CSSAnimationPlayer and we happen to know that
320 // newPlayer will only ever be paused by calling PauseFromStyle
321 // making IsPaused synonymous in this case.)
322 if (!oldPlayer
->IsStylePaused() && newPlayer
->IsPaused()) {
323 oldPlayer
->PauseFromStyle();
324 } else if (oldPlayer
->IsStylePaused() && !newPlayer
->IsPaused()) {
325 oldPlayer
->PlayFromStyle();
328 // Replace new animation with the (updated) old one and remove the
329 // old one from the array so we don't try to match it any more.
331 // Although we're doing this while iterating this is safe because
332 // we're not changing the length of newPlayers and we've finished
333 // iterating over the list of old iterations.
336 newPlayers
.ReplaceElementAt(newIdx
, oldPlayer
);
337 collection
->mPlayers
.RemoveElementAt(oldIdx
);
342 GetAnimationPlayers(aElement
, aStyleContext
->GetPseudoType(), true);
344 collection
->mPlayers
.SwapElements(newPlayers
);
345 collection
->mNeedsRefreshes
= true;
348 // Cancel removed animations
349 for (size_t newPlayerIdx
= newPlayers
.Length(); newPlayerIdx
-- != 0; ) {
350 newPlayers
[newPlayerIdx
]->Cancel();
353 TimeStamp refreshTime
= mPresContext
->RefreshDriver()->MostRecentRefresh();
354 UpdateStyleAndEvents(collection
, refreshTime
,
355 EnsureStyleRule_IsNotThrottled
);
356 // We don't actually dispatch the mPendingEvents now. We'll either
357 // dispatch them the next time we get a refresh driver notification
358 // or the next time somebody calls
359 // nsPresShell::FlushPendingNotifications.
360 if (!mPendingEvents
.IsEmpty()) {
361 mPresContext
->Document()->SetNeedStyleFlush();
365 return GetAnimationRule(aElement
, aStyleContext
->GetPseudoType());
368 struct KeyframeData
{
370 uint32_t mIndex
; // store original order since sort algorithm is not stable
371 nsCSSKeyframeRule
*mRule
;
374 struct KeyframeDataComparator
{
375 bool Equals(const KeyframeData
& A
, const KeyframeData
& B
) const {
376 return A
.mKey
== B
.mKey
&& A
.mIndex
== B
.mIndex
;
378 bool LessThan(const KeyframeData
& A
, const KeyframeData
& B
) const {
379 return A
.mKey
< B
.mKey
|| (A
.mKey
== B
.mKey
&& A
.mIndex
< B
.mIndex
);
383 class ResolvedStyleCache
{
385 ResolvedStyleCache() : mCache() {}
386 nsStyleContext
* Get(nsPresContext
*aPresContext
,
387 nsStyleContext
*aParentStyleContext
,
388 nsCSSKeyframeRule
*aKeyframe
);
391 nsRefPtrHashtable
<nsPtrHashKey
<nsCSSKeyframeRule
>, nsStyleContext
> mCache
;
395 ResolvedStyleCache::Get(nsPresContext
*aPresContext
,
396 nsStyleContext
*aParentStyleContext
,
397 nsCSSKeyframeRule
*aKeyframe
)
399 // FIXME (spec): The css3-animations spec isn't very clear about how
400 // properties are resolved when they have values that depend on other
401 // properties (e.g., values in 'em'). I presume that they're resolved
402 // relative to the other styles of the element. The question is
403 // whether they are resolved relative to other animations: I assume
404 // that they're not, since that would prevent us from caching a lot of
405 // data that we'd really like to cache (in particular, the
406 // StyleAnimationValue values in AnimationPropertySegment).
407 nsStyleContext
*result
= mCache
.GetWeak(aKeyframe
);
409 nsCOMArray
<nsIStyleRule
> rules
;
410 rules
.AppendObject(aKeyframe
);
411 nsRefPtr
<nsStyleContext
> resultStrong
= aPresContext
->StyleSet()->
412 ResolveStyleByAddingRules(aParentStyleContext
, rules
);
413 mCache
.Put(aKeyframe
, resultStrong
);
414 result
= resultStrong
;
420 nsAnimationManager::BuildAnimations(nsStyleContext
* aStyleContext
,
421 dom::Element
* aTarget
,
422 dom::AnimationTimeline
* aTimeline
,
423 AnimationPlayerPtrArray
& aPlayers
)
425 NS_ABORT_IF_FALSE(aPlayers
.IsEmpty(), "expect empty array");
427 ResolvedStyleCache resolvedStyles
;
429 const nsStyleDisplay
*disp
= aStyleContext
->StyleDisplay();
431 for (size_t animIdx
= 0, animEnd
= disp
->mAnimationNameCount
;
432 animIdx
!= animEnd
; ++animIdx
) {
433 const StyleAnimation
& src
= disp
->mAnimations
[animIdx
];
435 // CSS Animations whose animation-name does not match a @keyframes rule do
436 // not generate animation events. This includes when the animation-name is
437 // "none" which is represented by an empty name in the StyleAnimation.
438 // Since such animations neither affect style nor dispatch events, we do
439 // not generate a corresponding AnimationPlayer for them.
440 nsCSSKeyframesRule
* rule
=
441 src
.GetName().IsEmpty()
443 : mPresContext
->StyleSet()->KeyframesRuleForName(mPresContext
,
449 nsRefPtr
<CSSAnimationPlayer
> dest
= new CSSAnimationPlayer(aTimeline
);
450 aPlayers
.AppendElement(dest
);
452 AnimationTiming timing
;
453 timing
.mIterationDuration
=
454 TimeDuration::FromMilliseconds(src
.GetDuration());
455 timing
.mDelay
= TimeDuration::FromMilliseconds(src
.GetDelay());
456 timing
.mIterationCount
= src
.GetIterationCount();
457 timing
.mDirection
= src
.GetDirection();
458 timing
.mFillMode
= src
.GetFillMode();
460 nsRefPtr
<Animation
> destAnim
=
461 new Animation(mPresContext
->Document(), aTarget
,
462 aStyleContext
->GetPseudoType(), timing
, src
.GetName());
463 dest
->SetSource(destAnim
);
465 // Even in the case where we call PauseFromStyle below, we still need to
466 // call PlayFromStyle first. This is because a newly-created player is idle
467 // and has no effect until it is played (or otherwise given a start time).
468 dest
->PlayFromStyle();
470 if (src
.GetPlayState() == NS_STYLE_ANIMATION_PLAY_STATE_PAUSED
) {
471 dest
->PauseFromStyle();
474 // While current drafts of css3-animations say that later keyframes
475 // with the same key entirely replace earlier ones (no cascading),
476 // this is a bad idea and contradictory to the rest of CSS. So
477 // we're going to keep all the keyframes for each key and then do
478 // the replacement on a per-property basis rather than a per-rule
479 // basis, just like everything else in CSS.
481 AutoInfallibleTArray
<KeyframeData
, 16> sortedKeyframes
;
483 for (uint32_t ruleIdx
= 0, ruleEnd
= rule
->StyleRuleCount();
484 ruleIdx
!= ruleEnd
; ++ruleIdx
) {
485 css::Rule
* cssRule
= rule
->GetStyleRuleAt(ruleIdx
);
486 NS_ABORT_IF_FALSE(cssRule
, "must have rule");
487 NS_ABORT_IF_FALSE(cssRule
->GetType() == css::Rule::KEYFRAME_RULE
,
488 "must be keyframe rule");
489 nsCSSKeyframeRule
*kfRule
= static_cast<nsCSSKeyframeRule
*>(cssRule
);
491 const nsTArray
<float> &keys
= kfRule
->GetKeys();
492 for (uint32_t keyIdx
= 0, keyEnd
= keys
.Length();
493 keyIdx
!= keyEnd
; ++keyIdx
) {
494 float key
= keys
[keyIdx
];
495 // FIXME (spec): The spec doesn't say what to do with
496 // out-of-range keyframes. We'll ignore them.
497 if (0.0f
<= key
&& key
<= 1.0f
) {
498 KeyframeData
*data
= sortedKeyframes
.AppendElement();
500 data
->mIndex
= ruleIdx
;
501 data
->mRule
= kfRule
;
506 sortedKeyframes
.Sort(KeyframeDataComparator());
508 if (sortedKeyframes
.Length() == 0) {
513 // Record the properties that are present in any keyframe rules we
515 nsCSSPropertySet properties
;
517 for (uint32_t kfIdx
= 0, kfEnd
= sortedKeyframes
.Length();
518 kfIdx
!= kfEnd
; ++kfIdx
) {
519 css::Declaration
*decl
= sortedKeyframes
[kfIdx
].mRule
->Declaration();
520 for (uint32_t propIdx
= 0, propEnd
= decl
->Count();
521 propIdx
!= propEnd
; ++propIdx
) {
522 nsCSSProperty prop
= decl
->GetPropertyAt(propIdx
);
523 if (prop
!= eCSSPropertyExtra_variable
) {
524 // CSS Variables are not animatable
525 properties
.AddProperty(prop
);
530 for (nsCSSProperty prop
= nsCSSProperty(0);
531 prop
< eCSSProperty_COUNT_no_shorthands
;
532 prop
= nsCSSProperty(prop
+ 1)) {
533 if (!properties
.HasProperty(prop
) ||
534 nsCSSProps::kAnimTypeTable
[prop
] == eStyleAnimType_None
) {
538 // Build a list of the keyframes to use for this property. This
539 // means we need every keyframe with the property in it, except
540 // for those keyframes where a later keyframe with the *same key*
541 // also has the property.
542 AutoInfallibleTArray
<uint32_t, 16> keyframesWithProperty
;
543 float lastKey
= 100.0f
; // an invalid key
544 for (uint32_t kfIdx
= 0, kfEnd
= sortedKeyframes
.Length();
545 kfIdx
!= kfEnd
; ++kfIdx
) {
546 KeyframeData
&kf
= sortedKeyframes
[kfIdx
];
547 if (!kf
.mRule
->Declaration()->HasProperty(prop
)) {
550 if (kf
.mKey
== lastKey
) {
551 // Replace previous occurrence of same key.
552 keyframesWithProperty
[keyframesWithProperty
.Length() - 1] = kfIdx
;
554 keyframesWithProperty
.AppendElement(kfIdx
);
559 AnimationProperty
&propData
= *destAnim
->Properties().AppendElement();
560 propData
.mProperty
= prop
;
562 KeyframeData
*fromKeyframe
= nullptr;
563 nsRefPtr
<nsStyleContext
> fromContext
;
564 bool interpolated
= true;
565 for (uint32_t wpIdx
= 0, wpEnd
= keyframesWithProperty
.Length();
566 wpIdx
!= wpEnd
; ++wpIdx
) {
567 uint32_t kfIdx
= keyframesWithProperty
[wpIdx
];
568 KeyframeData
&toKeyframe
= sortedKeyframes
[kfIdx
];
570 nsRefPtr
<nsStyleContext
> toContext
=
571 resolvedStyles
.Get(mPresContext
, aStyleContext
, toKeyframe
.mRule
);
574 interpolated
= interpolated
&&
575 BuildSegment(propData
.mSegments
, prop
, src
,
576 fromKeyframe
->mKey
, fromContext
,
577 fromKeyframe
->mRule
->Declaration(),
578 toKeyframe
.mKey
, toContext
);
580 if (toKeyframe
.mKey
!= 0.0f
) {
581 // There's no data for this property at 0%, so use the
582 // cascaded value above us.
583 interpolated
= interpolated
&&
584 BuildSegment(propData
.mSegments
, prop
, src
,
585 0.0f
, aStyleContext
, nullptr,
586 toKeyframe
.mKey
, toContext
);
590 fromContext
= toContext
;
591 fromKeyframe
= &toKeyframe
;
594 if (fromKeyframe
->mKey
!= 1.0f
) {
595 // There's no data for this property at 100%, so use the
596 // cascaded value above us.
597 interpolated
= interpolated
&&
598 BuildSegment(propData
.mSegments
, prop
, src
,
599 fromKeyframe
->mKey
, fromContext
,
600 fromKeyframe
->mRule
->Declaration(),
601 1.0f
, aStyleContext
);
604 // If we failed to build any segments due to inability to
605 // interpolate, remove the property from the animation. (It's not
606 // clear if this is the right thing to do -- we could run some of
607 // the segments, but it's really not clear whether we should skip
608 // values (which?) or skip segments, so best to skip the whole
611 destAnim
->Properties().RemoveElementAt(
612 destAnim
->Properties().Length() - 1);
619 nsAnimationManager::BuildSegment(InfallibleTArray
<AnimationPropertySegment
>&
621 nsCSSProperty aProperty
,
622 const StyleAnimation
& aAnimation
,
623 float aFromKey
, nsStyleContext
* aFromContext
,
624 mozilla::css::Declaration
* aFromDeclaration
,
625 float aToKey
, nsStyleContext
* aToContext
)
627 StyleAnimationValue fromValue
, toValue
, dummyValue
;
628 if (!ExtractComputedValueForTransition(aProperty
, aFromContext
, fromValue
) ||
629 !ExtractComputedValueForTransition(aProperty
, aToContext
, toValue
) ||
630 // Check that we can interpolate between these values
631 // (If this is ever a performance problem, we could add a
632 // CanInterpolate method, but it seems fine for now.)
633 !StyleAnimationValue::Interpolate(aProperty
, fromValue
, toValue
,
638 AnimationPropertySegment
&segment
= *aSegments
.AppendElement();
640 segment
.mFromValue
= fromValue
;
641 segment
.mToValue
= toValue
;
642 segment
.mFromKey
= aFromKey
;
643 segment
.mToKey
= aToKey
;
644 const nsTimingFunction
*tf
;
645 if (aFromDeclaration
&&
646 aFromDeclaration
->HasProperty(eCSSProperty_animation_timing_function
)) {
647 tf
= &aFromContext
->StyleDisplay()->mAnimations
[0].GetTimingFunction();
649 tf
= &aAnimation
.GetTimingFunction();
651 segment
.mTimingFunction
.Init(*tf
);
657 nsAnimationManager::WillRefresh(mozilla::TimeStamp aTime
)
659 NS_ABORT_IF_FALSE(mPresContext
,
660 "refresh driver should not notify additional observers "
661 "after pres context has been destroyed");
662 if (!mPresContext
->GetPresShell()) {
663 // Someone might be keeping mPresContext alive past the point
664 // where it has been torn down; don't bother doing anything in
665 // this case. But do get rid of all our transitions so we stop
666 // triggering refreshes.
667 RemoveAllElementCollections();
671 FlushAnimations(Can_Throttle
);
675 nsAnimationManager::FlushAnimations(FlushFlags aFlags
)
677 // FIXME: check that there's at least one style rule that's not
678 // in its "done" state, and if there isn't, remove ourselves from
679 // the refresh driver (but leave the animations!).
680 TimeStamp now
= mPresContext
->RefreshDriver()->MostRecentRefresh();
681 bool didThrottle
= false;
682 for (PRCList
*l
= PR_LIST_HEAD(&mElementCollections
);
683 l
!= &mElementCollections
;
684 l
= PR_NEXT_LINK(l
)) {
685 AnimationPlayerCollection
* collection
=
686 static_cast<AnimationPlayerCollection
*>(l
);
688 bool canThrottleTick
= aFlags
== Can_Throttle
&&
689 collection
->CanPerformOnCompositorThread(
690 AnimationPlayerCollection::CanAnimateFlags(0)) &&
691 collection
->CanThrottleAnimation(now
);
693 nsRefPtr
<css::AnimValuesStyleRule
> oldStyleRule
= collection
->mStyleRule
;
694 UpdateStyleAndEvents(collection
, now
, canThrottleTick
695 ? EnsureStyleRule_IsThrottled
696 : EnsureStyleRule_IsNotThrottled
);
697 if (oldStyleRule
!= collection
->mStyleRule
) {
698 collection
->PostRestyleForAnimation(mPresContext
);
705 mPresContext
->Document()->SetNeedStyleFlush();
708 DispatchEvents(); // may destroy us
712 nsAnimationManager::DoDispatchEvents()
715 mPendingEvents
.SwapElements(events
);
716 for (uint32_t i
= 0, i_end
= events
.Length(); i
< i_end
; ++i
) {
717 AnimationEventInfo
&info
= events
[i
];
718 EventDispatcher::Dispatch(info
.mElement
, mPresContext
, &info
.mEvent
);