nsIStyleRule* CommonAnimationManager::GetAnimationRule(mozilla::dom::Element* aElement, nsCSSPseudoElements::Type aPseudoType) { MOZ_ASSERT( aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement || aPseudoType == nsCSSPseudoElements::ePseudo_before || aPseudoType == nsCSSPseudoElements::ePseudo_after, "forbidden pseudo type"); if (!mPresContext->IsDynamic()) { // For print or print preview, ignore animations. return nullptr; } AnimationPlayerCollection* collection = GetAnimations(aElement, aPseudoType, false); if (!collection) { return nullptr; } RestyleManager* restyleManager = mPresContext->RestyleManager(); if (restyleManager->SkipAnimationRules()) { return nullptr; } collection->EnsureStyleRuleFor( mPresContext->RefreshDriver()->MostRecentRefresh(), EnsureStyleRule_IsNotThrottled); return collection->mStyleRule; }
void CommonAnimationManager::AddStyleUpdatesTo(RestyleTracker& aTracker) { TimeStamp now = mPresContext->RefreshDriver()->MostRecentRefresh(); PRCList* next = PR_LIST_HEAD(&mElementCollections); while (next != &mElementCollections) { AnimationPlayerCollection* collection = static_cast<AnimationPlayerCollection*>(next); next = PR_NEXT_LINK(next); if (!collection->mNeedsRefreshes) { continue; } collection->EnsureStyleRuleFor(now, EnsureStyleRule_IsNotThrottled); dom::Element* elementToRestyle = collection->GetElementToRestyle(); if (elementToRestyle) { nsRestyleHint rshint = collection->IsForTransitions() ? eRestyle_CSSTransitions : eRestyle_CSSAnimations; aTracker.AddPendingRestyle(elementToRestyle, rshint, nsChangeHint(0)); } } }
void AnimationPlayer::PostUpdate() { AnimationPlayerCollection* collection = GetCollection(); if (collection) { collection->NotifyPlayerUpdated(); } }
void CommonAnimationManager::NotifyCollectionUpdated(AnimationPlayerCollection& aCollection) { MaybeStartObservingRefreshDriver(); mPresContext->ClearLastStyleUpdateForAllAnimations(); mPresContext->RestyleManager()->IncrementAnimationGeneration(); aCollection.UpdateAnimationGeneration(mPresContext); aCollection.PostRestyleForAnimation(mPresContext); }
void CommonAnimationManager::NotifyCollectionUpdated(AnimationPlayerCollection& aCollection) { CheckNeedsRefresh(); mPresContext->ClearLastStyleUpdateForAllAnimations(); mPresContext->RestyleManager()->IncrementAnimationGeneration(); aCollection.UpdateAnimationGeneration(mPresContext); aCollection.PostRestyleForAnimation(mPresContext); }
nsIStyleRule* CommonAnimationManager::GetAnimationRule(mozilla::dom::Element* aElement, nsCSSPseudoElements::Type aPseudoType) { MOZ_ASSERT( aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement || aPseudoType == nsCSSPseudoElements::ePseudo_before || aPseudoType == nsCSSPseudoElements::ePseudo_after, "forbidden pseudo type"); if (!mPresContext->IsDynamic()) { // For print or print preview, ignore animations. return nullptr; } AnimationPlayerCollection* collection = GetAnimationPlayers(aElement, aPseudoType, false); if (!collection) { return nullptr; } RestyleManager* restyleManager = mPresContext->RestyleManager(); if (restyleManager->SkipAnimationRules()) { // During the non-animation part of processing restyles, we don't // add the animation rule. if (collection->mStyleRule && restyleManager->PostAnimationRestyles()) { collection->PostRestyleForAnimation(mPresContext); } return nullptr; } // Animations should already be refreshed, but transitions may not be. // Note that this is temporary, we would like both animations and transitions // to both be refreshed by this point. if (IsAnimationManager()) { NS_WARN_IF_FALSE(!collection->mNeedsRefreshes || collection->mStyleRuleRefreshTime == mPresContext->RefreshDriver()->MostRecentRefresh(), "should already have refreshed style rule"); } else { // FIXME: Remove this assignment. See bug 1061364. collection->mNeedsRefreshes = true; collection->EnsureStyleRuleFor( mPresContext->RefreshDriver()->MostRecentRefresh(), EnsureStyleRule_IsNotThrottled); } return collection->mStyleRule; }
AnimationPlayerCollection* CommonAnimationManager::GetAnimationsForCompositor(nsIContent* aContent, nsIAtom* aElementProperty, nsCSSProperty aProperty) { if (!aContent->MayHaveAnimations()) return nullptr; AnimationPlayerCollection* collection = static_cast<AnimationPlayerCollection*>( aContent->GetProperty(aElementProperty)); if (!collection || !collection->HasAnimationOfProperty(aProperty) || !collection->CanPerformOnCompositorThread( AnimationPlayerCollection::CanAnimate_AllowPartial)) { return nullptr; } // This animation can be done on the compositor. return collection; }
nsIStyleRule* nsAnimationManager::GetAnimationRule(mozilla::dom::Element* aElement, nsCSSPseudoElements::Type aPseudoType) { NS_ABORT_IF_FALSE( aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement || aPseudoType == nsCSSPseudoElements::ePseudo_before || aPseudoType == nsCSSPseudoElements::ePseudo_after, "forbidden pseudo type"); if (!mPresContext->IsDynamic()) { // For print or print preview, ignore animations. return nullptr; } AnimationPlayerCollection* collection = GetAnimationPlayers(aElement, aPseudoType, false); if (!collection) { return nullptr; } RestyleManager* restyleManager = mPresContext->RestyleManager(); if (restyleManager->SkipAnimationRules()) { // During the non-animation part of processing restyles, we don't // add the animation rule. if (collection->mStyleRule && restyleManager->PostAnimationRestyles()) { collection->PostRestyleForAnimation(mPresContext); } return nullptr; } NS_WARN_IF_FALSE(!collection->mNeedsRefreshes || collection->mStyleRuleRefreshTime == mPresContext->RefreshDriver()->MostRecentRefresh(), "should already have refreshed style rule"); return collection->mStyleRule; }
void nsAnimationManager::FlushAnimations(FlushFlags aFlags) { // FIXME: check that there's at least one style rule that's not // in its "done" state, and if there isn't, remove ourselves from // the refresh driver (but leave the animations!). TimeStamp now = mPresContext->RefreshDriver()->MostRecentRefresh(); bool didThrottle = false; for (PRCList *l = PR_LIST_HEAD(&mElementCollections); l != &mElementCollections; l = PR_NEXT_LINK(l)) { AnimationPlayerCollection* collection = static_cast<AnimationPlayerCollection*>(l); nsAutoAnimationMutationBatch mb(collection->mElement); collection->Tick(); bool canThrottleTick = aFlags == Can_Throttle && collection->CanPerformOnCompositorThread( AnimationPlayerCollection::CanAnimateFlags(0)) && collection->CanThrottleAnimation(now); nsRefPtr<css::AnimValuesStyleRule> oldStyleRule = collection->mStyleRule; UpdateStyleAndEvents(collection, now, canThrottleTick ? EnsureStyleRule_IsThrottled : EnsureStyleRule_IsNotThrottled); if (oldStyleRule != collection->mStyleRule) { collection->PostRestyleForAnimation(mPresContext); } else { didThrottle = true; } } if (didThrottle) { mPresContext->Document()->SetNeedStyleFlush(); } DispatchEvents(); // may destroy us }
nsIStyleRule* nsAnimationManager::CheckAnimationRule(nsStyleContext* aStyleContext, mozilla::dom::Element* aElement) { // FIXME (bug 960465): This test should go away. if (!mPresContext->RestyleManager()->IsProcessingAnimationStyleChange()) { if (!mPresContext->IsDynamic()) { // For print or print preview, ignore animations. return nullptr; } // Everything that causes our animation data to change triggers a // style change, which in turn triggers a non-animation restyle. // Likewise, when we initially construct frames, we're not in a // style change, but also not in an animation restyle. const nsStyleDisplay* disp = aStyleContext->StyleDisplay(); AnimationPlayerCollection* collection = GetAnimationPlayers(aElement, aStyleContext->GetPseudoType(), false); if (!collection && disp->mAnimationNameCount == 1 && disp->mAnimations[0].GetName().IsEmpty()) { return nullptr; } // build the animations list dom::AnimationTimeline* timeline = aElement->OwnerDoc()->Timeline(); AnimationPlayerPtrArray newPlayers; BuildAnimations(aStyleContext, aElement, timeline, newPlayers); if (newPlayers.IsEmpty()) { if (collection) { collection->Destroy(); } return nullptr; } if (collection) { collection->mStyleRule = nullptr; collection->mStyleRuleRefreshTime = TimeStamp(); collection->UpdateAnimationGeneration(mPresContext); // Copy over the start times and (if still paused) pause starts // for each animation (matching on name only) that was also in the // old list of animations. // This means that we honor dynamic changes, which isn't what the // spec says to do, but WebKit seems to honor at least some of // them. See // http://lists.w3.org/Archives/Public/www-style/2011Apr/0079.html // In order to honor what the spec said, we'd copy more data over // (or potentially optimize BuildAnimations to avoid rebuilding it // in the first place). if (!collection->mPlayers.IsEmpty()) { for (size_t newIdx = newPlayers.Length(); newIdx-- != 0;) { AnimationPlayer* newPlayer = newPlayers[newIdx]; // Find the matching animation with this name in the old list // of animations. We iterate through both lists in a backwards // direction which means that if there are more animations in // the new list of animations with a given name than in the old // list, it will be the animations towards the of the beginning of // the list that do not match and are treated as new animations. nsRefPtr<CSSAnimationPlayer> oldPlayer; size_t oldIdx = collection->mPlayers.Length(); while (oldIdx-- != 0) { CSSAnimationPlayer* a = collection->mPlayers[oldIdx]->AsCSSAnimationPlayer(); MOZ_ASSERT(a, "All players in the CSS Animation collection should" " be CSSAnimationPlayer objects"); if (a->Name() == newPlayer->Name()) { oldPlayer = a; break; } } if (!oldPlayer) { continue; } // Update the old from the new so we can keep the original object // identity (and any expando properties attached to it). if (oldPlayer->GetSource() && newPlayer->GetSource()) { Animation* oldAnim = oldPlayer->GetSource(); Animation* newAnim = newPlayer->GetSource(); oldAnim->Timing() = newAnim->Timing(); oldAnim->Properties() = newAnim->Properties(); } // Reset compositor state so animation will be re-synchronized. oldPlayer->ClearIsRunningOnCompositor(); // Handle changes in play state. // CSSAnimationPlayer takes care of override behavior so that, // for example, if the author has called pause(), that will // override the animation-play-state. // (We should check newPlayer->IsStylePaused() but that requires // downcasting to CSSAnimationPlayer and we happen to know that // newPlayer will only ever be paused by calling PauseFromStyle // making IsPaused synonymous in this case.) if (!oldPlayer->IsStylePaused() && newPlayer->IsPaused()) { oldPlayer->PauseFromStyle(); } else if (oldPlayer->IsStylePaused() && !newPlayer->IsPaused()) { oldPlayer->PlayFromStyle(); } // Replace new animation with the (updated) old one and remove the // old one from the array so we don't try to match it any more. // // Although we're doing this while iterating this is safe because // we're not changing the length of newPlayers and we've finished // iterating over the list of old iterations. newPlayer = nullptr; newPlayers.ReplaceElementAt(newIdx, oldPlayer); collection->mPlayers.RemoveElementAt(oldIdx); } } } else { collection = GetAnimationPlayers(aElement, aStyleContext->GetPseudoType(), true); } collection->mPlayers.SwapElements(newPlayers); collection->mNeedsRefreshes = true; collection->Tick(); TimeStamp refreshTime = mPresContext->RefreshDriver()->MostRecentRefresh(); UpdateStyleAndEvents(collection, refreshTime, EnsureStyleRule_IsNotThrottled); // We don't actually dispatch the mPendingEvents now. We'll either // dispatch them the next time we get a refresh driver notification // or the next time somebody calls // nsPresShell::FlushPendingNotifications. if (!mPendingEvents.IsEmpty()) { mPresContext->Document()->SetNeedStyleFlush(); } } return GetAnimationRule(aElement, aStyleContext->GetPseudoType()); }