Skip to content

Commit 7a80152

Browse files
noamrchromium-wpt-export-bot
authored andcommitted
Don't reset animations/transitions on moveBefore
See whatwg/dom#1255 Animations & transitions should attempt to continue from where they left off, if possible. This is done in the following way: - Animations are not cancelled on removal when in a state-preserving atomic move. - We don't reset the computed style when removing the element in preparation for an atomic move. - We don't clear the layout/style flags, so that the layout is recomputed and reattached on the next style recalc. Bug: 40150299 Change-Id: I559e69e75df14df589485cb024da0f0f28b1e1ec Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5458120 Commit-Queue: Noam Rosenthal <[email protected]> Reviewed-by: Rune Lillesveen <[email protected]> Cr-Commit-Position: refs/heads/main@{#1291811}
1 parent d064974 commit 7a80152

6 files changed

+264
-0
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<!DOCTYPE html>
2+
<title>Node.moveBefore should preserve CSS animation state (left)</title>
3+
<script src="/resources/testharness.js"></script>
4+
<script src="/resources/testharnessreport.js"></script>
5+
<body>
6+
<section id="old-parent">
7+
<div id="item"></div>
8+
</section>
9+
<section id="new-parent">
10+
</section>
11+
<style>
12+
@keyframes anim {
13+
from {
14+
left: 100px;
15+
}
16+
17+
to {
18+
left: 400px;
19+
}
20+
}
21+
22+
section {
23+
position: absolute;
24+
}
25+
26+
#item {
27+
position: relative;
28+
width: 100px;
29+
height: 100px;
30+
background: green;
31+
animation: 1s linear infinite alternate anim;
32+
animation-delay: 100ms;
33+
}
34+
</style>
35+
<script>
36+
promise_test(async t => {
37+
const item = document.querySelector("#item");
38+
let num_events = 0;
39+
await new Promise(resolve => addEventListener("animationstart", () => {
40+
num_events++;
41+
resolve();
42+
}));
43+
44+
// Reparent item
45+
document.body.querySelector("#new-parent").moveBefore(item, null);
46+
await new Promise(resolve => requestAnimationFrame(() => resolve()));
47+
assert_equals(num_events, 1);
48+
assert_not_equals(getComputedStyle(item).left, "0px");
49+
});
50+
</script>
51+
</body>
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<!DOCTYPE html>
2+
<title>Node.moveBefore should preserve CSS animation state (transform)</title>
3+
<script src="/resources/testharness.js"></script>
4+
<script src="/resources/testharnessreport.js"></script>
5+
6+
<body>
7+
<section id="old-parent">
8+
<div id="item"></div>
9+
</section>
10+
<section id="new-parent">
11+
</section>
12+
<style>
13+
@keyframes anim {
14+
from {
15+
transform: translateX(100px);
16+
}
17+
18+
to {
19+
transform: translateX(400px);
20+
}
21+
}
22+
23+
#item {
24+
position: relative;
25+
width: 100px;
26+
height: 100px;
27+
background: green;
28+
animation: 1s linear infinite alternate anim;
29+
animation-delay: 100ms;
30+
}
31+
</style>
32+
<script>
33+
promise_test(async t => {
34+
const item = document.querySelector("#item");
35+
let num_events = 0;
36+
await new Promise(resolve => addEventListener("animationstart", () => {
37+
num_events++;
38+
resolve();
39+
}));
40+
41+
// Reparent item
42+
document.body.querySelector("#new-parent").moveBefore(item, null);
43+
await new Promise(resolve => requestAnimationFrame(() => resolve()));
44+
assert_equals(num_events, 1);
45+
assert_not_equals(getComputedStyle(item).transform, "none");
46+
});
47+
</script>
48+
</body>
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<!DOCTYPE html>
2+
<title>Node.moveBefore should preserve CSS transition state (left)</title>
3+
<script src="/resources/testharness.js"></script>
4+
<script src="/resources/testharnessreport.js"></script>
5+
6+
<body>
7+
<section id="old-parent">
8+
<div id="item"></div>
9+
</section>
10+
<section id="new-parent">
11+
</section>
12+
<style>
13+
#item {
14+
width: 100px;
15+
height: 100px;
16+
background: green;
17+
transition: left 10s;
18+
position: absolute;
19+
left: 0;
20+
}
21+
22+
section {
23+
position: relative;
24+
}
25+
26+
body {
27+
margin-left: 0;
28+
}
29+
</style>
30+
<script>
31+
promise_test(async t => {
32+
const item = document.querySelector("#item");
33+
assert_equals(item.getBoundingClientRect().x, 0);
34+
item.style.left = "400px";
35+
await new Promise(resolve => item.addEventListener("transitionstart", resolve));
36+
document.querySelector("#new-parent").moveBefore(item, null);
37+
await new Promise(resolve => requestAnimationFrame(() => resolve()));
38+
assert_less_than(item.getBoundingClientRect().x, 399);
39+
});
40+
</script>
41+
</body>
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<!DOCTYPE html>
2+
<title>Node.moveBefore should preserve CSS transition state (transform)</title>
3+
<script src="/resources/testharness.js"></script>
4+
<script src="/resources/testharnessreport.js"></script>
5+
6+
<body>
7+
<section id="old-parent">
8+
<div id="item"></div>
9+
</section>
10+
<section id="new-parent">
11+
</section>
12+
<style>
13+
#item {
14+
width: 100px;
15+
height: 100px;
16+
background: green;
17+
transition: transform 60s steps(1, jump-both);
18+
}
19+
20+
body {
21+
margin-left: 0;
22+
}
23+
</style>
24+
<script>
25+
promise_test(async t => {
26+
const item = document.querySelector("#item");
27+
assert_equals(item.getBoundingClientRect().x, 0);
28+
item.style.transform = "translateX(400px)";
29+
await new Promise(resolve => item.addEventListener("transitionstart", resolve));
30+
document.querySelector("#new-parent").moveBefore(item, null);
31+
await new Promise(resolve => requestAnimationFrame(() => resolve()));
32+
assert_equals(item.getBoundingClientRect().x, 200);
33+
assert_equals(item.getAnimations().length, 1);
34+
});
35+
</script>
36+
</body>
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<!DOCTYPE html>
2+
<title>Calling commitStyles after Node.moveBefore should commit mid-transition value</title>
3+
<script src="/resources/testharness.js"></script>
4+
<script src="/resources/testharnessreport.js"></script>
5+
6+
<body>
7+
<section id="old-parent">
8+
<div id="item"></div>
9+
</section>
10+
<section id="new-parent">
11+
</section>
12+
<style>
13+
@keyframes anim {
14+
from {
15+
transform: translateX(100px);
16+
}
17+
18+
to {
19+
transform: translateX(400px);
20+
}
21+
}
22+
23+
#item {
24+
position: relative;
25+
width: 100px;
26+
height: 100px;
27+
background: green;
28+
animation: 1s linear infinite alternate anim;
29+
animation-delay: 100ms;
30+
}
31+
</style>
32+
<script>
33+
promise_test(async t => {
34+
const item = document.querySelector("#item");
35+
await new Promise(resolve => item.addEventListener("animationstart", resolve));
36+
37+
// Reparent item
38+
document.body.querySelector("#new-parent").moveBefore(item, null);
39+
40+
item.getAnimations()[0].commitStyles();
41+
assert_true("transform" in item.style);
42+
assert_not_equals(item.style.transform, "none");
43+
});
44+
</script>
45+
</body>
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<!DOCTYPE html>
2+
<title>Node.moveBefore should trigger CSS transition state (left) if needed</title>
3+
<script src="/resources/testharness.js"></script>
4+
<script src="/resources/testharnessreport.js"></script>
5+
6+
<body>
7+
<section id="old-parent">
8+
<div id="item"></div>
9+
</section>
10+
<section id="new-parent">
11+
</section>
12+
<style>
13+
#item {
14+
width: 100px;
15+
height: 100px;
16+
background: green;
17+
transition: left 10s steps(1, jump-both);
18+
position: absolute;
19+
left: 0;
20+
}
21+
22+
#new-parent #item {
23+
left: 400px;
24+
}
25+
26+
section {
27+
position: relative;
28+
}
29+
30+
body {
31+
margin-left: 0;
32+
}
33+
</style>
34+
<script>
35+
promise_test(async t => {
36+
const item = document.querySelector("#item");
37+
assert_equals(item.getBoundingClientRect().x, 0);
38+
document.querySelector("#new-parent").moveBefore(item, null);
39+
await new Promise(resolve => item.addEventListener("transitionstart", resolve));
40+
assert_equals(item.getBoundingClientRect().x, 200);
41+
});
42+
</script>
43+
</body>

0 commit comments

Comments
 (0)