[Web Animations] Style changes due to Web Animations should not trigger CSS Transitions
authorgraouts@webkit.org <graouts@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 14 Feb 2020 19:00:08 +0000 (19:00 +0000)
committergraouts@webkit.org <graouts@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 14 Feb 2020 19:00:08 +0000 (19:00 +0000)
https://bugs.webkit.org/show_bug.cgi?id=207760
<rdar://problem/59458111>

Reviewed by Simon Fraser.

LayoutTests/imported/w3c:

Mark Web Platform Tests progressions.

* web-platform-tests/web-animations/interfaces/Animatable/animate-expected.txt:
* web-platform-tests/web-animations/interfaces/Animation/style-change-events-expected.txt:
* web-platform-tests/web-animations/interfaces/DocumentTimeline/style-change-events-expected.txt:
* web-platform-tests/web-animations/interfaces/KeyframeEffect/style-change-events-expected.txt:

Source/WebCore:

While we would consider the unanimated style of CSS Animations specifically when considering what the "start" style values (before-change style in spec terminology)
should be when considering whether to start a CSS Transition during style resolution, we would not consider other types of animations, specifically JS-created Web
Animations. However, Web Platform Tests specifically test whether changes made using the Web Animations API may trigger transitions, and until now they would because
the RenderStyle used to determine the before-change style was the style from the previous resolution, which would include animated values.

To fix this, we make it so that KeyframeEffect objects now keep a copy of the unanimated style used when blending animated values for the very first time. That style
is cleared each time keyframes change, which is rare, but may happen through the Web Animations API. Then in AnimationTimeline::updateCSSTransitionsForElementAndProperty(),
we look for a KeyframeEffect currently affecting the property for which we're considering starting a CSS Transition, and use its unanimated style.

If that unanimated style has not been set yet, this is because the KeyframeEffect has not had a chance to apply itself with a non-null progress. In this case, the before-change
and after-change styles should be the same in order to prevent a transition from being triggered as the unanimated style for this keyframe effect will most likely be this
after-change style, or any future style change that may happen before the keyframe effect starts blending animated values.

Finally, tracking the unanimated style at the KeyframeEffect level means we no longer to track it specifically for CSSAnimation.

* animation/AnimationTimeline.cpp:
(WebCore::keyframeEffectForElementAndProperty):
(WebCore::AnimationTimeline::updateCSSTransitionsForElementAndProperty):
* animation/AnimationTimeline.h:
* animation/CSSAnimation.cpp:
(WebCore::CSSAnimation::create):
(WebCore::CSSAnimation::CSSAnimation):
* animation/CSSAnimation.h:
* animation/KeyframeEffect.cpp:
(WebCore::KeyframeEffect::animatesProperty const): Because the backing KeyframeList object may not have been created by the first time we query a KeyframeEffect during
CSS Transitions resolution, we provide a method that will check the values provided by the Web Animations API to determine whether it targets a given CSS property.
(WebCore::KeyframeEffect::clearBlendingKeyframes):
(WebCore::KeyframeEffect::computeDeclarativeAnimationBlendingKeyframes):
(WebCore::KeyframeEffect::computeCSSAnimationBlendingKeyframes):
(WebCore::KeyframeEffect::apply):
* animation/KeyframeEffect.h:
(WebCore::KeyframeEffect::unanimatedStyle const):
* style/StyleTreeResolver.cpp:
(WebCore::Style::TreeResolver::createAnimatedElementUpdate):

LayoutTests:

Mark that a couple of tests are no longer flaky.

* TestExpectations:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@256627 268f45cc-cd09-0410-ab3c-d52691b4dbfc

15 files changed:
LayoutTests/ChangeLog
LayoutTests/TestExpectations
LayoutTests/imported/w3c/ChangeLog
LayoutTests/imported/w3c/web-platform-tests/web-animations/interfaces/Animatable/animate-expected.txt
LayoutTests/imported/w3c/web-platform-tests/web-animations/interfaces/Animation/style-change-events-expected.txt
LayoutTests/imported/w3c/web-platform-tests/web-animations/interfaces/DocumentTimeline/style-change-events-expected.txt
LayoutTests/imported/w3c/web-platform-tests/web-animations/interfaces/KeyframeEffect/style-change-events-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/animation/AnimationTimeline.cpp
Source/WebCore/animation/AnimationTimeline.h
Source/WebCore/animation/CSSAnimation.cpp
Source/WebCore/animation/CSSAnimation.h
Source/WebCore/animation/KeyframeEffect.cpp
Source/WebCore/animation/KeyframeEffect.h
Source/WebCore/style/StyleTreeResolver.cpp

