1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
|
<!doctype html>
<meta charset=utf-8>
<script src="../testcommon.js"></script>
<script src="/tests/SimpleTest/paint_listener.js"></script>
<style>
@keyframes empty { }
.target {
/* Element needs geometry to be eligible for layerization */
width: 100px;
height: 100px;
background-color: white;
}
</style>
<body>
<script>
'use strict';
function waitForDocLoad() {
return new Promise((resolve, reject) => {
if (document.readyState === 'complete') {
resolve();
} else {
window.addEventListener('load', resolve);
}
});
}
function waitForPaints() {
return new Promise((resolve, reject) => {
waitForAllPaintsFlushed(resolve);
});
}
promise_test(async t => {
// Test that empty animations actually start.
//
// Normally we tie the start of animations to when their first frame of
// the animation is rendered. However, for animations that don't actually
// trigger a paint (e.g. because they are empty, or are animating something
// that doesn't render or is offscreen) we want to make sure they still
// start.
//
// Before we start, wait for the document to finish loading, then create
// div element, and wait for painting. This is because during loading we will
// have other paint events taking place which might, by luck, happen to
// trigger animations that otherwise would not have been triggered, leading to
// false positives.
//
// As a result, it's better to wait until we have a more stable state before
// continuing.
await waitForDocLoad();
const div = addDiv(t);
await waitForPaints();
div.style.animation = 'empty 1000s';
const animation = div.getAnimations()[0];
let promiseCallbackDone = false;
animation.ready.then(() => {
promiseCallbackDone = true;
}).catch(() => {
assert_unreached('ready promise was rejected');
});
// We need to wait for up to three frames. This is because in some
// cases it can take up to two frames for the initial layout
// to take place. Even after that happens we don't actually resolve the
// ready promise until the following tick.
await waitForAnimationFrames(3);
assert_true(promiseCallbackDone,
'ready promise for an empty animation was resolved'
+ ' within three animation frames');
}, 'Animation.ready is resolved for an empty animation');
// Test that compositor animations with delays get synced correctly
//
// NOTE: It is important that we DON'T use
// SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh here since that takes
// us through a different code path.
promise_test(async t => {
assert_false(SpecialPowers.DOMWindowUtils.isTestControllingRefreshes,
'Test should run without the refresh driver being under'
+ ' test control');
// This test only applies to compositor animations
if (!isOMTAEnabled()) {
return;
}
const div = addDiv(t, { class: 'target' });
// As with the above test, any stray paints can cause this test to produce
// a false negative (that is, pass when it should fail). To avoid this we
// wait for paints and only then do we commence the test.
await waitForPaints();
const animation =
div.animate({ transform: [ 'translate(0px)', 'translate(100px)' ] },
{ duration: 400 * MS_PER_SEC,
delay: -200 * MS_PER_SEC });
await waitForAnimationReadyToRestyle(animation);
await waitForPaints();
const transformStr =
SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform');
const translateX = getTranslateXFromTransform(transformStr);
// If the delay has been applied we should be about half-way through
// the animation. However, if we applied it twice we will be at the
// end of the animation already so check that we are roughly half way
// through.
assert_between_inclusive(translateX, 40, 75,
'Animation is about half-way through on the compositor');
}, 'Starting an animation with a delay starts from the correct point');
// Test that compositor animations with a playback rate start at the
// appropriate point.
//
// NOTE: As with the previous test, it is important that we DON'T use
// SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh here since that takes
// us through a different code path.
promise_test(async t => {
assert_false(SpecialPowers.DOMWindowUtils.isTestControllingRefreshes,
'Test should run without the refresh driver being under'
+ ' test control');
// This test only applies to compositor animations
if (!isOMTAEnabled()) {
return;
}
const div = addDiv(t, { class: 'target' });
// Wait for the document to load and painting (see notes in previous test).
await waitForPaints();
const animation =
div.animate({ transform: [ 'translate(0px)', 'translate(100px)' ] },
200 * MS_PER_SEC);
animation.currentTime = 100 * MS_PER_SEC;
animation.playbackRate = 0.1;
await waitForPaints();
const transformStr =
SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform');
const translateX = getTranslateXFromTransform(transformStr);
// We pass the playback rate to the compositor independently and we have
// tests to ensure that it is correctly applied there. However, if, when
// we resolve the start time of the pending animation, we fail to
// incorporate the playback rate, we will end up starting from the wrong
// point and the current time calculated on the compositor will be wrong.
assert_between_inclusive(translateX, 25, 75,
'Animation is about half-way through on the compositor');
}, 'Starting an animation with a playbackRate starts from the correct point');
function getTranslateXFromTransform(transformStr) {
const matrixComponents =
transformStr.startsWith('matrix(')
? transformStr.substring('matrix('.length, transformStr.length-1)
.split(',')
.map(component => Number(component))
: [];
assert_equals(matrixComponents.length, 6,
'Got a valid transform matrix on the compositor'
+ ' (got: "' + transformStr + '")');
return matrixComponents[4];
}
done();
</script>
</body>
|