void KeyframeEffect::SetTarget(const Nullable<ElementOrCSSPseudoElement>& aTarget) { Maybe<OwningAnimationTarget> newTarget = ConvertTarget(aTarget); if (mTarget == newTarget) { // Assign the same target, skip it. return; } if (mTarget) { UnregisterTarget(); ResetIsRunningOnCompositor(); // We don't need to reset the mWinsInCascade member since it will be updated // when we later associate with a different target (and until that time this // flag is not used). RequestRestyle(EffectCompositor::RestyleType::Layer); nsAutoAnimationMutationBatch mb(mTarget->mElement->OwnerDoc()); if (mAnimation) { nsNodeUtils::AnimationRemoved(mAnimation); } } mTarget = newTarget; if (mTarget) { UpdateTargetRegistration(); RefPtr<nsStyleContext> styleContext = GetTargetStyleContext(); if (styleContext) { UpdateProperties(styleContext); } else if (mEffectOptions.mSpacingMode == SpacingMode::paced) { KeyframeUtils::ApplyDistributeSpacing(mKeyframes); } MaybeUpdateFrameForCompositor(); RequestRestyle(EffectCompositor::RestyleType::Layer); nsAutoAnimationMutationBatch mb(mTarget->mElement->OwnerDoc()); if (mAnimation) { nsNodeUtils::AnimationAdded(mAnimation); } } else if (mEffectOptions.mSpacingMode == SpacingMode::paced) { // New target is null, so fall back to distribute spacing. KeyframeUtils::ApplyDistributeSpacing(mKeyframes); } }
void KeyframeEffect::NotifySpecifiedTimingUpdated() { // Use the same document for a pseudo element and its parent element. // Use nullptr if we don't have mTarget, so disable the mutation batch. nsAutoAnimationMutationBatch mb(mTarget ? mTarget->mElement->OwnerDoc() : nullptr); if (mAnimation) { mAnimation->NotifyEffectTimingUpdated(); if (mAnimation->IsRelevant()) { nsNodeUtils::AnimationChanged(mAnimation); } RequestRestyle(EffectCompositor::RestyleType::Layer); } }
void KeyframeEffectReadOnly::SetAnimation(Animation* aAnimation) { if (mAnimation == aAnimation) { return; } // Restyle for the old animation. RequestRestyle(EffectCompositor::RestyleType::Layer); mAnimation = aAnimation; // The order of these function calls is important: // NotifyAnimationTimingUpdated() need the updated mIsRelevant flag to check // if it should create the effectSet or not, and MarkCascadeNeedsUpdate() // needs a valid effectSet, so we should call them in this order. if (mAnimation) { mAnimation->UpdateRelevance(); } NotifyAnimationTimingUpdated(); if (mAnimation) { MarkCascadeNeedsUpdate(); } }
void KeyframeEffectReadOnly::UpdateProperties(nsStyleContext* aStyleContext) { MOZ_ASSERT(aStyleContext); nsTArray<AnimationProperty> properties = BuildProperties(aStyleContext); if (mProperties == properties) { return; } // Preserve the state of the mIsRunningOnCompositor flag. nsCSSPropertyIDSet runningOnCompositorProperties; for (const AnimationProperty& property : mProperties) { if (property.mIsRunningOnCompositor) { runningOnCompositorProperties.AddProperty(property.mProperty); } } mProperties = Move(properties); for (AnimationProperty& property : mProperties) { property.mIsRunningOnCompositor = runningOnCompositorProperties.HasProperty(property.mProperty); } // FIXME (bug 1303235): Do this for Servo too if (aStyleContext->PresContext()->StyleSet()->IsGecko()) { CalculateCumulativeChangeHint(aStyleContext); } MarkCascadeNeedsUpdate(); RequestRestyle(EffectCompositor::RestyleType::Layer); }
void KeyframeEffectReadOnly::UpdateProperties(nsStyleContext* aStyleContext) { MOZ_ASSERT(aStyleContext); nsTArray<AnimationProperty> properties; if (mTarget) { // When GetComputedKeyframeValues or GetAnimationPropertiesFromKeyframes // calculate computed values from |mKeyframes|, they could possibly // trigger a subsequent restyle in which we rebuild animations. If that // happens we could find that |mKeyframes| is overwritten while it is // being iterated over. Normally that shouldn't happen but just in case we // make a copy of |mKeyframes| first and iterate over that instead. auto keyframesCopy(mKeyframes); nsTArray<ComputedKeyframeValues> computedValues = KeyframeUtils::GetComputedKeyframeValues(keyframesCopy, mTarget->mElement, aStyleContext); if (mEffectOptions.mSpacingMode == SpacingMode::paced) { KeyframeUtils::ApplySpacing(keyframesCopy, SpacingMode::paced, mEffectOptions.mPacedProperty, computedValues); } properties = KeyframeUtils::GetAnimationPropertiesFromKeyframes(keyframesCopy, computedValues, aStyleContext); #ifdef DEBUG MOZ_ASSERT(SpecifiedKeyframeArraysAreEqual(mKeyframes, keyframesCopy), "Apart from the computed offset members, the keyframes array" " should not be modified"); #endif mKeyframes.SwapElements(keyframesCopy); } if (mProperties == properties) { return; } // Preserve the state of mWinsInCascade and mIsRunningOnCompositor flags. nsCSSPropertyIDSet winningInCascadeProperties; nsCSSPropertyIDSet runningOnCompositorProperties; for (const AnimationProperty& property : mProperties) { if (property.mWinsInCascade) { winningInCascadeProperties.AddProperty(property.mProperty); } if (property.mIsRunningOnCompositor) { runningOnCompositorProperties.AddProperty(property.mProperty); } } mProperties = Move(properties); for (AnimationProperty& property : mProperties) { property.mWinsInCascade = winningInCascadeProperties.HasProperty(property.mProperty); property.mIsRunningOnCompositor = runningOnCompositorProperties.HasProperty(property.mProperty); } CalculateCumulativeChangeHint(aStyleContext); MarkCascadeNeedsUpdate(); RequestRestyle(EffectCompositor::RestyleType::Layer); }