Update web-platform-tests and CSS tests.

- Update CSS tests to revision e05bfd5e30ed662c2f8a353577003f8eed230180.
- Update web-platform-tests to revision a052787dd5c069a340031011196b73affbd68cd9.
This commit is contained in:
Ms2ger 2017-02-06 11:06:12 +01:00
parent fb4f421c8b
commit 296fa2512b
21852 changed files with 2080936 additions and 892894 deletions

View file

@ -0,0 +1,57 @@
<!doctype html>
<meta charset=utf-8>
<title>Tests for animation type of addition</title>
<link rel="help" href="https://w3c.github.io/web-animations/#animation-types">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../../testcommon.js"></script>
<script src="property-list.js"></script>
<script src="property-types.js"></script>
<style>
html {
font-size: 10px;
}
</style>
<body>
<div id="log"></div>
<script>
'use strict';
for (var property in gCSSProperties) {
if (!isSupported(property)) {
continue;
}
var animationTypes = gCSSProperties[property].types;
var setupFunction = gCSSProperties[property].setup;
animationTypes.forEach(function(animationType) {
var typeObject;
var animationTypeString;
if (typeof animationType === 'string') {
typeObject = types[animationType];
animationTypeString = animationType;
} else if (typeof animationType === 'object' &&
animationType.type && typeof animationType.type === 'string') {
typeObject = types[animationType.type];
animationTypeString = animationType.type;
}
// First, test that the animation type object has 'testAddition'.
// We use test() function here so that we can continue the remainder tests
// even if this test fails.
test(function(t) {
assert_own_property(typeObject, 'testAddition', animationTypeString +
' should have testAddition property');
assert_equals(typeof typeObject.testAddition, 'function',
'testAddition method should be a function');
}, animationTypeString + ' has testAddition function');
if (typeObject.testAddition &&
typeof typeObject.testAddition === 'function') {
typeObject.testAddition(property,
setupFunction,
animationType.options);
}
});
}
</script>

View file

@ -0,0 +1,57 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>Tests for animation type of interpolation</title>
<link rel="help" href="https://w3c.github.io/web-animations/#animation-types">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../../testcommon.js"></script>
<script src="property-list.js"></script>
<script src="property-types.js"></script>
<style>
html {
font-size: 10px;
}
</style>
<body>
<div id="log"></div>
<script>
'use strict';
for (var property in gCSSProperties) {
if (!isSupported(property)) {
continue;
}
var animationTypes = gCSSProperties[property].types;
var setupFunction = gCSSProperties[property].setup;
animationTypes.forEach(function(animationType) {
var typeObject;
var animationTypeString;
if (typeof animationType === 'string') {
typeObject = types[animationType];
animationTypeString = animationType;
} else if (typeof animationType === 'object' &&
animationType.type && typeof animationType.type === 'string') {
typeObject = types[animationType.type];
animationTypeString = animationType.type;
}
// First, test that the animation type object has 'testInterpolation'.
// We use test() function() here so that we can continue the remainder tests
// even if this test fails.
test(function(t) {
assert_own_property(typeObject, 'testInterpolation', animationTypeString +
' should have testInterpolation property');
assert_equals(typeof typeObject.testInterpolation, 'function',
'testInterpolation method should be a function');
}, animationTypeString + ' has testInterpolation function');
if (typeObject.testInterpolation &&
typeof typeObject.testInterpolation === 'function') {
typeObject.testInterpolation(property,
setupFunction,
animationType.options);
}
});
}
</script>

View file

