void Animation::Tick() { // Finish pending if we have a pending ready time, but only if we also // have an active timeline. if (mPendingState != PendingState::NotPending && !mPendingReadyTime.IsNull() && mTimeline && !mTimeline->GetCurrentTime().IsNull()) { // Even though mPendingReadyTime is initialized using TimeStamp::Now() // during the *previous* tick of the refresh driver, it can still be // ahead of the *current* timeline time when we are using the // vsync timer so we need to clamp it to the timeline time. mPendingReadyTime.SetValue(std::min(mTimeline->GetCurrentTime().Value(), mPendingReadyTime.Value())); FinishPendingAt(mPendingReadyTime.Value()); mPendingReadyTime.SetNull(); } if (IsPossiblyOrphanedPendingAnimation()) { MOZ_ASSERT(mTimeline && !mTimeline->GetCurrentTime().IsNull(), "Orphaned pending animtaions should have an active timeline"); FinishPendingAt(mTimeline->GetCurrentTime().Value()); } UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async); // FIXME: Detect the no-change case and don't request a restyle at all // FIXME: Detect changes to IsPlaying() state and request RestyleType::Layer // so that layers get updated immediately AnimationCollection* collection = GetCollection(); if (collection) { collection->RequestRestyle(CanThrottle() ? AnimationCollection::RestyleType::Throttled : AnimationCollection::RestyleType::Standard); } }
/* static */ void EffectCompositor::UpdateCascadeResults(EffectSet& aEffectSet, Element* aElement, nsCSSPseudoElements::Type aPseudoType, nsStyleContext* aStyleContext) { MOZ_ASSERT(EffectSet::GetEffectSet(aElement, aPseudoType) == &aEffectSet, "Effect set should correspond to the specified (pseudo-)element"); if (aEffectSet.IsEmpty()) { aEffectSet.MarkCascadeUpdated(); return; } // Get a list of effects sorted by composite order. nsTArray<KeyframeEffectReadOnly*> sortedEffectList; for (KeyframeEffectReadOnly* effect : aEffectSet) { sortedEffectList.AppendElement(effect); } sortedEffectList.Sort(EffectCompositeOrderComparator()); // Get properties that override the *animations* level of the cascade. // // We only do this for properties that we can animate on the compositor // since we will apply other properties on the main thread where the usual // cascade applies. nsCSSPropertySet overriddenProperties; if (aStyleContext) { GetOverriddenProperties(aStyleContext, aEffectSet, overriddenProperties); } bool changed = false; nsCSSPropertySet animatedProperties; // Iterate from highest to lowest composite order. for (KeyframeEffectReadOnly* effect : Reversed(sortedEffectList)) { MOZ_ASSERT(effect->GetAnimation(), "Effects on a target element should have an Animation"); bool inEffect = effect->IsInEffect(); for (AnimationProperty& prop : effect->Properties()) { bool winsInCascade = !animatedProperties.HasProperty(prop.mProperty) && inEffect; // If this property wins in the cascade, add it to the set of animated // properties. We need to do this even if the property is overridden // (in which case we set winsInCascade to false below) since we don't // want to fire transitions on these properties. if (winsInCascade) { animatedProperties.AddProperty(prop.mProperty); } // For effects that will be applied to the animations level of the // cascade, we need to check that the property isn't being set by // something with higher priority in the cascade. // // We only do this, however, for properties that can be animated on // the compositor. For properties animated on the main thread the usual // cascade ensures these animations will be correctly overridden. if (winsInCascade && effect->GetAnimation()->CascadeLevel() == CascadeLevel::Animations && overriddenProperties.HasProperty(prop.mProperty)) { winsInCascade = false; } if (winsInCascade != prop.mWinsInCascade) { changed = true; } prop.mWinsInCascade = winsInCascade; } } aEffectSet.MarkCascadeUpdated(); // If there is any change in the cascade result, update animations on // layers with the winning animations. nsPresContext* presContext = GetPresContext(aElement); if (changed && presContext) { // We currently unconditionally update both animations and transitions // even if we could, for example, get away with only updating animations. // This is a temporary measure until we unify all animation style updating // under EffectCompositor. AnimationCollection* animations = presContext->AnimationManager()->GetAnimationCollection(aElement, aPseudoType, false); /* don't create */ if (animations) { animations->RequestRestyle(AnimationCollection::RestyleType::Layer); } AnimationCollection* transitions = presContext->TransitionManager()->GetAnimationCollection(aElement, aPseudoType, false); /* don't create */ if (transitions) { transitions->RequestRestyle(AnimationCollection::RestyleType::Layer); } } }