diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /dom/animation/test/mozilla/file_deferred_start.html | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/animation/test/mozilla/file_deferred_start.html')
-rw-r--r-- | dom/animation/test/mozilla/file_deferred_start.html | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/dom/animation/test/mozilla/file_deferred_start.html b/dom/animation/test/mozilla/file_deferred_start.html new file mode 100644 index 0000000000..863fc80fec --- /dev/null +++ b/dom/animation/test/mozilla/file_deferred_start.html @@ -0,0 +1,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> |