@ -0,0 +1,972 @@
const discreteType = {
testInterpolation: function(property, setup, options) {
options.forEach(function(keyframes) {
var [ from, to ] = keyframes;
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
var animation = target.animate({ [idlName]: [from, to] },
{ duration: 1000, fill: 'both' });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: from.toLowerCase() },
{ time: 499, expected: from.toLowerCase() },
{ time: 500, expected: to.toLowerCase() },
{ time: 1000, expected: to.toLowerCase() }]);
}, property + ' uses discrete animation when animating between "'
+ from + '" and "' + to + '" with linear easing');
test(function(t) {
// Easing: http://cubic-bezier.com/#.68,0,1,.01
// With this curve, we don't reach the 50% point until about 95% of
// the time has expired.
var idlName = propertyToIDL(property);
var keyframes = {};
var target = createTestElement(t, setup);
var animation = target.animate({ [idlName]: [from, to] },
{ duration: 1000, fill: 'both',
easing: 'cubic-bezier(0.68,0,1,0.01)' });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: from.toLowerCase() },
{ time: 940, expected: from.toLowerCase() },
{ time: 960, expected: to.toLowerCase() }]);
}, property + ' uses discrete animation when animating between "'
+ from + '" and "' + to + '" with effect easing');
test(function(t) {
// Easing: http://cubic-bezier.com/#.68,0,1,.01
// With this curve, we don't reach the 50% point until about 95% of
// the time has expired.
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
var animation = target.animate({ [idlName]: [from, to],
easing: 'cubic-bezier(0.68,0,1,0.01)' },
{ duration: 1000, fill: 'both' });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: from.toLowerCase() },
{ time: 940, expected: from.toLowerCase() },
{ time: 960, expected: to.toLowerCase() }]);
}, property + ' uses discrete animation when animating between "'
+ from + '" and "' + to + '" with keyframe easing');
});
},
testAddition: function(property, setup, options) {
options.forEach(function(keyframes) {
var [ from, to ] = keyframes;
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
target.animate({ [idlName]: [from, from] }, 1000);
var animation = target.animate({ [idlName]: [to, to] },
{ duration: 1000, composite: 'add' });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: to.toLowerCase() }]);
}, property + ': "' + to + '" onto "' + from + '"');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
target.animate({ [idlName]: [to, to] }, 1000);
var animation = target.animate({ [idlName]: [from, from] },
{ duration: 1000, composite: 'add' });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: from.toLowerCase() }]);
}, property + ': "' + from + '" onto "' + to + '"');
});
},
};
const lengthType = {
testInterpolation: function(property, setup) {
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
var animation = target.animate({ [idlName]: ['10px', '50px'] },
{ duration: 1000, fill: 'both' });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: '10px' },
{ time: 500, expected: '30px' },
{ time: 1000, expected: '50px' }]);
}, property + ' supports animating as a length');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
var animation = target.animate({ [idlName]: ['1rem', '5rem'] },
{ duration: 1000, fill: 'both' });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: '10px' },
{ time: 500, expected: '30px' },
{ time: 1000, expected: '50px' }]);
}, property + ' supports animating as a length of rem');
},
testAddition: function(property, setup) {
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
target.style[idlName] = '10px';
var animation = target.animate({ [idlName]: ['10px', '50px'] },
{ duration: 1000, composite: 'add' });
testAnimationSamples(animation, idlName, [{ time: 0, expected: '20px' }]);
}, property + ': length');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
target.style[idlName] = '1rem';
var animation = target.animate({ [idlName]: ['1rem', '5rem'] },
{ duration: 1000, composite: 'add' });
testAnimationSamples(animation, idlName, [{ time: 0, expected: '20px' }]);
}, property + ': length of rem');
},
};
const percentageType = {
testInterpolation: function(property, setup) {
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
var animation = target.animate({ [idlName]: ['10%', '50%'] },
{ duration: 1000, fill: 'both' });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: '10%' },
{ time: 500, expected: '30%' },
{ time: 1000, expected: '50%' }]);
}, property + ' supports animating as a percentage');
},
testAddition: function(property, setup) {
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
target.style[idlName] = '60%';
var animation = target.animate({ [idlName]: ['70%', '100%'] },
{ duration: 1000, composite: 'add' });
testAnimationSamples(animation, idlName, [{ time: 0, expected: '130%' }]);
}, property + ': percentage');
},
};
const integerType = {
testInterpolation: function(property, setup) {
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
var animation = target.animate({ [idlName]: [-2, 2] },
{ duration: 1000, fill: 'both' });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: '-2' },
{ time: 500, expected: '0' },
{ time: 1000, expected: '2' }]);
}, property + ' supports animating as an integer');
},
testAddition: function(property, setup) {
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
target.style[idlName] = -1;
var animation = target.animate({ [idlName]: [-2, 2] },
{ duration: 1000, composite: 'add' });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: '-3' }]);
}, property + ': integer');
},
};
const lengthPercentageOrCalcType = {
testInterpolation: function(property, setup) {
lengthType.testInterpolation(property, setup);
percentageType.testInterpolation(property, setup);
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
var animation = target.animate({ [idlName]: ['10px', '20%'] },
{ duration: 1000, fill: 'both' });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: '10px' },
{ time: 500, expected: 'calc(5px + 10%)' },
{ time: 1000, expected: '20%' }]);
}, property + ' supports animating as combination units "px" and "%"');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
var animation = target.animate({ [idlName]: ['10%', '2em'] },
{ duration: 1000, fill: 'both' });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: '10%' },
{ time: 500, expected: 'calc(10px + 5%)' },
{ time: 1000, expected: '20px' }]);
}, property + ' supports animating as combination units "%" and "em"');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
var animation = target.animate({ [idlName]: ['1em', '2rem'] },
{ duration: 1000, fill: 'both' });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: '10px' },
{ time: 500, expected: '15px' },
{ time: 1000, expected: '20px' }]);
}, property + ' supports animating as combination units "em" and "rem"');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
var animation = target.animate({ [idlName]: ['10px', 'calc(1em + 20%)'] },
{ duration: 1000, fill: 'both' });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: '10px' },
{ time: 500, expected: 'calc(10px + 10%)' },
{ time: 1000, expected: 'calc(10px + 20%)' }]);
}, property + ' supports animating as combination units "px" and "calc"');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
var animation = target.animate(
{ [idlName]: ['calc(10px + 10%)', 'calc(1em + 1rem + 20%)'] },
{ duration: 1000, fill: 'both' });
testAnimationSamples(animation, idlName,
[{ time: 0,
expected: 'calc(10px + 10%)' },
{ time: 500,
expected: 'calc(15px + 15%)' },
{ time: 1000,
expected: 'calc(20px + 20%)' }]);
}, property + ' supports animating as a calc');
},
testAddition: function(property, setup) {
lengthType.testAddition(property, setup);
percentageType.testAddition(property, setup);
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
target.style[idlName] = '10px';
var animation = target.animate({ [idlName]: ['10%', '50%'] },
{ duration: 1000, composite: 'add' });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: 'calc(10px + 10%)' }]);
}, property + ': units "%" onto "px"');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
target.style[idlName] = '10%';
var animation = target.animate({ [idlName]: ['10px', '50px'] },
{ duration: 1000, composite: 'add' });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: 'calc(10px + 10%)' }]);
}, property + ': units "px" onto "%"');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
target.style[idlName] = '10%';
var animation = target.animate({ [idlName]: ['2rem', '5rem'] },
{ duration: 1000, composite: 'add' });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: 'calc(20px + 10%)' }]);
}, property + ': units "rem" onto "%"');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
target.style[idlName] = '2rem';
var animation = target.animate({ [idlName]: ['10%', '50%'] },
{ duration: 1000, composite: 'add' });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: 'calc(20px + 10%)' }]);
}, property + ': units "%" onto "rem"');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
target.style[idlName] = '2em';
var animation = target.animate({ [idlName]: ['2rem', '5rem'] },
{ duration: 1000, composite: 'add' });
testAnimationSamples(animation, idlName, [{ time: 0, expected: '40px' }]);
}, property + ': units "rem" onto "em"');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
target.style[idlName] = '2rem';
var animation = target.animate({ [idlName]: ['2em', '5em'] },
{ duration: 1000, composite: 'add' });
testAnimationSamples(animation, idlName, [{ time: 0, expected: '40px' }]);
}, property + ': units "em" onto "rem"');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
target.style[idlName] = '10px';
var animation = target.animate({ [idlName]: ['calc(2em + 20%)',
'calc(5rem + 50%)'] },
{ duration: 1000, composite: 'add' });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: 'calc(30px + 20%)' }]);
}, property + ': units "calc" onto "px"');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
target.style[idlName] = 'calc(10px + 10%)';
var animation = target.animate({ [idlName]: ['calc(20px + 20%)',
'calc(2em + 3rem + 40%)'] },
{ duration: 1000, composite: 'add' });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: 'calc(30px + 30%)' }]);
}, property + ': calc');
},
};
const positiveNumberType = {
testInterpolation: function(property, setup) {
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
var animation = target.animate({ [idlName]: [1.1, 1.5] },
{ duration: 1000, fill: 'both' });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: '1.1' },
{ time: 500, expected: '1.3' },
{ time: 1000, expected: '1.5' }]);
}, property + ' supports animating as a positive number');
},
testAddition: function(property, setup) {
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
target.style[idlName] = 1.1;
var animation = target.animate({ [idlName]: [1.1, 1.5] },
{ duration: 1000, composite: 'add' });
testAnimationSamples(animation, idlName, [{ time: 0, expected: '2.2' }]);
}, property + ': positive number');
},
};
const visibilityType = {
testInterpolation: function(property, setup) {
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
var animation = target.animate({ [idlName]: ['visible', 'hidden'] },
{ duration: 1000, fill: 'both' });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: 'visible' },
{ time: 999, expected: 'visible' },
{ time: 1000, expected: 'hidden' }]);
}, property + ' uses visibility animation when animating '
+ 'from "visible" to "hidden"');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
var animation = target.animate({ [idlName]: ['hidden', 'visible'] },
{ duration: 1000, fill: 'both' });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: 'hidden' },
{ time: 1, expected: 'visible' },
{ time: 1000, expected: 'visible' }]);
}, property + ' uses visibility animation when animating '
+ 'from "hidden" to "visible"');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
var animation = target.animate({ [idlName]: ['hidden', 'collapse'] },
{ duration: 1000, fill: 'both' });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: 'hidden' },
{ time: 499, expected: 'hidden' },
{ time: 500, expected: 'collapse' },
{ time: 1000, expected: 'collapse' }]);
}, property + ' uses visibility animation when animating '
+ 'from "hidden" to "collapse"');
test(function(t) {
// Easing: http://cubic-bezier.com/#.68,-.55,.26,1.55
// With this curve, the value is less than 0 till about 34%
// also more than 1 since about 63%
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
var animation =
target.animate({ [idlName]: ['visible', 'hidden'] },
{ duration: 1000, fill: 'both',
easing: 'cubic-bezier(0.68, -0.55, 0.26, 1.55)' });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: 'visible' },
{ time: 1, expected: 'visible' },
{ time: 330, expected: 'visible' },
{ time: 340, expected: 'visible' },
{ time: 620, expected: 'visible' },
{ time: 630, expected: 'hidden' },
{ time: 1000, expected: 'hidden' }]);
}, property + ' uses visibility animation when animating '
+ 'from "visible" to "hidden" with easeInOutBack easing');
},
testAddition: function(property, setup) {
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
target.style[idlName] = 'visible';
var animation = target.animate({ [idlName]: ['visible', 'hidden'] },
{ duration: 1000, fill: 'both',
composite: 'add' });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: 'visible' },
{ time: 1000, expected: 'visible' }]);
}, property + ': onto "visible"');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
target.style[idlName] = 'hidden';
var animation = target.animate({ [idlName]: ['hidden', 'visible'] },
{ duration: 1000, fill: 'both',
composite: 'add' });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: 'hidden' },
{ time: 1000, expected: 'visible' }]);
}, property + ': onto "hidden"');
},
};
const colorType = {
testInterpolation: function(property, setup) {
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
var animation = target.animate({ [idlName]: ['rgb(255, 0, 0)',
'rgb(0, 0, 255)'] },
1000);
testAnimationSamples(animation, idlName,
[{ time: 500, expected: 'rgb(128, 0, 128)' }]);
}, property + ' supports animating as color of rgb()');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
var animation = target.animate({ [idlName]: ['#ff0000', '#0000ff'] },
1000);
testAnimationSamples(animation, idlName,
[{ time: 500, expected: 'rgb(128, 0, 128)' }]);
}, property + ' supports animating as color of #RGB');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
var animation = target.animate({ [idlName]: ['hsl(0, 100%, 50%)',
'hsl(240, 100%, 50%)'] },
1000);
testAnimationSamples(animation, idlName,
[{ time: 500, expected: 'rgb(128, 0, 128)' }]);
}, property + ' supports animating as color of hsl()');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
var animation = target.animate({ [idlName]: ['#ff000066', '#0000ffcc'] },
1000);
// R: 255 * (0.4 * 0.5) / 0.6 = 85
// G: 255 * (0.8 * 0.5) / 0.6 = 170
testAnimationSamples(animation, idlName,
[{ time: 500, expected: 'rgba(85, 0, 170, 0.6)' }]);
}, property + ' supports animating as color of #RGBa');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
var animation = target.animate({ [idlName]: ['rgba(255, 0, 0, 0.4)',
'rgba(0, 0, 255, 0.8)'] },
1000);
testAnimationSamples(animation, idlName, // Same as above.
[{ time: 500, expected: 'rgba(85, 0, 170, 0.6)' }]);
}, property + ' supports animating as color of rgba()');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
var animation = target.animate({ [idlName]: ['hsla(0, 100%, 50%, 0.4)',
'hsla(240, 100%, 50%, 0.8)'] },
1000);
testAnimationSamples(animation, idlName, // Same as above.
[{ time: 500, expected: 'rgba(85, 0, 170, 0.6)' }]);
}, property + ' supports animating as color of hsla()');
},
testAddition: function(property, setup) {
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
target.style[idlName] = 'rgb(128, 128, 128)';
var animation = target.animate({ [idlName]: ['rgb(255, 0, 0)',
'rgb(0, 0, 255)'] },
{ duration: 1000, composite: 'add' });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: 'rgb(255, 128, 128)' },
// The value at 50% is interpolated
// from 'rgb(128+255, 128, 128)'
// to 'rgb(128, 128, 128+255)'.
{ time: 500, expected: 'rgb(255, 128, 255)' }]);
}, property + ' supports animating as color of rgb() with overflowed ' +
'from and to values');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
target.style[idlName] = 'rgb(128, 128, 128)';
var animation = target.animate({ [idlName]: ['#ff0000', '#0000ff'] },
{ duration: 1000, composite: 'add' });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: 'rgb(255, 128, 128)' }]);
}, property + ' supports animating as color of #RGB');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
target.style[idlName] = 'rgb(128, 128, 128)';
var animation = target.animate({ [idlName]: ['hsl(0, 100%, 50%)',
'hsl(240, 100%, 50%)'] },
{ duration: 1000, composite: 'add' });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: 'rgb(255, 128, 128)' }]);
}, property + ' supports animating as color of hsl()');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
target.style[idlName] = 'rgb(128, 128, 128)';
var animation = target.animate({ [idlName]: ['#ff000066', '#0000ffcc'] },
{ duration: 1000, composite: 'add' });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: 'rgb(230, 128, 128)' }]);
}, property + ' supports animating as color of #RGBa');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
target.style[idlName] = 'rgb(128, 128, 128)';
var animation = target.animate({ [idlName]: ['rgba(255, 0, 0, 0.4)',
'rgba(0, 0, 255, 0.8)'] },
{ duration: 1000, composite: 'add' });
testAnimationSamples(animation, idlName, // Same as above.
[{ time: 0, expected: 'rgb(230, 128, 128)' }]);
}, property + ' supports animating as color of rgba()');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
target.style[idlName] = 'rgb(128, 128, 128)';
var animation = target.animate({ [idlName]: ['hsla(0, 100%, 50%, 0.4)',
'hsla(240, 100%, 50%, 0.8)'] },
{ duration: 1000, composite: 'add' });
testAnimationSamples(animation, idlName, // Same as above.
[{ time: 0, expected: 'rgb(230, 128, 128)' }]);
}, property + ' supports animating as color of hsla()');
},
};
const transformListType = {
testInterpolation: function(property, setup) {
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
var animation = target.animate({ [idlName]: ['translate(200px, -200px)',
'translate(400px, 400px)'] },
1000);
testAnimationSampleMatrices(animation, idlName,
[{ time: 500, expected: [ 1, 0, 0, 1, 300, 100 ] }]);
}, property + ': translate');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
var animation = target.animate({ [idlName]: ['rotate(45deg)',
'rotate(135deg)'] },
1000);
testAnimationSampleMatrices(animation, idlName,
[{ time: 500, expected: [ Math.cos(Math.PI / 2),
Math.sin(Math.PI / 2),
-Math.sin(Math.PI / 2),
Math.cos(Math.PI / 2),
0, 0] }]);
}, property + ': rotate');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
var animation = target.animate({ [idlName]: ['scale(3)', 'scale(5)'] },
1000);
testAnimationSampleMatrices(animation, idlName,
[{ time: 500, expected: [ 4, 0, 0, 4, 0, 0 ] }]);
}, property + ': scale');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
var animation = target.animate({ [idlName]: ['skew(30deg, 60deg)',
'skew(60deg, 30deg)'] },
1000);
testAnimationSampleMatrices(animation, idlName,
[{ time: 500, expected: [ 1, Math.tan(Math.PI / 4),
Math.tan(Math.PI / 4), 1,
0, 0] }]);
}, property + ': skew');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
var animation =
target.animate({ [idlName]: ['translateX(100px) rotate(45deg)',
'translateX(200px) rotate(135deg)'] },
1000);
testAnimationSampleMatrices(animation, idlName,
[{ time: 500, expected: [ Math.cos(Math.PI / 2),
Math.sin(Math.PI / 2),
-Math.sin(Math.PI / 2),
Math.cos(Math.PI / 2),
150, 0 ] }]);
}, property + ': rotate and translate');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
var animation =
target.animate({ [idlName]: ['rotate(45deg) translateX(100px)',
'rotate(135deg) translateX(200px)'] },
1000);
testAnimationSampleMatrices(animation, idlName,
[{ time: 500, expected: [ Math.cos(Math.PI / 2),
Math.sin(Math.PI / 2),
-Math.sin(Math.PI / 2),
Math.cos(Math.PI / 2),
150 * Math.cos(Math.PI / 2),
150 * Math.sin(Math.PI / 2) ] }]);
}, property + ': translate and rotate');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
var animation = // matrix(0, 1, -1, 0, 0, 100)
target.animate({ [idlName]: ['rotate(90deg) translateX(100px)',
// matrix(-1, 0, 0, -1, 200, 0)
'translateX(200px) rotate(180deg)'] },
1000);
testAnimationSampleMatrices(animation, idlName,
[{ time: 500, expected: [ Math.cos(Math.PI * 3 / 4),
Math.sin(Math.PI * 3 / 4),
-Math.sin(Math.PI * 3 / 4),
Math.cos(Math.PI * 3 / 4),
100, 50 ] }]);
}, property + ': mismatch order of translate and rotate');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
var animation = // Same matrices as above.
target.animate({ [idlName]: [ 'matrix(0, 1, -1, 0, 0, 100)',
'matrix(-1, 0, 0, -1, 200, 0)' ] },
1000);
testAnimationSampleMatrices(animation, idlName,
[{ time: 500, expected: [ Math.cos(Math.PI * 3 / 4),
Math.sin(Math.PI * 3 / 4),
-Math.sin(Math.PI * 3 / 4),
Math.cos(Math.PI * 3 / 4),
100, 50 ] }]);
}, property + ': matrix');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
var animation =
target.animate({ [idlName]: [ 'rotate3d(1, 1, 0, 0deg)',
'rotate3d(1, 1, 0, 90deg)'] },
1000);
testAnimationSampleMatrices(animation, idlName,
[{ time: 500, expected: rotate3dToMatrix(1, 1, 0, Math.PI / 4) }]);
}, property + ': rotate3d');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
// To calculate expected matrices easily, generate input matrices from
// rotate3d.
var from = rotate3dToMatrix3d(1, 1, 0, Math.PI / 4);
var to = rotate3dToMatrix3d(1, 1, 0, Math.PI * 3 / 4);
var animation =
target.animate({ [idlName]: [ from, to ] }, 1000);
testAnimationSampleMatrices(animation, idlName,
[{ time: 500, expected: rotate3dToMatrix(1, 1, 0, Math.PI * 2 / 4) }]);
}, property + ': matrix3d');
},
testAddition: function(property, setup) {
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
target.style[idlName] = 'translateX(100px)';
var animation = target.animate({ [idlName]: ['translateX(-200px)',
'translateX(500px)'] },
{ duration: 1000, fill: 'both',
composite: 'add' });
testAnimationSampleMatrices(animation, idlName,
[ { time: 0, expected: [ 1, 0, 0, 1, -100, 0 ] },
{ time: 1000, expected: [ 1, 0, 0, 1, 600, 0 ] }]);
}, property + ': translate');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
target.style[idlName] = 'rotate(45deg)';
var animation = target.animate({ [idlName]: ['rotate(-90deg)',
'rotate(90deg)'] },
{ duration: 1000, fill: 'both',
composite: 'add' });
testAnimationSampleMatrices(animation, idlName,
[{ time: 0, expected: [ Math.cos(-Math.PI / 4),
Math.sin(-Math.PI / 4),
-Math.sin(-Math.PI / 4),
Math.cos(-Math.PI / 4),
0, 0] },
{ time: 1000, expected: [ Math.cos(Math.PI * 3 / 4),
Math.sin(Math.PI * 3 / 4),
-Math.sin(Math.PI * 3 / 4),
Math.cos(Math.PI * 3 / 4),
0, 0] }]);
}, property + ': rotate');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
target.style[idlName] = 'scale(2)';
var animation = target.animate({ [idlName]: ['scale(-3)', 'scale(5)'] },
{ duration: 1000, fill: 'both',
composite: 'add' });
testAnimationSampleMatrices(animation, idlName,
[{ time: 0, expected: [ -6, 0, 0, -6, 0, 0 ] }, // scale(-3) scale(2)
{ time: 1000, expected: [ 10, 0, 0, 10, 0, 0 ] }]); // scale(5) scale(2)
}, property + ': scale');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
// matrix(1, tan(10deg), tan(10deg), 1)
target.style[idlName] = 'skew(10deg, 10deg)';
var animation = // matrix(1, tan(20deg), tan(-30deg), 1)
target.animate({ [idlName]: ['skew(-30deg, 20deg)',
// matrix(1, tan(-30deg), tan(20deg), 1)
'skew(20deg, -30deg)'] },
{ duration: 1000, fill: 'both', composite: 'add' });
// matrix at 0%.
// [ 1 tan(10deg) ] [ 1 tan(-30deg) ]
// [ tan(10deg) 1 ] [ tan(20deg) 1 ] =
//
// [ 1 + tan(10deg) * tan(20deg) tan(-30deg) + tan(10deg) ]
// [ tan(10deg) + tan(20deg) tan(10deg) * tan(-30deg) + 1 ]
// matrix at 100%.
// [ 1 tan(10deg) ] [ 1 tan(20deg) ]
// [ tan(10deg) 1 ] [ tan(-30deg) 1 ] =
//
// [ 1 + tan(10deg) * tan(-30deg) tan(20deg) + tan(10deg) ]
// [ tan(10deg) + tan(-30deg) tan(10deg) * tan(20deg) + 1 ]
testAnimationSampleMatrices(animation, idlName,
[{ time: 0, expected: [ 1 + Math.tan(Math.PI/18) * Math.tan(Math.PI/9),
Math.tan(Math.PI/18) + Math.tan(Math.PI/9),
Math.tan(-Math.PI/6) + Math.tan(Math.PI/18),
1 + Math.tan(Math.PI/18) * Math.tan(-Math.PI/6),
0, 0] },
{ time: 1000, expected: [ 1 + Math.tan(Math.PI/18) * Math.tan(-Math.PI/6),
Math.tan(Math.PI/18) + Math.tan(-Math.PI/6),
Math.tan(Math.PI/9) + Math.tan(Math.PI/18),
1 + Math.tan(Math.PI/18) * Math.tan(Math.PI/9),
0, 0] }]);
}, property + ': skew');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
// matrix(1, 0, 0, 1, 100, 0)
target.style[idlName] = 'translateX(100px)';
var animation = // matrix(0, 1, -1, 0, 0, 0)
target.animate({ [idlName]: ['rotate(90deg)',
// matrix(-1, 0, 0, -1, 0, 0)
'rotate(180deg)'] },
{ duration: 1000, fill: 'both', composite: 'add' });
testAnimationSampleMatrices(animation, idlName,
[{ time: 0, expected: [ 0, 1, -1, 0, 100, 0 ] },
{ time: 1000, expected: [ -1, 0, 0, -1, 100, 0 ] }]);
}, property + ': rotate on translate');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
// matrix(0, 1, -1, 0, 0, 0)
target.style[idlName] = 'rotate(90deg)';
var animation = // matrix(1, 0, 0, 1, 100, 0)
target.animate({ [idlName]: ['translateX(100px)',
// matrix(1, 0, 0, 1, 200, 0)
'translateX(200px)'] },
{ duration: 1000, fill: 'both', composite: 'add' });
testAnimationSampleMatrices(animation, idlName,
[{ time: 0, expected: [ 0, 1, -1, 0, 0, 100 ] },
{ time: 1000, expected: [ 0, 1, -1, 0, 0, 200 ] }]);
}, property + ': translate on rotate');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
target.style[idlName] = 'matrix(0, 1, -1, 0, 0, 0)';
var animation = // Same matrices as above.
target.animate({ [idlName]: [ 'matrix(1, 0, 0, 1, 100, 0)',
'matrix(1, 0, 0, 1, 200, 0)' ] },
{ duration: 1000, fill: 'both', composite: 'add' });
testAnimationSampleMatrices(animation, idlName,
[{ time: 0, expected: [ 0, 1, -1, 0, 0, 100 ] },
{ time: 1000, expected: [ 0, 1, -1, 0, 0, 200 ] }]);
}, property + ': matrix');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
target.style[idlName] = 'rotate3d(1, 1, 0, 45deg)';
var animation =
target.animate({ [idlName]: [ 'rotate3d(1, 1, 0, -90deg)',
'rotate3d(1, 1, 0, 90deg)'] },
{ duration: 1000, fill: 'both', composite: 'add' });
testAnimationSampleMatrices(animation, idlName,
[{ time: 0, expected: rotate3dToMatrix(1, 1, 0, -Math.PI / 4) },
{ time: 1000, expected: rotate3dToMatrix(1, 1, 0, 3 * Math.PI / 4) }]);
}, property + ': rotate3d');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
// To calculate expected matrices easily, generate input matrices from
// rotate3d.
target.style[idlName] = rotate3dToMatrix3d(1, 1, 0, Math.PI / 4);
var from = rotate3dToMatrix3d(1, 1, 0, -Math.PI / 2);
var to = rotate3dToMatrix3d(1, 1, 0, Math.PI / 2);
var animation =
target.animate({ [idlName]: [ from, to ] },
{ duration: 1000, fill: 'both', composite: 'add' });
testAnimationSampleMatrices(animation, idlName,
[{ time: 0, expected: rotate3dToMatrix(1, 1, 0, -Math.PI / 4) },
{ time: 1000, expected: rotate3dToMatrix(1, 1, 0, 3 * Math.PI / 4) }]);
}, property + ': matrix3d');
},
};
const filterListType = {
testAddition: function(property, setup) {
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
target.style[idlName] = 'blur(10px)';
var animation = target.animate({ [idlName]: ['blur(20px)',
'blur(50px)'] },
{ duration: 1000, composite: 'add' });
testAnimationSamples(animation, idlName,
[ { time: 0, expected: 'blur(10px) blur(20px)' }]);
}, property + ': blur on blur');
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
target.style[idlName] = 'blur(10px)';
var animation = target.animate({ [idlName]: ['brightness(80%)',
'brightness(40%)'] },
{ duration: 1000, composite: 'add' });
testAnimationSamples(animation, idlName,
[ { time: 0, expected: 'blur(10px) brightness(0.8)' }]);
}, property + ': different filter functions');
},
};
const textShadowListType = {
testAddition: function(property, setup) {
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
target.style[idlName] = 'rgb(0, 0, 0) 0px 0px 0px';
var animation =
target.animate({ [idlName]: [ 'rgb(120, 120, 120) 10px 10px 10px',
'rgb(120, 120, 120) 10px 10px 10px'] },
{ duration: 1000, composite: 'add' });
testAnimationSamples(animation, idlName,
[ { time: 0, expected: 'rgb(0, 0, 0) 0px 0px 0px, ' +
'rgb(120, 120, 120) 10px 10px 10px' }]);
}, property + ': shadow');
},
};
const boxShadowListType = {
testAddition: function(property, setup) {
test(function(t) {
var idlName = propertyToIDL(property);
var target = createTestElement(t, setup);
target.style[idlName] = 'rgb(0, 0, 0) 0px 0px 0px 0px';
var animation =
target.animate({ [idlName]: [ 'rgb(120, 120, 120) 10px 10px 10px 0px',
'rgb(120, 120, 120) 10px 10px 10px 0px'] },
{ duration: 1000, composite: 'add' });
testAnimationSamples(animation, idlName,
[ { time: 0, expected: 'rgb(0, 0, 0) 0px 0px 0px 0px, ' +
'rgb(120, 120, 120) 10px 10px 10px 0px' }]);
}, property + ': shadow');
},
};
const types = {
color: colorType,
discrete: discreteType,
filterList: filterListType,
integer: integerType,
length: lengthType,
percentage: percentageType,
lengthPercentageOrCalc: lengthPercentageOrCalcType,
positiveNumber: positiveNumberType,
transformList: transformListType,
visibility: visibilityType,
boxShadowList: boxShadowListType,
textShadowList: textShadowListType,
};

