mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-06 07:48:38 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
|
|
@ -0,0 +1,278 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<title>KeyframeEffectReadOnly constructor tests</title>
|
||||
<link rel="help" href="https://w3c.github.io/web-animations/#the-keyframeeffect-interfaces">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../../testcommon.js"></script>
|
||||
<script src="../../resources/keyframe-utils.js"></script>
|
||||
<body>
|
||||
<div id="log"></div>
|
||||
<div id="target"></div>
|
||||
<style>
|
||||
#target {
|
||||
border-style: solid; /* so border-*-width values don't compute to 0 */
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
var target = document.getElementById("target");
|
||||
|
||||
test(function(t) {
|
||||
gEmptyKeyframeListTests.forEach(function(frames) {
|
||||
assert_equals(new KeyframeEffectReadOnly(target, frames)
|
||||
.getKeyframes().length,
|
||||
0, "number of frames for " + JSON.stringify(frames));
|
||||
});
|
||||
}, "a KeyframeEffectReadOnly can be constructed with no frames");
|
||||
|
||||
test(function(t) {
|
||||
gEasingValueTests.forEach(function(subtest) {
|
||||
var easing = subtest[0];
|
||||
var expected = subtest[1];
|
||||
var effect = new KeyframeEffectReadOnly(target, {
|
||||
left: ["10px", "20px"],
|
||||
easing: easing
|
||||
});
|
||||
assert_equals(effect.getKeyframes()[0].easing, expected,
|
||||
"resulting easing for '" + easing + "'");
|
||||
});
|
||||
}, "easing values are parsed correctly when passed to the " +
|
||||
"KeyframeEffectReadOnly constructor in a property-indexed keyframe");
|
||||
|
||||
test(function(t) {
|
||||
gEasingValueTests.forEach(function(subtest) {
|
||||
var easing = subtest[0];
|
||||
var expected = subtest[1];
|
||||
var effect = new KeyframeEffectReadOnly(target, [
|
||||
{ offset: 0, left: "10px", easing: easing },
|
||||
{ offset: 1, left: "20px" }
|
||||
]);
|
||||
assert_equals(effect.getKeyframes()[0].easing, expected,
|
||||
"resulting easing for '" + easing + "'");
|
||||
});
|
||||
}, "easing values are parsed correctly when passed to the " +
|
||||
"KeyframeEffectReadOnly constructor in regular keyframes");
|
||||
|
||||
test(function(t) {
|
||||
gEasingValueTests.forEach(function(subtest) {
|
||||
var easing = subtest[0];
|
||||
var expected = subtest[1];
|
||||
var effect = new KeyframeEffectReadOnly(target, {
|
||||
left: ["10px", "20px"]
|
||||
}, { easing: easing });
|
||||
assert_equals(effect.timing.easing, expected,
|
||||
"resulting easing for '" + easing + "'");
|
||||
});
|
||||
}, "easing values are parsed correctly when passed to the " +
|
||||
"KeyframeEffectReadOnly constructor in KeyframeTimingOptions");
|
||||
|
||||
test(function(t) {
|
||||
var getKeyframe = function(composite) {
|
||||
return { left: [ "10px", "20px" ], composite: composite };
|
||||
};
|
||||
gGoodKeyframeCompositeValueTests.forEach(function(composite) {
|
||||
var effect = new KeyframeEffectReadOnly(target, getKeyframe(composite));
|
||||
assert_equals(effect.getKeyframes()[0].composite, composite,
|
||||
"resulting composite for '" + composite + "'");
|
||||
});
|
||||
gBadCompositeValueTests.forEach(function(composite) {
|
||||
assert_throws(new TypeError, function() {
|
||||
new KeyframeEffectReadOnly(target, getKeyframe(composite));
|
||||
});
|
||||
});
|
||||
}, "composite values are parsed correctly when passed to the " +
|
||||
"KeyframeEffectReadOnly constructor in property-indexed keyframes");
|
||||
|
||||
test(function(t) {
|
||||
var getKeyframes = function(composite) {
|
||||
return [
|
||||
{ offset: 0, left: "10px", composite: composite },
|
||||
{ offset: 1, left: "20px" }
|
||||
];
|
||||
};
|
||||
gGoodKeyframeCompositeValueTests.forEach(function(composite) {
|
||||
var effect = new KeyframeEffectReadOnly(target, getKeyframes(composite));
|
||||
assert_equals(effect.getKeyframes()[0].composite, composite,
|
||||
"resulting composite for '" + composite + "'");
|
||||
});
|
||||
gBadCompositeValueTests.forEach(function(composite) {
|
||||
assert_throws(new TypeError, function() {
|
||||
new KeyframeEffectReadOnly(target, getKeyframes(composite));
|
||||
});
|
||||
});
|
||||
}, "composite values are parsed correctly when passed to the " +
|
||||
"KeyframeEffectReadOnly constructor in regular keyframes");
|
||||
|
||||
test(function(t) {
|
||||
gGoodOptionsCompositeValueTests.forEach(function(composite) {
|
||||
var effect = new KeyframeEffectReadOnly(target, {
|
||||
left: ["10px", "20px"]
|
||||
}, { composite: composite });
|
||||
assert_equals(effect.getKeyframes()[0].composite, composite,
|
||||
"resulting composite for '" + composite + "'");
|
||||
});
|
||||
gBadCompositeValueTests.forEach(function(composite) {
|
||||
assert_throws(new TypeError, function() {
|
||||
new KeyframeEffectReadOnly(target, {
|
||||
left: ["10px", "20px"]
|
||||
}, { composite: composite });
|
||||
});
|
||||
});
|
||||
}, "composite values are parsed correctly when passed to the " +
|
||||
"KeyframeEffectReadOnly constructor in KeyframeTimingOptions");
|
||||
|
||||
gPropertyIndexedKeyframesTests.forEach(function(subtest) {
|
||||
test(function(t) {
|
||||
var effect = new KeyframeEffectReadOnly(target, subtest.input);
|
||||
assert_frame_lists_equal(effect.getKeyframes(), subtest.output);
|
||||
}, "a KeyframeEffectReadOnly can be constructed with " + subtest.desc);
|
||||
|
||||
test(function(t) {
|
||||
var effect = new KeyframeEffectReadOnly(target, subtest.input);
|
||||
var secondEffect =
|
||||
new KeyframeEffectReadOnly(target, effect.getKeyframes());
|
||||
assert_frame_lists_equal(secondEffect.getKeyframes(),
|
||||
effect.getKeyframes());
|
||||
}, "a KeyframeEffectReadOnly constructed with " + subtest.desc +
|
||||
" roundtrips");
|
||||
});
|
||||
|
||||
test(function(t) {
|
||||
var expectedOrder = ["composite", "easing", "offset", "left", "marginLeft"];
|
||||
var actualOrder = [];
|
||||
var kf1 = {};
|
||||
var kf2 = { marginLeft: "10px", left: "20px", offset: 1 };
|
||||
[{ p: "marginLeft", v: "10px" },
|
||||
{ p: "left", v: "20px" },
|
||||
{ p: "offset", v: "0" },
|
||||
{ p: "easing", v: "linear" },
|
||||
{ p: "composite", v: "replace" }].forEach(function(e) {
|
||||
Object.defineProperty(kf1, e.p, {
|
||||
enumerable: true,
|
||||
get: function() { actualOrder.push(e.p); return e.v; }
|
||||
});
|
||||
});
|
||||
new KeyframeEffectReadOnly(target, [kf1, kf2]);
|
||||
assert_array_equals(actualOrder, expectedOrder, "property access order");
|
||||
}, "the KeyframeEffectReadOnly constructor reads keyframe properties in the " +
|
||||
"expected order");
|
||||
|
||||
gKeyframeSequenceTests.forEach(function(subtest) {
|
||||
test(function(t) {
|
||||
var effect = new KeyframeEffectReadOnly(target, subtest.input);
|
||||
assert_frame_lists_equal(effect.getKeyframes(), subtest.output);
|
||||
}, "a KeyframeEffectReadOnly can be constructed with " + subtest.desc);
|
||||
|
||||
test(function(t) {
|
||||
var effect = new KeyframeEffectReadOnly(target, subtest.input);
|
||||
var secondEffect =
|
||||
new KeyframeEffectReadOnly(target, effect.getKeyframes());
|
||||
assert_frame_lists_equal(secondEffect.getKeyframes(),
|
||||
effect.getKeyframes());
|
||||
}, "a KeyframeEffectReadOnly constructed with " + subtest.desc +
|
||||
" roundtrips");
|
||||
});
|
||||
|
||||
gInvalidKeyframesTests.forEach(function(subtest) {
|
||||
test(function(t) {
|
||||
assert_throws(subtest.expected, function() {
|
||||
new KeyframeEffectReadOnly(target, subtest.input);
|
||||
});
|
||||
}, "KeyframeEffectReadOnly constructor throws with " + subtest.desc);
|
||||
});
|
||||
|
||||
gInvalidEasingInKeyframeSequenceTests.forEach(function(subtest) {
|
||||
test(function(t) {
|
||||
assert_throws(new TypeError, function() {
|
||||
new KeyframeEffectReadOnly(target, subtest.input);
|
||||
});
|
||||
}, "Invalid easing [" + subtest.desc + "] in keyframe sequence " +
|
||||
"should be thrown");
|
||||
});
|
||||
|
||||
test(function(t) {
|
||||
var effect = new KeyframeEffectReadOnly(target,
|
||||
{ left: ["10px", "20px"] });
|
||||
|
||||
var timing = effect.timing;
|
||||
assert_equals(timing.delay, 0, "default delay");
|
||||
assert_equals(timing.endDelay, 0, "default endDelay");
|
||||
assert_equals(timing.fill, "auto", "default fill");
|
||||
assert_equals(timing.iterations, 1.0, "default iterations");
|
||||
assert_equals(timing.iterationStart, 0.0, "default iterationStart");
|
||||
assert_equals(timing.duration, "auto", "default duration");
|
||||
assert_equals(timing.direction, "normal", "default direction");
|
||||
assert_equals(timing.easing, "linear", "default easing");
|
||||
|
||||
assert_equals(effect.composite, "replace", "default composite");
|
||||
assert_equals(effect.iterationComposite, "replace",
|
||||
"default iterationComposite");
|
||||
assert_equals(effect.spacing, "distribute",
|
||||
"default spacing");
|
||||
}, "a KeyframeEffectReadOnly constructed without any " +
|
||||
"KeyframeEffectOptions object");
|
||||
|
||||
gKeyframeEffectOptionTests.forEach(function(stest) {
|
||||
test(function(t) {
|
||||
var effect = new KeyframeEffectReadOnly(target,
|
||||
{ left: ["10px", "20px"] },
|
||||
stest.input);
|
||||
|
||||
// Helper function to provide default expected values when the test does
|
||||
// not supply them.
|
||||
var expected = function(field, defaultValue) {
|
||||
return field in stest.expected ? stest.expected[field] : defaultValue;
|
||||
};
|
||||
|
||||
var timing = effect.timing;
|
||||
assert_equals(timing.delay, expected("delay", 0),
|
||||
"timing delay");
|
||||
assert_equals(timing.fill, expected("fill", "auto"),
|
||||
"timing fill");
|
||||
assert_equals(timing.iterations, expected("iterations", 1),
|
||||
"timing iterations");
|
||||
assert_equals(timing.duration, expected("duration", "auto"),
|
||||
"timing duration");
|
||||
assert_equals(timing.direction, expected("direction", "normal"),
|
||||
"timing direction");
|
||||
|
||||
}, "a KeyframeEffectReadOnly constructed by " + stest.desc);
|
||||
});
|
||||
|
||||
gInvalidKeyframeEffectOptionTests.forEach(function(stest) {
|
||||
test(function(t) {
|
||||
assert_throws(stest.expected, function() {
|
||||
new KeyframeEffectReadOnly(target,
|
||||
{ left: ["10px", "20px"] },
|
||||
stest.input);
|
||||
});
|
||||
}, "Invalid KeyframeEffectReadOnly option by " + stest.desc);
|
||||
});
|
||||
|
||||
test(function(t) {
|
||||
var effect = new KeyframeEffectReadOnly(null,
|
||||
{ left: ["10px", "20px"] },
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
fill: "forwards" });
|
||||
assert_equals(effect.target, null,
|
||||
"Effect created with null target has correct target");
|
||||
}, "a KeyframeEffectReadOnly constructed with null target");
|
||||
|
||||
test(function(t) {
|
||||
var effect = new KeyframeEffect(target, null);
|
||||
assert_class_string(effect, "KeyframeEffect");
|
||||
assert_class_string(effect.timing, "AnimationEffectTiming");
|
||||
}, "KeyframeEffect constructor creates an AnimationEffectTiming timing object");
|
||||
|
||||
test(function(t) {
|
||||
var test_error = { name: "test" };
|
||||
|
||||
assert_throws(test_error, function() {
|
||||
new KeyframeEffect(target, { get left() { throw test_error }})
|
||||
});
|
||||
}, "KeyframeEffect constructor propagates exceptions generated by accessing"
|
||||
+ " the options object");
|
||||
</script>
|
||||
</body>
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<title>KeyframeEffect copy constructor tests</title>
|
||||
<link rel="help"
|
||||
href="https://w3c.github.io/web-animations/#dom-keyframeeffect-keyframeeffect-source">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../../testcommon.js"></script>
|
||||
<body>
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
test(function(t) {
|
||||
var effect = new KeyframeEffectReadOnly(createDiv(t), null);
|
||||
assert_equals(effect.constructor.name, 'KeyframeEffectReadOnly');
|
||||
assert_equals(effect.timing.constructor.name,
|
||||
'AnimationEffectTimingReadOnly');
|
||||
|
||||
// Make a mutable copy
|
||||
var copiedEffect = new KeyframeEffect(effect);
|
||||
assert_equals(copiedEffect.constructor.name, 'KeyframeEffect');
|
||||
assert_equals(copiedEffect.timing.constructor.name, 'AnimationEffectTiming');
|
||||
}, 'Test mutable copy from a KeyframeEffectReadOnly source');
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
|
@ -0,0 +1,683 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<title>Effect-level easing tests</title>
|
||||
<link rel="help" href="http://w3c.github.io/web-animations/#calculating-the-transformed-time">
|
||||
<link rel="author" title="Hiroyuki Ikezoe" href="mailto:hiikezoe@mozilla-japan.org">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../../testcommon.js"></script>
|
||||
<script src="../../resources/effect-easing-tests.js"></script>
|
||||
<body>
|
||||
<div id="log"></div>
|
||||
<div id="target"></div>
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
function assert_style_left_at(animation, time, easingFunction) {
|
||||
animation.currentTime = time;
|
||||
var portion = time / animation.effect.timing.duration;
|
||||
assert_approx_equals(pxToNum(getComputedStyle(animation.effect.target).left),
|
||||
easingFunction(portion) * 100,
|
||||
0.01,
|
||||
'The left of the animation should be approximately ' +
|
||||
easingFunction(portion) * 100 + ' at ' + time + 'ms');
|
||||
}
|
||||
|
||||
gEffectEasingTests.forEach(function(options) {
|
||||
test(function(t) {
|
||||
var target = createDiv(t);
|
||||
target.style.position = 'absolute';
|
||||
var anim = target.animate([ { left: '0px' }, { left: '100px' } ],
|
||||
{ duration: 1000,
|
||||
fill: 'forwards',
|
||||
easing: options.easing });
|
||||
var easing = options.easingFunction;
|
||||
|
||||
anim.pause();
|
||||
|
||||
assert_style_left_at(anim, 0, easing);
|
||||
assert_style_left_at(anim, 250, easing);
|
||||
assert_style_left_at(anim, 500, easing);
|
||||
assert_style_left_at(anim, 750, easing);
|
||||
assert_style_left_at(anim, 1000, easing);
|
||||
}, options.desc);
|
||||
});
|
||||
|
||||
var gEffectEasingTestsWithKeyframeEasing = [
|
||||
{
|
||||
desc: 'effect easing produces values greater than 1 with keyframe ' +
|
||||
'easing cubic-bezier(0, 0, 0, 0)',
|
||||
easing: 'cubic-bezier(0, 1.5, 1, 1.5)',
|
||||
keyframeEasing: 'cubic-bezier(0, 0, 0, 0)', // linear
|
||||
easingFunction: cubicBezier(0, 1.5, 1, 1.5)
|
||||
},
|
||||
{
|
||||
desc: 'effect easing produces values greater than 1 with keyframe ' +
|
||||
'easing cubic-bezier(1, 1, 1, 1)',
|
||||
easing: 'cubic-bezier(0, 1.5, 1, 1.5)',
|
||||
keyframeEasing: 'cubic-bezier(1, 1, 1, 1)', // linear
|
||||
easingFunction: cubicBezier(0, 1.5, 1, 1.5)
|
||||
},
|
||||
{
|
||||
desc: 'effect easing produces negative values 1 with keyframe ' +
|
||||
'easing cubic-bezier(0, 0, 0, 0)',
|
||||
easing: 'cubic-bezier(0, -0.5, 1, -0.5)',
|
||||
keyframeEasing: 'cubic-bezier(0, 0, 0, 0)', // linear
|
||||
easingFunction: cubicBezier(0, -0.5, 1, -0.5)
|
||||
},
|
||||
{
|
||||
desc: 'effect easing produces negative values 1 with keyframe ' +
|
||||
'easing cubic-bezier(1, 1, 1, 1)',
|
||||
easing: 'cubic-bezier(0, -0.5, 1, -0.5)',
|
||||
keyframeEasing: 'cubic-bezier(1, 1, 1, 1)', // linear
|
||||
easingFunction: cubicBezier(0, -0.5, 1, -0.5)
|
||||
},
|
||||
];
|
||||
|
||||
gEffectEasingTestsWithKeyframeEasing.forEach(function(options) {
|
||||
test(function(t) {
|
||||
var target = createDiv(t);
|
||||
target.style.position = 'absolute';
|
||||
var anim = target.animate(
|
||||
[ { left: '0px', easing: options.keyframeEasing },
|
||||
{ left: '100px' } ],
|
||||
{ duration: 1000,
|
||||
fill: 'forwards',
|
||||
easing: options.easing });
|
||||
var easing = options.easingFunction;
|
||||
|
||||
anim.pause();
|
||||
|
||||
assert_style_left_at(anim, 0, easing);
|
||||
assert_style_left_at(anim, 250, easing);
|
||||
assert_style_left_at(anim, 500, easing);
|
||||
assert_style_left_at(anim, 750, easing);
|
||||
assert_style_left_at(anim, 1000, easing);
|
||||
}, options.desc);
|
||||
});
|
||||
|
||||
// Other test cases that effect easing produces values outside of [0,1].
|
||||
test(function(t) {
|
||||
var target = createDiv(t);
|
||||
target.style.position = 'absolute';
|
||||
var anim = target.animate([ { left: '0px', easing: 'step-start' },
|
||||
{ left: '100px' } ],
|
||||
{ duration: 1000,
|
||||
fill: 'forwards',
|
||||
easing: 'cubic-bezier(0, 1.5, 1, 1.5)' });
|
||||
anim.pause();
|
||||
|
||||
// The bezier function produces values greater than 1 in (0.23368794, 1)
|
||||
anim.currentTime = 0;
|
||||
assert_equals(getComputedStyle(target).left, '100px');
|
||||
anim.currentTime = 230;
|
||||
assert_equals(getComputedStyle(target).left, '100px');
|
||||
anim.currentTime = 250;
|
||||
assert_equals(getComputedStyle(target).left, '100px');
|
||||
anim.currentTime = 1000;
|
||||
assert_equals(getComputedStyle(target).left, '100px');
|
||||
}, 'effect easing produces values greater than 1 with step-start keyframe');
|
||||
|
||||
test(function(t) {
|
||||
var target = createDiv(t);
|
||||
target.style.position = 'absolute';
|
||||
var anim = target.animate([ { left: '0px', easing: 'step-end' },
|
||||
{ left: '100px' } ],
|
||||
{ duration: 1000,
|
||||
fill: 'forwards',
|
||||
easing: 'cubic-bezier(0, 1.5, 1, 1.5)' });
|
||||
anim.pause();
|
||||
|
||||
// The bezier function produces values greater than 1 in (0.23368794, 1)
|
||||
anim.currentTime = 0;
|
||||
assert_equals(getComputedStyle(target).left, '0px');
|
||||
anim.currentTime = 230;
|
||||
assert_equals(getComputedStyle(target).left, '0px');
|
||||
anim.currentTime = 250;
|
||||
assert_equals(getComputedStyle(target).left, '100px');
|
||||
anim.currentTime = 1000;
|
||||
assert_equals(getComputedStyle(target).left, '100px');
|
||||
}, 'effect easing produces values greater than 1 with step-end keyframe');
|
||||
|
||||
test(function(t) {
|
||||
var target = createDiv(t);
|
||||
target.style.position = 'absolute';
|
||||
var anim = target.animate([ { left: '0px', easing: 'step-start' },
|
||||
{ left: '100px' } ],
|
||||
{ duration: 1000,
|
||||
fill: 'forwards',
|
||||
easing: 'cubic-bezier(0, -0.5, 1, -0.5)' });
|
||||
anim.pause();
|
||||
|
||||
// The bezier function produces negative values in (0, 0.766312060)
|
||||
anim.currentTime = 0;
|
||||
assert_equals(getComputedStyle(target).left, '100px');
|
||||
anim.currentTime = 750;
|
||||
assert_equals(getComputedStyle(target).left, '0px');
|
||||
anim.currentTime = 800;
|
||||
assert_equals(getComputedStyle(target).left, '100px');
|
||||
anim.currentTime = 1000;
|
||||
assert_equals(getComputedStyle(target).left, '100px');
|
||||
}, 'effect easing produces negative values with step-start keyframe');
|
||||
|
||||
test(function(t) {
|
||||
var target = createDiv(t);
|
||||
target.style.position = 'absolute';
|
||||
var anim = target.animate([ { left: '0px', easing: 'step-end' },
|
||||
{ left: '100px' } ],
|
||||
{ duration: 1000,
|
||||
fill: 'forwards',
|
||||
easing: 'cubic-bezier(0, -0.5, 1, -0.5)' });
|
||||
anim.pause();
|
||||
|
||||
// The bezier function produces negative values in (0, 0.766312060)
|
||||
anim.currentTime = 0;
|
||||
assert_equals(getComputedStyle(target).left, '0px');
|
||||
anim.currentTime = 750;
|
||||
assert_equals(getComputedStyle(target).left, '0px');
|
||||
anim.currentTime = 800;
|
||||
assert_equals(getComputedStyle(target).left, '0px');
|
||||
anim.currentTime = 1000;
|
||||
assert_equals(getComputedStyle(target).left, '100px');
|
||||
}, 'effect easing produces negative values with step-end keyframe');
|
||||
|
||||
test(function(t) {
|
||||
var target = createDiv(t);
|
||||
target.style.position = 'absolute';
|
||||
var anim = target.animate(
|
||||
// http://cubic-bezier.com/#.5,1,.5,0
|
||||
[ { left: '0px', easing: 'cubic-bezier(0.5, 1, 0.5, 0)' },
|
||||
{ left: '100px' } ],
|
||||
{ duration: 1000,
|
||||
fill: 'forwards',
|
||||
easing: 'cubic-bezier(0, 1.5, 1, 1.5)' });
|
||||
var keyframeEasing = function(x) {
|
||||
assert_greater_than_equal(x, 0.0,
|
||||
'This function should be called in [0, 1.0] range');
|
||||
assert_less_than_equal(x, 1.0,
|
||||
'This function should be called in [0, 1.0] range');
|
||||
return cubicBezier(0.5, 1, 0.5, 0)(x);
|
||||
}
|
||||
var keyframeEasingExtrapolated = function(x) {
|
||||
assert_greater_than(x, 1.0,
|
||||
'This function should be called in (1.0, infinity) range');
|
||||
// p3x + (p2y - p3y) / (p2x - p3x) * (x - p3x)
|
||||
return 1.0 + (0 - 1) / (0.5 - 1) * (x - 1.0);
|
||||
}
|
||||
var effectEasing = function(x) {
|
||||
return cubicBezier(0, 1.5, 1, 1.5)(x);
|
||||
}
|
||||
|
||||
anim.pause();
|
||||
|
||||
// The effect-easing produces values greater than 1 in (0.23368794, 1)
|
||||
assert_style_left_at(anim, 0, function(x) {
|
||||
return keyframeEasing(effectEasing(x));
|
||||
});
|
||||
assert_style_left_at(anim, 230, function(x) {
|
||||
return keyframeEasing(effectEasing(x));
|
||||
});
|
||||
assert_style_left_at(anim, 240, function(x) {
|
||||
return keyframeEasingExtrapolated(effectEasing(x));
|
||||
});
|
||||
// Near the extreme point of the effect-easing function
|
||||
assert_style_left_at(anim, 700, function(x) {
|
||||
return keyframeEasingExtrapolated(effectEasing(x));
|
||||
});
|
||||
assert_style_left_at(anim, 990, function(x) {
|
||||
return keyframeEasingExtrapolated(effectEasing(x));
|
||||
});
|
||||
assert_style_left_at(anim, 1000, function(x) {
|
||||
return keyframeEasing(effectEasing(x));
|
||||
});
|
||||
}, 'effect easing produces values greater than 1 with keyframe easing ' +
|
||||
'producing values greater than 1');
|
||||
|
||||
test(function(t) {
|
||||
var target = createDiv(t);
|
||||
target.style.position = 'absolute';
|
||||
var anim = target.animate(
|
||||
// http://cubic-bezier.com/#0,1.5,1,1.5
|
||||
[ { left: '0px', easing: 'cubic-bezier(0, 1.5, 1, 1.5)' },
|
||||
{ left: '100px' } ],
|
||||
{ duration: 1000,
|
||||
fill: 'forwards',
|
||||
easing: 'cubic-bezier(0, 1.5, 1, 1.5)' });
|
||||
var easing = function(x) {
|
||||
assert_greater_than_equal(x, 0.0,
|
||||
'This function should be called in [0, 1.0] range');
|
||||
assert_less_than_equal(x, 1.0,
|
||||
'This function should be called in [0, 1.0] range');
|
||||
return cubicBezier(0, 1.5, 1, 1.5)(x);
|
||||
}
|
||||
var easingExtrapolated = function(x) {
|
||||
assert_greater_than(x, 1.0,
|
||||
'This function should be called in negative range');
|
||||
// For cubic-bezier(0, 1.5, 1, 1.5), the tangent at the
|
||||
// endpoint (x = 1.0) is infinity so we should just return 1.0.
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
anim.pause();
|
||||
|
||||
// The effect-easing produces values greater than 1 in (0.23368794, 1)
|
||||
assert_style_left_at(anim, 0, function(x) {
|
||||
return easing(easing(x))
|
||||
});
|
||||
assert_style_left_at(anim, 230, function(x) {
|
||||
return easing(easing(x))
|
||||
});
|
||||
assert_style_left_at(anim, 240, function(x) {
|
||||
return easingExtrapolated(easing(x));
|
||||
});
|
||||
// Near the extreme point of the effect-easing function
|
||||
assert_style_left_at(anim, 700, function(x) {
|
||||
return easingExtrapolated(easing(x));
|
||||
});
|
||||
assert_style_left_at(anim, 990, function(x) {
|
||||
return easingExtrapolated(easing(x));
|
||||
});
|
||||
assert_style_left_at(anim, 1000, function(x) {
|
||||
return easing(easing(x))
|
||||
});
|
||||
}, 'effect easing which produces values greater than 1 and the tangent on ' +
|
||||
'the upper boundary is infinity with keyframe easing producing values ' +
|
||||
'greater than 1');
|
||||
|
||||
test(function(t) {
|
||||
var target = createDiv(t);
|
||||
target.style.position = 'absolute';
|
||||
var anim = target.animate(
|
||||
// http://cubic-bezier.com/#.5,1,.5,0
|
||||
[ { left: '0px', easing: 'cubic-bezier(0.5, 1, 0.5, 0)' },
|
||||
{ left: '100px' } ],
|
||||
{ duration: 1000,
|
||||
fill: 'forwards',
|
||||
easing: 'cubic-bezier(0, -0.5, 1, -0.5)' });
|
||||
var keyframeEasing = function(x) {
|
||||
assert_greater_than_equal(x, 0.0,
|
||||
'This function should be called in [0, 1.0] range');
|
||||
assert_less_than_equal(x, 1.0,
|
||||
'This function should be called in [0, 1.0] range');
|
||||
return cubicBezier(0.5, 1, 0.5, 0)(x);
|
||||
}
|
||||
var keyframeEasingExtrapolated = function(x) {
|
||||
assert_less_than(x, 0.0,
|
||||
'This function should be called in negative range');
|
||||
// p0x + (p1y - p0y) / (p1x - p0x) * (x - p0x)
|
||||
return (1 / 0.5) * x;
|
||||
}
|
||||
var effectEasing = function(x) {
|
||||
return cubicBezier(0, -0.5, 1, -0.5)(x);
|
||||
}
|
||||
|
||||
anim.pause();
|
||||
|
||||
// The effect-easing produces negative values in (0, 0.766312060)
|
||||
assert_style_left_at(anim, 0, function(x) {
|
||||
return keyframeEasing(effectEasing(x));
|
||||
});
|
||||
assert_style_left_at(anim, 10, function(x) {
|
||||
return keyframeEasingExtrapolated(effectEasing(x));
|
||||
});
|
||||
// Near the extreme point of the effect-easing function
|
||||
assert_style_left_at(anim, 300, function(x) {
|
||||
return keyframeEasingExtrapolated(effectEasing(x));
|
||||
});
|
||||
assert_style_left_at(anim, 750, function(x) {
|
||||
return keyframeEasingExtrapolated(effectEasing(x));
|
||||
});
|
||||
assert_style_left_at(anim, 770, function(x) {
|
||||
return keyframeEasing(effectEasing(x));
|
||||
});
|
||||
assert_style_left_at(anim, 1000, function(x) {
|
||||
return keyframeEasing(effectEasing(x));
|
||||
});
|
||||
}, 'effect easing produces negative values with keyframe easing ' +
|
||||
'producing negative values');
|
||||
|
||||
test(function(t) {
|
||||
var target = createDiv(t);
|
||||
target.style.position = 'absolute';
|
||||
var anim = target.animate(
|
||||
// http://cubic-bezier.com/#0,-0.5,1,-0.5
|
||||
[ { left: '0px', easing: 'cubic-bezier(0, -0.5, 1, -0.5)' },
|
||||
{ left: '100px' } ],
|
||||
{ duration: 1000,
|
||||
fill: 'forwards',
|
||||
easing: 'cubic-bezier(0, -0.5, 1, -0.5)' });
|
||||
var easing = function(x) {
|
||||
assert_greater_than_equal(x, 0.0,
|
||||
'This function should be called in [0, 1.0] range');
|
||||
assert_less_than_equal(x, 1.0,
|
||||
'This function should be called in [0, 1.0] range');
|
||||
return cubicBezier(0, -0.5, 1, -0.5)(x);
|
||||
}
|
||||
var easingExtrapolated = function(x) {
|
||||
assert_less_than(x, 0.0,
|
||||
'This function should be called in negative range');
|
||||
// For cubic-bezier(0, -0.5, 1, -0.5), the tangent at the
|
||||
// endpoint (x = 0.0) is infinity so we should just return 0.0.
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
anim.pause();
|
||||
|
||||
// The effect-easing produces negative values in (0, 0.766312060)
|
||||
assert_style_left_at(anim, 0, function(x) {
|
||||
return easing(easing(x))
|
||||
});
|
||||
assert_style_left_at(anim, 10, function(x) {
|
||||
return easingExtrapolated(easing(x));
|
||||
});
|
||||
// Near the extreme point of the effect-easing function
|
||||
assert_style_left_at(anim, 300, function(x) {
|
||||
return easingExtrapolated(easing(x));
|
||||
});
|
||||
assert_style_left_at(anim, 750, function(x) {
|
||||
return easingExtrapolated(easing(x));
|
||||
});
|
||||
assert_style_left_at(anim, 770, function(x) {
|
||||
return easing(easing(x))
|
||||
});
|
||||
assert_style_left_at(anim, 1000, function(x) {
|
||||
return easing(easing(x))
|
||||
});
|
||||
}, 'effect easing which produces negative values and the tangent on ' +
|
||||
'the lower boundary is infinity with keyframe easing producing ' +
|
||||
'negative values');
|
||||
|
||||
var gStepTimingFunctionTests = [
|
||||
{
|
||||
description: 'Test bounds point of step-start easing',
|
||||
keyframe: [ { width: '0px' },
|
||||
{ width: '100px' } ],
|
||||
effect: {
|
||||
delay: 1000,
|
||||
duration: 1000,
|
||||
fill: 'both',
|
||||
easing: 'steps(2, start)'
|
||||
},
|
||||
conditions: [
|
||||
{ currentTime: 0, progress: 0 },
|
||||
{ currentTime: 999, progress: 0 },
|
||||
{ currentTime: 1000, progress: 0.5 },
|
||||
{ currentTime: 1499, progress: 0.5 },
|
||||
{ currentTime: 1500, progress: 1 },
|
||||
{ currentTime: 2000, progress: 1 }
|
||||
]
|
||||
},
|
||||
{
|
||||
description: 'Test bounds point of step-start easing with compositor',
|
||||
keyframe: [ { opacity: 0 },
|
||||
{ opacity: 1 } ],
|
||||
effect: {
|
||||
delay: 1000,
|
||||
duration: 1000,
|
||||
fill: 'both',
|
||||
easing: 'steps(2, start)'
|
||||
},
|
||||
conditions: [
|
||||
{ currentTime: 0, progress: 0 },
|
||||
{ currentTime: 999, progress: 0 },
|
||||
{ currentTime: 1000, progress: 0.5 },
|
||||
{ currentTime: 1499, progress: 0.5 },
|
||||
{ currentTime: 1500, progress: 1 },
|
||||
{ currentTime: 2000, progress: 1 }
|
||||
]
|
||||
},
|
||||
{
|
||||
description: 'Test bounds point of step-start easing with reverse direction',
|
||||
keyframe: [ { width: '0px' },
|
||||
{ width: '100px' } ],
|
||||
effect: {
|
||||
delay: 1000,
|
||||
duration: 1000,
|
||||
fill: 'both',
|
||||
direction: 'reverse',
|
||||
easing: 'steps(2, start)'
|
||||
},
|
||||
conditions: [
|
||||
{ currentTime: 0, progress: 1 },
|
||||
{ currentTime: 1001, progress: 1 },
|
||||
{ currentTime: 1500, progress: 1 },
|
||||
{ currentTime: 1501, progress: 0.5 },
|
||||
{ currentTime: 2000, progress: 0 },
|
||||
{ currentTime: 2500, progress: 0 }
|
||||
]
|
||||
},
|
||||
{
|
||||
description: 'Test bounds point of step-start easing ' +
|
||||
'with iterationStart not at a transition point',
|
||||
keyframe: [ { width: '0px' },
|
||||
{ width: '100px' } ],
|
||||
effect: {
|
||||
delay: 1000,
|
||||
duration: 1000,
|
||||
fill: 'both',
|
||||
iterationStart: 0.25,
|
||||
easing: 'steps(2, start)'
|
||||
},
|
||||
conditions: [
|
||||
{ currentTime: 0, progress: 0.5 },
|
||||
{ currentTime: 999, progress: 0.5 },
|
||||
{ currentTime: 1000, progress: 0.5 },
|
||||
{ currentTime: 1249, progress: 0.5 },
|
||||
{ currentTime: 1250, progress: 1 },
|
||||
{ currentTime: 1749, progress: 1 },
|
||||
{ currentTime: 1750, progress: 0.5 },
|
||||
{ currentTime: 2000, progress: 0.5 },
|
||||
{ currentTime: 2500, progress: 0.5 },
|
||||
]
|
||||
},
|
||||
{
|
||||
description: 'Test bounds point of step-start easing ' +
|
||||
'with iterationStart and delay',
|
||||
keyframe: [ { width: '0px' },
|
||||
{ width: '100px' } ],
|
||||
effect: {
|
||||
delay: 1000,
|
||||
duration: 1000,
|
||||
fill: 'both',
|
||||
iterationStart: 0.5,
|
||||
easing: 'steps(2, start)'
|
||||
},
|
||||
conditions: [
|
||||
{ currentTime: 0, progress: 0.5 },
|
||||
{ currentTime: 999, progress: 0.5 },
|
||||
{ currentTime: 1000, progress: 1 },
|
||||
{ currentTime: 1499, progress: 1 },
|
||||
{ currentTime: 1500, progress: 0.5 },
|
||||
{ currentTime: 2000, progress: 1 }
|
||||
]
|
||||
},
|
||||
{
|
||||
description: 'Test bounds point of step-start easing ' +
|
||||
'with iterationStart and reverse direction',
|
||||
keyframe: [ { width: '0px' },
|
||||
{ width: '100px' } ],
|
||||
effect: {
|
||||
delay: 1000,
|
||||
duration: 1000,
|
||||
fill: 'both',
|
||||
iterationStart: 0.5,
|
||||
direction: 'reverse',
|
||||
easing: 'steps(2, start)'
|
||||
},
|
||||
conditions: [
|
||||
{ currentTime: 0, progress: 1 },
|
||||
{ currentTime: 1000, progress: 1 },
|
||||
{ currentTime: 1001, progress: 0.5 },
|
||||
{ currentTime: 1499, progress: 0.5 },
|
||||
{ currentTime: 1500, progress: 1 },
|
||||
{ currentTime: 1999, progress: 1 },
|
||||
{ currentTime: 2000, progress: 0.5 },
|
||||
{ currentTime: 2500, progress: 0.5 }
|
||||
]
|
||||
},
|
||||
{
|
||||
description: 'Test bounds point of step(4, start) easing ' +
|
||||
'with iterationStart 0.75 and delay',
|
||||
keyframe: [ { width: '0px' },
|
||||
{ width: '100px' } ],
|
||||
effect: {
|
||||
duration: 1000,
|
||||
fill: 'both',
|
||||
delay: 1000,
|
||||
iterationStart: 0.75,
|
||||
easing: 'steps(4, start)'
|
||||
},
|
||||
conditions: [
|
||||
{ currentTime: 0, progress: 0.75 },
|
||||
{ currentTime: 999, progress: 0.75 },
|
||||
{ currentTime: 1000, progress: 1 },
|
||||
{ currentTime: 2000, progress: 1 },
|
||||
{ currentTime: 2500, progress: 1 }
|
||||
]
|
||||
},
|
||||
{
|
||||
description: 'Test bounds point of step-start easing ' +
|
||||
'with alternate direction',
|
||||
keyframe: [ { width: '0px' },
|
||||
{ width: '100px' } ],
|
||||
effect: {
|
||||
duration: 1000,
|
||||
fill: 'both',
|
||||
delay: 1000,
|
||||
iterations: 2,
|
||||
iterationStart: 1.5,
|
||||
direction: 'alternate',
|
||||
easing: 'steps(2, start)'
|
||||
},
|
||||
conditions: [
|
||||
{ currentTime: 0, progress: 1 },
|
||||
{ currentTime: 1000, progress: 1 },
|
||||
{ currentTime: 1001, progress: 0.5 },
|
||||
{ currentTime: 2999, progress: 1 },
|
||||
{ currentTime: 3000, progress: 0.5 },
|
||||
{ currentTime: 3500, progress: 0.5 }
|
||||
]
|
||||
},
|
||||
{
|
||||
description: 'Test bounds point of step-start easing ' +
|
||||
'with alternate-reverse direction',
|
||||
keyframe: [ { width: '0px' },
|
||||
{ width: '100px' } ],
|
||||
effect: {
|
||||
duration: 1000,
|
||||
fill: 'both',
|
||||
delay: 1000,
|
||||
iterations: 2,
|
||||
iterationStart: 0.5,
|
||||
direction: 'alternate-reverse',
|
||||
easing: 'steps(2, start)'
|
||||
},
|
||||
conditions: [
|
||||
{ currentTime: 0, progress: 1 },
|
||||
{ currentTime: 1000, progress: 1 },
|
||||
{ currentTime: 1001, progress: 0.5 },
|
||||
{ currentTime: 2999, progress: 1 },
|
||||
{ currentTime: 3000, progress: 0.5 },
|
||||
{ currentTime: 3500, progress: 0.5 }
|
||||
]
|
||||
},
|
||||
{
|
||||
description: 'Test bounds point of step-start easing in keyframe',
|
||||
keyframe: [ { width: '0px', easing: 'steps(2, start)' },
|
||||
{ width: '100px' } ],
|
||||
effect: {
|
||||
delay: 1000,
|
||||
duration: 1000,
|
||||
fill: 'both',
|
||||
},
|
||||
conditions: [
|
||||
{ currentTime: 0, progress: 0, width: '0px' },
|
||||
{ currentTime: 999, progress: 0, width: '0px' },
|
||||
{ currentTime: 1000, progress: 0, width: '50px' },
|
||||
{ currentTime: 1499, progress: 0.499, width: '50px' },
|
||||
{ currentTime: 1500, progress: 0.5, width: '100px' },
|
||||
{ currentTime: 2000, progress: 1, width: '100px' },
|
||||
{ currentTime: 2500, progress: 1, width: '100px' }
|
||||
]
|
||||
},
|
||||
{
|
||||
description: 'Test bounds point of step-end easing ' +
|
||||
'with iterationStart and delay',
|
||||
keyframe: [ { width: '0px' },
|
||||
{ width: '100px' } ],
|
||||
effect: {
|
||||
duration: 1000,
|
||||
fill: 'both',
|
||||
delay: 1000,
|
||||
iterationStart: 0.5,
|
||||
easing: 'steps(2, end)'
|
||||
},
|
||||
conditions: [
|
||||
{ currentTime: 0, progress: 0 },
|
||||
{ currentTime: 999, progress: 0 },
|
||||
{ currentTime: 1000, progress: 0.5 },
|
||||
{ currentTime: 1499, progress: 0.5 },
|
||||
{ currentTime: 1500, progress: 0 },
|
||||
{ currentTime: 1999, progress: 0 },
|
||||
{ currentTime: 2000, progress: 0.5 },
|
||||
{ currentTime: 2500, progress: 0.5 }
|
||||
]
|
||||
},
|
||||
{
|
||||
description: 'Test bounds point of step-end easing ' +
|
||||
'with iterationStart not at a transition point',
|
||||
keyframe: [ { width: '0px' },
|
||||
{ width: '100px' } ],
|
||||
effect: {
|
||||
delay: 1000,
|
||||
duration: 1000,
|
||||
fill: 'both',
|
||||
iterationStart: 0.75,
|
||||
easing: 'steps(2, end)'
|
||||
},
|
||||
conditions: [
|
||||
{ currentTime: 0, progress: 0.5 },
|
||||
{ currentTime: 999, progress: 0.5 },
|
||||
{ currentTime: 1000, progress: 0.5 },
|
||||
{ currentTime: 1249, progress: 0.5 },
|
||||
{ currentTime: 1250, progress: 0 },
|
||||
{ currentTime: 1749, progress: 0 },
|
||||
{ currentTime: 1750, progress: 0.5 },
|
||||
{ currentTime: 2000, progress: 0.5 },
|
||||
{ currentTime: 2500, progress: 0.5 },
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
gStepTimingFunctionTests.forEach(function(options) {
|
||||
test(function(t) {
|
||||
var target = createDiv(t);
|
||||
var animation = target.animate(options.keyframe, options.effect);
|
||||
options.conditions.forEach(function(condition) {
|
||||
animation.currentTime = condition.currentTime;
|
||||
if (typeof condition.progress !== 'undefined') {
|
||||
assert_equals(animation.effect.getComputedTiming().progress,
|
||||
condition.progress,
|
||||
'Progress at ' + animation.currentTime + 'ms');
|
||||
}
|
||||
if (typeof condition.width !== 'undefined') {
|
||||
assert_equals(getComputedStyle(target).width,
|
||||
condition.width,
|
||||
'Progress at ' + animation.currentTime + 'ms');
|
||||
}
|
||||
});
|
||||
}, options.description);
|
||||
});
|
||||
|
||||
gInvalidEasingTests.forEach(function(options) {
|
||||
test(function(t) {
|
||||
var div = createDiv(t);
|
||||
assert_throws({ name: 'TypeError' },
|
||||
function() {
|
||||
div.animate({ easing: options.easing }, 100 * MS_PER_SEC);
|
||||
});
|
||||
}, 'Invalid keyframe easing value: \'' + options.easing + '\'');
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
|
@ -0,0 +1,212 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<title>KeyframeEffectReadOnly getComputedTiming() tests</title>
|
||||
<link rel="help" href="https://w3c.github.io/web-animations/#dom-animationeffectreadonly-getcomputedtiming">
|
||||
<link rel="author" title="Boris Chiou" href="mailto:boris.chiou@gmail.com">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../../testcommon.js"></script>
|
||||
<body>
|
||||
<div id="log"></div>
|
||||
<div id="target"></div>
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
var target = document.getElementById("target");
|
||||
|
||||
test(function(t) {
|
||||
var effect = new KeyframeEffectReadOnly(target,
|
||||
{ left: ["10px", "20px"] });
|
||||
|
||||
var ct = effect.getComputedTiming();
|
||||
assert_equals(ct.delay, 0, "computed delay");
|
||||
assert_equals(ct.fill, "none", "computed fill");
|
||||
assert_equals(ct.iterations, 1.0, "computed iterations");
|
||||
assert_equals(ct.duration, 0, "computed duration");
|
||||
assert_equals(ct.direction, "normal", "computed direction");
|
||||
}, "values of getComputedTiming() when a KeyframeEffectReadOnly is " +
|
||||
"constructed without any KeyframeEffectOptions object");
|
||||
|
||||
var gGetComputedTimingTests = [
|
||||
{ desc: "an empty KeyframeEffectOptions object",
|
||||
input: { },
|
||||
expected: { } },
|
||||
{ desc: "a normal KeyframeEffectOptions object",
|
||||
input: { delay: 1000,
|
||||
fill: "auto",
|
||||
iterations: 5.5,
|
||||
duration: "auto",
|
||||
direction: "alternate" },
|
||||
expected: { delay: 1000,
|
||||
fill: "none",
|
||||
iterations: 5.5,
|
||||
duration: 0,
|
||||
direction: "alternate" } },
|
||||
{ desc: "a double value",
|
||||
input: 3000,
|
||||
timing: { duration: 3000 },
|
||||
expected: { delay: 0,
|
||||
fill: "none",
|
||||
iterations: 1,
|
||||
duration: 3000,
|
||||
direction: "normal" } },
|
||||
{ desc: "+Infinity",
|
||||
input: Infinity,
|
||||
expected: { duration: Infinity } },
|
||||
{ desc: "an Infinity duration",
|
||||
input: { duration: Infinity },
|
||||
expected: { duration: Infinity } },
|
||||
{ desc: "an auto duration",
|
||||
input: { duration: "auto" },
|
||||
expected: { duration: 0 } },
|
||||
{ desc: "an Infinity iterations",
|
||||
input: { iterations: Infinity },
|
||||
expected: { iterations: Infinity } },
|
||||
{ desc: "an auto fill",
|
||||
input: { fill: "auto" },
|
||||
expected: { fill: "none" } },
|
||||
{ desc: "a forwards fill",
|
||||
input: { fill: "forwards" },
|
||||
expected: { fill: "forwards" } }
|
||||
];
|
||||
|
||||
gGetComputedTimingTests.forEach(function(stest) {
|
||||
test(function(t) {
|
||||
var effect = new KeyframeEffectReadOnly(target,
|
||||
{ left: ["10px", "20px"] },
|
||||
stest.input);
|
||||
|
||||
// Helper function to provide default expected values when the test does
|
||||
// not supply them.
|
||||
var expected = function(field, defaultValue) {
|
||||
return field in stest.expected ? stest.expected[field] : defaultValue;
|
||||
};
|
||||
|
||||
var ct = effect.getComputedTiming();
|
||||
assert_equals(ct.delay, expected("delay", 0),
|
||||
"computed delay");
|
||||
assert_equals(ct.fill, expected("fill", "none"),
|
||||
"computed fill");
|
||||
assert_equals(ct.iterations, expected("iterations", 1),
|
||||
"computed iterations");
|
||||
assert_equals(ct.duration, expected("duration", 0),
|
||||
"computed duration");
|
||||
assert_equals(ct.direction, expected("direction", "normal"),
|
||||
"computed direction");
|
||||
|
||||
}, "values of getComputedTiming() when a KeyframeEffectReadOnly is " +
|
||||
"constructed by " + stest.desc);
|
||||
});
|
||||
|
||||
var gActiveDurationTests = [
|
||||
{ desc: "an empty KeyframeEffectOptions object",
|
||||
input: { },
|
||||
expected: 0 },
|
||||
{ desc: "a non-zero duration and default iteration count",
|
||||
input: { duration: 1000 },
|
||||
expected: 1000 },
|
||||
{ desc: "a non-zero duration and integral iteration count",
|
||||
input: { duration: 1000, iterations: 7 },
|
||||
expected: 7000 },
|
||||
{ desc: "a non-zero duration and fractional iteration count",
|
||||
input: { duration: 1000, iterations: 2.5 },
|
||||
expected: 2500 },
|
||||
{ desc: "an non-zero duration and infinite iteration count",
|
||||
input: { duration: 1000, iterations: Infinity },
|
||||
expected: Infinity },
|
||||
{ desc: "an non-zero duration and zero iteration count",
|
||||
input: { duration: 1000, iterations: 0 },
|
||||
expected: 0 },
|
||||
{ desc: "a zero duration and default iteration count",
|
||||
input: { duration: 0 },
|
||||
expected: 0 },
|
||||
{ desc: "a zero duration and fractional iteration count",
|
||||
input: { duration: 0, iterations: 2.5 },
|
||||
expected: 0 },
|
||||
{ desc: "a zero duration and infinite iteration count",
|
||||
input: { duration: 0, iterations: Infinity },
|
||||
expected: 0 },
|
||||
{ desc: "a zero duration and zero iteration count",
|
||||
input: { duration: 0, iterations: 0 },
|
||||
expected: 0 },
|
||||
{ desc: "an infinite duration and default iteration count",
|
||||
input: { duration: Infinity },
|
||||
expected: Infinity },
|
||||
{ desc: "an infinite duration and zero iteration count",
|
||||
input: { duration: Infinity, iterations: 0 },
|
||||
expected: 0 },
|
||||
{ desc: "an infinite duration and fractional iteration count",
|
||||
input: { duration: Infinity, iterations: 2.5 },
|
||||
expected: Infinity },
|
||||
{ desc: "an infinite duration and infinite iteration count",
|
||||
input: { duration: Infinity, iterations: Infinity },
|
||||
expected: Infinity },
|
||||
];
|
||||
|
||||
gActiveDurationTests.forEach(function(stest) {
|
||||
test(function(t) {
|
||||
var effect = new KeyframeEffectReadOnly(target,
|
||||
{ left: ["10px", "20px"] },
|
||||
stest.input);
|
||||
|
||||
assert_equals(effect.getComputedTiming().activeDuration,
|
||||
stest.expected);
|
||||
|
||||
}, "getComputedTiming().activeDuration for " + stest.desc);
|
||||
});
|
||||
|
||||
var gEndTimeTests = [
|
||||
{ desc: "an empty KeyframeEffectOptions object",
|
||||
input: { },
|
||||
expected: 0 },
|
||||
{ desc: "a non-zero duration and default iteration count",
|
||||
input: { duration: 1000 },
|
||||
expected: 1000 },
|
||||
{ desc: "a non-zero duration and non-default iteration count",
|
||||
input: { duration: 1000, iterations: 2.5 },
|
||||
expected: 2500 },
|
||||
{ desc: "a non-zero duration and non-zero delay",
|
||||
input: { duration: 1000, delay: 1500 },
|
||||
expected: 2500 },
|
||||
{ desc: "a non-zero duration, non-zero delay and non-default iteration",
|
||||
input: { duration: 1000, delay: 1500, iterations: 2 },
|
||||
expected: 3500 },
|
||||
{ desc: "an infinite iteration count",
|
||||
input: { duration: 1000, iterations: Infinity },
|
||||
expected: Infinity },
|
||||
{ desc: "an infinite duration",
|
||||
input: { duration: Infinity, iterations: 10 },
|
||||
expected: Infinity },
|
||||
{ desc: "an infinite duration and delay",
|
||||
input: { duration: Infinity, iterations: 10, delay: 1000 },
|
||||
expected: Infinity },
|
||||
{ desc: "an infinite duration and negative delay",
|
||||
input: { duration: Infinity, iterations: 10, delay: -1000 },
|
||||
expected: Infinity },
|
||||
{ desc: "an non-zero duration and negative delay",
|
||||
input: { duration: 1000, iterations: 2, delay: -1000 },
|
||||
expected: 1000 },
|
||||
{ desc: "an non-zero duration and negative delay greater than active " +
|
||||
"duration",
|
||||
input: { duration: 1000, iterations: 2, delay: -3000 },
|
||||
expected: 0 },
|
||||
{ desc: "a zero duration and negative delay",
|
||||
input: { duration: 0, iterations: 2, delay: -1000 },
|
||||
expected: 0 }
|
||||
];
|
||||
|
||||
gEndTimeTests.forEach(function(stest) {
|
||||
test(function(t) {
|
||||
var effect = new KeyframeEffectReadOnly(target,
|
||||
{ left: ["10px", "20px"] },
|
||||
stest.input);
|
||||
|
||||
assert_equals(effect.getComputedTiming().endTime,
|
||||
stest.expected);
|
||||
|
||||
}, "getComputedTiming().endTime for " + stest.desc);
|
||||
});
|
||||
|
||||
done();
|
||||
</script>
|
||||
</body>
|
||||
|
|
@ -0,0 +1,693 @@
|
|||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<title>KeyframeEffect.iterationComposite tests</title>
|
||||
<link rel="help" href="https://w3c.github.io/web-animations/#effect-accumulation-section">
|
||||
<script src=/resources/testharness.js></script>
|
||||
<script src=/resources/testharnessreport.js></script>
|
||||
<script src="../../testcommon.js"></script>
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
test(function(t) {
|
||||
var div = createDiv(t);
|
||||
var anim =
|
||||
div.animate({ marginLeft: ['0px', '10px'] },
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
easing: 'linear',
|
||||
iterations: 10,
|
||||
iterationComposite: 'accumulate' });
|
||||
anim.pause();
|
||||
|
||||
anim.currentTime = anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).marginLeft, '5px',
|
||||
'Animated margin-left style at 50s of the first iteration');
|
||||
anim.currentTime = anim.effect.timing.duration * 2;
|
||||
assert_equals(getComputedStyle(div).marginLeft, '20px',
|
||||
'Animated margin-left style at 0s of the third iteration');
|
||||
anim.currentTime += anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).marginLeft, '25px',
|
||||
'Animated margin-left style at 50s of the third iteration');
|
||||
}, 'iterationComposite of <length> type animation');
|
||||
|
||||
test(function(t) {
|
||||
var parent = createDiv(t);
|
||||
parent.style.width = '100px';
|
||||
var div = createDiv(t);
|
||||
parent.appendChild(div);
|
||||
|
||||
var anim =
|
||||
div.animate({ width: ['0%', '50%'] },
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
easing: 'linear',
|
||||
iterations: 10,
|
||||
iterationComposite: 'accumulate' });
|
||||
anim.pause();
|
||||
|
||||
anim.currentTime = anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).width, '25px',
|
||||
'Animated width style at 50s of the first iteration');
|
||||
anim.currentTime = anim.effect.timing.duration * 2;
|
||||
assert_equals(getComputedStyle(div).width, '100px',
|
||||
'Animated width style at 0s of the third iteration');
|
||||
anim.currentTime += anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).width, '125px',
|
||||
'Animated width style at 50s of the third iteration');
|
||||
}, 'iterationComposite of <percentage> type animation');
|
||||
|
||||
test(function(t) {
|
||||
var div = createDiv(t);
|
||||
var anim =
|
||||
div.animate({ color: ['rgb(0, 0, 0)', 'rgb(120, 120, 120)'] },
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
easing: 'linear',
|
||||
iterations: 10,
|
||||
iterationComposite: 'accumulate' });
|
||||
anim.pause();
|
||||
|
||||
anim.currentTime = anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).color, 'rgb(60, 60, 60)',
|
||||
'Animated color style at 50s of the first iteration');
|
||||
anim.currentTime = anim.effect.timing.duration * 2;
|
||||
assert_equals(getComputedStyle(div).color, 'rgb(240, 240, 240)',
|
||||
'Animated color style at 0s of the third iteration');
|
||||
anim.currentTime += anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).color, 'rgb(255, 255, 255)',
|
||||
'Animated color style at 50s of the third iteration');
|
||||
}, 'iterationComposite of <color> type animation');
|
||||
|
||||
test(function(t) {
|
||||
var div = createDiv(t);
|
||||
var anim =
|
||||
div.animate({ color: ['rgb(0, 120, 0)', 'rgb(60, 60, 60)'] },
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
easing: 'linear',
|
||||
iterations: 10,
|
||||
iterationComposite: 'accumulate' });
|
||||
anim.pause();
|
||||
|
||||
anim.currentTime = anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).color, 'rgb(30, 90, 30)',
|
||||
'Animated color style at 50s of the first iteration');
|
||||
anim.currentTime = anim.effect.timing.duration * 2;
|
||||
assert_equals(getComputedStyle(div).color, 'rgb(120, 240, 120)',
|
||||
'Animated color style at 0s of the third iteration');
|
||||
anim.currentTime += anim.effect.timing.duration / 2;
|
||||
// The green color is (240 + 180) / 2 = 210
|
||||
assert_equals(getComputedStyle(div).color, 'rgb(150, 210, 150)',
|
||||
'Animated color style at 50s of the third iteration');
|
||||
}, 'iterationComposite of <color> type animation that green component is ' +
|
||||
'decreasing');
|
||||
|
||||
test(function(t) {
|
||||
var div = createDiv(t);
|
||||
var anim =
|
||||
div.animate({ flexGrow: [0, 10] },
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
easing: 'linear',
|
||||
iterations: 10,
|
||||
iterationComposite: 'accumulate' });
|
||||
anim.pause();
|
||||
|
||||
anim.currentTime = anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).flexGrow, '5',
|
||||
'Animated flex-grow style at 50s of the first iteration');
|
||||
anim.currentTime = anim.effect.timing.duration * 2;
|
||||
assert_equals(getComputedStyle(div).flexGrow, '20',
|
||||
'Animated flex-grow style at 0s of the third iteration');
|
||||
anim.currentTime += anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).flexGrow, '25',
|
||||
'Animated flex-grow style at 50s of the third iteration');
|
||||
}, 'iterationComposite of <number> type animation');
|
||||
|
||||
test(function(t) {
|
||||
var div = createDiv(t);
|
||||
div.style.position = 'absolute';
|
||||
var anim =
|
||||
div.animate({ clip: ['rect(0px, 0px, 0px, 0px)',
|
||||
'rect(10px, 10px, 10px, 10px)'] },
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
easing: 'linear',
|
||||
iterations: 10,
|
||||
iterationComposite: 'accumulate' });
|
||||
anim.pause();
|
||||
|
||||
anim.currentTime = anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).clip, 'rect(5px, 5px, 5px, 5px)',
|
||||
'Animated clip style at 50s of the first iteration');
|
||||
anim.currentTime = anim.effect.timing.duration * 2;
|
||||
assert_equals(getComputedStyle(div).clip, 'rect(20px, 20px, 20px, 20px)',
|
||||
'Animated clip style at 0s of the third iteration');
|
||||
anim.currentTime += anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).clip, 'rect(25px, 25px, 25px, 25px)',
|
||||
'Animated clip style at 50s of the third iteration');
|
||||
}, 'iterationComposite of <shape> type animation');
|
||||
|
||||
test(function(t) {
|
||||
var div = createDiv(t);
|
||||
var anim =
|
||||
div.animate({ width: ['calc(0vw + 0px)', 'calc(0vw + 10px)'] },
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
easing: 'linear',
|
||||
iterations: 10,
|
||||
iterationComposite: 'accumulate' });
|
||||
anim.pause();
|
||||
|
||||
anim.currentTime = anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).width, '5px',
|
||||
'Animated calc width style at 50s of the first iteration');
|
||||
anim.currentTime = anim.effect.timing.duration * 2;
|
||||
assert_equals(getComputedStyle(div).width, '20px',
|
||||
'Animated calc width style at 0s of the third iteration');
|
||||
anim.currentTime += anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).width, '25px',
|
||||
'Animated calc width style at 50s of the third iteration');
|
||||
}, 'iterationComposite of <calc()> value animation');
|
||||
|
||||
test(function(t) {
|
||||
var parent = createDiv(t);
|
||||
parent.style.width = '100px';
|
||||
var div = createDiv(t);
|
||||
parent.appendChild(div);
|
||||
|
||||
var anim =
|
||||
div.animate({ width: ['calc(0% + 0px)', 'calc(10% + 10px)'] },
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
easing: 'linear',
|
||||
iterations: 10,
|
||||
iterationComposite: 'accumulate' });
|
||||
anim.pause();
|
||||
|
||||
anim.currentTime = anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).width, '10px',
|
||||
// 100px * 5% + 5px
|
||||
'Animated calc width style at 50s of the first iteration');
|
||||
anim.currentTime = anim.effect.timing.duration * 2;
|
||||
assert_equals(getComputedStyle(div).width,
|
||||
'40px', // 100px * (10% + 10%) + (10px + 10px)
|
||||
'Animated calc width style at 0s of the third iteration');
|
||||
anim.currentTime += anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).width,
|
||||
'50px', // (40px + 60px) / 2
|
||||
'Animated calc width style at 50s of the third iteration');
|
||||
}, 'iterationComposite of <calc()> value animation that the values can\'t' +
|
||||
'be reduced');
|
||||
|
||||
test(function(t) {
|
||||
var div = createDiv(t);
|
||||
var anim =
|
||||
div.animate({ opacity: [0, 0.4] },
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
easing: 'linear',
|
||||
iterations: 10,
|
||||
iterationComposite: 'accumulate' });
|
||||
anim.pause();
|
||||
|
||||
anim.currentTime = anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).opacity, '0.2',
|
||||
'Animated opacity style at 50s of the first iteration');
|
||||
anim.currentTime = anim.effect.timing.duration * 2;
|
||||
assert_equals(getComputedStyle(div).opacity, '0.8',
|
||||
'Animated opacity style at 0s of the third iteration');
|
||||
anim.currentTime += anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).opacity, '1', // (0.8 + 1.2) * 0.5
|
||||
'Animated opacity style at 50s of the third iteration');
|
||||
}, 'iterationComposite of opacity animation');
|
||||
|
||||
test(function(t) {
|
||||
var div = createDiv(t);
|
||||
var anim =
|
||||
div.animate({ boxShadow: ['rgb(0, 0, 0) 0px 0px 0px 0px',
|
||||
'rgb(120, 120, 120) 10px 10px 10px 0px'] },
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
easing: 'linear',
|
||||
iterations: 10,
|
||||
iterationComposite: 'accumulate' });
|
||||
anim.pause();
|
||||
|
||||
anim.currentTime = anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).boxShadow,
|
||||
'rgb(60, 60, 60) 5px 5px 5px 0px',
|
||||
'Animated box-shadow style at 50s of the first iteration');
|
||||
anim.currentTime = anim.effect.timing.duration * 2;
|
||||
assert_equals(getComputedStyle(div).boxShadow,
|
||||
'rgb(240, 240, 240) 20px 20px 20px 0px',
|
||||
'Animated box-shadow style at 0s of the third iteration');
|
||||
anim.currentTime += anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).boxShadow,
|
||||
'rgb(255, 255, 255) 25px 25px 25px 0px',
|
||||
'Animated box-shadow style at 50s of the third iteration');
|
||||
}, 'iterationComposite of box-shadow animation');
|
||||
|
||||
test(function(t) {
|
||||
var div = createDiv(t);
|
||||
var anim =
|
||||
div.animate({ filter: ['blur(0px)', 'blur(10px)'] },
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
easing: 'linear',
|
||||
iterations: 10,
|
||||
iterationComposite: 'accumulate' });
|
||||
anim.pause();
|
||||
|
||||
anim.currentTime = anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).filter, 'blur(5px)',
|
||||
'Animated filter blur style at 50s of the first iteration');
|
||||
anim.currentTime = anim.effect.timing.duration * 2;
|
||||
assert_equals(getComputedStyle(div).filter, 'blur(20px)',
|
||||
'Animated filter blur style at 0s of the third iteration');
|
||||
anim.currentTime += anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).filter, 'blur(25px)',
|
||||
'Animated filter blur style at 50s of the third iteration');
|
||||
}, 'iterationComposite of filter blur animation');
|
||||
|
||||
test(function(t) {
|
||||
var div = createDiv(t);
|
||||
var anim =
|
||||
div.animate({ filter: ['brightness(1)',
|
||||
'brightness(180%)'] },
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
easing: 'linear',
|
||||
iterations: 10,
|
||||
iterationComposite: 'accumulate' });
|
||||
anim.pause();
|
||||
|
||||
anim.currentTime = anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).filter,
|
||||
'brightness(1.4)',
|
||||
'Animated filter brightness style at 50s of the first iteration');
|
||||
anim.currentTime = anim.effect.timing.duration * 2;
|
||||
assert_equals(getComputedStyle(div).filter,
|
||||
'brightness(2.6)', // brightness(1) + brightness(0.8) + brightness(0.8)
|
||||
'Animated filter brightness style at 0s of the third iteration');
|
||||
anim.currentTime += anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).filter,
|
||||
'brightness(3)', // (brightness(2.6) + brightness(3.4)) * 0.5
|
||||
'Animated filter brightness style at 50s of the third iteration');
|
||||
}, 'iterationComposite of filter brightness for different unit animation');
|
||||
|
||||
test(function(t) {
|
||||
var div = createDiv(t);
|
||||
var anim =
|
||||
div.animate({ filter: ['brightness(0)',
|
||||
'brightness(1)'] },
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
easing: 'linear',
|
||||
iterations: 10,
|
||||
iterationComposite: 'accumulate' });
|
||||
anim.pause();
|
||||
|
||||
anim.currentTime = anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).filter,
|
||||
'brightness(0.5)',
|
||||
'Animated filter brightness style at 50s of the first iteration');
|
||||
anim.currentTime = anim.effect.timing.duration * 2;
|
||||
assert_equals(getComputedStyle(div).filter,
|
||||
'brightness(0)', // brightness(1) is an identity element, not accumulated.
|
||||
'Animated filter brightness style at 0s of the third iteration');
|
||||
anim.currentTime += anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).filter,
|
||||
'brightness(0.5)', // brightness(1) is an identity element, not accumulated.
|
||||
'Animated filter brightness style at 50s of the third iteration');
|
||||
}, 'iterationComposite of filter brightness animation');
|
||||
|
||||
test(function(t) {
|
||||
var div = createDiv(t);
|
||||
var anim =
|
||||
div.animate({ filter: ['drop-shadow(rgb(0, 0, 0) 0px 0px 0px)',
|
||||
'drop-shadow(rgb(120, 120, 120) 10px 10px 10px)'] },
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
easing: 'linear',
|
||||
iterations: 10,
|
||||
iterationComposite: 'accumulate' });
|
||||
anim.pause();
|
||||
|
||||
anim.currentTime = anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).filter,
|
||||
'drop-shadow(rgb(60, 60, 60) 5px 5px 5px)',
|
||||
'Animated filter drop-shadow style at 50s of the first iteration');
|
||||
anim.currentTime = anim.effect.timing.duration * 2;
|
||||
assert_equals(getComputedStyle(div).filter,
|
||||
'drop-shadow(rgb(240, 240, 240) 20px 20px 20px)',
|
||||
'Animated filter drop-shadow style at 0s of the third iteration');
|
||||
anim.currentTime += anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).filter,
|
||||
'drop-shadow(rgb(255, 255, 255) 25px 25px 25px)',
|
||||
'Animated filter drop-shadow style at 50s of the third iteration');
|
||||
}, 'iterationComposite of filter drop-shadow animation');
|
||||
|
||||
test(function(t) {
|
||||
var div = createDiv(t);
|
||||
var anim =
|
||||
div.animate({ filter: ['brightness(1) contrast(1)',
|
||||
'brightness(2) contrast(2)'] },
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
easing: 'linear',
|
||||
iterations: 10,
|
||||
iterationComposite: 'accumulate' });
|
||||
anim.pause();
|
||||
|
||||
anim.currentTime = anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).filter,
|
||||
'brightness(1.5) contrast(1.5)',
|
||||
'Animated filter list at 50s of the first iteration');
|
||||
anim.currentTime = anim.effect.timing.duration * 2;
|
||||
assert_equals(getComputedStyle(div).filter,
|
||||
'brightness(3) contrast(3)',
|
||||
'Animated filter list at 0s of the third iteration');
|
||||
anim.currentTime += anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).filter,
|
||||
'brightness(3.5) contrast(3.5)',
|
||||
'Animated filter list at 50s of the third iteration');
|
||||
}, 'iterationComposite of same filter list animation');
|
||||
|
||||
test(function(t) {
|
||||
var div = createDiv(t);
|
||||
var anim =
|
||||
div.animate({ filter: ['brightness(1) contrast(1)',
|
||||
'contrast(2) brightness(2)'] },
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
easing: 'linear',
|
||||
iterations: 10,
|
||||
iterationComposite: 'accumulate' });
|
||||
anim.pause();
|
||||
|
||||
anim.currentTime = anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).filter,
|
||||
'contrast(2) brightness(2)', // discrete
|
||||
'Animated filter list at 50s of the first iteration');
|
||||
anim.currentTime = anim.effect.timing.duration * 2;
|
||||
assert_equals(getComputedStyle(div).filter,
|
||||
// We can't accumulate 'contrast(2) brightness(2)' onto
|
||||
// the first list 'brightness(1) contrast(1)' because of
|
||||
// mismatch of the order.
|
||||
'brightness(1) contrast(1)',
|
||||
'Animated filter list at 0s of the third iteration');
|
||||
anim.currentTime += anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).filter,
|
||||
// We *can* accumulate 'contrast(2) brightness(2)' onto
|
||||
// the same list 'contrast(2) brightness(2)' here.
|
||||
'contrast(4) brightness(4)', // discrete
|
||||
'Animated filter list at 50s of the third iteration');
|
||||
}, 'iterationComposite of discrete filter list because of mismatch ' +
|
||||
'of the order');
|
||||
|
||||
test(function(t) {
|
||||
var div = createDiv(t);
|
||||
var anim =
|
||||
div.animate({ filter: ['sepia(0)',
|
||||
'sepia(1) contrast(2)'] },
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
easing: 'linear',
|
||||
iterations: 10,
|
||||
iterationComposite: 'accumulate' });
|
||||
anim.pause();
|
||||
|
||||
anim.currentTime = anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).filter,
|
||||
'sepia(0.5) contrast(1.5)',
|
||||
'Animated filter list at 50s of the first iteration');
|
||||
anim.currentTime = anim.effect.timing.duration * 2;
|
||||
assert_equals(getComputedStyle(div).filter,
|
||||
'sepia(2) contrast(3)',
|
||||
'Animated filter list at 0s of the third iteration');
|
||||
anim.currentTime += anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).filter,
|
||||
'sepia(2.5) contrast(3.5)',
|
||||
'Animated filter list at 50s of the third iteration');
|
||||
}, 'iterationComposite of different length filter list animation');
|
||||
|
||||
test(function(t) {
|
||||
var div = createDiv(t);
|
||||
var anim =
|
||||
div.animate({ transform: ['rotate(0deg)', 'rotate(180deg)'] },
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
easing: 'linear',
|
||||
iterations: 10,
|
||||
iterationComposite: 'accumulate' });
|
||||
anim.pause();
|
||||
|
||||
anim.currentTime = anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).transform,
|
||||
'matrix(0, 1, -1, 0, 0, 0)', // rotate(90deg)
|
||||
'Animated transform(rotate) style at 50s of the first iteration');
|
||||
anim.currentTime = anim.effect.timing.duration * 2;
|
||||
assert_equals(getComputedStyle(div).transform,
|
||||
'matrix(1, 0, 0, 1, 0, 0)', // rotate(360deg)
|
||||
'Animated transform(rotate) style at 0s of the third iteration');
|
||||
anim.currentTime += anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).transform,
|
||||
'matrix(0, 1, -1, 0, 0, 0)', // rotate(450deg)
|
||||
'Animated transform(rotate) style at 50s of the third iteration');
|
||||
}, 'iterationComposite of transform(rotate) animation');
|
||||
|
||||
test(function(t) {
|
||||
var div = createDiv(t);
|
||||
var anim =
|
||||
div.animate({ transform: ['scale(0)', 'scale(1)'] },
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
easing: 'linear',
|
||||
iterations: 10,
|
||||
iterationComposite: 'accumulate' });
|
||||
anim.pause();
|
||||
|
||||
anim.currentTime = anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).transform,
|
||||
'matrix(0.5, 0, 0, 0.5, 0, 0)', // scale(0.5)
|
||||
'Animated transform(scale) style at 50s of the first iteration');
|
||||
anim.currentTime = anim.effect.timing.duration * 2;
|
||||
assert_equals(getComputedStyle(div).transform,
|
||||
'matrix(0, 0, 0, 0, 0, 0)', // scale(0); scale(1) is an identity element,
|
||||
// not accumulated.
|
||||
'Animated transform(scale) style at 0s of the third iteration');
|
||||
anim.currentTime += anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).transform,
|
||||
'matrix(0.5, 0, 0, 0.5, 0, 0)', // scale(0.5); scale(1) an identity
|
||||
// element, not accumulated.
|
||||
'Animated transform(scale) style at 50s of the third iteration');
|
||||
}, 'iterationComposite of transform: [ scale(0), scale(1) ] animation');
|
||||
|
||||
test(function(t) {
|
||||
var div = createDiv(t);
|
||||
var anim =
|
||||
div.animate({ transform: ['scale(1)', 'scale(2)'] },
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
easing: 'linear',
|
||||
iterations: 10,
|
||||
iterationComposite: 'accumulate' });
|
||||
anim.pause();
|
||||
|
||||
anim.currentTime = anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).transform,
|
||||
'matrix(1.5, 0, 0, 1.5, 0, 0)', // scale(1.5)
|
||||
'Animated transform(scale) style at 50s of the first iteration');
|
||||
anim.currentTime = anim.effect.timing.duration * 2;
|
||||
assert_equals(getComputedStyle(div).transform,
|
||||
'matrix(3, 0, 0, 3, 0, 0)', // scale(1 + (2 -1) + (2 -1))
|
||||
'Animated transform(scale) style at 0s of the third iteration');
|
||||
anim.currentTime += anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).transform,
|
||||
'matrix(3.5, 0, 0, 3.5, 0, 0)', // (scale(3) + scale(4)) * 0.5
|
||||
'Animated transform(scale) style at 50s of the third iteration');
|
||||
}, 'iterationComposite of transform: [ scale(1), scale(2) ] animation');
|
||||
|
||||
test(function(t) {
|
||||
var div = createDiv(t);
|
||||
var anim =
|
||||
div.animate({ transform: ['scale(0)', 'scale(2)'] },
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
easing: 'linear',
|
||||
iterations: 10,
|
||||
iterationComposite: 'accumulate' });
|
||||
anim.pause();
|
||||
|
||||
anim.currentTime = anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).transform,
|
||||
'matrix(1, 0, 0, 1, 0, 0)', // scale(1)
|
||||
'Animated transform(scale) style at 50s of the first iteration');
|
||||
anim.currentTime = anim.effect.timing.duration * 2;
|
||||
assert_equals(getComputedStyle(div).transform,
|
||||
'matrix(2, 0, 0, 2, 0, 0)', // (scale(0) + scale(2-1)*2)
|
||||
'Animated transform(scale) style at 0s of the third iteration');
|
||||
anim.currentTime += anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).transform,
|
||||
'matrix(3, 0, 0, 3, 0, 0)', // (scale(2) + scale(4)) * 0.5
|
||||
'Animated transform(scale) style at 50s of the third iteration');
|
||||
}, 'iterationComposite of transform: scale(2) animation');
|
||||
|
||||
test(function(t) {
|
||||
var div = createDiv(t);
|
||||
var anim =
|
||||
div.animate({ transform: ['rotate(0deg) translateX(0px)',
|
||||
'rotate(180deg) translateX(10px)'] },
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
easing: 'linear',
|
||||
iterations: 10,
|
||||
iterationComposite: 'accumulate' });
|
||||
anim.pause();
|
||||
|
||||
anim.currentTime = anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).transform,
|
||||
'matrix(0, 1, -1, 0, 0, 5)', // rotate(90deg) translateX(5px)
|
||||
'Animated transform list at 50s of the first iteration');
|
||||
anim.currentTime = anim.effect.timing.duration * 2;
|
||||
assert_equals(getComputedStyle(div).transform,
|
||||
'matrix(1, 0, 0, 1, 20, 0)', // rotate(360deg) translateX(20px)
|
||||
'Animated transform list at 0s of the third iteration');
|
||||
anim.currentTime += anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).transform,
|
||||
'matrix(0, 1, -1, 0, 0, 25)', // rotate(450deg) translateX(25px)
|
||||
'Animated transform list at 50s of the third iteration');
|
||||
}, 'iterationComposite of transform list animation');
|
||||
|
||||
test(function(t) {
|
||||
var div = createDiv(t);
|
||||
// The transform list whose order is mismatched is compounded,
|
||||
// so below animation is the same as;
|
||||
// from matrix(2, 0, 0, 2, 0, 0) to matrix(3, 0, 0, 3, 30, 0)
|
||||
var anim =
|
||||
div.animate({ transform: ['translateX(0px) scale(2)',
|
||||
'scale(3) translateX(10px)'] },
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
easing: 'linear',
|
||||
iterations: 10,
|
||||
iterationComposite: 'accumulate' });
|
||||
anim.pause();
|
||||
|
||||
anim.currentTime = anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).transform,
|
||||
'matrix(2.5, 0, 0, 2.5, 15, 0)', // scale(2.5) (0px + 30px*2) / 2
|
||||
'Animated transform list at 50s of the first iteration');
|
||||
anim.currentTime = anim.effect.timing.duration * 2;
|
||||
assert_equals(getComputedStyle(div).transform,
|
||||
'matrix(4, 0, 0, 4, 60, 0)', // scale(2+(3-2)*2) (0px + 30px*2)
|
||||
'Animated transform list at 0s of the third iteration');
|
||||
anim.currentTime += anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).transform,
|
||||
'matrix(5.5, 0, 0, 5.5, 135, 0)', // scale(4+7)/2 (60px + 210px)
|
||||
'Animated transform list at 50s of the third iteration');
|
||||
}, 'iterationComposite of transform list animation whose order is mismatched');
|
||||
|
||||
test(function(t) {
|
||||
var div = createDiv(t);
|
||||
// Even if each transform list does not have functions which exist in
|
||||
// other pair of the list, we don't fill any missing functions at all,
|
||||
// it's just computed as compounded matrices
|
||||
// Below animation is the same as;
|
||||
// from matrix(1, 0, 0, 1, 0, 0) to matrix(2, 0, 0, 2, 20, 0)
|
||||
var anim =
|
||||
div.animate({ transform: ['translateX(0px)',
|
||||
'scale(2) translateX(10px)'] },
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
easing: 'linear',
|
||||
iterations: 10,
|
||||
iterationComposite: 'accumulate' });
|
||||
anim.pause();
|
||||
|
||||
anim.currentTime = anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).transform,
|
||||
'matrix(1.5, 0, 0, 1.5, 10, 0)', // scale(1.5) (0px + 10px*2) / 2
|
||||
'Animated transform list at 50s of the first iteration');
|
||||
anim.currentTime = anim.effect.timing.duration * 2;
|
||||
assert_equals(getComputedStyle(div).transform,
|
||||
'matrix(3, 0, 0, 3, 40, 0)', // scale(1+(2-1)*2) (0px + 20px*2)
|
||||
'Animated transform list at 0s of the third iteration');
|
||||
anim.currentTime += anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).transform,
|
||||
'matrix(3.5, 0, 0, 3.5, 80, 0)', // scale(3+4)/2 (40px + 20px)
|
||||
'Animated transform list at 50s of the third iteration');
|
||||
}, 'iterationComposite of transform list animation whose order is mismatched');
|
||||
|
||||
test(function(t) {
|
||||
var div = createDiv(t);
|
||||
var anim =
|
||||
div.animate({ marginLeft: ['10px', '20px'] },
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
easing: 'linear',
|
||||
iterations: 10,
|
||||
iterationComposite: 'accumulate' });
|
||||
anim.pause();
|
||||
|
||||
anim.currentTime = anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).marginLeft, '15px',
|
||||
'Animated margin-left style at 50s of the first iteration');
|
||||
anim.currentTime = anim.effect.timing.duration * 2;
|
||||
assert_equals(getComputedStyle(div).marginLeft, '50px', // 10px + 20px + 20px
|
||||
'Animated margin-left style at 0s of the third iteration');
|
||||
anim.currentTime += anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).marginLeft, '55px', // (50px + 60px) * 0.5
|
||||
'Animated margin-left style at 50s of the third iteration');
|
||||
}, 'iterationComposite starts with non-zero value animation');
|
||||
|
||||
test(function(t) {
|
||||
var div = createDiv(t);
|
||||
var anim =
|
||||
div.animate({ marginLeft: ['10px', '-10px'] },
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
easing: 'linear',
|
||||
iterations: 10,
|
||||
iterationComposite: 'accumulate' });
|
||||
anim.pause();
|
||||
|
||||
anim.currentTime = anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).marginLeft,
|
||||
'0px',
|
||||
'Animated margin-left style at 50s of the first iteration');
|
||||
anim.currentTime = anim.effect.timing.duration * 2;
|
||||
assert_equals(getComputedStyle(div).marginLeft,
|
||||
'-10px', // 10px + -10px + -10px
|
||||
'Animated margin-left style at 0s of the third iteration');
|
||||
anim.currentTime += anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).marginLeft,
|
||||
'-20px', // (-10px + -30px) * 0.5
|
||||
'Animated margin-left style at 50s of the third iteration');
|
||||
}, 'iterationComposite with negative final value animation');
|
||||
|
||||
test(function(t) {
|
||||
var div = createDiv(t);
|
||||
var anim = div.animate({ marginLeft: ['0px', '10px'] },
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
easing: 'linear',
|
||||
iterations: 10,
|
||||
iterationComposite: 'accumulate' });
|
||||
anim.pause();
|
||||
|
||||
anim.currentTime =
|
||||
anim.effect.timing.duration * 2 + anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).marginLeft, '25px',
|
||||
'Animated style at 50s of the third iteration');
|
||||
|
||||
anim.effect.iterationComposite = 'replace';
|
||||
assert_equals(getComputedStyle(div).marginLeft, '5px',
|
||||
'Animated style at 50s of the third iteration');
|
||||
|
||||
anim.effect.iterationComposite = 'accumulate';
|
||||
assert_equals(getComputedStyle(div).marginLeft, '25px',
|
||||
'Animated style at 50s of the third iteration');
|
||||
}, 'interationComposite changes');
|
||||
|
||||
test(function(t) {
|
||||
var div = createDiv(t);
|
||||
var anim = div.animate({ marginLeft: ['0px', '10px'] },
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
easing: 'linear',
|
||||
iterations: 10,
|
||||
iterationComposite: 'accumulate' });
|
||||
anim.pause();
|
||||
|
||||
anim.currentTime =
|
||||
anim.effect.timing.duration * 2 + anim.effect.timing.duration / 2;
|
||||
assert_equals(getComputedStyle(div).marginLeft, '25px',
|
||||
'Animated style at 50s of the third iteration');
|
||||
|
||||
// double its duration.
|
||||
anim.effect.timing.duration = anim.effect.timing.duration * 2;
|
||||
assert_equals(getComputedStyle(div).marginLeft, '12.5px',
|
||||
'Animated style at 25s of the first iteration');
|
||||
|
||||
// half of original.
|
||||
anim.effect.timing.duration = anim.effect.timing.duration / 4;
|
||||
assert_equals(getComputedStyle(div).marginLeft, '50px',
|
||||
'Animated style at 50s of the fourth iteration');
|
||||
}, 'duration changes with iterationComposite(accumulate)');
|
||||
|
||||
</script>
|
||||
|
|
@ -0,0 +1,329 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<title>KeyframeEffectReadOnly constructor tests</title>
|
||||
<link rel="help" href="https://w3c.github.io/web-animations/#processing-a-keyframes-argument">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../../testcommon.js"></script>
|
||||
<script src="../../resources/keyframe-utils.js"></script>
|
||||
<body>
|
||||
<div id="log"></div>
|
||||
<div id="target"></div>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
// Test the "process a keyframe-like object" procedure.
|
||||
//
|
||||
// This file only tests the KeyframeEffectReadOnly constructor since it is
|
||||
// assumed that the implementation of the KeyframeEffect constructor,
|
||||
// Animatable.animate() method, and KeyframeEffect.setKeyframes() method will
|
||||
// all share common machinery and it is not necessary to test each method.
|
||||
|
||||
// Test that only animatable properties are accessed
|
||||
|
||||
var gNonAnimatableProps = [
|
||||
'animation', // Shorthands where all the longhand sub-properties are not
|
||||
// animatable, are also not animatable.
|
||||
'animationDelay',
|
||||
'animationDirection',
|
||||
'animationDuration',
|
||||
'animationFillMode',
|
||||
'animationIterationCount',
|
||||
'animationName',
|
||||
'animationPlayState',
|
||||
'animationTimingFunction',
|
||||
'transition',
|
||||
'transitionDelay',
|
||||
'transitionDuration',
|
||||
'transitionProperty',
|
||||
'transitionTimingFunction',
|
||||
'display',
|
||||
'unsupportedProperty',
|
||||
];
|
||||
|
||||
function TestKeyframe(testProp) {
|
||||
var _propAccessCount = 0;
|
||||
|
||||
Object.defineProperty(this, testProp, {
|
||||
get: function() { _propAccessCount++; },
|
||||
enumerable: true
|
||||
});
|
||||
|
||||
Object.defineProperty(this, 'propAccessCount', {
|
||||
get: function() { return _propAccessCount; }
|
||||
});
|
||||
}
|
||||
|
||||
function GetTestKeyframeSequence(testProp) {
|
||||
return [ new TestKeyframe(testProp) ]
|
||||
}
|
||||
|
||||
gNonAnimatableProps.forEach(function(prop) {
|
||||
test(function(t) {
|
||||
var testKeyframe = new TestKeyframe(prop);
|
||||
|
||||
new KeyframeEffectReadOnly(null, testKeyframe);
|
||||
|
||||
assert_equals(testKeyframe.propAccessCount, 0, 'Accessor not called');
|
||||
}, 'non-animatable property \'' + prop + '\' is not accessed when using'
|
||||
+ ' a property-indexed keyframe object');
|
||||
});
|
||||
|
||||
gNonAnimatableProps.forEach(function(prop) {
|
||||
test(function(t) {
|
||||
var testKeyframes = GetTestKeyframeSequence(prop);
|
||||
|
||||
new KeyframeEffectReadOnly(null, testKeyframes);
|
||||
|
||||
assert_equals(testKeyframes[0].propAccessCount, 0, 'Accessor not called');
|
||||
}, 'non-animatable property \'' + prop + '\' is not accessed when using'
|
||||
+ ' a keyframe sequence');
|
||||
});
|
||||
|
||||
// Test equivalent forms of property indexed and sequenced keyframe syntax
|
||||
|
||||
function assertEquivalentKeyframeSyntax(keyframesA, keyframesB) {
|
||||
var processedKeyframesA = new KeyframeEffectReadOnly(null, keyframesA).getKeyframes();
|
||||
var processedKeyframesB = new KeyframeEffectReadOnly(null, keyframesB).getKeyframes();
|
||||
assert_frame_lists_equal(processedKeyframesA, processedKeyframesB);
|
||||
}
|
||||
|
||||
var gEquivalentSyntaxTests = [
|
||||
{
|
||||
description: 'two properties with one value',
|
||||
indexedKeyframes: {
|
||||
left: '100px',
|
||||
opacity: ['1'],
|
||||
},
|
||||
sequencedKeyframes: [
|
||||
{left: '100px', opacity: '1'},
|
||||
],
|
||||
},
|
||||
{
|
||||
description: 'two properties with three values',
|
||||
indexedKeyframes: {
|
||||
left: ['10px', '100px', '150px'],
|
||||
opacity: ['1', '0', '1'],
|
||||
},
|
||||
sequencedKeyframes: [
|
||||
{left: '10px', opacity: '1'},
|
||||
{left: '100px', opacity: '0'},
|
||||
{left: '150px', opacity: '1'},
|
||||
],
|
||||
},
|
||||
{
|
||||
description: 'two properties with different numbers of values',
|
||||
indexedKeyframes: {
|
||||
left: ['0px', '100px', '200px'],
|
||||
opacity: ['0', '1']
|
||||
},
|
||||
sequencedKeyframes: [
|
||||
{left: '0px', opacity: '0'},
|
||||
{left: '100px'},
|
||||
{left: '200px', opacity: '1'},
|
||||
],
|
||||
},
|
||||
{
|
||||
description: 'same offset applied to all keyframes',
|
||||
indexedKeyframes: {
|
||||
left: ['0px', '100px'],
|
||||
offset: 0.5,
|
||||
},
|
||||
sequencedKeyframes: [
|
||||
{left: '0px', offset: 0.5},
|
||||
{left: '100px', offset: 0.5},
|
||||
],
|
||||
},
|
||||
{
|
||||
description: 'same easing applied to all keyframes',
|
||||
indexedKeyframes: {
|
||||
left: ['10px', '100px', '150px'],
|
||||
opacity: ['1', '0', '1'],
|
||||
easing: 'ease',
|
||||
},
|
||||
sequencedKeyframes: [
|
||||
{left: '10px', opacity: '1', easing: 'ease'},
|
||||
{left: '100px', opacity: '0', easing: 'ease'},
|
||||
{left: '150px', opacity: '1', easing: 'ease'},
|
||||
],
|
||||
},
|
||||
{
|
||||
description: 'same composite applied to all keyframes',
|
||||
indexedKeyframes: {
|
||||
left: ['0px', '100px'],
|
||||
composite: 'add',
|
||||
},
|
||||
sequencedKeyframes: [
|
||||
{left: '0px', composite: 'add'},
|
||||
{left: '100px', composite: 'add'},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
gEquivalentSyntaxTests.forEach(function({description, indexedKeyframes, sequencedKeyframes}) {
|
||||
test(function(t) {
|
||||
assertEquivalentKeyframeSyntax(indexedKeyframes, sequencedKeyframes);
|
||||
}, 'Equivalent property indexed and sequenced keyframes: ' + description);
|
||||
});
|
||||
|
||||
// Test handling of custom iterable objects.
|
||||
|
||||
function createIterable(iterations) {
|
||||
return {
|
||||
[Symbol.iterator]() {
|
||||
var i = 0;
|
||||
return {
|
||||
next() {
|
||||
return iterations[i++];
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
test(() => {
|
||||
var effect = new KeyframeEffect(null, createIterable([
|
||||
{done: false, value: {left: '100px'}},
|
||||
{done: false, value: {left: '300px'}},
|
||||
{done: false, value: {left: '200px'}},
|
||||
{done: true},
|
||||
]));
|
||||
assert_frame_lists_equal(effect.getKeyframes(), [
|
||||
{offset: null, computedOffset: 0, easing: 'linear', left: '100px'},
|
||||
{offset: null, computedOffset: 0.5, easing: 'linear', left: '300px'},
|
||||
{offset: null, computedOffset: 1, easing: 'linear', left: '200px'},
|
||||
]);
|
||||
}, 'Custom iterator with basic keyframes.');
|
||||
|
||||
test(() => {
|
||||
var keyframes = createIterable([
|
||||
{done: false, value: {left: '100px'}},
|
||||
{done: false, value: {left: '300px'}},
|
||||
{done: false, value: {left: '200px'}},
|
||||
{done: true},
|
||||
]);
|
||||
keyframes.easing = 'ease-in-out';
|
||||
keyframes.offset = '0.1';
|
||||
var effect = new KeyframeEffect(null, keyframes);
|
||||
assert_frame_lists_equal(effect.getKeyframes(), [
|
||||
{offset: null, computedOffset: 0, easing: 'linear', left: '100px'},
|
||||
{offset: null, computedOffset: 0.5, easing: 'linear', left: '300px'},
|
||||
{offset: null, computedOffset: 1, easing: 'linear', left: '200px'},
|
||||
]);
|
||||
}, 'easing and offset are ignored on iterable objects.');
|
||||
|
||||
test(() => {
|
||||
var effect = new KeyframeEffect(null, createIterable([
|
||||
{done: false, value: {left: '100px', top: '200px'}},
|
||||
{done: false, value: {left: '300px'}},
|
||||
{done: false, value: {left: '200px', top: '100px'}},
|
||||
{done: true},
|
||||
]));
|
||||
assert_frame_lists_equal(effect.getKeyframes(), [
|
||||
{offset: null, computedOffset: 0, easing: 'linear', left: '100px', top: '200px'},
|
||||
{offset: null, computedOffset: 0.5, easing: 'linear', left: '300px'},
|
||||
{offset: null, computedOffset: 1, easing: 'linear', left: '200px', top: '100px'},
|
||||
]);
|
||||
}, 'Custom iterator with multiple properties specified.');
|
||||
|
||||
test(() => {
|
||||
var effect = new KeyframeEffect(null, createIterable([
|
||||
{done: false, value: {left: '100px'}},
|
||||
{done: false, value: {left: '250px', offset: 0.75}},
|
||||
{done: false, value: {left: '200px'}},
|
||||
{done: true},
|
||||
]));
|
||||
assert_frame_lists_equal(effect.getKeyframes(), [
|
||||
{offset: null, computedOffset: 0, easing: 'linear', left: '100px'},
|
||||
{offset: 0.75, computedOffset: 0.75, easing: 'linear', left: '250px'},
|
||||
{offset: null, computedOffset: 1, easing: 'linear', left: '200px'},
|
||||
]);
|
||||
}, 'Custom iterator with offset specified.');
|
||||
|
||||
test(() => {
|
||||
assert_throws({name: 'TypeError'}, function() {
|
||||
new KeyframeEffect(null, createIterable([
|
||||
{done: false, value: {left: '100px'}},
|
||||
{done: false, value: 1234},
|
||||
{done: false, value: {left: '200px'}},
|
||||
{done: true},
|
||||
]));
|
||||
});
|
||||
}, 'Custom iterator with non object keyframe should throw.');
|
||||
|
||||
test(() => {
|
||||
var effect = new KeyframeEffect(null, createIterable([
|
||||
{done: false, value: {left: ['100px', '200px']}},
|
||||
{done: true},
|
||||
]));
|
||||
assert_frame_lists_equal(effect.getKeyframes(), [
|
||||
{offset: null, computedOffset: 1, easing: 'linear', left: '100px,200px'}
|
||||
]);
|
||||
}, 'Custom iterator with value list in keyframe should give bizarre string representation of list.');
|
||||
|
||||
test(function(t) {
|
||||
var keyframe = {};
|
||||
Object.defineProperty(keyframe, 'width', {value: '200px'});
|
||||
Object.defineProperty(keyframe, 'height', {
|
||||
value: '100px',
|
||||
enumerable: true});
|
||||
assert_equals(keyframe.width, '200px', 'width of keyframe is readable');
|
||||
assert_equals(keyframe.height, '100px', 'height of keyframe is readable');
|
||||
var anim = createDiv(t).animate([keyframe, {height: '200px'}], 1);
|
||||
assert_frame_lists_equal(anim.effect.getKeyframes(), [
|
||||
{offset: null, computedOffset: 0, easing: 'linear', height: '100px'},
|
||||
{offset: null, computedOffset: 1, easing: 'linear', height: '200px'},
|
||||
]);
|
||||
}, 'Only enumerable properties on keyframes are considered');
|
||||
|
||||
test(function(t) {
|
||||
var KeyframeParent = function() { this.width = '100px'; };
|
||||
KeyframeParent.prototype = { height: '100px' };
|
||||
var Keyframe = function() { this.top = '100px'; };
|
||||
Keyframe.prototype = Object.create(KeyframeParent.prototype);
|
||||
Object.defineProperty(Keyframe.prototype, 'left', {
|
||||
value: '100px',
|
||||
enumerable: 'true'});
|
||||
var keyframe = new Keyframe();
|
||||
var anim = createDiv(t).animate([keyframe, {top: '200px'}], 1);
|
||||
assert_frame_lists_equal(anim.effect.getKeyframes(), [
|
||||
{offset: null, computedOffset: 0, easing: 'linear', top: '100px'},
|
||||
{offset: null, computedOffset: 1, easing: 'linear', top: '200px'},
|
||||
]);
|
||||
}, 'Only properties defined directly on keyframes are considered');
|
||||
|
||||
test(function(t) {
|
||||
var keyframes = {};
|
||||
Object.defineProperty(keyframes, 'width', ['100px', '200px']);
|
||||
Object.defineProperty(keyframes, 'height', {
|
||||
value: ['100px', '200px'],
|
||||
enumerable: true});
|
||||
var anim = createDiv(t).animate(keyframes, 1);
|
||||
assert_frame_lists_equal(anim.effect.getKeyframes(), [
|
||||
{offset: null, computedOffset: 0, easing: 'linear', height: '100px'},
|
||||
{offset: null, computedOffset: 1, easing: 'linear', height: '200px'},
|
||||
]);
|
||||
}, 'Only enumerable properties on property indexed keyframes are considered');
|
||||
|
||||
test(function(t) {
|
||||
var KeyframesParent = function() { this.width = '100px'; };
|
||||
KeyframesParent.prototype = { height: '100px' };
|
||||
var Keyframes = function() { this.top = ['100px', '200px']; };
|
||||
Keyframes.prototype = Object.create(KeyframesParent.prototype);
|
||||
Object.defineProperty(Keyframes.prototype, 'left', {
|
||||
value: ['100px', '200px'],
|
||||
enumerable: 'true'});
|
||||
var keyframes = new Keyframes();
|
||||
var anim = createDiv(t).animate(keyframes, 1);
|
||||
assert_frame_lists_equal(anim.effect.getKeyframes(), [
|
||||
{offset: null, computedOffset: 0, easing: 'linear', top: '100px'},
|
||||
{offset: null, computedOffset: 1, easing: 'linear', top: '200px'},
|
||||
]);
|
||||
}, 'Only properties defined directly on property indexed keyframes are considered');
|
||||
|
||||
// FIXME: Test that properties are accessed in ascending order by Unicode
|
||||
// codepoint
|
||||
// (There is an existing test for this in
|
||||
// keyframe-effect/constructor.html that should be moved here.)
|
||||
|
||||
</script>
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<title>KeyframeEffect setKeyframes() tests</title>
|
||||
<link rel="help" href="https://w3c.github.io/web-animations/#dom-keyframeeffect-setkeyframes">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../../testcommon.js"></script>
|
||||
<script src="../../resources/keyframe-utils.js"></script>
|
||||
<body>
|
||||
<div id="log"></div>
|
||||
<div id="target"></div>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
var target = document.getElementById('target');
|
||||
|
||||
test(function(t) {
|
||||
gEmptyKeyframeListTests.forEach(function(frame) {
|
||||
var effect = new KeyframeEffect(target, {});
|
||||
effect.setKeyframes(frame);
|
||||
assert_frame_lists_equal(effect.getKeyframes(), []);
|
||||
});
|
||||
}, 'Keyframes can be replaced with an empty keyframe');
|
||||
|
||||
gPropertyIndexedKeyframesTests.forEach(function(subtest) {
|
||||
test(function(t) {
|
||||
var effect = new KeyframeEffect(target, {});
|
||||
effect.setKeyframes(subtest.input);
|
||||
assert_frame_lists_equal(effect.getKeyframes(), subtest.output);
|
||||
}, 'Keyframes can be replaced with ' + subtest.desc);
|
||||
});
|
||||
|
||||
gKeyframeSequenceTests.forEach(function(subtest) {
|
||||
test(function(t) {
|
||||
var effect = new KeyframeEffect(target, {});
|
||||
effect.setKeyframes(subtest.input);
|
||||
assert_frame_lists_equal(effect.getKeyframes(), subtest.output);
|
||||
}, 'Keyframes can be replaced with ' + subtest.desc);
|
||||
});
|
||||
|
||||
gInvalidKeyframesTests.forEach(function(subtest) {
|
||||
test(function(t) {
|
||||
var effect = new KeyframeEffect(target, {});
|
||||
assert_throws(subtest.expected, function() {
|
||||
effect.setKeyframes(subtest.input);
|
||||
});
|
||||
}, 'KeyframeEffect constructor throws with ' + subtest.desc);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
|
@ -0,0 +1,160 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<title>Writable effect.target tests</title>
|
||||
<link rel="help"
|
||||
href="https://w3c.github.io/web-animations/#dom-keyframeeffect-target">
|
||||
<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";
|
||||
|
||||
var gKeyFrames = { 'marginLeft': ['0px', '100px'] };
|
||||
|
||||
test(function(t) {
|
||||
var div = createDiv(t);
|
||||
var effect = new KeyframeEffect(null, gKeyFrames, 100 * MS_PER_SEC);
|
||||
effect.target = div;
|
||||
|
||||
var anim = new Animation(effect, document.timeline);
|
||||
anim.play();
|
||||
|
||||
anim.currentTime = 50 * MS_PER_SEC;
|
||||
assert_equals(getComputedStyle(div).marginLeft, '50px',
|
||||
'Value at 50% progress');
|
||||
}, 'Test setting target before constructing the associated animation');
|
||||
|
||||
test(function(t) {
|
||||
var div = createDiv(t);
|
||||
div.style.marginLeft = '10px';
|
||||
var effect = new KeyframeEffect(null, gKeyFrames, 100 * MS_PER_SEC);
|
||||
var anim = new Animation(effect, document.timeline);
|
||||
anim.play();
|
||||
|
||||
anim.currentTime = 50 * MS_PER_SEC;
|
||||
assert_equals(getComputedStyle(div).marginLeft, '10px',
|
||||
'Value at 50% progress before setting new target');
|
||||
effect.target = div;
|
||||
assert_equals(getComputedStyle(div).marginLeft, '50px',
|
||||
'Value at 50% progress after setting new target');
|
||||
}, 'Test setting target from null to a valid target');
|
||||
|
||||
test(function(t) {
|
||||
var div = createDiv(t);
|
||||
div.style.marginLeft = '10px';
|
||||
var anim = div.animate(gKeyFrames, 100 * MS_PER_SEC);
|
||||
|
||||
anim.currentTime = 50 * MS_PER_SEC;
|
||||
assert_equals(getComputedStyle(div).marginLeft, '50px',
|
||||
'Value at 50% progress before clearing the target')
|
||||
|
||||
anim.effect.target = null;
|
||||
assert_equals(getComputedStyle(div).marginLeft, '10px',
|
||||
'Value after clearing the target')
|
||||
}, 'Test setting target from a valid target to null');
|
||||
|
||||
test(function(t) {
|
||||
var a = createDiv(t);
|
||||
var b = createDiv(t);
|
||||
a.style.marginLeft = '10px';
|
||||
b.style.marginLeft = '20px';
|
||||
var anim = a.animate(gKeyFrames, 100 * MS_PER_SEC);
|
||||
|
||||
anim.currentTime = 50 * MS_PER_SEC;
|
||||
assert_equals(getComputedStyle(a).marginLeft, '50px',
|
||||
'Value of 1st element (currently targeted) before ' +
|
||||
'changing the effect target');
|
||||
assert_equals(getComputedStyle(b).marginLeft, '20px',
|
||||
'Value of 2nd element (currently not targeted) before ' +
|
||||
'changing the effect target');
|
||||
anim.effect.target = b;
|
||||
assert_equals(getComputedStyle(a).marginLeft, '10px',
|
||||
'Value of 1st element (currently not targeted) after ' +
|
||||
'changing the effect target');
|
||||
assert_equals(getComputedStyle(b).marginLeft, '50px',
|
||||
'Value of 2nd element (currently targeted) after ' +
|
||||
'changing the effect target');
|
||||
|
||||
// This makes sure the animation property is changed correctly on new
|
||||
// targeted element.
|
||||
anim.currentTime = 75 * MS_PER_SEC;
|
||||
assert_equals(getComputedStyle(b).marginLeft, '75px',
|
||||
'Value of 2nd target (currently targeted) after ' +
|
||||
'changing the animation current time.');
|
||||
}, 'Test setting target from a valid target to another target');
|
||||
|
||||
test(function(t) {
|
||||
var anim = createDiv(t).animate([ { marginLeft: '0px' },
|
||||
{ marginLeft: '-20px' },
|
||||
{ marginLeft: '100px' },
|
||||
{ marginLeft: '50px' } ],
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
spacing: 'paced(margin-left)' });
|
||||
|
||||
anim.effect.target = null;
|
||||
|
||||
var frames = anim.effect.getKeyframes();
|
||||
var slots = frames.length - 1;
|
||||
assert_equals(frames[0].computedOffset, 0.0, '1st frame offset');
|
||||
assert_equals(frames[1].computedOffset, 1.0 / slots, '2nd frame offset');
|
||||
assert_equals(frames[2].computedOffset, 2.0 / slots, '3rd frame offset');
|
||||
assert_equals(frames[3].computedOffset, 1.0, 'last frame offset');
|
||||
}, 'Test falling back to distribute spacing mode after setting null target');
|
||||
|
||||
test(function(t) {
|
||||
var effect = new KeyframeEffect(null,
|
||||
[ { marginLeft: '0px' },
|
||||
{ marginLeft: '-20px' },
|
||||
{ marginLeft: '100px' },
|
||||
{ marginLeft: '50px' } ],
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
spacing: 'paced(margin-left)' });
|
||||
var frames = effect.getKeyframes();
|
||||
var slots = frames.length - 1;
|
||||
assert_equals(frames[1].computedOffset, 1.0 / slots, '2nd frame offset');
|
||||
assert_equals(frames[2].computedOffset, 2.0 / slots, '3rd frame offset');
|
||||
}, 'Test falling back to distribute spacing mode if there is no context ' +
|
||||
'element');
|
||||
|
||||
test(function(t) {
|
||||
var div1 = createDiv(t);
|
||||
var div2 = createDiv(t);
|
||||
div1.style.marginLeft = '-20px';
|
||||
div2.style.marginLeft = '-50px';
|
||||
var child1 = document.createElement('div');
|
||||
var child2 = document.createElement('div');
|
||||
div1.appendChild(child1);
|
||||
div2.appendChild(child2);
|
||||
// body
|
||||
// / \
|
||||
// div1 div2
|
||||
// (-20px) (-50px)
|
||||
// | |
|
||||
// child1 child2
|
||||
var anim = child1.animate([ { marginLeft: '0px' },
|
||||
{ marginLeft: 'inherit' },
|
||||
{ marginLeft: '100px' },
|
||||
{ marginLeft: '50px' } ],
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
spacing: 'paced(margin-left)' });
|
||||
|
||||
var frames = anim.effect.getKeyframes();
|
||||
var cumDist = [0, 20, 140, 190];
|
||||
assert_equals(frames[1].computedOffset, cumDist[1] / cumDist[3],
|
||||
'2nd frame offset');
|
||||
assert_equals(frames[2].computedOffset, cumDist[2] / cumDist[3],
|
||||
'3rd frame offset');
|
||||
|
||||
anim.effect.target = child2;
|
||||
frames = anim.effect.getKeyframes();
|
||||
cumDist = [0, 50, 200, 250];
|
||||
assert_equals(frames[1].computedOffset, cumDist[1] / cumDist[3],
|
||||
'2nd frame offset after setting a new target');
|
||||
assert_equals(frames[2].computedOffset, cumDist[2] / cumDist[3],
|
||||
'3rd frame offset after setting a new target');
|
||||
}, 'Test paced spacing mode after setting a new target');
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<title>KeyframeEffect spacing attribute tests</title>
|
||||
<link rel="help"
|
||||
href="https://w3c.github.io/web-animations/#dom-keyframeeffect-spacing">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../../testcommon.js"></script>
|
||||
<body>
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
test(function(t) {
|
||||
var anim = createDiv(t).animate(null);
|
||||
assert_throws(new TypeError, function() {
|
||||
anim.effect.spacing = '';
|
||||
});
|
||||
}, 'Test throwing TypeError if using empty string');
|
||||
|
||||
test(function(t) {
|
||||
var anim = createDiv(t).animate(null);
|
||||
assert_throws(new TypeError, function() {
|
||||
anim.effect.spacing = 'dist';
|
||||
});
|
||||
}, 'Test throwing TypeError if not using the correct keyword');
|
||||
|
||||
test(function(t) {
|
||||
var anim = createDiv(t).animate(null);
|
||||
anim.effect.spacing = 'paced(A)';
|
||||
assert_equals(anim.effect.spacing, 'distribute', 'spacing mode');
|
||||
}, 'Test falling back to distribute spacing if using a unrecognized property');
|
||||
|
||||
test(function(t) {
|
||||
var anim = createDiv(t).animate(null);
|
||||
anim.effect.spacing = 'paced(--bg-color)';
|
||||
assert_equals(anim.effect.spacing, 'distribute', 'spacing mode');
|
||||
}, 'Test falling back to distribute spacing if using CSS variables');
|
||||
|
||||
test(function(t) {
|
||||
var anim = createDiv(t).animate(null);
|
||||
anim.effect.spacing = 'paced(animation-duration)';
|
||||
assert_equals(anim.effect.spacing, 'distribute', 'spacing mode');
|
||||
}, 'Test falling back to distribute spacing if using a non-animatable ' +
|
||||
'property');
|
||||
|
||||
test(function(t) {
|
||||
var anim = createDiv(t).animate(null);
|
||||
anim.effect.spacing = 'distribute';
|
||||
assert_equals(anim.effect.spacing, 'distribute', 'spacing mode');
|
||||
}, 'Test spacing value if setting distribute');
|
||||
|
||||
test(function(t) {
|
||||
var anim = createDiv(t).animate(null);
|
||||
anim.effect.spacing = 'paced(transform)';
|
||||
assert_equals(anim.effect.spacing, 'paced(transform)', 'spacing mode');
|
||||
}, 'Test spacing value if setting paced');
|
||||
|
||||
</script>
|
||||
</body>
|
||||
Loading…
Add table
Add a link
Reference in a new issue