Title: [227622] trunk
Revision
227622
Author
grao...@webkit.org
Date
2018-01-25 12:21:47 -0800 (Thu, 25 Jan 2018)

Log Message

[Web Animations] Account for provided easings when computing progress and resolving keyframe effect values
https://bugs.webkit.org/show_bug.cgi?id=182098
<rdar://problem/36866149>

Reviewed by Dean Jackson.

LayoutTests/imported/w3c:

Update expected values with a few adjusted failures and many progressions.

* web-platform-tests/css-timing-1/step-timing-functions-output-expected.txt:
* web-platform-tests/web-animations/animation-model/keyframe-effects/effect-value-iteration-composite-operation-expected.txt:
* web-platform-tests/web-animations/interfaces/Animation/effect-expected.txt:
* web-platform-tests/web-animations/interfaces/AnimationEffectTiming/easing-expected.txt:
* web-platform-tests/web-animations/interfaces/KeyframeEffect/iterationComposite-expected.txt:
* web-platform-tests/web-animations/timing-model/time-transformations/transformed-progress-expected.txt:

Source/WebCore:

We now account for the timing functions provided through the "easing" propreties on whole animation effects
and individual keyframes. Exposing those exposed shortcomings of our keyframe resolution in general through
WPT tests so we now implement the "effect value of a keyframe effect" procedure from the spec to correctly
resolve keyframes in KeyframeEffect::setAnimatedPropertiesInStyle(). The tests also showed some shortcomings
in our TimingFunction code where our step() function resolution wasn't fully compliant and our cubic-bezier()
resolution not accurate enough. We now have microsecond accuracy when resolving cubic-bezier() timing functions
and identify cubic-bezier(0, 0, 0, 0), cubic-bezier(0, 0, 1, 1) and cubic-bezier(1, 1, 1, 1) as linear timing
functions, as called out by the WPT tests.

* animation/AnimationEffect.cpp:
(WebCore::AnimationEffect::transformedProgress const): Account for the effect-wide timing function when computing
the progress.
(WebCore::AnimationEffect::iterationProgress const): Use the transformed progress now that we support this procedure.
* animation/AnimationEffect.h:
* animation/KeyframeEffect.cpp:
(WebCore::KeyframeEffect::apply): We now use the computed progress from AnimationEffect rather than compute based
on the provided time, which we've dropped as an argument.
(WebCore::KeyframeEffect::getAnimatedStyle):
(WebCore::KeyframeEffect::setAnimatedPropertiesInStyle): Implement the "effect value of a keyframe effect" procedure
in full as specified (save for composite operations).
(WebCore::KeyframeEffect::applyAtLocalTime): Deleted.
* animation/KeyframeEffect.h:
* animation/WebAnimation.cpp:
(WebCore::WebAnimation::resolve):
* css/CSSTimingFunctionValue.h: Fix a small error made in a previous patch where we used "int" instead of "unsigned".
* platform/animation/TimingFunction.cpp:
(WebCore::TimingFunction::transformTime const):
* platform/animation/TimingFunction.h:

LayoutTests:

Update an animated value due to more accurate resolution of cubic-bezier() timing functions.

* platform/mac/transitions/default-timing-function-expected.txt:

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (227621 => 227622)


--- trunk/LayoutTests/ChangeLog	2018-01-25 20:13:41 UTC (rev 227621)
+++ trunk/LayoutTests/ChangeLog	2018-01-25 20:21:47 UTC (rev 227622)
@@ -1,3 +1,15 @@
+2018-01-25  Antoine Quint  <grao...@apple.com>
+
+        [Web Animations] Account for provided easings when computing progress and resolving keyframe effect values
+        https://bugs.webkit.org/show_bug.cgi?id=182098
+        <rdar://problem/36866149>
+
+        Reviewed by Dean Jackson.
+
+        Update an animated value due to more accurate resolution of cubic-bezier() timing functions.
+
+        * platform/mac/transitions/default-timing-function-expected.txt:
+
 2018-01-25  Per Arne Vollan  <pvol...@apple.com>
 
         [Win] Update test expectations.

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (227621 => 227622)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2018-01-25 20:13:41 UTC (rev 227621)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2018-01-25 20:21:47 UTC (rev 227622)
@@ -1,3 +1,20 @@
+2018-01-25  Antoine Quint  <grao...@apple.com>
+
+        [Web Animations] Account for provided easings when computing progress and resolving keyframe effect values
+        https://bugs.webkit.org/show_bug.cgi?id=182098
+        <rdar://problem/36866149>
+
+        Reviewed by Dean Jackson.
+
+        Update expected values with a few adjusted failures and many progressions.
+
+        * web-platform-tests/css-timing-1/step-timing-functions-output-expected.txt:
+        * web-platform-tests/web-animations/animation-model/keyframe-effects/effect-value-iteration-composite-operation-expected.txt:
+        * web-platform-tests/web-animations/interfaces/Animation/effect-expected.txt:
+        * web-platform-tests/web-animations/interfaces/AnimationEffectTiming/easing-expected.txt:
+        * web-platform-tests/web-animations/interfaces/KeyframeEffect/iterationComposite-expected.txt:
+        * web-platform-tests/web-animations/timing-model/time-transformations/transformed-progress-expected.txt:
+
 2018-01-25  Youenn Fablet  <you...@apple.com>
 
         Set integrity fetch options for loading scripts and CSS

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/css-timing-1/step-timing-functions-output-expected.txt (227621 => 227622)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css-timing-1/step-timing-functions-output-expected.txt	2018-01-25 20:13:41 UTC (rev 227621)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css-timing-1/step-timing-functions-output-expected.txt	2018-01-25 20:21:47 UTC (rev 227622)
@@ -1,8 +1,8 @@
 