View file

@ -0,0 +1,210 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>Keyframe spacing tests on filters</title>
<link rel="help" href="https://w3c.github.io/web-animations/#spacing-keyframes">
<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";
// Help function for testing the computed offsets by the distance array.
function assert_animation_offsets(anim, dist) {
const frames = anim.effect.getKeyframes();
const cumDist = dist.reduce( (prev, curr) => {
prev.push(prev.length == 0 ? curr : curr + prev[prev.length - 1]);
return prev;
}, []);
const total = cumDist[cumDist.length - 1];
for (var i = 0; i < frames.length; ++i) {
assert_equals(frames[i].computedOffset, cumDist[i] / total,
'computedOffset of frame ' + i);
}
}
test(function(t) {
var anim =
createDiv(t).animate([ { filter: 'blur(1px)'},
{ filter: 'none' }, // The default value is 0px.
{ filter: 'blur(10px)' },
{ filter: 'blur(8px)' } ],
{ spacing: 'paced(filter)' });
var dist = [ 0, 1, 10, (10 - 8) ];
assert_animation_offsets(anim, dist);
}, 'Test spacing on blur' );
test(function(t) {
var anim =
createDiv(t).animate([ { filter: 'brightness(50%)'},
{ filter: 'none' }, // The default value is 1.
{ filter: 'brightness(2)' },
{ filter: 'brightness(175%)' } ],
{ spacing: 'paced(filter)' });
var dist = [ 0, (1 - 0.5), (2 - 1), (2.0 - 1.75) ];
assert_animation_offsets(anim, dist);
}, 'Test spacing on brightness' );
test(function(t) {
var anim =
createDiv(t).animate([ { filter: 'contrast(50%)'},
{ filter: 'none' }, // The default value is 1.
{ filter: 'contrast(2)' },
{ filter: 'contrast(175%)' } ],
{ spacing: 'paced(filter)' });
var dist = [ 0, (1 - 0.5), (2 - 1), (2.0 - 1.75) ];
assert_animation_offsets(anim, dist);
}, 'Test spacing on contrast' );
test(function(t) {
var anim =
createDiv(t).animate([ { filter: 'drop-shadow(10px 10px 10px blue)'},
{ filter: 'none' },
// none filter: 'drop-shadow(0, 0, 0, rgba(0, 0, 0, 0))'
{ filter: 'drop-shadow(5px 5px 1px black)' },
{ filter: 'drop-shadow(20px 20px yellow)' } ],
{ spacing: 'paced(filter)' });
// Blue: rgba(0, 0, 255, 1.0) = rgba( 0%, 0%, 100%, 100%).
// Black: rgba(0, 0, 0, 1.0) = rgba( 0%, 0%, 0%, 100%).
// Yellow: rgba(255, 255, 0, 1.0) = rgba(100%, 100%, 0%, 100%).
var dist = [ 0,
Math.sqrt(10 * 10 + 10 * 10 + 10 * 10 + (1 * 1 + 1 * 1)),
Math.sqrt(5 * 5 + 5 * 5 + 1 * 1 + (1 * 1)),
Math.sqrt(15 * 15 + 15 * 15 + 1 * 1 + (1 * 1 + 1 * 1)) ];
assert_animation_offsets(anim, dist);
}, 'Test spacing on drop-shadow' );
test(function(t) {
var anim =
createDiv(t).animate([ { filter: 'drop-shadow(10px 10px 10px)'},
{ filter: 'drop-shadow(0 0)' },
{ filter: 'drop-shadow(5px 5px 1px black)' },
{ filter: 'drop-shadow(20px 20px yellow)' } ],
{ spacing: 'paced(filter)' });
// Black: rgba(0, 0, 0, 1.0) = rgba( 0%, 0%, 0%, 100%).
// Yellow: rgba(255, 255, 0, 1.0) = rgba(100%, 100%, 0%, 100%).
var dist = [ 0,
Math.sqrt(10 * 10 + 10 * 10 + 10 * 10),
0, // The distance is zero because the 2nd frame uses no-color.
Math.sqrt(15 * 15 + 15 * 15 + 1 * 1 + (1 * 1 + 1 * 1)) ];
assert_animation_offsets(anim, dist);
}, 'Test getting zero distance when computing distance between ' +
'color and no-color on drop-shadow');
test(function(t) {
var anim =
createDiv(t).animate([ { filter: 'grayscale(50%)'},
{ filter: 'none' }, // The default value is 0.
// Values of grayscale over 100% are clamped to 1.
{ filter: 'grayscale(2)' },
{ filter: 'grayscale(75%)' } ],
{ spacing: 'paced(filter)' });
var dist = [ 0, 0.5, 1, (1.0 - 0.75) ];
assert_animation_offsets(anim, dist);
}, 'Test spacing on grayscale' );
test(function(t) {
var anim =
createDiv(t).animate([ { filter: 'hue-rotate(180deg)'},
{ filter: 'none' }, // The default value is 0deg.
{ filter: 'hue-rotate(720deg)' },
{ filter: 'hue-rotate(-180deg)' } ],
{ spacing: 'paced(filter)' });
var dist = [ 0, 180, 720, 720 + 180 ];
assert_animation_offsets(anim, dist);
}, 'Test spacing on hue-rotate' );
test(function(t) {
var anim =
createDiv(t).animate([ { filter: 'invert(50%)'},
{ filter: 'none' }, // The default value is 0.
// Values of invert over 100% are clamped to 1.
{ filter: 'invert(2)' },
{ filter: 'invert(75%)' } ],
{ spacing: 'paced(filter)' });
var dist = [ 0, 0.5, 1, (1.0 - 0.75) ];
assert_animation_offsets(anim, dist);
}, 'Test spacing on invert' );
test(function(t) {
var anim =
createDiv(t).animate([ { filter: 'opacity(50%)'},
{ filter: 'none' }, // The default value is 1.
// Values of opacity over 100% are clamped to 1.
{ filter: 'opacity(2)' },
{ filter: 'opacity(75%)' } ],
{ spacing: 'paced(filter)' });
var dist = [ 0, (1 - 0.5), (1 - 1), (1.0 - 0.75) ];
assert_animation_offsets(anim, dist);
}, 'Test spacing on opacity' );
test(function(t) {
var anim =
createDiv(t).animate([ { filter: 'saturate(50%)'},
{ filter: 'none' }, // The default value is 1.
{ filter: 'saturate(2)' },
{ filter: 'saturate(175%)' } ],
{ spacing: 'paced(filter)' });
var dist = [ 0, (1 - 0.5), (2 - 1), (2.0 - 1.75) ];
assert_animation_offsets(anim, dist);
}, 'Test spacing on saturate' );
test(function(t) {
var anim =
createDiv(t).animate([ { filter: 'sepia(50%)'},
{ filter: 'none' }, // The default value is 0.
// Values of sepia over 100% are clamped to 1.
{ filter: 'sepia(2)' },
{ filter: 'sepia(75%)' } ],
{ spacing: 'paced(filter)' });
var dist = [ 0, 0.5, 1, (1.0 - 0.75) ];
assert_animation_offsets(anim, dist);
}, 'Test spacing on sepia' );
test(function(t) {
var anim =
createDiv(t).animate([ { filter: 'grayscale(50%) opacity(100%) blur(5px)' },
{ filter: 'none' },
// none filter: 'grayscale(0) opacity(1) blur(0px)'
{ filter: 'grayscale(100%) opacity(50%) blur(1px)' },
{ filter: 'grayscale(75%) opacity(50%)' } ],
{ spacing: 'paced(filter)' });
var dist = [ 0,
Math.sqrt(0.5 * 0.5 + 5 * 5),
Math.sqrt(1 * 1 + 0.5 * 0.5 + 1 * 1),
Math.sqrt(0.25 * 0.25 + 1 * 1) ];
assert_animation_offsets(anim, dist);
}, 'Test spacing on filter function lists' );
test(function(t) {
var anim =
createDiv(t).animate([ { filter: 'grayscale(50%) opacity(100%)' },
{ filter: 'opacity(10%) grayscale(50%)' },
{ filter: 'grayscale(100%) opacity(50%) blur(1px)' },
{ filter: 'grayscale(75%) opacity(50%)' } ],
{ spacing: 'paced(filter)' });
var dist = [ 0,
0,
0,
Math.sqrt(0.25 * 0.25 + 1 * 1) ];
assert_animation_offsets(anim, dist);
}, 'Test spacing on filter function lists' );
</script>
</body>

