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::calculateCompositorAnimationUpdate(CSSAnimationUpdate& update, const Element* animatingElement, Element& element, const ComputedStyle& style) { ElementAnimations* elementAnimations = animatingElement ? animatingElement->elementAnimations() : nullptr; // We only update compositor animations in response to changes in the base style. if (!elementAnimations || elementAnimations->isAnimationStyleChange()) return; if (!animatingElement->layoutObject() || !animatingElement->layoutObject()->style()) return; const ComputedStyle& oldStyle = *animatingElement->layoutObject()->style(); if (!oldStyle.shouldCompositeForCurrentAnimations()) return; CSSAnimations& cssAnimations = elementAnimations->cssAnimations(); for (auto& runningAnimation : cssAnimations.m_animations.values()) { Animation& animation = *runningAnimation->animation; if (animation.effect() && animation.effect()->isKeyframeEffect()) { EffectModel* model = toKeyframeEffect(animation.effect())->model(); if (model && model->isKeyframeEffectModel()) { KeyframeEffectModelBase* keyframeEffect = toKeyframeEffectModelBase(model); if (keyframeEffect->hasSyntheticKeyframes() && keyframeEffect->snapshotNeutralCompositorKeyframes(element, oldStyle, style)) update.updateCompositorKeyframes(&animation); } } } if (oldStyle.hasCurrentTransformAnimation() && oldStyle.effectiveZoom() != style.effectiveZoom()) { for (auto& entry : elementAnimations->animations()) { Animation& animation = *entry.key; if (animation.effect() && animation.effect()->isKeyframeEffect()) { EffectModel* model = toKeyframeEffect(animation.effect())->model(); if (model && model->isKeyframeEffectModel()) { KeyframeEffectModelBase* keyframeEffect = toKeyframeEffectModelBase(model); if (keyframeEffect->affects(PropertyHandle(CSSPropertyTransform)) && keyframeEffect->snapshotAllCompositorKeyframes(element, &style)) update.updateCompositorKeyframes(&animation); } } } } }
void CSSAnimations::calculateTransitionUpdate(CSSAnimationUpdate& update, const Element* animatingElement, const ComputedStyle& style) { if (!animatingElement) return; if (animatingElement->document().printing() || animatingElement->document().wasPrinting()) return; ElementAnimations* elementAnimations = animatingElement->elementAnimations(); const TransitionMap* activeTransitions = elementAnimations ? &elementAnimations->cssAnimations().m_transitions : nullptr; const CSSTransitionData* transitionData = style.transitions(); #if ENABLE(ASSERT) // In debug builds we verify that it would have been safe to avoid populating and testing listedProperties if the style recalc is due to animation. const bool animationStyleRecalc = false; #else // In release builds we avoid the cost of checking for new and interrupted transitions if the style recalc is due to animation. const bool animationStyleRecalc = elementAnimations && elementAnimations->isAnimationStyleChange(); #endif BitArray<numCSSProperties> listedProperties; bool anyTransitionHadTransitionAll = false; const LayoutObject* layoutObject = animatingElement->layoutObject(); if (!animationStyleRecalc && style.display() != NONE && layoutObject && layoutObject->style() && transitionData) { const ComputedStyle& oldStyle = *layoutObject->style(); for (size_t i = 0; i < transitionData->propertyList().size(); ++i) { const CSSTransitionData::TransitionProperty& transitionProperty = transitionData->propertyList()[i]; if (transitionProperty.propertyType != CSSTransitionData::TransitionKnownProperty) continue; CSSPropertyID property = resolveCSSPropertyID(transitionProperty.unresolvedProperty); bool animateAll = property == CSSPropertyAll; if (animateAll) anyTransitionHadTransitionAll = true; const StylePropertyShorthand& propertyList = animateAll ? CSSAnimations::propertiesForTransitionAll() : shorthandForProperty(property); // If not a shorthand we only execute one iteration of this loop, and refer to the property directly. for (unsigned j = 0; !j || j < propertyList.length(); ++j) { CSSPropertyID id = propertyList.length() ? propertyList.properties()[j] : property; ASSERT(id >= firstCSSProperty); if (!animateAll) { if (CSSPropertyMetadata::isInterpolableProperty(id)) listedProperties.set(id - firstCSSProperty); else continue; } // FIXME: We should transition if an !important property changes even when an animation is running, // but this is a bit hard to do with the current applyMatchedProperties system. PropertyHandle property = PropertyHandle(id); if (!update.activeInterpolationsForAnimations().contains(property) && (!elementAnimations || !elementAnimations->cssAnimations().m_previousActiveInterpolationsForAnimations.contains(property))) { calculateTransitionUpdateForProperty(id, *transitionData, i, oldStyle, style, activeTransitions, update, animatingElement); } } } } if (activeTransitions) { for (const auto& entry : *activeTransitions) { CSSPropertyID id = entry.key; if (!anyTransitionHadTransitionAll && !animationStyleRecalc && !listedProperties.get(id - firstCSSProperty)) { // TODO: Figure out why this fails on Chrome OS login page. crbug.com/365507 // ASSERT(animation.playStateInternal() == Animation::Finished || !(elementAnimations && elementAnimations->isAnimationStyleChange())); update.cancelTransition(id); } else if (entry.value.animation->finishedInternal()) { update.finishTransition(id); } } } }