-FAIL step-start easing with input progress greater than 1 assert_equals: expected "100px" but got "0px"
+FAIL step-start easing with input progress greater than 1 assert_equals: expected "200px" but got "100px"
 FAIL step-end easing with input progress greater than 1 assert_equals: expected "100px" but got "0px"
 FAIL step-end easing with input progress greater than 2 assert_equals: expected "200px" but got "0px"
-FAIL step-start easing with input progress less than 0 assert_equals: expected "100px" but got "0px"
-FAIL step-start easing with input progress less than -1 assert_equals: expected "100px" but got "0px"
+FAIL step-start easing with input progress less than 0 assert_equals: expected "0px" but got "100px"
+FAIL step-start easing with input progress less than -1 assert_equals: expected "0px" but got "100px"
 FAIL step-end easing with input progress less than 0 assert_equals: expected "-100px" but got "0px"
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/web-animations/animation-model/keyframe-effects/effect-value-iteration-composite-operation-expected.txt (227621 => 227622)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/web-animations/animation-model/keyframe-effects/effect-value-iteration-composite-operation-expected.txt	2018-01-25 20:13:41 UTC (rev 227621)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/web-animations/animation-model/keyframe-effects/effect-value-iteration-composite-operation-expected.txt	2018-01-25 20:21:47 UTC (rev 227622)
@@ -15,7 +15,7 @@
 FAIL iteration composition of filter brightness animation assert_equals: Animated filter brightness style at 50s of the first iteration expected "brightness(0.5)" but got "brightness(1)"
 FAIL iteration composition of filter drop-shadow animation assert_equals: Animated filter drop-shadow style at 50s of the first iteration expected "drop-shadow(rgb(60, 60, 60) 5px 5px 5px)" but got "drop-shadow(rgb(120, 120, 120) 10px 10px 10px)"
 FAIL iteration composition of same filter list animation assert_equals: Animated filter list at 50s of the first iteration expected "brightness(1.5) contrast(1.5)" but got "brightness(2) contrast(2)"
-FAIL iteration composition of discrete filter list because of mismatch of the order assert_equals: Animated filter list at 0s of the third iteration expected "brightness(1) contrast(1)" but got "none"
+FAIL iteration composition of discrete filter list because of mismatch of the order assert_equals: Animated filter list at 0s of the third iteration expected "brightness(1) contrast(1)" but got "contrast(2) brightness(2)"
 FAIL iteration composition of different length filter list animation assert_equals: Animated filter list at 50s of the first iteration expected "sepia(0.5) contrast(1.5)" but got "sepia(1) contrast(2)"
 FAIL iteration composition of transform(rotate) animation assert_regexp_match: Actual value is not a matrix expected object "/^matrix(?:3d)*\((.+)\)/" but got "none"
 FAIL iteration composition of transform: [ scale(0), scale(1) ] animation assert_regexp_match: Actual value is not a matrix expected object "/^matrix(?:3d)*\((.+)\)/" but got "none"
@@ -30,5 +30,5 @@
 FAIL iteration composition of transform of rotate3d function assert_regexp_match: Actual value is not a matrix expected object "/^matrix(?:3d)*\((.+)\)/" but got "none"
 FAIL iteration composition starts with non-zero value animation assert_equals: Animated margin-left style at 0s of the third iteration expected "50px" but got "15px"
 FAIL iteration composition with negative final value animation assert_equals: Animated margin-left style at 0s of the third iteration expected "-10px" but got "0px"
-FAIL duration changes with an iteration composition operation of accumulate assert_equals: Animated style at 50s of the third iteration expected "25px" but got "0px"
+FAIL duration changes with an iteration composition operation of accumulate assert_equals: Animated style at 50s of the third iteration expected "25px" but got "5px"
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/web-animations/interfaces/Animation/effect-expected.txt (227621 => 227622)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/web-animations/interfaces/Animation/effect-expected.txt	2018-01-25 20:13:41 UTC (rev 227621)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/web-animations/interfaces/Animation/effect-expected.txt	2018-01-25 20:21:47 UTC (rev 227622)
@@ -1,4 +1,4 @@
 
 FAIL effect is set correctly. Can't find variable: KeyframeEffectReadOnly
-FAIL Clearing and setting Animation.effect should update the computed style of the target element assert_equals: animation is initially having an effect expected "100px" but got "auto"
+FAIL Clearing and setting Animation.effect should update the computed style of the target element assert_equals: animation no longer has an effect expected "auto" but got "100px"
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/easing-expected.txt (227621 => 227622)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/easing-expected.txt	2018-01-25 20:13:41 UTC (rev 227621)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/web-animations/interfaces/AnimationEffectTiming/easing-expected.txt	2018-01-25 20:21:47 UTC (rev 227622)
@@ -1,20 +1,20 @@
 
 PASS Has the default value 'linear' 
-FAIL step-start function assert_approx_equals: The progress of the animation should be approximately 1 at 0ms expected 1 +/- 0.01 but got 0
-FAIL steps(1, start) function assert_approx_equals: The progress of the animation should be approximately 1 at 0ms expected 1 +/- 0.01 but got 0
-FAIL steps(2, start) function assert_approx_equals: The progress of the animation should be approximately 0.5 at 0ms expected 0.5 +/- 0.01 but got 0
-FAIL step-end function assert_approx_equals: The progress of the animation should be approximately 0 at 250000ms expected 0 +/- 0.01 but got 0.25
-FAIL steps(1) function assert_approx_equals: The progress of the animation should be approximately 0 at 250000ms expected 0 +/- 0.01 but got 0.25
-FAIL steps(1, end) function assert_approx_equals: The progress of the animation should be approximately 0 at 250000ms expected 0 +/- 0.01 but got 0.25
-FAIL steps(2, end) function assert_approx_equals: The progress of the animation should be approximately 0 at 250000ms expected 0 +/- 0.01 but got 0.25
+PASS step-start function 
+PASS steps(1, start) function 
+PASS steps(2, start) function 
+PASS step-end function 
+PASS steps(1) function 
+PASS steps(1, end) function 
+PASS steps(2, end) function 
 PASS frames function 
 PASS linear function 
