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/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;
}