Title: [263506] trunk
Revision
263506
Author
[email protected]
Date
2020-06-25 06:42:02 -0700 (Thu, 25 Jun 2020)

Log Message

REGRESSION (r260360): easing curves are broken on JS-originated animations
https://bugs.webkit.org/show_bug.cgi?id=213495
<rdar://problem/64649747>

Reviewed by Darin Adler.

Source/WebCore:

Prior to Web Animations, there was no way for an animation to set an animation-wide timing function while
also setting a per-keyframe timing function. As such GraphicsLayerCA would sometimes decide to set the
timing function on keyframes or on the entire CAAnimation. However, we can no longer do this with Web
Animations where an animation can set an animation-wide timing function and also keyframe-specific
timing functions.

In this patch we create CAKeyframeAnimation objects for any animation that has at least two keyframes
if Web Animations are enabled, whereas the legacy code path requires at least three keyframes. We allow
PlatformCAAnimation::setTimingFunction() to be called in the Web Animations code path only under
GraphicsLayerCA::setupAnimation() while leaving the only call sites in place only for the legacy code
path.

Finally, we modify GraphicsLayerCA::timingFunctionForAnimationValue() to only ever return a keyframe-
specific timing function or fall back to a default linear timing function in the Web Animations code
path, leaving the function to behave the same way as it used to in the legacy code path.

Test: webanimations/accelerated-animation-with-easing.html

* platform/animation/TimingFunction.h:
* platform/graphics/ca/GraphicsLayerCA.cpp:
(WebCore::isKeyframe):
(WebCore::GraphicsLayerCA::createAnimationFromKeyframes):
(WebCore::GraphicsLayerCA::appendToUncommittedAnimations):
(WebCore::GraphicsLayerCA::createTransformAnimationsFromKeyframes):

LayoutTests:

Add a new test that checks that various ways of setting the easing timing function on a JS-originated
animation always yield the same visible animation behavior.

* webanimations/accelerated-animation-with-easing-expected.html: Added.
* webanimations/accelerated-animation-with-easing.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (263505 => 263506)


--- trunk/LayoutTests/ChangeLog	2020-06-25 13:09:27 UTC (rev 263505)
+++ trunk/LayoutTests/ChangeLog	2020-06-25 13:42:02 UTC (rev 263506)
@@ -1,3 +1,17 @@
+2020-06-25  Antoine Quint  <[email protected]>
+
+        REGRESSION (r260360): easing curves are broken on JS-originated animations
+        https://bugs.webkit.org/show_bug.cgi?id=213495
+        <rdar://problem/64649747>
+
+        Reviewed by Darin Adler.
+
+        Add a new test that checks that various ways of setting the easing timing function on a JS-originated
+        animation always yield the same visible animation behavior.
+
+        * webanimations/accelerated-animation-with-easing-expected.html: Added.
+        * webanimations/accelerated-animation-with-easing.html: Added.
+
 2020-06-24  Sergio Villar Senin  <[email protected]>
 
         Make video-inside-flex-item.html more robust

Added: trunk/LayoutTests/webanimations/accelerated-animation-with-easing-expected.html (0 => 263506)


--- trunk/LayoutTests/webanimations/accelerated-animation-with-easing-expected.html	                        (rev 0)
+++ trunk/LayoutTests/webanimations/accelerated-animation-with-easing-expected.html	2020-06-25 13:42:02 UTC (rev 263506)
@@ -0,0 +1,2 @@
+<body style="background-color: green">
+</body>

Added: trunk/LayoutTests/webanimations/accelerated-animation-with-easing.html (0 => 263506)


