diff options
Diffstat (limited to 'testing/web-platform/tests/css/css-easing')
10 files changed, 878 insertions, 0 deletions
diff --git a/testing/web-platform/tests/css/css-easing/META.yml b/testing/web-platform/tests/css/css-easing/META.yml new file mode 100644 index 0000000000..2c412b40f0 --- /dev/null +++ b/testing/web-platform/tests/css/css-easing/META.yml @@ -0,0 +1,4 @@ +spec: https://drafts.csswg.org/css-easing/ +suggested_reviewers: + - birtles + - BorisChiou diff --git a/testing/web-platform/tests/css/css-easing/cubic-bezier-timing-functions-output.html b/testing/web-platform/tests/css/css-easing/cubic-bezier-timing-functions-output.html new file mode 100644 index 0000000000..168f4cd907 --- /dev/null +++ b/testing/web-platform/tests/css/css-easing/cubic-bezier-timing-functions-output.html @@ -0,0 +1,221 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<meta name="assert" +content="This test checks the output of Cubic Bézier functions" /> +<title>Tests for the output of Cubic Bézier timing functions</title> +<link rel="help" +href="https://drafts.csswg.org/css-easing/#cubic-bezier-timing-functions"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="testcommon.js"></script> +<body> +<div id="log"></div> +<script> +'use strict'; + +function assert_style_left_at(animation, time, easingFunction) { + animation.currentTime = time; + var portion = time / animation.effect.getTiming()['duration']; + assert_approx_equals(pxToNum(getComputedStyle(animation.effect.target).left), + easingFunction(portion) * 100, + 0.01, + 'The left of the animation should be approximately ' + + easingFunction(portion) * 100 + ' at ' + time + 'ms'); +} + +test(function(t) { + var target = createDiv(t); + target.style.position = 'absolute'; + var anim = target.animate( + // http://cubic-bezier.com/#.5,1,.5,0 + [ { left: '0px', easing: 'cubic-bezier(0.5, 1, 0.5, 0)' }, + { left: '100px' } ], + { duration: 1000, + fill: 'forwards', + easing: 'cubic-bezier(0, 1.5, 1, 1.5)' }); + var keyframeEasing = function(x) { + assert_greater_than_equal(x, 0.0, + 'This function should be called in [0, 1.0] range'); + assert_less_than_equal(x, 1.0, + 'This function should be called in [0, 1.0] range'); + return cubicBezier(0.5, 1, 0.5, 0)(x); + } + var keyframeEasingExtrapolated = function(x) { + assert_greater_than(x, 1.0, + 'This function should be called in (1.0, infinity) range'); + // p3x + (p2y - p3y) / (p2x - p3x) * (x - p3x) + return 1.0 + (0 - 1) / (0.5 - 1) * (x - 1.0); + } + var effectEasing = function(x) { + return cubicBezier(0, 1.5, 1, 1.5)(x); + } + + // The effect-easing produces values greater than 1 in (0.23368794, 1) + assert_style_left_at(anim, 0, function(x) { + return keyframeEasing(effectEasing(x)); + }); + assert_style_left_at(anim, 230, function(x) { + return keyframeEasing(effectEasing(x)); + }); + assert_style_left_at(anim, 240, function(x) { + return keyframeEasingExtrapolated(effectEasing(x)); + }); + // Near the extreme point of the effect-easing function + assert_style_left_at(anim, 700, function(x) { + return keyframeEasingExtrapolated(effectEasing(x)); + }); + assert_style_left_at(anim, 990, function(x) { + return keyframeEasingExtrapolated(effectEasing(x)); + }); + assert_style_left_at(anim, 1000, function(x) { + return keyframeEasing(effectEasing(x)); + }); +}, 'cubic-bezier easing with input progress greater than 1'); + +test(function(t) { + var target = createDiv(t); + target.style.position = 'absolute'; + var anim = target.animate( + // http://cubic-bezier.com/#0,1.5,1,1.5 + [ { left: '0px', easing: 'cubic-bezier(0, 1.5, 1, 1.5)' }, + { left: '100px' } ], + { duration: 1000, + fill: 'forwards', + easing: 'cubic-bezier(0, 1.5, 1, 1.5)' }); + var easing = function(x) { + assert_greater_than_equal(x, 0.0, + 'This function should be called in [0, 1.0] range'); + assert_less_than_equal(x, 1.0, + 'This function should be called in [0, 1.0] range'); + return cubicBezier(0, 1.5, 1, 1.5)(x); + } + var easingExtrapolated = function(x) { + assert_greater_than(x, 1.0, + 'This function should be called in negative range'); + // For cubic-bezier(0, 1.5, 1, 1.5), the tangent at the + // endpoint (x = 1.0) is infinity so we should just return 1.0. + return 1.0; + } + + // The effect-easing produces values greater than 1 in (0.23368794, 1) + assert_style_left_at(anim, 0, function(x) { + return easing(easing(x)) + }); + assert_style_left_at(anim, 230, function(x) { + return easing(easing(x)) + }); + assert_style_left_at(anim, 240, function(x) { + return easingExtrapolated(easing(x)); + }); + // Near the extreme point of the effect-easing function + assert_style_left_at(anim, 700, function(x) { + return easingExtrapolated(easing(x)); + }); + assert_style_left_at(anim, 990, function(x) { + return easingExtrapolated(easing(x)); + }); + assert_style_left_at(anim, 1000, function(x) { + return easing(easing(x)) + }); +}, 'cubic-bezier easing with input progress greater than 1 and where the ' + + 'tangent on the upper boundary is infinity'); + +test(function(t) { + var target = createDiv(t); + target.style.position = 'absolute'; + var anim = target.animate( + // http://cubic-bezier.com/#.5,1,.5,0 + [ { left: '0px', easing: 'cubic-bezier(0.5, 1, 0.5, 0)' }, + { left: '100px' } ], + { duration: 1000, + fill: 'forwards', + easing: 'cubic-bezier(0, -0.5, 1, -0.5)' }); + var keyframeEasing = function(x) { + assert_greater_than_equal(x, 0.0, + 'This function should be called in [0, 1.0] range'); + assert_less_than_equal(x, 1.0, + 'This function should be called in [0, 1.0] range'); + return cubicBezier(0.5, 1, 0.5, 0)(x); + } + var keyframeEasingExtrapolated = function(x) { + assert_less_than(x, 0.0, + 'This function should be called in negative range'); + // p0x + (p1y - p0y) / (p1x - p0x) * (x - p0x) + return (1 / 0.5) * x; + } + var effectEasing = function(x) { + return cubicBezier(0, -0.5, 1, -0.5)(x); + } + + // The effect-easing produces negative values in (0, 0.766312060) + assert_style_left_at(anim, 0, function(x) { + return keyframeEasing(effectEasing(x)); + }); + assert_style_left_at(anim, 10, function(x) { + return keyframeEasingExtrapolated(effectEasing(x)); + }); + // Near the extreme point of the effect-easing function + assert_style_left_at(anim, 300, function(x) { + return keyframeEasingExtrapolated(effectEasing(x)); + }); + assert_style_left_at(anim, 750, function(x) { + return keyframeEasingExtrapolated(effectEasing(x)); + }); + assert_style_left_at(anim, 770, function(x) { + return keyframeEasing(effectEasing(x)); + }); + assert_style_left_at(anim, 1000, function(x) { + return keyframeEasing(effectEasing(x)); + }); +}, 'cubic-bezier easing with input progress less than 0'); + +test(function(t) { + var target = createDiv(t); + target.style.position = 'absolute'; + var anim = target.animate( + // http://cubic-bezier.com/#0,-0.5,1,-0.5 + [ { left: '0px', easing: 'cubic-bezier(0, -0.5, 1, -0.5)' }, + { left: '100px' } ], + { duration: 1000, + fill: 'forwards', + easing: 'cubic-bezier(0, -0.5, 1, -0.5)' }); + var easing = function(x) { + assert_greater_than_equal(x, 0.0, + 'This function should be called in [0, 1.0] range'); + assert_less_than_equal(x, 1.0, + 'This function should be called in [0, 1.0] range'); + return cubicBezier(0, -0.5, 1, -0.5)(x); + } + var easingExtrapolated = function(x) { + assert_less_than(x, 0.0, + 'This function should be called in negative range'); + // For cubic-bezier(0, -0.5, 1, -0.5), the tangent at the + // endpoint (x = 0.0) is infinity so we should just return 0.0. + return 0.0; + } + + // The effect-easing produces negative values in (0, 0.766312060) + assert_style_left_at(anim, 0, function(x) { + return easing(easing(x)) + }); + assert_style_left_at(anim, 10, function(x) { + return easingExtrapolated(easing(x)); + }); + // Near the extreme point of the effect-easing function + assert_style_left_at(anim, 300, function(x) { + return easingExtrapolated(easing(x)); + }); + assert_style_left_at(anim, 750, function(x) { + return easingExtrapolated(easing(x)); + }); + assert_style_left_at(anim, 770, function(x) { + return easing(easing(x)) + }); + assert_style_left_at(anim, 1000, function(x) { + return easing(easing(x)) + }); +}, 'cubic-bezier easing with input progress less than 0 and where the ' + + 'tangent on the lower boundary is infinity'); + +</script> +</body> diff --git a/testing/web-platform/tests/css/css-easing/linear-timing-functions-output.tentative.html b/testing/web-platform/tests/css/css-easing/linear-timing-functions-output.tentative.html new file mode 100644 index 0000000000..82ea469052 --- /dev/null +++ b/testing/web-platform/tests/css/css-easing/linear-timing-functions-output.tentative.html @@ -0,0 +1,100 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<meta name="assert" content="This test checks the output of linear timing functions" /> +<title>Tests for the output of linear timing functions</title> +<link rel="help" href="https://github.com/w3c/csswg-drafts/pull/6533"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/util.js"></script> +<script src="testcommon.js"></script> +<body> +<div id="log"></div> +<script> +'use strict'; + +function assert_style_left_at(animation, time, expected_y) { + animation.currentTime = time; + assert_approx_equals(pxToNum(getComputedStyle(animation.effect.target).left), + expected_y * 100, + 0.01, + 'The left of the animation should be approximately ' + + expected_y * 100 + ' at ' + time + 'ms'); +} + +function assert_animations_equal_at(actual_animation, expected_animation, time) { + actual_animation.currentTime = time; + var actual_left = pxToNum(getComputedStyle(actual_animation.effect.target).left); + expected_animation.currentTime = time; + var expected_left = pxToNum(getComputedStyle(expected_animation.effect.target).left); + assert_approx_equals(actual_left, + expected_left, + 0.01, + 'The left of the animation should be approximately ' + + expected_left + ' at ' + time + 'ms'); +} + +function create_animated_div(t, easing_function) { + var target = createDiv(t); + target.style.position = 'absolute'; + return target.animate( + [ { left: '0px' }, + { left: '100px' } ], + { duration: 1000, + fill: 'forwards', + easing: easing_function }); +} + +test(function(t) { + var anim = create_animated_div(t, 'linear(0, 1.5, 1)'); + + assert_style_left_at(anim, 0, 0.0); + assert_style_left_at(anim, 250, 0.75); + assert_style_left_at(anim, 500, 1.5); + assert_style_left_at(anim, 750, 1.25); + assert_style_left_at(anim, 1000, 1.00); +}, 'linear function easing with output greater than 1'); + +test(function(t) { + var anim = create_animated_div(t, 'linear(1, -0.5, 0)'); + + assert_style_left_at(anim, 0, 1.0); + assert_style_left_at(anim, 250, 0.25); + assert_style_left_at(anim, 500, -0.5); + assert_style_left_at(anim, 750, -0.25); + assert_style_left_at(anim, 1000, 0.00); +}, 'linear function easing with output less than 1'); + +test(function(t) { + var anim = create_animated_div(t, 'linear(0.2 0% 20%, 0.4 20% 40%, 0.6 40% 60%, 0.8 60% 80%, 1.0 80% 100%)'); + var equiv = create_animated_div(t, 'steps(5, jump-start)'); + + assert_animations_equal_at(anim, equiv, 0); + assert_animations_equal_at(anim, equiv, 200); + assert_animations_equal_at(anim, equiv, 400); + assert_animations_equal_at(anim, equiv, 600); + assert_animations_equal_at(anim, equiv, 800); + assert_animations_equal_at(anim, equiv, 1000); +}, 'linear function easing, steps equivalent'); + +test(function(t) { + var anim = create_animated_div(t, 'linear(0, 0.1 -10%, 1)'); + var equiv = create_animated_div(t, 'linear(0, 0.1 0%, 1)'); + + assert_animations_equal_at(anim, equiv, 0); + assert_animations_equal_at(anim, equiv, 100); + assert_animations_equal_at(anim, equiv, 550); + assert_animations_equal_at(anim, equiv, 1000); +}, 'linear function easing, input value being unspecified in the first entry implies zero'); + +test(function(t) { + var anim = create_animated_div(t, 'linear(0, 0.9 110%, 1)'); + var equiv = create_animated_div(t, 'linear(0, 0.9 110%, 1 110%)'); + + assert_animations_equal_at(anim, equiv, 0); + assert_animations_equal_at(anim, equiv, 450); + assert_animations_equal_at(anim, equiv, 900); + assert_animations_equal_at(anim, equiv, 950); + assert_animations_equal_at(anim, equiv, 1000); +}, 'linear function easing, input value being unspecified in the last entry implies max input value'); +</script> +</body> diff --git a/testing/web-platform/tests/css/css-easing/linear-timing-functions-syntax.tentative.html b/testing/web-platform/tests/css/css-easing/linear-timing-functions-syntax.tentative.html new file mode 100644 index 0000000000..99b680d0bd --- /dev/null +++ b/testing/web-platform/tests/css/css-easing/linear-timing-functions-syntax.tentative.html @@ -0,0 +1,39 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Easing: getComputedStyle().animationTimingFunction with linear(...)</title> +<link rel="help" href="https://github.com/w3c/csswg-drafts/pull/6533"> +<meta name="assert" content="animation-timing-function: linear(...) parsing tests"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/computed-testcommon.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +</head> +<body> +<div id="target"></div> +<script> +test_valid_value("animation-timing-function", "linear(0 0%, 1 100%)"); +test_valid_value("animation-timing-function", "linear(0 0% 50%, 1 50% 100%)", "linear(0 0%, 0 50%, 1 50%, 1 100%)"); +test_valid_value("animation-timing-function", "linear(0, 0.5 25% 75%, 1 100% 100%)", "linear(0 0%, 0.5 25%, 0.5 75%, 1 100%, 1 100%)"); +test_valid_value("animation-timing-function", "linear(0, 1.3, 1, 0.92, 1, 0.99, 1, 1.004, 0.998, 1 100% 100%)", "linear(0 0%, 1.3 11.1111%, 1 22.2222%, 0.92 33.3333%, 1 44.4444%, 0.99 55.5556%, 1 66.6667%, 1.004 77.7778%, 0.998 88.8889%, 1 100%, 1 100%)"); + +test_invalid_value("animation-timing-function", "linear()"); +test_invalid_value("animation-timing-function", "linear(0)"); +test_invalid_value("animation-timing-function", "linear(100%)"); +test_invalid_value("animation-timing-function", "linear(0% 1 50%)"); +test_invalid_value("animation-timing-function", "linear(0 0% 100%)"); +test_invalid_value("animation-timing-function", "linear(0% 100% 0)"); +test_invalid_value("animation-timing-function", "linear(0 calc(50px - 50%), 0 calc(50em + 50em))"); +test_invalid_value("animation-timing-function", "linear(0 calc(50%, 50%), 0 calc(50% + 50%))"); + +test_computed_value("animation-timing-function", "linear(0, 1)", "linear(0 0%, 1 100%)"); +test_computed_value("animation-timing-function", "linear(0 calc(0%), 0 calc(100%))", "linear(0 0%, 0 100%)"); +test_computed_value("animation-timing-function", "linear(0 calc(50% - 50%), 0 calc(50% + 50%))", "linear(0 0%, 0 100%)"); +test_computed_value("animation-timing-function", "linear(0 calc(min(50%, 60%)), 0 100%)", "linear(0 50%, 0 100%)"); +test_computed_value("animation-timing-function", "linear(0 0% 50%, 1 50% 100%)", "linear(0 0%, 0 50%, 1 50%, 1 100%)"); +test_computed_value("animation-timing-function", "linear(0, 0.5 25% 75%, 1 100% 100%)", "linear(0 0%, 0.5 25%, 0.5 75%, 1 100%, 1 100%)"); +test_computed_value("animation-timing-function", "linear(0, 1.3, 1, 0.92, 1, 0.99, 1, 0.998, 1 100% 100%)", "linear(0 0%, 1.3 12.5%, 1 25%, 0.92 37.5%, 1 50%, 0.99 62.5%, 1 75%, 0.998 87.5%, 1 100%, 1 100%)"); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/css/css-easing/step-timing-functions-output.html b/testing/web-platform/tests/css/css-easing/step-timing-functions-output.html new file mode 100644 index 0000000000..978ac25df6 --- /dev/null +++ b/testing/web-platform/tests/css/css-easing/step-timing-functions-output.html @@ -0,0 +1,318 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<meta name="assert" +content="This test checks the output of step timing functions" /> +<title>Tests for the output of step timing functions</title> +<link rel="help" +href="https://drafts.csswg.org/css-easing/#step-timing-functions"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="testcommon.js"></script> +<body> +<div id="log"></div> +<script> +'use strict'; + +test(function(t) { + var target = createDiv(t); + target.style.position = 'absolute'; + var anim = target.animate([ { left: '0px', easing: 'step-start' }, + { left: '100px' } ], + { duration: 1000, + fill: 'forwards', + easing: 'cubic-bezier(0, 1.5, 1, 1.5)' }); + + // The bezier function produces values greater than 1 (but always less than 2) + // in (0.23368794, 1) + anim.currentTime = 0; + assert_equals(getComputedStyle(target).left, '100px'); + anim.currentTime = 230; + assert_equals(getComputedStyle(target).left, '100px'); + anim.currentTime = 250; + assert_equals(getComputedStyle(target).left, '200px'); + anim.currentTime = 1000; + assert_equals(getComputedStyle(target).left, '100px'); +}, 'step-start easing with input progress greater than 1'); + +test(function(t) { + var target = createDiv(t); + target.style.position = 'absolute'; + var anim = target.animate([ { left: '0px', easing: 'step-start' }, + { left: '100px' } ], + { duration: 1000, + fill: 'forwards', + easing: 'cubic-bezier(0, 3, 1, 3)' }); + + // The bezier function produces values: + // Input -> Output + // 0.0 0.0 + // 0.114 ~ 0.245 1.5~2.0, so current step is 2, jumps is 1 => 2.0 + // 0.245 ~ 0.6 2.0~2.4, so current step is 3, jumps is 1 => 3.0 + // 0.6 ~ 0.882 2.4~2.0, so current step is 3, jumps is 1 => 3.0 + // 0.882 ~ 0.976 2.0~1.5, so current step is 2, jumps is 1 => 2.0 + // 1.0 1.0 + anim.currentTime = 0; + assert_equals(getComputedStyle(target).left, '100px'); + anim.currentTime = 114; + assert_equals(getComputedStyle(target).left, '200px'); + anim.currentTime = 500; + assert_equals(getComputedStyle(target).left, '300px'); + anim.currentTime = 900; + assert_equals(getComputedStyle(target).left, '200px'); +}, 'step-start easing with input progress greater than 2'); + +test(function(t) { + var target = createDiv(t); + target.style.position = 'absolute'; + var anim = target.animate([ { left: '0px', easing: 'step-start' }, + { left: '100px' } ], + { duration: 1000, + fill: 'forwards', + easing: 'cubic-bezier(0, -0.5, 1, -0.5)' }); + + // The bezier function produces negative values (but always greater than -1) + // in (0, 0.766312060) + anim.currentTime = 0; + assert_equals(getComputedStyle(target).left, '100px'); + anim.currentTime = 750; + assert_equals(getComputedStyle(target).left, '0px'); + anim.currentTime = 800; + assert_equals(getComputedStyle(target).left, '100px'); + anim.currentTime = 1000; + assert_equals(getComputedStyle(target).left, '100px'); +}, 'step-start easing with input progress less than 0'); + +test(function(t) { + var target = createDiv(t); + target.style.position = 'absolute'; + var anim = target.animate([ { left: '0px', easing: 'step-start' }, + { left: '100px' } ], + { duration: 1000, + fill: 'forwards', + easing: 'cubic-bezier(0, -2, 1, -2)' }); + + // The bezier function produces values less than -1 (but always greater than + // -2) in the range (~0.118, ~0.755) + anim.currentTime = 0; + assert_equals(getComputedStyle(target).left, '100px'); + anim.currentTime = 100; + assert_equals(getComputedStyle(target).left, '0px'); + anim.currentTime = 500; + assert_equals(getComputedStyle(target).left, '-100px'); + anim.currentTime = 1000; + assert_equals(getComputedStyle(target).left, '100px'); +}, 'step-start easing with input progress less than -1'); + +test(function(t) { + var target = createDiv(t); + target.style.position = 'absolute'; + var anim = target.animate([ { left: '0px', easing: 'step-end' }, + { left: '100px' } ], + { duration: 1000, + fill: 'forwards', + easing: 'cubic-bezier(0, 1.5, 1, 1.5)' }); + + // The bezier function produces values greater than 1 (but always less than 2) + // in (0.23368794, 1) + anim.currentTime = 0; + assert_equals(getComputedStyle(target).left, '0px'); + anim.currentTime = 230; + assert_equals(getComputedStyle(target).left, '0px'); + anim.currentTime = 250; + assert_equals(getComputedStyle(target).left, '100px'); + anim.currentTime = 1000; + assert_equals(getComputedStyle(target).left, '100px'); +}, 'step-end easing with input progress greater than 1'); + +test(function(t) { + var target = createDiv(t); + target.style.position = 'absolute'; + var anim = target.animate([ { left: '0px', easing: 'step-end' }, + { left: '100px' } ], + { duration: 1000, + fill: 'forwards', + easing: 'cubic-bezier(0, 3, 1, 3)' }); + + // The bezier function produces values: + // Input -> Output + // 0.0 0.0 + // 0.114 ~ 0.245 1.5~2.0, so current step is 1, jumps is 1 => 1.0 + // 0.245 ~ 0.6 2.0~2.4, so current step is 2, jumps is 1 => 2.0 + // 0.6 ~ 0.882 2.4~2.0, so current step is 2, jumps is 1 => 2.0 + // 0.882 ~ 0.976 2.0~1.5, so current step is 1, jumps is 1 => 1.0 + // 1.0 1.0 + anim.currentTime = 0; + assert_equals(getComputedStyle(target).left, '0px'); + anim.currentTime = 114; + assert_equals(getComputedStyle(target).left, '100px'); + anim.currentTime = 500; + assert_equals(getComputedStyle(target).left, '200px'); + anim.currentTime = 900; + assert_equals(getComputedStyle(target).left, '100px'); +}, 'step-end easing with input progress greater than 2'); + +test(function(t) { + var target = createDiv(t); + target.style.position = 'absolute'; + var anim = target.animate([ { left: '0px', easing: 'step-end' }, + { left: '100px' } ], + { duration: 1000, + fill: 'forwards', + easing: 'cubic-bezier(0, -0.5, 1, -0.5)' }); + + // The bezier function produces negative values (but always greater than -1) + // in (0, 0.766312060) + anim.currentTime = 0; + assert_equals(getComputedStyle(target).left, '0px'); + anim.currentTime = 750; + assert_equals(getComputedStyle(target).left, '-100px'); + anim.currentTime = 800; + assert_equals(getComputedStyle(target).left, '0px'); + anim.currentTime = 1000; + assert_equals(getComputedStyle(target).left, '100px'); +}, 'step-end easing with input progress less than 0'); + +test(function(t) { + var target = createDiv(t); + target.style.position = 'absolute'; + var anim = target.animate([ { left: '0px', easing: 'steps(1, jump-both)' }, + { left: '100px' } ], + { duration: 1000, + fill: 'forwards', + easing: 'cubic-bezier(0, 1.5, 1, 1.5)' }); + + // The bezier function produces values greater than 1 (but always less than 2) + // in (0.23368794, 1) + anim.currentTime = 0; + assert_equals(getComputedStyle(target).left, '50px'); + anim.currentTime = 230; + assert_equals(getComputedStyle(target).left, '50px'); + anim.currentTime = 250; + assert_equals(getComputedStyle(target).left, '100px'); + anim.currentTime = 1000; + assert_equals(getComputedStyle(target).left, '100px'); +}, 'steps(1, jump-both) easing with input progress greater than 1'); + +test(function(t) { + var target = createDiv(t); + target.style.position = 'absolute'; + var anim = target.animate([ { left: '0px', easing: 'steps(1, jump-both)' }, + { left: '100px' } ], + { duration: 1000, + fill: 'forwards', + easing: 'cubic-bezier(0, 3, 1, 3)' }); + + // The bezier function produces values: + // Input -> Output + // 0.0 0.0, so current step is 1, jumps is 2 => 0.5 + // 0.114 ~ 0.245 1.5~2.0, so current step is 2, jumps is 2 => 1.0 + // 0.245 ~ 0.6 2.0~2.4, so current step is 3, jumps is 2 => 1.5 + // 0.6 ~ 0.882 2.4~2.0, so current step is 3, jumps is 2 => 1.5 + // 0.882 ~ 0.976 2.0~1.5, so current step is 2, jumps is 2 => 1.0 + // 1.0 1.0 + anim.currentTime = 0; + assert_equals(getComputedStyle(target).left, '50px'); + anim.currentTime = 114; + assert_equals(getComputedStyle(target).left, '100px'); + anim.currentTime = 500; + assert_equals(getComputedStyle(target).left, '150px'); + anim.currentTime = 900; + assert_equals(getComputedStyle(target).left, '100px'); +}, 'steps(1, jump-both) easing with input progress greater than 2'); + +test(function(t) { + var target = createDiv(t); + target.style.position = 'absolute'; + var anim = target.animate([ { left: '0px', easing: 'steps(1, jump-both)' }, + { left: '100px' } ], + { duration: 1000, + fill: 'forwards', + easing: 'cubic-bezier(0, -0.5, 1, -0.5)' }); + + // The bezier function produces negative values (but always greater than -0.5) + // in (0, 0.766312060). + anim.currentTime = 0; + assert_equals(getComputedStyle(target).left, '50px'); + anim.currentTime = 750; + // current step is 0, jumps is 2. + assert_equals(getComputedStyle(target).left, '0px'); + anim.currentTime = 800; + assert_equals(getComputedStyle(target).left, '50px'); + anim.currentTime = 1000; + assert_equals(getComputedStyle(target).left, '100px'); +}, 'steps(1, jump-both) easing with input progress less than 0'); + +test(function(t) { + var target = createDiv(t); + target.style.position = 'absolute'; + var anim = target.animate([ { left: '0px', easing: 'steps(2, jump-none)' }, + { left: '100px' } ], + { duration: 1000, + fill: 'forwards', + easing: 'cubic-bezier(0, 1.5, 1, 1.5)' }); + + // The bezier function produces values between 0.5 and 1 in + // (~0.0442, 0.23368), and values between 1 and 2 in (0.23368794, 1). + anim.currentTime = 0; + assert_equals(getComputedStyle(target).left, '0px'); + anim.currentTime = 45; + assert_equals(getComputedStyle(target).left, '100px'); + anim.currentTime = 230; + assert_equals(getComputedStyle(target).left, '100px'); + anim.currentTime = 250; + assert_equals(getComputedStyle(target).left, '200px'); + anim.currentTime = 1000; + assert_equals(getComputedStyle(target).left, '100px'); +}, 'steps(2, jump-none) easing with input progress greater than 1'); + +test(function(t) { + var target = createDiv(t); + target.style.position = 'absolute'; + var anim = target.animate([ { left: '0px', easing: 'steps(2, jump-none)' }, + { left: '100px' } ], + { duration: 1000, + fill: 'forwards', + easing: 'cubic-bezier(0, 3, 1, 3)' }); + + // The bezier function produces values: + // Input -> Output + // 0.0 0.0, so current step is 0, jumps is 1 => 0.0 + // 0.114 ~ 0.245 1.5~2.0, so current step is 3, jumps is 1 => 3.0 + // 0.245 ~ 0.6 2.0~2.4, so current step is 4, jumps is 1 => 4.0 + // 0.6 ~ 0.882 2.4~2.0, so current step is 4, jumps is 1 => 4.0 + // 0.882 ~ 0.976 2.0~1.5, so current step is 3, jumps is 1 => 3.0 + // 1.0 1.0 + anim.currentTime = 0; + assert_equals(getComputedStyle(target).left, '0px'); + anim.currentTime = 114; + assert_equals(getComputedStyle(target).left, '300px'); + anim.currentTime = 500; + assert_equals(getComputedStyle(target).left, '400px'); + anim.currentTime = 900; + assert_equals(getComputedStyle(target).left, '300px'); +}, 'steps(2, jump-none) easing with input progress greater than 2'); + +test(function(t) { + var target = createDiv(t); + target.style.position = 'absolute'; + var anim = target.animate([ { left: '0px', easing: 'steps(2, jump-none)' }, + { left: '100px' } ], + { duration: 1000, + fill: 'forwards', + easing: 'cubic-bezier(0, -0.5, 1, -0.5)' }); + + // The bezier function produces negative values (but always greater than -0.5) + // in (0, 0.766312060). + anim.currentTime = 0; + assert_equals(getComputedStyle(target).left, '0px'); + anim.currentTime = 750; + // current step is -1, jumps is 1. + assert_equals(getComputedStyle(target).left, '-100px'); + anim.currentTime = 800; + assert_equals(getComputedStyle(target).left, '0px'); + anim.currentTime = 1000; + assert_equals(getComputedStyle(target).left, '100px'); +}, 'steps(2, jump-none) easing with input progress less than 0'); + +</script> +</body> diff --git a/testing/web-platform/tests/css/css-easing/step-timing-functions-syntax.html b/testing/web-platform/tests/css/css-easing/step-timing-functions-syntax.html new file mode 100644 index 0000000000..4e8b21e441 --- /dev/null +++ b/testing/web-platform/tests/css/css-easing/step-timing-functions-syntax.html @@ -0,0 +1,34 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<meta name="assert" +content="This test checks the syntax output of step timing functions" /> +<title>Step timing function syntax tests</title> +<link rel="help" + href="https://drafts.csswg.org/css-easing-1/#step-timing-functions"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="testcommon.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +<body> +<div id="log"></div> +<script> +"use strict"; + +test_valid_value("animation-timing-function", "step-start", "steps(1, start)"); +test_valid_value("animation-timing-function", "step-end", "steps(1)"); +test_valid_value("animation-timing-function", "steps(1, start)"); +test_valid_value("animation-timing-function", "steps(1, end)", "steps(1)"); +test_valid_value("animation-timing-function", "steps(1, jump-start)"); +test_valid_value("animation-timing-function", "steps(1, jump-end)", "steps(1)"); +test_valid_value("animation-timing-function", "steps(1, jump-both)"); +test_valid_value("animation-timing-function", "steps(2, jump-none)"); + +test_invalid_value("animation-timing-function", "steps(0, start)"); +test_invalid_value("animation-timing-function", "steps(0, end)"); +test_invalid_value("animation-timing-function", "steps(0, jump-start)"); +test_invalid_value("animation-timing-function", "steps(0, jump-end)"); +test_invalid_value("animation-timing-function", "steps(0, jump-both)"); +test_invalid_value("animation-timing-function", "steps(1, jump-none)"); + +</script> +</body> diff --git a/testing/web-platform/tests/css/css-easing/testcommon.js b/testing/web-platform/tests/css/css-easing/testcommon.js new file mode 100644 index 0000000000..9fd25b8650 --- /dev/null +++ b/testing/web-platform/tests/css/css-easing/testcommon.js @@ -0,0 +1,65 @@ +'use strict'; + +// Creates a <div> element, appends it to the document body and +// removes the created element during test cleanup. +function createDiv(test, doc) { + return createElement(test, 'div', doc); +} + +// Creates an element with the given |tagName|, appends it to the document body +// and removes the created element during test cleanup. +// If |tagName| is null or undefined, creates a <div> element. +function createElement(test, tagName, doc) { + if (!doc) { + doc = document; + } + var element = doc.createElement(tagName || 'div'); + doc.body.appendChild(element); + test.add_cleanup(function() { + element.remove(); + }); + return element; +} + +// Convert px unit value to a Number +function pxToNum(str) { + return Number(String(str).match(/^(-?[\d.]+)px$/)[1]); +} + +// Cubic bezier with control points (0, 0), (x1, y1), (x2, y2), and (1, 1). +function cubicBezier(x1, y1, x2, y2) { + function xForT(t) { + var omt = 1-t; + return 3 * omt * omt * t * x1 + 3 * omt * t * t * x2 + t * t * t; + } + + function yForT(t) { + var omt = 1-t; + return 3 * omt * omt * t * y1 + 3 * omt * t * t * y2 + t * t * t; + } + + function tForX(x) { + // Binary subdivision. + var mint = 0, maxt = 1; + for (var i = 0; i < 30; ++i) { + var guesst = (mint + maxt) / 2; + var guessx = xForT(guesst); + if (x < guessx) { + maxt = guesst; + } else { + mint = guesst; + } + } + return (mint + maxt) / 2; + } + + return function bezierClosure(x) { + if (x == 0) { + return 0; + } + if (x == 1) { + return 1; + } + return yForT(tForX(x)); + } +} diff --git a/testing/web-platform/tests/css/css-easing/timing-functions-syntax-computed.html b/testing/web-platform/tests/css/css-easing/timing-functions-syntax-computed.html new file mode 100644 index 0000000000..ad37d2769e --- /dev/null +++ b/testing/web-platform/tests/css/css-easing/timing-functions-syntax-computed.html @@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Easing: getComputedStyle().animationTimingFunction</title> +<link rel="help" href="https://drafts.csswg.org/css-easing/#timing-functions"> +<meta name="assert" content="animation-timing-function computed value is a computed <easing-function> list."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/computed-testcommon.js"></script> +</head> +<body> +<div id="target"></div> +<script> +test_computed_value("animation-timing-function", "linear"); + +test_computed_value("animation-timing-function", "ease"); +test_computed_value("animation-timing-function", "ease-in"); +test_computed_value("animation-timing-function", "ease-out"); +test_computed_value("animation-timing-function", "ease-in-out"); +test_computed_value("animation-timing-function", "cubic-bezier(0.1, 0.2, 0.8, 0.9)"); +test_computed_value("animation-timing-function", "cubic-bezier(0, -2, 1, 3)"); +test_computed_value("animation-timing-function", "cubic-bezier(0, 0.7, 1, 1.3)"); + + +test_computed_value("animation-timing-function", "steps(4, start)"); +test_computed_value("animation-timing-function", "steps(2, end)", "steps(2)"); +test_computed_value("animation-timing-function", "steps(2, jump-start)"); +test_computed_value("animation-timing-function", "steps(2, jump-end)", "steps(2)"); +test_computed_value("animation-timing-function", "steps(2, jump-both)"); +test_computed_value("animation-timing-function", "steps(2, jump-none)"); + +test_computed_value("animation-timing-function", "linear, ease, linear"); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/css/css-easing/timing-functions-syntax-invalid.html b/testing/web-platform/tests/css/css-easing/timing-functions-syntax-invalid.html new file mode 100644 index 0000000000..b279369b3b --- /dev/null +++ b/testing/web-platform/tests/css/css-easing/timing-functions-syntax-invalid.html @@ -0,0 +1,26 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Easing: parsing animation-timing-function with invalid values</title> +<link rel="help" href="https://drafts.csswg.org/css-easing/#timing-functions"> +<meta name="assert" content="animation-timing-function supports only the grammar '<timing-function> #'."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +</head> +<body> +<script> +test_invalid_value("animation-timing-function", "auto"); +test_invalid_value("animation-timing-function", "ease-in ease-out"); +test_invalid_value("animation-timing-function", "cubic-bezier(1, 2, 3)"); +test_invalid_value("animation-timing-function", "cubic-bezier(1, 2, 3, infinite)"); +test_invalid_value("animation-timing-function", "cubic-bezier(1, 2, 3, 4, 5)"); +test_invalid_value("animation-timing-function", "cubic-bezier(-0.1, 0.1, 0.5, 0.9)"); +test_invalid_value("animation-timing-function", "cubic-bezier(0.5, 0.1, 1.1, 0.9)"); + +test_invalid_value("animation-timing-function", "initial, cubic-bezier(0, -2, 1, 3)"); +test_invalid_value("animation-timing-function", "cubic-bezier(0, -2, 1, 3), initial"); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/css/css-easing/timing-functions-syntax-valid.html b/testing/web-platform/tests/css/css-easing/timing-functions-syntax-valid.html new file mode 100644 index 0000000000..fbeffea73f --- /dev/null +++ b/testing/web-platform/tests/css/css-easing/timing-functions-syntax-valid.html @@ -0,0 +1,35 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Easing: parsing animation-timing-function with valid values</title> +<link rel="help" href="https://drafts.csswg.org/css-easing/#timing-functions"> +<meta name="assert" content="animation-timing-function supports the full grammar '<timing-function> #'."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +</head> +<body> +<script> +test_valid_value("animation-timing-function", "linear"); + +test_valid_value("animation-timing-function", "ease"); +test_valid_value("animation-timing-function", "ease-in"); +test_valid_value("animation-timing-function", "ease-out"); +test_valid_value("animation-timing-function", "ease-in-out"); +test_valid_value("animation-timing-function", "cubic-bezier(0.1, 0.2, 0.8, 0.9)"); +test_valid_value("animation-timing-function", "cubic-bezier(0, -2, 1, 3)"); +test_valid_value("animation-timing-function", "cubic-bezier(0, 0.7, 1, 1.3)"); + + +test_valid_value("animation-timing-function", "steps(4, start)"); +test_valid_value("animation-timing-function", "steps(2, end)", "steps(2)"); +test_valid_value("animation-timing-function", "steps(2, jump-start)"); +test_valid_value("animation-timing-function", "steps(2, jump-end)", "steps(2)"); +test_valid_value("animation-timing-function", "steps(2, jump-both)"); +test_valid_value("animation-timing-function", "steps(2, jump-none)"); + +test_valid_value("animation-timing-function", "linear, ease, linear"); +</script> +</body> +</html> |