diff options
Diffstat (limited to 'dom/animation/test/mozilla')
28 files changed, 1616 insertions, 0 deletions
diff --git a/dom/animation/test/mozilla/file_cubic_bezier_limits.html b/dom/animation/test/mozilla/file_cubic_bezier_limits.html new file mode 100644 index 0000000000..a0378f3953 --- /dev/null +++ b/dom/animation/test/mozilla/file_cubic_bezier_limits.html @@ -0,0 +1,167 @@ +<!doctype html> +<meta charset=utf-8> +<script src="../testcommon.js"></script> +<body> +<style> +@keyframes anim { + to { margin-left: 100px; } +} + +.transition-div { + margin-left: 100px; +} +</style> +<script> +'use strict'; + +// We clamp +infinity or -inifinity value in floating point to +// maximum floating point value or -maxinum floating point value. +const max_float = 3.40282e+38; + +test(function(t) { + var div = addDiv(t); + var anim = div.animate({ }, 100 * MS_PER_SEC); + + anim.effect.timing.easing = 'cubic-bezier(0, 1e+39, 0, 0)'; + assert_equals(anim.effect.timing.easing, + 'cubic-bezier(0, ' + max_float + ', 0, 0)', + 'y1 control point for effect easing is out of upper boundary'); + + anim.effect.timing.easing = 'cubic-bezier(0, 0, 0, 1e+39)'; + assert_equals(anim.effect.timing.easing, + 'cubic-bezier(0, 0, 0, ' + max_float + ')', + 'y2 control point for effect easing is out of upper boundary'); + + anim.effect.timing.easing = 'cubic-bezier(0, -1e+39, 0, 0)'; + assert_equals(anim.effect.timing.easing, + 'cubic-bezier(0, ' + -max_float + ', 0, 0)', + 'y1 control point for effect easing is out of lower boundary'); + + anim.effect.timing.easing = 'cubic-bezier(0, 0, 0, -1e+39)'; + assert_equals(anim.effect.timing.easing, + 'cubic-bezier(0, 0, 0, ' + -max_float + ')', + 'y2 control point for effect easing is out of lower boundary'); + +}, 'Clamp y1 and y2 control point out of boundaries for effect easing' ); + +test(function(t) { + var div = addDiv(t); + var anim = div.animate({ }, 100 * MS_PER_SEC); + + anim.effect.setKeyframes([ { easing: 'cubic-bezier(0, 1e+39, 0, 0)' }]); + assert_equals(anim.effect.getKeyframes()[0].easing, + 'cubic-bezier(0, ' + max_float + ', 0, 0)', + 'y1 control point for keyframe easing is out of upper boundary'); + + anim.effect.setKeyframes([ { easing: 'cubic-bezier(0, 0, 0, 1e+39)' }]); + assert_equals(anim.effect.getKeyframes()[0].easing, + 'cubic-bezier(0, 0, 0, ' + max_float + ')', + 'y2 control point for keyframe easing is out of upper boundary'); + + anim.effect.setKeyframes([ { easing: 'cubic-bezier(0, -1e+39, 0, 0)' }]); + assert_equals(anim.effect.getKeyframes()[0].easing, + 'cubic-bezier(0, ' + -max_float + ', 0, 0)', + 'y1 control point for keyframe easing is out of lower boundary'); + + anim.effect.setKeyframes([ { easing: 'cubic-bezier(0, 0, 0, -1e+39)' }]); + assert_equals(anim.effect.getKeyframes()[0].easing, + 'cubic-bezier(0, 0, 0, ' + -max_float + ')', + 'y2 control point for keyframe easing is out of lower boundary'); + +}, 'Clamp y1 and y2 control point out of boundaries for keyframe easing' ); + +test(function(t) { + var div = addDiv(t); + + div.style.animation = 'anim 100s cubic-bezier(0, 1e+39, 0, 0)'; + + assert_equals(div.getAnimations()[0].effect.getKeyframes()[0].easing, + 'cubic-bezier(0, ' + max_float + ', 0, 0)', + 'y1 control point for CSS animation is out of upper boundary'); + + div.style.animation = 'anim 100s cubic-bezier(0, 0, 0, 1e+39)'; + assert_equals(div.getAnimations()[0].effect.getKeyframes()[0].easing, + 'cubic-bezier(0, 0, 0, ' + max_float + ')', + 'y2 control point for CSS animation is out of upper boundary'); + + div.style.animation = 'anim 100s cubic-bezier(0, -1e+39, 0, 0)'; + assert_equals(div.getAnimations()[0].effect.getKeyframes()[0].easing, + 'cubic-bezier(0, ' + -max_float + ', 0, 0)', + 'y1 control point for CSS animation is out of lower boundary'); + + div.style.animation = 'anim 100s cubic-bezier(0, 0, 0, -1e+39)'; + assert_equals(div.getAnimations()[0].effect.getKeyframes()[0].easing, + 'cubic-bezier(0, 0, 0, ' + -max_float + ')', + 'y2 control point for CSS animation is out of lower boundary'); + +}, 'Clamp y1 and y2 control point out of boundaries for CSS animation' ); + +test(function(t) { + var div = addDiv(t, {'class': 'transition-div'}); + + div.style.transition = 'margin-left 100s cubic-bezier(0, 1e+39, 0, 0)'; + flushComputedStyle(div); + div.style.marginLeft = '0px'; + assert_equals(div.getAnimations()[0].effect.getKeyframes()[0].easing, + 'cubic-bezier(0, ' + max_float + ', 0, 0)', + 'y1 control point for CSS transition on upper boundary'); + div.style.transition = ''; + div.style.marginLeft = ''; + + div.style.transition = 'margin-left 100s cubic-bezier(0, 0, 0, 1e+39)'; + flushComputedStyle(div); + div.style.marginLeft = '0px'; + assert_equals(div.getAnimations()[0].effect.getKeyframes()[0].easing, + 'cubic-bezier(0, 0, 0, ' + max_float + ')', + 'y2 control point for CSS transition on upper boundary'); + div.style.transition = ''; + div.style.marginLeft = ''; + + div.style.transition = 'margin-left 100s cubic-bezier(0, -1e+39, 0, 0)'; + flushComputedStyle(div); + div.style.marginLeft = '0px'; + assert_equals(div.getAnimations()[0].effect.getKeyframes()[0].easing, + 'cubic-bezier(0, ' + -max_float + ', 0, 0)', + 'y1 control point for CSS transition on lower boundary'); + div.style.transition = ''; + div.style.marginLeft = ''; + + div.style.transition = 'margin-left 100s cubic-bezier(0, 0, 0, -1e+39)'; + flushComputedStyle(div); + div.style.marginLeft = '0px'; + assert_equals(div.getAnimations()[0].effect.getKeyframes()[0].easing, + 'cubic-bezier(0, 0, 0, ' + -max_float + ')', + 'y2 control point for CSS transition on lower boundary'); + +}, 'Clamp y1 and y2 control point out of boundaries for CSS transition' ); + +test(function(t) { + var div = addDiv(t); + var anim = div.animate({ }, { duration: 100 * MS_PER_SEC, fill: 'forwards' }); + + anim.pause(); + // The positive steepest function on both edges. + anim.effect.timing.easing = 'cubic-bezier(0, 1e+39, 0, 1e+39)'; + assert_equals(anim.effect.getComputedTiming().progress, 0.0, + 'progress on lower edge for the highest value of y1 and y2 control points'); + + anim.finish(); + assert_equals(anim.effect.getComputedTiming().progress, 1.0, + 'progress on upper edge for the highest value of y1 and y2 control points'); + + // The negative steepest function on both edges. + anim.effect.timing.easing = 'cubic-bezier(0, -1e+39, 0, -1e+39)'; + anim.currentTime = 0; + assert_equals(anim.effect.getComputedTiming().progress, 0.0, + 'progress on lower edge for the lowest value of y1 and y2 control points'); + + anim.finish(); + assert_equals(anim.effect.getComputedTiming().progress, 1.0, + 'progress on lower edge for the lowest value of y1 and y2 control points'); + +}, 'Calculated values on both edges'); + +done(); + +</script> +</body> diff --git a/dom/animation/test/mozilla/file_deferred_start.html b/dom/animation/test/mozilla/file_deferred_start.html new file mode 100644 index 0000000000..3be3f56aae --- /dev/null +++ b/dom/animation/test/mozilla/file_deferred_start.html @@ -0,0 +1,121 @@ +<!doctype html> +<meta charset=utf-8> +<script src="../testcommon.js"></script> +<script src="/tests/SimpleTest/paint_listener.js"></script> +<style> +@keyframes empty { } +@keyframes animTransform { + from { transform: translate(0px); } + to { transform: translate(100px); } +} +.target { + /* Element needs geometry to be eligible for layerization */ + width: 100px; + height: 100px; + background-color: white; +} +</style> +<body> +<script> +'use strict'; + +function waitForDocLoad() { + return new Promise(function(resolve, reject) { + if (document.readyState === 'complete') { + resolve(); + } else { + window.addEventListener('load', resolve); + } + }); +} + +function waitForPaints() { + return new Promise(function(resolve, reject) { + waitForAllPaintsFlushed(resolve); + }); +} + +promise_test(function(t) { + var div = addDiv(t); + var cs = window.getComputedStyle(div); + + // Test that empty animations actually start. + // + // Normally we tie the start of animations to when their first frame of + // the animation is rendered. However, for animations that don't actually + // trigger a paint (e.g. because they are empty, or are animating something + // that doesn't render or is offscreen) we want to make sure they still + // start. + // + // Before we start, wait for the document to finish loading. This is because + // during loading we will have other paint events taking place which might, + // by luck, happen to trigger animations that otherwise would not have been + // triggered, leading to false positives. + // + // As a result, it's better to wait until we have a more stable state before + // continuing. + var promiseCallbackDone = false; + return waitForDocLoad().then(function() { + div.style.animation = 'empty 1000s'; + var animation = div.getAnimations()[0]; + + return animation.ready.then(function() { + promiseCallbackDone = true; + }).catch(function() { + assert_unreached('ready promise was rejected'); + }); + }).then(function() { + // We need to wait for up to three frames. This is because in some + // cases it can take up to two frames for the initial layout + // to take place. Even after that happens we don't actually resolve the + // ready promise until the following tick. + return waitForAnimationFrames(3); + }).then(function() { + assert_true(promiseCallbackDone, + 'ready promise for an empty animation was resolved' + + ' within three animation frames'); + }); +}, 'Animation.ready is resolved for an empty animation'); + +// Test that compositor animations with delays get synced correctly +// +// NOTE: It is important that we DON'T use +// SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh here since that takes +// us through a different code path. +promise_test(function(t) { + // This test only applies to compositor animations + if (!isOMTAEnabled()) { + return; + } + + // Setup animation + var div = addDiv(t); + div.classList.add('target'); + div.style.animation = 'animTransform 100s -50s forwards'; + var animation = div.getAnimations()[0]; + + return waitForPaints(function() { + var transformStr = + SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform'); + + var matrixComponents = + transformStr.startsWith('matrix(') + ? transformStr.substring('matrix('.length, transformStr.length-1) + .split(',') + .map(component => Number(component)) + : []; + assert_equals(matrixComponents.length, 6, + 'Got a valid transform matrix on the compositor' + + ' (got: "' + transformStr + '")'); + + // If the delay has been applied correctly we should be at least + // half-way through the animation + assert_true(matrixComponents[4] >= 50, + 'Animation is at least half-way through on the compositor' + + ' (got translation of ' + matrixComponents[4] + ')'); + }); +}, 'Starting an animation with a delay starts from the correct point'); + +done(); +</script> +</body> diff --git a/dom/animation/test/mozilla/file_disable_animations_api_core.html b/dom/animation/test/mozilla/file_disable_animations_api_core.html new file mode 100644 index 0000000000..ef77988d9a --- /dev/null +++ b/dom/animation/test/mozilla/file_disable_animations_api_core.html @@ -0,0 +1,30 @@ +<!doctype html> +<meta charset=utf-8> +<script src="../testcommon.js"></script> +<body> +<script> +'use strict'; + +test(function(t) { + var div = addDiv(t); + var anim = + div.animate({ marginLeft: ['0px', '10px'] }, + { duration: 100 * MS_PER_SEC, + easing: 'linear', + iterations: 10, + iterationComposite: 'accumulate' }); + anim.pause(); + + // NOTE: We can't check iterationComposite value itself though API since + // Animation.effect is also behind the the Web Animations API. So we just + // check that style value is not affected by iterationComposite. + anim.currentTime = 200 * MS_PER_SEC; + assert_equals(getComputedStyle(div).marginLeft, '0px', + 'Animated style should not be accumulated when the Web Animations API is ' + + 'not enabled even if accumulate is specified in the constructor'); +}, 'iterationComposite should not affect at all if the Web Animations API ' + + 'is not enabled'); + +done(); +</script> +</body> diff --git a/dom/animation/test/mozilla/file_disabled_properties.html b/dom/animation/test/mozilla/file_disabled_properties.html new file mode 100644 index 0000000000..f1b72973f4 --- /dev/null +++ b/dom/animation/test/mozilla/file_disabled_properties.html @@ -0,0 +1,73 @@ +<!doctype html> +<meta charset=utf-8> +<script src="../testcommon.js"></script> +<body> +<script> +'use strict'; + +function waitForSetPref(pref, value) { + return new Promise(function(resolve, reject) { + SpecialPowers.pushPrefEnv({ 'set': [[pref, value]] }, resolve); + }); +} + +/* + * These tests rely on the fact that the -webkit-text-fill-color property + * is disabled by the layout.css.prefixes.webkit pref. If we ever remove that + * pref we will need to substitute some other pref:property combination. + */ + +promise_test(function(t) { + return waitForSetPref('layout.css.prefixes.webkit', true).then(() => { + var anim = addDiv(t).animate({ webkitTextFillColor: [ 'green', 'blue' ]}); + assert_equals(anim.effect.getKeyframes().length, 2, + 'A property-indexed keyframe specifying only enabled' + + ' properties produces keyframes'); + return waitForSetPref('layout.css.prefixes.webkit', false); + }).then(() => { + var anim = addDiv(t).animate({ webkitTextFillColor: [ 'green', 'blue' ]}); + assert_equals(anim.effect.getKeyframes().length, 0, + 'A property-indexed keyframe specifying only disabled' + + ' properties produces no keyframes'); + }); +}, 'Specifying a disabled property using a property-indexed keyframe'); + +promise_test(function(t) { + var createAnim = () => { + var anim = addDiv(t).animate([ { webkitTextFillColor: 'green' }, + { webkitTextFillColor: 'blue' } ]); + assert_equals(anim.effect.getKeyframes().length, 2, + 'Animation specified using a keyframe sequence should' + + ' return the same number of keyframes regardless of' + + ' whether or not the specified properties are disabled'); + return anim; + }; + + var assert_has_property = (anim, index, descr, property) => { + assert_true( + anim.effect.getKeyframes()[index].hasOwnProperty(property), + `${descr} should have the '${property}' property`); + }; + var assert_does_not_have_property = (anim, index, descr, property) => { + assert_false( + anim.effect.getKeyframes()[index].hasOwnProperty(property), + `${descr} should NOT have the '${property}' property`); + }; + + return waitForSetPref('layout.css.prefixes.webkit', true).then(() => { + var anim = createAnim(); + assert_has_property(anim, 0, 'Initial keyframe', 'webkitTextFillColor'); + assert_has_property(anim, 1, 'Final keyframe', 'webkitTextFillColor'); + return waitForSetPref('layout.css.prefixes.webkit', false); + }).then(() => { + var anim = createAnim(); + assert_does_not_have_property(anim, 0, 'Initial keyframe', + 'webkitTextFillColor'); + assert_does_not_have_property(anim, 1, 'Final keyframe', + 'webkitTextFillColor'); + }); +}, 'Specifying a disabled property using a keyframe sequence'); + +done(); +</script> +</body> diff --git a/dom/animation/test/mozilla/file_discrete-animations.html b/dom/animation/test/mozilla/file_discrete-animations.html new file mode 100644 index 0000000000..35e818a909 --- /dev/null +++ b/dom/animation/test/mozilla/file_discrete-animations.html @@ -0,0 +1,170 @@ +<!doctype html> +<head> +<meta charset=utf-8> +<title>Test Mozilla-specific discrete animatable properties</title> +<script type="application/javascript" src="../testcommon.js"></script> +</head> +<body> +<script> +"use strict"; + +const gMozillaSpecificProperties = { + "-moz-appearance": { + // https://drafts.csswg.org/css-align/#propdef-align-content + from: "button", + to: "none" + }, + "-moz-border-bottom-colors": { + from: "rgb(255, 0, 0) rgb(255, 0, 0) rgb(255, 0, 0) rgb(255, 0, 0)", + to: "rgb(0, 255, 0) rgb(0, 255, 0) rgb(0, 255, 0) rgb(0, 255, 0)" + }, + "-moz-border-left-colors": { + from: "rgb(255, 0, 0) rgb(255, 0, 0) rgb(255, 0, 0) rgb(255, 0, 0)", + to: "rgb(0, 255, 0) rgb(0, 255, 0) rgb(0, 255, 0) rgb(0, 255, 0)" + }, + "-moz-border-right-colors": { + from: "rgb(255, 0, 0) rgb(255, 0, 0) rgb(255, 0, 0) rgb(255, 0, 0)", + to: "rgb(0, 255, 0) rgb(0, 255, 0) rgb(0, 255, 0) rgb(0, 255, 0)" + }, + "-moz-border-top-colors": { + from: "rgb(255, 0, 0) rgb(255, 0, 0) rgb(255, 0, 0) rgb(255, 0, 0)", + to: "rgb(0, 255, 0) rgb(0, 255, 0) rgb(0, 255, 0) rgb(0, 255, 0)" + }, + "-moz-box-align": { + // https://developer.mozilla.org/en/docs/Web/CSS/box-align + from: "center", + to: "stretch" + }, + "-moz-box-direction": { + // https://developer.mozilla.org/en/docs/Web/CSS/box-direction + from: "reverse", + to: "normal" + }, + "-moz-box-ordinal-group": { + // https://developer.mozilla.org/en/docs/Web/CSS/box-ordinal-group + from: "1", + to: "5" + }, + "-moz-box-orient": { + // https://www.w3.org/TR/css-flexbox-1/ + from: "horizontal", + to: "vertical" + }, + "-moz-box-pack": { + // https://www.w3.org/TR/2009/WD-css3-flexbox-20090723/#propdef-box-pack + from: "center", + to: "end" + }, + "-moz-float-edge": { + // https://developer.mozilla.org/en/docs/Web/CSS/-moz-float-edge + from: "margin-box", + to: "content-box" + }, + "-moz-force-broken-image-icon": { + // https://developer.mozilla.org/en/docs/Web/CSS/-moz-force-broken-image-icon + from: "1", + to: "5" + }, + "image-rendering": { + // https://drafts.csswg.org/css-images-3/#propdef-image-rendering + from: "-moz-crisp-edges", + to: "auto" + }, + "-moz-stack-sizing": { + // https://developer.mozilla.org/en/docs/Web/CSS/-moz-stack-sizing + from: "ignore", + to: "stretch-to-fit" + }, + "-moz-tab-size": { + // https://drafts.csswg.org/css-text-3/#propdef-tab-size + from: "1", + to: "5" + }, + "-moz-text-size-adjust": { + // https://drafts.csswg.org/css-size-adjust/#propdef-text-size-adjust + from: "none", + to: "auto" + }, + "-webkit-text-stroke-width": { + // https://compat.spec.whatwg.org/#propdef--webkit-text-stroke-width + from: "10px", + to: "50px" + } +} + +for (let property in gMozillaSpecificProperties) { + const testData = gMozillaSpecificProperties[property]; + const from = testData.from; + const to = testData.to; + const idlName = propertyToIDL(property); + const keyframes = {}; + keyframes[idlName] = [from, to]; + + test(t => { + const div = addDiv(t); + const animation = div.animate(keyframes, + { duration: 1000, fill: "both" }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: from.toLowerCase() }, + { time: 499, expected: from.toLowerCase() }, + { time: 500, expected: to.toLowerCase() }, + { time: 1000, expected: to.toLowerCase() }]); + }, property + " should animate between '" + + from + "' and '" + to + "' with linear easing"); + + test(function(t) { + // Easing: http://cubic-bezier.com/#.68,0,1,.01 + // With this curve, we don't reach the 50% point until about 95% of + // the time has expired. + const div = addDiv(t); + const animation = div.animate(keyframes, + { duration: 1000, fill: "both", + easing: "cubic-bezier(0.68,0,1,0.01)" }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: from.toLowerCase() }, + { time: 940, expected: from.toLowerCase() }, + { time: 960, expected: to.toLowerCase() }]); + }, property + " should animate between '" + + from + "' and '" + to + "' with effect easing"); + + test(function(t) { + // Easing: http://cubic-bezier.com/#.68,0,1,.01 + // With this curve, we don't reach the 50% point until about 95% of + // the time has expired. + keyframes.easing = "cubic-bezier(0.68,0,1,0.01)"; + const div = addDiv(t); + const animation = div.animate(keyframes, + { duration: 1000, fill: "both" }); + testAnimationSamples(animation, idlName, + [{ time: 0, expected: from.toLowerCase() }, + { time: 940, expected: from.toLowerCase() }, + { time: 960, expected: to.toLowerCase() }]); + }, property + " should animate between '" + + from + "' and '" + to + "' with keyframe easing"); +} + +function propertyToIDL(property) { + var prefixMatch = property.match(/^-(\w+)-/); + if (prefixMatch) { + var prefix = prefixMatch[1] === "moz" ? "Moz" : prefixMatch[1]; + property = prefix + property.substring(prefixMatch[0].length - 1); + } + // https://drafts.csswg.org/cssom/#css-property-to-idl-attribute + return property.replace(/-([a-z])/gi, function(str, group) { + return group.toUpperCase(); + }); +} + +function testAnimationSamples(animation, idlName, testSamples) { + const target = animation.effect.target; + testSamples.forEach(testSample => { + animation.currentTime = testSample.time; + assert_equals(getComputedStyle(target)[idlName], testSample.expected, + "The value should be " + testSample.expected + + " at " + testSample.time + "ms"); + }); +} + +done(); +</script> +</body> diff --git a/dom/animation/test/mozilla/file_document-timeline-origin-time-range.html b/dom/animation/test/mozilla/file_document-timeline-origin-time-range.html new file mode 100644 index 0000000000..083bf0903b --- /dev/null +++ b/dom/animation/test/mozilla/file_document-timeline-origin-time-range.html @@ -0,0 +1,30 @@ +<!doctype html> +<meta charset=utf-8> +<script src="../testcommon.js"></script> +<body> +<script> +'use strict'; + +// If the originTime parameter passed to the DocumentTimeline exceeds +// the range of the internal storage type (a signed 64-bit integer number +// of ticks--a platform-dependent unit) then we should throw. +// Infinity isn't allowed as an origin time value and clamping to just +// inside the allowed range will just mean we overflow elsewhere. + +test(function(t) { + assert_throws({ name: 'TypeError'}, + function() { + new DocumentTimeline({ originTime: Number.MAX_SAFE_INTEGER }); + }); +}, 'Calculated current time is positive infinity'); + +test(function(t) { + assert_throws({ name: 'TypeError'}, + function() { + new DocumentTimeline({ originTime: -1 * Number.MAX_SAFE_INTEGER }); + }); +}, 'Calculated current time is negative infinity'); + +done(); +</script> +</body> diff --git a/dom/animation/test/mozilla/file_hide_and_show.html b/dom/animation/test/mozilla/file_hide_and_show.html new file mode 100644 index 0000000000..0771fcce1f --- /dev/null +++ b/dom/animation/test/mozilla/file_hide_and_show.html @@ -0,0 +1,162 @@ +<!doctype html> +<meta charset=utf-8> +<script src="../testcommon.js"></script> +<style> +@keyframes move { + 100% { + transform: translateX(100px); + } +} + +</style> +<body> +<script> +'use strict'; + +test(function(t) { + var div = addDiv(t, { style: 'animation: move 100s infinite' }); + assert_equals(div.getAnimations().length, 1, + 'display:initial element has animations'); + + div.style.display = 'none'; + assert_equals(div.getAnimations().length, 0, + 'display:none element has no animations'); +}, 'Animation stops playing when the element style display is set to "none"'); + +test(function(t) { + var parentElement = addDiv(t); + var div = addDiv(t, { style: 'animation: move 100s infinite' }); + parentElement.appendChild(div); + assert_equals(div.getAnimations().length, 1, + 'display:initial element has animations'); + + parentElement.style.display = 'none'; + assert_equals(div.getAnimations().length, 0, + 'Element in display:none subtree has no animations'); +}, 'Animation stops playing when its parent element style display is set ' + + 'to "none"'); + +test(function(t) { + var div = addDiv(t, { style: 'animation: move 100s infinite' }); + assert_equals(div.getAnimations().length, 1, + 'display:initial element has animations'); + + div.style.display = 'none'; + assert_equals(div.getAnimations().length, 0, + 'display:none element has no animations'); + + div.style.display = ''; + assert_equals(div.getAnimations().length, 1, + 'Element which is no longer display:none has animations ' + + 'again'); +}, 'Animation starts playing when the element gets shown from ' + + '"display:none" state'); + +test(function(t) { + var parentElement = addDiv(t); + var div = addDiv(t, { style: 'animation: move 100s infinite' }); + parentElement.appendChild(div); + assert_equals(div.getAnimations().length, 1, + 'display:initial element has animations'); + + parentElement.style.display = 'none'; + assert_equals(div.getAnimations().length, 0, + 'Element in display:none subtree has no animations'); + + parentElement.style.display = ''; + assert_equals(div.getAnimations().length, 1, + 'Element which is no longer in display:none subtree has ' + + 'animations again'); +}, 'Animation starts playing when its parent element is shown from ' + + '"display:none" state'); + +test(function(t) { + var div = addDiv(t, { style: 'animation: move 100s forwards' }); + assert_equals(div.getAnimations().length, 1, + 'display:initial element has animations'); + + var animation = div.getAnimations()[0]; + animation.finish(); + assert_equals(div.getAnimations().length, 1, + 'Element has finished animation if the animation ' + + 'fill-mode is forwards'); + + div.style.display = 'none'; + assert_equals(animation.playState, 'idle', + 'The animation.playState should be idle'); + + assert_equals(div.getAnimations().length, 0, + 'display:none element has no animations'); + + div.style.display = ''; + assert_equals(div.getAnimations().length, 1, + 'Element which is no longer display:none has animations ' + + 'again'); + assert_not_equals(div.getAnimations()[0], animation, + 'Restarted animation is a newly-generated animation'); + +}, 'Animation which has already finished starts playing when the element ' + + 'gets shown from "display:none" state'); + +test(function(t) { + var parentElement = addDiv(t); + var div = addDiv(t, { style: 'animation: move 100s forwards' }); + parentElement.appendChild(div); + assert_equals(div.getAnimations().length, 1, + 'display:initial element has animations'); + + var animation = div.getAnimations()[0]; + animation.finish(); + assert_equals(div.getAnimations().length, 1, + 'Element has finished animation if the animation ' + + 'fill-mode is forwards'); + + parentElement.style.display = 'none'; + assert_equals(animation.playState, 'idle', + 'The animation.playState should be idle'); + assert_equals(div.getAnimations().length, 0, + 'Element in display:none subtree has no animations'); + + parentElement.style.display = ''; + assert_equals(div.getAnimations().length, 1, + 'Element which is no longer in display:none subtree has ' + + 'animations again'); + + assert_not_equals(div.getAnimations()[0], animation, + 'Restarted animation is a newly-generated animation'); + +}, 'Animation with fill:forwards which has already finished starts playing ' + + 'when its parent element is shown from "display:none" state'); + +test(function(t) { + var parentElement = addDiv(t); + var div = addDiv(t, { style: 'animation: move 100s' }); + parentElement.appendChild(div); + assert_equals(div.getAnimations().length, 1, + 'display:initial element has animations'); + + var animation = div.getAnimations()[0]; + animation.finish(); + assert_equals(div.getAnimations().length, 0, + 'Element does not have finished animations'); + + parentElement.style.display = 'none'; + assert_equals(animation.playState, 'idle', + 'The animation.playState should be idle'); + assert_equals(div.getAnimations().length, 0, + 'Element in display:none subtree has no animations'); + + parentElement.style.display = ''; + assert_equals(div.getAnimations().length, 1, + 'Element which is no longer in display:none subtree has ' + + 'animations again'); + + assert_not_equals(div.getAnimations()[0], animation, + 'Restarted animation is a newly-generated animation'); + +}, 'CSS Animation which has already finished starts playing when its parent ' + + 'element is shown from "display:none" state'); + +done(); +</script> +</body> diff --git a/dom/animation/test/mozilla/file_partial_keyframes.html b/dom/animation/test/mozilla/file_partial_keyframes.html new file mode 100644 index 0000000000..68832be7a0 --- /dev/null +++ b/dom/animation/test/mozilla/file_partial_keyframes.html @@ -0,0 +1,41 @@ +<!doctype html> +<meta charset=utf-8> +<script src="../testcommon.js"></script> +<body> +<script> +'use strict'; + +// Tests for cases we currently don't handle and should throw an exception for. +var gTests = [ + { desc: "single Keyframe with no offset", + keyframes: [{ left: "100px" }] }, + { desc: "multiple Keyframes with missing 0% Keyframe", + keyframes: [{ left: "100px", offset: 0.25 }, + { left: "200px", offset: 0.50 }, + { left: "300px", offset: 1.00 }] }, + { desc: "multiple Keyframes with missing 100% Keyframe", + keyframes: [{ left: "100px", offset: 0.00 }, + { left: "200px", offset: 0.50 }, + { left: "300px", offset: 0.75 }] }, + { desc: "multiple Keyframes with missing properties on first Keyframe", + keyframes: [{ left: "100px", offset: 0.0 }, + { left: "200px", top: "200px", offset: 0.5 }, + { left: "300px", top: "300px", offset: 1.0 }] }, + { desc: "multiple Keyframes with missing properties on last Keyframe", + keyframes: [{ left: "100px", top: "200px", offset: 0.0 }, + { left: "200px", top: "200px", offset: 0.5 }, + { left: "300px", offset: 1.0 }] }, +]; + +gTests.forEach(function(subtest) { + test(function(t) { + var div = addDiv(t); + assert_throws("NotSupportedError", function() { + new KeyframeEffectReadOnly(div, subtest.keyframes); + }); + }, "KeyframeEffectReadOnly constructor throws with " + subtest.desc); +}); + +done(); +</script> +</body> diff --git a/dom/animation/test/mozilla/file_set-easing.html b/dom/animation/test/mozilla/file_set-easing.html new file mode 100644 index 0000000000..072b125cb0 --- /dev/null +++ b/dom/animation/test/mozilla/file_set-easing.html @@ -0,0 +1,34 @@ +<!doctype html> +<head> +<meta charset=utf-8> +<title>Test setting easing in sandbox</title> +<script src="../testcommon.js"></script> +</head> +<body> +<script> +"use strict"; + +test(function(t) { + const div = document.createElement("div"); + document.body.appendChild(div); + div.animate({ opacity: [0, 1] }, 100000 ); + + const contentScript = function() { + try { + document.getAnimations()[0].effect.timing.easing = "linear"; + assert_true(true, 'Setting easing should not throw in sandbox'); + } catch (e) { + assert_unreached('Setting easing threw ' + e); + } + }; + + const sandbox = new SpecialPowers.Cu.Sandbox(window); + sandbox.importFunction(document, "document"); + sandbox.importFunction(assert_true, "assert_true"); + sandbox.importFunction(assert_unreached, "assert_unreached"); + SpecialPowers.Cu.evalInSandbox(`(${contentScript.toSource()})()`, sandbox); +}, 'Setting easing should not throw any exceptions in sandbox'); + +done(); +</script> +</body> diff --git a/dom/animation/test/mozilla/file_spacing_property_order.html b/dom/animation/test/mozilla/file_spacing_property_order.html new file mode 100644 index 0000000000..1338d60811 --- /dev/null +++ b/dom/animation/test/mozilla/file_spacing_property_order.html @@ -0,0 +1,33 @@ +<!doctype html> +<meta charset=utf-8> +<script src="../testcommon.js"></script> +<body> +<script> +'use strict'; + +test(function(t) { + var div = document.createElement('div'); + document.documentElement.appendChild(div); + var anim = div.animate([ { borderRadius: "0", borderTopRightRadius: "10%" }, + { borderTopLeftRadius: "20%", + borderTopRightRadius: "30%", + borderBottomRightRadius: "40%", + borderBottomLeftRadius: "50%" }, + { borderRadius: "50%" } ], + { spacing:"paced(border-radius)" }); + + var frames = anim.effect.getKeyframes(); + var dist = [ 0, + Math.sqrt(20 * 20 + (30 - 10) * (30 - 10) + 40 * 40 + 50 * 50), + Math.sqrt((50 - 20) * (50 - 20) + (50 - 30) * (50 - 30) + + (50 - 40) * (50 - 40) + (50 - 50) * (50 - 50)) ]; + var cumDist = []; + dist.reduce(function(prev, curr, i) { return cumDist[i] = prev + curr; }, 0); + assert_approx_equals(frames[1].computedOffset, cumDist[1] / cumDist[2], + 0.0001, 'frame offset'); +}, 'Test for the longhand components of the shorthand property surely sorted' ); + +done(); + +</script> +</body> diff --git a/dom/animation/test/mozilla/file_spacing_transform.html b/dom/animation/test/mozilla/file_spacing_transform.html new file mode 100644 index 0000000000..0de7737864 --- /dev/null +++ b/dom/animation/test/mozilla/file_spacing_transform.html @@ -0,0 +1,240 @@ +<!doctype html> +<meta charset=utf-8> +<script src="../testcommon.js"></script> +<body> +<script> +'use strict'; + +const pi = Math.PI; +const cos = Math.cos; +const sin = Math.sin; +const tan = Math.tan; +const sqrt = Math.sqrt; + +// Help function for testing the computed offsets by the distance array. +function assert_animation_offsets(anim, dist) { + const epsilon = 0.00000001; + const frames = anim.effect.getKeyframes(); + const cumDist = dist.reduce( (prev, curr) => { + prev.push(prev.length == 0 ? curr : curr + prev[prev.length - 1]); + return prev; + }, []); + + const total = cumDist[cumDist.length - 1]; + for (var i = 0; i < frames.length; ++i) { + assert_approx_equals(frames[i].computedOffset, cumDist[i] / total, + epsilon, 'computedOffset of frame ' + i); + } +} + +function getAngleDist(rotate1, rotate2) { + function quaternion(axis, angle) { + var x = axis[0] * sin(angle/2.0); + var y = axis[1] * sin(angle/2.0); + var z = axis[2] * sin(angle/2.0); + var w = cos(angle/2.0); + return { 'x': x, 'y': y, 'z': z, 'w': w }; + } + var q1 = quaternion(rotate1.axis, rotate1.angle); + var q2 = quaternion(rotate2.axis, rotate2.angle); + var dotProduct = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w; + return 2.0 * Math.acos(dotProduct); +} + +function createMatrix(elements, Is3D) { + return (Is3D ? "matrix3d" : "matrix") + "(" + elements.join() + ")"; +} + +test(function(t) { + var anim = addDiv(t).animate([ { transform: "none" }, + { transform: "translate(-20px)" }, + { transform: "translate(100px)" }, + { transform: "translate(50px)"} ], + { spacing: "paced(transform)" }); + assert_animation_offsets(anim, [ 0, 20, 120, 50 ]); +}, 'Test spacing on translate' ); + +test(function(t) { + var anim = + addDiv(t).animate([ { transform: "none" }, + { transform: "translate3d(-20px, 10px, 100px)" }, + { transform: "translate3d(100px, 200px, 50px)" }, + { transform: "translate(50px, -10px)"} ], + { spacing: "paced(transform)" }); + var dist = [ 0, + Math.sqrt(20 * 20 + 10 * 10 + 100 * 100), + Math.sqrt(120 * 120 + 190 * 190 + 50 * 50), + Math.sqrt(50 * 50 + 210 * 210 + 50 * 50) ]; + assert_animation_offsets(anim, dist); +}, 'Test spacing on translate3d' ); + +test(function(t) { + var anim = addDiv(t).animate([ { transform: "scale(0.5)" }, + { transform: "scale(4.5)" }, + { transform: "scale(2.5)" }, + { transform: "none"} ], + { spacing: "paced(transform)" }); + assert_animation_offsets(anim, [ 0, 4.0, 2.0, 1.5 ]); +}, 'Test spacing on scale' ); + +test(function(t) { + var anim = addDiv(t).animate([ { transform: "scale(0.5, 0.5)" }, + { transform: "scale3d(4.5, 5.0, 2.5)" }, + { transform: "scale3d(2.5, 1.0, 2.0)" }, + { transform: "scale3d(1, 0.5, 1.0)"} ], + { spacing:"paced(transform)" }); + var dist = [ 0, + Math.sqrt(4.0 * 4.0 + 4.5 * 4.5 + 1.5 * 1.5), + Math.sqrt(2.0 * 2.0 + 4.0 * 4.0 + 0.5 * 0.5), + Math.sqrt(1.5 * 1.5 + 0.5 * 0.5 + 1.0 * 1.0) ]; + assert_animation_offsets(anim, dist); +}, 'Test spacing on scale3d' ); + +test(function(t) { + var anim = addDiv(t).animate([ { transform: "rotate(60deg)" }, + { transform: "none" }, + { transform: "rotate(720deg)" }, + { transform: "rotate(-360deg)"} ], + { spacing: "paced(transform)" }); + assert_animation_offsets(anim, [ 0, 60, 720, 1080 ]); +}, 'Test spacing on rotate' ); + +test(function(t) { + var anim = addDiv(t).animate([ { transform: "rotate3d(1,0,0,60deg)" }, + { transform: "rotate3d(1,0,0,70deg)" }, + { transform: "rotate3d(0,0,1,-110deg)" }, + { transform: "rotate3d(1,0,0,219deg)"} ], + { spacing: "paced(transform)" }); + var dist = [ 0, + getAngleDist({ axis: [1,0,0], angle: 60 * pi / 180 }, + { axis: [1,0,0], angle: 70 * pi / 180 }), + getAngleDist({ axis: [0,1,0], angle: 70 * pi / 180 }, + { axis: [0,0,1], angle: -110 * pi / 180 }), + getAngleDist({ axis: [0,0,1], angle: -110 * pi / 180 }, + { axis: [1,0,0], angle: 219 * pi / 180 }) ]; + assert_animation_offsets(anim, dist); +}, 'Test spacing on rotate3d' ); + +test(function(t) { + var anim = addDiv(t).animate([ { transform: "skew(60deg)" }, + { transform: "none" }, + { transform: "skew(-90deg)" }, + { transform: "skew(90deg)"} ], + { spacing: "paced(transform)" }); + assert_animation_offsets(anim, [ 0, 60, 90, 180 ]); +}, 'Test spacing on skew' ); + +test(function(t) { + var anim = addDiv(t).animate([ { transform: "skew(60deg, 30deg)" }, + { transform: "none" }, + { transform: "skew(-90deg, 60deg)" }, + { transform: "skew(90deg, 60deg)"} ], + { spacing: "paced(transform)" }); + var dist = [ 0, + sqrt(60 * 60 + 30 * 30), + sqrt(90 * 90 + 60 * 60), + sqrt(180 * 180 + 0) ]; + assert_animation_offsets(anim, dist); +}, 'Test spacing on skew along both X and Y' ); + +test(function(t) { + // We calculate the distance of two perspective functions by converting them + // into two matrix3ds, and then do matrix decomposition to get two + // perspective vectors, so the equivalent perspective vectors are: + // perspective 1: (0, 0, -1/128, 1); + // perspective 2: (0, 0, -1/infinity = 0, 1); + // perspective 3: (0, 0, -1/1024, 1); + // perspective 4: (0, 0, -1/32, 1); + var anim = addDiv(t).animate([ { transform: "perspective(128px)" }, + { transform: "none" }, + { transform: "perspective(1024px)" }, + { transform: "perspective(32px)"} ], + { spacing: "paced(transform)" }); + assert_animation_offsets(anim, + [ 0, 1/128, 1/1024, 1/32 - 1/1024 ]); +}, 'Test spacing on perspective' ); + +test(function(t) { + var anim = + addDiv(t).animate([ { transform: "none" }, + { transform: "rotate(180deg) translate(0px)" }, + { transform: "rotate(180deg) translate(1000px)" }, + { transform: "rotate(360deg) translate(1000px)"} ], + { spacing: "paced(transform)" }); + var dist = [ 0, + sqrt(pi * pi + 0), + sqrt(1000 * 1000), + sqrt(pi * pi + 0) ]; + assert_animation_offsets(anim, dist); +}, 'Test spacing on matched transform lists' ); + +test(function(t) { + // matrix1 => translate(100px, 50px), skewX(60deg). + // matrix2 => translate(1000px), rotate(180deg). + // matrix3 => translate(1000px), scale(1.5, 0.7). + const matrix1 = createMatrix([ 1, 0, tan(pi/4.0), 1, 100, 50 ]); + const matrix2 = createMatrix([ cos(pi), sin(pi), + -sin(pi), cos(pi), + 1000, 0 ]); + const matrix3 = createMatrix([ 1.5, 0, 0, 0.7, 1000, 0 ]); + var anim = addDiv(t).animate([ { transform: "none" }, + { transform: matrix1 }, + { transform: matrix2 }, + { transform: matrix3 } ], + { spacing: "paced(transform)" }); + var dist = [ 0, + sqrt(100 * 100 + 50 * 50 + pi/4 * pi/4), + sqrt(900 * 900 + 50 * 50 + pi * pi + pi/4 * pi/4), + sqrt(pi * pi + 0.5 * 0.5 + 0.3 * 0.3) ]; + assert_animation_offsets(anim, dist); +}, 'Test spacing on matrix' ); + +test(function(t) { + // matrix1 => translate3d(100px, 50px, -10px), skew(60deg). + // matrix2 => translate3d(1000px, 0, 0), rotate3d(1, 0, 0, 180deg). + // matrix3 => translate3d(1000px, 0, 0), scale3d(1.5, 0.7, 2.2). + const matrix1 = createMatrix([ 1, 0, 0, 0, + tan(pi/4.0), 1, 0, 0, + 0, 0, 1, 0, + 100, 50, -10, 1 ], true); + const matrix2 = createMatrix([ 1, 0, 0, 0, + 0, cos(pi), sin(pi), 0, + 0, -sin(pi), cos(pi), 0, + 1000, 0, 0, 1 ], true); + const matrix3 = createMatrix([ 1.5, 0, 0, 0, + 0, 0.7, 0, 0, + 0, 0, 2.2, 0, + 1000, 0, 0, 1 ], true); + var anim = addDiv(t).animate([ { transform: "none" }, + { transform: matrix1 }, + { transform: matrix2 }, + { transform: matrix3 } ], + { spacing: "paced(transform)" }); + var dist = [ 0, + sqrt(100 * 100 + 50 * 50 + 10 * 10 + pi/4 * pi/4), + sqrt(900 * 900 + 50 * 50 + 10 * 10 + pi/4 * pi/4 + pi * pi), + sqrt(0.5 * 0.5 + 0.3 * 0.3 + 1.2 * 1.2 + pi * pi) ]; + assert_animation_offsets(anim, dist); +}, 'Test spacing on matrix3d' ); + +test(function(t) { + var anim = + addDiv(t).animate([ { transform: "none" }, + { transform: "translate(100px, 50px) skew(45deg)" }, + { transform: "translate(1000px) " + + "rotate3d(1, 0, 0, 180deg)" }, + { transform: "translate(1000px) " + + "scale3d(2.5, 0.5, 0.7)" } ], + { spacing: "paced(transform)" }); + + var dist = [ 0, + sqrt(100 * 100 + 50 * 50 + pi/4 * pi/4), + sqrt(900 * 900 + 50 * 50 + pi/4 * pi/4 + pi * pi), + sqrt(1.5 * 1.5 + 0.5 * 0.5 + 0.3 * 0.3 + pi * pi) ]; + assert_animation_offsets(anim, dist); +}, 'Test spacing on mismatched transform list' ); + +done(); + +</script> +</body> diff --git a/dom/animation/test/mozilla/file_transform_limits.html b/dom/animation/test/mozilla/file_transform_limits.html new file mode 100644 index 0000000000..d4c813c67d --- /dev/null +++ b/dom/animation/test/mozilla/file_transform_limits.html @@ -0,0 +1,55 @@ +<!doctype html> +<meta charset=utf-8> +<script src="../testcommon.js"></script> +<body> +<script> +'use strict'; + +// We clamp +infinity or -inifinity value in floating point to +// maximum floating point value or -maximum floating point value. +const max_float = 3.40282e+38; + +test(function(t) { + var div = addDiv(t); + div.style = "width: 1px; height: 1px;"; + var anim = div.animate([ { transform: 'scale(1)' }, + { transform: 'scale(3.5e+38)'}, + { transform: 'scale(3)' } ], 100 * MS_PER_SEC); + + anim.pause(); + anim.currentTime = 50 * MS_PER_SEC; + assert_equals(getComputedStyle(div).transform, + 'matrix(' + max_float + ', 0, 0, ' + max_float + ', 0, 0)'); +}, 'Test that the parameter of transform scale is clamped' ); + +test(function(t) { + var div = addDiv(t); + div.style = "width: 1px; height: 1px;"; + var anim = div.animate([ { transform: 'translate(1px)' }, + { transform: 'translate(3.5e+38px)'}, + { transform: 'translate(3px)' } ], 100 * MS_PER_SEC); + + anim.pause(); + anim.currentTime = 50 * MS_PER_SEC; + assert_equals(getComputedStyle(div).transform, + 'matrix(1, 0, 0, 1, ' + max_float + ', 0)'); +}, 'Test that the parameter of transform translate is clamped' ); + +test(function(t) { + var div = addDiv(t); + div.style = "width: 1px; height: 1px;"; + var anim = div.animate([ { transform: 'matrix(0.5, 0, 0, 0.5, 0, 0)' }, + { transform: 'matrix(2, 0, 0, 2, 3.5e+38, 0)'}, + { transform: 'matrix(0, 2, 0, -2, 0, 0)' } ], + 100 * MS_PER_SEC); + + anim.pause(); + anim.currentTime = 50 * MS_PER_SEC; + assert_equals(getComputedStyle(div).transform, + 'matrix(2, 0, 0, 2, ' + max_float + ', 0)'); +}, 'Test that the parameter of transform matrix is clamped' ); + +done(); + +</script> +</body> diff --git a/dom/animation/test/mozilla/file_transition_finish_on_compositor.html b/dom/animation/test/mozilla/file_transition_finish_on_compositor.html new file mode 100644 index 0000000000..4912d05dd1 --- /dev/null +++ b/dom/animation/test/mozilla/file_transition_finish_on_compositor.html @@ -0,0 +1,67 @@ +<!doctype html> +<meta charset=utf-8> +<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> +<script> +'use strict'; + +function waitForPaints() { + return new Promise(function(resolve, reject) { + waitForAllPaintsFlushed(resolve); + }); +} + +promise_test(t => { + // This test only applies to compositor animations + if (!isOMTAEnabled()) { + return; + } + + var div = addDiv(t, { style: 'transition: transform 50ms; ' + + 'transform: translateX(0px)' }); + getComputedStyle(div).transform; + + div.style.transform = 'translateX(100px)'; + + var timeBeforeStart = window.performance.now(); + return waitForPaints().then(() => { + // If it took over 50ms to paint the transition, we have no luck + // to test it. This situation will happen if GC runs while waiting for the + // paint. + if (window.performance.now() - timeBeforeStart >= 50) { + return; + } + + var transform = + SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform'); + assert_not_equals(transform, '', + 'The transition style is applied on the compositor'); + + // Generate artificial busyness on the main thread for 100ms. + var timeAtStart = window.performance.now(); + while (window.performance.now() - timeAtStart < 100) {} + + // Now the transition on the compositor should finish but stay at the final + // position because there was no chance to pull the transition back from + // the compositor. + transform = + SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform'); + assert_equals(transform, 'matrix(1, 0, 0, 1, 100, 0)', + 'The final transition style is still applied on the ' + + 'compositor'); + }); +}, 'Transition on the compositor keeps the final style while the main thread ' + + 'is busy even if the transition finished on the compositor'); + +done(); +</script> +</body> diff --git a/dom/animation/test/mozilla/file_underlying-discrete-value.html b/dom/animation/test/mozilla/file_underlying-discrete-value.html new file mode 100644 index 0000000000..3be01b9041 --- /dev/null +++ b/dom/animation/test/mozilla/file_underlying-discrete-value.html @@ -0,0 +1,192 @@ +<!doctype html> +<meta charset=utf-8> +<script src="../testcommon.js"></script> +<body> +<script> +"use strict"; + +// Tests that we correctly extract the underlying value when the animation +// type is 'discrete'. +const discreteTests = [ + { + stylesheet: { + "@keyframes keyframes": + "from { align-content: flex-start; } to { align-content: flex-end; } " + }, + expectedKeyframes: [ + { computedOffset: 0, alignContent: "flex-start" }, + { computedOffset: 1, alignContent: "flex-end" } + ], + explanation: "Test for fully-specified keyframes" + }, + { + stylesheet: { + "@keyframes keyframes": "from { align-content: flex-start; }" + }, + // The value of 100% should be 'stretch', + // but we are not supporting underlying value. + // https://bugzilla.mozilla.org/show_bug.cgi?id=1295401 + expectedKeyframes: [ + { computedOffset: 0, alignContent: "flex-start" }, + { computedOffset: 1, alignContent: "unset" } + ], + explanation: "Test for 0% keyframe only" + }, + { + stylesheet: { + "@keyframes keyframes": "to { align-content: flex-end; }" + }, + // The value of 0% should be 'stretch', + // but we are not supporting underlying value. + // https://bugzilla.mozilla.org/show_bug.cgi?id=1295401 + expectedKeyframes: [ + { computedOffset: 0, alignContent: "unset" }, + { computedOffset: 1, alignContent: "flex-end" } + ], + explanation: "Test for 100% keyframe only" + }, + { + stylesheet: { + "@keyframes keyframes": "50% { align-content: center; }", + "#target": "align-content: space-between;" + }, + expectedKeyframes: [ + { computedOffset: 0, alignContent: "space-between" }, + { computedOffset: 0.5, alignContent: "center" }, + { computedOffset: 1, alignContent: "space-between" } + ], + explanation: "Test for no 0%/100% keyframes " + + "and specified style on target element" + }, + { + stylesheet: { + "@keyframes keyframes": "50% { align-content: center; }" + }, + attributes: { + style: "align-content: space-between" + }, + expectedKeyframes: [ + { computedOffset: 0, alignContent: "space-between" }, + { computedOffset: 0.5, alignContent: "center" }, + { computedOffset: 1, alignContent: "space-between" } + ], + explanation: "Test for no 0%/100% keyframes " + + "and specified style on target element using style attribute" + }, + { + stylesheet: { + "@keyframes keyframes": "50% { align-content: center; }", + "#target": "align-content: inherit;" + }, + // The value of 0%/100% should be 'stretch', + // but we are not supporting underlying value. + // https://bugzilla.mozilla.org/show_bug.cgi?id=1295401 + expectedKeyframes: [ + { computedOffset: 0, alignContent: "inherit" }, + { computedOffset: 0.5, alignContent: "center" }, + { computedOffset: 1, alignContent: "inherit" } + ], + explanation: "Test for no 0%/100% keyframes " + + "and 'inherit' specified on target element" + }, + { + stylesheet: { + "@keyframes keyframes": "50% { align-content: center; }", + ".target": "align-content: space-between;" + }, + attributes: { + class: "target" + }, + expectedKeyframes: [ + { computedOffset: 0, alignContent: "space-between" }, + { computedOffset: 0.5, alignContent: "center" }, + { computedOffset: 1, alignContent: "space-between" } + ], + explanation: "Test for no 0%/100% keyframes " + + "and specified style on target element using class selector" + }, + { + stylesheet: { + "@keyframes keyframes": "50% { align-content: center; }", + "div": "align-content: space-between;" + }, + expectedKeyframes: [ + { computedOffset: 0, alignContent: "space-between" }, + { computedOffset: 0.5, alignContent: "center" }, + { computedOffset: 1, alignContent: "space-between" } + ], + explanation: "Test for no 0%/100% keyframes " + + "and specified style on target element using type selector" + }, + { + stylesheet: { + "@keyframes keyframes": "50% { align-content: center; }", + "div": "align-content: space-between;", + ".target": "align-content: flex-start;", + "#target": "align-content: flex-end;" + }, + attributes: { + class: "target" + }, + expectedKeyframes: [ + { computedOffset: 0, alignContent: "flex-end" }, + { computedOffset: 0.5, alignContent: "center" }, + { computedOffset: 1, alignContent: "flex-end" } + ], + explanation: "Test for no 0%/100% keyframes " + + "and specified style on target element " + + "using ID selector that overrides class selector" + }, + { + stylesheet: { + "@keyframes keyframes": "50% { align-content: center; }", + "div": "align-content: space-between !important;", + ".target": "align-content: flex-start;", + "#target": "align-content: flex-end;" + }, + attributes: { + class: "target" + }, + expectedKeyframes: [ + { computedOffset: 0, alignContent: "space-between" }, + { computedOffset: 0.5, alignContent: "center" }, + { computedOffset: 1, alignContent: "space-between" } + ], + explanation: "Test for no 0%/100% keyframes " + + "and specified style on target element " + + "using important type selector that overrides other rules" + }, +]; + +discreteTests.forEach(testcase => { + test(t => { + addStyle(t, testcase.stylesheet); + + const div = addDiv(t, { "id": "target" }); + if (testcase.attributes) { + for (let attributeName in testcase.attributes) { + div.setAttribute(attributeName, testcase.attributes[attributeName]); + } + } + div.style.animation = "keyframes 100s"; + + const keyframes = div.getAnimations()[0].effect.getKeyframes(); + const expectedKeyframes = testcase.expectedKeyframes; + assert_equals(keyframes.length, expectedKeyframes.length, + `keyframes.length should be ${ expectedKeyframes.length }`); + + keyframes.forEach((keyframe, index) => { + const expectedKeyframe = expectedKeyframes[index]; + assert_equals(keyframe.computedOffset, expectedKeyframe.computedOffset, + `computedOffset of keyframes[${ index }] should be ` + + `${ expectedKeyframe.computedOffset }`); + assert_equals(keyframe.alignContent, expectedKeyframe.alignContent, + `alignContent of keyframes[${ index }] should be ` + + `${ expectedKeyframe.alignContent }`); + }); + }, testcase.explanation); +}); + +done(); +</script> +</body> diff --git a/dom/animation/test/mozilla/test_cubic_bezier_limits.html b/dom/animation/test/mozilla/test_cubic_bezier_limits.html new file mode 100644 index 0000000000..e67e5dbbb0 --- /dev/null +++ b/dom/animation/test/mozilla/test_cubic_bezier_limits.html @@ -0,0 +1,14 @@ +<!doctype html> +<meta charset=utf-8> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +'use strict'; +setup({explicit_done: true}); +SpecialPowers.pushPrefEnv( + { "set": [["dom.animations-api.core.enabled", true]]}, + function() { + window.open("file_cubic_bezier_limits.html"); + }); +</script> diff --git a/dom/animation/test/mozilla/test_deferred_start.html b/dom/animation/test/mozilla/test_deferred_start.html new file mode 100644 index 0000000000..4db4bf6766 --- /dev/null +++ b/dom/animation/test/mozilla/test_deferred_start.html @@ -0,0 +1,14 @@ +<!doctype html> +<meta charset=utf-8> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +'use strict'; +setup({explicit_done: true}); +SpecialPowers.pushPrefEnv( + { "set": [["dom.animations-api.core.enabled", true]]}, + function() { + window.open("file_deferred_start.html"); + }); +</script> diff --git a/dom/animation/test/mozilla/test_disable_animations_api_core.html b/dom/animation/test/mozilla/test_disable_animations_api_core.html new file mode 100644 index 0000000000..cfb64e5371 --- /dev/null +++ b/dom/animation/test/mozilla/test_disable_animations_api_core.html @@ -0,0 +1,14 @@ +<!doctype html> +<meta charset=utf-8> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +'use strict'; +setup({explicit_done: true}); +SpecialPowers.pushPrefEnv( + { "set": [["dom.animations-api.core.enabled", false]]}, + function() { + window.open("file_disable_animations_api_core.html"); + }); +</script> diff --git a/dom/animation/test/mozilla/test_disabled_properties.html b/dom/animation/test/mozilla/test_disabled_properties.html new file mode 100644 index 0000000000..86d02e6b69 --- /dev/null +++ b/dom/animation/test/mozilla/test_disabled_properties.html @@ -0,0 +1,14 @@ +<!doctype html> +<meta charset=utf-8> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +'use strict'; +setup({explicit_done: true}); +SpecialPowers.pushPrefEnv( + { "set": [["dom.animations-api.core.enabled", true]]}, + function() { + window.open("file_disabled_properties.html"); + }); +</script> diff --git a/dom/animation/test/mozilla/test_discrete-animations.html b/dom/animation/test/mozilla/test_discrete-animations.html new file mode 100644 index 0000000000..2a36bd50e0 --- /dev/null +++ b/dom/animation/test/mozilla/test_discrete-animations.html @@ -0,0 +1,18 @@ +<!doctype html> +<meta charset=utf-8> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +'use strict'; +setup({explicit_done: true}); +SpecialPowers.pushPrefEnv( + { "set": [ + ["dom.animations-api.core.enabled", true], + ["layout.css.osx-font-smoothing.enabled", true], + ["layout.css.prefixes.webkit", true] + ] }, + function() { + window.open("file_discrete-animations.html"); + }); +</script> diff --git a/dom/animation/test/mozilla/test_document-timeline-origin-time-range.html b/dom/animation/test/mozilla/test_document-timeline-origin-time-range.html new file mode 100644 index 0000000000..f73c233d39 --- /dev/null +++ b/dom/animation/test/mozilla/test_document-timeline-origin-time-range.html @@ -0,0 +1,14 @@ +<!doctype html> +<meta charset=utf-8> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +'use strict'; +setup({explicit_done: true}); +SpecialPowers.pushPrefEnv( + { "set": [["dom.animations-api.core.enabled", true]]}, + function() { + window.open("file_document-timeline-origin-time-range.html"); + }); +</script> diff --git a/dom/animation/test/mozilla/test_hide_and_show.html b/dom/animation/test/mozilla/test_hide_and_show.html new file mode 100644 index 0000000000..929a31bd47 --- /dev/null +++ b/dom/animation/test/mozilla/test_hide_and_show.html @@ -0,0 +1,14 @@ +<!doctype html> +<meta charset=utf-8> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +'use strict'; +setup({explicit_done: true}); +SpecialPowers.pushPrefEnv( + { "set": [["dom.animations-api.core.enabled", true]]}, + function() { + window.open("file_hide_and_show.html"); + }); +</script> diff --git a/dom/animation/test/mozilla/test_partial_keyframes.html b/dom/animation/test/mozilla/test_partial_keyframes.html new file mode 100644 index 0000000000..28eb4c5881 --- /dev/null +++ b/dom/animation/test/mozilla/test_partial_keyframes.html @@ -0,0 +1,14 @@ +<!doctype html> +<meta charset=utf-8> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +'use strict'; +setup({explicit_done: true}); +SpecialPowers.pushPrefEnv( + { "set": [["dom.animations-api.core.enabled", true]]}, + function() { + window.open("file_partial_keyframes.html"); + }); +</script> diff --git a/dom/animation/test/mozilla/test_set-easing.html b/dom/animation/test/mozilla/test_set-easing.html new file mode 100644 index 0000000000..e0069ff1c8 --- /dev/null +++ b/dom/animation/test/mozilla/test_set-easing.html @@ -0,0 +1,14 @@ +<!doctype html> +<meta charset=utf-8> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +'use strict'; +setup({explicit_done: true}); +SpecialPowers.pushPrefEnv( + { "set": [["dom.animations-api.core.enabled", true]]}, + function() { + window.open("file_set-easing.html"); + }); +</script> diff --git a/dom/animation/test/mozilla/test_spacing_property_order.html b/dom/animation/test/mozilla/test_spacing_property_order.html new file mode 100644 index 0000000000..afcc12bedf --- /dev/null +++ b/dom/animation/test/mozilla/test_spacing_property_order.html @@ -0,0 +1,14 @@ +<!doctype html> +<meta charset=utf-8> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +'use strict'; +setup({explicit_done: true}); +SpecialPowers.pushPrefEnv( + { "set": [["dom.animations-api.core.enabled", true]]}, + function() { + window.open("file_spacing_property_order.html"); + }); +</script> diff --git a/dom/animation/test/mozilla/test_spacing_transform.html b/dom/animation/test/mozilla/test_spacing_transform.html new file mode 100644 index 0000000000..38dce7e99c --- /dev/null +++ b/dom/animation/test/mozilla/test_spacing_transform.html @@ -0,0 +1,14 @@ +<!doctype html> +<meta charset=utf-8> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +'use strict'; +setup({explicit_done: true}); +SpecialPowers.pushPrefEnv( + { "set": [["dom.animations-api.core.enabled", true]]}, + function() { + window.open("file_spacing_transform.html"); + }); +</script> diff --git a/dom/animation/test/mozilla/test_transform_limits.html b/dom/animation/test/mozilla/test_transform_limits.html new file mode 100644 index 0000000000..6c9b5e4fa9 --- /dev/null +++ b/dom/animation/test/mozilla/test_transform_limits.html @@ -0,0 +1,14 @@ +<!doctype html> +<meta charset=utf-8> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +'use strict'; +setup({explicit_done: true}); +SpecialPowers.pushPrefEnv( + { "set": [["dom.animations-api.core.enabled", true]]}, + function() { + window.open("file_transform_limits.html"); + }); +</script> diff --git a/dom/animation/test/mozilla/test_transition_finish_on_compositor.html b/dom/animation/test/mozilla/test_transition_finish_on_compositor.html new file mode 100644 index 0000000000..357e5297e9 --- /dev/null +++ b/dom/animation/test/mozilla/test_transition_finish_on_compositor.html @@ -0,0 +1,14 @@ +<!doctype html> +<meta charset=utf-8> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +'use strict'; +setup({explicit_done: true}); +SpecialPowers.pushPrefEnv( + { "set": [["dom.animations-api.core.enabled", true]]}, + function() { + window.open("file_transition_finish_on_compositor.html"); + }); +</script> diff --git a/dom/animation/test/mozilla/test_underlying-discrete-value.html b/dom/animation/test/mozilla/test_underlying-discrete-value.html new file mode 100644 index 0000000000..7feee53a15 --- /dev/null +++ b/dom/animation/test/mozilla/test_underlying-discrete-value.html @@ -0,0 +1,15 @@ +<!doctype html> +<meta charset=utf-8> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +'use strict'; +setup({explicit_done: true}); +SpecialPowers.pushPrefEnv( + { "set": [["dom.animations-api.core.enabled", true]]}, + function() { + window.open("file_underlying-discrete-value.html"); + }); +</script> +</html> |