diff options
Diffstat (limited to 'layout/style/test/file_animations_omta_scroll.html')
-rw-r--r-- | layout/style/test/file_animations_omta_scroll.html | 392 |
1 files changed, 392 insertions, 0 deletions
diff --git a/layout/style/test/file_animations_omta_scroll.html b/layout/style/test/file_animations_omta_scroll.html new file mode 100644 index 0000000000..625b4b6c19 --- /dev/null +++ b/layout/style/test/file_animations_omta_scroll.html @@ -0,0 +1,392 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <title>Test for css-animations running on the compositor thread with scroll-timeline</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/paint_listener.js"></script> + <script src="/tests/gfx/layers/apz/test/mochitest/apz_test_utils.js"></script> + <script type="application/javascript" src="animation_utils.js"></script> + <style type="text/css"> + @keyframes transform_anim { + from { transform: translate(50px); } + to { transform: translate(150px); } + } + + @keyframes always_fifty { + from, to { transform: translate(50px); } + } + + @keyframes geometry { + from { width: 50px; } + to { width: 100px; } + } + + .target { + /* The animation target needs geometry in order to qualify for OMTA */ + width: 100px; + height: 100px; + background-color: green; + } + + .scroller { + width: 100px; + height: 100px; + overflow: scroll; + scroll-timeline-name: scroll_timeline; + } + + .content { + block-size: 100%; + padding-block-end: 100px; + } + </style> +</head> +<body> + <div id="display"></div> + <pre id="test"></pre> +</body> +<script type="application/javascript"> +"use strict"; + +// Global state +var gScroller = null; +var gDiv = null; + +// Shortcut omta_is and friends by filling in the initial 'elem' argument +// with gDiv. +[ 'omta_is', 'omta_todo_is', 'omta_is_approx' ].forEach(function(fn) { + var origFn = window[fn]; + window[fn] = function() { + var args = Array.from(arguments); + if (!(args[0] instanceof Element)) { + args.unshift(gDiv); + } + return origFn.apply(window, args); + }; +}); + +// Shortcut new_div and done_div to update gDiv +var originalNewDiv = window.new_div; +window.new_div = function(style) { + [ gDiv ] = originalNewDiv(style); +}; +var originalDoneDiv = window.done_div; +window.done_div = function() { + originalDoneDiv(); + gDiv = null; +}; + +// Bind the ok and todo to the opener, and close this window when we finish. +var ok = opener.ok.bind(opener); +var todo = opener.todo.bind(opener); +function finish() { + var o = opener; + self.close(); + o.SimpleTest.finish(); +} + +function new_scroller() { + gScroller = document.createElement('div'); + gScroller.className = `scroller`; + + let content = document.createElement('div'); + content.className = 'content'; + + gScroller.appendChild(content); + document.getElementById("display").appendChild(gScroller); + return gScroller; +} + +function done_scroller() { + gScroller.firstChild.remove(); + gScroller.remove(); + gScroller = null; +} + +waitUntilApzStable().then(() => { + runOMTATest(function() { + var onAbort = function() { + if (gDiv) { + done_div(); + } + if (gScroller) { + done_scroller(); + } + }; + runAllAsyncAnimTests(onAbort).then(finish); + }, finish); +}); + +//---------------------------------------------------------------------- +// +// Test cases +// +//---------------------------------------------------------------------- + +// The non-omta property with scroll-timeline together with an omta property +// with document-timeline. +addAsyncAnimTest(async function() { + new_scroller(); + new_div("animation: geometry 10s scroll_timeline, always_fifty 1s infinite;"); + await waitForPaintsFlushed(); + + // Note: width is not a OMTA property, so it must be running on the main + // thread. + omta_is("transform", { tx: 50 }, RunningOn.Compositor, + "transform animations should runs on compositor thread"); + + done_div(); + done_scroller(); +}); + +// transform property with scroll-driven animations. +addAsyncAnimTest(async function() { + let scroller = new_scroller(); + new_div("animation: transform_anim 1s linear scroll_timeline;"); + await waitForPaintsFlushed(); + + scroller.scrollTop = 50; + await waitForPaintsFlushed(); + + omta_is_approx("transform", { tx: 100 }, 0.1, RunningOn.Compositor, + "scroll transform animations should runs on compositor " + + "thread"); + + done_div(); + done_scroller(); +}); + + +// The scroll-driven animation with an underlying value and make it go from the +// active phase to the before phase. +addAsyncAnimTest(async function() { + let scroller = new_scroller(); + new_div("animation: always_fifty 5s linear 5s scroll_timeline; " + + "transform: translate(25px);"); + await waitForPaintsFlushed(); + + // NOTE: getOMTAStyle() can't detect the animation is running on the + // compositor during the delay phase. + omta_is_approx("transform", { tx: 25 }, 0.1, RunningOn.Either, + "The scroll animation is in delay"); + + scroller.scrollTop = 75; + await waitForPaintsFlushed(); + + omta_is_approx("transform", { tx: 50 }, 0.1, RunningOn.Compositor, + "scroll transform animations should runs on compositor " + + "thread"); + + // Use setAsyncScrollOffset() to update apz (compositor thread only) to make + // sure Bug 1776077 is reproducible. + let utils = SpecialPowers.wrap(window).windowUtils; + utils.setAsyncScrollOffset(scroller, 0, -50); + utils.advanceTimeAndRefresh(16); + utils.restoreNormalRefresh(); + await waitForPaints(); + + // NOTE: setAsyncScrollOffset() doesn't update main thread, so we check the + // OMTA style directly. + let compositorStr = + SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "transform"); + ok(compositorStr === "matrix(1, 0, 0, 1, 25, 0)", + "scroll animations is in delay phase before calling main thread style " + + "udpate"); + + scroller.scrollTop = 25; + await waitForPaintsFlushed(); + + compositorStr = SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "transform"); + ok(compositorStr === "", + "scroll animation in delay phase clears its OMTA style"); + omta_is_approx("transform", { tx: 25 }, 0.1, RunningOn.Either, + "The scroll animation is in delay"); + + done_div(); + done_scroller(); +}); + +// The scroll-driven animation without an underlying value and make it go from +// the active phase to the before phase. +addAsyncAnimTest(async function() { + let scroller = new_scroller(); + new_div("animation: always_fifty 5s linear 5s scroll_timeline; "); + await waitForPaintsFlushed(); + + // NOTE: getOMTAStyle() can't detect the animation is running on the + // compositor during the delay phase. + omta_is_approx("transform", { tx: 0 }, 0.1, RunningOn.Either, + "The scroll animation is in delay"); + + scroller.scrollTop = 75; + await waitForPaintsFlushed(); + + omta_is_approx("transform", { tx: 50 }, 0.1, RunningOn.Compositor, + "scroll transform animations should runs on compositor " + + "thread"); + + // Use setAsyncScrollOffset() to update apz (compositor thread only) to make + // sure Bug 1776077 is reproducible. + let utils = SpecialPowers.wrap(window).windowUtils; + utils.setAsyncScrollOffset(scroller, 0, -50); + utils.advanceTimeAndRefresh(16); + utils.restoreNormalRefresh(); + await waitForPaints(); + + // NOTE: setAsyncScrollOffset() doesn't update main thread, so we check the + // OMTA style directly. + let compositorStr = + SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "transform"); + ok(compositorStr === "matrix(1, 0, 0, 1, 0, 0)", + "scroll animations is in delay phase before calling main thread style " + + "udpate"); + + done_div(); + done_scroller(); +}); + +// The scroll-driven animation is in delay, together with other runing +// animations. +addAsyncAnimTest(async function() { + let scroller = new_scroller(); + new_div("animation: transform_anim 10s linear -5s paused, " + + " always_fifty 5s linear 5s scroll_timeline;"); + await waitForPaintsFlushed(); + + omta_is_approx("transform", { tx: 100 }, 0.1, RunningOn.Compositor, + "The scroll animation is in delay"); + + scroller.scrollTop = 75; + await waitForPaintsFlushed(); + + omta_is_approx("transform", { tx: 50 }, 0.1, RunningOn.Compositor, + "scroll transform animations should runs on compositor " + + "thread"); + + let utils = SpecialPowers.wrap(window).windowUtils; + utils.setAsyncScrollOffset(scroller, 0, -50); + utils.advanceTimeAndRefresh(16); + utils.restoreNormalRefresh(); + await waitForPaints(); + + // NOTE: setAsyncScrollOffset() doesn't update main thread, so we check the + // OMTA style directly. + let compositorStr = + SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "transform"); + ok(compositorStr === "matrix(1, 0, 0, 1, 100, 0)", + "scroll animations is in delay phase before calling main thread style " + + "udpate"); + + done_div(); + done_scroller(); +}); + +addAsyncAnimTest(async function() { + let iframe = document.createElement("iframe"); + iframe.setAttribute("style", "width: 200px; height: 200px"); + iframe.setAttribute("scrolling", "no"); + iframe.srcdoc = + "<!DOCTYPE HTML>" + + "<html style='min-height: 100%; padding-bottom: 100px;'>" + + "<style>" + + "@keyframes anim { from, to { transform: translate(50px) } }" + + "</style>" + + "<div id='target_in_iframe' " + + " style='width:50px; height:50px; background:green;" + + " animation: anim 10s linear scroll(root);'>" + + "</div>" + + "</html>"; + + await new Promise(resolve => { + iframe.onload = resolve; + document.body.appendChild(iframe); + }); + + gDiv = iframe.contentDocument.getElementById("target_in_iframe"); + + const root = iframe.contentDocument.scrollingElement; + const maxScroll = root.scrollHeight - root.clientHeight; + root.scrollTop = 0.5 * maxScroll; + await waitForPaintsFlushed(); + + omta_is_approx("transform", { tx: 50 }, 0, RunningOn.MainThread, + "scroll transform animations inside an iframe with " + + "scrolling:no should run on the main thread"); + + gDiv = null; + iframe.remove(); +}); + +// FIXME: Bug 1818346. Support OMTA for view-timeline. +addAsyncAnimTest(async function() { + let scroller = document.createElement("div"); + scroller.style.width = "100px"; + scroller.style.height = "100px"; + // Use hidden so we don't have scrollbar, to make sure the scrollport size + // is 100px x 100px, so view progress visibility range is 100px on block axis. + scroller.style.overflow = "hidden"; + + let content1 = document.createElement("div"); + content1.style.height = "150px"; + scroller.appendChild(content1); + + let subject = document.createElement("div"); + subject.style.width = "50px"; + subject.style.height = "50px"; + subject.style.viewTimelineName = "view_timeline"; + scroller.appendChild(subject); + + // Let |target| be the child of |subject|, so view-timeline-name property of + // |subject| is referenceable. + let target = document.createElement("div"); + target.style.width = "10px"; + target.style.height = "10px"; + subject.appendChild(target); + gDiv = target; + + let content2 = document.createElement("div"); + content2.style.height = "150px"; + scroller.appendChild(content2); + + // So the DOM tree looks like this: + // <div class=scroller> <!-- "scroller", height: 100px; --> + // <div></div> <!-- "", height: 150px --> + // <div></div> <!-- "subject", height: 50px; --> + // <div></div> <!-- "", height: 150px; --> + // </div> + // The subject is in view when scroller.scrollTop is [50px, 200px]. + document.getElementById("display").appendChild(scroller); + await waitForPaintsFlushed(); + + scroller.scrollTop = 0; + target.style.animation = "transform_anim 10s linear"; + target.style.animationTimeline = "view_timeline"; + await waitForPaintsFlushed(); + + omta_is_approx("transform", { tx: 0 }, 0.1, RunningOn.OnMainThread, + "The scroll animation is out of view"); + + scroller.scrollTop = 50; + await waitForPaintsFlushed(); + + omta_is_approx("transform", { tx: 50 }, 0.1, RunningOn.OnMainThread, + "The scroll animation is 0%"); + + scroller.scrollTop = 125; + await waitForPaintsFlushed(); + + omta_is_approx("transform", { tx: 100 }, 0.1, RunningOn.OnMainThread, + "The scroll animation is 50%"); + + target.remove(); + content2.remove(); + subject.remove(); + content1.remove(); + scroller.remove(); + gDiv = null; +}); + +</script> +</html> |