--- trunk/LayoutTests/webanimations/accelerated-animation-with-easing.html	                        (rev 0)
+++ trunk/LayoutTests/webanimations/accelerated-animation-with-easing.html	2020-06-25 13:42:02 UTC (rev 263506)
@@ -0,0 +1,84 @@
+<body>
+<style>
+    
+    body {
+        background-color: green;
+    }
+    
+    div {
+        position: absolute;
+        top: 0;
+        left: 0;
+        width: 100px;
+        height: 100px;
+        background-color: red;
+    }
+
+    /* Allow for a 1px error on either side */
+    #easing-on-keyframe {
+        left: -1px;
+        width: 102px;
+        background-color: green;
+    }
+
+</style>
+<div id="easing-on-animation-one-keyframe"></div>
+<div id="easing-on-animation-two-keyframes"></div>
+<div id="easing-on-animation-three-keyframes"></div>
+<div id="easing-on-keyframe"></div>
+<script>
+
+(async function() {
+    if (window.testRunner)
+        testRunner.waitUntilDone();
+
+    const animations = [];
+
+    animations.push(document.getElementById("easing-on-animation-one-keyframe").animate({ transform: "translateX(100px)" }, {
+        duration: 500,
+        easing: "ease",
+        direction: "alternate",
+        iterations: Infinity
+    }));
+
+    animations.push(document.getElementById("easing-on-animation-two-keyframes").animate([
+        { transform: "translateX(0)" },
+        { transform: "translateX(100px)" }
+    ], {
+        duration: 500,
+        easing: "ease",
+        direction: "alternate",
+        iterations: Infinity
+    }));
+
+    animations.push(document.getElementById("easing-on-animation-three-keyframes").animate([
+        { transform: "translateX(0)" },
+        { transform: "translateX(50px)" },
+        { transform: "translateX(100px)" }
+    ], {
+        duration: 500,
+        easing: "ease",
+        direction: "alternate",
+        iterations: Infinity
+    }));
+
+    animations.push(document.getElementById("easing-on-keyframe").animate([
+        { transform: "translateX(0)", easing: "ease" },
+        { transform: "translateX(100px)" }
+    ], {
+        duration: 500,
+        direction: "alternate",
+        iterations: Infinity
+    }));
+
+    await Promise.all(animations.map(animation => animation.ready));
+    await new Promise(requestAnimationFrame);
+    await new Promise(requestAnimationFrame);
+    await new Promise(requestAnimationFrame);
+
+    if (window.testRunner)
+        testRunner.notifyDone();
+})();
+
+</script>
+</body>

Modified: trunk/Source/WebCore/ChangeLog (263505 => 263506)


--- trunk/Source/WebCore/ChangeLog	2020-06-25 13:09:27 UTC (rev 263505)
+++ trunk/Source/WebCore/ChangeLog	2020-06-25 13:42:02 UTC (rev 263506)
@@ -1,3 +1,36 @@
+2020-06-25  Antoine Quint  <[email protected]>
+
+        REGRESSION (r260360): easing curves are broken on JS-originated animations
+        https://bugs.webkit.org/show_bug.cgi?id=213495
+        <rdar://problem/64649747>
+
+        Reviewed by Darin Adler.
+
+        Prior to Web Animations, there was no way for an animation to set an animation-wide timing function while
+        also setting a per-keyframe timing function. As such GraphicsLayerCA would sometimes decide to set the
+        timing function on keyframes or on the entire CAAnimation. However, we can no longer do this with Web
+        Animations where an animation can set an animation-wide timing function and also keyframe-specific
+        timing functions.
+
+        In this patch we create CAKeyframeAnimation objects for any animation that has at least two keyframes
+        if Web Animations are enabled, whereas the legacy code path requires at least three keyframes. We allow
+        PlatformCAAnimation::setTimingFunction() to be called in the Web Animations code path only under
+        GraphicsLayerCA::setupAnimation() while leaving the only call sites in place only for the legacy code
+        path.
+
+        Finally, we modify GraphicsLayerCA::timingFunctionForAnimationValue() to only ever return a keyframe-
+        specific timing function or fall back to a default linear timing function in the Web Animations code
+        path, leaving the function to behave the same way as it used to in the legacy code path. 
+
+        Test: webanimations/accelerated-animation-with-easing.html
+
+        * platform/animation/TimingFunction.h:
+        * platform/graphics/ca/GraphicsLayerCA.cpp:
+        (WebCore::isKeyframe):
+        (WebCore::GraphicsLayerCA::createAnimationFromKeyframes):
+        (WebCore::GraphicsLayerCA::appendToUncommittedAnimations):
+        (WebCore::GraphicsLayerCA::createTransformAnimationsFromKeyframes):
+
 2020-06-25  Sergio Villar Senin  <[email protected]>
 
         Unreviewed, WPE Debug build fix after r263503.