index 995c94b..efab961 100644 (file)
@@ -1,3 +1,15 @@
+2020-02-14  Antoine Quint  <graouts@webkit.org>
+
+        [Web Animations] Style changes due to Web Animations should not trigger CSS Transitions 
+        https://bugs.webkit.org/show_bug.cgi?id=207760
+        <rdar://problem/59458111>
+
+        Reviewed by Simon Fraser.
+
+        Mark that a couple of tests are no longer flaky.
+
+        * TestExpectations:
+
 2020-02-14  Jacob Uphoff  <jacob_uphoff@apple.com>
 
         [ macOS ] http/tests/media/now-playing-info.html is flaky failing
index e1393bb..94fce3b 100644 (file)
@@ -2654,9 +2654,6 @@ webkit.org/b/177799 accessibility/table-detection.html [ Pass Failure ]
 
 webkit.org/b/179069 imported/w3c/web-platform-tests/html/semantics/embedded-content/the-iframe-element/sandbox_032.htm [ Pass Failure ]
 
-webkit.org/b/202107 imported/w3c/web-platform-tests/web-animations/interfaces/Animation/style-change-events.html [ Pass Failure ]
-webkit.org/b/202108 imported/w3c/web-platform-tests/web-animations/interfaces/DocumentTimeline/style-change-events.html [ Pass Failure ]
-
 webkit.org/b/157068 [ Debug ] imported/w3c/web-platform-tests/fetch/nosniff/importscripts.html [ Pass Crash ]
 webkit.org/b/157068 [ Release ] imported/w3c/web-platform-tests/fetch/nosniff/importscripts.html [ Pass Failure ]
 
index fa3f081..06c751f 100644 (file)
@@ -1,5 +1,20 @@
 2020-02-14  Antoine Quint  <graouts@webkit.org>
 
+        [Web Animations] Style changes due to Web Animations should not trigger CSS Transitions 
+        https://bugs.webkit.org/show_bug.cgi?id=207760
+        <rdar://problem/59458111>
+
+        Reviewed by Simon Fraser.
+
+        Mark Web Platform Tests progressions.
+
+        * web-platform-tests/web-animations/interfaces/Animatable/animate-expected.txt:
+        * web-platform-tests/web-animations/interfaces/Animation/style-change-events-expected.txt:
+        * web-platform-tests/web-animations/interfaces/DocumentTimeline/style-change-events-expected.txt:
+        * web-platform-tests/web-animations/interfaces/KeyframeEffect/style-change-events-expected.txt:
+
+2020-02-14  Antoine Quint  <graouts@webkit.org>
+
         [Web Animations] Ensure CSS Transition and CSS Animation events are queued, sorted and dispatched by their timeline
         https://bugs.webkit.org/show_bug.cgi?id=207364
         <rdar://problem/59370413>
index 16ec853..7514426 100644 (file)
@@ -132,7 +132,7 @@ PASS Element.animate() correctly sets the id attribute
 PASS Element.animate() correctly sets the Animation's timeline 
 PASS Element.animate() correctly sets the Animation's timeline when triggered on an element in a different document 
 PASS Element.animate() calls play on the Animation 
-FAIL Element.animate() does NOT trigger a style change event assert_false: A transition should NOT have been triggered expected false got true
+PASS Element.animate() does NOT trigger a style change event 
 PASS animate() with pseudoElement parameter creates an Animation object 
 PASS animate() with pseudoElement parameter without content creates an Animation object 
 PASS animate() with pseudoElement parameter  creates an Animation object for ::marker 
index 8ce8356..188c1dc 100644 (file)
@@ -1,26 +1,26 @@
 
 PASS All property keys are recognized 