-FAIL ease function assert_approx_equals: The progress of the animation should be approximately 0.40851059137130497 at 250000ms expected 0.40851059137130497 +/- 0.01 but got 0.25
-FAIL ease-in function assert_approx_equals: The progress of the animation should be approximately 0.09346465078656778 at 250000ms expected 0.09346465078656778 +/- 0.01 but got 0.25
-FAIL ease-in-out function assert_approx_equals: The progress of the animation should be approximately 0.129161930735705 at 250000ms expected 0.129161930735705 +/- 0.01 but got 0.25
-FAIL ease-out function assert_approx_equals: The progress of the animation should be approximately 0.37813813135508706 at 250000ms expected 0.37813813135508706 +/- 0.01 but got 0.25
-FAIL easing function which produces values greater than 1 assert_approx_equals: The progress of the animation should be approximately 1.0240666638411384 at 250000ms expected 1.0240666638411384 +/- 0.01 but got 0.25
-FAIL easing function which produces values less than 1 assert_approx_equals: The progress of the animation should be approximately -0.29501119758965655 at 250000ms expected -0.29501119758965655 +/- 0.01 but got 0.25
+PASS ease function 
+PASS ease-in function 
+PASS ease-in-out function 
+PASS ease-out function 
+PASS easing function which produces values greater than 1 
+PASS easing function which produces values less than 1 
 PASS Throws on invalid easing: '' 
 PASS Throws on invalid easing: '7' 
 PASS Throws on invalid easing: 'test' 
@@ -53,5 +53,5 @@
 PASS Canonical easing 'steps(3, start)' is returned as set 
 PASS Canonical easing 'steps(3)' is returned as set 
 PASS Canonical easing 'frames(3)' is returned as set 
-FAIL Allows the easing to be changed while the animation is in progress assert_equals: change currentTime to active phase expected 0.5 but got 0.75
+PASS Allows the easing to be changed while the animation is in progress 
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/web-animations/interfaces/KeyframeEffect/iterationComposite-expected.txt (227621 => 227622)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/web-animations/interfaces/KeyframeEffect/iterationComposite-expected.txt	2018-01-25 20:13:41 UTC (rev 227621)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/web-animations/interfaces/KeyframeEffect/iterationComposite-expected.txt	2018-01-25 20:21:47 UTC (rev 227622)
@@ -1,3 +1,3 @@
 
-FAIL iterationComposite can be updated while an animation is in progress assert_equals: Animated style at 50s of the third iteration expected "25px" but got "0px"
+FAIL iterationComposite can be updated while an animation is in progress assert_equals: Animated style at 50s of the third iteration expected "25px" but got "5px"
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/web-animations/timing-model/time-transformations/transformed-progress-expected.txt (227621 => 227622)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/web-animations/timing-model/time-transformations/transformed-progress-expected.txt	2018-01-25 20:13:41 UTC (rev 227621)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/web-animations/timing-model/time-transformations/transformed-progress-expected.txt	2018-01-25 20:21:47 UTC (rev 227622)
@@ -1,30 +1,30 @@
 
-FAIL Transformed progress for step-start function assert_approx_equals: The progress should be approximately 1 at 0ms expected 1 +/- 0.01 but got 0
-FAIL Transformed progress for steps(1, start) function assert_approx_equals: The progress should be approximately 1 at 0ms expected 1 +/- 0.01 but got 0
-FAIL Transformed progress for steps(2, start) function assert_approx_equals: The progress should be approximately 0.5 at 0ms expected 0.5 +/- 0.01 but got 0
-FAIL Transformed progress for step-end function assert_approx_equals: The progress should be approximately 0 at 250ms expected 0 +/- 0.01 but got 0.25
-FAIL Transformed progress for steps(1) function assert_approx_equals: The progress should be approximately 0 at 250ms expected 0 +/- 0.01 but got 0.25
-FAIL Transformed progress for steps(1, end) function assert_approx_equals: The progress should be approximately 0 at 250ms expected 0 +/- 0.01 but got 0.25
-FAIL Transformed progress for steps(2, end) function assert_approx_equals: The progress should be approximately 0 at 250ms expected 0 +/- 0.01 but got 0.25
+PASS Transformed progress for step-start function 
+PASS Transformed progress for steps(1, start) function 
+PASS Transformed progress for steps(2, start) function 
+PASS Transformed progress for step-end function 
+PASS Transformed progress for steps(1) function 
+PASS Transformed progress for steps(1, end) function 
+PASS Transformed progress for steps(2, end) function 
 PASS Transformed progress for frames function 
 PASS Transformed progress for linear function 
