summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/css/css-fonts/animations
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/css/css-fonts/animations')
-rw-r--r--testing/web-platform/tests/css/css-fonts/animations/font-palette-animation-not-specified-endpoints.html67
-rw-r--r--testing/web-platform/tests/css/css-fonts/animations/font-palette-interpolation.html142
-rw-r--r--testing/web-platform/tests/css/css-fonts/animations/font-size-adjust-composition.html665
-rw-r--r--testing/web-platform/tests/css/css-fonts/animations/font-size-adjust-interpolation.html169
-rw-r--r--testing/web-platform/tests/css/css-fonts/animations/font-size-interpolation-001.html103
-rw-r--r--testing/web-platform/tests/css/css-fonts/animations/font-size-interpolation-002.html49
-rw-r--r--testing/web-platform/tests/css/css-fonts/animations/font-size-interpolation-003.html47
-rw-r--r--testing/web-platform/tests/css/css-fonts/animations/font-stretch-interpolation.html164
-rw-r--r--testing/web-platform/tests/css/css-fonts/animations/font-style-interpolation.html122
-rw-r--r--testing/web-platform/tests/css/css-fonts/animations/font-variation-settings-composition.html102
-rw-r--r--testing/web-platform/tests/css/css-fonts/animations/font-variation-settings-interpolation.html161
-rw-r--r--testing/web-platform/tests/css/css-fonts/animations/multiple-elements-font-palette-animation.html61
-rw-r--r--testing/web-platform/tests/css/css-fonts/animations/system-fonts.html70
13 files changed, 1922 insertions, 0 deletions
diff --git a/testing/web-platform/tests/css/css-fonts/animations/font-palette-animation-not-specified-endpoints.html b/testing/web-platform/tests/css/css-fonts/animations/font-palette-animation-not-specified-endpoints.html
new file mode 100644
index 0000000000..1539bd18a1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-fonts/animations/font-palette-animation-not-specified-endpoints.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>Font-palette animation with unspecified endpoints keyframes</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-4/#propdef-font-palette">
+<meta name="assert" content="Font-palette should be animated if `from` and `to` keyframes are not specified.">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+ @font-face {
+ font-family: "COLR-test-font";
+ src: url("../resources/COLR-palettes-test-font.ttf") format("truetype");
+ }
+ @font-palette-values --custom {
+ font-family: "COLR-test-font";
+ base-palette: 3;
+ }
+ @keyframes animFrom {
+ from {
+ font-palette: --custom;
+ }
+ }
+ @keyframes animTo {
+ to {
+ font-palette: --custom;
+ }
+ }
+ .demo {
+ font-family: "COLR-test-font";
+ font-size: 130px;
+ }
+ .animFrom {
+ animation: animFrom 0.1s forwards;
+ }
+ .animTo {
+ animation: animTo 0.1s forwards;
+ }
+</style>
+
+<body>
+ <div class="demo">
+ <div id="a" class="animTo">A</div>
+ <div id="b" class="animFrom" style="font-palette: --custom;">A</div>
+ </div>
+</body>
+
+<script>
+ var afterPaletteAnimationTest1 = async_test(
+ "Verify font-palette is animated when `from` keyframe is not specified"
+ );
+ document.getElementById("a").addEventListener("animationend",
+ afterPaletteAnimationTest1.step_func_done(function() {
+ assert_equals(window.getComputedStyle(
+ document.getElementById("a"))
+ .getPropertyValue('font-palette'), "--custom");
+ }));
+
+ var afterPaletteAnimationTest2 = async_test(
+ "Verify font-palette is animated when `to` keyframe is not specified"
+ );
+ document.getElementById("b").addEventListener("animationend",
+ afterPaletteAnimationTest2.step_func_done(function() {
+ assert_equals(window.getComputedStyle(
+ document.getElementById("b"))
+ .getPropertyValue('font-palette'), "normal");
+ }));
+</script>
diff --git a/testing/web-platform/tests/css/css-fonts/animations/font-palette-interpolation.html b/testing/web-platform/tests/css/css-fonts/animations/font-palette-interpolation.html
new file mode 100644
index 0000000000..43e1368412
--- /dev/null
+++ b/testing/web-platform/tests/css/css-fonts/animations/font-palette-interpolation.html
@@ -0,0 +1,142 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>font-palette interpolation</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-4/#propdef-font-palette">
+<meta name="assert" content="Font-palette should be animated smoothly.">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+<style>
+@font-palette-values --custom-palette {
+ font-family: "Color font";
+ base-palette: 0;
+ override-colors: 1 #000000;
+}
+
+.container {
+ font-palette: light;
+}
+.container2 {
+ font-palette: dark;
+}
+.target {
+ display: inline-block;
+ font: 100px sans-serif;
+ font-palette: normal;
+}
+.expected {
+ color: green;
+ margin-right: 30px;
+}
+</style>
+
+<body>
+<template id="target-template">
+ <span class="container">
+ <div class="target">TT</div>
+ </span>
+</template>
+
+<span id="inv-container" class="container">
+ <div id="inv-target" class="target">TT</div>
+</span>
+</body>
+
+<script>
+
+test_interpolation({
+ property: 'font-palette',
+ from: 'light',
+ to: 'dark'
+}, [
+ {at: -2, expect: 'light'},
+ {at: -0.25, expect: 'light'},
+ {at: 0, expect: 'light'},
+ {at: 0.3, expect: 'palette-mix(in oklab, light, dark 30%)'},
+ {at: 0.6, expect: 'palette-mix(in oklab, light, dark 60%)'},
+ {at: 1, expect: 'dark'},
+ {at: 1.5, expect: 'dark'},
+]);
+
+test_interpolation({
+ property: 'font-palette',
+ from: 'initial',
+ to: 'inherit'
+}, [
+ {at: -2, expect: 'normal'},
+ {at: -0.25, expect: 'normal'},
+ {at: 0, expect: 'normal'},
+ {at: 0.3, expect: 'palette-mix(in oklab, normal, light 30%)'},
+ {at: 0.6, expect: 'palette-mix(in oklab, normal, light 60%)'},
+ {at: 1, expect: 'light'},
+ {at: 1.5, expect: 'light'},
+]);
+
+test_interpolation({
+ property: 'font-palette',
+ from: '--custom-palette',
+ to: 'normal'
+}, [
+ {at: -2, expect: '--custom-palette'},
+ {at: -0.25, expect: '--custom-palette'},
+ {at: 0, expect: '--custom-palette'},
+ {at: 0.3, expect: 'palette-mix(in oklab, --custom-palette, normal 30%)'},
+ {at: 0.6, expect: 'palette-mix(in oklab, --custom-palette, normal 60%)'},
+ {at: 1, expect: 'normal'},
+ {at: 1.5, expect: 'normal'},
+]);
+
+/* palette-mix function for the equal endpoints should be simplified. */
+test_interpolation({
+ property: 'font-palette',
+ from: 'initial',
+ to: 'normal'
+}, [
+ {at: -2, expect: 'normal'},
+ {at: -0.25, expect: 'normal'},
+ {at: 0, expect: 'normal'},
+ {at: 0.3, expect: 'normal'},
+ {at: 0.6, expect: 'normal'},
+ {at: 1, expect: 'normal'},
+ {at: 1.5, expect: 'normal'},
+]);
+
+test(t => {
+ var container = document.getElementById('inv-container');
+ var target = document.getElementById('inv-target');
+ var anim = target.animate({ fontPalette: ['normal', 'inherit'] }, 1000);
+ anim.pause();
+ anim.currentTime = 500;
+ assert_equals(getComputedStyle(target).fontPalette, 'palette-mix(in oklab, normal, light)');
+
+ container.setAttribute('class', 'container2');
+ assert_equals(getComputedStyle(target).fontPalette, 'palette-mix(in oklab, normal, dark)');
+}, "An interpolation to inherit updates correctly on a parent style change.");
+
+test(t => {
+ var target = document.getElementById('inv-target');
+ target.animate(
+ { fontPalette: ['light', 'normal'] },
+ {
+ duration: 1000
+ }
+ );
+ target.animate(
+ { fontPalette: ['normal', 'dark'] },
+ {
+ duration: 1000,
+ /* Should work like 'replace', since <Color> type is not additive,
+ compare: https://drafts.csswg.org/css-values-4/#combine-colors. */
+ composite: "add"
+ }
+ );
+ document.getAnimations().forEach((animation) => {
+ animation.pause();
+ animation.currentTime = 500;
+ });
+ assert_equals(getComputedStyle(target).fontPalette,
+ "palette-mix(in oklab, normal, dark)");
+}, "Test additive animations");
+
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-fonts/animations/font-size-adjust-composition.html b/testing/web-platform/tests/css/css-fonts/animations/font-size-adjust-composition.html
new file mode 100644
index 0000000000..d98b0ffd10
--- /dev/null
+++ b/testing/web-platform/tests/css/css-fonts/animations/font-size-adjust-composition.html
@@ -0,0 +1,665 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>font-size-adjust composition</title>
+<link rel="author" title="ChangSeok Oh" href="mailto:changseok@webkit.org">
+<link rel="help" href="https://www.w3.org/TR/css-fonts-5/#font-size-adjust-prop">
+<meta name="assert" content="font-size-adjust supports animation with two value font metrics">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body></body>
+
+<script>
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "0.5",
+ replaceFrom: "none",
+ addTo: "2.0",
+}, [
+ {at: -0.5, expect: "none"},
+ {at: 0, expect: "none"},
+ {at: 0.5, expect: "2.5"},
+ {at: 1, expect: "2.5"},
+ {at: 1.5, expect: "2.5"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "0.5",
+ addFrom: "0.0",
+ addTo: "2.0",
+}, [
+ {at: -0.5, expect: "0.0"},
+ {at: 0, expect: "0.5"},
+ {at: 0.5, expect: "1.5"},
+ {at: 1, expect: "2.5"},
+ {at: 1.5, expect: "3.5"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "0.5",
+ replaceFrom: "0.0",
+ addTo: "2.0",
+}, [
+ {at: -0.5, expect: "0.0"},
+ {at: 0, expect: "0.0"},
+ {at: 0.5, expect: "1.25"},
+ {at: 1, expect: "2.5"},
+ {at: 1.5, expect: "3.75"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "0.5",
+ addFrom: "0.0",
+ replaceTo: "2.0",
+}, [
+ {at: -0.5, expect: "0.0"},
+ {at: 0, expect: "0.5"},
+ {at: 0.5, expect: "1.25"},
+ {at: 1, expect: "2.0"},
+ {at: 1.5, expect: "2.75"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "0.5",
+ replaceFrom: "2.0",
+ addTo: "none",
+}, [
+ {at: -0.5, expect: "2.0"},
+ {at: 0, expect: "2.0"},
+ {at: 0.5, expect: "none"},
+ {at: 1, expect: "none"},
+ {at: 1.5, expect: "none"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "ex-height 0.5",
+ replaceFrom: "none",
+ addTo: "ex-height 2.0",
+}, [
+ {at: -0.5, expect: "none"},
+ {at: 0, expect: "none"},
+ {at: 0.5, expect: "2.5"},
+ {at: 1, expect: "2.5"},
+ {at: 1.5, expect: "2.5"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "ex-height 0.5",
+ addFrom: "ex-height 0",
+ addTo: "ex-height 2.0",
+}, [
+ {at: -0.5, expect: "0.0"},
+ {at: 0, expect: "0.5"},
+ {at: 0.5, expect: "1.5"},
+ {at: 1, expect: "2.5"},
+ {at: 1.5, expect: "3.5"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "ex-height 0.5",
+ replaceFrom: "ex-height 0",
+ addTo: "ex-height 2.0",
+}, [
+ {at: -0.5, expect: "0.0"},
+ {at: 0, expect: "0.0"},
+ {at: 0.5, expect: "1.25"},
+ {at: 1, expect: "2.5"},
+ {at: 1.5, expect: "3.75"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "ex-height 0.5",
+ addFrom: "ex-height 0",
+ replaceTo: "ex-height 2.0",
+}, [
+ {at: -0.5, expect: "0.0"},
+ {at: 0, expect: "0.5"},
+ {at: 0.5, expect: "1.25"},
+ {at: 1, expect: "2.0"},
+ {at: 1.5, expect: "2.75"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "ex-height 0.5",
+ replaceFrom: "ex-height 2.0",
+ addTo: "none",
+}, [
+ {at: -0.5, expect: "2.0"},
+ {at: 0, expect: "2.0"},
+ {at: 0.5, expect: "none"},
+ {at: 1, expect: "none"},
+ {at: 1.5, expect: "none"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "cap-height 0.5",
+ replaceFrom: "none",
+ addTo: "cap-height 2.0",
+}, [
+ {at: -0.5, expect: "none"},
+ {at: 0, expect: "none"},
+ {at: 0.5, expect: "cap-height 2.5"},
+ {at: 1, expect: "cap-height 2.5"},
+ {at: 1.5, expect: "cap-height 2.5"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "cap-height 0.5",
+ addFrom: "cap-height 0",
+ addTo: "cap-height 2.0",
+}, [
+ {at: -0.5, expect: "cap-height 0.0"},
+ {at: 0, expect: "cap-height 0.5"},
+ {at: 0.5, expect: "cap-height 1.5"},
+ {at: 1, expect: "cap-height 2.5"},
+ {at: 1.5, expect: "cap-height 3.5"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "cap-height 0.5",
+ replaceFrom: "cap-height 0",
+ addTo: "cap-height 2.0",
+}, [
+ {at: -0.5, expect: "cap-height 0.0"},
+ {at: 0, expect: "cap-height 0.0"},
+ {at: 0.5, expect: "cap-height 1.25"},
+ {at: 1, expect: "cap-height 2.5"},
+ {at: 1.5, expect: "cap-height 3.75"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "cap-height 0.5",
+ addFrom: "cap-height 0.0",
+ replaceTo: "cap-height 2.0",
+}, [
+ {at: -0.5, expect: "cap-height 0.0"},
+ {at: 0, expect: "cap-height 0.5"},
+ {at: 0.5, expect: "cap-height 1.25"},
+ {at: 1, expect: "cap-height 2"},
+ {at: 1.5, expect: "cap-height 2.75"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "cap-height 0.5",
+ replaceFrom: "cap-height 2.0",
+ addTo: "none",
+}, [
+ {at: -0.5, expect: "cap-height 2.0"},
+ {at: 0, expect: "cap-height 2.0"},
+ {at: 0.5, expect: "none"},
+ {at: 1, expect: "none"},
+ {at: 1.5, expect: "none"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "ch-width 0.5",
+ replaceFrom: "none",
+ addTo: "ch-width 2.0",
+}, [
+ {at: -0.5, expect: "none"},
+ {at: 0, expect: "none"},
+ {at: 0.5, expect: "ch-width 2.5"},
+ {at: 1, expect: "ch-width 2.5"},
+ {at: 1.5, expect: "ch-width 2.5"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "ch-width 0.5",
+ addFrom: "ch-width 0",
+ addTo: "ch-width 2.0",
+}, [
+ {at: -0.5, expect: "ch-width 0.0"},
+ {at: 0, expect: "ch-width 0.5"},
+ {at: 0.5, expect: "ch-width 1.5"},
+ {at: 1, expect: "ch-width 2.5"},
+ {at: 1.5, expect: "ch-width 3.5"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "ch-width 0.5",
+ replaceFrom: "ch-width 0",
+ addTo: "ch-width 2.0",
+}, [
+ {at: -0.5, expect: "ch-width 0.0"},
+ {at: 0, expect: "ch-width 0.0"},
+ {at: 0.5, expect: "ch-width 1.25"},
+ {at: 1, expect: "ch-width 2.5"},
+ {at: 1.5, expect: "ch-width 3.75"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "ch-width 0.5",
+ addFrom: "ch-width 0",
+ replaceTo: "ch-width 2.0",
+}, [
+ {at: -0.5, expect: "ch-width 0.0"},
+ {at: 0, expect: "ch-width 0.5"},
+ {at: 0.5, expect: "ch-width 1.25"},
+ {at: 1, expect: "ch-width 2"},
+ {at: 1.5, expect: "ch-width 2.75"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "ch-width 0.5",
+ replaceFrom: "ch-width 2.0",
+ addTo: "none",
+}, [
+ {at: -0.5, expect: "ch-width 2.0"},
+ {at: 0, expect: "ch-width 2.0"},
+ {at: 0.5, expect: "none"},
+ {at: 1, expect: "none"},
+ {at: 1.5, expect: "none"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "ic-width 0.5",
+ replaceFrom: "none",
+ addTo: "ic-width 2.0",
+}, [
+ {at: -0.5, expect: "none"},
+ {at: 0, expect: "none"},
+ {at: 0.5, expect: "ic-width 2.5"},
+ {at: 1, expect: "ic-width 2.5"},
+ {at: 1.5, expect: "ic-width 2.5"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "ic-width 0.5",
+ addFrom: "ic-width 0",
+ addTo: "ic-width 2.0",
+}, [
+ {at: -0.5, expect: "ic-width 0.0"},
+ {at: 0, expect: "ic-width 0.5"},
+ {at: 0.5, expect: "ic-width 1.5"},
+ {at: 1, expect: "ic-width 2.5"},
+ {at: 1.5, expect: "ic-width 3.5"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "ic-width 0.5",
+ replaceFrom: "ic-width 0",
+ addTo: "ic-width 2.0",
+}, [
+ {at: -0.5, expect: "ic-width 0.0"},
+ {at: 0, expect: "ic-width 0.0"},
+ {at: 0.5, expect: "ic-width 1.25"},
+ {at: 1, expect: "ic-width 2.5"},
+ {at: 1.5, expect: "ic-width 3.75"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "ic-width 0.5",
+ addFrom: "ic-width 0",
+ replaceTo: "ic-width 2.0",
+}, [
+ {at: -0.5, expect: "ic-width 0.0"},
+ {at: 0, expect: "ic-width 0.5"},
+ {at: 0.5, expect: "ic-width 1.25"},
+ {at: 1, expect: "ic-width 2"},
+ {at: 1.5, expect: "ic-width 2.75"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "ic-width 0.5",
+ replaceFrom: "ic-width 2.0",
+ addTo: "none",
+}, [
+ {at: -0.5, expect: "ic-width 2.0"},
+ {at: 0, expect: "ic-width 2.0"},
+ {at: 0.5, expect: "none"},
+ {at: 1, expect: "none"},
+ {at: 1.5, expect: "none"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "ic-height 0.5",
+ replaceFrom: "none",
+ addTo: "ic-height 2.0",
+}, [
+ {at: -0.5, expect: "none"},
+ {at: 0, expect: "none"},
+ {at: 0.5, expect: "ic-height 2.5"},
+ {at: 1, expect: "ic-height 2.5"},
+ {at: 1.5, expect: "ic-height 2.5"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "ic-height 0.5",
+ addFrom: "ic-height 0",
+ addTo: "ic-height 2.0",
+}, [
+ {at: -0.5, expect: "ic-height 0.0"},
+ {at: 0, expect: "ic-height 0.5"},
+ {at: 0.5, expect: "ic-height 1.5"},
+ {at: 1, expect: "ic-height 2.5"},
+ {at: 1.5, expect: "ic-height 3.5"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "ic-height 0.5",
+ replaceFrom: "ic-height 0",
+ addTo: "ic-height 2.0",
+}, [
+ {at: -0.5, expect: "ic-height 0.0"},
+ {at: 0, expect: "ic-height 0.0"},
+ {at: 0.5, expect: "ic-height 1.25"},
+ {at: 1, expect: "ic-height 2.5"},
+ {at: 1.5, expect: "ic-height 3.75"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "ic-height 0.5",
+ addFrom: "ic-height 0",
+ replaceTo: "ic-height 2.0",
+}, [
+ {at: -0.5, expect: "ic-height 0.0"},
+ {at: 0, expect: "ic-height 0.5"},
+ {at: 0.5, expect: "ic-height 1.25"},
+ {at: 1, expect: "ic-height 2"},
+ {at: 1.5, expect: "ic-height 2.75"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "ic-height 0.5",
+ replaceFrom: "ic-height 2.0",
+ addTo: "none",
+}, [
+ {at: -0.5, expect: "ic-height 2.0"},
+ {at: 0, expect: "ic-height 2.0"},
+ {at: 0.5, expect: "none"},
+ {at: 1, expect: "none"},
+ {at: 1.5, expect: "none"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "0.5",
+ addFrom: "ex-height 0.0",
+ addTo: "cap-height 2.0",
+}, [
+ {at: -0.5, expect: "0.5"},
+ {at: 0, expect: "0.5"},
+ {at: 0.5, expect: "cap-height 2.0"},
+ {at: 1, expect: "cap-height 2.0"},
+ {at: 1.5, expect: "cap-height 2.0"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "0.5",
+ replaceFrom: "ex-height 0.0",
+ replaceTo: "cap-height 2.0",
+}, [
+ {at: -0.5, expect: "0.0"},
+ {at: 0, expect: "0.0"},
+ {at: 0.5, expect: "cap-height 2.0"},
+ {at: 1, expect: "cap-height 2.0"},
+ {at: 1.5, expect: "cap-height 2.0"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "0.5",
+ replaceFrom: "ex-height 0",
+ addTo: "cap-height 2.0",
+}, [
+ {at: -0.5, expect: "0.0"},
+ {at: 0, expect: "0.0"},
+ {at: 0.5, expect: "cap-height 2.0"},
+ {at: 1, expect: "cap-height 2.0"},
+ {at: 1.5, expect: "cap-height 2.0"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "0.5",
+ addFrom: "ex-height 0",
+ replaceTo: "cap-height 2.0",
+}, [
+ {at: -0.5, expect: "0.5"},
+ {at: 0, expect: "0.5"},
+ {at: 0.5, expect: "cap-height 2.0"},
+ {at: 1, expect: "cap-height 2.0"},
+ {at: 1.5, expect: "cap-height 2.0"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "0.5",
+ addFrom: "cap-height 0.0",
+ addTo: "ch-width 2.0",
+}, [
+ {at: -0.5, expect: "cap-height 0.0"},
+ {at: 0, expect: "cap-height 0.0"},
+ {at: 0.5, expect: "ch-width 2.0"},
+ {at: 1, expect: "ch-width 2.0"},
+ {at: 1.5, expect: "ch-width 2.0"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "0.5",
+ replaceFrom: "cap-height 0.0",
+ replaceTo: "ch-width 2.0",
+}, [
+ {at: -0.5, expect: "cap-height 0.0"},
+ {at: 0, expect: "cap-height 0.0"},
+ {at: 0.5, expect: "ch-width 2.0"},
+ {at: 1, expect: "ch-width 2.0"},
+ {at: 1.5, expect: "ch-width 2.0"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "0.5",
+ replaceFrom: "cap-height 0",
+ addTo: "ch-width 2.0",
+}, [
+ {at: -0.5, expect: "cap-height 0.0"},
+ {at: 0, expect: "cap-height 0.0"},
+ {at: 0.5, expect: "ch-width 2.0"},
+ {at: 1, expect: "ch-width 2.0"},
+ {at: 1.5, expect: "ch-width 2.0"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "0.5",
+ addFrom: "cap-height 0",
+ replaceTo: "ch-width 2.0",
+}, [
+ {at: -0.5, expect: "cap-height 0"},
+ {at: 0, expect: "cap-height 0"},
+ {at: 0.5, expect: "ch-width 2.0"},
+ {at: 1, expect: "ch-width 2.0"},
+ {at: 1.5, expect: "ch-width 2.0"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "0.5",
+ addFrom: "ch-width 0.0",
+ addTo: "ic-width 2.0",
+}, [
+ {at: -0.5, expect: "ch-width 0.0"},
+ {at: 0, expect: "ch-width 0.0"},
+ {at: 0.5, expect: "ic-width 2.0"},
+ {at: 1, expect: "ic-width 2.0"},
+ {at: 1.5, expect: "ic-width 2.0"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "0.5",
+ replaceFrom: "ch-width 0.0",
+ replaceTo: "ic-width 2.0",
+}, [
+ {at: -0.5, expect: "ch-width 0.0"},
+ {at: 0, expect: "ch-width 0.0"},
+ {at: 0.5, expect: "ic-width 2.0"},
+ {at: 1, expect: "ic-width 2.0"},
+ {at: 1.5, expect: "ic-width 2.0"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "0.5",
+ replaceFrom: "ch-width 0",
+ addTo: "ic-width 2.0",
+}, [
+ {at: -0.5, expect: "ch-width 0.0"},
+ {at: 0, expect: "ch-width 0.0"},
+ {at: 0.5, expect: "ic-width 2.0"},
+ {at: 1, expect: "ic-width 2.0"},
+ {at: 1.5, expect: "ic-width 2.0"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "0.5",
+ addFrom: "ch-width 0",
+ replaceTo: "ic-width 2.0",
+}, [
+ {at: -0.5, expect: "ch-width 0"},
+ {at: 0, expect: "ch-width 0"},
+ {at: 0.5, expect: "ic-width 2.0"},
+ {at: 1, expect: "ic-width 2.0"},
+ {at: 1.5, expect: "ic-width 2.0"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "0.5",
+ addFrom: "ic-width 0.0",
+ addTo: "ic-height 2.0",
+}, [
+ {at: -0.5, expect: "ic-width 0.0"},
+ {at: 0, expect: "ic-width 0.0"},
+ {at: 0.5, expect: "ic-height 2.0"},
+ {at: 1, expect: "ic-height 2.0"},
+ {at: 1.5, expect: "ic-height 2.0"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "0.5",
+ replaceFrom: "ic-width 0.0",
+ replaceTo: "ic-height 2.0",
+}, [
+ {at: -0.5, expect: "ic-width 0.0"},
+ {at: 0, expect: "ic-width 0.0"},
+ {at: 0.5, expect: "ic-height 2.0"},
+ {at: 1, expect: "ic-height 2.0"},
+ {at: 1.5, expect: "ic-height 2.0"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "0.5",
+ replaceFrom: "ic-width 0",
+ addTo: "ic-height 2.0",
+}, [
+ {at: -0.5, expect: "ic-width 0.0"},
+ {at: 0, expect: "ic-width 0.0"},
+ {at: 0.5, expect: "ic-height 2.0"},
+ {at: 1, expect: "ic-height 2.0"},
+ {at: 1.5, expect: "ic-height 2.0"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "0.5",
+ addFrom: "ic-width 0",
+ replaceTo: "ic-height 2.0",
+}, [
+ {at: -0.5, expect: "ic-width 0"},
+ {at: 0, expect: "ic-width 0"},
+ {at: 0.5, expect: "ic-height 2.0"},
+ {at: 1, expect: "ic-height 2.0"},
+ {at: 1.5, expect: "ic-height 2.0"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "0.5",
+ addFrom: "ic-height 0.0",
+ addTo: "ex-height 2.0",
+}, [
+ {at: -0.5, expect: "ic-height 0.0"},
+ {at: 0, expect: "ic-height 0.0"},
+ {at: 0.5, expect: "ex-height 2.5"},
+ {at: 1, expect: "ex-height 2.5"},
+ {at: 1.5, expect: "ex-height 2.5"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "0.5",
+ replaceFrom: "ic-height 0.0",
+ replaceTo: "ex-height 2.0",
+}, [
+ {at: -0.5, expect: "ic-height 0.0"},
+ {at: 0, expect: "ic-height 0.0"},
+ {at: 0.5, expect: "ex-height 2.0"},
+ {at: 1, expect: "ex-height 2.0"},
+ {at: 1.5, expect: "ex-height 2.0"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "0.5",
+ replaceFrom: "ic-height 0",
+ addTo: "ex-height 2.0",
+}, [
+ {at: -0.5, expect: "ic-height 0.0"},
+ {at: 0, expect: "ic-height 0.0"},
+ {at: 0.5, expect: "ex-height 2.5"},
+ {at: 1, expect: "ex-height 2.5"},
+ {at: 1.5, expect: "ex-height 2.5"},
+]);
+
+test_composition({
+ property: 'font-size-adjust',
+ underlying: "0.5",
+ addFrom: "ic-height 0",
+ replaceTo: "ex-height 2.0",
+}, [
+ {at: -0.5, expect: "ic-height 0"},
+ {at: 0, expect: "ic-height 0"},
+ {at: 0.5, expect: "ex-height 2.0"},
+ {at: 1, expect: "ex-height 2.0"},
+ {at: 1.5, expect: "ex-height 2.0"},
+]);
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-fonts/animations/font-size-adjust-interpolation.html b/testing/web-platform/tests/css/css-fonts/animations/font-size-adjust-interpolation.html
new file mode 100644
index 0000000000..a138d7fee5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-fonts/animations/font-size-adjust-interpolation.html
@@ -0,0 +1,169 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>font-size-adjust interpolation</title>
+<link rel="help" href="https://drafts.csswg.org/css-fonts-3/#propdef-font-size-adjust">
+<meta name="assert" content="font-size-adjust supports animation as a number">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style type="text/css">
+.container {
+ font-size: 20px;
+ line-height: 1;
+}
+
+.parent {
+ font-size-adjust: 3;
+}
+
+.target {
+ display: inline-block;
+ font-size-adjust: 1;
+}
+
+.expected {
+ color: green;
+ margin-right: 30px;
+}
+</style>
+
+<body>
+<template id="target-template">
+ <span class="container">
+ <div class="target">x</span>
+ </div>
+</template>
+</body>
+
+<script>
+test_interpolation({
+ property: 'font-size-adjust',
+ from: neutralKeyframe,
+ to: '2',
+}, [
+ {at: -2, expect: '0'},
+ {at: -0.3, expect: '0.7'},
+ {at: 0, expect: '1'},
+ {at: 0.3, expect: '1.3'},
+ {at: 0.6, expect: '1.6'},
+ {at: 1, expect: '2'},
+ {at: 1.5, expect: '2.5'},
+]);
+
+test_no_interpolation({
+ property: 'font-size-adjust',
+ from: 'initial',
+ to: '2',
+});
+
+test_no_interpolation({
+ property: 'font-size-adjust',
+ from: 'initial',
+ to: 'cap-height 2',
+});
+
+test_interpolation({
+ property: 'font-size-adjust',
+ from: 'inherit',
+ to: '2',
+}, [
+ {at: -2, expect: '5'},
+ {at: -0.3, expect: '3.3'},
+ {at: 0, expect: '3'},
+ {at: 0.3, expect: '2.7'},
+ {at: 0.6, expect: '2.4'},
+ {at: 1, expect: '2'},
+ {at: 1.5, expect: '1.5'},
+]);
+
+test_interpolation({
+ property: 'font-size-adjust',
+ from: 'unset',
+ to: '2',
+}, [
+ {at: -2, expect: '5'},
+ {at: -0.3, expect: '3.3'},
+ {at: 0, expect: '3'},
+ {at: 0.3, expect: '2.7'},
+ {at: 0.6, expect: '2.4'},
+ {at: 1, expect: '2'},
+ {at: 1.5, expect: '1.5'},
+]);
+
+
+test_interpolation({
+ property: 'font-size-adjust',
+ from: '0',
+ to: '1.2'
+}, [
+ {at: -2, expect: '0'},
+ {at: -0.3, expect: '0'},
+ {at: 0, expect: '0'},
+ {at: 0.3, expect: '0.36'},
+ {at: 0.6, expect: '0.72'},
+ {at: 1, expect: '1.2'},
+ {at: 1.5, expect: '1.8'},
+]);
+
+test_interpolation({
+ property: 'font-size-adjust',
+ from: 'cap-height 0',
+ to: 'cap-height 1.2'
+}, [
+ {at: -2, expect: 'cap-height 0'},
+ {at: -0.3, expect: 'cap-height 0'},
+ {at: 0, expect: 'cap-height 0'},
+ {at: 0.3, expect: 'cap-height 0.36'},
+ {at: 0.6, expect: 'cap-height 0.72'},
+ {at: 1, expect: 'cap-height 1.2'},
+ {at: 1.5, expect: 'cap-height 1.8'},
+]);
+
+test_no_interpolation({
+ property: 'font-size-adjust',
+ from: 'none',
+ to: '1.2'
+});
+
+test_no_interpolation({
+ property: 'font-size-adjust',
+ from: 'none',
+ to: 'cap-height 1.2'
+});
+
+test_interpolation({
+ property: 'font-size-adjust',
+ from: '0.2',
+ to: '1.2'
+}, [
+ {at: -2, expect: '0'}, // CSS font-size-adjust can't be negative.
+ {at: -0.3, expect: '0'},
+ {at: 0, expect: '0.2'},
+ {at: 0.3, expect: '0.5'},
+ {at: 0.6, expect: '0.8'},
+ {at: 1, expect: '1.2'},
+ {at: 1.5, expect: '1.7'},
+]);
+
+test_interpolation({
+ property: 'font-size-adjust',
+ from: 'ch-width 0.2',
+ to: 'ch-width 1.2'
+}, [
+ {at: -2, expect: 'ch-width 0'}, // CSS font-size-adjust can't be negative.
+ {at: -0.3, expect: 'ch-width 0'},
+ {at: 0, expect: 'ch-width 0.2'},
+ {at: 0.3, expect: 'ch-width 0.5'},
+ {at: 0.6, expect: 'ch-width 0.8'},
+ {at: 1, expect: 'ch-width 1.2'},
+ {at: 1.5, expect: 'ch-width 1.7'},
+]);
+
+test_no_interpolation({ // can't interpolate between different adjustment basis
+ property: 'font-size-adjust',
+ from: 'ex-height 0.2',
+ to: 'cap-height 1.2'
+});
+</script>
diff --git a/testing/web-platform/tests/css/css-fonts/animations/font-size-interpolation-001.html b/testing/web-platform/tests/css/css-fonts/animations/font-size-interpolation-001.html
new file mode 100644
index 0000000000..0f60018c2e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-fonts/animations/font-size-interpolation-001.html
@@ -0,0 +1,103 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>font-size interpolation</title>
+<link rel="help" href="https://drafts.csswg.org/css-fonts-3/#propdef-font-size">
+<meta name="assert" content="font-size supports animation as length">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.parent {
+ font-size: 30px;
+}
+.target {
+ display: inline-block;
+ font: 10px sans-serif;
+}
+.expected {
+ color: green;
+ margin-right: 30px;
+}
+</style>
+
+<body>
+<template id="target-template">
+ <span>
+ <div class="target">Test Text</div>
+ </span>
+</template>
+</body>
+
+<script>
+test_interpolation({
+ property: 'font-size',
+ from: neutralKeyframe,
+ to: '20px',
+}, [
+ {at: -2, expect: '0px'},
+ {at: -0.3, expect: '7px'},
+ {at: 0, expect: '10px'},
+ {at: 0.3, expect: '13px'},
+ {at: 0.6, expect: '16px'},
+ {at: 1, expect: '20px'},
+ {at: 1.5, expect: '25px'},
+]);
+
+test_interpolation({
+ property: 'font-size',
+ from: 'initial',
+ to: '20px',
+}, [
+ {at: -2, expect: '8px'},
+ {at: -0.3, expect: '14.8px'},
+ {at: 0, expect: '16px'},
+ {at: 0.3, expect: '17.2px'},
+ {at: 0.6, expect: '18.4px'},
+ {at: 1, expect: '20px'},
+ {at: 1.5, expect: '22px'},
+]);
+
+test_interpolation({
+ property: 'font-size',
+ from: 'inherit',
+ to: '20px',
+}, [
+ {at: -2, expect: '50px'},
+ {at: -0.3, expect: '33px'},
+ {at: 0, expect: '30px'},
+ {at: 0.3, expect: '27px'},
+ {at: 0.6, expect: '24px'},
+ {at: 1, expect: '20px'},
+ {at: 1.5, expect: '15px'},
+]);
+
+test_interpolation({
+ property: 'font-size',
+ from: 'unset',
+ to: '20px',
+}, [
+ {at: -2, expect: '50px'},
+ {at: -0.3, expect: '33px'},
+ {at: 0, expect: '30px'},
+ {at: 0.3, expect: '27px'},
+ {at: 0.6, expect: '24px'},
+ {at: 1, expect: '20px'},
+ {at: 1.5, expect: '15px'},
+]);
+
+test_interpolation({
+ property: 'font-size',
+ from: '4px',
+ to: '14px'
+}, [
+ {at: -2, expect: '0px'}, // CSS font-size can't be negative.
+ {at: -0.3, expect: '1px'},
+ {at: 0, expect: '4px'},
+ {at: 0.3, expect: '7px'},
+ {at: 0.6, expect: '10px'},
+ {at: 1, expect: '14px'},
+ {at: 1.5, expect: '19px'},
+]);
+</script>
diff --git a/testing/web-platform/tests/css/css-fonts/animations/font-size-interpolation-002.html b/testing/web-platform/tests/css/css-fonts/animations/font-size-interpolation-002.html
new file mode 100644
index 0000000000..d6f2f19ab1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-fonts/animations/font-size-interpolation-002.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>font-size interpolation</title>
+<link rel="help" href="https://drafts.csswg.org/css-fonts-3/#propdef-font-size">
+<meta name="assert" content="font-size supports animation as length">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.container {
+ font-size: 10px;
+}
+.target {
+ display: inline-block;
+ font: 100px sans-serif;
+ font-size: 20px;
+}
+.expected {
+ color: green;
+ margin-right: 30px;
+}
+</style>
+
+<body>
+<template id="target-template">
+ <span class="container">
+ <div class="target">TT</div>
+ </span>
+</template>
+</body>
+
+<script>
+// Test the 'unset' case.
+test_interpolation({
+ property: 'font-size',
+ from: 'unset',
+ to: '20px'
+}, [
+ {at: -2, expect: '0px'}, // CSS font-size can't be negative.
+ {at: -0.3, expect: '7px'},
+ {at: 0, expect: '10px'},
+ {at: 0.3, expect: '13px'},
+ {at: 0.6, expect: '16px'},
+ {at: 1, expect: '20px'},
+ {at: 1.5, expect: '25px'},
+]);
+</script>
diff --git a/testing/web-platform/tests/css/css-fonts/animations/font-size-interpolation-003.html b/testing/web-platform/tests/css/css-fonts/animations/font-size-interpolation-003.html
new file mode 100644
index 0000000000..d84ff7e5df
--- /dev/null
+++ b/testing/web-platform/tests/css/css-fonts/animations/font-size-interpolation-003.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>font-size interpolation with zoom</title>
+<link rel="help" href="https://drafts.csswg.org/css-fonts-3/#propdef-font-size">
+<meta name="assert" content="font-size supports animation as a length, respecting zoom">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.container {
+ zoom: 2;
+}
+.target {
+ display: inline-block;
+}
+.expected {
+ color: green;
+ margin-right: 30px;
+}
+</style>
+
+<body>
+<template id="target-template">
+ <span class="container">
+ <div class="target">TT</div>
+ </span>
+</template>
+</body>
+
+<script>
+// The container has zoom: 2 applied to it.
+test_interpolation({
+ property: 'font-size',
+ from: '10px',
+ to: '20px'
+}, [
+ {at: -2, expect: '0px'}, // CSS font-size can't be negative.
+ {at: -0.3, expect: '7px'},
+ {at: 0, expect: '10px'},
+ {at: 0.3, expect: '13px'},
+ {at: 0.6, expect: '16px'},
+ {at: 1, expect: '20px'},
+ {at: 1.5, expect: '25px'},
+]);
+</script>
diff --git a/testing/web-platform/tests/css/css-fonts/animations/font-stretch-interpolation.html b/testing/web-platform/tests/css/css-fonts/animations/font-stretch-interpolation.html
new file mode 100644
index 0000000000..e62788f82f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-fonts/animations/font-stretch-interpolation.html
@@ -0,0 +1,164 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>font-size interpolation</title>
+<link rel="help" href="https://drafts.csswg.org/css-fonts-3/#propdef-font-size">
+<meta name="assert" content="font-size supports animation as length">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.container {
+ font-stretch: ultra-expanded;
+}
+.container2 {
+ font-stretch: ultra-condensed;
+}
+.target {
+ display: inline-block;
+ font: 100px sans-serif;
+ font-stretch: normal;
+}
+.expected {
+ color: green;
+ margin-right: 30px;
+}
+</style>
+
+<body>
+<template id="target-template">
+ <span class="container">
+ <div class="target">TT</div>
+ </span>
+</template>
+
+<span id="inv-container" class="container">
+ <div id="inv-target" class="target">TT</div>
+</span>
+</body>
+
+<script>
+test_interpolation({
+ property: 'font-stretch',
+ from: '100%',
+ to: '200%'
+}, [
+ {at: -2, expect: '0%'}, // CSS font-stretch can't be negative.
+ {at: -0.25, expect: '75%'},
+ {at: 0, expect: '100%'},
+ {at: 0.3, expect: '130%'},
+ {at: 0.6, expect: '160%'},
+ {at: 1, expect: '200%'},
+ {at: 1.5, expect: '250%'},
+]);
+
+test_interpolation({
+ property: 'font-stretch',
+ from: neutralKeyframe,
+ to: '200%'
+}, [
+ {at: -2, expect: '0%'},
+ {at: -0.25, expect: '75%'},
+ {at: 0, expect: '100%'},
+ {at: 0.3, expect: '130%'},
+ {at: 0.6, expect: '160%'},
+ {at: 1, expect: '200%'},
+ {at: 1.5, expect: '250%'},
+]);
+
+test_interpolation({
+ property: 'font-stretch',
+ from: 'initial',
+ to: 'inherit'
+}, [
+ {at: -2, expect: '0%'},
+ {at: -0.25, expect: '75%'},
+ {at: 0, expect: '100%'},
+ {at: 0.3, expect: '130%'},
+ {at: 0.6, expect: '160%'},
+ {at: 1, expect: '200%'},
+ {at: 1.5, expect: '250%'},
+]);
+
+// Test interpolation from keywords.
+test_interpolation({
+ property: 'font-stretch',
+ from: 'normal',
+ to: 'ultra-expanded'
+}, [
+ {at: -0.25, expect: '75%'},
+ {at: 0, expect: '100%'},
+ {at: 0.125, expect: '112.5%'},
+ {at: 0.25, expect: '125%'},
+ {at: 0.5, expect: '150%'},
+ {at: 0.75, expect: '175%'},
+ {at: 1, expect: '200%'},
+]);
+
+test_interpolation({
+ property: 'font-stretch',
+ from: 'ultra-condensed',
+ to: 'condensed'
+}, [
+ {at: 0, expect: '50%'},
+ {at: 0.5, expect: '62.5%'},
+ {at: 1, expect: '75%'},
+]);
+
+test_interpolation({
+ property: 'font-stretch',
+ from: 'extra-condensed',
+ to: 'semi-condensed'
+}, [
+ {at: 0, expect: '62.5%'},
+ {at: 0.5, expect: '75%'},
+ {at: 1, expect: '87.5%'},
+]);
+
+test_interpolation({
+ property: 'font-stretch',
+ from: 'condensed',
+ to: 'expanded'
+}, [
+ {at: 0, expect: '75%'},
+ {at: 0.25, expect: '87.5%'},
+ {at: 0.5, expect: '100%'},
+ {at: 0.75, expect: '112.5%'},
+ {at: 1, expect: '125%'},
+]);
+
+test_interpolation({
+ property: 'font-stretch',
+ from: 'semi-condensed',
+ to: 'semi-expanded'
+}, [
+ {at: 0, expect: '87.5%'},
+ {at: 0.5, expect: '100%'},
+ {at: 1, expect: '112.5%'},
+]);
+
+test_interpolation({
+ property: 'font-stretch',
+ from: 'normal',
+ to: 'extra-expanded'
+}, [
+ {at: 0, expect: '100%'},
+ {at: 0.25, expect: '112.5%'},
+ {at: 0.5, expect: '125%'},
+ {at: 1, expect: '150%'},
+]);
+
+test(t => {
+ var container = document.getElementById('inv-container');
+ var target = document.getElementById('inv-target');
+ var anim = target.animate({fontStretch: ['normal', 'inherit']}, 1000);
+ anim.pause();
+ anim.currentTime = 500;
+ assert_equals(getComputedStyle(target).fontStretch, '150%');
+
+ container.setAttribute('class', 'container2');
+ assert_equals(getComputedStyle(target).fontStretch, '75%');
+}, "An interpolation to inherit updates correctly on a parent style change.");
+
+</script>
diff --git a/testing/web-platform/tests/css/css-fonts/animations/font-style-interpolation.html b/testing/web-platform/tests/css/css-fonts/animations/font-style-interpolation.html
new file mode 100644
index 0000000000..4666025d54
--- /dev/null
+++ b/testing/web-platform/tests/css/css-fonts/animations/font-style-interpolation.html
@@ -0,0 +1,122 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>font-style interpolation</title>
+<link rel="help" href="https://drafts.csswg.org/css-fonts-3/#propdef-font-style">
+<meta name="assert" content="Font-style should be animated smoothly.">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.container {
+ font-style: oblique 20deg;
+}
+.container2 {
+ font-style: oblique 5deg;
+}
+.target {
+ display: inline-block;
+ font: 100px sans-serif;
+ font-style: normal;
+}
+.expected {
+ color: green;
+ margin-right: 30px;
+}
+</style>
+
+<body>
+<template id="target-template">
+ <span class="container">
+ <div class="target">TT</div>
+ </span>
+</template>
+
+<span id="inv-container" class="container">
+ <div id="inv-target" class="target">TT</div>
+</span>
+</body>
+
+<script>
+test_interpolation({
+ property: 'font-style',
+ from: 'normal',
+ to: 'oblique 10deg'
+}, [
+ {at: -2, expect: 'oblique -20deg'},
+ {at: -0.25, expect: 'oblique -2.5deg'},
+ {at: 0, expect: 'normal'},
+ {at: 0.3, expect: 'oblique 3deg'},
+ {at: 0.6, expect: 'oblique 6deg'},
+ {at: 1, expect: 'oblique 10deg'},
+ {at: 1.5, expect: 'oblique 15deg'},
+]);
+
+test_interpolation({
+ property: 'font-style',
+ from: 'oblique 5deg',
+ to: 'oblique 15deg'
+}, [
+ { at: -2, expect: 'oblique -15deg' },
+ { at: -0.25, expect: 'oblique 2.5deg' },
+ { at: 0, expect: 'oblique 5deg' },
+ { at: 0.3, expect: 'oblique 8deg' },
+ { at: 0.6, expect: 'oblique 11deg' },
+ { at: 1, expect: 'oblique 15deg' },
+ { at: 1.5, expect: 'oblique 20deg' },
+]);
+
+test_interpolation({
+ property: 'font-style',
+ from: 'initial',
+ to: 'inherit'
+}, [
+ { at: -2, expect: 'oblique -40deg' },
+ { at: -0.25, expect: 'oblique -5deg' },
+ { at: 0, expect: 'normal' },
+ { at: 0.3, expect: 'oblique 6deg' },
+ { at: 0.6, expect: 'oblique 12deg' },
+ { at: 1, expect: 'oblique 20deg' },
+ { at: 1.5, expect: 'oblique 30deg' },
+]);
+
+test_interpolation({
+ property: 'font-style',
+ from: 'oblique 20deg',
+ to: 'normal'
+}, [
+ { at: -1, expect: 'oblique 40deg' },
+ { at: 0, expect: 'oblique 20deg' },
+ { at: 0.5, expect: 'oblique 10deg' },
+ { at: 1, expect: 'normal' },
+ { at: 1.5, expect: 'oblique -10deg' },
+]);
+
+test_interpolation({
+ property: 'font-style',
+ from: 'oblique -90deg',
+ to: 'oblique 90deg'
+}, [
+ { at: -2, expect: 'oblique -90deg' },
+ { at: -1, expect: 'oblique -90deg' },
+ { at: 0, expect: 'oblique -90deg' },
+ { at: 0.5, expect: 'normal' },
+ { at: 1, expect: 'oblique 90deg' },
+ { at: 1.5, expect: 'oblique 90deg' },
+]);
+
+test(t => {
+ var container = document.getElementById('inv-container');
+ var target = document.getElementById('inv-target');
+ var anim = target.animate({ fontStyle: ['normal', 'inherit'] }, 1000);
+ anim.pause();
+ anim.currentTime = 500;
+ assert_equals(getComputedStyle(target).fontStyle, 'oblique 10deg');
+
+ container.setAttribute('class', 'container2');
+ assert_equals(getComputedStyle(target).fontStyle, 'oblique 2.5deg');
+}, "An interpolation to inherit updates correctly on a parent style change.");
+
+</script>
+
diff --git a/testing/web-platform/tests/css/css-fonts/animations/font-variation-settings-composition.html b/testing/web-platform/tests/css/css-fonts/animations/font-variation-settings-composition.html
new file mode 100644
index 0000000000..e1ebfc2836
--- /dev/null
+++ b/testing/web-platform/tests/css/css-fonts/animations/font-variation-settings-composition.html
@@ -0,0 +1,102 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>font-variation-settings composition</title>
+<link rel="help" href="https://drafts.csswg.org/css-fonts-4/#propdef-font-variation-settings">
+<meta name="assert" content="font-variation-settings supports animation pairwise by 'like' properties">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body></body>
+
+<script>
+function compareVariationSettings(actual, expected) {
+ // The order of <axis, value> pairs in the variation-settings list is arbitrary,
+ // so we sort the pairs before attempting to compare. (We only need to use this
+ // when multiple settings are expected, otherwise the default comparison is OK.)
+ assert_equals(normalizeValue(actual).split(", ").sort().join(", "),
+ normalizeValue(expected).split(", ").sort().join(", "));
+};
+
+test_composition({
+ property: 'font-variation-settings',
+ underlying: "'test' 50",
+ addFrom: "'test' 100",
+ addTo: "'test' 200",
+}, [
+ {at: -0.3, expect: "'test' 120"},
+ {at: 0, expect: "'test' 150"},
+ {at: 0.5, expect: "'test' 200"},
+ {at: 1, expect: "'test' 250"},
+ {at: 1.5, expect: "'test' 300"},
+]);
+
+test_composition({
+ property: 'font-variation-settings',
+ underlying: "'test' 50",
+ addFrom: "'test' 100",
+ replaceTo: "'test' 200",
+}, [
+ {at: -0.3, expect: "'test' 135"},
+ {at: 0, expect: "'test' 150"},
+ {at: 0.5, expect: "'test' 175"},
+ {at: 1, expect: "'test' 200"},
+ {at: 1.5, expect: "'test' 225"},
+]);
+
+test_composition({
+ property: 'font-variation-settings',
+ underlying: "'test' 100",
+ addFrom: 'normal',
+ replaceTo: "'test' 200",
+}, [
+ {at: -0.3, expect: 'normal'},
+ {at: 0, expect: 'normal'},
+ {at: 0.5, expect: "'test' 200"},
+ {at: 1, expect: "'test' 200"},
+ {at: 1.5, expect: "'test' 200"},
+]);
+
+test_composition({
+ property: 'font-variation-settings',
+ underlying: "'test' 100",
+ addFrom: 'normal',
+ addTo: "'test' 200",
+}, [
+ {at: -0.3, expect: 'normal'},
+ {at: 0, expect: 'normal'},
+ {at: 0.5, expect: "'test' 300"},
+ {at: 1, expect: "'test' 300"},
+ {at: 1.5, expect: "'test' 300"},
+]);
+
+test_composition({
+ property: 'font-variation-settings',
+ underlying: "'aaaa' 100, 'bbbb' 200",
+ addFrom: "'aaaa' 20, 'bbbb' 50",
+ addTo: "'aaaa' 30, 'bbbb' 100",
+ comparisonFunction: compareVariationSettings,
+}, [
+ {at: -0.3, expect: "'aaaa' 117, 'bbbb' 235"},
+ {at: 0, expect: "'aaaa' 120, 'bbbb' 250"},
+ {at: 0.5, expect: "'aaaa' 125, 'bbbb' 275"},
+ {at: 1, expect: "'aaaa' 130, 'bbbb' 300"},
+ {at: 1.5, expect: "'aaaa' 135, 'bbbb' 325"},
+]);
+
+test_composition({
+ property: 'font-variation-settings',
+ underlying: "'test' 100",
+ addFrom: "'aaaa' 20, 'bbbb' 50",
+ addTo: "'aaaa' 30, 'bbbb' 100",
+ comparisonFunction: compareVariationSettings,
+}, [
+ {at: -0.3, expect: "'aaaa' 17, 'bbbb' 35"},
+ {at: 0, expect: "'aaaa' 20, 'bbbb' 50"},
+ {at: 0.5, expect: "'aaaa' 25, 'bbbb' 75"},
+ {at: 1, expect: "'aaaa' 30, 'bbbb' 100"},
+ {at: 1.5, expect: "'aaaa' 35, 'bbbb' 125"},
+]);
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-fonts/animations/font-variation-settings-interpolation.html b/testing/web-platform/tests/css/css-fonts/animations/font-variation-settings-interpolation.html
new file mode 100644
index 0000000000..cb99d7b255
--- /dev/null
+++ b/testing/web-platform/tests/css/css-fonts/animations/font-variation-settings-interpolation.html
@@ -0,0 +1,161 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>font-variation-settings interpolation</title>
+<link rel="help" href="https://drafts.csswg.org/css-fonts-4/#propdef-font-variation-settings">
+<meta name="assert" content="font-variation-settings supports animation pairwise by 'like' properties">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.parent {
+ font-variation-settings: "test" 30;
+}
+.target {
+ font-variation-settings: "test" 10;
+}
+</style>
+
+<body></body>
+
+<script>
+
+// Because font-variation-settings is specced as a map rather than a list
+// (https://github.com/w3c/csswg-drafts/issues/1959), browsers are allowed to
+// reorder the output as they see fit.
+function compareFontVariationSettings(actual, expected) {
+ // This is not perfect, but should serve as a reasonable comparison. We split
+ // the inputs into arrays and trim each characteristic, then sort the array
+ // and compare them.
+ const actual_arr = actual.split(',').map(x => x.trim()).sort();
+ const expected_arr = expected.split(',').map(x => x.trim()).sort();
+ assert_array_equals(actual_arr, expected_arr);
+}
+
+test_interpolation({
+ property: 'font-variation-settings',
+ from: neutralKeyframe,
+ to: '"test" 20',
+ comparisonFunction: compareFontVariationSettings,
+}, [
+ {at: -0.5, expect: "'test' 5"},
+ {at: 0, expect: "'test' 10"},
+ {at: 0.3, expect: "'test' 13"},
+ {at: 0.7, expect: "'test' 17"},
+ {at: 1, expect: "'test' 20"},
+ {at: 1.5, expect: "'test' 25"},
+]);
+
+test_no_interpolation({
+ property: 'font-variation-settings',
+ from: 'initial',
+ to: "'test' 50",
+});
+
+test_interpolation({
+ property: 'font-variation-settings',
+ from: 'inherit',
+ to: "'test' 20",
+ comparisonFunction: compareFontVariationSettings,
+}, [
+ {at: -0.5, expect: "'test' 35"},
+ {at: 0, expect: "'test' 30"},
+ {at: 0.3, expect: "'test' 27"},
+ {at: 0.7, expect: "'test' 23"},
+ {at: 1, expect: "'test' 20"},
+ {at: 1.5, expect: "'test' 15"},
+]);
+
+test_interpolation({
+ property: 'font-variation-settings',
+ from: 'unset',
+ to: "'test' 20",
+ comparisonFunction: compareFontVariationSettings,
+}, [
+ {at: -0.5, expect: "'test' 35"},
+ {at: 0, expect: "'test' 30"},
+ {at: 0.3, expect: "'test' 27"},
+ {at: 0.7, expect: "'test' 23"},
+ {at: 1, expect: "'test' 20"},
+ {at: 1.5, expect: "'test' 15"},
+]);
+
+test_no_interpolation({
+ property: 'font-variation-settings',
+ from: "'test' 20",
+ to: "normal",
+});
+
+test_interpolation({
+ property: 'font-variation-settings',
+ from: "'test' 20",
+ to: "'test' 30",
+ comparisonFunction: compareFontVariationSettings,
+}, [
+ {at: -0.5, expect: "'test' 15"},
+ {at: 0, expect: "'test' 20"},
+ {at: 0.3, expect: "'test' 23"},
+ {at: 0.7, expect: "'test' 27"},
+ {at: 1, expect: "'test' 30"},
+ {at: 1.5, expect: "'test' 35"},
+]);
+
+test_interpolation({
+ property: 'font-variation-settings',
+ from: "'aaaa' 0, 'bbbb' 10, 'cccc' 20",
+ to: "'aaaa' 10, 'bbbb' 20, 'cccc' 30",
+ comparisonFunction: compareFontVariationSettings,
+}, [
+ {at: -0.5, expect: "'aaaa' -5, 'bbbb' 5, 'cccc' 15"},
+ {at: 0, expect: "'aaaa' 0, 'bbbb' 10, 'cccc' 20"},
+ {at: 0.3, expect: "'aaaa' 3, 'bbbb' 13, 'cccc' 23"},
+ {at: 0.7, expect: "'aaaa' 7, 'bbbb' 17, 'cccc' 27"},
+ {at: 1, expect: "'aaaa' 10, 'bbbb' 20, 'cccc' 30"},
+ {at: 1.5, expect: "'aaaa' 15, 'bbbb' 25, 'cccc' 35"},
+]);
+
+// font-variation-settings is a map, so any order works.
+test_interpolation({
+ property: 'font-variation-settings',
+ from: "'aaaa' 0, 'bbbb' 10, 'cccc' 20",
+ to: "'cccc' 10, 'bbbb' 20, 'aaaa' 30",
+ comparisonFunction: compareFontVariationSettings,
+}, [
+ {at: -0.5, expect: "'aaaa' -15, 'bbbb' 5, 'cccc' 25"},
+ {at: 0, expect: "'aaaa' 0, 'bbbb' 10, 'cccc' 20"},
+ {at: 0.3, expect: "'aaaa' 9, 'bbbb' 13, 'cccc' 17"},
+ {at: 0.7, expect: "'aaaa' 21, 'bbbb' 17, 'cccc' 13"},
+ {at: 1, expect: "'aaaa' 30, 'bbbb' 20, 'cccc' 10"},
+ {at: 1.5, expect: "'aaaa' 45, 'bbbb' 25, 'cccc' 5"},
+]);
+
+test_no_interpolation({
+ property: 'font-variation-settings',
+ from: "'aaaa' 0, 'bbbb' 10",
+ to: "'aaaa' 10, 'bbbb' 20, 'cccc' 30",
+});
+
+test_no_interpolation({
+ property: 'font-variation-settings',
+ from: "'aaaa' 10, 'bbbb' 20, 'cccc' 30",
+ to: "'aaaa' 0, 'bbbb' 10",
+});
+
+test_no_interpolation({
+ property: 'font-variation-settings',
+ from: "'aaaa' 0, 'bbbb' 10, 'cccc' 20",
+ to: "'dddd' 10, 'eeee' 20, 'ffff' 30",
+});
+
+// crbug.com/910118: Test that ApplyStandardPropertyValue doesn't overflow.
+test_interpolation({
+ property: 'font-variation-settings',
+ from: "'aaaa' 30, 'bbbb' 20",
+ to: "'aaaa' 20, 'bbbb' 30",
+ comparisonFunction: compareFontVariationSettings,
+}, [
+ {at: 3.40282e+38, expect: "'aaaa' -3.40282e+38, 'bbbb' 3.40282e+38"},
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-fonts/animations/multiple-elements-font-palette-animation.html b/testing/web-platform/tests/css/css-fonts/animations/multiple-elements-font-palette-animation.html
new file mode 100644
index 0000000000..a3804487d2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-fonts/animations/multiple-elements-font-palette-animation.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>Font-palette animation of multiple elements</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-4/#propdef-font-palette">
+<meta name="assert" content="Animating font-palette CSS property of multiple elements.">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+ @font-face {
+ font-family: "COLR-test-font";
+ src: url("../resources/COLR-palettes-test-font.ttf") format("truetype");
+ }
+ @font-palette-values --custom {
+ font-family: "COLR-test-font";
+ base-palette: 3;
+ }
+ @keyframes anim {
+ from {
+ font-palette: normal;
+ }
+ to {
+ font-palette: --custom;
+ }
+ }
+ .demo {
+ font-family: "COLR-test-font";
+ font-size: 130px;
+ }
+ .anim {
+ animation: anim 0.1s forwards;
+ }
+</style>
+
+<body>
+ <div class="demo">
+ <div id="a" class="anim">A</div><div id="b" class="anim">A</div>
+ </div>
+</body>
+
+<script>
+ var afterPaletteAnimationTest1 = async_test(
+ "Verify font-palette value of the first element after animation"
+ );
+ document.getElementById("a").addEventListener("animationend",
+ afterPaletteAnimationTest1.step_func_done(function() {
+ assert_equals(window.getComputedStyle(
+ document.getElementById("a"))
+ .getPropertyValue('font-palette'), "--custom");
+ }));
+
+ var afterPaletteAnimationTest2 = async_test(
+ "Verify font-palette value of the second element after animation"
+ );
+ document.getElementById("b").addEventListener("animationend",
+ afterPaletteAnimationTest2.step_func_done(function() {
+ assert_equals(window.getComputedStyle(
+ document.getElementById("b"))
+ .getPropertyValue('font-palette'), "--custom");
+ }));
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-fonts/animations/system-fonts.html b/testing/web-platform/tests/css/css-fonts/animations/system-fonts.html
new file mode 100644
index 0000000000..7021a5264e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-fonts/animations/system-fonts.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Fonts Test: Interpolation of system fonts</title>
+<link rel="help" href="https://drafts.csswg.org/css-fonts/#valdef-font-caption">
+<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com">
+<meta name="assert" content="When interpolating system fonts, they are first resolved and then the font longhands interpolate as usual">
+<link rel="stylesheet" herf="/fonts/ahem.css">
+
+<div id="resolver"></div>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+<script>
+// The system fonts will probably resolve to something very different.
+const initialFont = "italic 100 small-caps ultra-expanded 100px / 100px Ahem";
+
+const resolver = document.getElementById("resolver");
+const resolvedStyle = getComputedStyle(resolver);
+
+function extractNumber(value, unit) {
+ value = value.trim();
+ if (!value.endsWith(unit))
+ return NaN;
+ value = value.slice(0, -unit.length);
+ if (!value.length || value !== value.trim())
+ return NaN;
+ return Number(value);
+}
+
+const systemFonts = ["caption", "icon", "menu", "message-box", "small-caption", "status-bar"];
+for (const systemFont of systemFonts) {
+ resolver.style.font = systemFont;
+ const expectations = [];
+ const systemFontStyle = resolvedStyle["font-style"];
+ const systemFontWeight = Number(resolvedStyle["font-weight"]);
+ const systemFontVariant = resolvedStyle["font-variant"];
+ const systemFontStretch = extractNumber(resolvedStyle["font-stretch"], "%");
+ const systemFontSize = extractNumber(resolvedStyle["font-size"], "px");
+ const systemLineHeight = resolvedStyle["line-height"];
+ const systemLineHeightNumber = extractNumber(systemLineHeight, "px");
+ const systemFontFamily = resolvedStyle["font-family"];
+
+ for (const at of [-2, -0.5, 0, 0.3, 0.6, 1, 1.5]) {
+ const expect = {};
+ expect["font-style"] = at >= 0.5 ? systemFontStyle : "italic";
+ expect["font-weight"] = `${Math.max(1, at * systemFontWeight + (1 - at) * 100)}`;
+ expect["font-variant"] = at >= 0.5 ? systemFontVariant : "small-caps";
+ expect["font-stretch"] = `${at * systemFontStretch + (1 - at) * 200}%`;
+ expect["font-size"] = `${Math.max(0, at * systemFontSize + (1 - at) * 100)}px`;
+ expect["line-height"] = Number.isNaN(systemLineHeightNumber)
+ ? (at >= 0.5 ? systemLineHeight : "100px")
+ : `${Math.max(0, at * systemLineHeightNumber + (1 - at) * 100)}px`;
+ expect["font-family"] = at >= 0.5 ? systemFontFamily : "Ahem";
+ // There are more font longhands, but they can't be set in the shorthand,
+ // and the system fonts will probably resolve to the initial value,
+ // preventing a noticeable interpolation.
+ expectations.push({at, expect});
+ }
+
+ for (const method of ["CSS Animations", "Web Animations"]) {
+ test_interpolation({
+ method,
+ property: "font",
+ from: initialFont,
+ to: systemFont,
+ }, expectations);
+ }
+}
+</script>