Modified: trunk/Source/WebCore/platform/animation/TimingFunction.h (263505 => 263506)


--- trunk/Source/WebCore/platform/animation/TimingFunction.h	2020-06-25 13:09:27 UTC (rev 263505)
+++ trunk/Source/WebCore/platform/animation/TimingFunction.h	2020-06-25 13:42:02 UTC (rev 263506)
@@ -80,6 +80,12 @@
         return is<LinearTimingFunction>(other);
     }
 
+    static const LinearTimingFunction& sharedLinearTimingFunction()
+    {
+        static const LinearTimingFunction& function = create().leakRef();
+        return function;
+    }
+
 private:
     LinearTimingFunction()
         : TimingFunction(LinearFunction)

Modified: trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp (263505 => 263506)


--- trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp	2020-06-25 13:09:27 UTC (rev 263505)
+++ trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp	2020-06-25 13:42:02 UTC (rev 263506)
@@ -41,6 +41,7 @@
 #include "PlatformScreen.h"
 #include "Region.h"
 #include "RotateTransformOperation.h"
+#include "RuntimeEnabledFeatures.h"
 #include "ScaleTransformOperation.h"
 #include "TiledBacking.h"
 #include "TransformState.h"
@@ -3073,11 +3074,17 @@
         m_contentsLayer->setNeedsDisplay();
 }
 