View file

@ -0,0 +1,152 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>Keyframe spacing tests on shapes</title>
<link rel="help" href="https://w3c.github.io/web-animations/#spacing-keyframes">
<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";
// Help function for testing the computed offsets by the distance array.
function assert_animation_offsets(anim, dist) {
const frames = anim.effect.getKeyframes();
const cumDist = dist.reduce( (prev, curr) => {
prev.push(prev.length == 0 ? curr : curr + prev[prev.length - 1]);
return prev;
}, []);
const total = cumDist[cumDist.length - 1];
for (var i = 0; i < frames.length; ++i) {
assert_equals(frames[i].computedOffset, cumDist[i] / total,
'computedOffset of frame ' + i);
}
}
test(function(t) {
var anim =
createDiv(t).animate([ { clipPath: 'circle(20px)' },
{ clipPath: 'ellipse(10px 20px)' },
{ clipPath: 'polygon(50px 0px, 100px 50px, ' +
' 50px 100px, 0px 50px)' },
{ clipPath: 'inset(20px round 10px)' } ],
{ spacing: 'paced(clip-path)' });
const frames = anim.effect.getKeyframes();
const slots = frames.length - 1;
for (var i = 0; i < frames.length; ++i) {
assert_equals(frames[i].computedOffset, i / slots,
'computedOffset of frame ' + i);
}
}, 'Test falling back to distribute spacing when using different basic shapes');
test(function(t) {
var anim =
createDiv(t).animate([ { clipPath: 'circle(10px)' },
{ clipPath: 'circle(20px) content-box' },
{ clipPath: 'circle(70px)' },
{ clipPath: 'circle(10px) padding-box' } ],
{ spacing: 'paced(clip-path)' });
const frames = anim.effect.getKeyframes();
const slots = frames.length - 1;
for (var i = 0; i < frames.length; ++i) {
assert_equals(frames[i].computedOffset, i / slots,
'computedOffset of frame ' + i);
}
}, 'Test falling back to distribute spacing when using different ' +
'reference boxes');
test(function(t) {
// 1st: circle(calc(20px) at calc(20px + 0%) calc(10px + 0%))
// 2nd: circle(calc(50px) at calc(10px + 0%) calc(10px + 0%))
// 3rd: circle(70px at calc(10px + 0%) calc(50px + 0%))
// 4th: circle(10px at calc(50px + 0%) calc(30px + 0%))
var anim =
createDiv(t).animate([ { clipPath: 'circle(calc(10px + 10px) ' +
' at 20px 10px)' },
{ clipPath: 'circle(calc(20px + 30px) ' +
' at 10px 10px)' },
{ clipPath: 'circle(70px at 10px 50px)' },
{ clipPath: 'circle(10px at 50px 30px)' } ],
{ spacing: 'paced(clip-path)' });
var dist = [ 0,
Math.sqrt(30 * 30 + 10 * 10),
Math.sqrt(20 * 20 + 40 * 40),
Math.sqrt(60 * 60 + 40 * 40 + 20 * 20) ];
assert_animation_offsets(anim, dist);
}, 'Test spacing on circle' );
test(function(t) {
// 1st: ellipse(20px calc(20px) at calc(0px + 50%) calc(0px + 50%))
// 2nd: ellipse(20px calc(50px) at calc(0px + 50%) calc(0px + 50%))
// 3rd: ellipse(30px 70px at calc(0px + 50%) calc(0px + 50%))
// 4th: ellipse(30px 10px at calc(0px + 50%) calc(0px + 50%))
var anim =
createDiv(t).animate([ { clipPath: 'ellipse(20px calc(10px + 10px))' },
{ clipPath: 'ellipse(20px calc(20px + 30px))' },
{ clipPath: 'ellipse(30px 70px)' },
{ clipPath: 'ellipse(30px 10px)' } ],
{ spacing: 'paced(clip-path)' });
var dist = [ 0,
Math.sqrt(30 * 30),
Math.sqrt(10 * 10 + 20 * 20),
Math.sqrt(60 * 60) ];
assert_animation_offsets(anim, dist);
}, 'Test spacing on ellipse' );
test(function(t) {
// 1st: polygon(nonzero, 50px 0px, 100px 50px, 50px 100px, 0px 50px)
// 2nd: polygon(nonzero, 40px 0px, 100px 70px, 10px 100px, 0px 70px)
// 3rd: polygon(nonzero, 100px 0px, 100px 100px, 10px 80px, 0px 50px)
// 4th: polygon(nonzero, 100px 100px, -10px 100px, 20px 80px, 20px 50px)
var anim =
createDiv(t).animate([ { clipPath: 'polygon(50px 0px, 100px 50px, ' +
' 50px 100px, 0px 50px)' },
{ clipPath: 'polygon(40px 0px, 100px 70px, ' +
' 10px 100px, 0px 70px)' },
{ clipPath: 'polygon(100px 0px, 100px 100px, ' +
' 10px 80px, 0px 50px)' },
{ clipPath: 'polygon(100px 100px, -10px 100px, ' +
' 20px 80px, 20px 50px)' } ],
{ spacing: 'paced(clip-path)' });
var dist = [ 0,
Math.sqrt(10 * 10 + 20 * 20 + 40 * 40 + 20 * 20),
Math.sqrt(60 * 60 + 30 * 30 + 20 * 20 + 20 * 20),
Math.sqrt(100 * 100 + 110 * 110 + 10 * 10 + 20 * 20) ];
assert_animation_offsets(anim, dist);
}, 'Test spacing on polygon' );
test(function(t) {
// Note: Rounding corners are 4 CSS pair values and
// each pair has x & y components.
// 1st: inset(5px 5px 5px 5px round 40px 30px 20px 5px / 40px 30px 20px 5px)
// 2nd: inset(10px 5px 10px 5px round 50px 60px / 50px 60px)
// 3rd: inset(40px 40px 40px 40px round 10px / 10px)
// 4th: inset(30px 40px 30px 40px round 20px / 20px)
var anim =
createDiv(t).animate([ { clipPath: 'inset(5px 5px 5px 5px ' +
' round 40px 30px 20px 5px)' },
{ clipPath: 'inset(10px 5px round 50px 60px)' },
{ clipPath: 'inset(40px 40px round 10px)' },
{ clipPath: 'inset(30px 40px round 20px)' } ],
{ spacing: 'paced(clip-path)' });
var dist = [ 0,
Math.sqrt(5 * 5 * 2 + (50 - 40) * (50 - 40) * 2 +
(60 - 30) * (60 - 30) * 2 +
(50 - 20) * (50 - 20) * 2 +
(60 - 5) * (60 - 5) * 2),
Math.sqrt(30 * 30 * 2 + 35 * 35 * 2 + (50 - 10) * (50 - 10) * 4 +
(60 - 10) * (60 - 10) * 4),
Math.sqrt(10 * 10 * 2 + (20 - 10) * (20 - 10) * 8) ];
assert_animation_offsets(anim, dist);
}, 'Test spacing on inset' );
</script>
</body>