-FAIL Animation.id produces expected style change events assert_false: A transition should NOT have been triggered expected false got true
-FAIL Animation.effect produces expected style change events assert_false: A transition should NOT have been triggered expected false got true
-FAIL Animation.timeline produces expected style change events assert_false: A transition should NOT have been triggered expected false got true
-FAIL Animation.startTime produces expected style change events assert_false: A transition should NOT have been triggered expected false got true
-FAIL Animation.currentTime produces expected style change events assert_false: A transition should NOT have been triggered expected false got true
-FAIL Animation.playbackRate produces expected style change events assert_false: A transition should NOT have been triggered expected false got true
-FAIL Animation.playState produces expected style change events assert_false: A transition should NOT have been triggered expected false got true
-FAIL Animation.replaceState produces expected style change events assert_false: A transition should NOT have been triggered expected false got true
-FAIL Animation.pending produces expected style change events assert_false: A transition should NOT have been triggered expected false got true
-FAIL Animation.onfinish produces expected style change events assert_false: A transition should NOT have been triggered expected false got true
-FAIL Animation.oncancel produces expected style change events assert_false: A transition should NOT have been triggered expected false got true
-FAIL Animation.onremove produces expected style change events assert_false: A transition should NOT have been triggered expected false got true
-FAIL Animation.ready produces expected style change events assert_false: A transition should NOT have been triggered expected false got true
-FAIL Animation.finished produces expected style change events assert_false: A transition should NOT have been triggered expected false got true
-FAIL Animation.cancel produces expected style change events assert_false: A transition should NOT have been triggered expected false got true
-FAIL Animation.finish produces expected style change events assert_false: A transition should NOT have been triggered expected false got true
-FAIL Animation.play produces expected style change events assert_false: A transition should NOT have been triggered expected false got true
-FAIL Animation.pause produces expected style change events assert_false: A transition should NOT have been triggered expected false got true
-FAIL Animation.updatePlaybackRate produces expected style change events assert_false: A transition should NOT have been triggered expected false got true
-FAIL Animation.reverse produces expected style change events assert_false: A transition should NOT have been triggered expected false got true
+PASS Animation.id produces expected style change events 
+PASS Animation.effect produces expected style change events 
+PASS Animation.timeline produces expected style change events 
+PASS Animation.startTime produces expected style change events 
+PASS Animation.currentTime produces expected style change events 
+PASS Animation.playbackRate produces expected style change events 
+PASS Animation.playState produces expected style change events 
+PASS Animation.replaceState produces expected style change events 
+PASS Animation.pending produces expected style change events 
+PASS Animation.onfinish produces expected style change events 
+PASS Animation.oncancel produces expected style change events 
+PASS Animation.onremove produces expected style change events 
+PASS Animation.ready produces expected style change events 
+PASS Animation.finished produces expected style change events 
+PASS Animation.cancel produces expected style change events 
+PASS Animation.finish produces expected style change events 
+PASS Animation.play produces expected style change events 
+PASS Animation.pause produces expected style change events 
+PASS Animation.updatePlaybackRate produces expected style change events 
+PASS Animation.reverse produces expected style change events 
 FAIL Animation.persist produces expected style change events assert_false: A transition should NOT have been triggered expected false got true
 FAIL Animation.commitStyles produces expected style change events assert_true: A transition should have been triggered expected true got false
-FAIL Animation.Animation constructor produces expected style change events assert_false: A transition should NOT have been triggered expected false got true
+PASS Animation.Animation constructor produces expected style change events 
 
index 9bf6a63..3a1f8ce 100644 (file)
@@ -1,4 +1,4 @@
 
-FAIL DocumentTimeline.currentTime does NOT trigger a style change event assert_false: A transition should NOT have been triggered expected false got true
-FAIL DocumentTimeline constructor does NOT trigger a style change event assert_false: A transition should NOT have been triggered expected false got true
+PASS DocumentTimeline.currentTime does NOT trigger a style change event 
+PASS DocumentTimeline constructor does NOT trigger a style change event 
 
index 3935548..d309a47 100644 (file)
@@ -1,13 +1,13 @@
 
 FAIL All property keys are recognized assert_in_array: Test property 'pseudoElement' should be one of the properties on  KeyframeEffect value "pseudoElement" not in array ["getTiming", "getComputedTiming", "updateTiming", "target", "iterationComposite", "composite", "getKeyframes", "setKeyframes", "KeyframeEffect constructor", "KeyframeEffect copy constructor"]
