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)