View file

@ -0,0 +1,242 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>Keyframe spacing tests on transform</title>
<link rel="help" href="https://w3c.github.io/web-animations/#spacing-keyframes">
<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";
const pi = Math.PI;
const cos = Math.cos;
const sin = Math.sin;
const tan = Math.tan;
const sqrt = Math.sqrt;
// Help function for testing the computed offsets by the distance array.
function assert_animation_offsets(anim, dist) {
const epsilon = 0.00000001;
const frames = anim.effect.getKeyframes();
const cumDist = dist.reduce( (prev, curr) => {
prev.push(prev.length == 0 ? curr : curr + prev[prev.length - 1]);
return prev;
}, []);
const total = cumDist[cumDist.length - 1];
for (var i = 0; i < frames.length; ++i) {
assert_approx_equals(frames[i].computedOffset, cumDist[i] / total,
epsilon, 'computedOffset of frame ' + i);
}
}
function getAngleDist(rotate1, rotate2) {
function quaternion(axis, angle) {
var x = axis[0] * sin(angle/2.0);
var y = axis[1] * sin(angle/2.0);
var z = axis[2] * sin(angle/2.0);
var w = cos(angle/2.0);
return { 'x': x, 'y': y, 'z': z, 'w': w };
}
var q1 = quaternion(rotate1.axis, rotate1.angle);
var q2 = quaternion(rotate2.axis, rotate2.angle);
var dotProduct = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w;
return 2.0 * Math.acos(dotProduct);
}
function createMatrix(elements, Is3D) {
return (Is3D ? "matrix3d" : "matrix") + "(" + elements.join() + ")";
}
test(function(t) {
var anim = createDiv(t).animate([ { transform: "none" },
{ transform: "translate(-20px)" },
{ transform: "translate(100px)" },
{ transform: "translate(50px)"} ],
{ spacing: "paced(transform)" });
assert_animation_offsets(anim, [ 0, 20, 120, 50 ]);
}, 'Test spacing on translate' );
test(function(t) {
var anim =
createDiv(t).animate([ { transform: "none" },
{ transform: "translate3d(-20px, 10px, 100px)" },
{ transform: "translate3d(100px, 200px, 50px)" },
{ transform: "translate(50px, -10px)"} ],
{ spacing: "paced(transform)" });
var dist = [ 0,
sqrt(20 * 20 + 10 * 10 + 100 * 100),
sqrt(120 * 120 + 190 * 190 + 50 * 50),
sqrt(50 * 50 + 210 * 210 + 50 * 50) ];
assert_animation_offsets(anim, dist);
}, 'Test spacing on translate3d' );
test(function(t) {
var anim = createDiv(t).animate([ { transform: "scale(0.5)" },
{ transform: "scale(4.5)" },
{ transform: "scale(2.5)" },
{ transform: "none"} ],
{ spacing: "paced(transform)" });
assert_animation_offsets(anim, [ 0, 4.0, 2.0, 1.5 ]);
}, 'Test spacing on scale' );
test(function(t) {
var anim = createDiv(t).animate([ { transform: "scale(0.5, 0.5)" },
{ transform: "scale3d(4.5, 5.0, 2.5)" },
{ transform: "scale3d(2.5, 1.0, 2.0)" },
{ transform: "scale3d(1, 0.5, 1.0)"} ],
{ spacing:"paced(transform)" });
var dist = [ 0,
sqrt(4.0 * 4.0 + 4.5 * 4.5 + 1.5 * 1.5),
sqrt(2.0 * 2.0 + 4.0 * 4.0 + 0.5 * 0.5),
sqrt(1.5 * 1.5 + 0.5 * 0.5 + 1.0 * 1.0) ];
assert_animation_offsets(anim, dist);
}, 'Test spacing on scale3d' );
test(function(t) {
var anim = createDiv(t).animate([ { transform: "rotate(60deg)" },
{ transform: "none" },
{ transform: "rotate(720deg)" },
{ transform: "rotate(-360deg)"} ],
{ spacing: "paced(transform)" });
assert_animation_offsets(anim, [ 0, 60, 720, 1080 ]);
}, 'Test spacing on rotate' );
test(function(t) {
var anim = createDiv(t).animate([ { transform: "rotate3d(1,0,0,60deg)" },
{ transform: "rotate3d(1,0,0,70deg)" },
{ transform: "rotate3d(0,0,1,-110deg)" },
{ transform: "rotate3d(1,0,0,219deg)"} ],
{ spacing: "paced(transform)" });
var dist = [ 0,
getAngleDist({ axis: [1,0,0], angle: 60 * pi / 180 },
{ axis: [1,0,0], angle: 70 * pi / 180 }),
getAngleDist({ axis: [0,1,0], angle: 70 * pi / 180 },
{ axis: [0,0,1], angle: -110 * pi / 180 }),
getAngleDist({ axis: [0,0,1], angle: -110 * pi / 180 },
{ axis: [1,0,0], angle: 219 * pi / 180 }) ];
assert_animation_offsets(anim, dist);
}, 'Test spacing on rotate3d' );
test(function(t) {
var anim = createDiv(t).animate([ { transform: "skew(60deg)" },
{ transform: "none" },
{ transform: "skew(-90deg)" },
{ transform: "skew(90deg)"} ],
{ spacing: "paced(transform)" });
assert_animation_offsets(anim, [ 0, 60, 90, 180 ]);
}, 'Test spacing on skew' );
test(function(t) {
var anim = createDiv(t).animate([ { transform: "skew(60deg, 30deg)" },
{ transform: "none" },
{ transform: "skew(-90deg, 60deg)" },
{ transform: "skew(90deg, 60deg)"} ],
{ spacing: "paced(transform)" });
var dist = [ 0,
sqrt(60 * 60 + 30 * 30),
sqrt(90 * 90 + 60 * 60),
sqrt(180 * 180 + 0) ];
assert_animation_offsets(anim, dist);
}, 'Test spacing on skew along both X and Y' );
test(function(t) {
// We calculate the distance of two perspective functions by converting them
// into two matrix3ds, and then do matrix decomposition to get two
// perspective vectors, so the equivalent perspective vectors are:
// perspective 1: (0, 0, -1/128, 1);
// perspective 2: (0, 0, -1/infinity = 0, 1);
// perspective 3: (0, 0, -1/1024, 1);
// perspective 4: (0, 0, -1/32, 1);
var anim = createDiv(t).animate([ { transform: "perspective(128px)" },
{ transform: "none" },
{ transform: "perspective(1024px)" },
{ transform: "perspective(32px)"} ],
{ spacing: "paced(transform)" });
assert_animation_offsets(anim, [ 0, 1/128, 1/1024, 1/32 - 1/1024 ]);
}, 'Test spacing on perspective' );
test(function(t) {
var anim =
createDiv(t).animate([ { transform: "none" },
{ transform: "rotate(180deg) translate(0px)" },
{ transform: "rotate(180deg) translate(1000px)" },
{ transform: "rotate(360deg) translate(1000px)"} ],
{ spacing: "paced(transform)" });
var dist = [ 0,
sqrt(pi * pi + 0),
sqrt(1000 * 1000),
sqrt(pi * pi + 0) ];
assert_animation_offsets(anim, dist);
}, 'Test spacing on matched transform lists' );
test(function(t) {
// matrix1 => translate(100px, 50px), skewX(60deg).
// matrix2 => translate(1000px), rotate(180deg).
// matrix3 => translate(1000px), scale(1.5, 0.7).
const matrix1 = createMatrix([ 1, 0, tan(pi/4.0), 1, 100, 50 ]);
const matrix2 = createMatrix([ cos(pi), sin(pi),
-sin(pi), cos(pi),
1000, 0 ]);
const matrix3 = createMatrix([ 1.5, 0, 0, 0.7, 1000, 0 ]);
var anim = createDiv(t).animate([ { transform: "none" },
{ transform: matrix1 },
{ transform: matrix2 },
{ transform: matrix3 } ],
{ spacing: "paced(transform)" });
var dist = [ 0,
sqrt(100 * 100 + 50 * 50 + pi/4 * pi/4),
sqrt(900 * 900 + 50 * 50 + pi * pi + pi/4 * pi/4),
sqrt(pi * pi + 0.5 * 0.5 + 0.3 * 0.3) ];
assert_animation_offsets(anim, dist);
}, 'Test spacing on matrix' );
test(function(t) {
// matrix1 => translate3d(100px, 50px, -10px), skew(60deg).
// matrix2 => translate3d(1000px, 0, 0), rotate3d(1, 0, 0, 180deg).
// matrix3 => translate3d(1000px, 0, 0), scale3d(1.5, 0.7, 2.2).
const matrix1 = createMatrix([ 1, 0, 0, 0,
tan(pi/4.0), 1, 0, 0,
0, 0, 1, 0,
100, 50, -10, 1 ], true);
const matrix2 = createMatrix([ 1, 0, 0, 0,
0, cos(pi), sin(pi), 0,
0, -sin(pi), cos(pi), 0,
1000, 0, 0, 1 ], true);
const matrix3 = createMatrix([ 1.5, 0, 0, 0,
0, 0.7, 0, 0,
0, 0, 2.2, 0,
1000, 0, 0, 1 ], true);
var anim = createDiv(t).animate([ { transform: "none" },
{ transform: matrix1 },
{ transform: matrix2 },
{ transform: matrix3 } ],
{ spacing: "paced(transform)" });
var dist = [ 0,
sqrt(100 * 100 + 50 * 50 + 10 * 10 + pi/4 * pi/4),
sqrt(900 * 900 + 50 * 50 + 10 * 10 + pi/4 * pi/4 + pi * pi),
sqrt(0.5 * 0.5 + 0.3 * 0.3 + 1.2 * 1.2 + pi * pi) ];
assert_animation_offsets(anim, dist);
}, 'Test spacing on matrix3d' );
test(function(t) {
var anim =
createDiv(t).animate([ { transform: "none" },
{ transform: "translate(100px, 50px) skew(45deg)" },
{ transform: "translate(1000px) " +
"rotate3d(1, 0, 0, 180deg)" },
{ transform: "translate(1000px) " +
"scale3d(2.5, 0.5, 0.7)" } ],
{ spacing: "paced(transform)" });
var dist = [ 0,
sqrt(100 * 100 + 50 * 50 + pi/4 * pi/4),
sqrt(900 * 900 + 50 * 50 + pi/4 * pi/4 + pi * pi),
sqrt(1.5 * 1.5 + 0.5 * 0.5 + 0.3 * 0.3 + pi * pi) ];
assert_animation_offsets(anim, dist);
}, 'Test spacing on mismatched transform list' );
</script>
</body>

View file

