blob: 6eaf0b5e1d40f560505975f0a15b175dad9310ee [file] [log] [blame]
<!DOCTYPE html>
<meta charset="UTF-8">
<body>
<script src="../interpolation/resources/interpolation-test.js"></script>
<script>
// Basic additive composition; the lists should be concatenated.
assertComposition({
property: 'backdrop-filter',
underlying: 'blur(10px)',
addFrom: 'blur(40px)',
addTo: 'blur(90px)',
}, [
{at: -0.5, is: 'blur(10px) blur(15px)'},
{at: 0, is: 'blur(10px) blur(40px)'},
{at: 0.25, is: 'blur(10px) blur(52.5px)'},
{at: 0.5, is: 'blur(10px) blur(65px)'},
{at: 0.75, is: 'blur(10px) blur(77.5px)'},
{at: 1, is: 'blur(10px) blur(90px)'},
{at: 1.5, is: 'blur(10px) blur(115px)'},
]);
// Here we have add-from and replace-to, so the list will be have mismatched
// lengths and the replace-to list will have to be extended to interpolate as
// per https://drafts.fxtf.org/filter-effects-1/#interpolation-of-filters
//
// That is, this becomes an interpolation of the form:
// sepia(0.5) sepia(0.5) --> sepia(1) sepia(0)
assertComposition({
property: 'backdrop-filter',
underlying: 'sepia(0.5)',
addFrom: 'sepia(0.5)',
replaceTo: 'sepia(1)',
}, [
{at: -0.5, is: 'sepia(0.25) sepia(0.75)'},
{at: 0, is: 'sepia(0.5) sepia(0.5)'},
{at: 0.25, is: 'sepia(0.625) sepia(0.375)'},
{at: 0.5, is: 'sepia(0.75) sepia(0.25)'},
{at: 0.75, is: 'sepia(0.875) sepia(0.125)'},
{at: 1, is: 'sepia(1) sepia(0)'},
{at: 1.5, is: 'sepia(1) sepia(0)'},
]);
// In this case we have replace-from and add-to, so similar extending behavior
// takes place. Note that brightness has an initial value of 1.
//
// That is, this becomes an interpolation of the form:
// brightness(0.5) brightness(1) --> brightness(0) brightness(1.5)
assertComposition({
property: 'backdrop-filter',
underlying: 'brightness(0)',
replaceFrom: 'brightness(0.5)',
addTo: 'brightness(1.5)',
}, [
{at: -0.5, is: 'brightness(0.75) brightness(0.75)'},
{at: 0, is: 'brightness(0.5) brightness(1)'},
{at: 0.25, is: 'brightness(0.375) brightness(1.125)'},
{at: 0.5, is: 'brightness(0.25) brightness(1.25)'},
{at: 0.75, is: 'brightness(0.125) brightness(1.375)'},
{at: 1, is: 'brightness(0) brightness(1.5)'},
{at: 1.5, is: 'brightness(0) brightness(1.75)'},
]);
// Test mixing properties.
assertComposition({
property: 'backdrop-filter',
underlying: 'invert(0.5)',
addFrom: 'saturate(2)',
addTo: 'saturate(3)',
}, [
{at: -0.5, is: 'invert(0.5) saturate(1.5)'},
{at: 0, is: 'invert(0.5) saturate(2)'},
{at: 0.25, is: 'invert(0.5) saturate(2.25)'},
{at: 0.5, is: 'invert(0.5) saturate(2.5)'},
{at: 0.75, is: 'invert(0.5) saturate(2.75)'},
{at: 1, is: 'invert(0.5) saturate(3)'},
{at: 1.5, is: 'invert(0.5) saturate(3.5)'},
]);
// Test the 'none' behavior; composition happens before interpolation, so this
// is actually an interpolation of:
// invert(0.5) saturate(1) --> invert(1) saturate(3)
assertComposition({
property: 'backdrop-filter',
underlying: 'invert(0.5)',
addFrom: 'none',
replaceTo: 'invert(1) saturate(3)',
}, [
{at: -0.5, is: 'invert(0.25) saturate(0)'},
{at: 0, is: 'invert(0.5) saturate(1)'},
{at: 0.25, is: 'invert(0.625) saturate(1.5)'},
{at: 0.5, is: 'invert(0.75) saturate(2)'},
{at: 0.75, is: 'invert(0.875) saturate(2.5)'},
{at: 1, is: 'invert(1) saturate(3)'},
{at: 1.5, is: 'invert(1.25) saturate(4)'},
]);
// Test having multiple underlying values
assertComposition({
property: 'backdrop-filter',
underlying: 'grayscale(25%) blur(10px)',
addFrom: 'brightness(0)',
addTo: 'brightness(1)',
}, [
{at: -0.5, is: 'grayscale(25%) blur(10px) brightness(0)'},
{at: 0, is: 'grayscale(25%) blur(10px) brightness(0)'},
{at: 0.25, is: 'grayscale(25%) blur(10px) brightness(0.25)'},
{at: 0.5, is: 'grayscale(25%) blur(10px) brightness(0.5)'},
{at: 0.75, is: 'grayscale(25%) blur(10px) brightness(0.75)'},
{at: 1, is: 'grayscale(25%) blur(10px) brightness(1)'},
{at: 1.5, is: 'grayscale(25%) blur(10px) brightness(1.5)'},
]);
// Make sure that a matching underlying value is still prefixed.
assertComposition({
property: 'backdrop-filter',
underlying: 'blur(10px)',
addFrom: 'grayscale(50%) blur(10px)',
addTo: 'grayscale(25%) blur(10px)',
}, [
{at: -0.5, is: 'blur(10px) grayscale(0.625) blur(10px)'},
{at: 0, is: 'blur(10px) grayscale(0.5) blur(10px)'},
{at: 0.25, is: 'blur(10px) grayscale(0.4375) blur(10px)'},
{at: 0.5, is: 'blur(10px) grayscale(0.375) blur(10px)'},
{at: 0.75, is: 'blur(10px) grayscale(0.3125) blur(10px)'},
{at: 1, is: 'blur(10px) grayscale(0.25) blur(10px)'},
{at: 1.5, is: 'blur(10px) grayscale(0.125) blur(10px)'},
]);
// Check the case where composition causes a url() to be included; the animation
// should change to discrete.
assertComposition({
property: 'backdrop-filter',
underlying: 'url(#a)',
addFrom: 'grayscale(50%) blur(30px)',
addTo: 'grayscale(25%) blur(40px)',
}, [
{at: -0.5, is: 'url("#a") grayscale(0.5) blur(30px)'},
{at: 0, is: 'url("#a") grayscale(0.5) blur(30px)'},
{at: 0.25, is: 'url("#a") grayscale(0.5) blur(30px)'},
{at: 0.5, is: 'url("#a") grayscale(0.25) blur(40px)'},
{at: 0.75, is: 'url("#a") grayscale(0.25) blur(40px)'},
{at: 1, is: 'url("#a") grayscale(0.25) blur(40px)'},
{at: 1.5, is: 'url("#a") grayscale(0.25) blur(40px)'},
]);
// And check the inverse; nothing fancy here but it should be a discrete
// animation with blur prepended.
assertComposition({
property: 'backdrop-filter',
underlying: 'blur(10px)',
addFrom: 'url(#a) brightness(1)',
addTo: 'url(#b) brightness(0)',
}, [
{at: -0.5, is: 'blur(10px) url(#a) brightness(1)'},
{at: 0, is: 'blur(10px) url(#a) brightness(1)'},
{at: 0.25, is: 'blur(10px) url(#a) brightness(1)'},
{at: 0.5, is: 'blur(10px) url(#b) brightness(0)'},
{at: 0.75, is: 'blur(10px) url(#b) brightness(0)'},
{at: 1, is: 'blur(10px) url(#b) brightness(0)'},
{at: 1.5, is: 'blur(10px) url(#b) brightness(0)'},
]);
// --------------- Accumulation tests. ---------------------
// blur; simple addition.
assertComposition({
property: 'backdrop-filter',
underlying: 'blur(10px)',
accumulateFrom: 'blur(40px)',
accumulateTo: 'blur(90px)',
}, [
{at: -0.5, is: 'blur(25px)'},
{at: 0, is: 'blur(50px)'},
{at: 0.25, is: 'blur(62.5px)'},
{at: 0.5, is: 'blur(75px)'},
{at: 0.75, is: 'blur(87.5px)'},
{at: 1, is: 'blur(100px)'},
{at: 1.5, is: 'blur(125px)'},
]);
// brightness; 1-based addition.
assertComposition({
property: 'backdrop-filter',
underlying: 'brightness(0.25)',
accumulateFrom: 'brightness(0.5)',
accumulateTo: 'brightness(1.5)',
}, [
{at: -0.5, is: 'brightness(0)'},
{at: 0, is: 'brightness(0)'},
{at: 0.25, is: 'brightness(0)'},
{at: 0.5, is: 'brightness(0.25)'},
{at: 0.75, is: 'brightness(0.5)'},
{at: 1, is: 'brightness(0.75)'},
{at: 1.5, is: 'brightness(1.25)'},
]);
// contrast; 1-based addition.
assertComposition({
property: 'backdrop-filter',
underlying: 'contrast(0.25)',
accumulateFrom: 'contrast(0.5)',
accumulateTo: 'contrast(1.5)',
}, [
{at: -0.5, is: 'contrast(0)'},
{at: 0, is: 'contrast(0)'},
{at: 0.25, is: 'contrast(0)'},
{at: 0.5, is: 'contrast(0.25)'},
{at: 0.75, is: 'contrast(0.5)'},
{at: 1, is: 'contrast(0.75)'},
{at: 1.5, is: 'contrast(1.25)'},
]);
// drop-shadow; addition of lengths plus color addition
assertComposition({
property: 'backdrop-filter',
underlying: 'drop-shadow(10px 5px 0px rgb(255, 0, 0))',
accumulateFrom: 'drop-shadow(0px 10px 10px rgb(0, 255, 0))',
accumulateTo: 'drop-shadow(50px 30px 10px rgb(0, 0, 255))',
}, [
{at: -0.5, is: 'drop-shadow(-15px 5px 10px rgb(255, 255, 0))'},
{at: 0, is: 'drop-shadow(10px 15px 10px rgb(255, 255, 0))'},
{at: 0.25, is: 'drop-shadow(22.5px 20px 10px rgb(255, 191, 64))'},
{at: 0.5, is: 'drop-shadow(35px 25px 10px rgb(255, 128, 128))'},
{at: 0.75, is: 'drop-shadow(47.5px 30px 10px rgb(255, 64, 191))'},
{at: 1, is: 'drop-shadow(60px 35px 10px rgb(255, 0, 255))'},
{at: 1.5, is: 'drop-shadow(85px 45px 10px rgb(255, 0, 255))'},
]);
// grayscale; 1-based addition.
assertComposition({
property: 'backdrop-filter',
underlying: 'grayscale(0.25)',
accumulateFrom: 'grayscale(0.5)',
accumulateTo: 'grayscale(1.5)', // clamped to 1
}, [
{at: -0.5, is: 'grayscale(0)'},
{at: 0, is: 'grayscale(0)'},
{at: 0.25, is: 'grayscale(0)'},
{at: 0.5, is: 'grayscale(0)'},
{at: 0.75, is: 'grayscale(0.125)'},
{at: 1, is: 'grayscale(0.25)'},
{at: 1.5, is: 'grayscale(0.5)'},
]);
// hue-rotate; simple addition
assertComposition({
property: 'backdrop-filter',
underlying: 'hue-rotate(45deg)',
accumulateFrom: 'hue-rotate(140deg)',
accumulateTo: 'hue-rotate(400deg)',
}, [
{at: -0.5, is: 'hue-rotate(55deg)'},
{at: 0, is: 'hue-rotate(185deg)'},
{at: 0.25, is: 'hue-rotate(250deg)'},
{at: 0.5, is: 'hue-rotate(315deg)'},
{at: 0.75, is: 'hue-rotate(380deg)'},
{at: 1, is: 'hue-rotate(445deg)'},
{at: 1.5, is: 'hue-rotate(575deg)'},
]);
// invert; 1-based addition.
assertComposition({
property: 'backdrop-filter',
underlying: 'invert(0.25)',
accumulateFrom: 'invert(0.5)',
accumulateTo: 'invert(1.5)', // clamped to 1
}, [
{at: -0.5, is: 'invert(0)'},
{at: 0, is: 'invert(0)'},
{at: 0.25, is: 'invert(0)'},
{at: 0.5, is: 'invert(0)'},
{at: 0.75, is: 'invert(0.125)'},
{at: 1, is: 'invert(0.25)'},
{at: 1.5, is: 'invert(0.5)'},
]);
// opacity; 1-based addition
assertComposition({
property: 'backdrop-filter',
underlying: 'opacity(0.25)',
accumulateFrom: 'opacity(0.5)',
accumulateTo: 'opacity(1.5)', // clamped to 1
}, [
{at: -0.5, is: 'opacity(0)'},
{at: 0, is: 'opacity(0)'},
{at: 0.25, is: 'opacity(0)'},
{at: 0.5, is: 'opacity(0)'},
{at: 0.75, is: 'opacity(0.125)'},
{at: 1, is: 'opacity(0.25)'},
{at: 1.5, is: 'opacity(0.5)'},
]);
// saturate; 1-based addition
assertComposition({
property: 'backdrop-filter',
underlying: 'saturate(0.25)',
accumulateFrom: 'saturate(0.5)',
accumulateTo: 'saturate(1.5)',
}, [
{at: -0.5, is: 'saturate(0)'},
{at: 0, is: 'saturate(0)'},
{at: 0.25, is: 'saturate(0)'},
{at: 0.5, is: 'saturate(0.25)'},
{at: 0.75, is: 'saturate(0.5)'},
{at: 1, is: 'saturate(0.75)'},
{at: 1.5, is: 'saturate(1.25)'},
]);
// sepia; 1-based addition
assertComposition({
property: 'backdrop-filter',
underlying: 'sepia(0.25)',
accumulateFrom: 'sepia(0.5)',
accumulateTo: 'sepia(1.5)', // clamped to 1
}, [
{at: -0.5, is: 'sepia(0)'},
{at: 0, is: 'sepia(0)'},
{at: 0.25, is: 'sepia(0)'},
{at: 0.5, is: 'sepia(0)'},
{at: 0.75, is: 'sepia(0.125)'},
{at: 1, is: 'sepia(0.25)'},
{at: 1.5, is: 'sepia(0.5)'},
]);
// url; cannot be accumulated
assertComposition({
property: 'backdrop-filter',
underlying: 'url(#a)',
accumulateFrom: 'url(#b)',
accumulateTo: 'url(#c)',
}, [
{at: -0.5, is: 'url(#b)'},
{at: 0, is: 'url(#b)'},
{at: 0.25, is: 'url(#b)'},
{at: 0.5, is: 'url(#c)'},
{at: 0.75, is: 'url(#c)'},
{at: 1, is: 'url(#c)'},
{at: 1.5, is: 'url(#c)'},
]);
// Test auto-extension of the underlying list.
assertComposition({
property: 'backdrop-filter',
underlying: 'blur(10px)',
accumulateFrom: 'blur(40px) saturate(1)',
accumulateTo: 'blur(90px) saturate(0)',
}, [
{at: -0.5, is: 'blur(25px) saturate(1.5)'},
{at: 0, is: 'blur(50px) saturate(1)'},
{at: 0.25, is: 'blur(62.5px) saturate(0.75)'},
{at: 0.5, is: 'blur(75px) saturate(0.5)'},
{at: 0.75, is: 'blur(87.5px) saturate(0.25)'},
{at: 1, is: 'blur(100px) saturate(0)'},
{at: 1.5, is: 'blur(125px) saturate(0)'},
]);
// Test auto-extension of the composited-onto list.
assertComposition({
property: 'backdrop-filter',
underlying: 'blur(10px) saturate(0.75)',
accumulateFrom: 'blur(40px)',
accumulateTo: 'blur(90px)',
}, [
{at: -0.5, is: 'blur(25px) saturate(0.75)'},
{at: 0, is: 'blur(50px) saturate(0.75)'},
{at: 0.25, is: 'blur(62.5px) saturate(0.75)'},
{at: 0.5, is: 'blur(75px) saturate(0.75)'},
{at: 0.75, is: 'blur(87.5px) saturate(0.75)'},
{at: 1, is: 'blur(100px) saturate(0.75)'},
{at: 1.5, is: 'blur(125px) saturate(0.75)'},
]);
// Mismatching type for underlying; it just gets replaced.
assertComposition({
property: 'backdrop-filter',
underlying: 'contrast(0.75)',
accumulateFrom: 'blur(40px)',
accumulateTo: 'blur(80px)',
}, [
{at: -0.5, is: 'blur(20px)'},
{at: 0, is: 'blur(40px)'},
{at: 0.25, is: 'blur(50px)'},
{at: 0.5, is: 'blur(60px)'},
{at: 0.75, is: 'blur(70px)'},
{at: 1, is: 'blur(80px)'},
{at: 1.5, is: 'blur(100px)'},
]);
// Underlying only type-matches one side of the interpolation; it should be
// accumulated onto that side, but the entire animation will be discrete due to
// the mis-matching types.
assertComposition({
property: 'backdrop-filter',
underlying: 'blur(10px)',
accumulateFrom: 'blur(40px)',
accumulateTo: 'saturate(1)',
}, [
{at: -0.5, is: 'blur(50px)'},
{at: 0, is: 'blur(50px)'},
{at: 0.25, is: 'blur(50px)'},
{at: 0.5, is: 'saturate(1)'},
{at: 0.75, is: 'saturate(1)'},
{at: 1, is: 'saturate(1)'},
{at: 1.5, is: 'saturate(1)'},
]);
// Test a case where only one side is accumulative and the other is replace.
assertComposition({
property: 'backdrop-filter',
underlying: 'blur(10px)',
accumulateFrom: 'blur(30px)',
replaceTo: 'blur(100px)',
}, [
{at: -0.5, is: 'blur(10px)'},
{at: 0, is: 'blur(40px)'},
{at: 0.25, is: 'blur(55px)'},
{at: 0.5, is: 'blur(70px)'},
{at: 0.75, is: 'blur(85px)'},
{at: 1, is: 'blur(100px)'},
{at: 1.5, is: 'blur(130px)'},
]);
// Test a case where only one side is accumulative and the other is add.
// This basically looks like:
// accumulateSide = blur(Apx) neutral-blur
// addSide = blur(10px) blur(Bpx)
assertComposition({
property: 'backdrop-filter',
underlying: 'blur(10px)',
accumulateFrom: 'blur(40px)',
addTo: 'blur(100px)',
}, [
{at: -0.5, is: 'blur(70px) blur(0px)'},
{at: 0, is: 'blur(50px) blur(0px)'},
{at: 0.25, is: 'blur(40px) blur(25px)'},
{at: 0.5, is: 'blur(30px) blur(50px)'},
{at: 0.75, is: 'blur(20px) blur(75px)'},
{at: 1, is: 'blur(10px) blur(100px)'},
{at: 1.5, is: 'blur(0px) blur(150px)'},
]);
</script>
</body>