diff options
Diffstat (limited to '')
8 files changed, 1273 insertions, 0 deletions
diff --git a/dom/animation/test/style/test_animation-seeking-with-current-time.html b/dom/animation/test/style/test_animation-seeking-with-current-time.html new file mode 100644 index 0000000000..265de8f0f5 --- /dev/null +++ b/dom/animation/test/style/test_animation-seeking-with-current-time.html @@ -0,0 +1,123 @@ +<!doctype html> +<html> + <head> + <meta charset=utf-8> + <title>Tests for seeking using Animation.currentTime</title> + <style> +.animated-div { + margin-left: -10px; + animation-timing-function: linear ! important; +} + +@keyframes anim { + from { margin-left: 0px; } + to { margin-left: 100px; } +} + </style> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="../testcommon.js"></script> + </head> + <body> + <div id="log"></div> + <script type="text/javascript"> +'use strict'; + +function assert_marginLeft_equals(target, expect, description) { + var marginLeft = parseFloat(getComputedStyle(target).marginLeft); + assert_equals(marginLeft, expect, description); +} + +promise_test(function(t) { + var div = addDiv(t, {'class': 'animated-div'}); + div.style.animation = "anim 100s"; + var animation = div.getAnimations()[0]; + + return animation.ready.then(function() { + animation.currentTime = 90 * MS_PER_SEC; + assert_marginLeft_equals(div, 90, + 'Computed style is updated when seeking forwards in active interval'); + + animation.currentTime = 10 * MS_PER_SEC; + assert_marginLeft_equals(div, 10, + 'Computed style is updated when seeking backwards in active interval'); + }); +}, 'Seeking forwards and backward in active interval'); + +promise_test(function(t) { + var div = addDiv(t, {'class': 'animated-div'}); + div.style.animation = "anim 100s 100s"; + var animation = div.getAnimations()[0]; + + return animation.ready.then(function() { + assert_marginLeft_equals(div, -10, + 'Computed style is unaffected in before phase with no backwards fill'); + + // before -> active (non-active -> active) + animation.currentTime = 150 * MS_PER_SEC; + assert_marginLeft_equals(div, 50, + 'Computed style is updated when seeking forwards from ' + + 'not \'in effect\' to \'in effect\' state'); + }); +}, 'Seeking to non-\'in effect\' from \'in effect\' (before -> active)'); + +promise_test(function(t) { + var div = addDiv(t, {'class': 'animated-div'}); + div.style.animation = "anim 100s 100s"; + var animation = div.getAnimations()[0]; + + return animation.ready.then(function() { + // move to after phase + animation.currentTime = 250 * MS_PER_SEC; + assert_marginLeft_equals(div, -10, + 'Computed style is unaffected in after phase with no forwards fill'); + + // after -> active (non-active -> active) + animation.currentTime = 150 * MS_PER_SEC; + assert_marginLeft_equals(div, 50, + 'Computed style is updated when seeking backwards from ' + + 'not \'in effect\' to \'in effect\' state'); + }); +}, 'Seeking to non-\'in effect\' from \'in effect\' (after -> active)'); + +promise_test(function(t) { + var div = addDiv(t, {'class': 'animated-div'}); + div.style.animation = "anim 100s 100s"; + var animation = div.getAnimations()[0]; + + return animation.ready.then(function() { + // move to active phase + animation.currentTime = 150 * MS_PER_SEC; + assert_marginLeft_equals(div, 50, + 'Computed value is set during active phase'); + + // active -> before + animation.currentTime = 50 * MS_PER_SEC; + assert_marginLeft_equals(div, -10, + 'Computed value is not effected after seeking backwards from ' + + '\'in effect\' to not \'in effect\' state'); + }); +}, 'Seeking to \'in effect\' from non-\'in effect\' (active -> before)'); + +promise_test(function(t) { + var div = addDiv(t, {'class': 'animated-div'}); + div.style.animation = "anim 100s 100s"; + var animation = div.getAnimations()[0]; + + return animation.ready.then(function() { + // move to active phase + animation.currentTime = 150 * MS_PER_SEC; + assert_marginLeft_equals(div, 50, + 'Computed value is set during active phase'); + + // active -> after + animation.currentTime = 250 * MS_PER_SEC; + assert_marginLeft_equals(div, -10, + 'Computed value is not affected after seeking forwards from ' + + '\'in effect\' to not \'in effect\' state'); + }); +}, 'Seeking to \'in effect\' from non-\'in effect\' (active -> after)'); + + </script> + </body> +</html> diff --git a/dom/animation/test/style/test_animation-seeking-with-start-time.html b/dom/animation/test/style/test_animation-seeking-with-start-time.html new file mode 100644 index 0000000000..e56db5f23d --- /dev/null +++ b/dom/animation/test/style/test_animation-seeking-with-start-time.html @@ -0,0 +1,123 @@ +<!doctype html> +<html> + <head> + <meta charset=utf-8> + <title>Tests for seeking using Animation.startTime</title> + <style> +.animated-div { + margin-left: -10px; + animation-timing-function: linear ! important; +} + +@keyframes anim { + from { margin-left: 0px; } + to { margin-left: 100px; } +} + </style> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="../testcommon.js"></script> + </head> + <body> + <div id="log"></div> + <script type="text/javascript"> +'use strict'; + +function assert_marginLeft_equals(target, expect, description) { + var marginLeft = parseFloat(getComputedStyle(target).marginLeft); + assert_equals(marginLeft, expect, description); +} + +promise_test(function(t) { + var div = addDiv(t, {'class': 'animated-div'}); + div.style.animation = "anim 100s"; + var animation = div.getAnimations()[0]; + + return animation.ready.then(function() { + animation.startTime = animation.timeline.currentTime - 90 * MS_PER_SEC + assert_marginLeft_equals(div, 90, + 'Computed style is updated when seeking forwards in active interval'); + + animation.startTime = animation.timeline.currentTime - 10 * MS_PER_SEC; + assert_marginLeft_equals(div, 10, + 'Computed style is updated when seeking backwards in active interval'); + }); +}, 'Seeking forwards and backward in active interval'); + +promise_test(function(t) { + var div = addDiv(t, {'class': 'animated-div'}); + div.style.animation = "anim 100s 100s"; + var animation = div.getAnimations()[0]; + + return animation.ready.then(function() { + assert_marginLeft_equals(div, -10, + 'Computed style is unaffected in before phase with no backwards fill'); + + // before -> active (non-active -> active) + animation.startTime = animation.timeline.currentTime - 150 * MS_PER_SEC; + assert_marginLeft_equals(div, 50, + 'Computed style is updated when seeking forwards from ' + + 'not \'in effect\' to \'in effect\' state'); + }); +}, 'Seeking to non-\'in effect\' from \'in effect\' (before -> active)'); + +promise_test(function(t) { + var div = addDiv(t, {'class': 'animated-div'}); + div.style.animation = "anim 100s 100s"; + var animation = div.getAnimations()[0]; + + return animation.ready.then(function() { + // move to after phase + animation.startTime = animation.timeline.currentTime - 250 * MS_PER_SEC; + assert_marginLeft_equals(div, -10, + 'Computed style is unaffected in after phase with no forwards fill'); + + // after -> active (non-active -> active) + animation.startTime = animation.timeline.currentTime - 150 * MS_PER_SEC; + assert_marginLeft_equals(div, 50, + 'Computed style is updated when seeking backwards from ' + + 'not \'in effect\' to \'in effect\' state'); + }); +}, 'Seeking to non-\'in effect\' from \'in effect\' (after -> active)'); + +promise_test(function(t) { + var div = addDiv(t, {'class': 'animated-div'}); + div.style.animation = "anim 100s 100s"; + var animation = div.getAnimations()[0]; + + return animation.ready.then(function() { + // move to active phase + animation.startTime = animation.timeline.currentTime - 150 * MS_PER_SEC; + assert_marginLeft_equals(div, 50, + 'Computed value is set during active phase'); + + // active -> before + animation.startTime = animation.timeline.currentTime - 50 * MS_PER_SEC; + assert_marginLeft_equals(div, -10, + 'Computed value is not affected after seeking backwards from ' + + '\'in effect\' to not \'in effect\' state'); + }); +}, 'Seeking to \'in effect\' from non-\'in effect\' (active -> before)'); + +promise_test(function(t) { + var div = addDiv(t, {'class': 'animated-div'}); + div.style.animation = "anim 100s 100s"; + var animation = div.getAnimations()[0]; + + return animation.ready.then(function() { + // move to active phase + animation.startTime = animation.timeline.currentTime - 150 * MS_PER_SEC; + assert_marginLeft_equals(div, 50, + 'Computed value is set during active phase'); + + // active -> after + animation.startTime = animation.timeline.currentTime - 250 * MS_PER_SEC; + assert_marginLeft_equals(div, -10, + 'Computed value is not affected after seeking forwards from ' + + '\'in effect\' to not \'in effect\' state'); + }); +}, 'Seeking to \'in effect\' from non-\'in effect\' (active -> after)'); + + </script> + </body> +</html> diff --git a/dom/animation/test/style/test_animation-setting-effect.html b/dom/animation/test/style/test_animation-setting-effect.html new file mode 100644 index 0000000000..8712072a51 --- /dev/null +++ b/dom/animation/test/style/test_animation-setting-effect.html @@ -0,0 +1,127 @@ +<!doctype html> +<html> + <head> + <meta charset=utf-8> + <title>Tests for setting effects by using Animation.effect</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src='../testcommon.js'></script> + </head> + <body> + <div id="log"></div> + <script type='text/javascript'> + +'use strict'; + +test(function(t) { + var target = addDiv(t); + var anim = new Animation(); + anim.effect = new KeyframeEffect(target, + { marginLeft: [ '0px', '100px' ] }, + 100 * MS_PER_SEC); + anim.currentTime = 50 * MS_PER_SEC; + assert_equals(getComputedStyle(target).marginLeft, '50px'); +}, 'After setting target effect on an animation with null effect, the ' + + 'animation still works'); + +test(function(t) { + var target = addDiv(t); + target.style.marginLeft = '10px'; + var anim = target.animate({ marginLeft: [ '0px', '100px' ] }, + 100 * MS_PER_SEC); + anim.currentTime = 50 * MS_PER_SEC; + assert_equals(getComputedStyle(target).marginLeft, '50px'); + + anim.effect = null; + assert_equals(getComputedStyle(target).marginLeft, '10px'); +}, 'After setting null target effect, the computed style of the target ' + + 'element becomes the initial value'); + +test(function(t) { + var target = addDiv(t); + var animA = target.animate({ marginLeft: [ '0px', '100px' ] }, + 100 * MS_PER_SEC); + var animB = new Animation(); + animA.currentTime = 50 * MS_PER_SEC; + animB.currentTime = 20 * MS_PER_SEC; + assert_equals(getComputedStyle(target).marginLeft, '50px', + 'original computed style of the target element'); + + animB.effect = animA.effect; + assert_equals(getComputedStyle(target).marginLeft, '20px', + 'new computed style of the target element'); +}, 'After setting the target effect from an existing animation, the computed ' + + 'style of the target effect should reflect the time of the updated ' + + 'animation.'); + +test(function(t) { + var target = addDiv(t); + target.style.marginTop = '-10px'; + var animA = target.animate({ marginLeft: [ '0px', '100px' ] }, + 100 * MS_PER_SEC); + var animB = target.animate({ marginTop: [ '0px', '100px' ] }, + 50 * MS_PER_SEC); + animA.currentTime = 50 * MS_PER_SEC; + animB.currentTime = 10 * MS_PER_SEC; + assert_equals(getComputedStyle(target).marginLeft, '50px', + 'original margin-left of the target element'); + assert_equals(getComputedStyle(target).marginTop, '20px', + 'original margin-top of the target element'); + + animB.effect = animA.effect; + assert_equals(getComputedStyle(target).marginLeft, '10px', + 'new margin-left of the target element'); + assert_equals(getComputedStyle(target).marginTop, '-10px', + 'new margin-top of the target element'); +}, 'After setting target effect with an animation to another animation which ' + + 'also has an target effect and both animation effects target to the same ' + + 'element, the computed style of this element should reflect the time and ' + + 'effect of the animation that was set'); + +test(function(t) { + var targetA = addDiv(t); + var targetB = addDiv(t); + targetB.style.marginLeft = '-10px'; + var animA = targetA.animate({ marginLeft: [ '0px', '100px' ] }, + 100 * MS_PER_SEC); + var animB = targetB.animate({ marginLeft: [ '0px', '100px' ] }, + 50 * MS_PER_SEC); + animA.currentTime = 50 * MS_PER_SEC; + animB.currentTime = 10 * MS_PER_SEC; + assert_equals(getComputedStyle(targetA).marginLeft, '50px', + 'original margin-left of the first element'); + assert_equals(getComputedStyle(targetB).marginLeft, '20px', + 'original margin-left of the second element'); + + animB.effect = animA.effect; + assert_equals(getComputedStyle(targetA).marginLeft, '10px', + 'new margin-left of the first element'); + assert_equals(getComputedStyle(targetB).marginLeft, '-10px', + 'new margin-left of the second element'); +}, 'After setting target effect with an animation to another animation which ' + + 'also has an target effect and these animation effects target to ' + + 'different elements, the computed styles of the two elements should ' + + 'reflect the time and effect of the animation that was set'); + +test(function(t) { + var target = addDiv(t); + var animA = target.animate({ marginLeft: [ '0px', '100px' ] }, + 50 * MS_PER_SEC); + var animB = target.animate({ marginTop: [ '0px', '50px' ] }, + 100 * MS_PER_SEC); + animA.currentTime = 20 * MS_PER_SEC; + animB.currentTime = 30 * MS_PER_SEC; + assert_equals(getComputedStyle(target).marginLeft, '40px'); + assert_equals(getComputedStyle(target).marginTop, '15px'); + + var effectA = animA.effect; + animA.effect = animB.effect; + animB.effect = effectA; + assert_equals(getComputedStyle(target).marginLeft, '60px'); + assert_equals(getComputedStyle(target).marginTop, '10px'); +}, 'After swapping effects of two playing animations, both animations are ' + + 'still running with the same current time'); + + </script> + </body> +</html> diff --git a/dom/animation/test/style/test_composite.html b/dom/animation/test/style/test_composite.html new file mode 100644 index 0000000000..1383b1b1e6 --- /dev/null +++ b/dom/animation/test/style/test_composite.html @@ -0,0 +1,142 @@ +<!doctype html> +<meta charset=utf-8> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../testcommon.js"></script> +<script src="/tests/SimpleTest/paint_listener.js"></script> +<style> +div { + /* Element needs geometry to be eligible for layerization */ + width: 20px; + height: 20px; + background-color: white; +} +</style> +<body> +<div id="log"></div> +<script> +'use strict'; + +if (!SpecialPowers.DOMWindowUtils.layerManagerRemote || + !SpecialPowers.getBoolPref( + 'layers.offmainthreadcomposition.async-animations')) { + // If OMTA is disabled, nothing to run. + done(); +} + +function waitForPaintsFlushed() { + return new Promise(function(resolve, reject) { + waitForAllPaintsFlushed(resolve); + }); +} + +promise_test(t => { + // Without this, the first test case fails on Android. + return waitForDocumentLoad(); +}, 'Ensure document has been loaded'); + +promise_test(t => { + var div; + return useTestRefreshMode(t).then(() => { + div = addDiv(t, { style: 'transform: translateX(100px)' }); + div.animate({ transform: ['translateX(0px)', 'translateX(200px)'], + composite: 'accumulate' }, + 100 * MS_PER_SEC); + + return waitForPaintsFlushed(); + }).then(() => { + SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(50 * MS_PER_SEC); + var transform = + SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform'); + assert_matrix_equals(transform, 'matrix(1, 0, 0, 1, 200, 0)', + 'Transform value at 50%'); + }); +}, 'Accumulate onto the base value'); + +promise_test(t => { + var div; + return useTestRefreshMode(t).then(() => { + div = addDiv(t); + div.animate({ transform: ['translateX(100px)', 'translateX(200px)'], + composite: 'replace' }, + 100 * MS_PER_SEC); + div.animate({ transform: ['translateX(0px)', 'translateX(100px)'], + composite: 'accumulate' }, + 100 * MS_PER_SEC); + + return waitForPaintsFlushed(); + }).then(() => { + SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(50 * MS_PER_SEC); + var transform = + SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform'); + assert_matrix_equals(transform, 'matrix(1, 0, 0, 1, 200, 0)', + 'Transform value at 50%'); + }); +}, 'Accumulate onto an underlying animation value'); + +promise_test(t => { + var div; + return useTestRefreshMode(t).then(() => { + div = addDiv(t, { style: 'transform: translateX(100px)' }); + div.animate([{ transform: 'translateX(100px)', composite: 'accumulate' }, + { transform: 'translateX(300px)', composite: 'replace' }], + 100 * MS_PER_SEC); + + return waitForPaintsFlushed(); + }).then(() => { + SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(50 * MS_PER_SEC); + var transform = + SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform'); + assert_matrix_equals(transform, 'matrix(1, 0, 0, 1, 250, 0)', + 'Transform value at 50s'); + }); +}, 'Composite when mixing accumulate and replace'); + +promise_test(t => { + var div; + return useTestRefreshMode(t).then(() => { + div = addDiv(t, { style: 'transform: translateX(100px)' }); + div.animate([{ transform: 'translateX(100px)', composite: 'replace' }, + { transform: 'translateX(300px)' }], + { duration: 100 * MS_PER_SEC, composite: 'accumulate' }); + return waitForPaintsFlushed(); + }).then(() => { + SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(50 * MS_PER_SEC); + var transform = + SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform'); + assert_matrix_equals(transform, 'matrix(1, 0, 0, 1, 250, 0)', + 'Transform value at 50%'); + }); +}, 'Composite specified on a keyframe overrides the composite mode of the ' + + 'effect'); + +promise_test(t => { + var div; + var anim; + return useTestRefreshMode(t).then(() => { + div = addDiv(t); + div.animate({ transform: [ 'scale(2)', 'scale(2)' ] }, 100 * MS_PER_SEC); + anim = div.animate({ transform: [ 'scale(4)', 'scale(4)' ] }, + { duration: 100 * MS_PER_SEC, composite: 'add' }); + + return waitForPaintsFlushed(); + }).then(() => { + var transform = + SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform'); + assert_matrix_equals(transform, 'matrix(8, 0, 0, 8, 0, 0)', + 'The additive scale value should be scale(8)'); // scale(2) scale(4) + + anim.effect.composite = 'accumulate'; + return waitForPaintsFlushed(); + }).then(() => { + SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(1); + var transform = + SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform'); + assert_matrix_equals(transform, 'matrix(5, 0, 0, 5, 0, 0)', + // (scale(2 - 1) + scale(4 - 1) + scale(1)) + 'The accumulate scale value should be scale(5)'); + }); +}, 'Composite operation change'); + +</script> +</body> diff --git a/dom/animation/test/style/test_interpolation-from-interpolatematrix-to-none.html b/dom/animation/test/style/test_interpolation-from-interpolatematrix-to-none.html new file mode 100644 index 0000000000..1da95392eb --- /dev/null +++ b/dom/animation/test/style/test_interpolation-from-interpolatematrix-to-none.html @@ -0,0 +1,43 @@ +<!doctype html> +<meta charset=utf-8> +<script src='/resources/testharness.js'></script> +<script src='/resources/testharnessreport.js'></script> +<script src='../testcommon.js'></script> +<div id='log'></div> +<script type='text/javascript'> +'use strict'; + +test(function(t) { + var target = addDiv(t); + target.style.transform = 'translateX(100px)'; + target.style.transition = 'all 10s linear -5s'; + getComputedStyle(target).transform; + + target.style.transform = 'rotate(90deg)'; + var interpolated_matrix = 'matrix(' + Math.cos(Math.PI / 4) + ',' + + Math.sin(Math.PI / 4) + ',' + + -Math.sin(Math.PI / 4) + ',' + + Math.cos(Math.PI / 4) + ',' + + '50, 0)'; + assert_matrix_equals(getComputedStyle(target).transform, + interpolated_matrix, + 'the equivalent matrix of ' + 'interpolatematrix(' + + 'translateX(100px), rotate(90deg), 0.5)'); + + // Trigger a new transition from + // interpolatematrix(translateX(100px), rotate(90deg), 0.5) to none + // with 'all 10s linear -5s'. + target.style.transform = 'none'; + interpolated_matrix = 'matrix(' + Math.cos(Math.PI / 8) + ',' + + Math.sin(Math.PI / 8) + ',' + + -Math.sin(Math.PI / 8) + ',' + + Math.cos(Math.PI / 8) + ',' + + '25, 0)'; + assert_matrix_equals(getComputedStyle(target).transform, + interpolated_matrix, + 'the expected matrix from interpolatematrix(' + + 'translateX(100px), rotate(90deg), 0.5) to none at 50%'); +}, 'Test interpolation from interpolatematrix to none at 50%'); + +</script> +</html> diff --git a/dom/animation/test/style/test_missing-keyframe-on-compositor.html b/dom/animation/test/style/test_missing-keyframe-on-compositor.html new file mode 100644 index 0000000000..8b92a89168 --- /dev/null +++ b/dom/animation/test/style/test_missing-keyframe-on-compositor.html @@ -0,0 +1,577 @@ +<!doctype html> +<meta charset=utf-8> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../testcommon.js"></script> +<script src="/tests/SimpleTest/paint_listener.js"></script> +<style> +div { + /* Element needs geometry to be eligible for layerization */ + width: 100px; + height: 100px; + background-color: white; +} +</style> +<body> +<div id="log"></div> +<script> +'use strict'; + +if (!SpecialPowers.DOMWindowUtils.layerManagerRemote || + !SpecialPowers.getBoolPref( + 'layers.offmainthreadcomposition.async-animations')) { + // If OMTA is disabled, nothing to run. + done(); +} + +function waitForPaintsFlushed() { + return new Promise(function(resolve, reject) { + waitForAllPaintsFlushed(resolve); + }); +} + +// Note that promise tests run in sequence so this ensures the document is +// loaded before any of the other tests run. +promise_test(t => { + // Without this, the first test case fails on Android. + return waitForDocumentLoad(); +}, 'Ensure document has been loaded'); + +promise_test(t => { + var div; + return useTestRefreshMode(t).then(() => { + div = addDiv(t, { style: 'opacity: 0.1' }); + div.animate({ opacity: 1 }, 100 * MS_PER_SEC); + return waitForPaintsFlushed(); + }).then(() => { + var opacity = + SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'opacity'); + assert_equals(opacity, '0.1', + 'The initial opacity value should be the base value'); + }); +}, 'Initial opacity value for animation with no no keyframe at offset 0'); + +promise_test(t => { + var div; + return useTestRefreshMode(t).then(() => { + div = addDiv(t, { style: 'opacity: 0.1' }); + div.animate({ opacity: [ 0.5, 1 ] }, 100 * MS_PER_SEC); + div.animate({ opacity: 1 }, 100 * MS_PER_SEC); + + return waitForPaintsFlushed(); + }).then(() => { + var opacity = + SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'opacity'); + assert_equals(opacity, '0.5', + 'The initial opacity value should be the value of ' + + 'lower-priority animation value'); + }); +}, 'Initial opacity value for animation with no keyframe at offset 0 when ' + + 'there is a lower-priority animation'); + +promise_test(t => { + var div; + return useTestRefreshMode(t).then(() => { + div = addDiv(t, { style: 'opacity: 0.1; transition: opacity 100s linear' }); + getComputedStyle(div).opacity; + + div.style.opacity = '0.5'; + getComputedStyle(div).opacity; + + div.animate({ opacity: 1 }, 100 * MS_PER_SEC); + + return waitForPaintsFlushed(); + }).then(() => { + var opacity = + SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'opacity'); + assert_equals(opacity, '0.1', + 'The initial opacity value should be the initial value of ' + + 'the transition'); + }); +}, 'Initial opacity value for animation with no keyframe at offset 0 when ' + + 'there is a transition on the same property'); + +promise_test(t => { + var div; + return useTestRefreshMode(t).then(() => { + div = addDiv(t, { style: 'opacity: 0' }); + div.animate([{ offset: 0, opacity: 1 }], 100 * MS_PER_SEC); + + return waitForPaintsFlushed(); + }).then(() => { + SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(50 * MS_PER_SEC); + + var opacity = + SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'opacity'); + assert_equals(opacity, '0.5', + 'Opacity value at 50% should be composed onto the base ' + + 'value'); + }); +}, 'Opacity value for animation with no keyframe at offset 1 at 50% '); + +promise_test(t => { + var div; + return useTestRefreshMode(t).then(() => { + div = addDiv(t, { style: 'opacity: 0' }); + div.animate({ opacity: [ 0.5, 0.5 ] }, 100 * MS_PER_SEC); + div.animate([{ offset: 0, opacity: 1 }], 100 * MS_PER_SEC); + + return waitForPaintsFlushed(); + }).then(() => { + SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(50 * MS_PER_SEC); + + var opacity = + SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'opacity'); + assert_equals(opacity, '0.75', // (0.5 + 1) * 0.5 + 'Opacity value at 50% should be composed onto the value ' + + 'of middle of lower-priority animation'); + }); +}, 'Opacity value for animation with no keyframe at offset 1 at 50% when ' + + 'there is a lower-priority animation'); + +promise_test(t => { + var div; + return useTestRefreshMode(t).then(() => { + div = addDiv(t, { style: 'opacity: 0; transition: opacity 100s linear' }); + getComputedStyle(div).opacity; + + div.style.opacity = '0.5'; + getComputedStyle(div).opacity; + + div.animate([{ offset: 0, opacity: 1 }], 100 * MS_PER_SEC); + + return waitForPaintsFlushed(); + }).then(() => { + SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(50 * MS_PER_SEC); + + var opacity = + SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'opacity'); + assert_equals(opacity, '0.625', // ((0 + 0.5) * 0.5 + 1) * 0.5 + 'Opacity value at 50% should be composed onto the value ' + + 'of middle of transition'); + }); +}, 'Opacity value for animation with no keyframe at offset 1 at 50% when ' + + 'there is a transition on the same property'); + +promise_test(t => { + var div; + var lowerAnimation; + return useTestRefreshMode(t).then(() => { + div = addDiv(t); + lowerAnimation = div.animate({ opacity: [ 0.5, 1 ] }, 100 * MS_PER_SEC); + var higherAnimation = div.animate({ opacity: 1 }, 100 * MS_PER_SEC); + + return waitForPaintsFlushed(); + }).then(() => { + lowerAnimation.pause(); + return waitForPaintsFlushed(); + }).then(() => { + SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(50 * MS_PER_SEC); + + var opacity = + SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'opacity'); + // The underlying value is the value that is staying at 0ms of the + // lowerAnimation, that is 0.5. + // (0.5 + 1.0) * (50 * MS_PER_SEC / 100 * MS_PER_SEC) = 0.75. + assert_equals(opacity, '0.75', + 'Composed opacity value should be composed onto the value ' + + 'of lower-priority paused animation'); + }); +}, 'Opacity value for animation with no keyframe at offset 0 at 50% when ' + + 'composed onto a paused underlying animation'); + +promise_test(t => { + var div; + var lowerAnimation; + return useTestRefreshMode(t).then(() => { + div = addDiv(t); + lowerAnimation = div.animate({ opacity: [ 0.5, 1 ] }, 100 * MS_PER_SEC); + var higherAnimation = div.animate({ opacity: 1 }, 100 * MS_PER_SEC); + + return waitForPaintsFlushed(); + }).then(() => { + lowerAnimation.playbackRate = 0; + return waitForPaintsFlushed(); + }).then(() => { + SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(50 * MS_PER_SEC); + + var opacity = + SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'opacity'); + // The underlying value is the value that is staying at 0ms of the + // lowerAnimation, that is 0.5. + // (0.5 + 1.0) * (50 * MS_PER_SEC / 100 * MS_PER_SEC) = 0.75. + assert_equals(opacity, '0.75', + 'Composed opacity value should be composed onto the value ' + + 'of lower-priority zero playback rate animation'); + }); +}, 'Opacity value for animation with no keyframe at offset 0 at 50% when ' + + 'composed onto a zero playback rate underlying animation'); + +promise_test(t => { + var div; + var lowerAnimation; + return useTestRefreshMode(t).then(() => { + div = addDiv(t); + lowerAnimation = div.animate({ opacity: [ 1, 0.5 ] }, 100 * MS_PER_SEC); + var higherAnimation = div.animate({ opacity: 1 }, 100 * MS_PER_SEC); + + return waitForPaintsFlushed(); + }).then(() => { + lowerAnimation.effect.updateTiming({ + duration: 0, + fill: 'forwards', + }); + return waitForPaintsFlushed(); + }).then(() => { + SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(50 * MS_PER_SEC); + + var opacity = + SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'opacity'); + // The underlying value is the value that is filling forwards state of the + // lowerAnimation, that is 0.5. + // (0.5 + 1.0) * (50 * MS_PER_SEC / 100 * MS_PER_SEC) = 0.75. + assert_equals(opacity, '0.75', + 'Composed opacity value should be composed onto the value ' + + 'of lower-priority zero active duration animation'); + }); +}, 'Opacity value for animation with no keyframe at offset 0 at 50% when ' + + 'composed onto a zero active duration underlying animation'); + +promise_test(t => { + var div; + return useTestRefreshMode(t).then(() => { + div = addDiv(t, { style: 'transform: translateX(100px)' }); + div.animate({ transform: 'translateX(200px)' }, 100 * MS_PER_SEC); + + return waitForPaintsFlushed(); + }).then(() => { + var transform = + SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform'); + assert_matrix_equals(transform, 'matrix(1, 0, 0, 1, 100, 0)', + 'The initial transform value should be the base value'); + }); +}, 'Initial transform value for animation with no keyframe at offset 0'); + +promise_test(t => { + var div; + return useTestRefreshMode(t).then(() => { + div = addDiv(t, { style: 'transform: translateX(100px)' }); + div.animate({ transform: [ 'translateX(200px)', 'translateX(300px)' ] }, + 100 * MS_PER_SEC); + div.animate({ transform: 'translateX(400px)' }, 100 * MS_PER_SEC); + + return waitForPaintsFlushed(); + }).then(() => { + var transform = + SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform'); + assert_matrix_equals(transform, 'matrix(1, 0, 0, 1, 200, 0)', + 'The initial transform value should be lower-priority animation value'); + }); +}, 'Initial transform value for animation with no keyframe at offset 0 when ' + + 'there is a lower-priority animation'); + +promise_test(t => { + var div; + return useTestRefreshMode(t).then(() => { + div = addDiv(t, { style: 'transform: translateX(100px);' + + 'transition: transform 100s linear' }); + getComputedStyle(div).transform; + + div.style.transform = 'translateX(200px)'; + getComputedStyle(div).transform; + + div.animate({ transform: 'translateX(400px)' }, 100 * MS_PER_SEC); + + return waitForPaintsFlushed(); + }).then(() => { + var transform = + SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform'); + assert_matrix_equals(transform, 'matrix(1, 0, 0, 1, 100, 0)', + 'The initial transform value should be the initial value of the ' + + 'transition'); + }); +}, 'Initial transform value for animation with no keyframe at offset 0 when ' + + 'there is a transition'); + +promise_test(t => { + var div; + return useTestRefreshMode(t).then(() => { + div = addDiv(t, { style: 'transform: translateX(100px)' }); + div.animate([{ offset: 0, transform: 'translateX(200pX)' }], + 100 * MS_PER_SEC); + + return waitForPaintsFlushed(); + }).then(() => { + SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(50 * MS_PER_SEC); + + var transform = + SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform'); + assert_matrix_equals(transform, 'matrix(1, 0, 0, 1, 150, 0)', + 'Transform value at 50% should be the base value'); + }); +}, 'Transform value for animation with no keyframe at offset 1 at 50%'); + +promise_test(t => { + var div; + return useTestRefreshMode(t).then(() => { + div = addDiv(t, { style: 'transform: translateX(100px)' }); + div.animate({ transform: [ 'translateX(200px)', 'translateX(200px)' ] }, + 100 * MS_PER_SEC); + div.animate([{ offset: 0, transform: 'translateX(300px)' }], + 100 * MS_PER_SEC); + + return waitForPaintsFlushed(); + }).then(() => { + SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(50 * MS_PER_SEC); + + var transform = + SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform'); + assert_matrix_equals(transform, 'matrix(1, 0, 0, 1, 250, 0)', + 'The final transform value should be the base value'); + }); +}, 'Transform value for animation with no keyframe at offset 1 at 50% when ' + + 'there is a lower-priority animation'); + +promise_test(t => { + var div; + return useTestRefreshMode(t).then(() => { + div = addDiv(t, { style: 'transform: translateX(100px);' + + 'transition: transform 100s linear' }); + getComputedStyle(div).transform; + + div.style.transform = 'translateX(200px)'; + getComputedStyle(div).transform; + + div.animate([{ offset: 0, transform: 'translateX(300px)' }], + 100 * MS_PER_SEC); + + return waitForPaintsFlushed(); + }).then(() => { + SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(50 * MS_PER_SEC); + + var transform = + SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform'); + // (150px + 300px) * 0.5 + assert_matrix_equals(transform, 'matrix(1, 0, 0, 1, 225, 0)', + 'The final transform value should be the final value of the transition'); + }); +}, 'Transform value for animation with no keyframe at offset 1 at 50% when ' + + 'there is a transition'); + +promise_test(t => { + var div; + var lowerAnimation; + return useTestRefreshMode(t).then(() => { + div = addDiv(t); + lowerAnimation = + div.animate({ transform: [ 'translateX(100px)', 'translateX(200px)' ] }, + 100 * MS_PER_SEC); + var higherAnimation = div.animate({ transform: 'translateX(300px)' }, + 100 * MS_PER_SEC); + + return waitForPaintsFlushed(); + }).then(() => { + lowerAnimation.pause(); + return waitForPaintsFlushed(); + }).then(() => { + SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(50 * MS_PER_SEC); + + var transform = + SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform'); + // The underlying value is the value that is staying at 0ms of the + // lowerAnimation, that is 100px. + // (100px + 300px) * (50 * MS_PER_SEC / 100 * MS_PER_SEC) = 200px. + assert_matrix_equals(transform, 'matrix(1, 0, 0, 1, 200, 0)', + 'Composed transform value should be composed onto the value of ' + + 'lower-priority paused animation'); + }); +}, 'Transform value for animation with no keyframe at offset 0 at 50% when ' + + 'composed onto a paused underlying animation'); + +promise_test(t => { + var div; + var lowerAnimation; + return useTestRefreshMode(t).then(() => { + div = addDiv(t); + lowerAnimation = + div.animate({ transform: [ 'translateX(100px)', 'translateX(200px)' ] }, + 100 * MS_PER_SEC); + var higherAnimation = div.animate({ transform: 'translateX(300px)' }, + 100 * MS_PER_SEC); + + return waitForPaintsFlushed(); + }).then(() => { + lowerAnimation.playbackRate = 0; + return waitForPaintsFlushed(); + }).then(() => { + SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(50 * MS_PER_SEC); + + var transform = + SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform'); + // The underlying value is the value that is staying at 0ms of the + // lowerAnimation, that is 100px. + // (100px + 300px) * (50 * MS_PER_SEC / 100 * MS_PER_SEC) = 200px. + assert_matrix_equals(transform, 'matrix(1, 0, 0, 1, 200, 0)', + 'Composed transform value should be composed onto the value of ' + + 'lower-priority zero playback rate animation'); + }); +}, 'Transform value for animation with no keyframe at offset 0 at 50% when ' + + 'composed onto a zero playback rate underlying animation'); + +promise_test(t => { + var div; + return useTestRefreshMode(t).then(() => { + div = addDiv(t); + var lowerAnimation = + div.animate({ transform: [ 'translateX(100px)', 'translateX(200px)' ] }, + { duration: 10 * MS_PER_SEC, + fill: 'forwards' }); + var higherAnimation = div.animate({ transform: 'translateX(300px)' }, + 100 * MS_PER_SEC); + + return waitForPaintsFlushed(); + }).then(() => { + SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(50 * MS_PER_SEC); + + // We need to wait for a paint so that we can send the state of the lower + // animation that is actually finished at this point. + return waitForPaintsFlushed(); + }).then(() => { + var transform = + SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform'); + // (200px + 300px) * (50 * MS_PER_SEC / 100 * MS_PER_SEC) = 250px. + assert_matrix_equals(transform, 'matrix(1, 0, 0, 1, 250, 0)', + 'Composed transform value should be composed onto the value of ' + + 'lower-priority animation with fill:forwards'); + }); +}, 'Transform value for animation with no keyframe at offset 0 at 50% when ' + + 'composed onto a underlying animation with fill:forwards'); + +promise_test(t => { + var div; + return useTestRefreshMode(t).then(() => { + div = addDiv(t); + var lowerAnimation = + div.animate({ transform: [ 'translateX(100px)', 'translateX(200px)' ] }, + { duration: 10 * MS_PER_SEC, + endDelay: -5 * MS_PER_SEC, + fill: 'forwards' }); + var higherAnimation = div.animate({ transform: 'translateX(300px)' }, + 100 * MS_PER_SEC); + + return waitForPaintsFlushed(); + }).then(() => { + SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(50 * MS_PER_SEC); + + // We need to wait for a paint just like the above test. + return waitForPaintsFlushed(); + }).then(() => { + var transform = + SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform'); + // (150px + 300px) * (50 * MS_PER_SEC / 100 * MS_PER_SEC) = 225px. + assert_matrix_equals(transform, 'matrix(1, 0, 0, 1, 225, 0)', + 'Composed transform value should be composed onto the value of ' + + 'lower-priority animation with fill:forwards and negative endDelay'); + }); +}, 'Transform value for animation with no keyframe at offset 0 at 50% when ' + + 'composed onto a underlying animation with fill:forwards and negative ' + + 'endDelay'); + +promise_test(t => { + var div; + return useTestRefreshMode(t).then(() => { + div = addDiv(t); + var lowerAnimation = + div.animate({ transform: [ 'translateX(100px)', 'translateX(200px)' ] }, + { duration: 10 * MS_PER_SEC, + endDelay: 100 * MS_PER_SEC, + fill: 'forwards' }); + var higherAnimation = div.animate({ transform: 'translateX(300px)' }, + 100 * MS_PER_SEC); + + return waitForPaintsFlushed(); + }).then(() => { + SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(50 * MS_PER_SEC); + + var transform = + SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform'); + // (200px + 300px) * 0.5 + assert_matrix_equals(transform, 'matrix(1, 0, 0, 1, 250, 0)', + 'Composed transform value should be composed onto the value of ' + + 'lower-priority animation with fill:forwards during positive endDelay'); + }); +}, 'Transform value for animation with no keyframe at offset 0 at 50% when ' + + 'composed onto a underlying animation with fill:forwards during positive ' + + 'endDelay'); + +promise_test(t => { + var div; + return useTestRefreshMode(t).then(() => { + div = addDiv(t, { style: 'transform: translateX(100px)' }); + div.animate({ transform: 'translateX(200px)' }, + { duration: 100 * MS_PER_SEC, delay: 50 * MS_PER_SEC }); + + return waitForPaintsFlushed(); + }).then(() => { + SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(100 * MS_PER_SEC); + + var transform = + SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform'); + assert_matrix_equals(transform, 'matrix(1, 0, 0, 1, 150, 0)', + 'Transform value for animation with positive delay should be composed ' + + 'onto the base style'); + }); +}, 'Transform value for animation with no keyframe at offset 0 and with ' + + 'positive delay'); + +promise_test(t => { + var div; + return useTestRefreshMode(t).then(() => { + div = addDiv(t, { style: 'transform: translateX(100px)' }); + + div.animate([{ offset: 0, transform: 'translateX(200px)'}], + { duration: 100 * MS_PER_SEC, + iterationStart: 1, + iterationComposite: 'accumulate' }); + + return waitForPaintsFlushed(); + }).then(() => { + var transform = + SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform'); + assert_matrix_equals(transform, 'matrix(1, 0, 0, 1, 300, 0)', + 'Transform value for animation with no keyframe at offset 1 and its ' + + 'iterationComposite is accumulate'); + }); +}, 'Transform value for animation with no keyframe at offset 1 and its ' + + 'iterationComposite is accumulate'); + +promise_test(t => { + var div; + return useTestRefreshMode(t).then(() => { + div = addDiv(t); + var lowerAnimation = + div.animate({ transform: [ 'translateX(100px)', 'translateX(200px)' ] }, + 100 * MS_PER_SEC); + var higherAnimation = div.animate({ transform: 'translateX(300px)' }, + 100 * MS_PER_SEC); + + lowerAnimation.timeline = null; + // Set current time at 50% duration. + lowerAnimation.currentTime = 50 * MS_PER_SEC; + + return waitForPaintsFlushed(); + }).then(() => { + SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(50 * MS_PER_SEC); + + var transform = + SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform'); + // (150px + 300px) * (50 * MS_PER_SEC / 100 * MS_PER_SEC) = 225px. + assert_matrix_equals(transform, 'matrix(1, 0, 0, 1, 225, 0)', + 'Composed transform value should be composed onto the value of ' + + 'lower-priority animation without timeline'); + }); +}, 'Transform value for animation with no keyframe at offset 0 at 50% when ' + + 'composed onto an animation without timeline'); + +</script> +</body> diff --git a/dom/animation/test/style/test_missing-keyframe.html b/dom/animation/test/style/test_missing-keyframe.html new file mode 100644 index 0000000000..4047e62408 --- /dev/null +++ b/dom/animation/test/style/test_missing-keyframe.html @@ -0,0 +1,110 @@ +<!doctype html> +<meta charset=utf-8> +<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(t => { + var div = addDiv(t, { style: 'margin-left: 100px' }); + div.animate([{ marginLeft: '200px' }], 100 * MS_PER_SEC); + + assert_equals(getComputedStyle(div).marginLeft, '100px', + 'The initial margin-left value should be the base value'); +}, 'Initial margin-left value for an animation with no keyframe at offset 0'); + +test(t => { + var div = addDiv(t, { style: 'margin-left: 100px' }); + div.animate([{ offset: 0, marginLeft: '200px' }, + { offset: 1, marginLeft: '300px' }], + 100 * MS_PER_SEC); + div.animate([{ marginLeft: '200px' }], 100 * MS_PER_SEC); + + assert_equals(getComputedStyle(div).marginLeft, '200px', + 'The initial margin-left value should be the initial value ' + + 'of lower-priority animation'); +}, 'Initial margin-left value for an animation with no keyframe at offset 0 ' + + 'is that of lower-priority animations'); + +test(t => { + var div = addDiv(t, { style: 'margin-left: 100px;' + + 'transition: margin-left 100s -50s linear'}); + flushComputedStyle(div); + + div.style.marginLeft = '200px'; + flushComputedStyle(div); + + div.animate([{ marginLeft: '300px' }], 100 * MS_PER_SEC); + + assert_equals(getComputedStyle(div).marginLeft, '150px', + 'The initial margin-left value should be the initial value ' + + 'of the transition'); +}, 'Initial margin-left value for an animation with no keyframe at offset 0 ' + + 'is that of transition'); + +test(t => { + var div = addDiv(t, { style: 'margin-left: 100px' }); + var animation = div.animate([{ offset: 0, marginLeft: '200px' }], + 100 * MS_PER_SEC); + + animation.currentTime = 50 * MS_PER_SEC; + assert_equals(getComputedStyle(div).marginLeft, '150px', + 'The margin-left value at 50% should be the base value'); +}, 'margin-left value at 50% for an animation with no keyframe at offset 1'); + +test(t => { + var div = addDiv(t, { style: 'margin-left: 100px' }); + var lowerAnimation = div.animate([{ offset: 0, marginLeft: '200px' }, + { offset: 1, marginLeft: '300px' }], + 100 * MS_PER_SEC); + var higherAnimation = div.animate([{ offset: 0, marginLeft: '400px' }], + 100 * MS_PER_SEC); + + lowerAnimation.currentTime = 50 * MS_PER_SEC; + higherAnimation.currentTime = 50 * MS_PER_SEC; + // (250px + 400px) * 0.5 + assert_equals(getComputedStyle(div).marginLeft, '325px', + 'The margin-left value at 50% should be additive value of ' + + 'lower-priority animation and higher-priority animation'); +}, 'margin-left value at 50% for an animation with no keyframe at offset 1 ' + + 'is that of lower-priority animations'); + +test(t => { + var div = addDiv(t, { style: 'margin-left: 100px;' + + 'transition: margin-left 100s linear' }); + flushComputedStyle(div); + + div.style.marginLeft = '300px'; + flushComputedStyle(div); + + div.animate([{ offset: 0, marginLeft: '200px' }], 100 * MS_PER_SEC); + + div.getAnimations().forEach(animation => { + animation.currentTime = 50 * MS_PER_SEC; + }); + // (200px + 200px) * 0.5 + assert_equals(getComputedStyle(div).marginLeft, '200px', + 'The margin-left value at 50% should be additive value of ' + + 'the transition and animation'); +}, 'margin-left value at 50% for an animation with no keyframe at offset 1 ' + + 'is that of transition'); + +test(t => { + var div = addDiv(t, { style: 'margin-left: 100px' }); + + var animation = div.animate([{ offset: 0, marginLeft: '200px' }], + { duration: 100 * MS_PER_SEC, + iterationStart: 1, + iterationComposite: 'accumulate' }); + + assert_equals(getComputedStyle(div).marginLeft, '300px', + 'The margin-left value should be additive value of the ' + + 'accumulation of the initial value onto the base value '); +}, 'margin-left value for an animation with no keyframe at offset 1 and its ' + + 'iterationComposite is accumulate'); + +</script> +</body> diff --git a/dom/animation/test/style/test_transform-non-normalizable-rotate3d.html b/dom/animation/test/style/test_transform-non-normalizable-rotate3d.html new file mode 100644 index 0000000000..ad2584ac40 --- /dev/null +++ b/dom/animation/test/style/test_transform-non-normalizable-rotate3d.html @@ -0,0 +1,28 @@ +<!doctype html> +<meta charset=utf-8> +<script src='/resources/testharness.js'></script> +<script src='/resources/testharnessreport.js'></script> +<script src='../testcommon.js'></script> +<div id='log'></div> +<script type='text/javascript'> +'use strict'; + +test(function(t) { + var target = addDiv(t); + target.style.transform = 'rotate3d(0, 0, 1, 90deg)'; + target.style.transition = 'all 10s linear -5s'; + getComputedStyle(target).transform; + + target.style.transform = 'rotate3d(0, 0, 0, 270deg)'; + var interpolated_matrix = 'matrix(' + Math.cos(Math.PI / 4) + ',' + + Math.sin(Math.PI / 4) + ',' + + -Math.sin(Math.PI / 4) + ',' + + Math.cos(Math.PI / 4) + ',' + + '0, 0)'; + assert_matrix_equals(getComputedStyle(target).transform, interpolated_matrix, + 'transition from a normal rotate3d to a ' + + 'non-normalizable rotate3d'); +}, 'Test interpolation on non-normalizable rotate3d function'); + +</script> +</html> |