+static bool isKeyframe(const KeyframeValueList& list)
+{
+    if (RuntimeEnabledFeatures::sharedFeatures().webAnimationsCSSIntegrationEnabled())
+        return list.size() > 1;
+    return list.size() > 2;
+}
+
 bool GraphicsLayerCA::createAnimationFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& animationName, Seconds timeOffset)
 {
     ASSERT(valueList.property() != AnimatedPropertyTransform && (!supportsAcceleratedFilterAnimations() || valueList.property() != AnimatedPropertyFilter));
 
-    bool isKeyframe = valueList.size() > 2;
     bool valuesOK;
     
     bool additive = false;
@@ -3085,7 +3092,7 @@
     
     RefPtr<PlatformCAAnimation> caAnimation;
 
-    if (isKeyframe) {
+    if (isKeyframe(valueList)) {
         caAnimation = createKeyframeAnimation(animation, propertyIdToString(valueList.property()), additive);
         valuesOK = setAnimationKeyframes(valueList, animation, caAnimation.get());
     } else {
@@ -3113,11 +3120,10 @@
     int numAnimations = isMatrixAnimation ? 1 : operations->size();
     bool additive = animationIndex < numAnimations - 1;
 #endif
-    bool isKeyframe = valueList.size() > 2;
 
     RefPtr<PlatformCAAnimation> caAnimation;
     bool validMatrices = true;
-    if (isKeyframe) {
+    if (isKeyframe(valueList)) {
         caAnimation = createKeyframeAnimation(animation, propertyIdToString(valueList.property()), additive);
         validMatrices = setTransformAnimationKeyframes(valueList, animation, caAnimation.get(), animationIndex, transformOp, isMatrixAnimation, boxSize);
     } else {
@@ -3166,8 +3172,6 @@
 
 bool GraphicsLayerCA::appendToUncommittedAnimations(const KeyframeValueList& valueList, const FilterOperation* operation, const Animation* animation, const String& animationName, int animationIndex, Seconds timeOffset)
 {
-    bool isKeyframe = valueList.size() > 2;
-    
     FilterOperation::OperationType filterOp = operation->type();
     int numAnimatedProperties = PlatformCAFilters::numAnimatedFilterProperties(filterOp);
     
@@ -3183,7 +3187,7 @@
         RefPtr<PlatformCAAnimation> caAnimation;
         String keyPath = makeString("filters.filter_", animationIndex, '.', PlatformCAFilters::animatedFilterPropertyName(filterOp, internalFilterPropertyIndex));
         
-        if (isKeyframe) {
+        if (isKeyframe(valueList)) {
             caAnimation = createKeyframeAnimation(animation, keyPath, false);
             valuesOK = setFilterAnimationKeyframes(valueList, animation, caAnimation.get(), animationIndex, internalFilterPropertyIndex, filterOp);
         } else {
@@ -3324,10 +3328,19 @@
     propertyAnim->setRemovedOnCompletion(false);
     propertyAnim->setAdditive(additive);
     propertyAnim->setFillMode(fillMode);
+
+    if (RuntimeEnabledFeatures::sharedFeatures().webAnimationsCSSIntegrationEnabled())
+        propertyAnim->setTimingFunction(anim->timingFunction());
 }
 
 const TimingFunction& GraphicsLayerCA::timingFunctionForAnimationValue(const AnimationValue& animValue, const Animation& anim)
 {
+    if (RuntimeEnabledFeatures::sharedFeatures().webAnimationsCSSIntegrationEnabled()) {
+        if (animValue.timingFunction())
+            return *animValue.timingFunction();
+        return LinearTimingFunction::sharedLinearTimingFunction();
+    }
+
     if (animValue.timingFunction())
         return *animValue.timingFunction();
     if (anim.isTimingFunctionSet())
@@ -3355,7 +3368,8 @@
 
     // This codepath is used for 2-keyframe animations, so we still need to look in the start
     // for a timing function. Even in the reversing animation case, the first keyframe provides the timing function.
-    basicAnim->setTimingFunction(&timingFunctionForAnimationValue(valueList.at(0), *animation), !forwards);
+    if (!RuntimeEnabledFeatures::sharedFeatures().webAnimationsCSSIntegrationEnabled())
+        basicAnim->setTimingFunction(&timingFunctionForAnimationValue(valueList.at(0), *animation), !forwards);
 
     return true;
 }
@@ -3448,7 +3462,8 @@
 
     // This codepath is used for 2-keyframe animations, so we still need to look in the start
     // for a timing function. Even in the reversing animation case, the first keyframe provides the timing function.
-    basicAnim->setTimingFunction(&timingFunctionForAnimationValue(valueList.at(0), *animation), !forwards);
+    if (!RuntimeEnabledFeatures::sharedFeatures().webAnimationsCSSIntegrationEnabled())
+        basicAnim->setTimingFunction(&timingFunctionForAnimationValue(valueList.at(0), *animation), !forwards);
 
     auto valueFunction = getValueFunctionNameForTransformOperation(transformOpType);
     if (valueFunction != PlatformCAAnimation::NoValueFunction)
@@ -3558,7 +3573,8 @@
 
     // This codepath is used for 2-keyframe animations, so we still need to look in the start
     // for a timing function. Even in the reversing animation case, the first keyframe provides the timing function.
-    basicAnim->setTimingFunction(&timingFunctionForAnimationValue(valueList.at(0), *animation), !forwards);
+    if (!RuntimeEnabledFeatures::sharedFeatures().webAnimationsCSSIntegrationEnabled())
+        basicAnim->setTimingFunction(&timingFunctionForAnimationValue(valueList.at(0), *animation), !forwards);
 
     return true;
 }
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to