@ -1,569 +0,0 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>Tests for animation types</title>
<link rel="help" href="https://w3c.github.io/web-animations/#animation-types">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../../testcommon.js"></script>
<style>
html {
font-size: 10px;
}
</style>
<body>
<div id="log"></div>
<script>
"use strict";
var gCSSProperties = {
"align-content": {
// https://drafts.csswg.org/css-align/#propdef-align-content
tests: [
discrete("flex-start", "flex-end")
]
},
"align-items": {
// https://drafts.csswg.org/css-align/#propdef-align-items
tests: [
discrete("flex-start", "flex-end")
]
},
"align-self": {
// https://drafts.csswg.org/css-align/#propdef-align-self
tests: [
discrete("flex-start", "flex-end")
]
},
"clip-rule": {
// https://drafts.fxtf.org/css-masking-1/#propdef-clip-rule
tests: [
discrete("evenodd", "nonzero")
]
},
"color-interpolation": {
// https://svgwg.org/svg2-draft/painting.html#ColorInterpolationProperty
tests: [
discrete("linearRGB", "auto")
]
},
"color-interpolation-filters": {
// https://drafts.fxtf.org/filters-1/#propdef-color-interpolation-filters
tests: [
discrete("sRGB", "linearRGB")
]
},
"dominant-baseline": {
// https://drafts.csswg.org/css-inline/#propdef-dominant-baseline
tests: [
discrete("ideographic", "alphabetic")
]
},
"fill-rule": {
// https://svgwg.org/svg2-draft/painting.html#FillRuleProperty
tests: [
discrete("evenodd", "nonzero")
]
},
"flex-basis": {
// https://drafts.csswg.org/css-flexbox/#propdef-flex-basis
tests: [
lengthPercentageOrCalc(),
discrete("auto", "10px")
]
},
"flex-direction": {
// https://drafts.csswg.org/css-flexbox/#propdef-flex-direction
tests: [
discrete("row", "row-reverse")
]
},
"flex-grow": {
// https://drafts.csswg.org/css-flexbox/#flex-grow-property
tests: [
positiveNumber()
]
},
"flex-shrink": {
// https://drafts.csswg.org/css-flexbox/#propdef-flex-shrink
tests: [
positiveNumber()
]
},
"flex-wrap": {
// https://drafts.csswg.org/css-flexbox/#propdef-flex-wrap
tests: [
discrete("nowrap", "wrap")
]
},
"font-style": {
// https://drafts.csswg.org/css-fonts/#propdef-font-style
tests: [
discrete("italic", "oblique")
]
},
"image-rendering": {
// https://drafts.csswg.org/css-images/#propdef-image-rendering
tests: [
discrete("optimizeQuality", "pixelated")
]
},
"justify-content": {
// https://drafts.csswg.org/css-align/#propdef-justify-content
tests: [
discrete("baseline", "last-baseline")
]
},
"justify-items": {
// https://drafts.csswg.org/css-align/#propdef-justify-items
tests: [
discrete("baseline", "last-baseline")
]
},
"justify-self": {
// https://drafts.csswg.org/css-align/#propdef-justify-self
tests: [
discrete("baseline", "last-baseline")
]
},
"mask-type": {
// https://drafts.fxtf.org/css-masking-1/#propdef-mask-type
tests: [
discrete("alpha", "luminance")
]
},
"order": {
// https://drafts.csswg.org/css-flexbox/#propdef-order
tests: [
integer()
]
},
"pointer-events": {
// https://svgwg.org/svg2-draft/interact.html#PointerEventsProperty
tests: [
discrete("fill", "none")
]
},
"ruby-align": {
// https://drafts.csswg.org/css-ruby-1/#propdef-ruby-align
tests: [
discrete("start", "center")
]
},
"ruby-position": {
// https://drafts.csswg.org/css-ruby-1/#propdef-ruby-position
tests: [
discrete("under", "over")
],
tagName: "ruby"
},
"shape-rendering": {
// https://svgwg.org/svg2-draft/painting.html#ShapeRenderingProperty
tests: [
discrete("optimizeSpeed", "crispEdges")
]
},
"stroke-linecap": {
// https://svgwg.org/svg2-draft/painting.html#StrokeLinecapProperty
tests: [
discrete("round", "square")
]
},
"stroke-linejoin": {
// https://svgwg.org/svg2-draft/painting.html#StrokeLinejoinProperty
tests: [
discrete("round", "miter")
],
tagName: "rect"
},
"text-anchor": {
// https://svgwg.org/svg2-draft/text.html#TextAnchorProperty
tests: [
discrete("middle", "end")
]
},
"text-combine-upright": {
// https://drafts.csswg.org/css-writing-modes-3/#propdef-text-combine-upright
tests: [
discrete("all", "digits")
]
},
"text-decoration-line": {
// https://drafts.csswg.org/css-text-decor-3/#propdef-text-decoration-line
tests: [
discrete("underline", "overline")
]
},
"text-orientation": {
// https://drafts.csswg.org/css-writing-modes-3/#propdef-text-orientation
tests: [
discrete("upright", "sideways")
]
},
"text-rendering": {
// https://svgwg.org/svg2-draft/painting.html#TextRenderingProperty
tests: [
discrete("optimizeSpeed", "optimizeLegibility")
]
},
"vector-effect": {
// https://svgwg.org/svg2-draft/coords.html#VectorEffectProperty
tests: [
discrete("none", "non-scaling-stroke")
]
},
"visibility": {
// https://drafts.csswg.org/css2/visufx.html#propdef-visibility
tests: [
visibility()
]
},
"word-break": {
// https://drafts.csswg.org/css-text-3/#propdef-word-break
tests: [
discrete("keep-all", "break-all")
]
},
"writing-mode": {
// https://drafts.csswg.org/css-writing-modes-3/#propdef-writing-mode
tests: [
discrete("vertical-rl", "sideways-rl")
]
},
}
for (var property in gCSSProperties) {
if (!isSupported(property)) {
continue;
}
var testData = gCSSProperties[property];
testData.tests.forEach(function(testFunction) {
testFunction(property, testData);
});
}
function discrete(from, to) {
return function(property, options) {
test(function(t) {
var idlName = propertyToIDL(property);
var keyframes = {};
keyframes[idlName] = [from, to];
var target = createElement(t, options.tagName);
var animation = target.animate(keyframes,
{ duration: 1000, fill: "both" });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: from.toLowerCase() },
{ time: 499, expected: from.toLowerCase() },
{ time: 500, expected: to.toLowerCase() },
{ time: 1000, expected: to.toLowerCase() }]);
}, property + " uses discrete animation when animating between '"
+ from + "' and '" + to + "' with linear easing");
test(function(t) {
// Easing: http://cubic-bezier.com/#.68,0,1,.01
// With this curve, we don't reach the 50% point until about 95% of
// the time has expired.
var idlName = propertyToIDL(property);
var keyframes = {};
keyframes[idlName] = [from, to];
var target = createElement(t, options.tagName);
var animation = target.animate(keyframes,
{ duration: 1000, fill: "both",
easing: "cubic-bezier(0.68,0,1,0.01)" });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: from.toLowerCase() },
{ time: 940, expected: from.toLowerCase() },
{ time: 960, expected: to.toLowerCase() }]);
}, property + " uses discrete animation when animating between '"
+ from + "' and '" + to + "' with effect easing");
test(function(t) {
// Easing: http://cubic-bezier.com/#.68,0,1,.01
// With this curve, we don't reach the 50% point until about 95% of
// the time has expired.
var idlName = propertyToIDL(property);
var keyframes = {};
keyframes[idlName] = [from, to];
keyframes.easing = "cubic-bezier(0.68,0,1,0.01)";
var target = createElement(t, options.tagName);
var animation = target.animate(keyframes,
{ duration: 1000, fill: "both" });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: from.toLowerCase() },
{ time: 940, expected: from.toLowerCase() },
{ time: 960, expected: to.toLowerCase() }]);
}, property + " uses discrete animation when animating between '"
+ from + "' and '" + to + "' with keyframe easing");
}
}
function length() {
return function(property, options) {
test(function(t) {
var idlName = propertyToIDL(property);
var keyframes = {};
keyframes[idlName] = ["10px", "50px"];
var target = createElement(t, options.tagName);
var animation = target.animate(keyframes,
{ duration: 1000, fill: "both" });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: "10px" },
{ time: 500, expected: "30px" },
{ time: 1000, expected: "50px" }]);
}, property + " supports animating as a length");
test(function(t) {
var idlName = propertyToIDL(property);
var keyframes = {};
keyframes[idlName] = ["1rem", "5rem"];
var target = createElement(t, options.tagName);
var animation = target.animate(keyframes,
{ duration: 1000, fill: "both" });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: "10px" },
{ time: 500, expected: "30px" },
{ time: 1000, expected: "50px" }]);
}, property + " supports animating as a length of rem");
}
}
function percentage() {
return function(property, options) {
test(function(t) {
var idlName = propertyToIDL(property);
var keyframes = {};
keyframes[idlName] = ["10%", "50%"];
var target = createElement(t, options.tagName);
var animation = target.animate(keyframes,
{ duration: 1000, fill: "both" });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: "10%" },
{ time: 500, expected: "30%" },
{ time: 1000, expected: "50%" }]);
}, property + " supports animating as a percentage");
}
}
function integer() {
return function(property, options) {
test(function(t) {
var idlName = propertyToIDL(property);
var keyframes = {};
keyframes[idlName] = [-2, 2];
var target = createElement(t, options.tagName);
var animation = target.animate(keyframes,
{ duration: 1000, fill: "both" });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: "-2" },
{ time: 500, expected: "0" },
{ time: 1000, expected: "2" }]);
}, property + " supports animating as an integer");
}
}
function positiveNumber() {
return function(property, options) {
test(function(t) {
var idlName = propertyToIDL(property);
var keyframes = {};
keyframes[idlName] = [1.1, 1.5];
var target = createElement(t, options.tagName);
var animation = target.animate(keyframes,
{ duration: 1000, fill: "both" });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: "1.1" },
{ time: 500, expected: "1.3" },
{ time: 1000, expected: "1.5" }]);
}, property + " supports animating as a positive number");
}
}
function lengthPercentageOrCalc() {
return function(property, options) {
length()(property, options);
percentage()(property, options);
test(function(t) {
var idlName = propertyToIDL(property);
var keyframes = {};
keyframes[idlName] = ["10px", "20%"];
var target = createElement(t, options.tagName);
var animation = target.animate(keyframes,
{ duration: 1000, fill: "both" });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: "10px" },
{ time: 500, expected: "calc(5px + 10%)" },
{ time: 1000, expected: "20%" }]);
}, property + " supports animating as combination units 'px' and '%'");
test(function(t) {
var idlName = propertyToIDL(property);
var keyframes = {};
keyframes[idlName] = ["10%", "2em"];
var target = createElement(t, options.tagName);
var animation = target.animate(keyframes,
{ duration: 1000, fill: "both" });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: "10%" },
{ time: 500, expected: "calc(10px + 5%)" },
{ time: 1000, expected: "20px" }]);
}, property + " supports animating as combination units '%' and 'em'");
test(function(t) {
var idlName = propertyToIDL(property);
var keyframes = {};
keyframes[idlName] = ["1em", "2rem"];
var target = createElement(t, options.tagName);
var animation = target.animate(keyframes,
{ duration: 1000, fill: "both" });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: "10px" },
{ time: 500, expected: "15px" },
{ time: 1000, expected: "20px" }]);
}, property + " supports animating as combination units 'em' and 'rem'");
test(function(t) {
var idlName = propertyToIDL(property);
var keyframes = {};
keyframes[idlName] = ["10px", "calc(1em + 20%)"];
var target = createElement(t, options.tagName);
var animation = target.animate(keyframes,
{ duration: 1000, fill: "both" });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: "10px" },
{ time: 500, expected: "calc(10px + 10%)" },
{ time: 1000, expected: "calc(10px + 20%)" }]);
}, property + " supports animating as combination units 'px' and 'calc'");
test(function(t) {
var idlName = propertyToIDL(property);
var keyframes = {};
keyframes[idlName] = ["calc(10px + 10%)", "calc(1em + 1rem + 20%)"];
var target = createElement(t, options.tagName);
var animation = target.animate(keyframes,
{ duration: 1000, fill: "both" });
testAnimationSamples(animation, idlName,
[{ time: 0,
expected: "calc(10px + 10%)" },
{ time: 500,
expected: "calc(15px + 15%)" },
{ time: 1000,
expected: "calc(20px + 20%)" }]);
}, property + " supports animating as a calc");
}
}
function visibility() {
return function(property, options) {
test(function(t) {
var idlName = propertyToIDL(property);
var keyframes = {};
keyframes[idlName] = ["visible", "hidden"];
var target = createElement(t, options.tagName);
var animation = target.animate(keyframes,
{ duration: 1000, fill: "both" });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: "visible" },
{ time: 999, expected: "visible" },
{ time: 1000, expected: "hidden" }]);
}, property + " uses visibility animation when animating "
+ "from 'visible' to 'hidden'");
test(function(t) {
var idlName = propertyToIDL(property);
var keyframes = {};
keyframes[idlName] = ["hidden", "visible"];
var target = createElement(t, options.tagName);
var animation = target.animate(keyframes,
{ duration: 1000, fill: "both" });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: "hidden" },
{ time: 1, expected: "visible" },
{ time: 1000, expected: "visible" }]);
}, property + " uses visibility animation when animating "
+ "from 'hidden' to 'visible'");
test(function(t) {
var idlName = propertyToIDL(property);
var keyframes = {};
keyframes[idlName] = ["hidden", "collapse"];
var target = createElement(t, options.tagName);
var animation = target.animate(keyframes,
{ duration: 1000, fill: "both" });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: "hidden" },
{ time: 499, expected: "hidden" },
{ time: 500, expected: "collapse" },
{ time: 1000, expected: "collapse" }]);
}, property + " uses visibility animation when animating "
+ "from 'hidden' to 'collapse'");
test(function(t) {
// Easing: http://cubic-bezier.com/#.68,-.55,.26,1.55
// With this curve, the value is less than 0 till about 34%
// also more than 1 since about 63%
var idlName = propertyToIDL(property);
var keyframes = {};
keyframes[idlName] = ["visible", "hidden"];
var target = createElement(t, options.tagName);
var animation =
target.animate(keyframes,
{ duration: 1000, fill: "both",
easing: "cubic-bezier(0.68, -0.55, 0.26, 1.55)" });
testAnimationSamples(animation, idlName,
[{ time: 0, expected: "visible" },
{ time: 1, expected: "visible" },
{ time: 330, expected: "visible" },
{ time: 340, expected: "visible" },
{ time: 620, expected: "visible" },
{ time: 630, expected: "hidden" },
{ time: 1000, expected: "hidden" }]);
}, property + " uses visibility animation when animating "
+ "from 'visible' to 'hidden' with easeInOutBack easing");
}
}
function testAnimationSamples(animation, idlName, testSamples) {
var target = animation.effect.target;
testSamples.forEach(function(testSample) {
animation.currentTime = testSample.time;
assert_equals(getComputedStyle(target)[idlName], testSample.expected,
"The value should be " + testSample.expected +
" at " + testSample.time + "ms");
});
}
function isSupported(property) {
var testKeyframe = new TestKeyframe(propertyToIDL(property));
try {
// Since TestKeyframe returns 'undefined' for |property|,
// the KeyframeEffect constructor will throw
// if the string "undefined" is not a valid value for the property.
new KeyframeEffect(null, testKeyframe);
} catch(e) {}
return testKeyframe.propAccessCount !== 0;
}
function TestKeyframe(testProp) {
var _propAccessCount = 0;
Object.defineProperty(this, testProp, {
get: function() { _propAccessCount++; },
enumerable: true
});
Object.defineProperty(this, 'propAccessCount', {
get: function() { return _propAccessCount; }
});
}
function propertyToIDL(property) {
// https://w3c.github.io/web-animations/#animation-property-name-to-idl-attribute-name
if (property === "float") {
return "cssFloat";
}
return property.replace(/-[a-z]/gi,
function (str) {
return str.substr(1).toUpperCase(); });
}
</script>