-FAIL KeyframeEffect.getTiming does NOT trigger a style change event assert_false: A transition should NOT have been triggered expected false got true
-FAIL KeyframeEffect.getComputedTiming does NOT trigger a style change event assert_false: A transition should NOT have been triggered expected false got true
-FAIL KeyframeEffect.updateTiming does NOT trigger a style change event assert_false: A transition should NOT have been triggered expected false got true
-FAIL KeyframeEffect.target does NOT trigger a style change event assert_false: A transition should NOT have been triggered expected false got true
-FAIL KeyframeEffect.iterationComposite does NOT trigger a style change event assert_false: A transition should NOT have been triggered expected false got true
-FAIL KeyframeEffect.composite does NOT trigger a style change event assert_false: A transition should NOT have been triggered expected false got true
-FAIL KeyframeEffect.getKeyframes does NOT trigger a style change event assert_false: A transition should NOT have been triggered expected false got true
-FAIL KeyframeEffect.setKeyframes does NOT trigger a style change event assert_false: A transition should NOT have been triggered expected false got true
-FAIL KeyframeEffect.KeyframeEffect constructor does NOT trigger a style change event assert_false: A transition should NOT have been triggered expected false got true
-FAIL KeyframeEffect.KeyframeEffect copy constructor does NOT trigger a style change event assert_false: A transition should NOT have been triggered expected false got true
+PASS KeyframeEffect.getTiming does NOT trigger a style change event 
+PASS KeyframeEffect.getComputedTiming does NOT trigger a style change event 
+PASS KeyframeEffect.updateTiming does NOT trigger a style change event 
+PASS KeyframeEffect.target does NOT trigger a style change event 
+PASS KeyframeEffect.iterationComposite does NOT trigger a style change event 
+PASS KeyframeEffect.composite does NOT trigger a style change event 
+PASS KeyframeEffect.getKeyframes does NOT trigger a style change event 
+PASS KeyframeEffect.setKeyframes does NOT trigger a style change event 
+PASS KeyframeEffect.KeyframeEffect constructor does NOT trigger a style change event 
+PASS KeyframeEffect.KeyframeEffect copy constructor does NOT trigger a style change event 
 
index 8935888..c1ca216 100644 (file)
@@ -1,3 +1,46 @@
+2020-02-14  Antoine Quint  <graouts@webkit.org>
+
+        [Web Animations] Style changes due to Web Animations should not trigger CSS Transitions 
+        https://bugs.webkit.org/show_bug.cgi?id=207760
+        <rdar://problem/59458111>
+
+        Reviewed by Simon Fraser.
+
+        While we would consider the unanimated style of CSS Animations specifically when considering what the "start" style values (before-change style in spec terminology)
+        should be when considering whether to start a CSS Transition during style resolution, we would not consider other types of animations, specifically JS-created Web
+        Animations. However, Web Platform Tests specifically test whether changes made using the Web Animations API may trigger transitions, and until now they would because
+        the RenderStyle used to determine the before-change style was the style from the previous resolution, which would include animated values.
+
+        To fix this, we make it so that KeyframeEffect objects now keep a copy of the unanimated style used when blending animated values for the very first time. That style
+        is cleared each time keyframes change, which is rare, but may happen through the Web Animations API. Then in AnimationTimeline::updateCSSTransitionsForElementAndProperty(),
+        we look for a KeyframeEffect currently affecting the property for which we're considering starting a CSS Transition, and use its unanimated style.
+
+        If that unanimated style has not been set yet, this is because the KeyframeEffect has not had a chance to apply itself with a non-null progress. In this case, the before-change
+        and after-change styles should be the same in order to prevent a transition from being triggered as the unanimated style for this keyframe effect will most likely be this
+        after-change style, or any future style change that may happen before the keyframe effect starts blending animated values.
+
+        Finally, tracking the unanimated style at the KeyframeEffect level means we no longer to track it specifically for CSSAnimation.
+
+        * animation/AnimationTimeline.cpp:
+        (WebCore::keyframeEffectForElementAndProperty):
+        (WebCore::AnimationTimeline::updateCSSTransitionsForElementAndProperty):
+        * animation/AnimationTimeline.h:
+        * animation/CSSAnimation.cpp:
+        (WebCore::CSSAnimation::create):
+        (WebCore::CSSAnimation::CSSAnimation):
+        * animation/CSSAnimation.h:
+        * animation/KeyframeEffect.cpp:
+        (WebCore::KeyframeEffect::animatesProperty const): Because the backing KeyframeList object may not have been created by the first time we query a KeyframeEffect during
+        CSS Transitions resolution, we provide a method that will check the values provided by the Web Animations API to determine whether it targets a given CSS property.
+        (WebCore::KeyframeEffect::clearBlendingKeyframes):
+        (WebCore::KeyframeEffect::computeDeclarativeAnimationBlendingKeyframes):
+        (WebCore::KeyframeEffect::computeCSSAnimationBlendingKeyframes):
+        (WebCore::KeyframeEffect::apply):
+        * animation/KeyframeEffect.h:
+        (WebCore::KeyframeEffect::unanimatedStyle const):
+        * style/StyleTreeResolver.cpp:
+        (WebCore::Style::TreeResolver::createAnimatedElementUpdate):
+
 2020-02-14  Sunny He  <sunny_he@apple.com>
 
         Ensure animations that lose their effect don't schedule an animation update
