summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/css/css-backgrounds/animations
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
commit43a97878ce14b72f0981164f87f2e35e14151312 (patch)
tree620249daf56c0258faa40cbdcf9cfba06de2a846 /testing/web-platform/tests/css/css-backgrounds/animations
parentInitial commit. (diff)
downloadfirefox-43a97878ce14b72f0981164f87f2e35e14151312.tar.xz
firefox-43a97878ce14b72f0981164f87f2e35e14151312.zip
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/css/css-backgrounds/animations')
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-backdrop-infinite-duration-crash.html28
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-element-not-visible-at-current-viewport-ref.html16
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-element-not-visible-at-current-viewport.html29
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fallback-additive-keyframe-ref.html11
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fallback-additive-keyframe.html29
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fallback-missing-0-percent-ref.html10
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fallback-missing-0-percent.html36
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fallback-missing-100-percent-ref.html10
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fallback-missing-100-percent.html36
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fallback-replace-ref.html10
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fallback-replace.html42
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-field-crash.html14
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fragmented-ref.html4
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fragmented.html21
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-half-opaque-ref.html11
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-half-opaque.html34
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-in-body-ref.html8
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-in-body.html21
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-non-empty-no-draw-crash.html16
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-non-zero-size-element-change-to-zero-ref.html0
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-non-zero-size-element-change-to-zero.html31
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-pseudo-element-ref.html41
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-pseudo-element.html67
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-ref.html10
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-removed-element-crash.html12
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-single-keyframe-ref.html10
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-single-keyframe.html21
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-three-keyframes1.html47
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-three-keyframes2-ref.html10
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-three-keyframes2.html45
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-three-keyframes3.html41
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-will-change-contents-ref.html11
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-will-change-contents.html45
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-blur-ref.html20
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-blur.html55
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-images-ref.html30
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-images.html51
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-mask-ref.html18
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-mask.html34
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-table1-ref.html10
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-table1.html19
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-table2.html22
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-table3.html19
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-table4.html20
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-zero-playbackRate-ref.html10
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-zero-playbackRate.html35
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-zero-size-element-change-to-non-zero-ref.html11
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-zero-size-element-change-to-non-zero.html29
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-zero-size-element-ref.html0
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-zero-size-element.html23
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation.html34
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-interpolation.html122
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-scroll-into-viewport-ref.html43
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-scroll-into-viewport.html50
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-transition-currentcolor-ref.html20
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-transition-currentcolor.html45
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-transition.html39
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-transparent-animation-in-body-ref.html3
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-color-transparent-animation-in-body.html21
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-image-interpolation.html230
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-position-interpolation.html137
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-position-origin-interpolation.html217
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-position-x-interpolation.html78
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-position-y-interpolation.html78
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/background-size-interpolation.html166
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/border-bottom-left-radius-composition.html58
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/border-bottom-right-radius-composition.html58
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/border-bottom-width-composition.html65
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/border-color-interpolation.html120
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/border-image-outset-composition.html133
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/border-image-outset-interpolation.html125
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/border-image-slice-composition.html133
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/border-image-slice-interpolation-stability.html24
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/border-image-slice-interpolation.html175
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/border-image-source-interpolation.html82
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/border-image-width-composition.html133
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/border-image-width-interpolation.html192
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/border-left-width-composition.html65
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/border-radius-interpolation.html141
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/border-right-width-composition.html65
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/border-top-left-radius-composition.html58
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/border-top-right-radius-composition.html58
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/border-top-width-composition.html65
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/border-width-interpolation.html175
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/box-shadow-composition.html118
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/box-shadow-interpolation.html198
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/invalidation/background-color-animation-with-zero-alpha-ref.html11
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/invalidation/background-color-animation-with-zero-alpha.html24
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/invalidation/background-color-transition-obscured-ref.html18
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/invalidation/background-color-transition-obscured.html44
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/invalidation/background-color-transition-with-delay-ref.html10
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/invalidation/background-color-transition-with-delay.html42
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/invalidation/background-color-transition-with-initially-transparent-ref.html11
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/invalidation/background-color-transition-with-initially-transparent.html33
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/two-background-color-animation-diff-length1-ref.html10
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/two-background-color-animation-diff-length1.html38
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/two-background-color-animation-diff-length2-ref.html10
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/two-background-color-animation-diff-length2.html36
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/two-background-color-animation-diff-length3-ref.html10
-rw-r--r--testing/web-platform/tests/css/css-backgrounds/animations/two-background-color-animation-diff-length3.html38
100 files changed, 5042 insertions, 0 deletions
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-backdrop-infinite-duration-crash.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-backdrop-infinite-duration-crash.html
new file mode 100644
index 0000000000..40aa54debc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-backdrop-infinite-duration-crash.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<style>
+ #target {
+ background: blue;
+ border: 2px solid black;
+ height: 100px;
+ width: 100px;
+ }
+</style>
+<body>
+ <dialog id="target"></dialog>
+</body>
+<script>
+ window.onload = async () => {
+ const target = document.getElementById('target');
+ target.showModal();
+ const anim =
+ target.animate({ backgroundColor: ['green', 'blue'] }, {
+ duration: Infinity,
+ pseudoElement: '::backdrop'
+ });
+ await anim.ready;
+ await waitForAnimationFrames(3);
+ };
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-element-not-visible-at-current-viewport-ref.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-element-not-visible-at-current-viewport-ref.html
new file mode 100644
index 0000000000..e47a83e393
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-element-not-visible-at-current-viewport-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<style>
+.box {
+ width: 100px;
+ height: 10000px;
+}
+.container {
+ width: 50px;
+ height: 50px;
+ background-color: rgb(100, 100, 0);
+}
+</style>
+<body>
+ <div class='box'></div>
+ <div class='container'></div>
+</body>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-element-not-visible-at-current-viewport.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-element-not-visible-at-current-viewport.html
new file mode 100644
index 0000000000..db212e3992
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-element-not-visible-at-current-viewport.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="background-color-animation-element-not-visible-at-current-viewport-ref.html">
+<style>
+.box {
+ width: 100px;
+ height: 10000px;
+}
+.container {
+ width: 50px;
+ height: 50px;
+ animation: bgcolor 1000000s cubic-bezier(0,1,1,0) -500000s;
+}
+@keyframes bgcolor {
+ 0% { background-color: rgb(0, 200, 0); }
+ 100% { background-color: rgb(200, 0, 0); }
+}
+</style>
+<script src="/common/reftest-wait.js"></script>
+<body>
+<div class="box"></div>
+<div class="container"></div>
+
+<script>
+takeScreenshot();
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fallback-additive-keyframe-ref.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fallback-additive-keyframe-ref.html
new file mode 100644
index 0000000000..b8ef74f8e1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fallback-additive-keyframe-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<style>
+.container {
+ width: 100px;
+ height: 100px;
+ background-color: rgb(200, 200, 0);
+}
+</style>
+<body>
+ <div class="container"></div>
+</body>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fallback-additive-keyframe.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fallback-additive-keyframe.html
new file mode 100644
index 0000000000..d4d3acf31e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fallback-additive-keyframe.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="background-color-animation-fallback-additive-keyframe-ref.html">
+<style>
+.container {
+ width: 100px;
+ height: 100px;
+ background-color: rgb(0, 200, 0);
+}
+</style>
+<script src="/common/reftest-wait.js"></script>
+<body>
+<div class="container" id="target"></div>
+
+<script>
+var target = document.getElementById("target");
+target.animate([
+ { backgroundColor: 'rgb(200, 0, 0)', composite: 'accumulate' },
+ { backgroundColor: 'rgb(0, 0, 0' }
+], {
+ duration: 1000000
+});
+requestAnimationFrame(() => {
+ takeScreenshot();
+});
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fallback-missing-0-percent-ref.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fallback-missing-0-percent-ref.html
new file mode 100644
index 0000000000..7a0046f27b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fallback-missing-0-percent-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<body>
+ <canvas id="canvas" width="100" height="100"></canvas>
+</body>
+<script>
+ var canvas = document.getElementById('canvas');
+ var ctx = canvas.getContext('2d');
+ ctx.fillStyle = 'rgb(0, 100, 100)';
+ ctx.fillRect(0, 0, 100, 100);
+</script>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fallback-missing-0-percent.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fallback-missing-0-percent.html
new file mode 100644
index 0000000000..9140b705d4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fallback-missing-0-percent.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="background-color-animation-fallback-missing-0-percent-ref.html">
+<style>
+.container {
+ /*TODO(crbug.com/1163949): Support animation keyframes without 0% or 100%.*/
+ width: 100px;
+ height: 100px;
+ background-color: green;
+ /* Use a long animation that start at 50% progress where the slope of the
+ selected timing function is zero. By setting up the animation in this way,
+ we accommodate lengthy delays in running the test without a potential drift
+ in the animated property value. This is important for avoiding flakes,
+ especially on debug builds. The screenshots are taken as soon as the
+ animation is ready, thus the long animation duration has no bearing on
+ the actual duration of the test. */
+ animation: bgcolor 1000000s cubic-bezier(0,1,1,0) -500000s;
+}
+@keyframes bgcolor {
+ 20% { background-color: rgb(0, 200, 0); }
+ 80% { background-color: rgb(0, 0, 200); }
+ 100% { background-color: rgb(200, 0, 0); }
+}
+</style>
+<script src="/common/reftest-wait.js"></script>
+<body>
+<div class="container"></div>
+
+<script>
+document.getAnimations()[0].ready.then(() => {
+ takeScreenshot();
+});
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fallback-missing-100-percent-ref.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fallback-missing-100-percent-ref.html
new file mode 100644
index 0000000000..7a0046f27b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fallback-missing-100-percent-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<body>
+ <canvas id="canvas" width="100" height="100"></canvas>
+</body>
+<script>
+ var canvas = document.getElementById('canvas');
+ var ctx = canvas.getContext('2d');
+ ctx.fillStyle = 'rgb(0, 100, 100)';
+ ctx.fillRect(0, 0, 100, 100);
+</script>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fallback-missing-100-percent.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fallback-missing-100-percent.html
new file mode 100644
index 0000000000..1c5b63201f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fallback-missing-100-percent.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="background-color-animation-fallback-missing-100-percent-ref.html">
+<style>
+.container {
+ /*TODO(crbug.com/1163949): Support animation keyframes without 0% or 100%.*/
+ width: 100px;
+ height: 100px;
+ background-color: green;
+ /* Use a long animation that start at 50% progress where the slope of the
+ selected timing function is zero. By setting up the animation in this way,
+ we accommodate lengthy delays in running the test without a potential drift
+ in the animated property value. This is important for avoiding flakes,
+ especially on debug builds. The screenshots are taken as soon as the
+ animation is ready, thus the long animation duration has no bearing on
+ the actual duration of the test. */
+ animation: bgcolor 1000000s cubic-bezier(0,1,1,0) -500000s;
+}
+@keyframes bgcolor {
+ 0% { background-color: rgb(200, 0, 0); }
+ 20% { background-color: rgb(0, 200, 0); }
+ 80% { background-color: rgb(0, 0, 200); }
+}
+</style>
+<script src="/common/reftest-wait.js"></script>
+<body>
+<div class="container"></div>
+
+<script>
+document.getAnimations()[0].ready.then(() => {
+ takeScreenshot();
+});
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fallback-replace-ref.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fallback-replace-ref.html
new file mode 100644
index 0000000000..271281cf88
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fallback-replace-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<body>
+ <canvas id="canvas" width="100" height="100"></canvas>
+</body>
+<script>
+ var canvas = document.getElementById('canvas');
+ var ctx = canvas.getContext('2d');
+ ctx.fillStyle = 'rgb(0, 0, 100)';
+ ctx.fillRect(0, 0, 100, 100);
+</script>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fallback-replace.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fallback-replace.html
new file mode 100644
index 0000000000..ce4e927f73
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fallback-replace.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="background-color-animation-fallback-replace-ref.html">
+<style>
+.container {
+ width: 100px;
+ height: 100px;
+ background-color: green;
+ /* Use a long animation that start at 50% progress where the slope of the
+ selected timing function is zero. By setting up the animation in this way,
+ we accommodate lengthy delays in running the test without a potential drift
+ in the animated property value. This is important for avoiding flakes,
+ especially on debug builds. The screenshots are taken as soon as the
+ animation is ready, thus the long animation duration has no bearing on
+ the actual duration of the test. */
+ animation: red 1000000s cubic-bezier(0,1,1,0) -500000s, green 1000000s cubic-bezier(0,1,1,0) -500000s, blue 1000000s cubic-bezier(0,1,1,0) -500000s;
+}
+@keyframes red {
+ 0% { background-color: rgb(0, 0, 0); }
+ 100% { background-color: rgb(200, 0, 0); }
+}
+@keyframes green {
+ 0% { background-color: rgb(0, 0, 0); }
+ 100% { background-color: rgb(0, 200, 0); }
+}
+@keyframes blue {
+ 0% { background-color: rgb(0, 0, 0); }
+ 100% { background-color: rgb(0, 0, 200); }
+}
+</style>
+<script src="/common/reftest-wait.js"></script>
+<body>
+<div class="container"></div>
+
+<script>
+document.getAnimations()[0].ready.then(() => {
+ takeScreenshot();
+});
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-field-crash.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-field-crash.html
new file mode 100644
index 0000000000..8e702fbac6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-field-crash.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<style>
+@keyframes bgcolor {
+ 0% { background: Field; }
+ 100% { background: green; }
+}
+.target {
+ animation: bgcolor 50ms;
+ width: 100px;
+ height: 100px;
+}
+</style>
+<div class="target"></div> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fragmented-ref.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fragmented-ref.html
new file mode 100644
index 0000000000..845a8b5a5b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fragmented-ref.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<div style="columns: 2; width: 200px; height: 100px;">
+ <div style="height: 100px; background: rgb(100, 100, 0)"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fragmented.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fragmented.html
new file mode 100644
index 0000000000..64d94b9322
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-fragmented.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="background-color-animation-fragmented-ref.html">
+<style>
+@keyframes bgcolor {
+ 0% { background-color: rgb(0, 200, 0); }
+ 100% { background-color: rgb(200, 0, 0); }
+}
+</style>
+<script src="/common/reftest-wait.js"></script>
+<body>
+<div style="columns: 2; width: 200px; height: 100px">
+ <div style="animation: bgcolor 1000000s cubic-bezier(0,1,1,0) -500000s; height: 100px"></div>
+</div>
+
+<script>
+takeScreenshot();
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-half-opaque-ref.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-half-opaque-ref.html
new file mode 100644
index 0000000000..6bcb9840b3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-half-opaque-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<style>
+.box {
+ width: 600px;
+ height: 600px;
+ background-color: rgba(75, 125, 0, 0.8);
+}
+</style>
+<body>
+ <div class='box'></div>
+</body> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-half-opaque.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-half-opaque.html
new file mode 100644
index 0000000000..2e00fa6113
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-half-opaque.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="background-color-animation-half-opaque-ref.html">
+<style>
+.container {
+ width: 600px;
+ height: 600px;
+ will-change: transform;
+ /* Use a long animation that start at 50% progress where the slope of the
+ selected timing function is zero. By setting up the animation in this way,
+ we accommodate lengthy delays in running the test without a potential drift
+ in the animated property value. This is important for avoiding flakes,
+ especially on debug builds. The screenshots are taken as soon as the
+ animation is ready, thus the long animation duration has no bearing on
+ the actual duration of the test. */
+ animation: bgcolor 1000000s cubic-bezier(0,1,1,0) -500000s;
+}
+@keyframes bgcolor {
+ 0% { background-color: rgba(0, 200, 0, 1); }
+ 100% { background-color: rgba(200, 0, 0, 0.6); }
+}
+</style>
+<script src="/common/reftest-wait.js"></script>
+<body>
+<div class="container"></div>
+
+<script>
+document.getAnimations()[0].ready.then(() => {
+ takeScreenshot();
+});
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-in-body-ref.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-in-body-ref.html
new file mode 100644
index 0000000000..5d3d419db6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-in-body-ref.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<style>
+body {
+ background-color: rgb(100, 100, 0);
+}
+</style>
+<body>
+</body>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-in-body.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-in-body.html
new file mode 100644
index 0000000000..e5783f2b41
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-in-body.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="background-color-animation-in-body-ref.html">
+<style>
+body {
+ /* Use a long animation that start at 50% progress where the slope of the
+ selected timing function is zero. By setting up the animation in this way,
+ we accommodate lengthy delays in running the test without a potential drift
+ in the animated property value. This is important for avoiding flakes,
+ especially on debug builds. The screenshots are taken as soon as the
+ animation is ready, thus the long animation duration has no bearing on
+ the actual duration of the test. */
+ animation: bgcolor 1000000s cubic-bezier(0,1,1,0) -500000s;
+}
+@keyframes bgcolor {
+ 0% { background-color: rgb(0, 200, 0); }
+ 100% { background-color: rgb(200, 0, 0); }
+}
+</style>
+<body>
+</body>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-non-empty-no-draw-crash.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-non-empty-no-draw-crash.html
new file mode 100644
index 0000000000..a00c08abce
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-non-empty-no-draw-crash.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<style>
+@keyframes bgcolor {
+
+ 0% { background: blue; }
+ 100% { background: none; }
+}
+.target {
+ animation: bgcolor 50ms;
+ opacity: 0.9;
+ height: 0.4px;
+ margin: 21.6px;
+}
+</style>
+<div class="target"></div> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-non-zero-size-element-change-to-zero-ref.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-non-zero-size-element-change-to-zero-ref.html
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-non-zero-size-element-change-to-zero-ref.html
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-non-zero-size-element-change-to-zero.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-non-zero-size-element-change-to-zero.html
new file mode 100644
index 0000000000..6ba25c8196
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-non-zero-size-element-change-to-zero.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="background-color-animation-non-zero-size-element-change-to-zero-ref.html">
+<style>
+.container {
+ width: 100px;
+ height: 100px;
+ animation: bgcolor 1000000s cubic-bezier(0,1,1,0) -500000s;
+}
+@keyframes bgcolor {
+ 0% { background-color: rgb(0, 200, 0); }
+ 100% { background-color: rgb(200, 0, 0); }
+}
+</style>
+<script src="/common/reftest-wait.js"></script>
+<body>
+<div class="container" id="target"></div>
+
+<script>
+requestAnimationFrame(() => {
+ var target = document.getElementById("target");
+ target.style.width = '0px';
+ target.style.height = '0px';
+ requestAnimationFrame(() => {
+ takeScreenshot();
+ });
+});
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-pseudo-element-ref.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-pseudo-element-ref.html
new file mode 100644
index 0000000000..d82d28782b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-pseudo-element-ref.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<style>
+ .body {
+ position: relative;
+ nargin: 0;
+ padding: 0;
+ }
+ .block {
+ width: 100px;
+ height: 100px;
+ padding: 0;
+ display: inline-block;
+ position: absolute;
+ top: 10px;
+ margin: 0;
+ padding: 0;
+ }
+
+ .block1 {
+ background: rgb(127, 0, 0);
+ left: 10px;
+ }
+
+ .block2 {
+ background: rgb(0, 127, 0);
+ left: 120px;
+ }
+
+ .block3 {
+ background: rgb(0, 0, 127);
+ left: 230px;
+ }
+</style>
+<body>
+ <div class = "block block1"></div>
+ <div class = "block block2"></div>
+ <div class = "block block3"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-pseudo-element.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-pseudo-element.html
new file mode 100644
index 0000000000..e5066281d9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-pseudo-element.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="background-color-animation-pseudo-element-ref.html">
+<style>
+ body {
+ padding: 0;
+ margin: 0;
+ }
+ .block, .block:after, .block:before {
+ width: 100px;
+ height: 100px;
+ padding: 0;
+ display: inline-block;
+ /* Use a long transition that can be stalled at the midpoint. */
+ transition: background 100000s cubic-bezier(0,1,1,0);
+ }
+
+ .block {
+ background: rgb(0, 254, 0);
+ margin-left: 120px;
+ margin-top: 10px;
+ position: relative;
+ }
+
+ .block:after {
+ background: rgb(0, 0, 254);
+ content: "";
+ position: absolute;
+ left: 110px;
+ }
+
+ .block:before {
+ background: rgb(254, 0, 0);
+ content: "";
+ position: absolute;
+ left: -110px;
+ }
+
+ .block.tweak, .block.tweak:before, .block.tweak:after {
+ background: black;
+ }
+</style>
+<body>
+ <div class="block"></div>
+</body>
+<script src="/common/reftest-wait.js"></script>
+<script src="../../../web-animations/testcommon.js"></script>
+<script>
+ window.onload = async () => {
+ await waitForAnimationFrames(2);
+
+ const promises = [];
+ document.querySelector('.block').classList.add('tweak');
+ document.getAnimations().forEach(anim => {
+ anim.currentTime = anim.effect.getTiming().duration/2;
+ promises.push(anim.ready);
+ });
+
+ Promise.all(promises).then(() => {
+ waitForAnimationFrames(2).then(() => {
+ takeScreenshot();
+ });
+ });
+ };
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-ref.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-ref.html
new file mode 100644
index 0000000000..8e0e70ba20
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<body>
+ <canvas id="canvas" width="100" height="100"></canvas>
+</body>
+<script>
+ var canvas = document.getElementById('canvas');
+ var ctx = canvas.getContext('2d');
+ ctx.fillStyle = 'rgb(100, 100, 0)';
+ ctx.fillRect(0, 0, 100, 100);
+</script>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-removed-element-crash.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-removed-element-crash.html
new file mode 100644
index 0000000000..f8408fb5a1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-removed-element-crash.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<iframe id="foo"></iframe>
+<div id="bar"></div>
+
+<script>
+ $ = document.querySelector.bind(document);
+ var target = document.getElementById("bar");
+ target.animate([{"backgroundColor":"blue"},{"backgroundColor":"green"}], {"duration":10});
+ $('iframe').contentDocument.documentElement.appendChild(target);
+ $('#foo').remove();
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-single-keyframe-ref.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-single-keyframe-ref.html
new file mode 100644
index 0000000000..befe7c7f9b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-single-keyframe-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<body>
+ <canvas id="canvas" width="100" height="100"></canvas>
+</body>
+<script>
+ var canvas = document.getElementById('canvas');
+ var ctx = canvas.getContext('2d');
+ ctx.fillStyle = 'rgb(200, 0, 0)';
+ ctx.fillRect(0, 0, 100, 100);
+</script>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-single-keyframe.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-single-keyframe.html
new file mode 100644
index 0000000000..019b7f83f1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-single-keyframe.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="background-color-animation-single-keyframe-ref.html">
+<style>
+.container {
+ width: 100px;
+ height: 100px;
+ background-color: rgb(200, 0, 0);
+}
+</style>
+<script src="/common/reftest-wait.js"></script>
+<body>
+<div class="container" id="target"></div>
+
+<script>
+document.getElementById("target").animate({backgroundColor: 'rgb(0, 200, 0)'}, 100000000000);
+takeScreenshot();
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-three-keyframes1.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-three-keyframes1.html
new file mode 100644
index 0000000000..cba0113f00
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-three-keyframes1.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="background-color-animation-ref.html">
+<style>
+.container {
+ width: 100px;
+ height: 100px;
+ background-color: green;
+ /* Use a long animation that start at 5% progress where the slope of the
+ selected timing function is zero. By setting up the animation in this way,
+ we accommodate lengthy delays in running the test without a potential drift
+ in the animated property value. This is important for avoiding flakes,
+ especially on debug builds. The screenshots are taken as soon as the
+ animation is ready, thus the long animation duration has no bearing on
+ the actual duration of the test. */
+ animation: bgcolor 1000000s cubic-bezier(0,1,1,0) -50000s;
+}
+@keyframes bgcolor {
+ 0% { background-color: rgb(0, 200, 0); }
+ 10% {
+ background-color: rgb(200, 0, 0);
+ animation-timing-function: cubic-bezier(0,1,1,0);
+ }
+ 100% {
+ background-color: rgb(0, 0, 200);
+ animation-timing-function: cubic-bezier(0,1,1,0);
+ }
+}
+</style>
+<script src="/common/reftest-wait.js"></script>
+<body>
+<div class="container"></div>
+
+<script>
+// This test and the "one-element-three-keyframes-animation2.html" ensure that
+// we select the correct start and end keyframes for interpolation. In this
+// test, the start delay of the animation makes it jump to 5% right away, and in
+// the "one-element-three-keyframes-animation2.html" the start delay makes it
+// jump to 50%. So for this test, we would choose the keyframes at 0% and 10%
+// for interpolation, where for the other test it would be 10% and 100%.
+document.getAnimations()[0].ready.then(() => {
+ takeScreenshot();
+});
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-three-keyframes2-ref.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-three-keyframes2-ref.html
new file mode 100644
index 0000000000..823d8ac382
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-three-keyframes2-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<body>
+ <canvas id="canvas" width="100" height="100"></canvas>
+</body>
+<script>
+ var canvas = document.getElementById('canvas');
+ var ctx = canvas.getContext('2d');
+ ctx.fillStyle = 'rgb(100, 0, 100)';
+ ctx.fillRect(0, 0, 100, 100);
+</script>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-three-keyframes2.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-three-keyframes2.html
new file mode 100644
index 0000000000..d2be16034f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-three-keyframes2.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="background-color-animation-three-keyframes2-ref.html">
+<style>
+.container {
+ width: 100px;
+ height: 100px;
+ background-color: green;
+ /* Use a long animation that start at 50% progress where the slope of the
+ selected timing function is zero. By setting up the animation in this way,
+ we accommodate lengthy delays in running the test without a potential drift
+ in the animated property value. This is important for avoiding flakes,
+ especially on debug builds. The screenshots are taken as soon as the
+ animation is ready, thus the long animation duration has no bearing on
+ the actual duration of the test. */
+ animation: bgcolor 1000000s cubic-bezier(0,1,1,0) -500000s;
+}
+@keyframes bgcolor {
+ 0% { background-color: rgb(0, 200, 0); }
+ 10% {
+ background-color: rgb(200, 0, 0);
+ animation-timing-function: cubic-bezier(0,1,1,0);
+ }
+ 100% {
+ background-color: rgb(0, 0, 200);
+ animation-timing-function: cubic-bezier(0,1,1,0);
+ }
+}
+</style>
+<script src="/common/reftest-wait.js"></script>
+<body>
+<div class="container"></div>
+
+<script>
+// The start delay of the animation makes it jump 50% of the animation, which
+// means we would select the keyframes at 10% and 100% for animation. The
+// progress would be (0.5-0.1) / (1-0.1) = 0.44. So a timing function input of
+// 0.44 results in an output of 0.5.
+document.getAnimations()[0].ready.then(() => {
+ takeScreenshot();
+});
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-three-keyframes3.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-three-keyframes3.html
new file mode 100644
index 0000000000..708faa5560
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-three-keyframes3.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="background-color-animation-ref.html">
+<style>
+.container {
+ width: 100px;
+ height: 100px;
+ background-color: green;
+ /* Use a long animation that start at 5% progress where the slope of the
+ selected timing function is zero. By setting up the animation in this way,
+ we accommodate lengthy delays in running the test without a potential drift
+ in the animated property value. This is important for avoiding flakes,
+ especially on debug builds. The screenshots are taken as soon as the
+ animation is ready, thus the long animation duration has no bearing on
+ the actual duration of the test. */
+ animation: bgcolor 1000000s cubic-bezier(0,1,1,0) -50000s;
+}
+@keyframes bgcolor {
+ 10% {
+ background-color: rgb(200, 0, 0);
+ animation-timing-function: cubic-bezier(0,1,1,0);
+ }
+ 0% { background-color: rgb(0, 200, 0); }
+ 100% {
+ background-color: rgb(0, 0, 200);
+ animation-timing-function: cubic-bezier(0,1,1,0);
+ }
+}
+</style>
+<script src="/common/reftest-wait.js"></script>
+<body>
+<div class="container"></div>
+
+<script>
+document.getAnimations()[0].ready.then(() => {
+ takeScreenshot();
+});
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-will-change-contents-ref.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-will-change-contents-ref.html
new file mode 100644
index 0000000000..d980a29ff7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-will-change-contents-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<style>
+.box {
+ width: 600px;
+ height: 600px;
+ background-color: rgba(0, 200, 0, 1);
+}
+</style>
+<body>
+ <div class='box'></div>
+</body>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-will-change-contents.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-will-change-contents.html
new file mode 100644
index 0000000000..a218098721
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-will-change-contents.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="background-color-animation-will-change-contents-ref.html">
+<style>
+.container {
+ width: 600px;
+ height: 600px;
+ will-change: contents;
+ /* Start with a short delay and ensure that we pick up the color change when
+ the animation enters the active phase. */
+ animation: bgcolor 10s steps(1, jump-start) backwards 0.2s;
+}
+@keyframes bgcolor {
+ 0% { background-color: rgba(200, 0, 0, 1); }
+ 100% { background-color: rgba(0, 200, 0, 1); }
+}
+</style>
+<script src="/common/reftest-wait.js"></script>
+<body>
+<div class="container"></div>
+
+<script>
+ function waitForActiveAnimation() {
+ const anim = document.getAnimations()[0];
+ return new Promise(resolve => {
+ const tick = () => {
+ requestAnimationFrame(() => {
+ if (anim.currentTime > 200)
+ resolve();
+ else
+ tick();
+ });
+ };
+ tick();
+ });
+ }
+
+ window.onload = async () => {
+ await waitForActiveAnimation();
+ takeScreenshot();
+ };
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-blur-ref.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-blur-ref.html
new file mode 100644
index 0000000000..31418d093c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-blur-ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<style>
+ #target {
+ height: 100px;
+ width: 100px;
+ background: green;
+ display: inline-block;
+ margin: 10px;
+ }
+ #container {
+ filter: blur(5px);
+ }
+</style>
+<body>
+ <div id="container">
+ <div id="target"></div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-blur.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-blur.html
new file mode 100644
index 0000000000..0685e5a7c2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-blur.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="background-color-animation-with-blur-ref.html">
+<!-- Allow off by one errors on each color channel. -->
+<meta name=fuzzy content="maxDifference=0-1;totalPixels=0-12100">
+<style>
+ @keyframes colorize {
+ 0% { background-color: blue; }
+ 50% { background-color: green; }
+ 100% { background-color: red; }
+ }
+ #target {
+ height: 100px;
+ width: 100px;
+ animation-name: colorize;
+ animation-duration: 100000s;
+ animation-timing-function: cubic-bezier(0, 1, 1, 0);
+ display: inline-block;
+ margin: 10px;
+ }
+ .blur {
+ filter: blur(5px);
+ }
+ .color-shift {
+ animation-delay: -50000s;
+ }
+</style>
+<body>
+ <div id="container">
+ <div id="target"></div>
+ </div>
+</body>
+<script src="/common/reftest-wait.js"></script>
+<script type="text/javascript">
+ async function rAF() {
+ return new Promise((resolve) => {
+ requestAnimationFrame(resolve);
+ });
+ };
+
+ window.onload = async () => {
+ const anim = document.getAnimations()[0];
+ await anim.ready;
+ await rAF();
+ // Add blur filter while animation is running.
+ container.classList.add('blur');
+ await rAF();
+ // Shift animation to the midpoint.
+ target.classList.add('color-shift');
+ await rAF();
+ takeScreenshot();
+ };
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-images-ref.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-images-ref.html
new file mode 100644
index 0000000000..ba414f7b34
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-images-ref.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<style>
+.container1 {
+ width: 200px;
+ height: 200px;
+ background-image: url("../support/green.png"), url("../support/red.png");
+ background-size: 100px 100px;
+ background-repeat: no-repeat;
+ background-color: rgb(0, 0, 199);
+}
+.container2 {
+ width: 200px;
+ height: 200px;
+ background-image: url("../support/green.png"), url("../support/red.png");
+ background-size: 100px 100px;
+ background-repeat: no-repeat;
+}
+.container3 {
+ width: 100px;
+ height: 100px;
+ background-image: url("../support/green.png"), url("../support/red.png");
+}
+</style>
+</style>
+<body>
+ <div class="container1"></div>
+ <div class="container2"></div>
+ <div class="container3"></div>
+ <div class="container3"></div>
+</body>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-images.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-images.html
new file mode 100644
index 0000000000..0ea29b8f1c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-images.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="background-color-animation-with-images-ref.html">
+<style>
+.container1 {
+ width: 200px;
+ height: 200px;
+ /* Test the case where images partially occludes the background color */
+ background-image: url("../support/green.png"), url("../support/red.png");
+ background-size: 100px 100px;
+ background-repeat: no-repeat;
+ animation: blue-anim 100s;
+}
+.container2 {
+ width: 200px;
+ height: 200px;
+ /* Test the case where images partially occludes the background color */
+ background-image: url("../support/green.png"), url("../support/red.png");
+ background-size: 100px 100px;
+ background-repeat: no-repeat;
+ animation: transparent-anim 100s;
+}
+.container3 {
+ width: 100px;
+ height: 100px;
+ /* Test the case where images occludes the background color */
+ background-image: url("../support/green.png"), url("../support/red.png");
+ animation: transparent-anim 100s;
+}
+.container4 {
+ width: 100px;
+ height: 100px;
+ /* Test the case where images occludes the background color */
+ background-image: url("../support/green.png"), url("../support/red.png");
+ animation: blue-anim 100s;
+}
+@keyframes blue-anim {
+ 0% { background-color: rgb(0, 0, 199); }
+ 100% { background-color: rgb(0, 0, 200); }
+}
+@keyframes transparent-anim {
+ 0% { background-color: rgba(0, 200, 0, 0); }
+ 100% { background-color: rgba(200, 0, 0, 0); }
+}
+</style>
+<body>
+ <div class="container1"></div>
+ <div class="container2"></div>
+ <div class="container3"></div>
+ <div class="container4"></div>
+</body>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-mask-ref.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-mask-ref.html
new file mode 100644
index 0000000000..6cb20f12d1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-mask-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<style>
+.container {
+ width: 100px;
+ height: 100px;
+ -webkit-mask-image: url('../resources/stripes-100.png');
+ -webkit-mask-size: 100px 100px;
+ -webkit-mask-repeat: no-repeat;
+ mask-image: url('../resources/stripes-100.png');
+ mask-size: 100px 100px;
+ mask-repeat: no-repeat;
+ background-color: rgb(0, 0, 150);
+}
+</style>
+</style>
+<body>
+ <div class="container"></div>
+</body>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-mask.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-mask.html
new file mode 100644
index 0000000000..9001121edc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-mask.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="background-color-animation-with-mask-ref.html">
+<style>
+@keyframes blue-anim {
+ 0% { background-color: rgb(0, 0, 100); }
+ 100% { background-color: rgb(0, 0, 200); }
+}
+.container {
+ width: 100px;
+ height: 100px;
+ -webkit-mask-image: url('../resources/stripes-100.png');
+ -webkit-mask-size: 100px 100px;
+ -webkit-mask-repeat: no-repeat;
+ mask-image: url('../resources/stripes-100.png');
+ mask-size: 100px 100px;
+ mask-repeat: no-repeat;
+
+ /* force animation to start effectively stalled at the midpoint */
+ animation: blue-anim 10000s cubic-bezier(0, 1, 1, 0) -5000s;
+}
+
+</style>
+<script src="/common/reftest-wait.js"></script>
+<body>
+ <div class="container"></div>
+<script>
+document.getAnimations()[0].ready.then(() => {
+ takeScreenshot();
+});
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-table1-ref.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-table1-ref.html
new file mode 100644
index 0000000000..7522c388f0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-table1-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<style>
+table {
+ width: 160px;
+}
+</style>
+<table>
+ <tr><td>1
+ <tr><td>2
+</table>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-table1.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-table1.html
new file mode 100644
index 0000000000..de5f482e88
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-table1.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="background-color-animation-with-table1-ref.html">
+<style>
+table {
+ width: 160px;
+}
+tr {
+ animation: bgcolor 0.1s;
+}
+@keyframes bgcolor {
+ 0% { background-color: rgba(0, 200, 0, 0); }
+ 100% { background-color: rgba(200, 0, 0, 0); }
+}
+</style>
+<table>
+ <tr><td>1
+ <tr><td>2
+</table>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-table2.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-table2.html
new file mode 100644
index 0000000000..5fc03b3d92
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-table2.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="background-color-animation-with-table1-ref.html">
+<style>
+table {
+ width: 160px;
+}
+.firstcolumn {
+ animation: bgcolor 100s;
+}
+@keyframes bgcolor {
+ 0% { background-color: rgba(0, 200, 0, 0); }
+ 100% { background-color: rgba(200, 0, 0, 0); }
+}
+</style>
+<table>
+ <colgroup>
+ <col class="firstcolumn">
+ </colgroup>
+ <tr><td>1</td></tr>
+ <tr><td>2</td></tr>
+</table>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-table3.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-table3.html
new file mode 100644
index 0000000000..0ee8fdd69f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-table3.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="background-color-animation-with-table1-ref.html">
+<style>
+table {
+ width: 160px;
+}
+td {
+ animation: bgcolor 100s;
+}
+@keyframes bgcolor {
+ 0% { background-color: rgba(0, 200, 0, 0); }
+ 100% { background-color: rgba(200, 0, 0, 0); }
+}
+</style>
+<table>
+ <tr><td>1
+ <tr><td>2
+</table>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-table4.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-table4.html
new file mode 100644
index 0000000000..319ee77481
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-table4.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="background-color-animation-with-table1-ref.html">
+<style>
+table {
+ width: 160px;
+ columns: 2;
+}
+tr {
+ animation: bgcolor 0.1s;
+}
+@keyframes bgcolor {
+ 0% { background-color: rgba(0, 200, 0, 0); }
+ 100% { background-color: rgba(200, 0, 0, 0); }
+}
+</style>
+<table>
+ <tr><td>1
+ <tr><td>2
+</table>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-zero-playbackRate-ref.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-zero-playbackRate-ref.html
new file mode 100644
index 0000000000..823d8ac382
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-zero-playbackRate-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<body>
+ <canvas id="canvas" width="100" height="100"></canvas>
+</body>
+<script>
+ var canvas = document.getElementById('canvas');
+ var ctx = canvas.getContext('2d');
+ ctx.fillStyle = 'rgb(100, 0, 100)';
+ ctx.fillRect(0, 0, 100, 100);
+</script>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-zero-playbackRate.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-zero-playbackRate.html
new file mode 100644
index 0000000000..2a56399462
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-with-zero-playbackRate.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="background-color-animation-with-zero-playbackRate-ref.html">
+<style>
+.container {
+ width: 100px;
+ height: 100px;
+ /* Use a long animation that start at 50% progress where the slope of the
+ selected timing function is zero. By setting up the animation in this way,
+ we accommodate lengthy delays in running the test without a potential drift
+ in the animated property value. This is important for avoiding flakes,
+ especially on debug builds. The screenshots are taken as soon as the
+ animation is ready, thus the long animation duration has no bearing on
+ the actual duration of the test. */
+ animation: bgcolor 1000000s cubic-bezier(0,1,1,0) -500000s;
+}
+@keyframes bgcolor {
+ 0% { background-color: rgb(200, 0, 0); }
+ 100% { background-color: rgb(0, 0, 200); }
+}
+</style>
+<script src="/common/reftest-wait.js"></script>
+<body>
+<div class="container"></div>
+
+<script>
+var animation = document.getAnimations()[0];
+animation.ready.then(() => {
+ animation.playbackRate = 0;
+ takeScreenshot();
+});
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-zero-size-element-change-to-non-zero-ref.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-zero-size-element-change-to-non-zero-ref.html
new file mode 100644
index 0000000000..26882bd23b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-zero-size-element-change-to-non-zero-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<style>
+.box {
+ width: 100px;
+ height: 100px;
+ background-color: rgb(100, 100, 0);
+}
+</style>
+<body>
+ <div class='box'></div>
+</body>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-zero-size-element-change-to-non-zero.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-zero-size-element-change-to-non-zero.html
new file mode 100644
index 0000000000..f62380f9ed
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-zero-size-element-change-to-non-zero.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="background-color-animation-zero-size-element-change-to-non-zero-ref.html">
+<style>
+.container {
+ animation: bgcolor 1000000s cubic-bezier(0,1,1,0) -500000s;
+}
+@keyframes bgcolor {
+ 0% { background-color: rgb(0, 200, 0); }
+ 100% { background-color: rgb(200, 0, 0); }
+}
+</style>
+<script src="/common/reftest-wait.js"></script>
+<body>
+<div class="container" id="target"></div>
+
+<script>
+requestAnimationFrame(() => {
+ var target = document.getElementById("target");
+ target.style.width = '100px';
+ target.style.height = '100px';
+ requestAnimationFrame(() => {
+ takeScreenshot();
+ });
+});
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-zero-size-element-ref.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-zero-size-element-ref.html
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-zero-size-element-ref.html
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-zero-size-element.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-zero-size-element.html
new file mode 100644
index 0000000000..008b78a4c0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation-zero-size-element.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="background-color-animation-zero-size-element-ref.html">
+<style>
+.container {
+ animation: bgcolor 1s;
+}
+@keyframes bgcolor {
+ 0% { background-color: rgb(0, 200, 0); }
+ 100% { background-color: rgb(200, 0, 0); }
+}
+</style>
+<script src="/common/reftest-wait.js"></script>
+<body>
+<div class="container"></div>
+
+<script>
+// Pass if there is no crash, nothing shows on the screen
+takeScreenshot();
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation.html
new file mode 100644
index 0000000000..597f52c915
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-animation.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="background-color-animation-ref.html">
+<style>
+.container {
+ width: 100px;
+ height: 100px;
+ background-color: green;
+ /* Use a long animation that start at 50% progress where the slope of the
+ selected timing function is zero. By setting up the animation in this way,
+ we accommodate lengthy delays in running the test without a potential drift
+ in the animated property value. This is important for avoiding flakes,
+ especially on debug builds. The screenshots are taken as soon as the
+ animation is ready, thus the long animation duration has no bearing on
+ the actual duration of the test. */
+ animation: bgcolor 1000000s cubic-bezier(0,1,1,0) -500000s;
+}
+@keyframes bgcolor {
+ 0% { background-color: rgb(0, 200, 0); }
+ 100% { background-color: rgb(200, 0, 0); }
+}
+</style>
+<script src="/common/reftest-wait.js"></script>
+<body>
+<div class="container"></div>
+
+<script>
+document.getAnimations()[0].ready.then(() => {
+ takeScreenshot();
+});
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-interpolation.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-interpolation.html
new file mode 100644
index 0000000000..bb727d8e4e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-interpolation.html
@@ -0,0 +1,122 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<meta name="test" content="background-color supports animation as a <color>">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.parent {
+ background-color: #eee;
+}
+.target {
+ width: 60px;
+ height: 60px;
+ display: inline-block;
+ border: 2px solid black;
+ margin-right: 2px;
+ color: rgba(0, 0, 255, 0.5);
+ background-color: black;
+}
+.expected {
+ margin-right: 15px;
+}
+</style>
+
+<body></body>
+
+<script>
+test_interpolation({
+ property: 'background-color',
+ from: neutralKeyframe,
+ to: 'green',
+}, [
+ {at: -0.3, expect: 'rgb(0, 0, 0)'},
+ {at: 0, expect: 'rgb(0, 0, 0)'},
+ {at: 0.3, expect: 'rgb(0, 38, 0)'},
+ {at: 0.6, expect: 'rgb(0, 77, 0)'},
+ {at: 1, expect: 'rgb(0, 128, 0)'},
+ {at: 1.5, expect: 'rgb(0, 192, 0)'},
+]);
+
+test_interpolation({
+ property: 'background-color',
+ from: 'initial',
+ to: 'green',
+}, [
+ {at: -0.3, expect: 'rgba(0, 0, 0, 0)'},
+ {at: 0, expect: 'rgba(0, 0, 0, 0)'},
+ {at: 0.3, expect: 'rgba(0, 128, 0, 0.3)'},
+ {at: 0.6, expect: 'rgba(0, 128, 0, 0.6)'},
+ {at: 1, expect: 'rgb(0, 128, 0)'},
+ {at: 1.5, expect: 'rgb(0, 192, 0)'},
+]);
+
+test_interpolation({
+ property: 'background-color',
+ from: 'inherit',
+ to: 'green',
+}, [
+ {at: -0.3, expect: 'rgb(255, 255, 255)'},
+ {at: 0, expect: 'rgb(238, 238, 238)'},
+ {at: 0.3, expect: 'rgb(167, 205, 167)'},
+ {at: 0.6, expect: 'rgb(95, 172, 95)'},
+ {at: 1, expect: 'rgb(0, 128, 0)'},
+ {at: 1.5, expect: 'rgb(0, 73, 0)'},
+]);
+
+test_interpolation({
+ property: 'background-color',
+ from: 'unset',
+ to: 'green',
+}, [
+ {at: -0.3, expect: 'rgba(0, 0, 0, 0)'},
+ {at: 0, expect: 'rgba(0, 0, 0, 0)'},
+ {at: 0.3, expect: 'rgba(0, 128, 0, 0.3)'},
+ {at: 0.6, expect: 'rgba(0, 128, 0, 0.6)'},
+ {at: 1, expect: 'rgb(0, 128, 0)'},
+ {at: 1.5, expect: 'rgb(0, 192, 0)'},
+]);
+
+test_interpolation({
+ property: 'background-color',
+ from: 'white',
+ to: 'orange',
+}, [
+ {at: -0.3, expect: 'white'},
+ {at: 0, expect: 'white'},
+ {at: 0.3, expect: 'rgb(255, 228, 179)'},
+ {at: 0.6, expect: 'rgb(255, 201, 102)'},
+ {at: 1, expect: 'orange'},
+ {at: 1.5, expect: 'rgb(255, 120, 0)'},
+]);
+
+test_interpolation({
+ property: 'background-color',
+ from: 'transparent',
+ to: 'green',
+}, [
+ {at: -0.3, expect: 'rgba(0, 0, 0, 0)'},
+ {at: 0, expect: 'rgba(0, 0, 0, 0)'},
+ {at: 0.3, expect: 'rgba(0, 128, 0, 0.3)'},
+ {at: 0.6, expect: 'rgba(0, 128, 0, 0.6)'},
+ {at: 1, expect: 'rgb(0, 128, 0)'},
+ {at: 1.5, expect: 'rgb(0, 192, 0)'},
+]);
+
+test_interpolation({
+ property: 'background-color',
+ from: 'currentcolor',
+ to: 'rgba(0, 255, 0, 0.75)',
+}, [
+ {at: -0.5, expect: 'rgba(0, 0, 255, 0.38)'},
+ {at: 0, expect: 'rgba(0, 0, 255, 0.5)'},
+ {at: 0.25, expect: 'rgba(0, 85, 170, 0.56)'},
+ {at: 0.5, expect: 'rgba(0, 153, 102, 0.63)'},
+ {at: 0.75, expect: 'rgba(0, 208, 47, 0.69)'},
+ {at: 1, expect: 'rgba(0, 255, 0, 0.75)'},
+ {at: 1.5, expect: 'rgba(0, 255, 0, 0.88)'},
+]);
+</script>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-scroll-into-viewport-ref.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-scroll-into-viewport-ref.html
new file mode 100644
index 0000000000..e5bbf67dfe
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-scroll-into-viewport-ref.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<style>
+.container {
+ width: 100vw;
+ height: 100vh;
+ overflow: hidden;
+ position: relative;
+}
+.spacer {
+ height: 1000vh;
+}
+#target {
+ width: 50vw;
+ height: 50vh;
+ background-color: rgb(100, 100, 0);
+}
+</style>
+<script src="/common/reftest-wait.js"></script>
+<body>
+ <div class="container">
+ <div class="spacer"></div>
+ <div id="target"></div>
+ </div>
+</body>
+<script>
+async function raf() {
+ return new Promise((resolve) => {
+ requestAnimationFrame(() => {
+ resolve();
+ });
+ })
+}
+
+window.onload = async () => {
+ await raf();
+ await raf();
+ target.scrollIntoView();
+ takeScreenshot();
+};
+</script>
+
+</html>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-scroll-into-viewport.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-scroll-into-viewport.html
new file mode 100644
index 0000000000..24b22b43e4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-scroll-into-viewport.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="background-color-scroll-into-viewport-ref.html">
+<style>
+.container {
+ width: 100vw;
+ height: 100vh;
+ overflow: hidden;
+ position: relative;
+}
+.spacer {
+ height: 1000vh;
+}
+#target {
+ width: 50vw;
+ height: 50vh;
+ background-color: green;
+ animation: bgcolor 1000000s cubic-bezier(0,1,1,0) -500000s;
+}
+@keyframes bgcolor {
+ 0% { background-color: rgb(0, 200, 0); }
+ 100% { background-color: rgb(200, 0, 0); }
+}
+</style>
+<script src="/common/reftest-wait.js"></script>
+<body>
+ <div class="container">
+ <div class="spacer"></div>
+ <div id="target"></div>
+ </div>
+</body>
+<script>
+async function raf() {
+ return new Promise((resolve) => {
+ requestAnimationFrame(() => {
+ resolve();
+ });
+ })
+}
+
+document.getAnimations()[0].ready.then(async () => {
+ await raf();
+ await raf();
+ target.scrollIntoView();
+ takeScreenshot();
+});
+</script>
+
+</html>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-transition-currentcolor-ref.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-transition-currentcolor-ref.html
new file mode 100644
index 0000000000..b910478656
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-transition-currentcolor-ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<style>
+ body {
+ padding: 0;
+ margin: 0;
+ }
+ .block {
+ width: 100px;
+ height: 100px;
+ padding: 0;
+ display: inline-block;
+ background: rgb(0, 127, 0);
+ margin: 10px;
+ }
+</style>
+<body>
+ <div class="block"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-transition-currentcolor.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-transition-currentcolor.html
new file mode 100644
index 0000000000..7d12b44051
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-transition-currentcolor.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="background-color-transition-currentcolor-ref.html">
+<style>
+ body {
+ padding: 0;
+ margin: 0;
+ }
+ .block {
+ width: 100px;
+ height: 100px;
+ padding: 0;
+ display: inline-block;
+ background: rgb(0, 254, 0);
+ color: black;
+ margin: 10px;
+ /* Use a long transition that can be stalled at the midpoint. */
+ transition: background 100000s cubic-bezier(0,1,1,0);
+ }
+ .block.tweak {
+ background: currentColor;
+ }
+</style>
+<body>
+ <div class="block"></div>
+</body>
+<script src="/common/reftest-wait.js"></script>
+<script>
+ window.onload = () => {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ document.querySelector('.block').classList.add('tweak');
+ const anim = document.getAnimations()[0];
+ anim.ready.then(() => {
+ anim.currentTime = anim.effect.getTiming().duration/2;
+ requestAnimationFrame(() => {
+ takeScreenshot();
+ });
+ });
+ });
+ });
+ };
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-transition.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-transition.html
new file mode 100644
index 0000000000..d43b9415cf
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-transition.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="background-color-animation-ref.html">
+<style>
+.container {
+ width: 100px;
+ height: 100px;
+ background-color: rgb(0, 200, 0);
+ transition-property: background-color;
+ /* Use a long animation that start at 50% progress where the slope of the
+ selected timing function is zero. By setting up the animation in this way,
+ we accommodate lengthy delays in running the test without a potential drift
+ in the animated property value. This is important for avoiding flakes,
+ especially on debug builds. The screenshots are taken as soon as the
+ animation is ready, thus the long animation duration has no bearing on
+ the actual duration of the test. */
+ transition-duration: 1000000s;
+ transition-timing-function: cubic-bezier(0,1,1,0);
+ transition-delay: -500000s;
+}
+</style>
+<script src="/common/reftest-wait.js"></script>
+<body>
+<div class="container" id="target"></div>
+
+<script>
+function update() {
+ document.getElementById('target').style.backgroundColor = "rgb(200, 0, 0)";
+ requestAnimationFrame(() => {
+ takeScreenshot();
+ });
+}
+requestAnimationFrame(function() {
+ requestAnimationFrame(update);
+});
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-transparent-animation-in-body-ref.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-transparent-animation-in-body-ref.html
new file mode 100644
index 0000000000..72c0c83ffc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-transparent-animation-in-body-ref.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<body>
+</body>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-color-transparent-animation-in-body.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-transparent-animation-in-body.html
new file mode 100644
index 0000000000..f156f91408
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-color-transparent-animation-in-body.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="background-color-transparent-animation-in-body-ref.html">
+<style>
+body {
+ /* Use a long animation that start at 50% progress where the slope of the
+ selected timing function is zero. By setting up the animation in this way,
+ we accommodate lengthy delays in running the test without a potential drift
+ in the animated property value. This is important for avoiding flakes,
+ especially on debug builds. The screenshots are taken as soon as the
+ animation is ready, thus the long animation duration has no bearing on
+ the actual duration of the test. */
+ animation: bgcolor 1000000s cubic-bezier(0,1,1,0) -500000s;
+}
+@keyframes bgcolor {
+ 0% { background-color: rgba(0, 200, 0, 0); }
+ 100% { background-color: rgba(200, 0, 0, 0); }
+}
+</style>
+<body>
+</body>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-image-interpolation.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-image-interpolation.html
new file mode 100644
index 0000000000..feda6afebe
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-image-interpolation.html
@@ -0,0 +1,230 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-image">
+<meta name="test" content="background-image supports animation">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.parent {
+ background-image: url(../resources/blue-100.png);
+ background-size: 0 0;
+}
+.target {
+ width: 100px;
+ height: 100px;
+ display: inline-block;
+ border: 10px solid black;
+ background-repeat: no-repeat;
+ background-image: url(../resources/blue-100.png);
+}
+.expected {
+ border-color: green;
+ margin-right: 2px;
+}
+</style>
+
+<body>
+<script>
+// Neutral to image
+var from = 'url(../resources/blue-100.png)';
+var to = 'url(../resources/green-100.png)';
+test_interpolation({
+ property: 'background-image',
+ from: neutralKeyframe,
+ to: to,
+}, [
+ {at: -0.3, expect: from},
+ {at: 0, expect: from},
+ {at: 0.3, expect: from},
+ {at: 0.6, expect: to},
+ {at: 1, expect: to},
+ {at: 1.5, expect: to},
+]);
+
+// initial to image
+to = 'url(../resources/green-100.png)';
+test_interpolation({
+ property: 'background-image',
+ from: 'initial',
+ to: to,
+}, [
+ {at: -0.3, expect: 'none'},
+ {at: 0, expect: 'none'},
+ {at: 0.3, expect: 'none'},
+ {at: 0.6, expect: to},
+ {at: 1, expect: to},
+ {at: 1.5, expect: to},
+]);
+
+// inherit to image
+from = 'url(../resources/blue-100.png)';
+to = 'url(../resources/green-100.png)';
+test_interpolation({
+ property: 'background-image',
+ from: 'inherit',
+ to: to,
+}, [
+ {at: -0.3, expect: from},
+ {at: 0, expect: from},
+ {at: 0.3, expect: from},
+ {at: 0.6, expect: to},
+ {at: 1, expect: to},
+ {at: 1.5, expect: to},
+]);
+
+// unset to image
+test_interpolation({
+ property: 'background-image',
+ from: 'unset',
+ to: to,
+}, [
+ {at: -0.3, expect: 'none'},
+ {at: 0, expect: 'none'},
+ {at: 0.3, expect: 'none'},
+ {at: 0.6, expect: to},
+ {at: 1, expect: to},
+ {at: 1.5, expect: to},
+]);
+
+// Image to image
+from = 'url(../resources/blue-100.png)';
+to = 'url(../resources/green-100.png)';
+test_interpolation({
+ property: 'background-image',
+ from: from,
+ to: to,
+}, [
+ {at: -0.3, expect: from},
+ {at: 0, expect: from},
+ {at: 0.3, expect: from},
+ {at: 0.6, expect: to},
+ {at: 1, expect: to},
+ {at: 1.5, expect: to},
+]);
+
+// Image to gradient
+from = 'url(../resources/blue-100.png)';
+to = 'linear-gradient(45deg, blue, orange)';
+test_interpolation({
+ property: 'background-image',
+ from: from,
+ to: to,
+}, [
+ {at: -0.3, expect: from},
+ {at: 0, expect: from},
+ {at: 0.3, expect: from},
+ {at: 0.6, expect: to},
+ {at: 1, expect: to},
+ {at: 1.5, expect: to},
+]);
+
+// Image to crossfade
+from = 'url(../resources/blue-100.png)';
+to = 'cross-fade(url(../resources/green-100.png), url(../resources/stripes-100.png), 0.5)';
+test_interpolation({
+ property: 'background-image',
+ from: from,
+ to: to,
+}, [
+ {at: -0.3, expect: from},
+ {at: 0, expect: from},
+ {at: 0.3, expect: from},
+ {at: 0.6, expect: to},
+ {at: 1, expect: to},
+ {at: 1.5, expect: to},
+]);
+
+// Gradient to gradient
+from = 'linear-gradient(-45deg, red, yellow)';
+to = 'linear-gradient(45deg, blue, orange)';
+test_interpolation({
+ property: 'background-image',
+ from: from,
+ to: to,
+}, [
+ {at: -0.3, expect: from},
+ {at: 0, expect: from},
+ {at: 0.3, expect: from},
+ {at: 0.6, expect: to},
+ {at: 1, expect: to},
+ {at: 1.5, expect: to},
+]);
+
+// Keyword to image
+from = 'none';
+to = 'url(../resources/green-100.png)';
+test_interpolation({
+ property: 'background-image',
+ from: from,
+ to: to,
+}, [
+ {at: -0.3, expect: from},
+ {at: 0, expect: from},
+ {at: 0.3, expect: from},
+ {at: 0.6, expect: to},
+ {at: 1, expect: to},
+ {at: 1.5, expect: to},
+]);
+
+// Multiple to multiple
+var fromA = 'url(../resources/stripes-100.png)';
+var fromB = 'url(../resources/blue-100.png)';
+var toA = 'url(../resources/blue-100.png)';
+var toB = 'url(../resources/stripes-100.png)';
+from = fromA + ', ' + fromB;
+to = toA + ', ' + toB;
+test_interpolation({
+ property: 'background-image',
+ from: from,
+ to: to,
+}, [
+ {at: -0.3, expect: from},
+ {at: 0, expect: from},
+ {at: 0.3, expect: from},
+ {at: 0.6, expect: to},
+ {at: 1, expect: to},
+ {at: 1.5, expect: to},
+]);
+
+// Single to multiple
+from = 'url(../resources/blue-100.png)';
+var toA = 'url(../resources/stripes-100.png)';
+var toB = 'url(../resources/green-100.png)';
+to = toA + ', ' + toB;
+test_interpolation({
+ property: 'background-image',
+ from: from,
+ to: to,
+}, [
+ // The interpolation of different numbers of background-images looks a bit strange here.
+ // Animating background-image is not specified to be possible however we do it for backwards compatibility.
+ // With this in mind we kept the implementation simple at the expense of this corner case because there is
+ // no official specification to support.
+ {at: -0.3, expect: from},
+ {at: 0, expect: from},
+ {at: 0.3, expect: from},
+ {at: 0.6, expect: to},
+ {at: 1, expect: to},
+ {at: 1.5, expect: to},
+]);
+
+// Multiple mismatched types
+from = 'url(../resources/blue-100.png), none';
+to = 'url(../resources/stripes-100.png), url(../resources/green-100.png)';
+test_interpolation({
+ property: 'background-image',
+ from: from,
+ to: to,
+}, [
+ {at: -0.3, expect: from},
+ {at: 0, expect: from},
+ {at: 0.3, expect: from},
+ {at: 0.6, expect: to},
+ {at: 1, expect: to},
+ {at: 1.5, expect: to},
+]);
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-position-interpolation.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-position-interpolation.html
new file mode 100644
index 0000000000..2e7f2e24a1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-position-interpolation.html
@@ -0,0 +1,137 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-position">
+<meta name="test" content="background-position supports animation as a repeatable list">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.parent {
+ background-position: 60px 60px;
+}
+.target {
+ width: 120px;
+ height: 120px;
+ display: inline-block;
+ border: 2px solid black;
+ background-repeat: no-repeat;
+ background-image: radial-gradient(20px circle at 20px 20px, red 18px, transparent),
+ radial-gradient(20px circle at 20px 20px, yellow 18px, transparent),
+ radial-gradient(20px circle at 20px 20px, lime 18px, transparent),
+ radial-gradient(20px circle at 20px 20px, blue 18px, transparent);
+ background-position: 40px 40px;
+}
+.expected {
+ margin-right: 10px;
+}
+</style>
+
+<body></body>
+
+<script>
+test_interpolation({
+ property: 'background-position',
+ from: neutralKeyframe,
+ to: '80px 80px, 80px 80px, 80px 80px, 80px 80px',
+}, [
+ {at: -0.25, expect: '30px 30px, 30px 30px, 30px 30px, 30px 30px'},
+ {at: 0, expect: '40px 40px, 40px 40px, 40px 40px, 40px 40px'},
+ {at: 0.25, expect: '50px 50px, 50px 50px, 50px 50px, 50px 50px'},
+ {at: 0.5, expect: '60px 60px, 60px 60px, 60px 60px, 60px 60px'},
+ {at: 0.75, expect: '70px 70px, 70px 70px, 70px 70px, 70px 70px'},
+ {at: 1, expect: '80px 80px, 80px 80px, 80px 80px, 80px 80px'},
+ {at: 1.25, expect: '90px 90px, 90px 90px, 90px 90px, 90px 90px'},
+]);
+
+// background-position's initial value is 0% 0%, and calcs involving percentages
+// are never resolved by the calc spec (even when the percentage is 0%).
+test_interpolation({
+ property: 'background-position',
+ from: 'initial',
+ to: '80px 80px, 80px 80px, 80px 80px, 80px 80px',
+}, [
+ {at: -0.25, expect: 'calc(0% - 20px) calc(0% - 20px), calc(0% - 20px) calc(0% - 20px), calc(0% - 20px) calc(0% - 20px), calc(0% - 20px) calc(0% - 20px)'},
+ {at: 0, expect: '0% 0%, 0% 0%, 0% 0%, 0% 0%'},
+ {at: 0.25, expect: 'calc(0% + 20px) calc(0% + 20px), calc(0% + 20px) calc(0% + 20px), calc(0% + 20px) calc(0% + 20px), calc(0% + 20px) calc(0% + 20px)'},
+ {at: 0.5, expect: 'calc(0% + 40px) calc(0% + 40px), calc(0% + 40px) calc(0% + 40px), calc(0% + 40px) calc(0% + 40px), calc(0% + 40px) calc(0% + 40px)'},
+ {at: 0.75, expect: 'calc(0% + 60px) calc(0% + 60px), calc(0% + 60px) calc(0% + 60px), calc(0% + 60px) calc(0% + 60px), calc(0% + 60px) calc(0% + 60px)'},
+ {at: 1, expect: 'calc(0% + 80px) calc(0% + 80px), calc(0% + 80px) calc(0% + 80px), calc(0% + 80px) calc(0% + 80px), calc(0% + 80px) calc(0% + 80px)'},
+ {at: 1.25, expect: 'calc(0% + 100px) calc(0% + 100px), calc(0% + 100px) calc(0% + 100px), calc(0% + 100px) calc(0% + 100px), calc(0% + 100px) calc(0% + 100px)'},
+]);
+
+test_interpolation({
+ property: 'background-position',
+ from: 'inherit',
+ to: '80px 80px, 80px 80px, 80px 80px, 80px 80px',
+}, [
+ {at: -0.25, expect: '55px 55px, 55px 55px, 55px 55px, 55px 55px'},
+ {at: 0, expect: '60px 60px, 60px 60px, 60px 60px, 60px 60px'},
+ {at: 0.25, expect: '65px 65px, 65px 65px, 65px 65px, 65px 65px'},
+ {at: 0.5, expect: '70px 70px, 70px 70px, 70px 70px, 70px 70px'},
+ {at: 0.75, expect: '75px 75px, 75px 75px, 75px 75px, 75px 75px'},
+ {at: 1, expect: '80px 80px, 80px 80px, 80px 80px, 80px 80px'},
+ {at: 1.25, expect: '85px 85px, 85px 85px, 85px 85px, 85px 85px'},
+]);
+
+// background-position is not inherited, so 'unset' is equivalent to initial.
+test_interpolation({
+ property: 'background-position',
+ from: 'unset',
+ to: '80px 80px, 80px 80px, 80px 80px, 80px 80px',
+}, [
+ {at: -0.25, expect: 'calc(0% - 20px) calc(0% - 20px), calc(0% - 20px) calc(0% - 20px), calc(0% - 20px) calc(0% - 20px), calc(0% - 20px) calc(0% - 20px)'},
+ {at: 0, expect: '0% 0%, 0% 0%, 0% 0%, 0% 0%'},
+ {at: 0.25, expect: 'calc(0% + 20px) calc(0% + 20px), calc(0% + 20px) calc(0% + 20px), calc(0% + 20px) calc(0% + 20px), calc(0% + 20px) calc(0% + 20px)'},
+ {at: 0.5, expect: 'calc(0% + 40px) calc(0% + 40px), calc(0% + 40px) calc(0% + 40px), calc(0% + 40px) calc(0% + 40px), calc(0% + 40px) calc(0% + 40px)'},
+ {at: 0.75, expect: 'calc(0% + 60px) calc(0% + 60px), calc(0% + 60px) calc(0% + 60px), calc(0% + 60px) calc(0% + 60px), calc(0% + 60px) calc(0% + 60px)'},
+ {at: 1, expect: 'calc(0% + 80px) calc(0% + 80px), calc(0% + 80px) calc(0% + 80px), calc(0% + 80px) calc(0% + 80px), calc(0% + 80px) calc(0% + 80px)'},
+ {at: 1.25, expect: 'calc(0% + 100px) calc(0% + 100px), calc(0% + 100px) calc(0% + 100px), calc(0% + 100px) calc(0% + 100px), calc(0% + 100px) calc(0% + 100px)'},
+]);
+
+// Test equal number of position values as background images.
+test_interpolation({
+ property: 'background-position',
+ from: '0px 0px, 0px 0px, 0px 0px, 0px 0px',
+ to: '80px 80px, 80px 80px, 80px 80px, 80px 80px',
+}, [
+ {at: -0.25, expect: '-20px -20px, -20px -20px, -20px -20px, -20px -20px'},
+ {at: 0, expect: ' 0px 0px, 0px 0px, 0px 0px, 0px 0px'},
+ {at: 0.25, expect: ' 20px 20px, 20px 20px, 20px 20px, 20px 20px'},
+ {at: 0.5, expect: ' 40px 40px, 40px 40px, 40px 40px, 40px 40px'},
+ {at: 0.75, expect: ' 60px 60px, 60px 60px, 60px 60px, 60px 60px'},
+ {at: 1, expect: ' 80px 80px, 80px 80px, 80px 80px, 80px 80px'},
+ {at: 1.25, expect: '100px 100px, 100px 100px, 100px 100px, 100px 100px'},
+]);
+
+// Test single position value repeated over background images.
+test_interpolation({
+ property: 'background-position',
+ from: 'top 0px left 0px',
+ to: 'left 80px top 80px',
+}, [
+ {at: -0.25, expect: '-20px -20px, -20px -20px, -20px -20px, -20px -20px'},
+ {at: 0, expect: ' 0px 0px, 0px 0px, 0px 0px, 0px 0px'},
+ {at: 0.25, expect: ' 20px 20px, 20px 20px, 20px 20px, 20px 20px'},
+ {at: 0.5, expect: ' 40px 40px, 40px 40px, 40px 40px, 40px 40px'},
+ {at: 0.75, expect: ' 60px 60px, 60px 60px, 60px 60px, 60px 60px'},
+ {at: 1, expect: ' 80px 80px, 80px 80px, 80px 80px, 80px 80px'},
+ {at: 1.25, expect: '100px 100px, 100px 100px, 100px 100px, 100px 100px'},
+]);
+
+// Test mismatched numbers of position values.
+test_interpolation({
+ property: 'background-position',
+ from: '0px 0px, 80px 0px',
+ to: '40px 40px, 80px 80px, 0px 80px',
+}, [
+ {at: -0.25, expect: '-10px -10px, 80px -20px, 0px -20px, 90px -10px'},
+ {at: 0, expect: ' 0px 0px, 80px 0px, 0px 0px, 80px 0px'},
+ {at: 0.25, expect: ' 10px 10px, 80px 20px, 0px 20px, 70px 10px'},
+ {at: 0.5, expect: ' 20px 20px, 80px 40px, 0px 40px, 60px 20px'},
+ {at: 0.75, expect: ' 30px 30px, 80px 60px, 0px 60px, 50px 30px'},
+ {at: 1, expect: ' 40px 40px, 80px 80px, 0px 80px, 40px 40px'},
+ {at: 1.25, expect: ' 50px 50px, 80px 100px, 0px 100px, 30px 50px'},
+]);
+</script>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-position-origin-interpolation.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-position-origin-interpolation.html
new file mode 100644
index 0000000000..f34145c573
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-position-origin-interpolation.html
@@ -0,0 +1,217 @@
+<!doctype html>
+<meta charset="utf-8">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-position">
+<meta name="test" content="background-position animation handles origin parameters">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.parent {
+ background-position: 80px 80px;
+}
+.target {
+ border: 3px solid skyblue;
+ width: 100px;
+ height: 100px;
+ background-image: linear-gradient(to right, green, green);
+ background-size: 20px 20px;
+ background-repeat: no-repeat;
+ background-position: 10px 10px;
+ display: inline-block;
+}
+
+.actual {
+ background-image: linear-gradient(to right, red, red);
+}
+.expected {
+ margin-left: -106px;
+}
+</style>
+
+<body></body>
+
+<script>
+// neutral
+test_interpolation({
+ property: 'background-position',
+ from: neutralKeyframe,
+ to: 'left 20px top 20px',
+}, [
+ {at: 0, expect: '10px 10px'},
+ {at: 0.25, expect: '12.5px 12.5px'},
+ {at: 0.5, expect: '15px 15px'},
+ {at: 0.75, expect: '17.5px 17.5px'},
+ {at: 1, expect: '20px 20px'},
+]);
+
+// initial
+test_interpolation({
+ property: 'background-position',
+ from: 'initial',
+ to: 'left 20px top 20px',
+}, [
+ {at: 0, expect: '0% 0%'},
+ {at: 0.25, expect: 'calc(0% + 5px) calc(0% + 5px)'},
+ {at: 0.5, expect: 'calc(0% + 10px) calc(0% + 10px)'},
+ {at: 0.75, expect: 'calc(0% + 15px) calc(0% + 15px)'},
+ {at: 1, expect: 'calc(0% + 20px) calc(0% + 20px)'},
+]);
+
+// inherit
+test_interpolation({
+ property: 'background-position',
+ from: 'inherit',
+ to: 'left 20px top 20px',
+}, [
+ {at: 0, expect: '80px 80px'},
+ {at: 0.25, expect: '65px 65px'},
+ {at: 0.5, expect: '50px 50px'},
+ {at: 0.75, expect: '35px 35px'},
+ {at: 1, expect: '20px 20px'},
+]);
+
+// unset
+test_interpolation({
+ property: 'background-position',
+ from: 'unset',
+ to: 'left 20px top 20px',
+}, [
+ {at: 0, expect: '0% 0%'},
+ {at: 0.25, expect: 'calc(0% + 5px) calc(0% + 5px)'},
+ {at: 0.5, expect: 'calc(0% + 10px) calc(0% + 10px)'},
+ {at: 0.75, expect: 'calc(0% + 15px) calc(0% + 15px)'},
+ {at: 1, expect: 'calc(0% + 20px) calc(0% + 20px)'},
+]);
+
+// left-top
+test_interpolation({
+ property: 'background-position',
+ from: 'center center',
+ to: 'left 20px top 20px',
+}, [
+ {at: 0, expect: '50% 50%'},
+ {at: 0.25, expect: 'calc(5px + 37.5%) calc(5px + 37.5%)'},
+ {at: 0.5, expect: 'calc(10px + 25%) calc(10px + 25%)'},
+ {at: 0.75, expect: 'calc(15px + 12.5%) calc(15px + 12.5%)'},
+ {at: 1, expect: 'calc(0% + 20px) calc(0% + 20px)'},
+]);
+
+// center-top
+test_interpolation({
+ property: 'background-position',
+ from: 'center center',
+ to: 'center top 20px',
+}, [
+ {at: 0, expect: '50% 50%'},
+ {at: 0.25, expect: '50% calc(5px + 37.5%)'},
+ {at: 0.5, expect: '50% calc(10px + 25%)'},
+ {at: 0.75, expect: '50% calc(15px + 12.5%)'},
+ {at: 1, expect: '50% calc(0% + 20px)'},
+]);
+
+// right-top
+test_interpolation({
+ property: 'background-position',
+ from: 'center center',
+ to: 'right 20px top 20px',
+}, [
+ {at: 0, expect: '50% 50%'},
+ {at: 0.25, expect: 'calc(-5px + 62.5%) calc(5px + 37.5%)'},
+ {at: 0.5, expect: 'calc(-10px + 75%) calc(10px + 25%)'},
+ {at: 0.75, expect: 'calc(-15px + 87.5%) calc(15px + 12.5%)'},
+ {at: 1, expect: 'calc(-20px + 100%) calc(0% + 20px)'},
+]);
+
+// left-center
+test_interpolation({
+ property: 'background-position',
+ from: 'center center',
+ to: 'left 20px center',
+}, [
+ {at: 0, expect: '50% 50%'},
+ {at: 0.25, expect: 'calc(5px + 37.5%) 50%'},
+ {at: 0.5, expect: 'calc(10px + 25%) 50%'},
+ {at: 0.75, expect: 'calc(15px + 12.5%) 50%'},
+ {at: 1, expect: 'calc(0% + 20px) 50%'},
+]);
+
+// center-center
+test_interpolation({
+ property: 'background-position',
+ from: 'center center',
+ to: 'center center',
+}, [
+ {at: 0, expect: '50% 50%'},
+ {at: 0.25, expect: '50% 50%'},
+ {at: 0.5, expect: '50% 50%'},
+ {at: 0.75, expect: '50% 50%'},
+ {at: 1, expect: '50% 50%'},
+]);
+
+// right-center
+test_interpolation({
+ property: 'background-position',
+ from: 'center center',
+ to: 'right 20px center',
+}, [
+ {at: 0, expect: '50% 50%'},
+ {at: 0.25, expect: 'calc(-5px + 62.5%) 50%'},
+ {at: 0.5, expect: 'calc(-10px + 75%) 50%'},
+ {at: 0.75, expect: 'calc(-15px + 87.5%) 50%'},
+ {at: 1, expect: 'calc(-20px + 100%) 50%'},
+]);
+
+// left-bottom
+test_interpolation({
+ property: 'background-position',
+ from: 'center center',
+ to: 'left 20px bottom 20px',
+}, [
+ {at: 0, expect: '50% 50%'},
+ {at: 0.25, expect: 'calc(5px + 37.5%) calc(-5px + 62.5%)'},
+ {at: 0.5, expect: 'calc(10px + 25%) calc(-10px + 75%)'},
+ {at: 0.75, expect: 'calc(15px + 12.5%) calc(-15px + 87.5%)'},
+ {at: 1, expect: 'calc(0% + 20px) calc(-20px + 100%)'},
+]);
+
+// center-bottom
+test_interpolation({
+ property: 'background-position',
+ from: 'center center',
+ to: 'center bottom 20px',
+}, [
+ {at: 0, expect: '50% 50%'},
+ {at: 0.25, expect: '50% calc(-5px + 62.5%)'},
+ {at: 0.5, expect: '50% calc(-10px + 75%)'},
+ {at: 0.75, expect: '50% calc(-15px + 87.5%)'},
+ {at: 1, expect: '50% calc(-20px + 100%)'},
+]);
+
+// right-bottom
+test_interpolation({
+ property: 'background-position',
+ from: 'center center',
+ to: 'right 20px bottom 20px',
+}, [
+ {at: 0, expect: '50% 50%'},
+ {at: 0.25, expect: 'calc(-5px + 62.5%) calc(-5px + 62.5%)'},
+ {at: 0.5, expect: 'calc(-10px + 75%) calc(-10px + 75%)'},
+ {at: 0.75, expect: 'calc(-15px + 87.5%) calc(-15px + 87.5%)'},
+ {at: 1, expect: 'calc(-20px + 100%) calc(-20px + 100%)'},
+]);
+
+// Single values
+test_interpolation({
+ property: 'background-position',
+ from: 'center',
+ to: 'bottom',
+}, [
+ {at: 0, expect: '50% 50%'},
+ {at: 0.25, expect: '50% 62.5%'},
+ {at: 0.5, expect: '50% 75%'},
+ {at: 0.75, expect: '50% 87.5%'},
+ {at: 1, expect: '50% 100%'},
+]);
+</script>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-position-x-interpolation.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-position-x-interpolation.html
new file mode 100644
index 0000000000..a66c1ea078
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-position-x-interpolation.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-position">
+<meta name="test" content="background-position-x supports animation">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.parent {
+ background-position-x: 60px;
+}
+
+.target {
+ background-position-x: 40px;
+}
+</style>
+
+<body>
+<script>
+test_interpolation({
+ property: 'background-position-x',
+ from: neutralKeyframe,
+ to: '80px',
+}, [
+ {at: -0.25, expect: '30px'},
+ {at: 0, expect: '40px'},
+ {at: 0.25, expect: '50px'},
+ {at: 0.5, expect: '60px'},
+ {at: 0.75, expect: '70px'},
+ {at: 1, expect: '80px'},
+ {at: 1.25, expect: '90px'},
+]);
+
+test_interpolation({
+ property: 'background-position-x',
+ from: 'initial',
+ to: 'right',
+}, [
+ {at: -0.25, expect: '-25%'},
+ {at: 0, expect: '0%'},
+ {at: 0.25, expect: '25%'},
+ {at: 0.5, expect: '50%'},
+ {at: 0.75, expect: '75%'},
+ {at: 1, expect: '100%'},
+ {at: 1.25, expect: '125%'},
+]);
+
+test_interpolation({
+ property: 'background-position-x',
+ from: 'inherit',
+ to: '80px',
+}, [
+ {at: -0.25, expect: '55px'},
+ {at: 0, expect: '60px'},
+ {at: 0.25, expect: '65px'},
+ {at: 0.5, expect: '70px'},
+ {at: 0.75, expect: '75px'},
+ {at: 1, expect: '80px'},
+ {at: 1.25, expect: '85px'},
+]);
+
+test_interpolation({
+ property: 'background-position-x',
+ from: '300px, 400px',
+ to: '500px, 600px, 700px',
+}, [
+ {at: -0.25, expect: '250px, 350px, 200px, 375px, 225px, 325px'},
+ {at: 0, expect: '300px, 400px, 300px, 400px, 300px, 400px'},
+ {at: 0.25, expect: '350px, 450px, 400px, 425px, 375px, 475px'},
+ {at: 0.5, expect: '400px, 500px, 500px, 450px, 450px, 550px'},
+ {at: 0.75, expect: '450px, 550px, 600px, 475px, 525px, 625px'},
+ {at: 1, expect: '500px, 600px, 700px, 500px, 600px, 700px'},
+ {at: 1.25, expect: '550px, 650px, 800px, 525px, 675px, 775px'},
+]);
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-position-y-interpolation.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-position-y-interpolation.html
new file mode 100644
index 0000000000..c272a71226
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-position-y-interpolation.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-position">
+<meta name="test" content="background-position-y supports animation">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.parent {
+ background-position-y: 60px;
+}
+
+.target {
+ background-position-y: 40px;
+}
+</style>
+
+<body>
+<script>
+test_interpolation({
+ property: 'background-position-y',
+ from: neutralKeyframe,
+ to: '80px',
+}, [
+ {at: -0.25, expect: '30px'},
+ {at: 0, expect: '40px'},
+ {at: 0.25, expect: '50px'},
+ {at: 0.5, expect: '60px'},
+ {at: 0.75, expect: '70px'},
+ {at: 1, expect: '80px'},
+ {at: 1.25, expect: '90px'},
+]);
+
+test_interpolation({
+ property: 'background-position-y',
+ from: 'initial',
+ to: 'bottom',
+}, [
+ {at: -0.25, expect: '-25%'},
+ {at: 0, expect: '0%'},
+ {at: 0.25, expect: '25%'},
+ {at: 0.5, expect: '50%'},
+ {at: 0.75, expect: '75%'},
+ {at: 1, expect: '100%'},
+ {at: 1.25, expect: '125%'},
+]);
+
+test_interpolation({
+ property: 'background-position-y',
+ from: 'inherit',
+ to: '80px',
+}, [
+ {at: -0.25, expect: '55px'},
+ {at: 0, expect: '60px'},
+ {at: 0.25, expect: '65px'},
+ {at: 0.5, expect: '70px'},
+ {at: 0.75, expect: '75px'},
+ {at: 1, expect: '80px'},
+ {at: 1.25, expect: '85px'},
+]);
+
+test_interpolation({
+ property: 'background-position-y',
+ from: '300px, 400px',
+ to: '500px, 600px, 700px',
+}, [
+ {at: -0.25, expect: '250px, 350px, 200px, 375px, 225px, 325px'},
+ {at: 0, expect: '300px, 400px, 300px, 400px, 300px, 400px'},
+ {at: 0.25, expect: '350px, 450px, 400px, 425px, 375px, 475px'},
+ {at: 0.5, expect: '400px, 500px, 500px, 450px, 450px, 550px'},
+ {at: 0.75, expect: '450px, 550px, 600px, 475px, 525px, 625px'},
+ {at: 1, expect: '500px, 600px, 700px, 500px, 600px, 700px'},
+ {at: 1.25, expect: '550px, 650px, 800px, 525px, 675px, 775px'},
+]);
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/background-size-interpolation.html b/testing/web-platform/tests/css/css-backgrounds/animations/background-size-interpolation.html
new file mode 100644
index 0000000000..f6a480c7bd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/background-size-interpolation.html
@@ -0,0 +1,166 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-size">
+<meta name="test" content="background-size supports animation as a repeatable list">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.parent {
+ background-size: 100px 100px;
+}
+.target {
+ width: 80px;
+ height: 100px;
+ display: inline-block;
+ border: 10px solid black;
+ background-repeat: no-repeat;
+ background-image: url(../resources/stripes-100.png),
+ url(../resources/stripes-100.png),
+ url(../resources/blue-100.png),
+ url(../resources/green-100.png);
+ background-position: left top, right top, left bottom, right bottom;
+ background-size: 10px 10px;
+}
+.expected {
+ margin-right: 10px;
+ border-color: green;
+}
+</style>
+
+<body></body>
+
+<script>
+// neutral
+test_interpolation({
+ property: 'background-size',
+ from: neutralKeyframe,
+ to: '20px 20px, 0px 0px',
+}, [
+ {at: -0.25, expect: ' 7.5px 7.5px, 12.5px 12.5px, 7.5px 7.5px, 12.5px 12.5px'},
+ {at: 0, expect: '10.0px 10.0px, 10.0px 10.0px, 10.0px 10.0px, 10.0px 10.0px'},
+ {at: 0.25, expect: '12.5px 12.5px, 7.5px 7.5px, 12.5px 12.5px, 7.5px 7.5px'},
+ {at: 0.5, expect: '15.0px 15.0px, 5.0px 5.0px, 15.0px 15.0px, 5.0px 5.0px'},
+ {at: 0.75, expect: '17.5px 17.5px, 2.5px 2.5px, 17.5px 17.5px, 2.5px 2.5px'},
+ {at: 1, expect: '20.0px 20.0px, 0.0px 0.0px, 20.0px 20.0px, 0.0px 0.0px'},
+ {at: 1.25, expect: '22.5px 22.5px, 0.0px 0.0px, 22.5px 22.5px, 0.0px 0.0px'},
+]);
+
+// initial
+test_no_interpolation({
+ property: 'background-size',
+ from: 'initial',
+ to: '20px 20px, 0px 0px',
+});
+
+// inherit
+test_interpolation({
+ property: 'background-size',
+ from: 'inherit',
+ to: '20px 20px, 0px 0px',
+}, [
+ {at: -0.25, expect: '120px 120px, 125px 125px, 120px 120px, 125px 125px'},
+ {at: 0, expect: '100px 100px, 100px 100px, 100px 100px, 100px 100px'},
+ {at: 0.25, expect: ' 80px 80px, 75px 75px, 80px 80px, 75px 75px'},
+ {at: 0.5, expect: ' 60px 60px, 50px 50px, 60px 60px, 50px 50px'},
+ {at: 0.75, expect: ' 40px 40px, 25px 25px, 40px 40px, 25px 25px'},
+ {at: 1, expect: ' 20px 20px, 0px 0px, 20px 20px, 0px 0px'},
+ {at: 1.25, expect: ' 0px 0px, 0px 0px, 0px 0px, 0px 0px'},
+]);
+
+// unset
+test_no_interpolation({
+ property: 'background-size',
+ from: 'unset',
+ to: '20px 20px, 0px 0px',
+});
+
+// Matched keywords in size value list.
+test_interpolation({
+ property: 'background-size',
+ from: '0px auto, 0px 0px, contain, cover',
+ to: '40px auto, 40px 40px, contain, cover',
+}, [
+ {at: -0.25, expect: ' 0px auto, 0px 0px, contain, cover'},
+ {at: 0, expect: ' 0px auto, 0px 0px, contain, cover'},
+ {at: 0.25, expect: '10px auto, 10px 10px, contain, cover'},
+ {at: 0.5, expect: '20px auto, 20px 20px, contain, cover'},
+ {at: 0.75, expect: '30px auto, 30px 30px, contain, cover'},
+ {at: 1, expect: '40px auto, 40px 40px, contain, cover'},
+ {at: 1.25, expect: '50px auto, 50px 50px, contain, cover'},
+]);
+
+// Mismatched keywords in size value list.
+test_no_interpolation({
+ property: 'background-size',
+ from: '0px 0px, 0px 0px, contain, cover',
+ to: '40px 40px, 40px 40px, cover, contain',
+});
+
+test_no_interpolation({
+ property: 'background-size',
+ from: '0px auto, 0px 0px',
+ to: 'auto 40px, 40px 40px',
+});
+
+// Equal number of size values as background images.
+test_interpolation({
+ property: 'background-size',
+ from: '0px 0px, 0px 0px, 0px 0px, 0px 0px',
+ to: '20px 20px, 40px 40px, 60px 60px, 100px 100px',
+}, [
+ {at: -0.25, expect: ' 0px 0px, 0px 0px, 0px 0px, 0px 0px'},
+ {at: 0, expect: ' 0px 0px, 0px 0px, 0px 0px, 0px 0px'},
+ {at: 0.25, expect: ' 5px 5px, 10px 10px, 15px 15px, 25px 25px'},
+ {at: 0.5, expect: '10px 10px, 20px 20px, 30px 30px, 50px 50px'},
+ {at: 0.75, expect: '15px 15px, 30px 30px, 45px 45px, 75px 75px'},
+ {at: 1, expect: '20px 20px, 40px 40px, 60px 60px, 100px 100px'},
+ {at: 1.25, expect: '25px 25px, 50px 50px, 75px 75px, 125px 125px'},
+]);
+
+// Single size value repeated over background images.
+test_interpolation({
+ property: 'background-size',
+ from: '0px 0px',
+ to: '80px 80px',
+}, [
+ {at: -0.25, expect: ' 0px 0px, 0px 0px, 0px 0px, 0px 0px'},
+ {at: 0, expect: ' 0px 0px, 0px 0px, 0px 0px, 0px 0px'},
+ {at: 0.25, expect: ' 20px 20px, 20px 20px, 20px 20px, 20px 20px'},
+ {at: 0.5, expect: ' 40px 40px, 40px 40px, 40px 40px, 40px 40px'},
+ {at: 0.75, expect: ' 60px 60px, 60px 60px, 60px 60px, 60px 60px'},
+ {at: 1, expect: ' 80px 80px, 80px 80px, 80px 80px, 80px 80px'},
+ {at: 1.25, expect: '100px 100px, 100px 100px, 100px 100px, 100px 100px'},
+]);
+
+test_interpolation({
+ property: 'background-size',
+ from: '0px',
+ to: '80px',
+}, [
+ {at: -0.25, expect: ' 0px, 0px, 0px, 0px'},
+ {at: 0, expect: ' 0px, 0px, 0px, 0px'},
+ {at: 0.25, expect: ' 20px, 20px, 20px, 20px'},
+ {at: 0.5, expect: ' 40px, 40px, 40px, 40px'},
+ {at: 0.75, expect: ' 60px, 60px, 60px, 60px'},
+ {at: 1, expect: ' 80px, 80px, 80px, 80px'},
+ {at: 1.25, expect: '100px, 100px, 100px, 100px'},
+]);
+
+// Mismatched numbers of size values.
+test_interpolation({
+ property: 'background-size',
+ from: '0px 0px, 80px 0px',
+ to: '40px 40px, 80px 80px, 0px 80px',
+}, [
+ {at: -0.25, expect: ' 0px 0px, 80px 0px, 0px 0px, 90px 0px'},
+ {at: 0, expect: ' 0px 0px, 80px 0px, 0px 0px, 80px 0px'},
+ {at: 0.25, expect: '10px 10px, 80px 20px, 0px 20px, 70px 10px'},
+ {at: 0.5, expect: '20px 20px, 80px 40px, 0px 40px, 60px 20px'},
+ {at: 0.75, expect: '30px 30px, 80px 60px, 0px 60px, 50px 30px'},
+ {at: 1, expect: '40px 40px, 80px 80px, 0px 80px, 40px 40px'},
+ {at: 1.25, expect: '50px 50px, 80px 100px, 0px 100px, 30px 50px'},
+]);
+</script>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/border-bottom-left-radius-composition.html b/testing/web-platform/tests/css/css-backgrounds/animations/border-bottom-left-radius-composition.html
new file mode 100644
index 0000000000..87042d1969
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/border-bottom-left-radius-composition.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>border-bottom-left-radius composition</title>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#the-border-radius">
+<meta name="assert" content="border-bottom-left-radius supports animation by computed value">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script>
+test_composition({
+ property: 'border-bottom-left-radius',
+ underlying: '40px 40px',
+ addFrom: '60px 60px',
+ addTo: '160px 160px',
+}, [
+ {at: -0.25, expect: '75px'},
+ {at: 0, expect: '100px'},
+ {at: 0.25, expect: '125px'},
+ {at: 0.5, expect: '150px'},
+ {at: 0.75, expect: '175px'},
+ {at: 1, expect: '200px'},
+ {at: 1.25, expect: '225px'},
+]);
+
+test_composition({
+ property: 'border-bottom-left-radius',
+ underlying: '40px 140px',
+ replaceFrom: '100px 120px',
+ addTo: '160px 60px',
+}, [
+ {at: -0.25, expect: '75px 100px'},
+ {at: 0, expect: '100px 120px'},
+ {at: 0.25, expect: '125px 140px'},
+ {at: 0.5, expect: '150px 160px'},
+ {at: 0.75, expect: '175px 180px'},
+ {at: 1, expect: '200px'},
+ {at: 1.25, expect: '225px 220px'},
+]);
+
+test_composition({
+ property: 'border-bottom-left-radius',
+ underlying: '40px 60px',
+ addFrom: '60px 140px',
+ replaceTo: '200px 120px',
+}, [
+ {at: -0.25, expect: '75px 220px'},
+ {at: 0, expect: '100px 200px'},
+ {at: 0.25, expect: '125px 180px'},
+ {at: 0.5, expect: '150px 160px'},
+ {at: 0.75, expect: '175px 140px'},
+ {at: 1, expect: '200px 120px'},
+ {at: 1.25, expect: '225px 100px'},
+]);
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/border-bottom-right-radius-composition.html b/testing/web-platform/tests/css/css-backgrounds/animations/border-bottom-right-radius-composition.html
new file mode 100644
index 0000000000..2b5a72df69
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/border-bottom-right-radius-composition.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>border-bottom-right-radius composition</title>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#the-border-radius">
+<meta name="assert" content="border-bottom-right-radius supports animation by computed value">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script>
+test_composition({
+ property: 'border-bottom-right-radius',
+ underlying: '40px 40px',
+ addFrom: '60px 60px',
+ addTo: '160px 160px',
+}, [
+ {at: -0.25, expect: '75px'},
+ {at: 0, expect: '100px'},
+ {at: 0.25, expect: '125px'},
+ {at: 0.5, expect: '150px'},
+ {at: 0.75, expect: '175px'},
+ {at: 1, expect: '200px'},
+ {at: 1.25, expect: '225px'},
+]);
+
+test_composition({
+ property: 'border-bottom-right-radius',
+ underlying: '40px 140px',
+ replaceFrom: '100px 120px',
+ addTo: '160px 60px',
+}, [
+ {at: -0.25, expect: '75px 100px'},
+ {at: 0, expect: '100px 120px'},
+ {at: 0.25, expect: '125px 140px'},
+ {at: 0.5, expect: '150px 160px'},
+ {at: 0.75, expect: '175px 180px'},
+ {at: 1, expect: '200px'},
+ {at: 1.25, expect: '225px 220px'},
+]);
+
+test_composition({
+ property: 'border-bottom-right-radius',
+ underlying: '40px 60px',
+ addFrom: '60px 140px',
+ replaceTo: '200px 120px',
+}, [
+ {at: -0.25, expect: '75px 220px'},
+ {at: 0, expect: '100px 200px'},
+ {at: 0.25, expect: '125px 180px'},
+ {at: 0.5, expect: '150px 160px'},
+ {at: 0.75, expect: '175px 140px'},
+ {at: 1, expect: '200px 120px'},
+ {at: 1.25, expect: '225px 100px'},
+]);
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/border-bottom-width-composition.html b/testing/web-platform/tests/css/css-backgrounds/animations/border-bottom-width-composition.html
new file mode 100644
index 0000000000..5377c0ab42
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/border-bottom-width-composition.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>border-bottom-width composition</title>
+<link rel="help" href="https://www.w3.org/TR/CSS2/box.html#border-width-properties">
+<meta name="assert" content="border-bottom-width supports animation by computed value">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script>
+test_composition({
+ property: 'border-bottom-width',
+ underlying: '50px',
+ addFrom: '100px',
+ addTo: '200px',
+}, [
+ {at: -0.3, expect: '120px'},
+ {at: 0, expect: '150px'},
+ {at: 0.5, expect: '200px'},
+ {at: 1, expect: '250px'},
+ {at: 1.5, expect: '300px'},
+]);
+
+test_composition({
+ property: 'border-bottom-width',
+ underlying: '100px',
+ addFrom: '10px',
+ addTo: '2px',
+}, [
+ {at: -0.5, expect: '114px'},
+ {at: 0, expect: '110px'},
+ {at: 0.5, expect: '106px'},
+ {at: 1, expect: '102px'},
+ {at: 1.5, expect: '98px'}, // Value clamping should happen after composition.
+]);
+
+test_composition({
+ property: 'border-bottom-width',
+ underlying: '10em',
+ addFrom: '100px',
+ addTo: '20em',
+}, [
+ {at: -0.3, expect: 'calc(130px + 4em)'},
+ {at: 0, expect: 'calc(100px + 10em)'},
+ {at: 0.5, expect: 'calc(50px + 20em)'},
+ {at: 1, expect: '30em'},
+ {at: 1.5, expect: 'calc(-50px + 40em)'},
+]);
+
+test_composition({
+ property: 'border-bottom-width',
+ underlying: '50px',
+ addFrom: '100px',
+ replaceTo: '200px',
+}, [
+ {at: -0.3, expect: '135px'},
+ {at: 0, expect: '150px'},
+ {at: 0.5, expect: '175px'},
+ {at: 1, expect: '200px'},
+ {at: 1.5, expect: '225px'},
+]);
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/border-color-interpolation.html b/testing/web-platform/tests/css/css-backgrounds/animations/border-color-interpolation.html
new file mode 100644
index 0000000000..3e7843b8a0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/border-color-interpolation.html
@@ -0,0 +1,120 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>border-color interpolation</title>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#border-color">
+<meta name="assert" content="border-color supports animation by computed value">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.parent {
+ border-color: white;
+}
+.target {
+ width: 50px;
+ height: 50px;
+ background-color: blue;
+ display: inline-block;
+ border: 12px solid;
+ border-color: darkblue;
+}
+.expected {
+ background-color: green;
+ margin-right: 2px;
+}
+</style>
+
+<body></body>
+
+<script>
+// As per https://bugzilla.mozilla.org/show_bug.cgi?id=137688, Firefox does not
+// support getComputedStyle for shorthands. As such, we have one test for this
+// which explicitly checks the shorthand variant, but most tests use one of the
+// longhands instead.
+function compareNotEmpty(actual, expected) {
+ assert_equals(actual, expected);
+ assert_not_equals(actual, '');
+}
+
+test_interpolation({
+ property: 'border-color',
+ from: 'rgb(20, 30, 40) rgb(40, 50, 60)',
+ to: 'rgb(10, 20, 30) rgb(40, 50, 60) rgb(30, 40, 50) rgb(50, 60, 70)',
+ comparisonFunction: compareNotEmpty,
+}, [
+ {at: -0.3, expect: 'rgb(23, 33, 43) rgb(40, 50, 60) rgb(17, 27, 37) rgb(37, 47, 57)'},
+ {at: 0, expect: 'rgb(20, 30, 40) rgb(40, 50, 60)'},
+ {at: 0.3, expect: 'rgb(17, 27, 37) rgb(40, 50, 60) rgb(23, 33, 43) rgb(43, 53, 63)'},
+ {at: 0.6, expect: 'rgb(14, 24, 34) rgb(40, 50, 60) rgb(26, 36, 46) rgb(46, 56, 66)'},
+ {at: 1, expect: 'rgb(10, 20, 30) rgb(40, 50, 60) rgb(30, 40, 50) rgb(50, 60, 70)'},
+ {at: 1.5, expect: 'rgb(5, 15, 25) rgb(40, 50, 60) rgb(35, 45, 55) rgb(55, 65, 75)'},
+]);
+
+test_interpolation({
+ property: 'border-top-color',
+ from: neutralKeyframe,
+ to: 'orange',
+}, [
+ {at: -0.3, expect: 'rgb(0, 0, 181)'},
+ {at: 0, expect: 'rgb(0, 0, 139)'},
+ {at: 0.3, expect: 'rgb(77, 50, 97)'},
+ {at: 0.6, expect: 'rgb(153, 99, 56)'},
+ {at: 1, expect: 'rgb(255, 165, 0)'},
+ {at: 1.5, expect: 'rgb(255, 248, 0)'},
+]);
+
+test_interpolation({
+ property: 'border-top-color',
+ from: 'initial',
+ to: 'orange',
+}, [
+ {at: -0.3, expect: 'rgb(0, 0, 0)'},
+ {at: 0, expect: 'rgb(0, 0, 0)'},
+ {at: 0.3, expect: 'rgb(77, 50, 0)'},
+ {at: 0.6, expect: 'rgb(153, 99, 0)'},
+ {at: 1, expect: 'rgb(255, 165, 0)'},
+ {at: 1.5, expect: 'rgb(255, 248, 0)'},
+]);
+
+test_interpolation({
+ property: 'border-top-color',
+ from: 'inherit',
+ to: 'orange',
+}, [
+ {at: -0.3, expect: 'rgb(255, 255, 255)'},
+ {at: 0, expect: 'rgb(255, 255, 255)'},
+ {at: 0.3, expect: 'rgb(255, 228, 179)'},
+ {at: 0.6, expect: 'rgb(255, 201, 102)'},
+ {at: 1, expect: 'rgb(255, 165, 0)'},
+ {at: 1.5, expect: 'rgb(255, 120, 0)'},
+]);
+
+test_interpolation({
+ property: 'border-top-color',
+ from: 'unset',
+ to: 'orange',
+}, [
+ {at: -0.3, expect: 'rgb(0, 0, 0)'},
+ {at: 0, expect: 'rgb(0, 0, 0)'},
+ {at: 0.3, expect: 'rgb(77, 50, 0)'},
+ {at: 0.6, expect: 'rgb(153, 99, 0)'},
+ {at: 1, expect: 'rgb(255, 165, 0)'},
+ {at: 1.5, expect: 'rgb(255, 248, 0)'},
+]);
+
+test_interpolation({
+ property: 'border-top-color',
+ from: 'white',
+ to: 'orange'
+}, [
+ {at: -0.3, expect: 'white'},
+ {at: 0, expect: 'white'},
+ {at: 0.3, expect: 'rgb(255, 228, 179)'},
+ {at: 0.6, expect: 'rgb(255, 201, 102)'},
+ {at: 1, expect: 'orange'},
+ {at: 1.5, expect: 'rgb(255, 120, 0)'},
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/border-image-outset-composition.html b/testing/web-platform/tests/css/css-backgrounds/animations/border-image-outset-composition.html
new file mode 100644
index 0000000000..e331171175
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/border-image-outset-composition.html
@@ -0,0 +1,133 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>border-image-outset composition</title>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#border-image-outset">
+<meta name="assert" content="border-image-outset supports animation by computed value">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script>
+test_composition({
+ property: 'border-image-outset',
+ underlying: '1 2 3 4',
+ addFrom: '1 2 3 4',
+ addTo: '101 102 103 104',
+}, [
+ {at: -0.25, expect: '0'}, // Non-negative.
+ {at: 0, expect: '2 4 6 8'},
+ {at: 0.25, expect: '27 29 31 33'},
+ {at: 0.5, expect: '52 54 56 58'},
+ {at: 0.75, expect: '77 79 81 83'},
+ {at: 1, expect: '102 104 106 108'},
+ {at: 1.25, expect: '127 129 131 133'},
+]);
+
+test_composition({
+ property: 'border-image-outset',
+ underlying: '100 200 300 400',
+ addFrom: '100',
+ addTo: '200 300 500',
+}, [
+ {at: -0.25, expect: '175 250 300 450'},
+ {at: 0, expect: '200 300 400 500'},
+ {at: 0.25, expect: '225 350 500 550'},
+ {at: 0.5, expect: '250 400 600 600'},
+ {at: 0.75, expect: '275 450 700 650'},
+ {at: 1, expect: '300 500 800 700'},
+ {at: 1.25, expect: '325 550 900 750'},
+]);
+
+test_composition({
+ property: 'border-image-outset',
+ underlying: '1 2 3px 4px',
+ addFrom: '1 2 3px 4px',
+ addTo: '101 102 103px 104px',
+}, [
+ {at: -0.25, expect: '0 0 0px 0px'}, // Non-negative.
+ {at: 0, expect: '2 4 6px 8px'},
+ {at: 0.25, expect: '27 29 31px 33px'},
+ {at: 0.5, expect: '52 54 56px 58px'},
+ {at: 0.75, expect: '77 79 81px 83px'},
+ {at: 1, expect: '102 104 106px 108px'},
+ {at: 1.25, expect: '127 129 131px 133px'},
+]);
+
+test_composition({
+ property: 'border-image-outset',
+ underlying: '10px 20px',
+ addFrom: '190px 180px 290px 280px',
+ addTo: '90px 80px',
+}, [
+ {at: -0.25, expect: '225px 225px 350px 350px'},
+ {at: 0, expect: '200px 200px 300px 300px'},
+ {at: 0.25, expect: '175px 175px 250px 250px'},
+ {at: 0.5, expect: '150px 150px 200px 200px'},
+ {at: 0.75, expect: '125px 125px 150px 150px'},
+ {at: 1, expect: '100px'},
+ {at: 1.25, expect: '75px 75px 50px 50px'},
+]);
+
+test_composition({
+ property: 'border-image-outset',
+ underlying: '10 20px',
+ replaceFrom: '100 100px',
+ addTo: '190 180px',
+}, [
+ {at: -0.25, expect: '75 75px'},
+ {at: 0, expect: '100 100px'},
+ {at: 0.25, expect: '125 125px'},
+ {at: 0.5, expect: '150 150px'},
+ {at: 0.75, expect: '175 175px'},
+ {at: 1, expect: '200 200px'},
+ {at: 1.25, expect: '225 225px'},
+]);
+
+test_composition({
+ property: 'border-image-outset',
+ underlying: '10px 20',
+ addFrom: '90px 80',
+ replaceTo: '0px 0 0px 0',
+}, [
+ {at: -0.25, expect: '125px 125'},
+ {at: 0, expect: '100px 100'},
+ {at: 0.25, expect: '75px 75'},
+ {at: 0.5, expect: '50px 50'},
+ {at: 0.75, expect: '25px 25'},
+ {at: 1, expect: '0px 0'},
+ {at: 1.25, expect: '0px 0'}, // Non-negative.
+]);
+
+test_composition({
+ property: 'border-image-outset',
+ underlying: '10 20',
+ addFrom: '100px 150px',
+ addTo: '200px 250px',
+}, [
+ {at: -0.25, expect: '75px 125px'},
+ {at: 0, expect: '100px 150px'},
+ {at: 0.25, expect: '125px 175px'},
+ {at: 0.5, expect: '150px 200px'},
+ {at: 0.75, expect: '175px 225px'},
+ {at: 1, expect: '200px 250px'},
+ {at: 1.25, expect: '225px 275px'},
+]);
+
+test_composition({
+ property: 'border-image-outset',
+ underlying: '10 20',
+ addFrom: '100 150px',
+ addTo: '200px 250',
+}, [
+ {at: -0.25, expect: '100 150px'},
+ {at: 0, expect: '100 150px'},
+ {at: 0.25, expect: '100 150px'},
+ {at: 0.5, expect: '200px 250'},
+ {at: 0.75, expect: '200px 250'},
+ {at: 1, expect: '200px 250'},
+ {at: 1.25, expect: '200px 250'},
+]);
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/border-image-outset-interpolation.html b/testing/web-platform/tests/css/css-backgrounds/animations/border-image-outset-interpolation.html
new file mode 100644
index 0000000000..aebadbbafb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/border-image-outset-interpolation.html
@@ -0,0 +1,125 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>border-image-outset interpolation</title>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#border-image-outset">
+<meta name="assert" content="border-image-outset supports animation by computed value">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.parent {
+ border-image-outset: 10px;
+}
+.target {
+ width: 50px;
+ height: 50px;
+ background-color: black;
+ display: inline-block;
+ border: 25px;
+ margin-right: 50px;
+ border-image-slice: 30%;
+ background-clip: content-box;
+ border-image-source: linear-gradient(45deg, pink, blue, white, black, green);
+ border-image-outset: 1px;
+}
+.expected {
+ background-color: green;
+}
+</style>
+
+<body></body>
+
+<script>
+test_interpolation({
+ property: 'border-image-outset',
+ from: neutralKeyframe,
+ to: '2px',
+}, [
+ {at: -0.3, expect: '0.7px'},
+ {at: 0, expect: '1px'},
+ {at: 0.3, expect: '1.3px'},
+ {at: 0.6, expect: '1.6px'},
+ {at: 1, expect: '2px'},
+ {at: 1.5, expect: '2.5px'},
+]);
+
+test_interpolation({
+ property: 'border-image-outset',
+ from: 'initial',
+ to: '2',
+}, [
+ {at: -0.3, expect: '0'}, // Non-negative
+ {at: 0, expect: '0'},
+ {at: 0.3, expect: '0.6'},
+ {at: 0.6, expect: '1.2'},
+ {at: 1, expect: '2'},
+ {at: 1.5, expect: '3'},
+]);
+
+test_interpolation({
+ property: 'border-image-outset',
+ from: 'inherit',
+ to: '2px',
+}, [
+ {at: -0.3, expect: '12.4px'},
+ {at: 0, expect: '10px'},
+ {at: 0.3, expect: '7.6px'},
+ {at: 0.6, expect: '5.2px'},
+ {at: 1, expect: '2px'},
+ {at: 1.5, expect: '0px'},
+]);
+
+test_interpolation({
+ property: 'border-image-outset',
+ from: 'unset',
+ to: '2',
+}, [
+ {at: -0.3, expect: '0'}, // Non-negative
+ {at: 0, expect: '0'},
+ {at: 0.3, expect: '0.6'},
+ {at: 0.6, expect: '1.2'},
+ {at: 1, expect: '2'},
+ {at: 1.5, expect: '3'},
+]);
+
+test_interpolation({
+ property: 'border-image-outset',
+ from: '0px',
+ to: '5px',
+}, [
+ {at: -0.3, expect: '0px'}, // Non-negative
+ {at: 0, expect: '0px'},
+ {at: 0.3, expect: '1.5px'},
+ {at: 0.6, expect: '3px'},
+ {at: 1, expect: '5px'},
+ {at: 1.5, expect: '7.5px'},
+]);
+
+test_interpolation({
+ property: 'border-image-outset',
+ from: '0',
+ to: '1',
+}, [
+ {at: -0.3, expect: '0'}, // Non-negative
+ {at: 0, expect: '0'},
+ {at: 0.3, expect: '0.3'},
+ {at: 0.6, expect: '0.6'},
+ {at: 1, expect: '1'},
+ {at: 1.5, expect: '1.5'},
+]);
+
+test_interpolation({
+ property: 'border-image-outset',
+ from: '1 2 3px 4px',
+ to: '101 102 103px 104px',
+}, [
+ {at: -0.3, expect: '0 0 0px 0px'}, // Non-negative
+ {at: 0, expect: '1 2 3px 4px'},
+ {at: 0.3, expect: '31 32 33px 34px'},
+ {at: 0.6, expect: '61 62 63px 64px'},
+ {at: 1, expect: '101 102 103px 104px'},
+ {at: 1.5, expect: '151 152 153px 154px'},
+]);
+</script>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/border-image-slice-composition.html b/testing/web-platform/tests/css/css-backgrounds/animations/border-image-slice-composition.html
new file mode 100644
index 0000000000..d0ccb1a3a6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/border-image-slice-composition.html
@@ -0,0 +1,133 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>border-image-slice composition</title>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#border-image-slice">
+<meta name="assert" content="border-image-slice supports animation by computed value">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script>
+test_composition({
+ property: 'border-image-slice',
+ underlying: '1 2 3 4',
+ addFrom: '1 2 3 4',
+ addTo: '101 102 103 104',
+}, [
+ {at: -0.25, expect: '0'}, // Non-negative.
+ {at: 0, expect: '2 4 6 8'},
+ {at: 0.25, expect: '27 29 31 33'},
+ {at: 0.5, expect: '52 54 56 58'},
+ {at: 0.75, expect: '77 79 81 83'},
+ {at: 1, expect: '102 104 106 108'},
+ {at: 1.25, expect: '127 129 131 133'},
+]);
+
+test_composition({
+ property: 'border-image-slice',
+ underlying: '100 200 300 400 fill',
+ addFrom: '100 fill',
+ addTo: '200 300 500 fill',
+}, [
+ {at: -0.25, expect: '175 250 300 450 fill'},
+ {at: 0, expect: '200 300 400 500 fill'},
+ {at: 0.25, expect: '225 350 500 550 fill'},
+ {at: 0.5, expect: '250 400 600 600 fill'},
+ {at: 0.75, expect: '275 450 700 650 fill'},
+ {at: 1, expect: '300 500 800 700 fill'},
+ {at: 1.25, expect: '325 550 900 750 fill'},
+]);
+
+test_composition({
+ property: 'border-image-slice',
+ underlying: '1 2 3% 4%',
+ addFrom: '1 2 3% 4%',
+ addTo: '101 102 103% 104%',
+}, [
+ {at: -0.25, expect: '0 0 0% 0%'}, // Non-negative.
+ {at: 0, expect: '2 4 6% 8%'},
+ {at: 0.25, expect: '27 29 31% 33%'},
+ {at: 0.5, expect: '52 54 56% 58%'},
+ {at: 0.75, expect: '77 79 81% 83%'},
+ {at: 1, expect: '102 104 106% 108%'},
+ {at: 1.25, expect: '127 129 131% 133%'},
+]);
+
+test_composition({
+ property: 'border-image-slice',
+ underlying: '10% 20%',
+ addFrom: '190% 180% 290% 280%',
+ addTo: '90% 80%',
+}, [
+ {at: -0.25, expect: '225% 225% 350% 350%'},
+ {at: 0, expect: '200% 200% 300% 300%'},
+ {at: 0.25, expect: '175% 175% 250% 250%'},
+ {at: 0.5, expect: '150% 150% 200% 200%'},
+ {at: 0.75, expect: '125% 125% 150% 150%'},
+ {at: 1, expect: '100%'},
+ {at: 1.25, expect: '75% 75% 50% 50%'},
+]);
+
+test_composition({
+ property: 'border-image-slice',
+ underlying: '10 20%',
+ replaceFrom: '100 100%',
+ addTo: '190 180%',
+}, [
+ {at: -0.25, expect: '75 75%'},
+ {at: 0, expect: '100 100%'},
+ {at: 0.25, expect: '125 125%'},
+ {at: 0.5, expect: '150 150%'},
+ {at: 0.75, expect: '175 175%'},
+ {at: 1, expect: '200 200%'},
+ {at: 1.25, expect: '225 225%'},
+]);
+
+test_composition({
+ property: 'border-image-slice',
+ underlying: '10% 20',
+ addFrom: '90% 80',
+ replaceTo: '0% 0 0% 0',
+}, [
+ {at: -0.25, expect: '125% 125'},
+ {at: 0, expect: '100% 100'},
+ {at: 0.25, expect: '75% 75'},
+ {at: 0.5, expect: '50% 50'},
+ {at: 0.75, expect: '25% 25'},
+ {at: 1, expect: '0% 0'},
+ {at: 1.25, expect: '0% 0'}, // Non-negative.
+]);
+
+test_composition({
+ property: 'border-image-slice',
+ underlying: '10 20',
+ addFrom: '100% 150%',
+ addTo: '200% 250% fill',
+}, [
+ {at: -0.25, expect: '100% 150%'},
+ {at: 0, expect: '100% 150%'},
+ {at: 0.25, expect: '100% 150%'},
+ {at: 0.5, expect: '200% 250% fill'},
+ {at: 0.75, expect: '200% 250% fill'},
+ {at: 1, expect: '200% 250% fill'},
+ {at: 1.25, expect: '200% 250% fill'},
+]);
+
+test_composition({
+ property: 'border-image-slice',
+ underlying: '10 20',
+ addFrom: '100 150%',
+ addTo: '200% 250',
+}, [
+ {at: -0.25, expect: '100 150%'},
+ {at: 0, expect: '100 150%'},
+ {at: 0.25, expect: '100 150%'},
+ {at: 0.5, expect: '200% 250'},
+ {at: 0.75, expect: '200% 250'},
+ {at: 1, expect: '200% 250'},
+ {at: 1.25, expect: '200% 250'},
+]);
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/border-image-slice-interpolation-stability.html b/testing/web-platform/tests/css/css-backgrounds/animations/border-image-slice-interpolation-stability.html
new file mode 100644
index 0000000000..26431334e4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/border-image-slice-interpolation-stability.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>border-image-slice interpolation stability</title>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#border-image-slice">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<div id="target"></div>
+<script>
+test(function() {
+ var player = target.animate([
+ {borderImageSlice: '50'},
+ {borderImageSlice: '50'},
+ ], {
+ duration: 1,
+ fill: 'forwards',
+ easing: 'cubic-bezier(0, 1.5, 1, 1.5)',
+ });
+ player.pause();
+ player.currentTime = 0.6345195996109396
+ assert_equals(getComputedStyle(target).borderImageSlice, '50');
+});
+</script>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/border-image-slice-interpolation.html b/testing/web-platform/tests/css/css-backgrounds/animations/border-image-slice-interpolation.html
new file mode 100644
index 0000000000..60301e755b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/border-image-slice-interpolation.html
@@ -0,0 +1,175 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>border-image-slice interpolation</title>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#border-image-slice">
+<meta name="assert" content="border-image-slice supports animation by computed value">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.parent {
+ border-image-slice: 50%;
+}
+.target {
+ width: 50px;
+ height: 50px;
+ background-color: black;
+ display: inline-block;
+ border: 25px;
+ border-image-source: linear-gradient(45deg, red, blue, green);
+ border-image-slice: 20%;
+}
+.expected {
+ background-color: green;
+ margin-right: 2px;
+}
+</style>
+
+<body></body>
+
+<script>
+test_interpolation({
+ property: 'border-image-slice',
+ from: neutralKeyframe,
+ to: '10%',
+}, [
+ {at: -0.3, expect: '23%'},
+ {at: 0, expect: '20%'},
+ {at: 0.3, expect: '17%'},
+ {at: 0.5, expect: '15%'},
+ {at: 0.6, expect: '14%'},
+ {at: 1, expect: '10%'},
+ {at: 1.5, expect: '5%'},
+]);
+
+test_interpolation({
+ property: 'border-image-slice',
+ from: 'initial',
+ to: '10%',
+}, [
+ {at: -0.3, expect: '127%'},
+ {at: 0, expect: '100%'},
+ {at: 0.3, expect: '73%'},
+ {at: 0.5, expect: '55%'},
+ {at: 0.6, expect: '46%'},
+ {at: 1, expect: '10%'},
+ {at: 1.5, expect: '0%'},
+]);
+
+test_interpolation({
+ property: 'border-image-slice',
+ from: 'inherit',
+ to: '10%',
+}, [
+ {at: -0.3, expect: '62%'},
+ {at: 0, expect: '50%'},
+ {at: 0.3, expect: '38%'},
+ {at: 0.5, expect: '30%'},
+ {at: 0.6, expect: '26%'},
+ {at: 1, expect: '10%'},
+ {at: 1.5, expect: '0%'},
+]);
+
+test_interpolation({
+ property: 'border-image-slice',
+ from: 'unset',
+ to: '10%',
+}, [
+ {at: -0.3, expect: '127%'},
+ {at: 0, expect: '100%'},
+ {at: 0.3, expect: '73%'},
+ {at: 0.5, expect: '55%'},
+ {at: 0.6, expect: '46%'},
+ {at: 1, expect: '10%'},
+ {at: 1.5, expect: '0%'},
+]);
+
+test_interpolation({
+ property: 'border-image-slice',
+ from: '0%',
+ to: '50%',
+}, [
+ {at: -0.3, expect: '0%'}, // CSS border-image-slice can't be negative.
+ {at: 0, expect: '0%'},
+ {at: 0.3, expect: '15%'},
+ {at: 0.5, expect: '25%'},
+ {at: 0.6, expect: '30%'},
+ {at: 1, expect: '50%'},
+ {at: 1.5, expect: '75%'},
+]);
+
+test_interpolation({
+ property: 'border-image-slice',
+ from: '0% 10% 20% 30%',
+ to: '40% 50% 60% 70%',
+}, [
+ {at: -0.5, expect: '0% 0% 0% 10%'},
+ {at: 0, expect: '0% 10% 20% 30%'},
+ {at: 0.3, expect: '12% 22% 32% 42%'},
+ {at: 0.5, expect: '20% 30% 40% 50%'},
+ {at: 0.6, expect: '24% 34% 44% 54%'},
+ {at: 1, expect: '40% 50% 60% 70%'},
+ {at: 1.5, expect: '60% 70% 80% 90%'},
+]);
+
+test_interpolation({
+ property: 'border-image-slice',
+ from: '0 10 20 30 fill',
+ to: '40 50 60 70 fill',
+}, [
+ {at: -0.5, expect: '0 0 0 10 fill'}, // CSS border-image-slice can't be negative.
+ {at: 0, expect: '0 10 20 30 fill'},
+ {at: 0.3, expect: '12 22 32 42 fill'},
+ {at: 0.5, expect: '20 30 40 50 fill'},
+ {at: 0.6, expect: '24 34 44 54 fill'},
+ {at: 1, expect: '40 50 60 70 fill'},
+ {at: 1.5, expect: '60 70 80 90 fill'},
+]);
+
+test_interpolation({
+ property: 'border-image-slice',
+ from: '0% 10 20% 30 fill',
+ to: '40% 50 60% 70 fill',
+}, [
+ {at: -0.5, expect: '0% 0 0% 10 fill'}, // CSS border-image-slice can't be negative.
+ {at: 0, expect: '0% 10 20% 30 fill'},
+ {at: 0.3, expect: '12% 22 32% 42 fill'},
+ {at: 0.5, expect: '20% 30 40% 50 fill'},
+ {at: 0.6, expect: '24% 34 44% 54 fill'},
+ {at: 1, expect: '40% 50 60% 70 fill'},
+ {at: 1.5, expect: '60% 70 80% 90 fill'},
+]);
+
+test_no_interpolation({
+ property: 'border-image-slice',
+ from: '0% fill',
+ to: '50%',
+});
+
+test_no_interpolation({
+ property: 'border-image-slice',
+ from: '50%',
+ to: '100',
+});
+
+test_no_interpolation({
+ property: 'border-image-slice',
+ from: '50% fill',
+ to: '100 fill',
+});
+
+test_no_interpolation({
+ property: 'border-image-slice',
+ from: '0% 10 20% 30 fill',
+ to: '40% 50 60% 70',
+});
+
+test_no_interpolation({
+ property: 'border-image-slice',
+ from: '0% 10 20 30 fill',
+ to: '40 50 60% 70',
+});
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/border-image-source-interpolation.html b/testing/web-platform/tests/css/css-backgrounds/animations/border-image-source-interpolation.html
new file mode 100644
index 0000000000..60dcfceddc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/border-image-source-interpolation.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>border-image-source interpolation</title>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#border-image-source">
+<meta name="assert" content="border-image-source has discrete animation">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.parent {
+ border-image-source: url(../support/green.png);
+}
+.target {
+ width: 50px;
+ height: 50px;
+ background-color: black;
+ display: inline-block;
+ border: 5px solid aqua;
+ border-image-source: url(../support/blue_color.png);
+ border-image-slice: 10%;
+}
+.expected {
+ background-color: green;
+ margin-right: 2px;
+}
+</style>
+
+<body></body>
+
+<script>
+// initial
+test_no_interpolation({
+ property: 'border-image-source',
+ from: 'initial',
+ to: 'url(../support/orange_color.png)',
+});
+
+// inherit
+test_no_interpolation({
+ property: 'border-image-source',
+ from: 'inherit',
+ to: 'url(../support/orange_color.png)',
+});
+
+// unset
+test_no_interpolation({
+ property: 'border-image-source',
+ from: 'unset',
+ to: 'url(../support/orange_color.png)',
+});
+
+// None to image
+test_no_interpolation({
+ property: 'border-image-source',
+ from: 'none',
+ to: 'url(../support/orange_color.png)',
+});
+
+// Image to image
+test_no_interpolation({
+ property: 'border-image-source',
+ from: 'url(../support/aqua_color.png)',
+ to: 'url(../support/orange_color.png)',
+});
+
+// Image to gradient
+test_no_interpolation({
+ property: 'border-image-source',
+ from: 'url(../support/aqua_color.png)',
+ to: 'linear-gradient(45deg, blue, orange)',
+});
+
+// Gradient to gradient
+test_no_interpolation({
+ property: 'border-image-source',
+ from: 'linear-gradient(-45deg, red, yellow)',
+ to: 'linear-gradient(45deg, blue, orange)',
+});
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/border-image-width-composition.html b/testing/web-platform/tests/css/css-backgrounds/animations/border-image-width-composition.html
new file mode 100644
index 0000000000..0d0a1dc4ed
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/border-image-width-composition.html
@@ -0,0 +1,133 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>border-image-width composition</title>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#border-image-width">
+<meta name="assert" content="border-image-width supports animation by computed value">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script>
+test_composition({
+ property: 'border-image-width',
+ underlying: '1 2 3 4',
+ addFrom: '1 2 3 4',
+ addTo: '101 102 103 104',
+}, [
+ {at: -0.25, expect: '0'}, // Non-negative.
+ {at: 0, expect: '2 4 6 8'},
+ {at: 0.25, expect: '27 29 31 33'},
+ {at: 0.5, expect: '52 54 56 58'},
+ {at: 0.75, expect: '77 79 81 83'},
+ {at: 1, expect: '102 104 106 108'},
+ {at: 1.25, expect: '127 129 131 133'},
+]);
+
+test_composition({
+ property: 'border-image-width',
+ underlying: '100 200 300 400',
+ addFrom: '100',
+ addTo: '200 300 500',
+}, [
+ {at: -0.25, expect: '175 250 300 450'},
+ {at: 0, expect: '200 300 400 500'},
+ {at: 0.25, expect: '225 350 500 550'},
+ {at: 0.5, expect: '250 400 600 600'},
+ {at: 0.75, expect: '275 450 700 650'},
+ {at: 1, expect: '300 500 800 700'},
+ {at: 1.25, expect: '325 550 900 750'},
+]);
+
+test_composition({
+ property: 'border-image-width',
+ underlying: '1 2 3px 4%',
+ addFrom: '1 2 3px 4%',
+ addTo: '101 102 103px 104%',
+}, [
+ {at: -0.25, expect: '0 0 0px 0%'}, // Non-negative.
+ {at: 0, expect: '2 4 6px 8%'},
+ {at: 0.25, expect: '27 29 31px 33%'},
+ {at: 0.5, expect: '52 54 56px 58%'},
+ {at: 0.75, expect: '77 79 81px 83%'},
+ {at: 1, expect: '102 104 106px 108%'},
+ {at: 1.25, expect: '127 129 131px 133%'},
+]);
+
+test_composition({
+ property: 'border-image-width',
+ underlying: '10px 20px',
+ addFrom: '190px 180px 290px 280px',
+ addTo: '90px 80px',
+}, [
+ {at: -0.25, expect: '225px 225px 350px 350px'},
+ {at: 0, expect: '200px 200px 300px 300px'},
+ {at: 0.25, expect: '175px 175px 250px 250px'},
+ {at: 0.5, expect: '150px 150px 200px 200px'},
+ {at: 0.75, expect: '125px 125px 150px 150px'},
+ {at: 1, expect: '100px'},
+ {at: 1.25, expect: '75px 75px 50px 50px'},
+]);
+
+test_composition({
+ property: 'border-image-width',
+ underlying: '10 20px',
+ replaceFrom: '100 100px',
+ addTo: '190 180px',
+}, [
+ {at: -0.25, expect: '75 75px'},
+ {at: 0, expect: '100 100px'},
+ {at: 0.25, expect: '125 125px'},
+ {at: 0.5, expect: '150 150px'},
+ {at: 0.75, expect: '175 175px'},
+ {at: 1, expect: '200 200px'},
+ {at: 1.25, expect: '225 225px'},
+]);
+
+test_composition({
+ property: 'border-image-width',
+ underlying: '10px 20',
+ addFrom: '90px 80',
+ replaceTo: '0px 0 0px 0',
+}, [
+ {at: -0.25, expect: '125px 125'},
+ {at: 0, expect: '100px 100'},
+ {at: 0.25, expect: '75px 75'},
+ {at: 0.5, expect: '50px 50'},
+ {at: 0.75, expect: '25px 25'},
+ {at: 1, expect: '0px 0'},
+ {at: 1.25, expect: '0px 0'}, // Non-negative.
+]);
+
+test_composition({
+ property: 'border-image-width',
+ underlying: '10 20',
+ addFrom: '100px 150px',
+ addTo: '200px 250px',
+}, [
+ {at: -0.25, expect: '75px 125px'},
+ {at: 0, expect: '100px 150px'},
+ {at: 0.25, expect: '125px 175px'},
+ {at: 0.5, expect: '150px 200px'},
+ {at: 0.75, expect: '175px 225px'},
+ {at: 1, expect: '200px 250px'},
+ {at: 1.25, expect: '225px 275px'},
+]);
+
+test_composition({
+ property: 'border-image-width',
+ underlying: '10 20',
+ addFrom: '100 150px',
+ addTo: '200% 250',
+}, [
+ {at: -0.25, expect: '100 150px'},
+ {at: 0, expect: '100 150px'},
+ {at: 0.25, expect: '100 150px'},
+ {at: 0.5, expect: '200% 250'},
+ {at: 0.75, expect: '200% 250'},
+ {at: 1, expect: '200% 250'},
+ {at: 1.25, expect: '200% 250'},
+]);
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/border-image-width-interpolation.html b/testing/web-platform/tests/css/css-backgrounds/animations/border-image-width-interpolation.html
new file mode 100644
index 0000000000..ea138201b1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/border-image-width-interpolation.html
@@ -0,0 +1,192 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>border-image-width interpolation</title>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#border-image-width">
+<meta name="assert" content="border-image-width supports animation by computed value">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.parent {
+ border-image-width: 100px;
+}
+.target {
+ width: 80px;
+ height: 80px;
+ background-color: black;
+ display: inline-block;
+ border: 10px;
+ border-image-source: linear-gradient(45deg, red, blue, green);
+ border-image-width: 10px;
+}
+.expected {
+ background-color: green;
+ margin-right: 2px;
+}
+</style>
+
+<body></body>
+
+<script>
+test_interpolation({
+ property: 'border-image-width',
+ from: neutralKeyframe,
+ to: '20px',
+}, [
+ {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'},
+ {at: 5, expect: '60px'},
+ {at: 10, expect: '110px'},
+]);
+test_no_interpolation({
+ property: 'border-image-width',
+ from: 'initial',
+ to: '20px',
+});
+test_interpolation({
+ property: 'border-image-width',
+ from: 'inherit',
+ to: '20px',
+}, [
+ {at: -0.3, expect: '124px'},
+ {at: 0, expect: '100px'},
+ {at: 0.3, expect: '76px'},
+ {at: 0.6, expect: '52px'},
+ {at: 1, expect: '20px'},
+ {at: 1.5, expect: '0px'},
+ {at: 5, expect: '0px'},
+ {at: 10, expect: '0px'},
+]);
+test_no_interpolation({
+ property: 'border-image-width',
+ from: 'unset',
+ to: '20px',
+});
+test_interpolation({
+ property: 'border-image-width',
+ from: '0px',
+ to: '20px'
+}, [
+ {at: -0.3, expect: '0px'}, // CSS border-image-width can't be negative.
+ {at: 0, expect: '0px'},
+ {at: 0.3, expect: '6px'},
+ {at: 0.6, expect: '12px'},
+ {at: 1, expect: '20px'},
+ {at: 1.5, expect: '30px'},
+ {at: 5, expect: '100px'},
+ {at: 10, expect: '200px'}
+]);
+test_interpolation({
+ property: 'border-image-width',
+ from: '0%',
+ to: '20%'
+}, [
+ {at: -0.3, expect: '0%'}, // CSS border-image-width can't be negative.
+ {at: 0, expect: '0%'},
+ {at: 0.3, expect: '6%'},
+ {at: 0.6, expect: '12%'},
+ {at: 1, expect: '20%'},
+ {at: 1.5, expect: '30%'},
+ {at: 5, expect: '100%'},
+ {at: 10, expect: '200%'}
+]);
+test_interpolation({
+ property: 'border-image-width',
+ from: '0',
+ to: '20'
+}, [
+ {at: -0.3, expect: '0'}, // CSS border-image-width can't be negative.
+ {at: 0, expect: '0'},
+ {at: 0.3, expect: '6'},
+ {at: 0.6, expect: '12'},
+ {at: 1, expect: '20'},
+ {at: 1.5, expect: '30'},
+ {at: 5, expect: '100'},
+ {at: 10, expect: '200'}
+]);
+test_interpolation({
+ property: 'border-image-width',
+ from: '10px 20% 30 40px',
+ to: '80px 70% 60 50px'
+}, [
+ {at: -0.3, expect: '0px 5% 21 37px'}, // CSS border-image-width can't be negative.
+ {at: 0, expect: '10px 20% 30 40px'},
+ {at: 0.3, expect: '31px 35% 39 43px'},
+ {at: 0.6, expect: '52px 50% 48 46px'},
+ {at: 1, expect: '80px 70% 60 50px'},
+ {at: 1.5, expect: '115px 95% 75 55px'},
+ {at: 5, expect: '360px 270% 180 90px'},
+ {at: 10, expect: '710px 520% 330 140px'}
+]);
+test_interpolation({
+ property: 'border-image-width',
+ from: '10%',
+ to: '20px'
+}, [
+ // Percentages are relative to the size of the border image area, which is 120px.
+ {at: -0.3, expect: 'calc(13% + -6px)'}, // Should be parsed as 16px - 6px = 10px
+ {at: 0, expect: '10%'}, // Should be parsed as 12px
+ {at: 0.3, expect: 'calc(7% + 6px)'}, // Should be parsed as 8px + 6px = 14px
+ {at: 0.6, expect: 'calc(4% + 12px)'}, // Should be parsed as 5px + 12px = 17px
+ {at: 1, expect: 'calc(0% + 20px)'},
+ {at: 1.5, expect: 'calc(-5% + 30px)'}, // Should be parsed as -6px + 30px = 24px
+]);
+test_interpolation({
+ property: 'border-image-width',
+ from: '10px',
+ to: '20%'
+}, [
+ // Percentages are relative to the size of the border image area, which is 120px.
+ {at: -0.3, expect: 'calc(13px + -6%)'}, // Should be parsed as 13px - 7px = 6px
+ {at: 0, expect: 'calc(0% + 10px)'},
+ {at: 0.3, expect: 'calc(7px + 6%)'}, // Should be parsed as 7px + 7px = 14px
+ {at: 0.6, expect: 'calc(4px + 12%)'}, // Should be parsed as 4px + 14px = 18px
+ {at: 1, expect: '20%'}, // Should be parsed as 24px
+ {at: 1.5, expect: 'calc(-5px + 30%)'}, // Should be parsed as -5px + 36px = 31px
+]);
+
+test_interpolation({
+ property: 'border-image-width',
+ from: '10px auto auto 20',
+ to: '110px auto auto 120'
+}, [
+ {at: -0.3, expect: ' 0px auto auto 0'},
+ {at: 0, expect: ' 10px auto auto 20'},
+ {at: 0.3, expect: ' 40px auto auto 50'},
+ {at: 0.6, expect: ' 70px auto auto 80'},
+ {at: 1, expect: '110px auto auto 120'},
+ {at: 1.5, expect: '160px auto auto 170'},
+]);
+
+test_no_interpolation({
+ property: 'border-image-width',
+ from: '10px auto auto 20',
+ to: '110px auto 120 auto'
+});
+test_no_interpolation({
+ property: 'border-image-width',
+ from: '10px',
+ to: '20'
+});
+test_no_interpolation({
+ property: 'border-image-width',
+ from: '10',
+ to: '20px'
+});
+test_no_interpolation({
+ property: 'border-image-width',
+ from: '10%',
+ to: '20'
+});
+test_no_interpolation({
+ property: 'border-image-width',
+ from: '10',
+ to: '20%'
+});
+</script>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/border-left-width-composition.html b/testing/web-platform/tests/css/css-backgrounds/animations/border-left-width-composition.html
new file mode 100644
index 0000000000..1b90effbc3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/border-left-width-composition.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>border-left-width composition</title>
+<link rel="help" href="https://www.w3.org/TR/CSS2/box.html#border-width-properties">
+<meta name="assert" content="border-left-width supports animation by computed value">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script>
+test_composition({
+ property: 'border-left-width',
+ underlying: '50px',
+ addFrom: '100px',
+ addTo: '200px',
+}, [
+ {at: -0.3, expect: '120px'},
+ {at: 0, expect: '150px'},
+ {at: 0.5, expect: '200px'},
+ {at: 1, expect: '250px'},
+ {at: 1.5, expect: '300px'},
+]);
+
+test_composition({
+ property: 'border-left-width',
+ underlying: '100px',
+ addFrom: '10px',
+ addTo: '2px',
+}, [
+ {at: -0.5, expect: '114px'},
+ {at: 0, expect: '110px'},
+ {at: 0.5, expect: '106px'},
+ {at: 1, expect: '102px'},
+ {at: 1.5, expect: '98px'}, // Value clamping should happen after composition.
+]);
+
+test_composition({
+ property: 'border-left-width',
+ underlying: '10em',
+ addFrom: '100px',
+ addTo: '20em',
+}, [
+ {at: -0.3, expect: 'calc(130px + 4em)'},
+ {at: 0, expect: 'calc(100px + 10em)'},
+ {at: 0.5, expect: 'calc(50px + 20em)'},
+ {at: 1, expect: '30em'},
+ {at: 1.5, expect: 'calc(-50px + 40em)'},
+]);
+
+test_composition({
+ property: 'border-left-width',
+ underlying: '50px',
+ addFrom: '100px',
+ replaceTo: '200px',
+}, [
+ {at: -0.3, expect: '135px'},
+ {at: 0, expect: '150px'},
+ {at: 0.5, expect: '175px'},
+ {at: 1, expect: '200px'},
+ {at: 1.5, expect: '225px'},
+]);
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/border-radius-interpolation.html b/testing/web-platform/tests/css/css-backgrounds/animations/border-radius-interpolation.html
new file mode 100644
index 0000000000..195469e831
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/border-radius-interpolation.html
@@ -0,0 +1,141 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>border-radius interpolation</title>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#border-radius">
+<meta name="assert" content="border-radius supports animation by computed value">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.parent {
+ border-radius: 30px;
+}
+.target {
+ width: 80px;
+ height: 80px;
+ display: inline-block;
+ background-color: black;
+ margin-right: 5px;
+ border-radius: 10px;
+}
+.expected {
+ background-color: green;
+ margin-right: 15px;
+}
+</style>
+
+<body></body>
+
+<script>
+// As per https://bugzilla.mozilla.org/show_bug.cgi?id=137688, Firefox does not
+// support getComputedStyle for shorthands. As such, we have one test for this
+// which explicitly checks the shorthand variant, but most tests use one of the
+// longhands instead.
+function compareNotEmpty(actual, expected) {
+ assert_equals(actual, expected);
+ assert_not_equals(actual, '');
+}
+
+test_interpolation({
+ property: 'border-radius',
+ from: '20px 40px 60px 80px / 120px 140px 160px 180px',
+ to: '30px 50px 70px 90px / 130px 150px 170px 190px',
+ comparisonFunction: compareNotEmpty,
+}, [
+ {at: -0.3, expect: '17px 37px 57px 77px / 117px 137px 157px 177px'},
+ {at: 0, expect: '20px 40px 60px 80px / 120px 140px 160px 180px'},
+ {at: 0.3, expect: '23px 43px 63px 83px / 123px 143px 163px 183px'},
+ {at: 0.6, expect: '26px 46px 66px 86px / 126px 146px 166px 186px'},
+ {at: 1, expect: '30px 50px 70px 90px / 130px 150px 170px 190px'},
+ {at: 1.5, expect: '35px 55px 75px 95px / 135px 155px 175px 195px'}
+]);
+
+test_interpolation({
+ property: 'border-top-left-radius',
+ from: neutralKeyframe,
+ to: '20px',
+}, [
+ {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: 'border-top-left-radius',
+ from: 'initial',
+ to: '20px',
+}, [
+ {at: -0.3, expect: '0px'},
+ {at: 0, expect: '0px'},
+ {at: 0.3, expect: '6px'},
+ {at: 0.6, expect: '12px'},
+ {at: 1, expect: '20px'},
+ {at: 1.5, expect: '30px'},
+]);
+test_interpolation({
+ property: 'border-top-left-radius',
+ from: 'inherit',
+ to: '20px',
+}, [
+ {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: 'border-top-left-radius',
+ from: 'unset',
+ to: '20px',
+}, [
+ {at: -0.3, expect: '0px'},
+ {at: 0, expect: '0px'},
+ {at: 0.3, expect: '6px'},
+ {at: 0.6, expect: '12px'},
+ {at: 1, expect: '20px'},
+ {at: 1.5, expect: '30px'},
+]);
+test_interpolation({
+ property: 'border-top-left-radius',
+ from: '10px',
+ to: '50px'
+}, [
+ {at: -0.3, expect: '0px'}, // CSS border-top-left-radius can't be negative.
+ {at: 0, expect: '10px'},
+ {at: 0.3, expect: '22px'},
+ {at: 0.6, expect: '34px'},
+ {at: 1, expect: '50px'},
+ {at: 1.5, expect: '70px'},
+]);
+test_interpolation({
+ property: 'border-top-left-radius',
+ from: '10px',
+ to: '100%'
+}, [
+ {at: -0.3, expect: 'calc(13px + -30%)'},
+ {at: 0, expect: 'calc(10px + 0%)'},
+ {at: 0.3, expect: 'calc(7px + 30%)'},
+ {at: 0.6, expect: 'calc(4px + 60%)'},
+ {at: 1, expect: '100%'},
+ {at: 1.5, expect: 'calc(-5px + 150%)'},
+]);
+
+test_interpolation({
+ property: 'border-top-left-radius',
+ from: '20px',
+ to: '10px 30px'
+}, [
+ {at: -2, expect: '40px 0px'},
+ {at: -0.3, expect: '23px 17px'},
+ {at: 0, expect: '20px'},
+ {at: 0.3, expect: '17px 23px'},
+ {at: 0.6, expect: '14px 26px'},
+ {at: 1, expect: '10px 30px'},
+ {at: 1.5, expect: '5px 35px'}
+]);
+</script>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/border-right-width-composition.html b/testing/web-platform/tests/css/css-backgrounds/animations/border-right-width-composition.html
new file mode 100644
index 0000000000..aa9e1dcc66
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/border-right-width-composition.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>border-right-width composition</title>
+<link rel="help" href="https://www.w3.org/TR/CSS2/box.html#border-width-properties">
+<meta name="assert" content="border-right-width supports animation by computed value">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script>
+test_composition({
+ property: 'border-right-width',
+ underlying: '50px',
+ addFrom: '100px',
+ addTo: '200px',
+}, [
+ {at: -0.3, expect: '120px'},
+ {at: 0, expect: '150px'},
+ {at: 0.5, expect: '200px'},
+ {at: 1, expect: '250px'},
+ {at: 1.5, expect: '300px'},
+]);
+
+test_composition({
+ property: 'border-right-width',
+ underlying: '100px',
+ addFrom: '10px',
+ addTo: '2px',
+}, [
+ {at: -0.5, expect: '114px'},
+ {at: 0, expect: '110px'},
+ {at: 0.5, expect: '106px'},
+ {at: 1, expect: '102px'},
+ {at: 1.5, expect: '98px'}, // Value clamping should happen after composition.
+]);
+
+test_composition({
+ property: 'border-right-width',
+ underlying: '10em',
+ addFrom: '100px',
+ addTo: '20em',
+}, [
+ {at: -0.3, expect: 'calc(130px + 4em)'},
+ {at: 0, expect: 'calc(100px + 10em)'},
+ {at: 0.5, expect: 'calc(50px + 20em)'},
+ {at: 1, expect: '30em'},
+ {at: 1.5, expect: 'calc(-50px + 40em)'},
+]);
+
+test_composition({
+ property: 'border-right-width',
+ underlying: '50px',
+ addFrom: '100px',
+ replaceTo: '200px',
+}, [
+ {at: -0.3, expect: '135px'},
+ {at: 0, expect: '150px'},
+ {at: 0.5, expect: '175px'},
+ {at: 1, expect: '200px'},
+ {at: 1.5, expect: '225px'},
+]);
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/border-top-left-radius-composition.html b/testing/web-platform/tests/css/css-backgrounds/animations/border-top-left-radius-composition.html
new file mode 100644
index 0000000000..1c2056bc01
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/border-top-left-radius-composition.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>border-top-left-radius composition</title>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#the-border-radius">
+<meta name="assert" content="border-top-left-radius supports animation by computed value">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script>
+test_composition({
+ property: 'border-top-left-radius',
+ underlying: '40px 40px',
+ addFrom: '60px 60px',
+ addTo: '160px 160px',
+}, [
+ {at: -0.25, expect: '75px'},
+ {at: 0, expect: '100px'},
+ {at: 0.25, expect: '125px'},
+ {at: 0.5, expect: '150px'},
+ {at: 0.75, expect: '175px'},
+ {at: 1, expect: '200px'},
+ {at: 1.25, expect: '225px'},
+]);
+
+test_composition({
+ property: 'border-top-left-radius',
+ underlying: '40px 140px',
+ replaceFrom: '100px 120px',
+ addTo: '160px 60px',
+}, [
+ {at: -0.25, expect: '75px 100px'},
+ {at: 0, expect: '100px 120px'},
+ {at: 0.25, expect: '125px 140px'},
+ {at: 0.5, expect: '150px 160px'},
+ {at: 0.75, expect: '175px 180px'},
+ {at: 1, expect: '200px'},
+ {at: 1.25, expect: '225px 220px'},
+]);
+
+test_composition({
+ property: 'border-top-left-radius',
+ underlying: '40px 60px',
+ addFrom: '60px 140px',
+ replaceTo: '200px 120px',
+}, [
+ {at: -0.25, expect: '75px 220px'},
+ {at: 0, expect: '100px 200px'},
+ {at: 0.25, expect: '125px 180px'},
+ {at: 0.5, expect: '150px 160px'},
+ {at: 0.75, expect: '175px 140px'},
+ {at: 1, expect: '200px 120px'},
+ {at: 1.25, expect: '225px 100px'},
+]);
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/border-top-right-radius-composition.html b/testing/web-platform/tests/css/css-backgrounds/animations/border-top-right-radius-composition.html
new file mode 100644
index 0000000000..9a26d51375
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/border-top-right-radius-composition.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>border-top-right-radius composition</title>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#the-border-radius">
+<meta name="assert" content="border-top-right-radius supports animation by computed value">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script>
+test_composition({
+ property: 'border-top-right-radius',
+ underlying: '40px 40px',
+ addFrom: '60px 60px',
+ addTo: '160px 160px',
+}, [
+ {at: -0.25, expect: '75px'},
+ {at: 0, expect: '100px'},
+ {at: 0.25, expect: '125px'},
+ {at: 0.5, expect: '150px'},
+ {at: 0.75, expect: '175px'},
+ {at: 1, expect: '200px'},
+ {at: 1.25, expect: '225px'},
+]);
+
+test_composition({
+ property: 'border-top-right-radius',
+ underlying: '40px 140px',
+ replaceFrom: '100px 120px',
+ addTo: '160px 60px',
+}, [
+ {at: -0.25, expect: '75px 100px'},
+ {at: 0, expect: '100px 120px'},
+ {at: 0.25, expect: '125px 140px'},
+ {at: 0.5, expect: '150px 160px'},
+ {at: 0.75, expect: '175px 180px'},
+ {at: 1, expect: '200px'},
+ {at: 1.25, expect: '225px 220px'},
+]);
+
+test_composition({
+ property: 'border-top-right-radius',
+ underlying: '40px 60px',
+ addFrom: '60px 140px',
+ replaceTo: '200px 120px',
+}, [
+ {at: -0.25, expect: '75px 220px'},
+ {at: 0, expect: '100px 200px'},
+ {at: 0.25, expect: '125px 180px'},
+ {at: 0.5, expect: '150px 160px'},
+ {at: 0.75, expect: '175px 140px'},
+ {at: 1, expect: '200px 120px'},
+ {at: 1.25, expect: '225px 100px'},
+]);
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/border-top-width-composition.html b/testing/web-platform/tests/css/css-backgrounds/animations/border-top-width-composition.html
new file mode 100644
index 0000000000..475c3930b9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/border-top-width-composition.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>border-top-width composition</title>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#border-width">
+<meta name="assert" content="border-top-width supports animation by computed value">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script>
+test_composition({
+ property: 'border-top-width',
+ underlying: '50px',
+ addFrom: '100px',
+ addTo: '200px',
+}, [
+ {at: -0.3, expect: '120px'},
+ {at: 0, expect: '150px'},
+ {at: 0.5, expect: '200px'},
+ {at: 1, expect: '250px'},
+ {at: 1.5, expect: '300px'},
+]);
+
+test_composition({
+ property: 'border-top-width',
+ underlying: '100px',
+ addFrom: '10px',
+ addTo: '2px',
+}, [
+ {at: -0.5, expect: '114px'},
+ {at: 0, expect: '110px'},
+ {at: 0.5, expect: '106px'},
+ {at: 1, expect: '102px'},
+ {at: 1.5, expect: '98px'}, // Value clamping should happen after composition.
+]);
+
+test_composition({
+ property: 'border-top-width',
+ underlying: '10em',
+ addFrom: '100px',
+ addTo: '20em',
+}, [
+ {at: -0.3, expect: 'calc(130px + 4em)'},
+ {at: 0, expect: 'calc(100px + 10em)'},
+ {at: 0.5, expect: 'calc(50px + 20em)'},
+ {at: 1, expect: '30em'},
+ {at: 1.5, expect: 'calc(-50px + 40em)'},
+]);
+
+test_composition({
+ property: 'border-top-width',
+ underlying: '50px',
+ addFrom: '100px',
+ replaceTo: '200px',
+}, [
+ {at: -0.3, expect: '135px'},
+ {at: 0, expect: '150px'},
+ {at: 0.5, expect: '175px'},
+ {at: 1, expect: '200px'},
+ {at: 1.5, expect: '225px'},
+]);
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/border-width-interpolation.html b/testing/web-platform/tests/css/css-backgrounds/animations/border-width-interpolation.html
new file mode 100644
index 0000000000..69f117b03e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/border-width-interpolation.html
@@ -0,0 +1,175 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>border-width interpolation</title>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#border-width">
+<meta name="assert" content="border-width supports animation by computed value">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.parent {
+ border-width: 30px;
+}
+.target {
+ width: 50px;
+ height: 50px;
+ background-color: black;
+ display: inline-block;
+ border: 2px solid orange;
+ margin: 18px;
+ border-width: 10px;
+}
+.expected {
+ background-color: green;
+}
+</style>
+
+<body></body>
+
+<script>
+// As per https://bugzilla.mozilla.org/show_bug.cgi?id=137688, Firefox does not
+// support getComputedStyle for shorthands. As such, we have one test for this
+// which explicitly checks the shorthand variant, but most tests use one of the
+// longhands instead.
+function compareNotEmpty(actual, expected) {
+ assert_equals(actual, expected);
+ assert_not_equals(actual, '');
+}
+
+test_interpolation({
+ property: 'border-width',
+ from: '20px 40px 60px 80px',
+ to: '30px 50px 70px 90px',
+ comparisonFunction: compareNotEmpty,
+}, [
+ {at: -0.3, expect: '17px 37px 57px 77px'},
+ {at: 0, expect: '20px 40px 60px 80px'},
+ {at: 0.3, expect: '23px 43px 63px 83px'},
+ {at: 0.6, expect: '26px 46px 66px 86px'},
+ {at: 1, expect: '30px 50px 70px 90px'},
+ {at: 1.5, expect: '35px 55px 75px 95px'}
+]);
+
+test_interpolation({
+ property: 'border-left-width',
+ from: neutralKeyframe,
+ to: '20px',
+}, [
+ {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: 'border-left-width',
+ from: 'initial',
+ to: '23px',
+}, [
+ {at: -0.3, expect: '0px'},
+ {at: 0, expect: '3px'},
+ {at: 0.3, expect: '9px'},
+ {at: 0.6, expect: '15px'},
+ {at: 1, expect: '23px'},
+ {at: 1.5, expect: '33px'},
+]);
+
+test_interpolation({
+ property: 'border-left-width',
+ from: 'inherit',
+ to: '20px',
+}, [
+ {at: -0.3, expect: '0px'},
+ {at: 0, expect: '0px'},
+ {at: 0.3, expect: '6px'},
+ {at: 0.6, expect: '12px'},
+ {at: 1, expect: '20px'},
+ {at: 1.5, expect: '30px'},
+]);
+
+test_interpolation({
+ property: 'border-left-width',
+ from: 'unset',
+ to: '23px',
+}, [
+ {at: -0.3, expect: '0px'},
+ {at: 0, expect: '3px'},
+ {at: 0.3, expect: '9px'},
+ {at: 0.6, expect: '15px'},
+ {at: 1, expect: '23px'},
+ {at: 1.5, expect: '33px'},
+]);
+
+test_interpolation({
+ property: 'border-left-width',
+ from: '0px',
+ to: '10px'
+}, [
+ {at: -0.3, expect: '0px'}, // CSS border-left-width can't be negative.
+ {at: 0, expect: '0px'},
+ {at: 0.3, expect: '3px'},
+ {at: 0.6, expect: '6px'},
+ {at: 1, expect: '10px'},
+ {at: 1.5, expect: '15px'}
+]);
+
+test_interpolation({
+ property: 'border-bottom-width',
+ from: 'thick',
+ to: '15px'
+}, [
+ {at: -2, expect: '0px'}, // CSS border-bottom-width can't be negative.
+ {at: -0.3, expect: '2px'},
+ {at: 0, expect: '5px'},
+ {at: 0.3, expect: '8px'},
+ {at: 0.6, expect: '11px'},
+ {at: 1, expect: '15px'},
+ {at: 1.5, expect: '20px'}
+]);
+
+test_interpolation({
+ property: 'border-left-width',
+ from: 'medium',
+ to: '13px'
+}, [
+ {at: -2, expect: '0px'}, // CSS border-left-width can't be negative.
+ {at: -0.25, expect: '0.5px'},
+ {at: 0, expect: '3px'},
+ {at: 0.3, expect: '6px'},
+ {at: 0.6, expect: '9px'},
+ {at: 1, expect: '13px'},
+ {at: 1.5, expect: '18px'}
+]);
+
+test_interpolation({
+ property: 'border-right-width',
+ from: 'thin',
+ to: '11px'
+}, [
+ {at: -2, expect: '0px'}, // CSS border-right-width can't be negative.
+ {at: -0.3, expect: '0px'}, // CSS border-right-width can't be negative.
+ {at: 0, expect: '1px'},
+ {at: 0.3, expect: '4px'},
+ {at: 0.6, expect: '7px'},
+ {at: 1, expect: '11px'},
+ {at: 1.5, expect: '16px'}
+]);
+
+test_interpolation({
+ property: 'border-top-width',
+ from: '15px',
+ to: 'thick'
+}, [
+ {at: -2, expect: '35px'},
+ {at: -0.3, expect: '18px'},
+ {at: 0, expect: '15px'},
+ {at: 0.3, expect: '12px'},
+ {at: 0.6, expect: '9px'},
+ {at: 1, expect: '5px'},
+ {at: 1.5, expect: '0px'}
+]);
+</script>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/box-shadow-composition.html b/testing/web-platform/tests/css/css-backgrounds/animations/box-shadow-composition.html
new file mode 100644
index 0000000000..7cc1ba2992
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/box-shadow-composition.html
@@ -0,0 +1,118 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>box-shadow composition</title>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#box-shadow">
+<meta name="test" content="box-shadow supports animation">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+<style>
+.target {
+ width: 40px;
+ height: 40px;
+ background-color: black;
+}
+.expected {
+ background-color: green;
+}
+</style>
+<body>
+<script>
+test_composition({
+ property: 'box-shadow',
+ replaceFrom: 'rgb(100, 100, 100) 10px 20px 30px 40px',
+ addTo: 'rgb(200, 200, 200) 20px 40px 60px 80px',
+}, [
+ {at: -0.3, expect: 'rgb(70, 70, 70 ) 7px 14px 21px 28px'},
+ {at: 0, expect: 'rgb(100, 100, 100) 10px 20px 30px 40px'},
+ {at: 0.5, expect: 'rgb(150, 150, 150) 15px 30px 45px 60px'},
+ {at: 1, expect: 'rgb(200, 200, 200) 20px 40px 60px 80px'},
+ {at: 1.5, expect: 'rgb(250, 250, 250) 25px 50px 75px 100px'},
+]);
+
+test_composition({
+ property: 'box-shadow',
+ underlying: 'rgb(10, 20, 30) 1px 2px 3px 4px',
+ addFrom: 'rgb(100, 100, 100) 10px 20px 30px 40px',
+ addTo: 'rgb(200, 200, 200) 20px 40px 60px 80px',
+}, [
+ {at: -0.3, expect: 'rgb(10, 20, 30) 1px 2px 3px 4px, rgb(70, 70, 70) 7px 14px 21px 28px'},
+ {at: 0, expect: 'rgb(10, 20, 30) 1px 2px 3px 4px, rgb(100, 100, 100) 10px 20px 30px 40px'},
+ {at: 0.5, expect: 'rgb(10, 20, 30) 1px 2px 3px 4px, rgb(150, 150, 150) 15px 30px 45px 60px'},
+ {at: 1, expect: 'rgb(10, 20, 30) 1px 2px 3px 4px, rgb(200, 200, 200) 20px 40px 60px 80px'},
+ {at: 1.5, expect: 'rgb(10, 20, 30) 1px 2px 3px 4px, rgb(250, 250, 250) 25px 50px 75px 100px'},
+]);
+test_composition({
+ property: 'box-shadow',
+ underlying: 'rgb(10, 20, 30) 1px 2px 3px 4px',
+ addFrom: 'rgb(100, 100, 100) 10px 20px 30px 40px inset',
+ addTo: 'rgb(200, 200, 200) 20px 40px 60px 80px inset',
+}, [
+ {at: -0.3, expect: 'rgb(10, 20, 30) 1px 2px 3px 4px, rgb(70, 70, 70) 7px 14px 21px 28px inset'},
+ {at: 0, expect: 'rgb(10, 20, 30) 1px 2px 3px 4px, rgb(100, 100, 100) 10px 20px 30px 40px inset'},
+ {at: 0.5, expect: 'rgb(10, 20, 30) 1px 2px 3px 4px, rgb(150, 150, 150) 15px 30px 45px 60px inset'},
+ {at: 1, expect: 'rgb(10, 20, 30) 1px 2px 3px 4px, rgb(200, 200, 200) 20px 40px 60px 80px inset'},
+ {at: 1.5, expect: 'rgb(10, 20, 30) 1px 2px 3px 4px, rgb(250, 250, 250) 25px 50px 75px 100px inset'},
+]);
+test_composition({
+ property: 'box-shadow',
+ underlying: 'rgb(10, 20, 30) 1px 2px 3px 4px, rgb(20, 40, 60) 2px 4px 6px 8px',
+ addFrom: 'rgb(100, 100, 100) 10px 20px 30px 40px',
+ addTo: 'rgb(200, 200, 200) 20px 40px 60px 80px',
+}, [
+ {at: -0.3, expect: 'rgb(10, 20, 30) 1px 2px 3px 4px, rgb(20, 40, 60) 2px 4px 6px 8px, rgb(70, 70, 70) 7px 14px 21px 28px'},
+ {at: 0, expect: 'rgb(10, 20, 30) 1px 2px 3px 4px, rgb(20, 40, 60) 2px 4px 6px 8px, rgb(100, 100, 100) 10px 20px 30px 40px'},
+ {at: 0.5, expect: 'rgb(10, 20, 30) 1px 2px 3px 4px, rgb(20, 40, 60) 2px 4px 6px 8px, rgb(150, 150, 150) 15px 30px 45px 60px'},
+ {at: 1, expect: 'rgb(10, 20, 30) 1px 2px 3px 4px, rgb(20, 40, 60) 2px 4px 6px 8px, rgb(200, 200, 200) 20px 40px 60px 80px'},
+ {at: 1.5, expect: 'rgb(10, 20, 30) 1px 2px 3px 4px, rgb(20, 40, 60) 2px 4px 6px 8px, rgb(250, 250, 250) 25px 50px 75px 100px'},
+]);
+test_composition({
+ property: 'box-shadow',
+ underlying: 'rgb(10, 20, 30) 1px 2px 3px 4px',
+ addFrom: 'rgb(100, 100, 100) 10px 20px 30px 40px, rgb(100, 100, 100) 10px 20px 30px 40px inset',
+ addTo: 'rgb(200, 200, 200) 20px 40px 60px 80px, rgb(200, 200, 200) 20px 40px 60px 80px inset',
+}, [
+ {at: -0.3, expect: 'rgb(10, 20, 30) 1px 2px 3px 4px, rgb(70, 70, 70) 7px 14px 21px 28px, rgb(70, 70, 70) 7px 14px 21px 28px inset'},
+ {at: 0, expect: 'rgb(10, 20, 30) 1px 2px 3px 4px, rgb(100, 100, 100) 10px 20px 30px 40px, rgb(100, 100, 100) 10px 20px 30px 40px inset'},
+ {at: 0.5, expect: 'rgb(10, 20, 30) 1px 2px 3px 4px, rgb(150, 150, 150) 15px 30px 45px 60px, rgb(150, 150, 150) 15px 30px 45px 60px inset'},
+ {at: 1, expect: 'rgb(10, 20, 30) 1px 2px 3px 4px, rgb(200, 200, 200) 20px 40px 60px 80px, rgb(200, 200, 200) 20px 40px 60px 80px inset'},
+ {at: 1.5, expect: 'rgb(10, 20, 30) 1px 2px 3px 4px, rgb(250, 250, 250) 25px 50px 75px 100px, rgb(250, 250, 250) 25px 50px 75px 100px inset'},
+]);
+test_composition({
+ property: 'box-shadow',
+ underlying: 'rgb(10, 20, 30) 1px 2px 3px 4px, rgb(20, 40, 60) 2px 4px 6px 8px',
+ addFrom: 'rgb(100, 100, 100) 10px 20px 30px 40px',
+ replaceTo: 'rgb(200, 200, 200) 20px 40px 60px 80px',
+}, [
+ {at: -0.3, expect: 'rgb(0, 0, 0) -4.7px -9.4px 0px -18.8px, rgb(26, 52, 78) 2.6px 5.2px 7.8px 10.4px, rgb(130, 130, 130) 13px 26px 39px 52px'},
+ {at: 0, expect: 'rgb(10, 20, 30) 1px 2px 3px 4px, rgb(20, 40, 60) 2px 4px 6px 8px, rgb(100, 100, 100) 10px 20px 30px 40px'},
+ {at: 0.5, expect: 'rgb(105, 110, 115) 10.5px 21px 31.5px 42px, rgba(20, 40, 60, 0.5) 1px 2px 3px 4px, rgba(100, 100, 100, 0.5) 5px 10px 15px 20px'},
+ {at: 1, expect: 'rgb(200, 200, 200) 20px 40px 60px 80px, rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px'},
+ {at: 1.5, expect: 'rgb(255, 255, 255) 29.5px 59px 88.5px 118px, rgba(0, 0, 0, 0) -1px -2px 0px -4px, rgba(0, 0, 0, 0) -5px -10px 0px -20px'},
+]);
+test_composition({
+ property: 'box-shadow',
+ underlying: 'rgb(10, 20, 30) 1px 2px 3px 4px, rgb(20, 40, 60) 2px 4px 6px 8px',
+ replaceFrom: 'rgb(100, 100, 100) 10px 20px 30px 40px',
+ addTo: 'rgb(200, 200, 200) 20px 40px 60px 80px',
+}, [
+ {at: -0.3, expect: 'rgb(127, 124, 121) 12.7px 25.4px 38.1px 50.8px, rgba(0, 0, 0, 0) -0.6px -1.2px 0px -2.4px, rgba(0, 0, 0, 0) -6px -12px 0px -24px'},
+ {at: 0, expect: 'rgb(100, 100, 100) 10px 20px 30px 40px, rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px'},
+ {at: 0.5, expect: 'rgb(55, 60, 65) 5.5px 11px 16.5px 22px, rgba(20, 40, 60, 0.5) 1px 2px 3px 4px, rgba(200, 200, 200, 0.5) 10px 20px 30px 40px'},
+ {at: 1, expect: 'rgb(10, 20, 30) 1px 2px 3px 4px, rgb(20, 40, 60) 2px 4px 6px 8px, rgb(200, 200, 200) 20px 40px 60px 80px'},
+ {at: 1.5, expect: 'rgb(0, 0, 0) -3.5px -7px 0px -14px, rgb(30, 60, 90) 3px 6px 9px 12px, rgb(255, 255, 255) 30px 60px 90px 120px'},
+]);
+test_composition({
+ property: 'box-shadow',
+ underlying: 'rgb(10, 20, 30) 1px 2px 3px 4px, rgb(20, 40, 60) 2px 4px 6px 8px, rgb(40, 80, 120) 4px 8px 12px 16px',
+ addFrom: 'rgb(100, 100, 100) 10px 20px 30px 40px, rgb(200, 200, 200) 20px 40px 60px 80px',
+ replaceTo: 'rgb(200, 200, 200) 20px 40px 60px 80px',
+}, [
+ {at: -0.3, expect: 'rgb(0, 0, 0) -4.7px -9.4px 0px -18.8px, rgb(26, 52, 78) 2.6px 5.2px 7.8px 10.4px, rgb(52, 104, 156) 5.2px 10.4px 15.6px 20.8px, rgb(130, 130, 130) 13px 26px 39px 52px, rgb(255, 255, 255) 26px 52px 78px 104px'},
+ {at: 0, expect: 'rgb(10, 20, 30) 1px 2px 3px 4px, rgb(20, 40, 60) 2px 4px 6px 8px, rgb(40, 80, 120) 4px 8px 12px 16px, rgb(100, 100, 100) 10px 20px 30px 40px, rgb(200, 200, 200) 20px 40px 60px 80px'},
+ {at: 0.5, expect: 'rgb(105, 110, 115) 10.5px 21px 31.5px 42px, rgba(20, 40, 60, 0.5) 1px 2px 3px 4px, rgba(40, 80, 120, 0.5) 2px 4px 6px 8px, rgba(100, 100, 100, 0.5) 5px 10px 15px 20px, rgba(200, 200, 200, 0.5) 10px 20px 30px 40px'},
+ {at: 1, expect: 'rgb(200, 200, 200) 20px 40px 60px 80px, rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px'},
+ {at: 1.5, expect: 'rgb(255, 255, 255) 29.5px 59px 88.5px 118px, rgba(0, 0, 0, 0) -1px -2px 0px -4px, rgba(0, 0, 0, 0) -2px -4px 0px -8px, rgba(0, 0, 0, 0) -5px -10px 0px -20px, rgba(0, 0, 0, 0) -10px -20px 0px -40px'},
+]);
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/box-shadow-interpolation.html b/testing/web-platform/tests/css/css-backgrounds/animations/box-shadow-interpolation.html
new file mode 100644
index 0000000000..4ed55abc9e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/box-shadow-interpolation.html
@@ -0,0 +1,198 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#box-shadow">
+<meta name="test" content="box-shadow supports animation">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.parent {
+ box-shadow: 30px 10px 30px 10px black;
+}
+.target {
+ display: inline-block;
+ width: 60px;
+ height: 60px;
+ font-size: 3px;
+ border: 2px solid;
+ margin-right: 20px;
+ margin-bottom: 30px;
+ color: green;
+ box-shadow: 10px 30px 10px 30px black;
+}
+.expected {
+ margin-right: 40px;
+}
+</style>
+<body>
+<script>
+test_interpolation({
+ property: 'box-shadow',
+ from: neutralKeyframe,
+ to: '20px 20px 20px 20px black',
+}, [
+ {at: -0.3, expect: 'rgb(0, 0, 0) 7px 33px 7px 33px'},
+ {at: 0, expect: 'rgb(0, 0, 0) 10px 30px 10px 30px'},
+ {at: 0.3, expect: 'rgb(0, 0, 0) 13px 27px 13px 27px'},
+ {at: 0.6, expect: 'rgb(0, 0, 0) 16px 24px 16px 24px'},
+ {at: 1, expect: 'rgb(0, 0, 0) 20px 20px 20px 20px'},
+ {at: 1.5, expect: 'rgb(0, 0, 0) 25px 15px 25px 15px'},
+]);
+
+test_interpolation({
+ property: 'box-shadow',
+ from: 'initial',
+ to: '20px 20px 20px 20px black',
+}, [
+ {at: -0.3, expect: 'rgba(0, 0, 0, 0) -6px -6px 0px -6px'},
+ {at: 0, expect: 'rgba(0, 0, 0, 0) 0px 0px 0px 0px'},
+ {at: 0.3, expect: 'rgba(0, 0, 0, 0.3) 6px 6px 6px 6px'},
+ {at: 0.6, expect: 'rgba(0, 0, 0, 0.6) 12px 12px 12px 12px'},
+ {at: 1, expect: 'rgb(0, 0, 0) 20px 20px 20px 20px'},
+ {at: 1.5, expect: 'rgb(0, 0, 0) 30px 30px 30px 30px'},
+]);
+
+test_interpolation({
+ property: 'box-shadow',
+ from: 'inherit',
+ to: '20px 20px 20px 20px black',
+}, [
+ {at: -0.3, expect: 'rgb(0, 0, 0) 33px 7px 33px 7px'},
+ {at: 0, expect: 'rgb(0, 0, 0) 30px 10px 30px 10px'},
+ {at: 0.3, expect: 'rgb(0, 0, 0) 27px 13px 27px 13px'},
+ {at: 0.6, expect: 'rgb(0, 0, 0) 24px 16px 24px 16px'},
+ {at: 1, expect: 'rgb(0, 0, 0) 20px 20px 20px 20px'},
+ {at: 1.5, expect: 'rgb(0, 0, 0) 15px 25px 15px 25px'},
+]);
+
+test_interpolation({
+ property: 'box-shadow',
+ from: 'unset',
+ to: '20px 20px 20px 20px black',
+}, [
+ {at: -0.3, expect: 'rgba(0, 0, 0, 0) -6px -6px 0px -6px'},
+ {at: 0, expect: 'rgba(0, 0, 0, 0) 0px 0px 0px 0px'},
+ {at: 0.3, expect: 'rgba(0, 0, 0, 0.3) 6px 6px 6px 6px'},
+ {at: 0.6, expect: 'rgba(0, 0, 0, 0.6) 12px 12px 12px 12px'},
+ {at: 1, expect: 'rgb(0, 0, 0) 20px 20px 20px 20px'},
+ {at: 1.5, expect: 'rgb(0, 0, 0) 30px 30px 30px 30px'},
+]);
+
+// Test basic functionality, and clipping blur at 0
+test_interpolation({
+ property: 'box-shadow',
+ from: '15px 10px 5px 6px black',
+ to: '-15px -10px 25px -4px orange',
+}, [
+ {at: -0.3, expect: 'rgb(0, 0, 0) 24px 16px 0px 9px'},
+ {at: 0, expect: 'rgb(0, 0, 0) 15px 10px 5px 6px'},
+ {at: 0.3, expect: 'rgb(77, 50, 0) 6px 4px 11px 3px'},
+ {at: 0.6, expect: 'rgb(153, 99, 0) -3px -2px 17px 0px'},
+ {at: 1, expect: 'rgb(255, 165, 0) -15px -10px 25px -4px'},
+ {at: 1.5, expect: 'rgb(255, 248, 0) -30px -20px 35px -9px'},
+]);
+
+test_interpolation({
+ property: 'box-shadow',
+ from: '0px 0px 0px 0px black',
+ to: '1px 1px 1px 1px black',
+}, [
+ {at: -0.3, expect: 'rgb(0, 0, 0) -0.3px -0.3px 0px -0.3px'},
+ {at: 0, expect: 'rgb(0, 0, 0) 0px 0px 0px 0px'},
+ {at: 0.3, expect: 'rgb(0, 0, 0) 0.3px 0.3px 0.3px 0.3px'},
+ {at: 0.6, expect: 'rgb(0, 0, 0) 0.6px 0.6px 0.6px 0.6px'},
+ {at: 1, expect: 'rgb(0, 0, 0) 1px 1px 1px 1px'},
+ {at: 1.5, expect: 'rgb(0, 0, 0) 1.5px 1.5px 1.5px 1.5px'},
+]);
+
+// Test with color as first value.
+test_interpolation({
+ property: 'box-shadow',
+ from: 'black 15px 10px 5px 6px',
+ to: 'orange -15px -10px 25px -4px',
+}, [
+ {at: -0.3, expect: 'rgb(0, 0, 0) 24px 16px 0px 9px'},
+ {at: 0, expect: 'rgb(0, 0, 0) 15px 10px 5px 6px'},
+ {at: 0.3, expect: 'rgb(77, 50, 0) 6px 4px 11px 3px'},
+ {at: 0.6, expect: 'rgb(153, 99, 0) -3px -2px 17px 0px'},
+ {at: 1, expect: 'rgb(255, 165, 0) -15px -10px 25px -4px'},
+ {at: 1.5, expect: 'rgb(255, 248, 0) -30px -20px 35px -9px'},
+]);
+
+test_interpolation({
+ property: 'box-shadow',
+ from: '15px 10px 5px 6px black inset',
+ to: '-15px -10px 25px -4px orange inset',
+}, [
+ {at: -0.3, expect: 'rgb(0, 0, 0) 24px 16px 0px 9px inset'},
+ {at: 0, expect: 'rgb(0, 0, 0) 15px 10px 5px 6px inset'},
+ {at: 0.3, expect: 'rgb(77, 50, 0) 6px 4px 11px 3px inset'},
+ {at: 0.6, expect: 'rgb(153, 99, 0) -3px -2px 17px 0px inset'},
+ {at: 1, expect: 'rgb(255, 165, 0) -15px -10px 25px -4px inset'},
+ {at: 1.5, expect: 'rgb(255, 248, 0) -30px -20px 35px -9px inset'},
+]);
+
+test_interpolation({
+ property: 'box-shadow',
+ from: '15px 10px 5px 6px black',
+ to: '-15px -10px 25px -4px',
+}, [
+ {at: -0.3, expect: 'rgb(0, 0, 0) 24px 16px 0px 9px'},
+ {at: 0, expect: 'rgb(0, 0, 0) 15px 10px 5px 6px'},
+ {at: 0.3, expect: 'rgb(0, 38, 0) 6px 4px 11px 3px'},
+ {at: 0.6, expect: 'rgb(0, 77, 0) -3px -2px 17px 0px'},
+ {at: 1, expect: 'rgb(0, 128, 0) -15px -10px 25px -4px'},
+ {at: 1.5, expect: 'rgb(0, 192, 0) -30px -20px 35px -9px'},
+]);
+
+test_interpolation({
+ property: 'box-shadow',
+ from: '10px 10px 10px 10px black',
+ to: '10px 10px 10px 10px currentColor',
+}, [
+ {at: -0.3, expect: 'rgb(0, 0, 0) 10px 10px 10px 10px'},
+ {at: 0, expect: 'rgb(0, 0, 0) 10px 10px 10px 10px'},
+ {at: 0.3, expect: 'rgb(0, 38, 0) 10px 10px 10px 10px'},
+ {at: 0.6, expect: 'rgb(0, 77, 0) 10px 10px 10px 10px'},
+ {at: 1, expect: 'rgb(0, 128, 0) 10px 10px 10px 10px'},
+ {at: 1.5, expect: 'rgb(0, 192, 0) 10px 10px 10px 10px'},
+]);
+
+// Test padding shorter lists
+test_interpolation({
+ property: 'box-shadow',
+ from: '10px 20px rgba(255, 255, 0, 0.5), inset 5px 10em #008000',
+ to: 'none',
+}, [
+ {at: -0.3, expect: 'rgba(255, 255, 0, 0.65) 13px 26px 0px 0px, rgb(0, 166, 0) 6.5px 39px 0px 0px inset'},
+ {at: 0, expect: 'rgba(255, 255, 0, 0.5) 10px 20px 0px 0px, rgb(0, 128, 0) 5px 30px 0px 0px inset'},
+ {at: 0.3, expect: 'rgba(255, 255, 0, 0.353) 7px 14px 0px 0px, rgba(0, 128, 0, 0.7) 3.5px 21px 0px 0px inset'},
+ {at: 0.6, expect: 'rgba(255, 255, 0, 0.2) 4px 8px 0px 0px, rgba(0, 128, 0, 0.4) 2px 12px 0px 0px inset'},
+ {at: 1, expect: 'rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px inset'},
+ {at: 1.5, expect: 'rgba(0, 0, 0, 0) -5px -10px 0px 0px, rgba(0, 0, 0, 0) -2.5px -15px 0px 0px inset'},
+]);
+
+// Test calc with comparison functions
+test_interpolation({
+ property: 'box-shadow',
+ from: 'inset 0 0 0 0 black',
+ to: 'inset 0 0 0 calc(max(10em, 20px) / 2) black',
+}, [
+ {at: -0.3, expect: 'rgb(0, 0, 0) 0px 0px 0px -4.5px inset'},
+ {at: 0, expect: 'rgb(0, 0, 0) 0px 0px 0px 0px inset'},
+ {at: 0.3, expect: 'rgb(0, 0, 0) 0px 0px 0px 4.5px inset'},
+ {at: 0.6, expect: 'rgb(0, 0, 0) 0px 0px 0px 9px inset'},
+ {at: 1, expect: 'rgb(0, 0, 0) 0px 0px 0px 15px inset'},
+ {at: 1.5, expect: 'rgb(0, 0, 0) 0px 0px 0px 22.5px inset'},
+]);
+
+// Test unmatched inset
+test_no_interpolation({
+ property: 'box-shadow',
+ from: '10px 20px yellow, 5px 10px green',
+ to: 'inset 5px 10px green, 15px 20px blue'
+});
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/invalidation/background-color-animation-with-zero-alpha-ref.html b/testing/web-platform/tests/css/css-backgrounds/animations/invalidation/background-color-animation-with-zero-alpha-ref.html
new file mode 100644
index 0000000000..8442d3de96
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/invalidation/background-color-animation-with-zero-alpha-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<style>
+.box {
+ width: 100px;
+ height: 100px;
+ background-color: rgba(100, 100, 0, 0);
+}
+</style>
+<body>
+ <div class='box'></div>
+</body>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/invalidation/background-color-animation-with-zero-alpha.html b/testing/web-platform/tests/css/css-backgrounds/animations/invalidation/background-color-animation-with-zero-alpha.html
new file mode 100644
index 0000000000..c282898287
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/invalidation/background-color-animation-with-zero-alpha.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="background-color-animation-with-zero-alpha-ref.html">
+<style>
+.container {
+ width: 100px;
+ height: 100px;
+ /* Use a long animation that start at 50% progress where the slope of the
+ selected timing function is zero. By setting up the animation in this way,
+ we accommodate lengthy delays in running the test without a potential drift
+ in the animated property value. This is important for avoiding flakes,
+ especially on debug builds. The screenshots are taken as soon as the
+ animation is ready, thus the long animation duration has no bearing on
+ the actual duration of the test. */
+ animation: bgcolor 1000000s cubic-bezier(0,1,1,0) -500000s;
+}
+@keyframes bgcolor {
+ 0% { background-color: rgb(0, 200, 0, 0); }
+ 100% { background-color: rgb(200, 0, 0, 0); }
+}
+</style>
+<body>
+<div class="container"></div>
+</body>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/invalidation/background-color-transition-obscured-ref.html b/testing/web-platform/tests/css/css-backgrounds/animations/invalidation/background-color-transition-obscured-ref.html
new file mode 100644
index 0000000000..d615522c84
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/invalidation/background-color-transition-obscured-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<style>
+.parent {
+ width: 100px;
+ height: 100px;
+ background-color: rgb(100, 100, 0);
+}
+.container {
+ width: 100px;
+ height: 100px;
+ background-color: rgb(100, 0, 100);
+}
+</style>
+<body>
+ <div class='parent'>
+ <div class='container'></div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/invalidation/background-color-transition-obscured.html b/testing/web-platform/tests/css/css-backgrounds/animations/invalidation/background-color-transition-obscured.html
new file mode 100644
index 0000000000..9f8c2fc9c4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/invalidation/background-color-transition-obscured.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="background-color-transition-obscured-ref.html">
+<style>
+.parent {
+ width: 100px;
+ height: 100px;
+ background-color: rgb(0, 200, 0);
+ transition: background-color 200000ms steps(2) -99999.9ms;
+}
+.container {
+ width: 100px;
+ height: 100px;
+ background-color: rgb(0, 0, 200);
+ transition: background-color 200000ms steps(2) -99999.9ms;
+}
+</style>
+<script src="/common/reftest-wait.js"></script>
+<body>
+<div class="parent" id="pa">
+ <div class="container" id="target"></div>
+</div>
+
+<script>
+function startTransition() {
+ requestAnimationFrame(() => {
+ document.getElementById('target').style.backgroundColor = "rgb(200, 0, 0)";
+ document.getElementById('pa').style.backgroundColor = "rgb(200, 0, 0)";
+ const animations = document.getAnimations();
+ Promise.all([animations[0].ready, animations[1].ready]).then(() => {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ takeScreenshot();
+ });
+ });
+ });
+ });
+}
+
+requestAnimationFrame(startTransition);
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/invalidation/background-color-transition-with-delay-ref.html b/testing/web-platform/tests/css/css-backgrounds/animations/invalidation/background-color-transition-with-delay-ref.html
new file mode 100644
index 0000000000..8e0e70ba20
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/invalidation/background-color-transition-with-delay-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<body>
+ <canvas id="canvas" width="100" height="100"></canvas>
+</body>
+<script>
+ var canvas = document.getElementById('canvas');
+ var ctx = canvas.getContext('2d');
+ ctx.fillStyle = 'rgb(100, 100, 0)';
+ ctx.fillRect(0, 0, 100, 100);
+</script>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/invalidation/background-color-transition-with-delay.html b/testing/web-platform/tests/css/css-backgrounds/animations/invalidation/background-color-transition-with-delay.html
new file mode 100644
index 0000000000..bf7d8fb63a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/invalidation/background-color-transition-with-delay.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="background-color-transition-with-delay-ref.html">
+<style>
+.container {
+ width: 100px;
+ height: 100px;
+ background-color: rgb(0, 200, 0);
+ transition: background-color 200000ms steps(2) -99999.9ms;
+}
+</style>
+<script src="/common/reftest-wait.js"></script>
+<body>
+<div class="container" id="target"></div>
+
+<script>
+// This test differs from "background-color-transition.html" because it runs the
+// transition starting from the set background color, rather than using a
+// delay to start in the middle of the transition. This tests a new codepath
+// where the first frame of the transition has the original background color,
+// which is why we need the transition fully running. Since we are using the
+// step(2) in the animation, so it is enough to wait for two frames and the
+// animation should be in its mid-point, that's the time we should take
+// screenshot.
+function startTransition() {
+ requestAnimationFrame(() => {
+ document.getElementById('target').style.backgroundColor = "rgb(200, 0, 0)";
+ document.getAnimations()[0].ready.then(() => {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ takeScreenshot();
+ });
+ });
+ });
+ });
+}
+
+requestAnimationFrame(startTransition);
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/invalidation/background-color-transition-with-initially-transparent-ref.html b/testing/web-platform/tests/css/css-backgrounds/animations/invalidation/background-color-transition-with-initially-transparent-ref.html
new file mode 100644
index 0000000000..10475b7bb1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/invalidation/background-color-transition-with-initially-transparent-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<style>
+.box {
+ width: 100px;
+ height: 100px;
+ background-color: rgba(200, 0, 0, 0.4);
+}
+</style>
+<body>
+ <div class='box'></div>
+</body>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/invalidation/background-color-transition-with-initially-transparent.html b/testing/web-platform/tests/css/css-backgrounds/animations/invalidation/background-color-transition-with-initially-transparent.html
new file mode 100644
index 0000000000..bd75226601
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/invalidation/background-color-transition-with-initially-transparent.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="background-color-transition-with-initially-transparent-ref.html">
+<style>
+.container {
+ width: 100px;
+ height: 100px;
+ transition: background-color 200000ms steps(2) -99999.9ms;
+}
+</style>
+<script src="/common/reftest-wait.js"></script>
+<body>
+<div class="container" id="target"></div>
+
+<script>
+function startTransition() {
+ requestAnimationFrame(() => {
+ document.getElementById('target').style.backgroundColor = "rgb(200, 0, 0, 0.8)";
+ document.getAnimations()[0].ready.then(() => {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ takeScreenshot();
+ });
+ });
+ });
+ });
+}
+
+requestAnimationFrame(startTransition);
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/two-background-color-animation-diff-length1-ref.html b/testing/web-platform/tests/css/css-backgrounds/animations/two-background-color-animation-diff-length1-ref.html
new file mode 100644
index 0000000000..44e416fe8f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/two-background-color-animation-diff-length1-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<body>
+ <canvas id="canvas" width="100" height="100"></canvas>
+</body>
+<script>
+ var canvas = document.getElementById('canvas');
+ var ctx = canvas.getContext('2d');
+ ctx.fillStyle = 'rgb(0, 0, 199)';
+ ctx.fillRect(0, 0, 100, 100);
+</script>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/two-background-color-animation-diff-length1.html b/testing/web-platform/tests/css/css-backgrounds/animations/two-background-color-animation-diff-length1.html
new file mode 100644
index 0000000000..b584ed835c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/two-background-color-animation-diff-length1.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="two-background-color-animation-diff-length1-ref.html">
+<style>
+.container {
+ width: 100px;
+ height: 100px;
+ background-color: green;
+ animation: bgcolor2 10s, bgcolor1 0.001s;
+}
+@keyframes bgcolor1 {
+ 0% { background-color: rgb(0, 200, 0); }
+ 100% { background-color: rgb(200, 0, 0); }
+}
+@keyframes bgcolor2 {
+ 0% { background-color: rgb(0, 0, 199); }
+ 100% { background-color: rgb(0, 0, 200); }
+}
+</style>
+<script src="/common/reftest-wait.js"></script>
+<script src="../../../web-animations/testcommon.js"></script>
+<body>
+<div class="container"></div>
+
+<script>
+// This test ensures that if we have two different-length animation, when the
+// one with higher compositing order finishes, the other one would still run
+// normally.
+const animations = document.getAnimations();
+Promise.all([animations[0].ready, animations[1].ready]).then(() => {
+ waitForAnimationFrames(3).then(() => {
+ takeScreenshot();
+ });
+});
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/two-background-color-animation-diff-length2-ref.html b/testing/web-platform/tests/css/css-backgrounds/animations/two-background-color-animation-diff-length2-ref.html
new file mode 100644
index 0000000000..44e416fe8f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/two-background-color-animation-diff-length2-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<body>
+ <canvas id="canvas" width="100" height="100"></canvas>
+</body>
+<script>
+ var canvas = document.getElementById('canvas');
+ var ctx = canvas.getContext('2d');
+ ctx.fillStyle = 'rgb(0, 0, 199)';
+ ctx.fillRect(0, 0, 100, 100);
+</script>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/two-background-color-animation-diff-length2.html b/testing/web-platform/tests/css/css-backgrounds/animations/two-background-color-animation-diff-length2.html
new file mode 100644
index 0000000000..c6822dec4c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/two-background-color-animation-diff-length2.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="two-background-color-animation-diff-length2-ref.html">
+<style>
+.container {
+ width: 100px;
+ height: 100px;
+ background-color: green;
+ animation: bgcolor2 10s, bgcolor1 2s 1s;
+}
+@keyframes bgcolor1 {
+ 0% { background-color: rgb(0, 200, 0); }
+ 100% { background-color: rgb(200, 0, 0); }
+}
+@keyframes bgcolor2 {
+ 0% { background-color: rgb(0, 0, 199); }
+ 100% { background-color: rgb(0, 0, 200); }
+}
+</style>
+<script src="/common/reftest-wait.js"></script>
+<script src="../../../web-animations/testcommon.js"></script>
+<body>
+<div class="container"></div>
+
+<script>
+// This test ensures that when there are two animations where one of them has
+// animation delays, we show the right color when the delayed animation is not
+// started yet.
+const animations = document.getAnimations();
+Promise.all([animations[0].ready, animations[1].ready]).then(() => {
+ takeScreenshot();
+});
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/two-background-color-animation-diff-length3-ref.html b/testing/web-platform/tests/css/css-backgrounds/animations/two-background-color-animation-diff-length3-ref.html
new file mode 100644
index 0000000000..66af34da3d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/two-background-color-animation-diff-length3-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<body>
+ <canvas id="canvas" width="100" height="100"></canvas>
+</body>
+<script>
+ var canvas = document.getElementById('canvas');
+ var ctx = canvas.getContext('2d');
+ ctx.fillStyle = 'rgb(0, 199, 0)';
+ ctx.fillRect(0, 0, 100, 100);
+</script>
diff --git a/testing/web-platform/tests/css/css-backgrounds/animations/two-background-color-animation-diff-length3.html b/testing/web-platform/tests/css/css-backgrounds/animations/two-background-color-animation-diff-length3.html
new file mode 100644
index 0000000000..e12d8a7fd2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-backgrounds/animations/two-background-color-animation-diff-length3.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
+<link rel="match" href="two-background-color-animation-diff-length3-ref.html">
+<style>
+.container {
+ width: 100px;
+ height: 100px;
+ background-color: green;
+ animation: bgcolor2 200s, bgcolor1 100s 0.001s;
+}
+@keyframes bgcolor1 {
+ 0% { background-color: rgb(0, 199, 0); }
+ 100% { background-color: rgb(0, 200, 0); }
+}
+@keyframes bgcolor2 {
+ 0% { background-color: rgb(0, 0, 199); }
+ 100% { background-color: rgb(0, 0, 200); }
+}
+</style>
+<script src="/common/reftest-wait.js"></script>
+<script src="../../../web-animations/testcommon.js"></script>
+<body>
+<div class="container"></div>
+
+<script>
+// This test ensures that when there are two animations where one of them has
+// animation delays, we show the right color when the delayed animation is
+// started.
+const animations = document.getAnimations();
+Promise.all([animations[0].ready, animations[1].ready]).then(() => {
+ waitForAnimationFrames(3).then(() => {
+ takeScreenshot();
+ });
+});
+</script>
+</body>
+</html>