View file

@ -0,0 +1,85 @@
<!doctype html>
<meta charset=utf-8>
<title>Test for effect composition</title>
<link rel="help" href="https://w3c.github.io/web-animations/#effect-composition">
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src="../../testcommon.js"></script>
<div id="log"></div>
<script>
'use strict';
[ 'accumulate', 'add' ].forEach(function(composite) {
test(function(t) {
var div = createDiv(t);
div.style.marginLeft = '10px';
var anim =
div.animate({ marginLeft: ['0px', '10px'], composite }, 100);
anim.currentTime = 50;
assert_equals(getComputedStyle(div).marginLeft, '15px',
'Animated margin-left style at 50%');
}, composite + ' onto the base value');
test(function(t) {
var div = createDiv(t);
var anims = [];
anims.push(div.animate({ marginLeft: ['10px', '20px'],
composite: 'replace' },
100));
anims.push(div.animate({ marginLeft: ['0px', '10px'],
composite },
100));
anims.forEach(function(anim) {
anim.currentTime = 50;
});
assert_equals(getComputedStyle(div).marginLeft, '20px',
'Animated style at 50%');
}, composite + ' onto an underlying animation value');
test(function(t) {
var div = createDiv(t);
div.style.marginLeft = '10px';
var anim =
div.animate([{ marginLeft: '10px', composite },
{ marginLeft: '30px', composite: 'replace' }],
100);
anim.currentTime = 50;
assert_equals(getComputedStyle(div).marginLeft, '25px',
'Animated style at 50%');
}, 'Composite when mixing ' + composite + ' and replace');
test(function(t) {
var div = createDiv(t);
div.style.marginLeft = '10px';
var anim =
div.animate([{ marginLeft: '10px', composite: 'replace' },
{ marginLeft: '20px' }],
{ duration: 100 , composite });
anim.currentTime = 50;
assert_equals(getComputedStyle(div).marginLeft, '20px',
'Animated style at 50%');
}, composite + ' specified on a keyframe overrides the composite mode of ' +
'the effect');
test(function(t) {
var div = createDiv(t);
div.style.marginLeft = '10px';
var anim =
div.animate([{ marginLeft: '10px', composite: 'replace' },
{ marginLeft: '20px' }],
100);
anim.effect.composite = composite;
anim.currentTime = 50; // (10 + (10 + 20)) * 0.5
assert_equals(getComputedStyle(div).marginLeft, '20px',
'Animated style at 50%');
}, 'unspecified composite mode on a keyframe is overriden by setting ' +
composite + ' of the effect');
});
</script>

View file

@ -66,30 +66,17 @@ async_test(function(t) {
var div = createDiv(t);
var anim = div.animate({ opacity: [ 0, 1 ] },
{ duration: 100000, endDelay: 30000 });
var finishedTimelineTime;
anim.finished.then(function() {
finishedTimelineTime = anim.timeline.currentTime;
});
var receivedEvents = [];
anim.onfinish = function(event) {
receivedEvents.push(event);
}
anim.ready.then(function() {
anim.currentTime = 110000; // during endDelay
anim.onfinish = t.step_func(function(event) {
assert_unreached('onfinish event should not be fired during endDelay');
});
return waitForAnimationFrames(2);
}).then(t.step_func(function() {
assert_equals(receivedEvents.length, 0,
'onfinish event is should not be fired' +
'when currentTime is during endDelay');
anim.onfinish = t.step_func(function(event) {
t.done();
});
anim.currentTime = 130000; // after endTime
return waitForAnimationFrames(2);
})).then(t.step_func_done(function() {
assert_equals(receivedEvents.length, 1, 'length of array should be one');
assert_equals(receivedEvents[0].timelineTime, finishedTimelineTime,
'receivedEvents[0].timelineTime should equal to the animation timeline '
+ 'when finished promise is resolved');
}));
}, 'onfinish event is fired currentTime is after endTime');

View file

@ -0,0 +1,47 @@
<!doctype html>
<meta charset=utf-8>
<title>KeyframeEffect.composite tests</title>
<link rel="help"
href="https://w3c.github.io/web-animations/#dom-keyframeeffect-composite">
<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_equals(anim.effect.composite, 'replace',
'The default value should be replace');
}, 'Default value');
test(function(t) {
var anim = createDiv(t).animate(null);
anim.effect.composite = 'add';
assert_equals(anim.effect.composite, 'add',
'The effect composite value should be replaced');
}, 'Change composite value');
test(function(t) {
var anim = createDiv(t).animate({ left: '10px' });
anim.effect.composite = 'add';
var keyframes = anim.effect.getKeyframes();
assert_equals(keyframes[0].composite, undefined,
'unspecified keyframe composite value should be absent even ' +
'if effect composite is set');
}, 'Unspecified keyframe composite value when setting effect composite');
test(function(t) {
var anim = createDiv(t).animate({ left: '10px', composite: 'replace' });
anim.effect.composite = 'add';
var keyframes = anim.effect.getKeyframes();
assert_equals(keyframes[0].composite, 'replace',
'specified keyframe composite value should not be overridden ' +
'by setting effect composite');
}, 'Specified keyframe composite value when setting effect composite');
</script>

View file