-FAIL Transformed progress for ease function assert_approx_equals: The progress should be approximately 0.40851059137130497 at 250ms expected 0.40851059137130497 +/- 0.01 but got 0.25
-FAIL Transformed progress for ease-in function assert_approx_equals: The progress should be approximately 0.09346465078656778 at 250ms expected 0.09346465078656778 +/- 0.01 but got 0.25
-FAIL Transformed progress for ease-in-out function assert_approx_equals: The progress should be approximately 0.129161930735705 at 250ms expected 0.129161930735705 +/- 0.01 but got 0.25
-FAIL Transformed progress for ease-out function assert_approx_equals: The progress should be approximately 0.37813813135508706 at 250ms expected 0.37813813135508706 +/- 0.01 but got 0.25
-FAIL Transformed progress for easing function which produces values greater than 1 assert_approx_equals: The progress should be approximately 1.0240666638411384 at 250ms expected 1.0240666638411384 +/- 0.01 but got 0.25
-FAIL Transformed progress for easing function which produces values less than 1 assert_approx_equals: The progress should be approximately -0.29501119758965655 at 250ms expected -0.29501119758965655 +/- 0.01 but got 0.25
-FAIL Test bounds point of step-start easing assert_equals: Progress at 1000ms expected 0.5 but got 0
-FAIL Test bounds point of step-start easing with reverse direction assert_equals: Progress at 1001ms expected 1 but got 0.999
-FAIL Test bounds point of step-start easing with iterationStart not at a transition point assert_equals: Progress at 0ms expected 0.5 but got 0.25
-FAIL Test bounds point of step-start easing with iterationStart and delay assert_equals: Progress at 1000ms expected 1 but got 0.5
-FAIL Test bounds point of step-start easing with iterationStart and reverse direction assert_equals: Progress at 0ms expected 1 but got 0.5
-FAIL Test bounds point of step(4, start) easing with iterationStart 0.75 and delay assert_equals: Progress at 1000ms expected 1 but got 0.75
-FAIL Test bounds point of step-start easing with alternate direction assert_equals: Progress at 0ms expected 1 but got 0.5
-FAIL Test bounds point of step-start easing with alternate-reverse direction assert_equals: Progress at 0ms expected 1 but got 0.5
-FAIL Test bounds point of step-end easing assert_equals: Progress at 1499ms expected 0 but got 0.499
-FAIL Test bounds point of step-end easing with iterationStart and delay assert_equals: Progress at 0ms expected 0 but got 0.5
-FAIL Test bounds point of step-end easing with iterationStart not at a transition point assert_equals: Progress at 0ms expected 0.5 but got 0.75
-FAIL Test bounds point of frames easing assert_equals: Progress at 1499ms expected 0 but got 0.499
-FAIL Test bounds point of frames easing with iterationStart and delay assert_equals: Progress at 0ms expected 1 but got 0.5
+PASS Transformed progress for ease function 
+PASS Transformed progress for ease-in function 
+PASS Transformed progress for ease-in-out function 
+PASS Transformed progress for ease-out function 
+PASS Transformed progress for easing function which produces values greater than 1 
+PASS Transformed progress for easing function which produces values less than 1 
+PASS Test bounds point of step-start easing 
+PASS Test bounds point of step-start easing with reverse direction 
+PASS Test bounds point of step-start easing with iterationStart not at a transition point 
+PASS Test bounds point of step-start easing with iterationStart and delay 
+PASS Test bounds point of step-start easing with iterationStart and reverse direction 
+PASS Test bounds point of step(4, start) easing with iterationStart 0.75 and delay 
+PASS Test bounds point of step-start easing with alternate direction 
+PASS Test bounds point of step-start easing with alternate-reverse direction 
+PASS Test bounds point of step-end easing 
+PASS Test bounds point of step-end easing with iterationStart and delay 
+PASS Test bounds point of step-end easing with iterationStart not at a transition point 
+PASS Test bounds point of frames easing 
+PASS Test bounds point of frames easing with iterationStart and delay 
 

Modified: trunk/LayoutTests/platform/mac/transitions/default-timing-function-expected.txt (227621 => 227622)


