5 <meta name=
"viewport" content=
"width=device-width,initial-scale=1">
6 <title>Test for css-animations running on the compositor thread with scroll-timeline
</title>
7 <script src=
"/tests/SimpleTest/SimpleTest.js"></script>
8 <script src=
"/tests/SimpleTest/paint_listener.js"></script>
9 <script src=
"/tests/gfx/layers/apz/test/mochitest/apz_test_utils.js"></script>
10 <script type=
"application/javascript" src=
"animation_utils.js"></script>
11 <style type=
"text/css">
12 @keyframes transform_anim
{
13 from
{ transform: translate
(50px); }
14 to
{ transform: translate
(150px); }
17 @keyframes always_fifty
{
18 from
, to
{ transform: translate
(50px); }
27 /* The animation target needs geometry in order to qualify for OMTA */
30 background-color: green
;
37 scroll-timeline-name: scroll_timeline
;
42 padding-block-end: 100px;
47 <div id=
"display"></div>
50 <script type=
"application/javascript">
57 // Shortcut omta_is and friends by filling in the initial 'elem' argument
59 [ 'omta_is', 'omta_todo_is', 'omta_is_approx' ].forEach(function(fn) {
60 var origFn = window[fn];
61 window[fn] = function() {
62 var args = Array.from(arguments);
63 if (!(args[
0] instanceof Element)) {
66 return origFn.apply(window, args);
70 // Shortcut new_div and done_div to update gDiv
71 var originalNewDiv = window.new_div;
72 window.new_div = function(style) {
73 [ gDiv ] = originalNewDiv(style);
75 var originalDoneDiv = window.done_div;
76 window.done_div = function() {
81 // Bind the ok and todo to the opener, and close this window when we finish.
82 var ok = opener.ok.bind(opener);
83 var todo = opener.todo.bind(opener);
87 o.SimpleTest.finish();
90 function new_scroller() {
91 gScroller = document.createElement('div');
92 gScroller.className = `scroller`;
94 let content = document.createElement('div');
95 content.className = 'content';
97 gScroller.appendChild(content);
98 document.getElementById(
"display").appendChild(gScroller);
102 function done_scroller() {
103 gScroller.firstChild.remove();
108 waitUntilApzStable().then(() =
> {
109 runOMTATest(function() {
110 var onAbort = function() {
118 runAllAsyncAnimTests(onAbort).then(finish);
122 //----------------------------------------------------------------------
126 //----------------------------------------------------------------------
128 // The non-omta property with scroll-timeline together with an omta property
129 // with document-timeline.
130 addAsyncAnimTest(async function() {
132 new_div(
"animation: geometry 10s scroll_timeline, always_fifty 1s infinite;");
133 await waitForPaintsFlushed();
135 // Note: width is not a OMTA property, so it must be running on the main
137 omta_is(
"transform", { tx:
50 }, RunningOn.Compositor,
138 "transform animations should runs on compositor thread");
144 // transform property with scroll-driven animations.
145 addAsyncAnimTest(async function() {
146 let scroller = new_scroller();
147 new_div(
"animation: transform_anim 1s linear scroll_timeline;");
148 await waitForPaintsFlushed();
150 scroller.scrollTop =
50;
151 await waitForPaintsFlushed();
153 omta_is_approx(
"transform", { tx:
100 },
0.1, RunningOn.Compositor,
154 "scroll transform animations should runs on compositor " +
162 // The scroll-driven animation with an underlying value and make it go from the
163 // active phase to the before phase.
164 addAsyncAnimTest(async function() {
165 let scroller = new_scroller();
166 new_div(
"animation: always_fifty 5s linear 5s scroll_timeline; " +
167 "transform: translate(25px);");
168 await waitForPaintsFlushed();
170 // NOTE: getOMTAStyle() can't detect the animation is running on the
171 // compositor during the delay phase.
172 omta_is_approx(
"transform", { tx:
25 },
0.1, RunningOn.Either,
173 "The scroll animation is in delay");
175 scroller.scrollTop =
75;
176 await waitForPaintsFlushed();
178 omta_is_approx(
"transform", { tx:
50 },
0.1, RunningOn.Compositor,
179 "scroll transform animations should runs on compositor " +
182 // Use setAsyncScrollOffset() to update apz (compositor thread only) to make
183 // sure Bug
1776077 is reproducible.
184 let utils = SpecialPowers.wrap(window).windowUtils;
185 utils.setAsyncScrollOffset(scroller,
0, -
50);
186 utils.advanceTimeAndRefresh(
16);
187 utils.restoreNormalRefresh();
188 await waitForPaints();
190 // NOTE: setAsyncScrollOffset() doesn't update main thread, so we check the
191 // OMTA style directly.
193 SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv,
"transform");
194 ok(compositorStr ===
"matrix(1, 0, 0, 1, 25, 0)",
195 "scroll animations is in delay phase before calling main thread style " +
198 scroller.scrollTop =
25;
199 await waitForPaintsFlushed();
201 compositorStr = SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv,
"transform");
202 ok(compositorStr ===
"",
203 "scroll animation in delay phase clears its OMTA style");
204 omta_is_approx(
"transform", { tx:
25 },
0.1, RunningOn.Either,
205 "The scroll animation is in delay");
211 // The scroll-driven animation without an underlying value and make it go from
212 // the active phase to the before phase.
213 addAsyncAnimTest(async function() {
214 let scroller = new_scroller();
215 new_div(
"animation: always_fifty 5s linear 5s scroll_timeline; ");
216 await waitForPaintsFlushed();
218 // NOTE: getOMTAStyle() can't detect the animation is running on the
219 // compositor during the delay phase.
220 omta_is_approx(
"transform", { tx:
0 },
0.1, RunningOn.Either,
221 "The scroll animation is in delay");
223 scroller.scrollTop =
75;
224 await waitForPaintsFlushed();
226 omta_is_approx(
"transform", { tx:
50 },
0.1, RunningOn.Compositor,
227 "scroll transform animations should runs on compositor " +
230 // Use setAsyncScrollOffset() to update apz (compositor thread only) to make
231 // sure Bug
1776077 is reproducible.
232 let utils = SpecialPowers.wrap(window).windowUtils;
233 utils.setAsyncScrollOffset(scroller,
0, -
50);
234 utils.advanceTimeAndRefresh(
16);
235 utils.restoreNormalRefresh();
236 await waitForPaints();
238 // NOTE: setAsyncScrollOffset() doesn't update main thread, so we check the
239 // OMTA style directly.
241 SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv,
"transform");
242 ok(compositorStr ===
"matrix(1, 0, 0, 1, 0, 0)",
243 "scroll animations is in delay phase before calling main thread style " +
250 // The scroll-driven animation is in delay, together with other runing
252 addAsyncAnimTest(async function() {
253 let scroller = new_scroller();
254 new_div(
"animation: transform_anim 10s linear -5s paused, " +
255 " always_fifty 5s linear 5s scroll_timeline;");
256 await waitForPaintsFlushed();
258 omta_is_approx(
"transform", { tx:
100 },
0.1, RunningOn.Compositor,
259 "The scroll animation is in delay");
261 scroller.scrollTop =
75;
262 await waitForPaintsFlushed();
264 omta_is_approx(
"transform", { tx:
50 },
0.1, RunningOn.Compositor,
265 "scroll transform animations should runs on compositor " +
268 let utils = SpecialPowers.wrap(window).windowUtils;
269 utils.setAsyncScrollOffset(scroller,
0, -
50);
270 utils.advanceTimeAndRefresh(
16);
271 utils.restoreNormalRefresh();
272 await waitForPaints();
274 // NOTE: setAsyncScrollOffset() doesn't update main thread, so we check the
275 // OMTA style directly.
277 SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv,
"transform");
278 ok(compositorStr ===
"matrix(1, 0, 0, 1, 100, 0)",
279 "scroll animations is in delay phase before calling main thread style " +
286 addAsyncAnimTest(async function() {
287 let iframe = document.createElement(
"iframe");
288 iframe.setAttribute(
"style",
"width: 200px; height: 200px");
289 iframe.setAttribute(
"scrolling",
"no");
292 "<html style='min-height: 100%; padding-bottom: 100px;'>" +
294 "@keyframes anim { from, to { transform: translate(50px) } }" +
296 "<div id='target_in_iframe' " +
297 " style='width:50px; height:50px; background:green;" +
298 " animation: anim 10s linear scroll(root);'>" +
302 await new Promise(resolve =
> {
303 iframe.onload = resolve;
304 document.body.appendChild(iframe);
307 gDiv = iframe.contentDocument.getElementById(
"target_in_iframe");
309 const root = iframe.contentDocument.scrollingElement;
310 const maxScroll = root.scrollHeight - root.clientHeight;
311 root.scrollTop =
0.5 * maxScroll;
312 await waitForPaintsFlushed();
314 omta_is_approx(
"transform", { tx:
50 },
0, RunningOn.MainThread,
315 "scroll transform animations inside an iframe with " +
316 "scrolling:no should run on the main thread");
322 // FIXME: Bug
1818346. Support OMTA for view-timeline.
323 addAsyncAnimTest(async function() {
324 let scroller = document.createElement(
"div");
325 scroller.style.width =
"100px";
326 scroller.style.height =
"100px";
327 // Use hidden so we don't have scrollbar, to make sure the scrollport size
328 // is
100px x
100px, so view progress visibility range is
100px on block axis.
329 scroller.style.overflow =
"hidden";
331 let content1 = document.createElement(
"div");
332 content1.style.height =
"150px";
333 scroller.appendChild(content1);
335 let subject = document.createElement(
"div");
336 subject.style.width =
"50px";
337 subject.style.height =
"50px";
338 subject.style.viewTimelineName =
"view_timeline";
339 scroller.appendChild(subject);
341 // Let |target| be the child of |subject|, so view-timeline-name property of
342 // |subject| is referenceable.
343 let target = document.createElement(
"div");
344 target.style.width =
"10px";
345 target.style.height =
"10px";
346 subject.appendChild(target);
349 let content2 = document.createElement(
"div");
350 content2.style.height =
"150px";
351 scroller.appendChild(content2);
353 // So the DOM tree looks like this:
354 //
<div class=scroller
> <!-- "scroller", height: 100px; -->
355 //
<div></div> <!-- "", height: 150px -->
356 //
<div></div> <!-- "subject", height: 50px; -->
357 //
<div></div> <!-- "", height: 150px; -->
359 // The subject is in view when scroller.scrollTop is [
50px,
200px].
360 document.getElementById(
"display").appendChild(scroller);
361 await waitForPaintsFlushed();
363 scroller.scrollTop =
0;
364 target.style.animation =
"transform_anim 10s linear";
365 target.style.animationTimeline =
"view_timeline";
366 await waitForPaintsFlushed();
368 omta_is_approx(
"transform", { tx:
0 },
0.1, RunningOn.OnMainThread,
369 "The scroll animation is out of view");
371 scroller.scrollTop =
50;
372 await waitForPaintsFlushed();
374 omta_is_approx(
"transform", { tx:
50 },
0.1, RunningOn.OnMainThread,
375 "The scroll animation is 0%");
377 scroller.scrollTop =
125;
378 await waitForPaintsFlushed();
380 omta_is_approx(
"transform", { tx:
100 },
0.1, RunningOn.OnMainThread,
381 "The scroll animation is 50%");