index 6cb77e8..1dbc2e4 100644 (file)
@@ -352,15 +352,17 @@ void AnimationTimeline::updateCSSAnimationsForElement(Element& element, const Re
     keyframeEffectStack.setCSSAnimationList(currentAnimationList);
 }
 
-RefPtr<WebAnimation> AnimationTimeline::cssAnimationForElementAndProperty(Element& element, CSSPropertyID property)
+static KeyframeEffect* keyframeEffectForElementAndProperty(Element& element, CSSPropertyID property)
 {
-    RefPtr<WebAnimation> matchingAnimation;
-    for (const auto& animation : m_elementToCSSAnimationsMap.get(&element)) {
-        auto* effect = animation->effect();
-        if (is<KeyframeEffect>(effect) && downcast<KeyframeEffect>(effect)->animatedProperties().contains(property))
-            matchingAnimation = animation;
+    if (auto* keyframeEffectStack = element.keyframeEffectStack()) {
+        auto effects = keyframeEffectStack->sortedEffects();
+        for (const auto& effect : makeReversedRange(effects)) {
+            if (effect->animatesProperty(property))
+                return effect.get();
+        }
     }
-    return matchingAnimation;
+
+    return nullptr;
 }
 
 static bool propertyInStyleMatchesValueForTransitionInMap(CSSPropertyID property, const RenderStyle& style, AnimationTimeline::PropertyToTransitionMap& transitions)
@@ -460,9 +462,21 @@ void AnimationTimeline::updateCSSTransitionsForElementAndProperty(Element& eleme
             }
         }
 
-        if (auto existingAnimation = cssAnimationForElementAndProperty(element, property))
-            return downcast<CSSAnimation>(existingAnimation.get())->unanimatedStyle();
+        if (auto* keyframeEffect = keyframeEffectForElementAndProperty(element, property)) {
+            // If we already have a keyframe effect targeting this property, we should use its unanimated style to determine what the potential
+            // start value of the transition shoud be to make sure that we don't account for animated values that would have been blended onto
+            // the style applied during the last style resolution.
+            if (auto* unanimatedStyle = keyframeEffect->unanimatedStyle())
+                return *unanimatedStyle;
+
+            // If we have a keyframe effect targeting this property, but it doesn't yet have an unanimated style, this is because it has not
+            // had a chance to apply itself with a non-null progress. In this case, the before-change and after-change styles should be the
+            // same in order to prevent a transition from being triggered as the unanimated style for this keyframe effect will most likely
+            // be this after-change style, or any future style change that may happen before the keyframe effect starts blending animated values.
+            return afterChangeStyle;
+        }
 
+        // In any other scenario, the before-change style should be the previously resolved style for this element.
         return currentStyle;
     }();
 
index 7b8a8b8..eb21ac8 100644 (file)
@@ -88,7 +88,6 @@ private:
     using ElementToCSSAnimationsMap = HashMap<Element*, CSSAnimationCollection>;
 
     void updateGlobalPosition(WebAnimation&);