--- trunk/LayoutTests/platform/mac/transitions/default-timing-function-expected.txt	2018-01-25 20:13:41 UTC (rev 227621)
+++ trunk/LayoutTests/platform/mac/transitions/default-timing-function-expected.txt	2018-01-25 20:21:47 UTC (rev 227622)
@@ -14,7 +14,7 @@
   RenderBlock (relative positioned) {DIV} at (0,0) size 784x200
 layer at (330,8) size 100x200
   RenderBlock (positioned) {DIV} at (322,0) size 100x200 [bgcolor=#FF0000]
-layer at (330,8) size 100x100
+layer at (329,8) size 100x100
   RenderBlock (relative positioned) {DIV} at (0,0) size 100x100 [bgcolor=#008000]
 layer at (8,108) size 100x100
   RenderBlock (relative positioned) {DIV} at (0,100) size 100x100 [bgcolor=#008000]

Modified: trunk/Source/WebCore/ChangeLog (227621 => 227622)


--- trunk/Source/WebCore/ChangeLog	2018-01-25 20:13:41 UTC (rev 227621)
+++ trunk/Source/WebCore/ChangeLog	2018-01-25 20:21:47 UTC (rev 227622)
@@ -1,5 +1,42 @@
 2018-01-25  Antoine Quint  <grao...@apple.com>
 
+        [Web Animations] Account for provided easings when computing progress and resolving keyframe effect values
+        https://bugs.webkit.org/show_bug.cgi?id=182098
+        <rdar://problem/36866149>
+
+        Reviewed by Dean Jackson.
+
+        We now account for the timing functions provided through the "easing" propreties on whole animation effects
+        and individual keyframes. Exposing those exposed shortcomings of our keyframe resolution in general through
+        WPT tests so we now implement the "effect value of a keyframe effect" procedure from the spec to correctly
+        resolve keyframes in KeyframeEffect::setAnimatedPropertiesInStyle(). The tests also showed some shortcomings
+        in our TimingFunction code where our step() function resolution wasn't fully compliant and our cubic-bezier()
+        resolution not accurate enough. We now have microsecond accuracy when resolving cubic-bezier() timing functions
+        and identify cubic-bezier(0, 0, 0, 0), cubic-bezier(0, 0, 1, 1) and cubic-bezier(1, 1, 1, 1) as linear timing
+        functions, as called out by the WPT tests.
+
+        * animation/AnimationEffect.cpp:
+        (WebCore::AnimationEffect::transformedProgress const): Account for the effect-wide timing function when computing
+        the progress.
+        (WebCore::AnimationEffect::iterationProgress const): Use the transformed progress now that we support this procedure.
+        * animation/AnimationEffect.h:
+        * animation/KeyframeEffect.cpp:
+        (WebCore::KeyframeEffect::apply): We now use the computed progress from AnimationEffect rather than compute based
+        on the provided time, which we've dropped as an argument.
+        (WebCore::KeyframeEffect::getAnimatedStyle):
+        (WebCore::KeyframeEffect::setAnimatedPropertiesInStyle): Implement the "effect value of a keyframe effect" procedure
+        in full as specified (save for composite operations).
+        (WebCore::KeyframeEffect::applyAtLocalTime): Deleted.
+        * animation/KeyframeEffect.h:
+        * animation/WebAnimation.cpp:
+        (WebCore::WebAnimation::resolve):
+        * css/CSSTimingFunctionValue.h: Fix a small error made in a previous patch where we used "int" instead of "unsigned".
+        * platform/animation/TimingFunction.cpp:
+        (WebCore::TimingFunction::transformTime const):
+        * platform/animation/TimingFunction.h:
+
+2018-01-25  Antoine Quint  <grao...@apple.com>
+
         [Web Animations] Avoid querying the current time multiple time when resolving the play state
         https://bugs.webkit.org/show_bug.cgi?id=182099
 

Modified: trunk/Source/WebCore/animation/AnimationEffect.cpp (227621 => 227622)


--- trunk/Source/WebCore/animation/AnimationEffect.cpp	2018-01-25 20:13:41 UTC (rev 227621)
+++ trunk/Source/WebCore/animation/AnimationEffect.cpp	2018-01-25 20:21:47 UTC (rev 227622)
@@ -259,9 +259,45 @@
     return 1 - effectSimpleIterationProgress.value();
 }
 
+std::optional<double> AnimationEffect::transformedProgress() const
+{
+    // 3.10.1. Calculating the transformed progress
+    // https://drafts.csswg.org/web-animations-1/#calculating-the-transformed-progress
+
+    // The transformed progress is calculated from the directed progress using the following steps:
+    //
+    // 1. If the directed progress is unresolved, return unresolved.
+    auto effectDirectedProgress = directedProgress();
+    if (!effectDirectedProgress)
+        return std::nullopt;
+
+    auto effectDirectedProgressValue = effectDirectedProgress.value();
+
+    if (auto iterationDuration = m_timing->iterationDuration().seconds()) {
+        bool before = false;
+        auto* timingFunction = m_timing->timingFunction();
+        // 2. Calculate the value of the before flag as follows:
+        if (is<StepsTimingFunction>(timingFunction)) {
+            // 1. Determine the current direction using the procedure defined in §3.9.1 Calculating the directed progress.
+            // 2. If the current direction is forwards, let going forwards be true, otherwise it is false.
+            bool goingForwards = currentDirection() == AnimationEffect::ComputedDirection::Forwards;
+            // 3. The before flag is set if the animation effect is in the before phase and going forwards is true;
+            //    or if the animation effect is in the after phase and going forwards is false.
+            auto effectPhase = phase();
+            before = (effectPhase == Phase::Before && goingForwards) || (effectPhase == Phase::After && !goingForwards);
+        }
+
+        // 3. Return the result of evaluating the animation effect’s timing function passing directed progress as the
+        //    input progress value and before flag as the before flag.
+        return timingFunction->transformTime(effectDirectedProgressValue, iterationDuration, before);
+    }
+
+    return effectDirectedProgressValue;
+}
+
 std::optional<double> AnimationEffect::iterationProgress() const
 {
-    return directedProgress();
+    return transformedProgress();
 }
 
 ComputedTimingProperties AnimationEffect::getComputedTiming()

Modified: trunk/Source/WebCore/animation/AnimationEffect.h (227621 => 227622)


--- trunk/Source/WebCore/animation/AnimationEffect.h	2018-01-25 20:13:41 UTC (rev 227621)
+++ trunk/Source/WebCore/animation/AnimationEffect.h	2018-01-25 20:21:47 UTC (rev 227622)
@@ -42,7 +42,7 @@
     bool isKeyframeEffect() const { return m_classType == KeyframeEffectClass; }
     AnimationEffectTiming* timing() const { return m_timing.get(); }
     ComputedTimingProperties getComputedTiming();
-    virtual void applyAtLocalTime(Seconds, RenderStyle&) = 0;
+    virtual void apply(RenderStyle&) = 0;
 
     WebAnimation* animation() const { return m_animation.get(); }
     void setAnimation(RefPtr<WebAnimation>&& animation) { m_animation = animation; }
@@ -71,6 +71,7 @@
     std::optional<double> currentIteration() const;
     AnimationEffect::ComputedDirection currentDirection() const;
     std::optional<double> directedProgress() const;
+    std::optional<double> transformedProgress() const;
 
     ClassType m_classType;
     RefPtr<WebAnimation> m_animation;

Modified: trunk/Source/WebCore/animation/KeyframeEffect.cpp (227621 => 227622)


--- trunk/Source/WebCore/animation/KeyframeEffect.cpp	2018-01-25 20:13:41 UTC (rev 227621)
+++ trunk/Source/WebCore/animation/KeyframeEffect.cpp	2018-01-25 20:21:47 UTC (rev 227622)
@@ -627,24 +627,20 @@
     }
 }
 
