Bumping manifests a=b2g-bump
[gecko.git] / layout / style / AnimationCommon.cpp
blob5abe8ea8323fca40fd752feec93702b8a86bb73f
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 "AnimationCommon.h"
7 #include "nsTransitionManager.h"
8 #include "nsAnimationManager.h"
10 #include "ActiveLayerTracker.h"
11 #include "gfxPlatform.h"
12 #include "nsRuleData.h"
13 #include "nsCSSPropertySet.h"
14 #include "nsCSSValue.h"
15 #include "nsCycleCollectionParticipant.h"
16 #include "nsStyleContext.h"
17 #include "nsIFrame.h"
18 #include "nsLayoutUtils.h"
19 #include "mozilla/LookAndFeel.h"
20 #include "Layers.h"
21 #include "FrameLayerBuilder.h"
22 #include "nsDisplayList.h"
23 #include "mozilla/MemoryReporting.h"
24 #include "RestyleManager.h"
25 #include "nsStyleSet.h"
26 #include "nsStyleChangeList.h"
29 using mozilla::layers::Layer;
30 using mozilla::dom::AnimationPlayer;
31 using mozilla::dom::Animation;
33 namespace mozilla {
35 /* static */ bool
36 IsGeometricProperty(nsCSSProperty aProperty)
38 switch (aProperty) {
39 case eCSSProperty_bottom:
40 case eCSSProperty_height:
41 case eCSSProperty_left:
42 case eCSSProperty_right:
43 case eCSSProperty_top:
44 case eCSSProperty_width:
45 return true;
46 default:
47 return false;
51 namespace css {
53 CommonAnimationManager::CommonAnimationManager(nsPresContext *aPresContext)
54 : mPresContext(aPresContext)
56 PR_INIT_CLIST(&mElementCollections);
59 CommonAnimationManager::~CommonAnimationManager()
61 NS_ABORT_IF_FALSE(!mPresContext, "Disconnect should have been called");
64 void
65 CommonAnimationManager::Disconnect()
67 // Content nodes might outlive the transition or animation manager.
68 RemoveAllElementCollections();
70 mPresContext = nullptr;
73 void
74 CommonAnimationManager::RemoveAllElementCollections()
76 while (!PR_CLIST_IS_EMPTY(&mElementCollections)) {
77 AnimationPlayerCollection* head =
78 static_cast<AnimationPlayerCollection*>(
79 PR_LIST_HEAD(&mElementCollections));
80 head->Destroy();
84 AnimationPlayerCollection*
85 CommonAnimationManager::GetAnimationsForCompositor(nsIContent* aContent,
86 nsIAtom* aElementProperty,
87 nsCSSProperty aProperty)
89 if (!aContent->MayHaveAnimations())
90 return nullptr;
91 AnimationPlayerCollection* collection =
92 static_cast<AnimationPlayerCollection*>(
93 aContent->GetProperty(aElementProperty));
94 if (!collection ||
95 !collection->HasAnimationOfProperty(aProperty) ||
96 !collection->CanPerformOnCompositorThread(
97 AnimationPlayerCollection::CanAnimate_AllowPartial)) {
98 return nullptr;
101 // This animation can be done on the compositor.
102 // Mark the frame as active, in case we are able to throttle this animation.
103 nsIFrame* frame = nsLayoutUtils::GetStyleFrame(collection->mElement);
104 if (frame) {
105 if (aProperty == eCSSProperty_opacity) {
106 ActiveLayerTracker::NotifyAnimated(frame, eCSSProperty_opacity);
107 } else if (aProperty == eCSSProperty_transform) {
108 ActiveLayerTracker::NotifyAnimated(frame, eCSSProperty_transform);
112 return collection;
116 * nsISupports implementation
119 NS_IMPL_ISUPPORTS(CommonAnimationManager, nsIStyleRuleProcessor)
121 nsRestyleHint
122 CommonAnimationManager::HasStateDependentStyle(StateRuleProcessorData* aData)
124 return nsRestyleHint(0);
127 nsRestyleHint
128 CommonAnimationManager::HasStateDependentStyle(PseudoElementStateRuleProcessorData* aData)
130 return nsRestyleHint(0);
133 bool
134 CommonAnimationManager::HasDocumentStateDependentStyle(StateRuleProcessorData* aData)
136 return false;
139 nsRestyleHint
140 CommonAnimationManager::HasAttributeDependentStyle(AttributeRuleProcessorData* aData)
142 return nsRestyleHint(0);
145 /* virtual */ bool
146 CommonAnimationManager::MediumFeaturesChanged(nsPresContext* aPresContext)
148 return false;
151 /* virtual */ size_t
152 CommonAnimationManager::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
154 // Measurement of the following members may be added later if DMD finds it is
155 // worthwhile:
156 // - mElementCollections
158 // The following members are not measured
159 // - mPresContext, because it's non-owning
161 return 0;
164 /* virtual */ size_t
165 CommonAnimationManager::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
167 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
170 void
171 CommonAnimationManager::AddStyleUpdatesTo(RestyleTracker& aTracker)
173 PRCList* next = PR_LIST_HEAD(&mElementCollections);
174 while (next != &mElementCollections) {
175 AnimationPlayerCollection* collection =
176 static_cast<AnimationPlayerCollection*>(next);
177 next = PR_NEXT_LINK(next);
179 dom::Element* elementToRestyle = collection->GetElementToRestyle();
180 if (elementToRestyle) {
181 nsRestyleHint rshint = collection->IsForTransitions()
182 ? eRestyle_CSSTransitions : eRestyle_CSSAnimations;
183 aTracker.AddPendingRestyle(elementToRestyle, rshint, nsChangeHint(0));
188 /* static */ bool
189 CommonAnimationManager::ExtractComputedValueForTransition(
190 nsCSSProperty aProperty,
191 nsStyleContext* aStyleContext,
192 StyleAnimationValue& aComputedValue)
194 bool result = StyleAnimationValue::ExtractComputedValue(aProperty,
195 aStyleContext,
196 aComputedValue);
197 if (aProperty == eCSSProperty_visibility) {
198 NS_ABORT_IF_FALSE(aComputedValue.GetUnit() ==
199 StyleAnimationValue::eUnit_Enumerated,
200 "unexpected unit");
201 aComputedValue.SetIntValue(aComputedValue.GetIntValue(),
202 StyleAnimationValue::eUnit_Visibility);
204 return result;
207 NS_IMPL_ISUPPORTS(AnimValuesStyleRule, nsIStyleRule)
209 /* virtual */ void
210 AnimValuesStyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
212 nsStyleContext *contextParent = aRuleData->mStyleContext->GetParent();
213 if (contextParent && contextParent->HasPseudoElementData()) {
214 // Don't apply transitions or animations to things inside of
215 // pseudo-elements.
216 // FIXME (Bug 522599): Add tests for this.
217 return;
220 for (uint32_t i = 0, i_end = mPropertyValuePairs.Length(); i < i_end; ++i) {
221 PropertyValuePair &cv = mPropertyValuePairs[i];
222 if (aRuleData->mSIDs & nsCachedStyleData::GetBitForSID(
223 nsCSSProps::kSIDTable[cv.mProperty]))
225 nsCSSValue *prop = aRuleData->ValueFor(cv.mProperty);
226 if (prop->GetUnit() == eCSSUnit_Null) {
227 #ifdef DEBUG
228 bool ok =
229 #endif
230 StyleAnimationValue::UncomputeValue(cv.mProperty, cv.mValue, *prop);
231 NS_ABORT_IF_FALSE(ok, "could not store computed value");
237 #ifdef DEBUG
238 /* virtual */ void
239 AnimValuesStyleRule::List(FILE* out, int32_t aIndent) const
241 for (int32_t index = aIndent; --index >= 0; ) fputs(" ", out);
242 fputs("[anim values] { ", out);
243 for (uint32_t i = 0, i_end = mPropertyValuePairs.Length(); i < i_end; ++i) {
244 const PropertyValuePair &pair = mPropertyValuePairs[i];
245 nsAutoString value;
246 StyleAnimationValue::UncomputeValue(pair.mProperty, pair.mValue, value);
247 fprintf(out, "%s: %s; ", nsCSSProps::GetStringValue(pair.mProperty).get(),
248 NS_ConvertUTF16toUTF8(value).get());
250 fputs("}\n", out);
252 #endif
254 } /* end sub-namespace css */
256 bool
257 AnimationPlayerCollection::CanAnimatePropertyOnCompositor(
258 const dom::Element *aElement,
259 nsCSSProperty aProperty,
260 CanAnimateFlags aFlags)
262 bool shouldLog = nsLayoutUtils::IsAnimationLoggingEnabled();
263 if (!gfxPlatform::OffMainThreadCompositingEnabled()) {
264 if (shouldLog) {
265 nsCString message;
266 message.AppendLiteral("Performance warning: Compositor disabled");
267 LogAsyncAnimationFailure(message);
269 return false;
272 nsIFrame* frame = nsLayoutUtils::GetStyleFrame(aElement);
273 if (IsGeometricProperty(aProperty)) {
274 if (shouldLog) {
275 nsCString message;
276 message.AppendLiteral("Performance warning: Async animation of geometric property '");
277 message.Append(nsCSSProps::GetStringValue(aProperty));
278 message.AppendLiteral("' is disabled");
279 LogAsyncAnimationFailure(message, aElement);
281 return false;
283 if (aProperty == eCSSProperty_transform) {
284 if (frame->Preserves3D() &&
285 frame->Preserves3DChildren()) {
286 if (shouldLog) {
287 nsCString message;
288 message.AppendLiteral("Gecko bug: Async animation of 'preserve-3d' transforms is not supported. See bug 779598");
289 LogAsyncAnimationFailure(message, aElement);
291 return false;
293 if (frame->IsSVGTransformed()) {
294 if (shouldLog) {
295 nsCString message;
296 message.AppendLiteral("Gecko bug: Async 'transform' animations of frames with SVG transforms is not supported. See bug 779599");
297 LogAsyncAnimationFailure(message, aElement);
299 return false;
301 if (aFlags & CanAnimate_HasGeometricProperty) {
302 if (shouldLog) {
303 nsCString message;
304 message.AppendLiteral("Performance warning: Async animation of 'transform' not possible due to presence of geometric properties");
305 LogAsyncAnimationFailure(message, aElement);
307 return false;
310 bool enabled = nsLayoutUtils::AreAsyncAnimationsEnabled();
311 if (!enabled && shouldLog) {
312 nsCString message;
313 message.AppendLiteral("Performance warning: Async animations are disabled");
314 LogAsyncAnimationFailure(message);
316 bool propertyAllowed = (aProperty == eCSSProperty_transform) ||
317 (aProperty == eCSSProperty_opacity) ||
318 (aFlags & CanAnimate_AllowPartial);
319 return enabled && propertyAllowed;
322 /* static */ bool
323 AnimationPlayerCollection::IsCompositorAnimationDisabledForFrame(
324 nsIFrame* aFrame)
326 void* prop = aFrame->Properties().Get(nsIFrame::RefusedAsyncAnimation());
327 return bool(reinterpret_cast<intptr_t>(prop));
330 bool
331 AnimationPlayerCollection::CanPerformOnCompositorThread(
332 CanAnimateFlags aFlags) const
334 nsIFrame* frame = nsLayoutUtils::GetStyleFrame(mElement);
335 if (!frame) {
336 return false;
339 if (mElementProperty != nsGkAtoms::transitionsProperty &&
340 mElementProperty != nsGkAtoms::animationsProperty) {
341 if (nsLayoutUtils::IsAnimationLoggingEnabled()) {
342 nsCString message;
343 message.AppendLiteral("Gecko bug: Async animation of pseudoelements"
344 " not supported. See bug 771367 (");
345 message.Append(nsAtomCString(mElementProperty));
346 message.Append(")");
347 LogAsyncAnimationFailure(message, mElement);
349 return false;
352 for (size_t playerIdx = mPlayers.Length(); playerIdx-- != 0; ) {
353 const AnimationPlayer* player = mPlayers[playerIdx];
354 if (!player->IsRunning() || !player->GetSource()) {
355 continue;
357 const Animation* anim = player->GetSource();
358 for (size_t propIdx = 0, propEnd = anim->Properties().Length();
359 propIdx != propEnd; ++propIdx) {
360 if (IsGeometricProperty(anim->Properties()[propIdx].mProperty)) {
361 aFlags = CanAnimateFlags(aFlags | CanAnimate_HasGeometricProperty);
362 break;
367 bool existsProperty = false;
368 for (size_t playerIdx = mPlayers.Length(); playerIdx-- != 0; ) {
369 const AnimationPlayer* player = mPlayers[playerIdx];
370 if (!player->IsRunning() || !player->GetSource()) {
371 continue;
374 const Animation* anim = player->GetSource();
375 existsProperty = existsProperty || anim->Properties().Length() > 0;
377 for (size_t propIdx = 0, propEnd = anim->Properties().Length();
378 propIdx != propEnd; ++propIdx) {
379 const AnimationProperty& prop = anim->Properties()[propIdx];
380 if (!CanAnimatePropertyOnCompositor(mElement,
381 prop.mProperty,
382 aFlags) ||
383 IsCompositorAnimationDisabledForFrame(frame)) {
384 return false;
389 // No properties to animate
390 if (!existsProperty) {
391 return false;
394 return true;
397 bool
398 AnimationPlayerCollection::HasAnimationOfProperty(
399 nsCSSProperty aProperty) const
401 for (size_t playerIdx = mPlayers.Length(); playerIdx-- != 0; ) {
402 const Animation* anim = mPlayers[playerIdx]->GetSource();
403 if (anim && anim->HasAnimationOfProperty(aProperty) &&
404 !anim->IsFinishedTransition()) {
405 return true;
408 return false;
411 mozilla::dom::Element*
412 AnimationPlayerCollection::GetElementToRestyle() const
414 if (IsForElement()) {
415 return mElement;
418 nsIFrame* primaryFrame = mElement->GetPrimaryFrame();
419 if (!primaryFrame) {
420 return nullptr;
422 nsIFrame* pseudoFrame;
423 if (IsForBeforePseudo()) {
424 pseudoFrame = nsLayoutUtils::GetBeforeFrame(primaryFrame);
425 } else if (IsForAfterPseudo()) {
426 pseudoFrame = nsLayoutUtils::GetAfterFrame(primaryFrame);
427 } else {
428 MOZ_ASSERT(false, "unknown mElementProperty");
429 return nullptr;
431 if (!pseudoFrame) {
432 return nullptr;
434 return pseudoFrame->GetContent()->AsElement();
437 /* static */ void
438 AnimationPlayerCollection::LogAsyncAnimationFailure(nsCString& aMessage,
439 const nsIContent* aContent)
441 if (aContent) {
442 aMessage.AppendLiteral(" [");
443 aMessage.Append(nsAtomCString(aContent->Tag()));
445 nsIAtom* id = aContent->GetID();
446 if (id) {
447 aMessage.AppendLiteral(" with id '");
448 aMessage.Append(nsAtomCString(aContent->GetID()));
449 aMessage.Append('\'');
451 aMessage.Append(']');
453 aMessage.Append('\n');
454 printf_stderr("%s", aMessage.get());
457 /*static*/ void
458 AnimationPlayerCollection::PropertyDtor(void *aObject, nsIAtom *aPropertyName,
459 void *aPropertyValue, void *aData)
461 AnimationPlayerCollection* collection =
462 static_cast<AnimationPlayerCollection*>(aPropertyValue);
463 #ifdef DEBUG
464 NS_ABORT_IF_FALSE(!collection->mCalledPropertyDtor, "can't call dtor twice");
465 collection->mCalledPropertyDtor = true;
466 #endif
467 delete collection;
470 void
471 AnimationPlayerCollection::Tick()
473 for (size_t playerIdx = 0, playerEnd = mPlayers.Length();
474 playerIdx != playerEnd; playerIdx++) {
475 mPlayers[playerIdx]->Tick();
479 void
480 AnimationPlayerCollection::EnsureStyleRuleFor(TimeStamp aRefreshTime,
481 EnsureStyleRuleFlags aFlags)
483 if (!mNeedsRefreshes) {
484 mStyleRuleRefreshTime = aRefreshTime;
485 return;
488 // If we're performing animations on the compositor thread, then we can skip
489 // most of the work in this method. But even if we are throttled, then we
490 // have to do the work if an animation is ending in order to get correct end
491 // of animation behaviour (the styles of the animation disappear, or the fill
492 // mode behaviour). This loop checks for any finishing animations and forces
493 // the style recalculation if we find any.
494 if (aFlags == EnsureStyleRule_IsThrottled) {
495 for (size_t playerIdx = mPlayers.Length(); playerIdx-- != 0; ) {
496 AnimationPlayer* player = mPlayers[playerIdx];
498 // Skip player with no source content, finished transitions, or animations
499 // whose @keyframes rule is empty.
500 if (!player->GetSource() ||
501 player->GetSource()->IsFinishedTransition() ||
502 player->GetSource()->Properties().IsEmpty()) {
503 continue;
506 // The GetComputedTiming() call here handles pausing. But:
507 // FIXME: avoid recalculating every time when paused.
508 ComputedTiming computedTiming = player->GetSource()->GetComputedTiming();
510 // XXX We shouldn't really be using LastNotification() as a general
511 // indicator that the animation has finished, it should be reserved for
512 // events. If we use it differently in the future this use might need
513 // changing.
514 if (!player->mIsRunningOnCompositor ||
515 (computedTiming.mPhase == ComputedTiming::AnimationPhase_After &&
516 player->GetSource()->LastNotification()
517 != Animation::LAST_NOTIFICATION_END))
519 aFlags = EnsureStyleRule_IsNotThrottled;
520 break;
525 if (aFlags == EnsureStyleRule_IsThrottled) {
526 return;
529 // mStyleRule may be null and valid, if we have no style to apply.
530 if (mStyleRuleRefreshTime.IsNull() ||
531 mStyleRuleRefreshTime != aRefreshTime) {
532 mStyleRuleRefreshTime = aRefreshTime;
533 mStyleRule = nullptr;
534 // We'll set mNeedsRefreshes to true below in all cases where we need them.
535 mNeedsRefreshes = false;
537 // FIXME(spec): assume that properties in higher animations override
538 // those in lower ones.
539 // Therefore, we iterate from last animation to first.
540 nsCSSPropertySet properties;
542 for (size_t playerIdx = mPlayers.Length(); playerIdx-- != 0; ) {
543 AnimationPlayer* player = mPlayers[playerIdx];
545 if (!player->GetSource() || player->GetSource()->IsFinishedTransition()) {
546 continue;
549 // The GetComputedTiming() call here handles pausing. But:
550 // FIXME: avoid recalculating every time when paused.
551 ComputedTiming computedTiming = player->GetSource()->GetComputedTiming();
553 if ((computedTiming.mPhase == ComputedTiming::AnimationPhase_Before ||
554 computedTiming.mPhase == ComputedTiming::AnimationPhase_Active) &&
555 !player->IsPaused()) {
556 mNeedsRefreshes = true;
559 // If the time fraction is null, we don't have fill data for the current
560 // time so we shouldn't animate.
561 // Likewise, if the player has no source content.
562 if (computedTiming.mTimeFraction == ComputedTiming::kNullTimeFraction) {
563 continue;
566 NS_ABORT_IF_FALSE(0.0 <= computedTiming.mTimeFraction &&
567 computedTiming.mTimeFraction <= 1.0,
568 "timing fraction should be in [0-1]");
570 const Animation* anim = player->GetSource();
571 for (size_t propIdx = 0, propEnd = anim->Properties().Length();
572 propIdx != propEnd; ++propIdx)
574 const AnimationProperty& prop = anim->Properties()[propIdx];
576 NS_ABORT_IF_FALSE(prop.mSegments[0].mFromKey == 0.0,
577 "incorrect first from key");
578 NS_ABORT_IF_FALSE(prop.mSegments[prop.mSegments.Length() - 1].mToKey
579 == 1.0,
580 "incorrect last to key");
582 if (properties.HasProperty(prop.mProperty)) {
583 // A later animation already set this property.
584 continue;
586 properties.AddProperty(prop.mProperty);
588 NS_ABORT_IF_FALSE(prop.mSegments.Length() > 0,
589 "property should not be in animations if it "
590 "has no segments");
592 // FIXME: Maybe cache the current segment?
593 const AnimationPropertySegment *segment = prop.mSegments.Elements(),
594 *segmentEnd = segment + prop.mSegments.Length();
595 while (segment->mToKey < computedTiming.mTimeFraction) {
596 NS_ABORT_IF_FALSE(segment->mFromKey < segment->mToKey,
597 "incorrect keys");
598 ++segment;
599 if (segment == segmentEnd) {
600 NS_ABORT_IF_FALSE(false, "incorrect time fraction");
601 break; // in order to continue in outer loop (just below)
603 NS_ABORT_IF_FALSE(segment->mFromKey == (segment-1)->mToKey,
604 "incorrect keys");
606 if (segment == segmentEnd) {
607 continue;
609 NS_ABORT_IF_FALSE(segment->mFromKey < segment->mToKey,
610 "incorrect keys");
611 NS_ABORT_IF_FALSE(segment >= prop.mSegments.Elements() &&
612 size_t(segment - prop.mSegments.Elements()) <
613 prop.mSegments.Length(),
614 "out of array bounds");
616 if (!mStyleRule) {
617 // Allocate the style rule now that we know we have animation data.
618 mStyleRule = new css::AnimValuesStyleRule();
621 double positionInSegment =
622 (computedTiming.mTimeFraction - segment->mFromKey) /
623 (segment->mToKey - segment->mFromKey);
624 double valuePosition =
625 segment->mTimingFunction.GetValue(positionInSegment);
627 StyleAnimationValue *val =
628 mStyleRule->AddEmptyValue(prop.mProperty);
630 #ifdef DEBUG
631 bool result =
632 #endif
633 StyleAnimationValue::Interpolate(prop.mProperty,
634 segment->mFromValue,
635 segment->mToValue,
636 valuePosition, *val);
637 NS_ABORT_IF_FALSE(result, "interpolate must succeed now");
644 bool
645 AnimationPlayerCollection::CanThrottleTransformChanges(TimeStamp aTime)
647 if (!nsLayoutUtils::AreAsyncAnimationsEnabled()) {
648 return false;
651 // If we know that the animation cannot cause overflow,
652 // we can just disable flushes for this animation.
654 // If we don't show scrollbars, we don't care about overflow.
655 if (LookAndFeel::GetInt(LookAndFeel::eIntID_ShowHideScrollbars) == 0) {
656 return true;
659 // If this animation can cause overflow, we can throttle some of the ticks.
660 if ((aTime - mStyleRuleRefreshTime) < TimeDuration::FromMilliseconds(200)) {
661 return true;
664 // If the nearest scrollable ancestor has overflow:hidden,
665 // we don't care about overflow.
666 nsIScrollableFrame* scrollable = nsLayoutUtils::GetNearestScrollableFrame(
667 nsLayoutUtils::GetStyleFrame(mElement));
668 if (!scrollable) {
669 return true;
672 ScrollbarStyles ss = scrollable->GetScrollbarStyles();
673 if (ss.mVertical == NS_STYLE_OVERFLOW_HIDDEN &&
674 ss.mHorizontal == NS_STYLE_OVERFLOW_HIDDEN &&
675 scrollable->GetLogicalScrollPosition() == nsPoint(0, 0)) {
676 return true;
679 return false;
682 bool
683 AnimationPlayerCollection::CanThrottleAnimation(TimeStamp aTime)
685 nsIFrame* frame = nsLayoutUtils::GetStyleFrame(mElement);
686 if (!frame) {
687 return false;
690 bool hasTransform = HasAnimationOfProperty(eCSSProperty_transform);
691 bool hasOpacity = HasAnimationOfProperty(eCSSProperty_opacity);
692 if (hasOpacity) {
693 Layer* layer = FrameLayerBuilder::GetDedicatedLayer(
694 frame, nsDisplayItem::TYPE_OPACITY);
695 if (!layer || mAnimationGeneration > layer->GetAnimationGeneration()) {
696 return false;
700 if (!hasTransform) {
701 return true;
704 Layer* layer = FrameLayerBuilder::GetDedicatedLayer(
705 frame, nsDisplayItem::TYPE_TRANSFORM);
706 if (!layer || mAnimationGeneration > layer->GetAnimationGeneration()) {
707 return false;
710 return CanThrottleTransformChanges(aTime);
713 void
714 AnimationPlayerCollection::UpdateAnimationGeneration(
715 nsPresContext* aPresContext)
717 mAnimationGeneration =
718 aPresContext->RestyleManager()->GetAnimationGeneration();
721 bool
722 AnimationPlayerCollection::HasCurrentAnimations()
724 for (size_t playerIdx = mPlayers.Length(); playerIdx-- != 0; ) {
725 if (mPlayers[playerIdx]->IsCurrent()) {
726 return true;
730 return false;