-    RefPtr<WebAnimation> cssAnimationForElementAndProperty(Element&, CSSPropertyID);
     PropertyToTransitionMap& ensureRunningTransitionsByProperty(Element&);
     void updateCSSTransitionsForElementAndProperty(Element&, CSSPropertyID, const RenderStyle& currentStyle, const RenderStyle& afterChangeStyle, PropertyToTransitionMap&, PropertyToTransitionMap&, const MonotonicTime);
     void removeCSSAnimationCreatedByMarkup(Element&, CSSAnimation&);
index fecf02a..2d1b3a5 100644 (file)
@@ -39,7 +39,7 @@ WTF_MAKE_ISO_ALLOCATED_IMPL(CSSAnimation);
 
 Ref<CSSAnimation> CSSAnimation::create(Element& owningElement, const Animation& backingAnimation, const RenderStyle* oldStyle, const RenderStyle& newStyle)
 {
-    auto result = adoptRef(*new CSSAnimation(owningElement, backingAnimation, newStyle));
+    auto result = adoptRef(*new CSSAnimation(owningElement, backingAnimation));
     result->initialize(oldStyle, newStyle);
 
     InspectorInstrumentation::didCreateWebAnimation(result.get());
@@ -47,10 +47,9 @@ Ref<CSSAnimation> CSSAnimation::create(Element& owningElement, const Animation&
     return result;
 }
 
-CSSAnimation::CSSAnimation(Element& element, const Animation& backingAnimation, const RenderStyle& unanimatedStyle)
+CSSAnimation::CSSAnimation(Element& element, const Animation& backingAnimation)
     : DeclarativeAnimation(element, backingAnimation)
     , m_animationName(backingAnimation.name())
-    , m_unanimatedStyle(RenderStyle::clonePtr(unanimatedStyle))
 {
 }
 
index 22e8d15..cbe0b42 100644 (file)
@@ -42,7 +42,6 @@ public:
 
     bool isCSSAnimation() const override { return true; }
     const String& animationName() const { return m_animationName; }
-    const RenderStyle& unanimatedStyle() const { return *m_unanimatedStyle; }
 
     ExceptionOr<void> bindingsPlay() final;
     ExceptionOr<void> bindingsPause() final;
@@ -52,10 +51,9 @@ protected:
     Ref<AnimationEventBase> createEvent(const AtomString& eventType, double elapsedTime, const String& pseudoId, Optional<Seconds> timelineTime) final;
 
 private:
-    CSSAnimation(Element&, const Animation&, const RenderStyle&);
+    CSSAnimation(Element&, const Animation&);
 
     String m_animationName;
-    std::unique_ptr<RenderStyle> m_unanimatedStyle;
     bool m_stickyPaused { false };
 };
 
index b31cef6..09ecd7a 100644 (file)
@@ -771,6 +771,20 @@ void KeyframeEffect::updateBlendingKeyframes(RenderStyle& elementStyle)
     setBlendingKeyframes(keyframeList);
 }
 