-void KeyframeEffect::applyAtLocalTime(Seconds localTime, RenderStyle& targetStyle)
+void KeyframeEffect::apply(RenderStyle& targetStyle)
 {
     if (!m_target)
         return;
 
-    if (m_startedAccelerated && localTime >= timing()->iterationDuration()) {
+    auto progress = iterationProgress();
+    if (!progress)
+        return;
+
+    if (m_startedAccelerated && progress.value() >= 1) {
         m_startedAccelerated = false;
         animation()->acceleratedRunningStateDidChange();
     }
 
-    // FIXME: Assume animations only apply in the range [0, duration[
-    // until we support fill modes, delays and iterations.
-    if (localTime < 0_s || localTime >= timing()->iterationDuration())
-        return;
-
-    if (!timing()->iterationDuration())
-        return;
-
     bool needsToStartAccelerated = false;
 
     if (!m_started && !m_startedAccelerated) {
@@ -656,7 +652,7 @@
     m_started = true;
 
     if (!needsToStartAccelerated && !m_startedAccelerated)
-        setAnimatedPropertiesInStyle(targetStyle, localTime / timing()->iterationDuration());
+        setAnimatedPropertiesInStyle(targetStyle, progress.value());
 
     // https://w3c.github.io/web-animations/#side-effects-section
     // For every property targeted by at least one animation effect that is current or in effect, the user agent
@@ -676,69 +672,157 @@
 
 void KeyframeEffect::getAnimatedStyle(std::unique_ptr<RenderStyle>& animatedStyle)
 {
-    if (!animation() || !timing()->iterationDuration())
+    if (!animation())
         return;
 
-    auto localTime = animation()->currentTime();
-
-    // FIXME: Assume animations only apply in the range [0, duration[
-    // until we support fill modes, delays and iterations.
-    if (!localTime || localTime < 0_s || localTime >= timing()->iterationDuration())
+    if (!m_keyframes.size())
         return;
 
-    if (!m_keyframes.size())
+    auto progress = iterationProgress();
+    if (!progress)
         return;
 
     if (!animatedStyle)
         animatedStyle = RenderStyle::clonePtr(renderer()->style());
 
-    setAnimatedPropertiesInStyle(*animatedStyle.get(), localTime.value() / timing()->iterationDuration());
+    setAnimatedPropertiesInStyle(*animatedStyle.get(), progress.value());
 }
 
-void KeyframeEffect::setAnimatedPropertiesInStyle(RenderStyle& targetStyle, double progress)
+void KeyframeEffect::setAnimatedPropertiesInStyle(RenderStyle& targetStyle, double iterationProgress)
 {
-    size_t numberOfKeyframes = m_keyframes.size();
+    // 4.4.3. The effect value of a keyframe effect
+    // https://drafts.csswg.org/web-animations-1/#the-effect-value-of-a-keyframe-animation-effect
+    //
+    // The effect value of a single property referenced by a keyframe effect as one of its target properties,
+    // for a given iteration progress, current iteration and underlying value is calculated as follows.
+
     for (auto cssPropertyId : m_keyframes.properties()) {
-        int startKeyframeIndex = -1;
-        int endKeyframeIndex = -1;
+        // 1. If iteration progress is unresolved abort this procedure.
+        // 2. Let target property be the longhand property for which the effect value is to be calculated.
+        // 3. If animation type of the target property is not animatable abort this procedure since the effect cannot be applied.
+        // 4. Define the neutral value for composition as a value which, when combined with an underlying value using the add composite operation,
+        //    produces the underlying value.
 
-        for (size_t i = 0; i < numberOfKeyframes; ++i) {
+        // 5. Let property-specific keyframes be the result of getting the set of computed keyframes for this keyframe effect.
+        // 6. Remove any keyframes from property-specific keyframes that do not have a property value for target property.
+        unsigned numberOfKeyframesWithZeroOffset = 0;
+        unsigned numberOfKeyframesWithOneOffset = 0;
+        Vector<std::optional<size_t>> propertySpecificKeyframes;
+        for (size_t i = 0; i < m_keyframes.size(); ++i) {
             auto& keyframe = m_keyframes[i];
             if (!keyframe.containsProperty(cssPropertyId))
                 continue;
+            auto offset = keyframe.key();
+            if (!offset)
+                numberOfKeyframesWithZeroOffset++;
+            if (offset == 1)
+                numberOfKeyframesWithOneOffset++;
+            propertySpecificKeyframes.append(i);
+        }
 
-            if (keyframe.key() > progress) {
-                endKeyframeIndex = i;
-                break;
-            }
+        // 7. If property-specific keyframes is empty, return underlying value.
+        if (propertySpecificKeyframes.isEmpty())
+            continue;
 
-            startKeyframeIndex = i;
+        // 8. If there is no keyframe in property-specific keyframes with a computed keyframe offset of 0, create a new keyframe with a computed keyframe
+        //    offset of 0, a property value set to the neutral value for composition, and a composite operation of add, and prepend it to the beginning of
+        //    property-specific keyframes.
+        if (!numberOfKeyframesWithZeroOffset) {
+            propertySpecificKeyframes.insert(0, std::nullopt);
+            numberOfKeyframesWithZeroOffset = 1;
         }
 
-        // If we didn't find a start keyframe, this means there is an implicit start keyframe.
-        double startOffset;
-        const RenderStyle* startStyle;
-        if (startKeyframeIndex == -1) {
-            startOffset = 0;
-            startStyle = &targetStyle;
-        } else {
-            startOffset = m_keyframes[startKeyframeIndex].key();
-            startStyle = m_keyframes[startKeyframeIndex].style();
+        // 9. Similarly, if there is no keyframe in property-specific keyframes with a computed keyframe offset of 1, create a new keyframe with a computed
+        //    keyframe offset of 1, a property value set to the neutral value for composition, and a composite operation of add, and append it to the end of
+        //    property-specific keyframes.
+        if (!numberOfKeyframesWithOneOffset) {
+            propertySpecificKeyframes.append(std::nullopt);
+            numberOfKeyframesWithOneOffset = 1;
         }
 
-        // If we didn't find an end keyframe, this means there is an implicit end keyframe.
-        double endOffset;
-        const RenderStyle* endStyle;
-        if (endKeyframeIndex == -1) {
-            endOffset = 1;
-            endStyle = &targetStyle;
+        // 10. Let interval endpoints be an empty sequence of keyframes.
+        Vector<std::optional<size_t>> intervalEndpoints;
+
+        // 11. Populate interval endpoints by following the steps from the first matching condition from below:
+        if (iterationProgress < 0 && numberOfKeyframesWithZeroOffset > 1) {
+            // If iteration progress < 0 and there is more than one keyframe in property-specific keyframes with a computed keyframe offset of 0,
+            // Add the first keyframe in property-specific keyframes to interval endpoints.
+            intervalEndpoints.append(propertySpecificKeyframes.first());
+        } else if (iterationProgress >= 1 && numberOfKeyframesWithOneOffset > 1) {
+            // If iteration progress ≥ 1 and there is more than one keyframe in property-specific keyframes with a computed keyframe offset of 1,
+            // Add the last keyframe in property-specific keyframes to interval endpoints.
+            intervalEndpoints.append(propertySpecificKeyframes.last());
         } else {
-            endOffset = m_keyframes[endKeyframeIndex].key();
-            endStyle = m_keyframes[endKeyframeIndex].style();
+            // Otherwise,
+            // 1. Append to interval endpoints the last keyframe in property-specific keyframes whose computed keyframe offset is less than or equal
+            //    to iteration progress and less than 1. If there is no such keyframe (because, for example, the iteration progress is negative),
+            //    add the last keyframe whose computed keyframe offset is 0.
+            // 2. Append to interval endpoints the next keyframe in property-specific keyframes after the one added in the previous step.
+            size_t indexOfLastKeyframeWithZeroOffset = 0;
+            int indexOfFirstKeyframeToAddToIntervalEndpoints = -1;
+            for (size_t i = 0; i < propertySpecificKeyframes.size(); ++i) {
+                auto keyframeIndex = propertySpecificKeyframes[i];
+                auto offset = [&] () -> double {
+                    if (!keyframeIndex)
+                        return i ? 1 : 0;
+                    return m_keyframes[keyframeIndex.value()].key();
+                }();
+                if (!offset)
+                    indexOfLastKeyframeWithZeroOffset = i;
+                if (offset <= iterationProgress && offset < 1)
+                    indexOfFirstKeyframeToAddToIntervalEndpoints = i;
+                else
+                    break;
+            }
+
+            if (indexOfFirstKeyframeToAddToIntervalEndpoints >= 0) {
+                intervalEndpoints.append(propertySpecificKeyframes[indexOfFirstKeyframeToAddToIntervalEndpoints]);
+                intervalEndpoints.append(propertySpecificKeyframes[indexOfFirstKeyframeToAddToIntervalEndpoints + 1]);
+            } else {
+                ASSERT(indexOfLastKeyframeWithZeroOffset < propertySpecificKeyframes.size() - 1);
+                intervalEndpoints.append(propertySpecificKeyframes[indexOfLastKeyframeWithZeroOffset]);
+                intervalEndpoints.append(propertySpecificKeyframes[indexOfLastKeyframeWithZeroOffset + 1]);
+            }
         }
 
-        auto progressInRange = (progress - startOffset) / (endOffset - startOffset);
-        CSSPropertyAnimation::blendProperties(this, cssPropertyId, &targetStyle, startStyle, endStyle, progressInRange);
+        // 12. For each keyframe in interval endpoints…
+        // FIXME: we don't support this step yet since we don't deal with any composite operation other than "replace".
+
+        // 13. If there is only one keyframe in interval endpoints return the property value of target property on that keyframe.
+        if (intervalEndpoints.size() == 1) {
+            auto keyframeIndex = intervalEndpoints[0];
+            auto keyframeStyle = !keyframeIndex ? &targetStyle : m_keyframes[keyframeIndex.value()].style();
+            CSSPropertyAnimation::blendProperties(this, cssPropertyId, &targetStyle, keyframeStyle, keyframeStyle, 0);
+            continue;
+        }
+
+        // 14. Let start offset be the computed keyframe offset of the first keyframe in interval endpoints.
+        auto startKeyframeIndex = intervalEndpoints.first();
+        auto startOffset = !startKeyframeIndex ? 0 : m_keyframes[startKeyframeIndex.value()].key();
+
+        // 15. Let end offset be the computed keyframe offset of last keyframe in interval endpoints.
+        auto endKeyframeIndex = intervalEndpoints.last();
+        auto endOffset = !endKeyframeIndex ? 1 : m_keyframes[endKeyframeIndex.value()].key();
+
+        // 16. Let interval distance be the result of evaluating (iteration progress - start offset) / (end offset - start offset).
+        auto intervalDistance = (iterationProgress - startOffset) / (endOffset - startOffset);
+
+        // 17. Let transformed distance be the result of evaluating the timing function associated with the first keyframe in interval endpoints
+        //     passing interval distance as the input progress.
+        auto transformedDistance = intervalDistance;
+        if (startKeyframeIndex) {
+            if (auto iterationDuration = timing()->iterationDuration()) {
+                auto rangeDuration = (endOffset - startOffset) * iterationDuration.seconds();
+                transformedDistance = m_timingFunctions[startKeyframeIndex.value()]->transformTime(intervalDistance, rangeDuration);
+            }
+        }
+
+        // 18. Return the result of applying the interpolation procedure defined by the animation type of the target property, to the values of the target
+        //     property specified on the two keyframes in interval endpoints taking the first such value as Vstart and the second as Vend and using transformed
+        //     distance as the interpolation parameter p.
+        auto startStyle = !startKeyframeIndex ? &targetStyle : m_keyframes[startKeyframeIndex.value()].style();
+        auto endStyle = !endKeyframeIndex ? &targetStyle : m_keyframes[endKeyframeIndex.value()].style();
+        CSSPropertyAnimation::blendProperties(this, cssPropertyId, &targetStyle, startStyle, endStyle, transformedDistance);
     }
 }
 

Modified: trunk/Source/WebCore/animation/KeyframeEffect.h (227621 => 227622)


--- trunk/Source/WebCore/animation/KeyframeEffect.h	2018-01-25 20:13:41 UTC (rev 227621)
+++ trunk/Source/WebCore/animation/KeyframeEffect.h	2018-01-25 20:21:47 UTC (rev 227622)
@@ -85,7 +85,7 @@
     void setComposite(CompositeOperation compositeOperation) { m_compositeOperation = compositeOperation; }
 
     void getAnimatedStyle(std::unique_ptr<RenderStyle>& animatedStyle);
-    void applyAtLocalTime(Seconds, RenderStyle&) override;
+    void apply(RenderStyle&) override;
     void startOrStopAccelerated();
     bool isRunningAccelerated() const { return m_startedAccelerated; }
 

Modified: trunk/Source/WebCore/animation/WebAnimation.cpp (227621 => 227622)


--- trunk/Source/WebCore/animation/WebAnimation.cpp	2018-01-25 20:13:41 UTC (rev 227621)
+++ trunk/Source/WebCore/animation/WebAnimation.cpp	2018-01-25 20:21:47 UTC (rev 227622)
@@ -817,8 +817,8 @@
 
 void WebAnimation::resolve(RenderStyle& targetStyle)
 {
-    if (m_effect && currentTime())
-        m_effect->applyAtLocalTime(currentTime().value(), targetStyle);
+    if (m_effect)
+        m_effect->apply(targetStyle);
 }
 
 void WebAnimation::acceleratedRunningStateDidChange()

Modified: trunk/Source/WebCore/css/CSSTimingFunctionValue.h (227621 => 227622)


--- trunk/Source/WebCore/css/CSSTimingFunctionValue.h	2018-01-25 20:13:41 UTC (rev 227621)
+++ trunk/Source/WebCore/css/CSSTimingFunctionValue.h	2018-01-25 20:21:47 UTC (rev 227622)
@@ -101,7 +101,7 @@
     bool equals(const CSSFramesTimingFunctionValue&) const;
 
 private:
-    CSSFramesTimingFunctionValue(int frames)
+    CSSFramesTimingFunctionValue(unsigned frames)
         : CSSValue(FramesTimingFunctionClass)
         , m_frames(frames)
     {

Modified: trunk/Source/WebCore/platform/animation/TimingFunction.cpp (227621 => 227622)


--- trunk/Source/WebCore/platform/animation/TimingFunction.cpp	2018-01-25 20:13:41 UTC (rev 227621)
+++ trunk/Source/WebCore/platform/animation/TimingFunction.cpp	2018-01-25 20:21:47 UTC (rev 227622)
@@ -64,22 +64,41 @@
     return ts;
 }
 
-double TimingFunction::transformTime(double inputTime, double duration) const
+double TimingFunction::transformTime(double inputTime, double duration, bool before) const
 {
     switch (m_type) {
     case TimingFunction::CubicBezierFunction: {
         auto& function = downcast<CubicBezierTimingFunction>(*this);
+        if (function.isLinear())
+            return inputTime;
         // The epsilon value we pass to UnitBezier::solve given that the animation is going to run over |dur| seconds. The longer the
         // animation, the more precision we need in the timing function result to avoid ugly discontinuities.
-        auto epsilon = 1.0 / (200.0 * duration);
+        auto epsilon = 1.0 / (1000.0 * duration);
         return UnitBezier(function.x1(), function.y1(), function.x2(), function.y2()).solve(inputTime, epsilon);
     }
     case TimingFunction::StepsFunction: {
+        // https://drafts.csswg.org/css-timing/#step-timing-functions
         auto& function = downcast<StepsTimingFunction>(*this);
-        auto numberOfSteps = function.numberOfSteps();
+        auto steps = function.numberOfSteps();
+        // 1. Calculate the current step as floor(input progress value × steps).
+        auto currentStep = std::floor(inputTime * steps);
+        // 2. If the step position property is start, increment current step by one.
         if (function.stepAtStart())
-            return std::min(1.0, (std::floor(numberOfSteps * inputTime) + 1) / numberOfSteps);
-        return std::floor(numberOfSteps * inputTime) / numberOfSteps;
+            currentStep++;
+        // 3. If both of the following conditions are true:
+        //    - the before flag is set, and
+        //    - input progress value × steps mod 1 equals zero (that is, if input progress value × steps is integral), then
+        //    decrement current step by one.
+        if (before && !fmod(inputTime * steps, 1))
+            currentStep--;
+        // 4. If input progress value ≥ 0 and current step < 0, let current step be zero.
+        if (inputTime >= 0 && currentStep < 0)
+            currentStep = 0;
+        // 5. If input progress value ≤ 1 and current step > steps, let current step be steps.
+        if (inputTime <= 1 && currentStep > steps)
+            currentStep = steps;
+        // 6. The output progress value is current step / steps.
+        return currentStep / steps;
     }
     case TimingFunction::FramesFunction: {
         // https://drafts.csswg.org/css-timing/#frames-timing-functions

Modified: trunk/Source/WebCore/platform/animation/TimingFunction.h (227621 => 227622)


--- trunk/Source/WebCore/platform/animation/TimingFunction.h	2018-01-25 20:13:41 UTC (rev 227621)
+++ trunk/Source/WebCore/platform/animation/TimingFunction.h	2018-01-25 20:21:47 UTC (rev 227622)
@@ -52,8 +52,8 @@
     virtual bool operator==(const TimingFunction&) const = 0;
     bool operator!=(const TimingFunction& other) const { return !(*this == other); }
 
-    double transformTime(double, double) const;
     static ExceptionOr<RefPtr<TimingFunction>> createFromCSSText(const String&);
+    double transformTime(double, double, bool before = false) const;
     String cssText() const;
 
 protected:
@@ -161,6 +161,11 @@
         return create(1.0 - m_x2, 1.0 - m_y2, 1.0 - m_x1, 1.0 - m_y1);
     }
 
+    bool isLinear() const
+    {
+        return (!m_x1 && !m_y1 && !m_x2 && !m_y2) || (m_x1 == 1.0 && m_y1 == 1.0 && m_x2 == 1.0 && m_y2 == 1.0) || (m_x1 == 0.0 && m_y1 == 0.0 && m_x2 == 1.0 && m_y2 == 1.0);
+    }
+
 private:
     explicit CubicBezierTimingFunction(TimingFunctionPreset preset = Ease, double x1 = 0.25, double y1 = 0.1, double x2 = 0.25, double y2 = 1.0)
         : TimingFunction(CubicBezierFunction)
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to