@ -110,7 +110,7 @@ test(function(t) {
var effect = new KeyframeEffectReadOnly(target, {
left: ["10px", "20px"]
}, { composite: composite });
assert_equals(effect.getKeyframes()[0].composite, composite,
assert_equals(effect.getKeyframes()[0].composite, undefined,
"resulting composite for '" + composite + "'");
});
gBadCompositeValueTests.forEach(function(composite) {
@ -120,8 +120,8 @@ test(function(t) {
}, { composite: composite });
});
});
}, "composite values are parsed correctly when passed to the " +
"KeyframeEffectReadOnly constructor in KeyframeTimingOptions");
}, "composite value is absent if the composite operation specified on the " +
"keyframe effect is being used");
gPropertyIndexedKeyframesTests.forEach(function(subtest) {
test(function(t) {

View file

@ -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>

View file

@ -9,6 +9,26 @@
<script>
'use strict';
test(function(t) {
var div = createDiv(t);
var anim =
div.animate({ alignContent: ['flex-start', 'flex-end'] },
{ duration: 100 * MS_PER_SEC,
easing: 'linear',
iterations: 10,
iterationComposite: 'accumulate' });
anim.currentTime = anim.effect.timing.duration / 2;
assert_equals(getComputedStyle(div).alignContent, 'flex-end',
'Animated align-content style at 50s of the first iteration');
anim.currentTime = anim.effect.timing.duration * 2;
assert_equals(getComputedStyle(div).alignContent, 'flex-start',
'Animated align-content style at 0s of the third iteration');
anim.currentTime += anim.effect.timing.duration / 2;
assert_equals(getComputedStyle(div).alignContent, 'flex-end',
'Animated align-content style at 50s of the third iteration');
}, 'iterationComposite of discrete type animation (align-content)');
test(function(t) {
var div = createDiv(t);
var anim =
@ -541,9 +561,35 @@ test(function(t) {
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: ['matrix(2, 0, 0, 2, 0, 0)',
'matrix(3, 0, 0, 3, 30, 0)'] },
{ 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)',
'Animated transform of matrix function at 50s of the first iteration');
anim.currentTime = anim.effect.timing.duration * 2;
assert_equals(getComputedStyle(div).transform,
// scale(2) + (scale(3-1)*2) + translateX(30px)*2
'matrix(6, 0, 0, 6, 60, 0)',
'Animated transform of matrix function at 0s of the third iteration');
anim.currentTime += anim.effect.timing.duration / 2;
assert_equals(getComputedStyle(div).transform,
// from: matrix(6, 0, 0, 6, 60, 0)
// to: matrix(7, 0, 0, 7, 90, 0)
// = scale(3) + (scale(3-1)*2) + translateX(30px)*3
'matrix(6.5, 0, 0, 6.5, 75, 0)',
'Animated transform of matrix function at 50s of the third iteration');
}, 'iterationComposite of transform of matrix function');
test(function(t) {
var div = createDiv(t);
var anim =
div.animate({ transform: ['translateX(0px) scale(2)',
'scale(3) translateX(10px)'] },
@ -555,25 +601,29 @@ test(function(t) {
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
// Interpolate between matrix(2, 0, 0, 2, 0, 0) = translateX(0px) scale(2)
// and matrix(3, 0, 0, 3, 30, 0) = scale(3) translateX(10px)
'matrix(2.5, 0, 0, 2.5, 15, 0)',
'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)
// 'from' and 'to' value are mismatched, so accumulate
// matrix(2, 0, 0, 2, 0, 0) onto matrix(3, 0, 0, 3, 30, 0) * 2
// = scale(2) + (scale(3-1)*2) + translateX(30px)*2
'matrix(6, 0, 0, 6, 60, 0)',
'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)
// Interpolate between matrix(6, 0, 0, 6, 60, 0)
// and matrix(7, 0, 0, 7, 210, 0) = scale(7) translate(30px)
'matrix(6.5, 0, 0, 6.5, 135, 0)',
'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)
// other pair of the list, we don't fill any missing functions at all.
var anim =
div.animate({ transform: ['translateX(0px)',
'scale(2) translateX(10px)'] },
@ -585,17 +635,110 @@ test(function(t) {
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
// Interpolate between matrix(1, 0, 0, 1, 0, 0) = translateX(0px)
// and matrix(2, 0, 0, 2, 20, 0) = scale(2) translateX(10px)
'matrix(1.5, 0, 0, 1.5, 10, 0)',
'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)
// 'from' and 'to' value are mismatched, so accumulate
// matrix(1, 0, 0, 1, 0, 0) onto matrix(2, 0, 0, 2, 20, 0) * 2
// = scale(1) + (scale(2-1)*2) + translateX(20px)*2
'matrix(3, 0, 0, 3, 40, 0)',
'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)
// Interpolate between matrix(3, 0, 0, 3, 40, 0)
// and matrix(4, 0, 0, 4, 120, 0) =
// scale(2 + (2-1)*2) translate(10px * 3)
'matrix(3.5, 0, 0, 3.5, 80, 0)',
'Animated transform list at 50s of the third iteration');
}, 'iterationComposite of transform list animation whose order is mismatched');
}, 'iterationComposite of transform list animation whose order is mismatched ' +
'because of missing functions');
test(function(t) {
var div = createDiv(t);
var anim =
div.animate({ transform: ['none',
'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, 0, 0, 1, 5, 0)', // (0px + 10px) / 2
'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, 0, 0)', // 'none' overrides any transforms.
'Animated transform list at 0s of the third iteration');
anim.currentTime += anim.effect.timing.duration / 2;
assert_equals(getComputedStyle(div).transform,
'matrix(1, 0, 0, 1, 15, 0)', // (0px + 10px*2)/2
'Animated transform list at 50s of the third iteration');
}, 'iterationComposite of transform from none to translate');
test(function(t) {
var div = createDiv(t);
var anim =
div.animate({ transform: ['matrix3d(1, 0, 0, 0, ' +
'0, 1, 0, 0, ' +
'0, 0, 1, 0, ' +
'0, 0, 30, 1)',
'matrix3d(1, 0, 0, 0, ' +
'0, 1, 0, 0, ' +
'0, 0, 1, 0, ' +
'0, 0, 50, 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,
'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 40, 1)',
'Animated transform of matrix3d function at 50s of the first iteration');
anim.currentTime = anim.effect.timing.duration * 2;
assert_equals(getComputedStyle(div).transform,
// translateZ(30px) + (translateZ(50px)*2)
'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 130, 1)',
'Animated transform of matrix3d function at 0s of the third iteration');
anim.currentTime += anim.effect.timing.duration / 2;
assert_equals(getComputedStyle(div).transform,
// from: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 130, 1)
// to: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 150, 1)
'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 140, 1)',
'Animated transform of matrix3d function at 50s of the third iteration');
}, 'iterationComposite of transform of matrix3d function');
test(function(t) {
var div = createDiv(t);
var anim =
div.animate({ transform: ['rotate3d(1, 1, 0, 0deg)',
'rotate3d(1, 1, 0, 90deg)'] },
{ duration: 100 * MS_PER_SEC,
easing: 'linear',
iterations: 10,
iterationComposite: 'accumulate' });
anim.pause();
anim.currentTime = 0;
assert_equals(getComputedStyle(div).transform,
'matrix(1, 0, 0, 1, 0, 0)', // Actually not rotated at all.
'Animated transform of rotate3d function at 50s of the first iteration');
anim.currentTime = anim.effect.timing.duration * 2;
assert_matrix_equals(getComputedStyle(div).transform,
rotate3dToMatrix3d(1, 1, 0, Math.PI), // 180deg
'Animated transform of rotate3d function at 0s of the third iteration');
anim.currentTime += anim.effect.timing.duration / 2;
assert_matrix_equals(getComputedStyle(div).transform,
rotate3dToMatrix3d(1, 1, 0, 225 * Math.PI / 180), //((270 + 180) * 0.5)deg
'Animated transform of rotate3d function at 50s of the third iteration');
}, 'iterationComposite of transform of rotate3d function');
test(function(t) {
var div = createDiv(t);

View file

@ -0,0 +1,94 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>KeyframeEffectReadOnly copy constructor tests</title>
<link rel="help"
href="https://w3c.github.io/web-animations/#dom-keyframeeffectreadonly-keyframeeffectreadonly-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);
var copiedEffect = new KeyframeEffectReadOnly(effect);
assert_equals(copiedEffect.target, effect.target, 'same target');
}, 'Test copied keyframeEffectReadOnly has the same target');
test(function(t) {
var effect =
new KeyframeEffectReadOnly(null,
[ { marginLeft: '0px' },
{ marginLeft: '-20px', easing: 'ease-in',
offset: 0.1 },
{ marginLeft: '100px', easing: 'ease-out' },
{ marginLeft: '50px' } ],
{ spacing: 'paced(margin-left)' });
var copiedEffect = new KeyframeEffectReadOnly(effect);
var KeyframesA = effect.getKeyframes();
var KeyframesB = copiedEffect.getKeyframes();
assert_equals(KeyframesA.length, KeyframesB.length, 'same keyframes length');
for (var i = 0; i < KeyframesA.length; ++i) {
assert_equals(KeyframesA[i].offset, KeyframesB[i].offset,
'Keyframe ' + i + ' has the same offset');
assert_equals(KeyframesA[i].computedOffset, KeyframesB[i].computedOffset,
'keyframe ' + i + ' has the same computedOffset');
assert_equals(KeyframesA[i].easing, KeyframesB[i].easing,
'keyframe ' + i + ' has the same easing');
assert_equals(KeyframesA[i].composite, KeyframesB[i].composite,
'keyframe ' + i + ' has the same composite');
assert_true(!!KeyframesA[i].marginLeft,
'original keyframe ' + i + ' has the valid property value');
assert_true(!!KeyframesB[i].marginLeft,
'new keyframe ' + i + ' has the valid property value');
assert_equals(KeyframesA[i].marginLeft, KeyframesB[i].marginLeft,
'keyframe ' + i + ' has the same property value pair');
}
}, 'Test copied keyframeEffectReadOnly has the same keyframes');
test(function(t) {
var effect = new KeyframeEffectReadOnly(null, null,
{ spacing: 'paced(margin-left)',
iterationComposite: 'accumulate' });
var copiedEffect = new KeyframeEffectReadOnly(effect);
assert_equals(copiedEffect.spacing, effect.spacing, 'same spacing');
assert_equals(copiedEffect.iterationComposite, effect.iterationComposite,
'same iterationCompositeOperation');
assert_equals(copiedEffect.composite, effect.composite,
'same compositeOperation');
}, 'Test copied keyframeEffectReadOnly has the same keyframeEffectOptions');
test(function(t) {
var effect = new KeyframeEffectReadOnly(null, null,
{ duration: 100 * MS_PER_SEC,
delay: -1 * MS_PER_SEC,
endDelay: 2 * MS_PER_SEC,
fill: 'forwards',
iterationStart: 2,
iterations: 20,
easing: 'ease-out',
direction: 'alternate' } );
var copiedEffect = new KeyframeEffectReadOnly(effect);
var timingA = effect.timing;
var timingB = copiedEffect.timing;
assert_not_equals(timingA, timingB, 'different timing objects');
assert_equals(timingA.delay, timingB.delay, 'same delay');
assert_equals(timingA.endDelay, timingB.endDelay, 'same endDelay');
assert_equals(timingA.fill, timingB.fill, 'same fill');
assert_equals(timingA.iterationStart, timingB.iterationStart,
'same iterationStart');
assert_equals(timingA.iterations, timingB.iterations, 'same iterations');
assert_equals(timingA.duration, timingB.duration, 'same duration');
assert_equals(timingA.direction, timingB.direction, 'same direction');
assert_equals(timingA.easing, timingB.easing, 'same easing');
}, 'Test copied keyframeEffectReadOnly has the same timing content');
</script>
</body>

View file

@ -182,7 +182,7 @@ var gPropertyIndexedKeyframesTests = [
var gKeyframeSequenceTests = [
{ desc: "a one property one keyframe sequence",
input: [{ offset: 1, left: "10px" }],
output: [{ offset: null, computedOffset: 1, easing: "linear",
output: [{ offset: 1, computedOffset: 1, easing: "linear",
left: "10px" }] },
{ desc: "a one property two keyframe sequence",
input: [{ offset: 0, left: "10px" },
@ -259,7 +259,7 @@ var gKeyframeSequenceTests = [
left: "10px" }] },
{ desc: "a single keyframe sequence with string offset",
input: [{ offset: '0.5', left: "10px" }],
output: [{ offset: 0.5, computedOffset: 1, easing: "linear",
output: [{ offset: 0.5, computedOffset: 0.5, easing: "linear",
left: "10px" }] },
{ desc: "a one property keyframe sequence with some omitted offsets",
input: [{ offset: 0.00, left: "10px" },
@ -341,9 +341,9 @@ var gKeyframeSequenceTests = [
composite: "replace", left: "10px" },
{ offset: 0.0, computedOffset: 0.0, easing: "linear",
composite: "replace", top: "20px" },
{ offset: 0.5, computedOffset: 0.0, easing: "linear",
{ offset: 0.5, computedOffset: 0.5, easing: "linear",
composite: "add", left: "30px" },
{ offset: 0.5, computedOffset: 0.0, easing: "linear",
{ offset: 0.5, computedOffset: 0.5, easing: "linear",
composite: "add", top: "40px" },
{ offset: 1.0, computedOffset: 1.0, easing: "linear",
composite: "replace", left: "50px" },

View file

@ -174,3 +174,68 @@ function waitForAnimationFramesWithDelay(minDelay) {
}());
});
}
// Returns 'matrix()' or 'matrix3d()' function string generated from an array.
function createMatrixFromArray(array) {
return (array.length == 16 ? 'matrix3d' : 'matrix') +
'(' + array.join() + ')';
}
// Returns 'matrix3d()' function string equivalent to
// 'rotate3d(x, y, z, radian)'.
function rotate3dToMatrix3d(x, y, z, radian) {
return createMatrixFromArray(rotate3dToMatrix(x, y, z, radian));
}
// Returns an array of the 4x4 matrix equivalent to 'rotate3d(x, y, z, radian)'.
// https://www.w3.org/TR/css-transforms-1/#Rotate3dDefined
function rotate3dToMatrix(x, y, z, radian) {
var sc = Math.sin(radian / 2) * Math.cos(radian / 2);
var sq = Math.sin(radian / 2) * Math.sin(radian / 2);
// Normalize the vector.
var length = Math.sqrt(x*x + y*y + z*z);
x /= length;
y /= length;
z /= length;
return [
1 - 2 * (y*y + z*z) * sq,
2 * (x * y * sq + z * sc),
2 * (x * z * sq - y * sc),
0,
2 * (x * y * sq - z * sc),
1 - 2 * (x*x + z*z) * sq,
2 * (y * z * sq + x * sc),
0,
2 * (x * z * sq + y * sc),
2 * (y * z * sq - x * sc),
1 - 2 * (x*x + y*y) * sq,
0,
0,
0,
0,
1
];
}
// Compare matrix string like 'matrix(1, 0, 0, 1, 100, 0)' with tolerances.
function assert_matrix_equals(actual, expected, description) {
var matrixRegExp = /^matrix(?:3d)*\((.+)\)/;
assert_regexp_match(actual, matrixRegExp,
'Actual value is not a matrix')
assert_regexp_match(expected, matrixRegExp,
'Expected value is not a matrix');
var actualMatrixArray =
actual.match(matrixRegExp)[1].split(',').map(Number);
var expectedMatrixArray =
expected.match(matrixRegExp)[1].split(',').map(Number);
assert_equals(actualMatrixArray.length, expectedMatrixArray.length,
'dimension of the matrix: ' + description);
for (var i = 0; i < actualMatrixArray.length; i++) {
assert_approx_equals(actualMatrixArray[i], expectedMatrixArray[i], 0.0001,
'expecetd ' + expected + ' but got ' + actual + ": " + description);
}
}

View file

@ -45,7 +45,7 @@ test(function(t) {
}, 'The current time is unresolved when the start time is unresolved ' +
'(and no hold time is set)');
promise_test(function(t) {
test(function(t) {
var animation =
new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC),
document.timeline);