+bool KeyframeEffect::animatesProperty(CSSPropertyID property) const
+{
+    if (!m_blendingKeyframes.isEmpty())
+        return m_blendingKeyframes.properties().contains(property);
+
+    for (auto& keyframe : m_parsedKeyframes) {
+        for (auto keyframeProperty : keyframe.unparsedStyle.keys()) {
+            if (keyframeProperty == property)
+                return true;
+        }
+    }
+    return false;
+}
+
 bool KeyframeEffect::forceLayoutIfNeeded()
 {
     if (!m_needsForcedLayout || !m_target)
@@ -792,6 +806,7 @@ bool KeyframeEffect::forceLayoutIfNeeded()
 void KeyframeEffect::clearBlendingKeyframes()
 {
     m_blendingKeyframesSource = BlendingKeyframesSource::WebAnimation;
+    m_unanimatedStyle = nullptr;
     m_blendingKeyframes.clear();
 }
 
@@ -910,12 +925,12 @@ void KeyframeEffect::computeDeclarativeAnimationBlendingKeyframes(const RenderSt
 {
     ASSERT(is<DeclarativeAnimation>(animation()));
     if (is<CSSAnimation>(animation()))
-        computeCSSAnimationBlendingKeyframes();
+        computeCSSAnimationBlendingKeyframes(newStyle);
     else if (is<CSSTransition>(animation()))
         computeCSSTransitionBlendingKeyframes(oldStyle, newStyle);
 }
 
-void KeyframeEffect::computeCSSAnimationBlendingKeyframes()
+void KeyframeEffect::computeCSSAnimationBlendingKeyframes(const RenderStyle& unanimatedStyle)
 {
     ASSERT(is<CSSAnimation>(animation()));
 
@@ -924,7 +939,7 @@ void KeyframeEffect::computeCSSAnimationBlendingKeyframes()
 
     KeyframeList keyframeList(backingAnimation.name());
     if (auto* styleScope = Style::Scope::forOrdinal(*m_target, backingAnimation.nameStyleScopeOrdinal()))
-        styleScope->resolver().keyframeStylesForAnimation(*m_target, &cssAnimation->unanimatedStyle(), keyframeList);
+        styleScope->resolver().keyframeStylesForAnimation(*m_target, &unanimatedStyle, keyframeList);
 
     // Ensure resource loads for all the frames.
     for (auto& keyframe : keyframeList.keyframes()) {
@@ -1091,6 +1106,9 @@ void KeyframeEffect::apply(RenderStyle& targetStyle)
     if (!computedTiming.progress)
         return;
 
+    if (!m_unanimatedStyle)
+        m_unanimatedStyle = RenderStyle::clonePtr(targetStyle);
+
     setAnimatedPropertiesInStyle(targetStyle, computedTiming.progress.value());
 }
 
index e88d225..b28558a 100644 (file)
@@ -144,6 +144,7 @@ public:
     void computeDeclarativeAnimationBlendingKeyframes(const RenderStyle* oldStyle, const RenderStyle& newStyle);
     const KeyframeList& blendingKeyframes() const { return m_blendingKeyframes; }
     const HashSet<CSSPropertyID>& animatedProperties() const { return m_blendingKeyframes.properties(); }
+    bool animatesProperty(CSSPropertyID) const;
 
     bool computeExtentOfTransformAnimation(LayoutRect&) const;
     bool computeTransformedExtentViaTransformList(const FloatRect&, const RenderStyle&, LayoutRect&) const;
@@ -154,6 +155,8 @@ public:
     bool isCurrentlyAffectingProperty(CSSPropertyID, Accelerated = Accelerated::No) const;
     bool isRunningAcceleratedAnimationForProperty(CSSPropertyID) const;
 
+    const RenderStyle* unanimatedStyle() const { return m_unanimatedStyle.get(); }
+
 private:
     KeyframeEffect(Element*);
 
@@ -173,7 +176,7 @@ private:
     void computeStackingContextImpact();
     void clearBlendingKeyframes();
     void updateBlendingKeyframes(RenderStyle&);
-    void computeCSSAnimationBlendingKeyframes();
+    void computeCSSAnimationBlendingKeyframes(const RenderStyle&);
     void computeCSSTransitionBlendingKeyframes(const RenderStyle* oldStyle, const RenderStyle& newStyle);
     void computeAcceleratedPropertiesState();
     void setBlendingKeyframes(KeyframeList&);
@@ -190,6 +193,8 @@ private:
     Vector<AcceleratedAction> m_pendingAcceleratedActions;
     RefPtr<Element> m_target;
 
+    std::unique_ptr<const RenderStyle> m_unanimatedStyle;
+
     AcceleratedAction m_lastRecordedAcceleratedAction { AcceleratedAction::Stop };
     BlendingKeyframesSource m_blendingKeyframesSource { BlendingKeyframesSource::WebAnimation };
     IterationCompositeOperation m_iterationCompositeOperation { IterationCompositeOperation::Replace };
index 7a30c6c..9f0c32a 100644 (file)
@@ -306,7 +306,7 @@ const RenderStyle* TreeResolver::parentBoxStyleForPseudo(const ElementUpdate& el
 ElementUpdate TreeResolver::createAnimatedElementUpdate(std::unique_ptr<RenderStyle> newStyle, Element& element, Change parentChange)
 {
     auto* oldStyle = element.renderOrDisplayContentsStyle();
-    
+
     OptionSet<AnimationImpact> animationImpact;
 
     // New code path for CSS Animations and CSS Transitions.