void nsAnimationManager::MaybeUpdateCascadeResults(AnimationCollection* aCollection) { for (size_t animIdx = aCollection->mAnimations.Length(); animIdx-- != 0; ) { CSSAnimation* anim = aCollection->mAnimations[animIdx]->AsCSSAnimation(); if (anim->IsInEffect() != anim->mInEffectForCascadeResults) { // Update our own cascade results. mozilla::dom::Element* element = aCollection->GetElementToRestyle(); bool updatedCascadeResults = false; if (element) { nsIFrame* frame = element->GetPrimaryFrame(); if (frame) { UpdateCascadeResults(frame->StyleContext(), aCollection); updatedCascadeResults = true; } } if (!updatedCascadeResults) { // If we don't have a style context we can't do the work of updating // cascading results but we need to make sure to update // mInEffectForCascadeResults or else we'll keep running this // code every time (potentially leading to infinite recursion due // to the fact that this method both calls and is (indirectly) called // by nsTransitionManager). anim->mInEffectForCascadeResults = anim->IsInEffect(); } // Notify the transition manager, whose results might depend on ours. mPresContext->TransitionManager()-> UpdateCascadeResultsWithAnimations(aCollection); return; } } }
void nsAnimationManager::MaybeUpdateCascadeResults(AnimationCollection* aCollection) { for (size_t animIdx = aCollection->mAnimations.Length(); animIdx-- != 0; ) { CSSAnimation* anim = aCollection->mAnimations[animIdx]->AsCSSAnimation(); if (anim->IsInEffect() != anim->mInEffectForCascadeResults) { // Update our own cascade results. mozilla::dom::Element* element = aCollection->GetElementToRestyle(); if (element) { nsIFrame* frame = element->GetPrimaryFrame(); if (frame) { UpdateCascadeResults(frame->StyleContext(), aCollection); } } // Notify the transition manager, whose results might depend on ours. mPresContext->TransitionManager()-> UpdateCascadeResultsWithAnimations(aCollection); return; } } }
/* static */ void nsAnimationManager::UpdateCascadeResults( nsStyleContext* aStyleContext, AnimationCollection* aElementAnimations) { /* * Figure out which properties we need to examine. */ // size of 2 since we only currently have 2 properties we animate on // the compositor nsAutoTArray<nsCSSProperty, 2> propertiesToTrack; { nsCSSPropertySet propertiesToTrackAsSet; for (size_t animIdx = aElementAnimations->mAnimations.Length(); animIdx-- != 0; ) { const Animation* anim = aElementAnimations->mAnimations[animIdx]; const KeyframeEffectReadOnly* effect = anim->GetEffect(); if (!effect) { continue; } for (size_t propIdx = 0, propEnd = effect->Properties().Length(); propIdx != propEnd; ++propIdx) { const AnimationProperty& prop = effect->Properties()[propIdx]; // We only bother setting mWinsInCascade for properties that we // can animate on the compositor. if (nsCSSProps::PropHasFlags(prop.mProperty, CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR)) { if (!propertiesToTrackAsSet.HasProperty(prop.mProperty)) { propertiesToTrack.AppendElement(prop.mProperty); propertiesToTrackAsSet.AddProperty(prop.mProperty); } } } } } /* * Determine whether those properties are set in things that * override animations. */ nsCSSPropertySet propertiesOverridden; nsRuleNode::ComputePropertiesOverridingAnimation(propertiesToTrack, aStyleContext, propertiesOverridden); /* * Set mWinsInCascade based both on what is overridden at levels * higher than animations and based on one animation overriding * another. * * We iterate from the last animation to the first, just like we do * when calling ComposeStyle from AnimationCollection::EnsureStyleRuleFor. * Later animations override earlier ones, so we add properties to the set * of overridden properties as we encounter them, if the animation is * currently in effect. */ bool changed = false; for (size_t animIdx = aElementAnimations->mAnimations.Length(); animIdx-- != 0; ) { CSSAnimation* anim = aElementAnimations->mAnimations[animIdx]->AsCSSAnimation(); KeyframeEffectReadOnly* effect = anim->GetEffect(); anim->mInEffectForCascadeResults = anim->IsInEffect(); if (!effect) { continue; } for (size_t propIdx = 0, propEnd = effect->Properties().Length(); propIdx != propEnd; ++propIdx) { AnimationProperty& prop = effect->Properties()[propIdx]; // We only bother setting mWinsInCascade for properties that we // can animate on the compositor. if (nsCSSProps::PropHasFlags(prop.mProperty, CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR)) { bool newWinsInCascade = !propertiesOverridden.HasProperty(prop.mProperty); if (newWinsInCascade != prop.mWinsInCascade) { changed = true; } prop.mWinsInCascade = newWinsInCascade; if (prop.mWinsInCascade && anim->mInEffectForCascadeResults) { // This animation is in effect right now, so it overrides // earlier animations. (For animations that aren't in effect, // we set mWinsInCascade as though they were, but they don't // suppress animations lower in the cascade.) propertiesOverridden.AddProperty(prop.mProperty); } } } } if (changed) { nsPresContext* presContext = aElementAnimations->mManager->PresContext(); presContext->RestyleManager()->IncrementAnimationGeneration(); aElementAnimations->UpdateAnimationGeneration(presContext); aElementAnimations->PostUpdateLayerAnimations(); // Invalidate our style rule. aElementAnimations->mNeedsRefreshes = true; aElementAnimations->mStyleRuleRefreshTime = TimeStamp(); } }