void CSSAnimations::calculateTransitionActiveInterpolations(CSSAnimationUpdate& update, const Element* animatingElement, double timelineCurrentTime)
{
    ElementAnimations* elementAnimations = animatingElement ? animatingElement->elementAnimations() : nullptr;
    AnimationStack* animationStack = elementAnimations ? &elementAnimations->defaultStack() : nullptr;

    ActiveInterpolationsMap activeInterpolationsForTransitions;
    if (update.newTransitions().isEmpty() && update.cancelledTransitions().isEmpty()) {
        activeInterpolationsForTransitions = AnimationStack::activeInterpolations(animationStack, 0, 0, KeyframeEffect::TransitionPriority, timelineCurrentTime);
    } else {
        HeapVector<Member<InertEffect>> newTransitions;
        for (const auto& entry : update.newTransitions())
            newTransitions.append(entry.value.effect.get());

        HeapHashSet<Member<const Animation>> cancelledAnimations;
        if (!update.cancelledTransitions().isEmpty()) {
            ASSERT(elementAnimations);
            const TransitionMap& transitionMap = elementAnimations->cssAnimations().m_transitions;
            for (CSSPropertyID id : update.cancelledTransitions()) {
                ASSERT(transitionMap.contains(id));
                cancelledAnimations.add(transitionMap.get(id).animation.get());
            }
        }

        activeInterpolationsForTransitions = AnimationStack::activeInterpolations(animationStack, &newTransitions, &cancelledAnimations, KeyframeEffect::TransitionPriority, timelineCurrentTime);
    }

    // Properties being animated by animations don't get values from transitions applied.
    if (!update.activeInterpolationsForAnimations().isEmpty() && !activeInterpolationsForTransitions.isEmpty()) {
        for (const auto& entry : update.activeInterpolationsForAnimations())
            activeInterpolationsForTransitions.remove(entry.key);
    }
    update.adoptActiveInterpolationsForTransitions(activeInterpolationsForTransitions);
}
void CSSAnimations::calculateAnimationActiveInterpolations(CSSAnimationUpdate& update, const Element* animatingElement, double timelineCurrentTime)
{
    ElementAnimations* elementAnimations = animatingElement ? animatingElement->elementAnimations() : nullptr;
    AnimationStack* animationStack = elementAnimations ? &elementAnimations->defaultStack() : nullptr;

    if (update.newAnimations().isEmpty() && update.suppressedAnimations().isEmpty()) {
        ActiveInterpolationsMap activeInterpolationsForAnimations(AnimationStack::activeInterpolations(animationStack, 0, 0, KeyframeEffect::DefaultPriority, timelineCurrentTime));
        update.adoptActiveInterpolationsForAnimations(activeInterpolationsForAnimations);
        return;
    }

    HeapVector<Member<InertEffect>> newEffects;
    for (const auto& newAnimation : update.newAnimations())
        newEffects.append(newAnimation.effect.get());
    for (const auto& updatedAnimation : update.animationsWithUpdates())
        newEffects.append(updatedAnimation.effect.get()); // Animations with updates use a temporary InertEffect for the current frame.

    ActiveInterpolationsMap activeInterpolationsForAnimations(AnimationStack::activeInterpolations(animationStack, &newEffects, &update.suppressedAnimations(), KeyframeEffect::DefaultPriority, timelineCurrentTime));
    update.adoptActiveInterpolationsForAnimations(activeInterpolationsForAnimations);
}