mirror of
https://github.com/servo/servo.git
synced 2025-08-11 08:25:32 +01:00
Auto merge of #26659 - mrobinson:events, r=jdm
Add support for remaining animation and transition events This PR adds support for remaining animation and transitions events. There are two commits here. The first is a bit more complicated: it reworks how rooting is done for animating nodes. Instead of having the `ScriptThread` try to track which animations are active via events (which can be inaccurate), it just maintains roots for nodes that are actually present in the animations- -related data structures. The second commit adds support for the new events. Unfortunately, the existing events tests either rely on the Web Animations API or other behavior (for example, that changing animation delay restarts an animation). Since those two things are out-of-scope for this change, I've forked some of the WPT tests, removed the reliance on the Web Animations API, and added them to Servo's internal tests. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes fix #21564. - [x] There are tests for these changes OR <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
This commit is contained in:
commit
93a6c37836
31 changed files with 763 additions and 399 deletions
|
@ -1,5 +0,0 @@
|
|||
[animationevent-types.html]
|
||||
expected: TIMEOUT
|
||||
[animationstart event is instanceof AnimationEvent]
|
||||
expected: TIMEOUT
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
[Element-getAnimations.tentative.html]
|
||||
bug: https://github.com/servo/servo/issues/21564
|
||||
bug: https://github.com/servo/servo/issues/26626
|
||||
[getAnimations for CSS Animations with animation-name: none]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[animationevent-pseudoelement.html]
|
||||
bug: https://github.com/servo/servo/issues/21564
|
||||
bug: https://github.com/servo/servo/issues/10316
|
||||
expected: TIMEOUT
|
||||
[AnimationEvent should have the correct pseudoElement memeber]
|
||||
expected: TIMEOUT
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
[animationevent-types.html]
|
||||
bug: https://github.com/servo/servo/issues/21564
|
||||
expected: TIMEOUT
|
||||
[animationstart event is instanceof AnimationEvent]
|
||||
expected: TIMEOUT
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
[events-006.html]
|
||||
bug: https://github.com/servo/servo/issues/21564
|
||||
bug: https://github.com/servo/servo/issues/10316
|
||||
expected: TIMEOUT
|
||||
[transition padding-left on ::after]
|
||||
expected: NOTRUN
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[variable-animation-from-to.html]
|
||||
bug: https://github.com/servo/servo/issues/21564
|
||||
bug: https://github.com/servo/servo/issues/26625
|
||||
expected: TIMEOUT
|
||||
[Verify CSS variable value before animation]
|
||||
expected: FAIL
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[variable-animation-over-transition.html]
|
||||
bug: https://github.com/servo/servo/issues/21564
|
||||
bug: https://github.com/servo/servo/issues/26625
|
||||
expected: TIMEOUT
|
||||
[Verify CSS variable value before animation]
|
||||
expected: FAIL
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
[variable-animation-substitute-into-keyframe-shorthand.html]
|
||||
bug: https://github.com/servo/servo/issues/21564
|
||||
bug: https://github.com/servo/servo/issues/26625
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[variable-animation-substitute-into-keyframe-transform.html]
|
||||
bug: https://github.com/servo/servo/issues/21564
|
||||
bug: https://github.com/servo/servo/issues/26625
|
||||
[Verify transform before animation]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
[variable-animation-substitute-into-keyframe.html]
|
||||
bug: https://github.com/servo/servo/issues/21564
|
||||
bug: https://github.com/servo/servo/issues/26625
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[variable-animation-substitute-within-keyframe-fallback.html]
|
||||
bug: https://github.com/servo/servo/issues/21564
|
||||
bug: https://github.com/servo/servo/issues/26625
|
||||
[Verify color after animation]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[variable-animation-substitute-within-keyframe-multiple.html]
|
||||
bug: https://github.com/servo/servo/issues/21564
|
||||
bug: https://github.com/servo/servo/issues/26625
|
||||
[Verify color after animation]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[variable-animation-substitute-within-keyframe.html]
|
||||
bug: https://github.com/servo/servo/issues/21564
|
||||
bug: https://github.com/servo/servo/issues/26625
|
||||
[Verify color after animation]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[variable-animation-to-only.html]
|
||||
bug: https://github.com/servo/servo/issues/21564
|
||||
bug: https://github.com/servo/servo/issues/26625
|
||||
expected: TIMEOUT
|
||||
[Verify CSS variable value after animation]
|
||||
expected: TIMEOUT
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[variable-transitions-from-no-value.html]
|
||||
bug: https://github.com/servo/servo/issues/21564
|
||||
bug: https://github.com/servo/servo/issues/26625
|
||||
expected: TIMEOUT
|
||||
[Verify CSS variable value after transition]
|
||||
expected: NOTRUN
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[variable-transitions-to-no-value.html]
|
||||
bug: https://github.com/servo/servo/issues/21564
|
||||
bug: https://github.com/servo/servo/issues/26625
|
||||
expected: TIMEOUT
|
||||
[Verify CSS variable value after transition]
|
||||
expected: NOTRUN
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[variable-transitions-transition-property-variable-before-value.html]
|
||||
bug: https://github.com/servo/servo/issues/21564
|
||||
bug: https://github.com/servo/servo/issues/26625
|
||||
expected: TIMEOUT
|
||||
[Verify CSS variable value after transition]
|
||||
expected: NOTRUN
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[variable-transitions-value-before-transition-property-variable.html]
|
||||
bug: https://github.com/servo/servo/issues/21564
|
||||
bug: https://github.com/servo/servo/issues/26625
|
||||
expected: TIMEOUT
|
||||
[Verify CSS variable value after transition]
|
||||
expected: NOTRUN
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
prefs: ["layout.animations.test.enabled:false",
|
||||
"dom.testbinding.enabled:false"]
|
|
@ -0,0 +1,3 @@
|
|||
prefs: ["layout.animations.test.enabled:false",
|
||||
"dom.testbinding.enabled:false"]
|
||||
|
|
@ -12849,6 +12849,15 @@
|
|||
},
|
||||
"css": {
|
||||
"animations": {
|
||||
"animation-events.html": [
|
||||
"0975aa64ec47ca4b4c8fc1e0a40414a51719ad67",
|
||||
[
|
||||
null,
|
||||
{
|
||||
"timeout": "long"
|
||||
}
|
||||
]
|
||||
],
|
||||
"animation-fill-mode.html": [
|
||||
"4cfaab9fbce0adccd83f592935e63fa8ff58a1cf",
|
||||
[
|
||||
|
@ -12884,6 +12893,13 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"transition-events.html": [
|
||||
"b561fc8353276e6bdd13a9d1b965f57733ecd19b",
|
||||
[
|
||||
null,
|
||||
{}
|
||||
]
|
||||
],
|
||||
"transition-raf.html": [
|
||||
"c38404503408e04b3c75b42df18ec3a7ec0819f5",
|
||||
[
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
prefs: ["layout.animations.test.enabled:false",
|
||||
"dom.testbinding.enabled:false"]
|
|
@ -0,0 +1,3 @@
|
|||
prefs: ["layout.animations.test.enabled:false",
|
||||
"dom.testbinding.enabled:false"]
|
||||
|
160
tests/wpt/mozilla/tests/css/animations/animation-events.html
Normal file
160
tests/wpt/mozilla/tests/css/animations/animation-events.html
Normal file
|
@ -0,0 +1,160 @@
|
|||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<title>CSS animation event dispatch</title>
|
||||
<meta name="timeout" content="long">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-animations-2/#event-dispatch"/>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<style>
|
||||
@keyframes anim {
|
||||
from { margin-left: 0px; }
|
||||
to { margin-left: 100px; }
|
||||
}
|
||||
</style>
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
// This series of tests is a forked version of the Web Platform Test
|
||||
// /css/css-animations/event-dispatch.tentative that do not make use
|
||||
// of the Web Animations API, since Servo doesn't yet support Web Animations.
|
||||
|
||||
function waitForFrame() {
|
||||
return new Promise(resolve => {
|
||||
window.requestAnimationFrame(resolve);
|
||||
});
|
||||
}
|
||||
|
||||
// All animation events should be received on the next animation frame.
|
||||
const animationEventsTimeout = () => {
|
||||
return new Promise(function(resolve) {
|
||||
setTimeout(resolve, 5000);
|
||||
});
|
||||
}
|
||||
|
||||
const setupAnimation = (t, animationStyle) => {
|
||||
var div = document.createElement('div');
|
||||
div.setAttribute('style', 'animation: ' + animationStyle);
|
||||
document.body.appendChild(div);
|
||||
if (t && typeof t.add_cleanup === 'function') {
|
||||
t.add_cleanup(function() {
|
||||
if (div.parentNode) {
|
||||
div.remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const watcher = new EventWatcher(t, div, [ 'animationstart',
|
||||
'animationiteration',
|
||||
'animationend',
|
||||
'animationcancel' ],
|
||||
animationEventsTimeout);
|
||||
|
||||
return { watcher, div };
|
||||
};
|
||||
|
||||
promise_test(async t => {
|
||||
const { watcher } = setupAnimation(t, 'anim 100s');
|
||||
|
||||
const events = await watcher.wait_for(
|
||||
['animationstart' ],
|
||||
{
|
||||
record: 'all',
|
||||
}
|
||||
);
|
||||
assert_equals(events[0].elapsedTime, 0.0);
|
||||
}, 'animationstart');
|
||||
|
||||
promise_test(async t => {
|
||||
const { watcher } = setupAnimation(t, 'anim 0.1s');
|
||||
|
||||
const events = await watcher.wait_for(
|
||||
['animationstart', 'animationend'],
|
||||
{
|
||||
record: 'all',
|
||||
}
|
||||
);
|
||||
assert_equals(events[0].elapsedTime, 0);
|
||||
assert_equals(events[0].animationName, "anim");
|
||||
|
||||
assert_approx_equals(events[1].elapsedTime, 0.1, 0.001);
|
||||
assert_equals(events[1].animationName, "anim");
|
||||
}, 'animationstart and animationend');
|
||||
|
||||
promise_test(async t => {
|
||||
const { watcher } = setupAnimation(t, 'anim 1s 0.5s');
|
||||
|
||||
const events = await watcher.wait_for(
|
||||
['animationstart', 'animationend'], { record: 'all', }
|
||||
);
|
||||
assert_approx_equals(events[0].elapsedTime, 0, 0.01);
|
||||
assert_equals(events[0].animationName, "anim");
|
||||
|
||||
assert_approx_equals(events[1].elapsedTime, 1, 0.01);
|
||||
assert_equals(events[1].animationName, "anim");
|
||||
}, 'animationstart and animationend with positive delay');
|
||||
|
||||
promise_test(async t => {
|
||||
const { watcher } = setupAnimation(t, 'anim 100s -99.99s');
|
||||
|
||||
const events = await watcher.wait_for(
|
||||
['animationstart', 'animationend'], { record: 'all', }
|
||||
);
|
||||
assert_approx_equals(events[0].elapsedTime, 99.99, 0.1);
|
||||
assert_equals(events[0].animationName, "anim");
|
||||
|
||||
assert_approx_equals(events[1].elapsedTime, 99.99, 0.1);
|
||||
assert_equals(events[1].animationName, "anim");
|
||||
}, 'animationstart and animationend with negative delay');
|
||||
|
||||
promise_test(async t => {
|
||||
const { watcher } = setupAnimation(t, 'anim 100s -200s');
|
||||
|
||||
const events = await watcher.wait_for(
|
||||
['animationstart', 'animationend'], { record: 'all', }
|
||||
);
|
||||
assert_approx_equals(events[0].elapsedTime, 99.99, 0.1);
|
||||
assert_equals(events[0].animationName, "anim");
|
||||
|
||||
assert_approx_equals(events[1].elapsedTime, 99.99, 0.1);
|
||||
assert_equals(events[1].animationName, "anim");
|
||||
}, 'animationstart and animationend with negative delay larger than active duration');
|
||||
|
||||
promise_test(async t => {
|
||||
const { watcher, div } = setupAnimation(t, 'anim 100s');
|
||||
await watcher.wait_for('animationstart');
|
||||
|
||||
div.style.animation = "";
|
||||
|
||||
await watcher.wait_for('animationcancel');
|
||||
}, 'animationcancel');
|
||||
|
||||
promise_test(async t => {
|
||||
const { watcher, div } = setupAnimation(t, 'anim 100s 50s');
|
||||
|
||||
// Wait for two animation frames. One is not enough in some browser engines.
|
||||
await waitForFrame();
|
||||
await waitForFrame();
|
||||
|
||||
div.style.animation = "";
|
||||
const events = await watcher.wait_for(
|
||||
['animationcancel'], { record: 'all', }
|
||||
);
|
||||
|
||||
assert_equals(events[0].elapsedTime, 0);
|
||||
}, 'animationcancel with positive delay');
|
||||
|
||||
promise_test(async t => {
|
||||
const { watcher, div } = setupAnimation(t, 'anim 100s -50s');
|
||||
await watcher.wait_for('animationstart');
|
||||
|
||||
div.style.animation = "";
|
||||
|
||||
const events = await watcher.wait_for(
|
||||
['animationcancel'], { record: 'all', }
|
||||
);
|
||||
|
||||
assert_approx_equals(events[0].elapsedTime, 50, 0.1);
|
||||
}, 'animationcancel with negative delay');
|
||||
|
||||
</script>
|
131
tests/wpt/mozilla/tests/css/animations/transition-events.html
Normal file
131
tests/wpt/mozilla/tests/css/animations/transition-events.html
Normal file
|
@ -0,0 +1,131 @@
|
|||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<title>CSS transition event dispatch</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-transitions-2/#event-dispatch">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
// This series of tests is a forked version of the Web Platform Test
|
||||
// /css/css-transitions/event-dispatch.tentative that do not make use
|
||||
// of the Web Animations API, since Servo doesn't yet support Web Animations.
|
||||
|
||||
|
||||
// All transition events should be received on the next animation frame.
|
||||
function transitionEventsTimeout() {
|
||||
return new Promise(function(resolve) {
|
||||
return new Promise(resolve => {
|
||||
window.requestAnimationFrame(resolve);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const setupTransition = (t, transitionStyle) => {
|
||||
var div = document.createElement('div');
|
||||
div.setAttribute('style', 'transition: ' + transitionStyle);
|
||||
document.body.appendChild(div);
|
||||
if (t && typeof t.add_cleanup === 'function') {
|
||||
t.add_cleanup(function() {
|
||||
if (div.parentNode) {
|
||||
div.remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
const watcher = new EventWatcher(t, div, [ 'transitionrun',
|
||||
'transitionstart',
|
||||
'transitionend',
|
||||
'transitioncancel' ],
|
||||
transitionEventsTimeout);
|
||||
getComputedStyle(div).marginLeft;
|
||||
|
||||
div.style.marginLeft = '100px';
|
||||
|
||||
return { watcher, div };
|
||||
};
|
||||
|
||||
promise_test(async t => {
|
||||
const { watcher } = setupTransition(t, 'margin-left 100s 100s');
|
||||
const events = await watcher.wait_for(
|
||||
['transitionrun' ],
|
||||
{
|
||||
record: 'all',
|
||||
}
|
||||
);
|
||||
assert_equals(events[0].elapsedTime, 0.0);
|
||||
}, 'transitionrun');
|
||||
|
||||
promise_test(async t => {
|
||||
const { watcher } = setupTransition(t, 'margin-left 100s');
|
||||
const events = await watcher.wait_for(
|
||||
['transitionrun', 'transitionstart', ],
|
||||
{
|
||||
record: 'all',
|
||||
}
|
||||
);
|
||||
assert_equals(events[0].elapsedTime, 0.0);
|
||||
assert_equals(events[1].elapsedTime, 0.0);
|
||||
}, 'transitionrun, transitionstart');
|
||||
|
||||
promise_test(async t => {
|
||||
const { watcher, div } = setupTransition(t, 'margin-left 0.1s');
|
||||
|
||||
const events = await watcher.wait_for(
|
||||
['transitionrun', 'transitionstart', 'transitionend'],
|
||||
{
|
||||
record: 'all',
|
||||
}
|
||||
);
|
||||
assert_equals(events[0].elapsedTime, 0);
|
||||
assert_equals(events[0].propertyName, "margin-left");
|
||||
|
||||
assert_equals(events[1].elapsedTime, 0);
|
||||
assert_equals(events[1].propertyName, "margin-left");
|
||||
|
||||
assert_approx_equals(events[2].elapsedTime, 0.1, 0.01);
|
||||
assert_equals(events[2].propertyName, "margin-left");
|
||||
|
||||
}, 'transitionrun, transitionstart, transitionend');
|
||||
|
||||
promise_test(async t => {
|
||||
const { watcher, div } = setupTransition(t, 'margin-left 1s 0.5s');
|
||||
|
||||
const events = await watcher.wait_for(
|
||||
['transitionrun', 'transitionstart', 'transitionend'],
|
||||
{
|
||||
record: 'all',
|
||||
}
|
||||
);
|
||||
|
||||
assert_equals(events[0].elapsedTime, 0);
|
||||
assert_equals(events[0].propertyName, "margin-left");
|
||||
|
||||
assert_equals(events[1].elapsedTime, 0);
|
||||
assert_equals(events[1].propertyName, "margin-left");
|
||||
|
||||
assert_equals(events[2].elapsedTime, 1);
|
||||
assert_equals(events[2].propertyName, "margin-left");
|
||||
}, 'transitionrun, transitionstart, transitionend with positive delay');
|
||||
|
||||
|
||||
promise_test(async t => {
|
||||
const { watcher, div } = setupTransition(t, 'margin-left 100s -99.99s');
|
||||
|
||||
const events = await watcher.wait_for(
|
||||
['transitionrun', 'transitionstart', 'transitionend'],
|
||||
{
|
||||
record: 'all',
|
||||
}
|
||||
);
|
||||
assert_approx_equals(events[0].elapsedTime, 99.99, 0.1);
|
||||
assert_equals(events[0].propertyName, "margin-left");
|
||||
|
||||
assert_approx_equals(events[1].elapsedTime, 99.99, 0.1);
|
||||
assert_equals(events[1].propertyName, "margin-left");
|
||||
|
||||
assert_approx_equals(events[2].elapsedTime, 99.99, 0.1);
|
||||
assert_equals(events[2].propertyName, "margin-left");
|
||||
}, 'transitionrun, transitionstart, transitionend with negative delay');
|
||||
|
||||
</script>
|
Loading…
Add table
Add a link
Reference in a new issue