test_animations_omta.html (119532B)
1 <!DOCTYPE HTML> 2 <html> 3 <!-- 4 https://bugzilla.mozilla.org/show_bug.cgi?id=964646 5 --> 6 <!-- 7 8 ========= PLEASE KEEP THIS IN SYNC WITH test_animations.html ========= 9 10 This test mimicks the content of test_animations.html but performs tests 11 specific to animations that run on the compositor thread since they require 12 special (asynchronous) handling. Furthermore, these tests check that 13 animations that are expected to run on the compositor thread, are actually 14 doing so. 15 16 If you are making changes to this file or to test_animations.html, please 17 try to keep them consistent where appropriate. 18 19 --> 20 <head> 21 <meta charset="utf-8"> 22 <title>Test for css3-animations running on the compositor thread (Bug 23 964646)</title> 24 <script src="/tests/SimpleTest/SimpleTest.js"></script> 25 <script src="/tests/SimpleTest/paint_listener.js"></script> 26 <script type="application/javascript" src="animation_utils.js"></script> 27 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> 28 <style type="text/css"> 29 @keyframes transform-anim { 30 to { 31 transform: translate(100px); 32 } 33 } 34 @keyframes anim1 { 35 0% { transform: translate(0px) } 36 50% { transform: translate(80px) } 37 100% { transform: translate(100px) } 38 } 39 @keyframes anim2 { 40 from { opacity: 0 } to { opacity: 1 } 41 } 42 @keyframes anim3 { 43 from { opacity: 0 } to { opacity: 1 } 44 } 45 @keyframes anim4 { 46 from { transform: translate(0px, 0px) } 47 to { transform: translate(0px, 100px) } 48 } 49 50 @keyframes kf1 { 51 50% { transform: translate(50px) } 52 to { transform: translate(150px) } 53 } 54 @keyframes kf2 { 55 from { transform: translate(150px) } 56 50% { transform: translate(50px) } 57 } 58 @keyframes kf3 { 59 25% { transform: translate(100px) } 60 } 61 @keyframes kf4 { 62 to, from { display: none; transform: translate(37px) } 63 } 64 @keyframes kf_cascade1 { 65 from { transform: translate(50px) } 66 50%, from { transform: translate(30px) } /* wins: 0% */ 67 75%, 85%, 50% { transform: translate(20px) } /* wins: 75%, 50% */ 68 100%, 85% { transform: translate(70px) } /* wins: 100% */ 69 85.1% { transform: translate(60px) } /* wins: 85.1% */ 70 85% { transform: translate(30px) } /* wins: 85% */ 71 } 72 @keyframes kf_cascade2 { from, to { opacity: 0.3 } } 73 @keyframes kf_cascade2 { from, to { transform: translate(50px) } } 74 @keyframes kf_cascade2 { from, to { transform: translate(100px) } } 75 @keyframes kf_tf1 { 76 0% { transform: translate(20px); animation-timing-function: ease } 77 25% { transform: translate(60px); } 78 50% { transform: translate(160px); animation-timing-function: steps(5) } 79 75% { transform: translate(120px); animation-timing-function: linear } 80 100% { transform: translate(20px); animation-timing-function: ease-out } 81 } 82 @keyframes kf_scale { 83 to { scale: 2.25 2.25; } 84 } 85 86 @keyframes always_fifty { 87 from, to { transform: translate(50px) } 88 } 89 90 #withbefore::before, #withafter::after { 91 content: "test"; 92 animation: anim4 1s linear alternate 3; 93 display:block; 94 } 95 96 @keyframes multiprop { 97 0% { 98 transform: translate(10px); opacity: 0.3; 99 animation-timing-function: ease; 100 } 101 25% { 102 opacity: 0.5; 103 animation-timing-function: ease-out; 104 } 105 50% { 106 transform: translate(40px); 107 } 108 75% { 109 transform: translate(80px); opacity: 0.6; 110 animation-timing-function: ease-in; 111 } 112 } 113 114 @keyframes cascade { 115 0%, 25%, 100% { transform: translate(0px) } 116 50%, 75% { transform: translate(100px) } 117 0%, 75%, 100% { opacity: 0 } 118 25%, 50% { opacity: 1 } 119 } 120 @keyframes cascade2 { 121 0% { transform: translate(0px) } 122 25% { transform: translate(30px); 123 animation-timing-function: ease-in } /* beaten by rule below */ 124 50% { transform: translate(0px) } 125 25% { transform: translate(50px) } 126 100% { transform: translate(100px) } 127 } 128 129 @keyframes primitives1 { 130 from { transform: rotate(0deg) translateX(0px) scaleX(1) 131 translate(0px) scale3d(1, 1, 1); } 132 to { transform: rotate(270deg) translate3d(0px, 0px, 0px) scale(1) 133 translateY(0px) scaleY(1); } 134 } 135 136 @keyframes important1 { 137 from { opacity: 0.5; } 138 50% { opacity: 1 !important; } /* ignored */ 139 to { opacity: 0.8; } 140 } 141 @keyframes important2 { 142 from { opacity: 0.5; 143 transform: translate(100px); } 144 to { opacity: 0.2 !important; /* ignored */ 145 transform: translate(50px); } 146 } 147 148 @keyframes empty { } 149 @keyframes nearlyempty { 150 to { 151 transform: translate(100px); 152 } 153 } 154 155 .target { 156 /* The animation target needs geometry in order to qualify for OMTA */ 157 width: 100px; 158 height: 100px; 159 background-color: white; 160 } 161 162 .visitedLink:link { background-color: yellow } 163 .visitedLink:visited { background-color: blue } 164 165 @keyframes opacitymid { 166 0% { opacity: 0.2 } 167 100% { opacity: 0.8 } 168 } 169 170 @keyframes transformnone { 171 0%, 100% { transform: translateX(50px) } 172 25%, 75% { transform: none } 173 } 174 </style> 175 </head> 176 <body> 177 <a target="_blank" 178 href="https://bugzilla.mozilla.org/show_bug.cgi?id=964646">Mozilla Bug 179 964646</a> 180 <div id="display"></div> 181 <pre id="test"> 182 <script type="application/javascript"> 183 "use strict"; 184 185 const { AppConstants } = SpecialPowers.ChromeUtils.importESModule( 186 "resource://gre/modules/AppConstants.sys.mjs" 187 ); 188 /** Test for css3-animations running on the compositor thread (Bug 964646) */ 189 190 // Global state 191 var gDisplay = document.getElementById("display") 192 , gDiv = null; 193 194 // Shortcut omta_is and friends by filling in the initial 'elem' argument 195 // with gDiv. 196 [ 'omta_is', 'omta_todo_is', 'omta_is_approx' ].forEach(function(fn) { 197 var origFn = window[fn]; 198 window[fn] = function() { 199 var args = Array.from(arguments); 200 if (!(args[0] instanceof Element)) { 201 args.unshift(gDiv); 202 } 203 return origFn.apply(window, args); 204 }; 205 }); 206 207 // Shortcut new_div and done_div to update gDiv 208 var originalNewDiv = window.new_div; 209 window.new_div = function(style) { 210 [ gDiv ] = originalNewDiv(style); 211 }; 212 var originalDoneDiv = window.done_div; 213 window.done_div = function() { 214 originalDoneDiv(); 215 gDiv = null; 216 }; 217 218 SimpleTest.waitForExplicitFinish(); 219 SimpleTest.requestLongerTimeout(2); 220 runOMTATest(function() { 221 var onAbort = function() { 222 if (gDiv) { 223 done_div(); 224 } 225 }; 226 runAllAsyncAnimTests(onAbort).then(function() { 227 SimpleTest.finish(); 228 }); 229 }, SimpleTest.finish); 230 231 //---------------------------------------------------------------------- 232 // 233 // Test cases 234 // 235 //---------------------------------------------------------------------- 236 237 // This test is not in test_animations.html but is here to test that 238 // transform animations are actually run on the compositor thread as expected. 239 addAsyncAnimTest(async function() { 240 new_div("animation: transform-anim linear 300s"); 241 242 await waitForPaintsFlushed(); 243 244 advance_clock(200000); 245 omta_is("transform", { tx: 100 * 2 / 3 }, RunningOn.Compositor, 246 "OMTA animation is animating as expected"); 247 done_div(); 248 }); 249 250 async function testFillMode(fillMode, fillsBackwards, fillsForwards) 251 { 252 var style = "transform: translate(30px); animation: 10s 3s anim1 linear"; 253 var desc; 254 if (fillMode.length > 0) { 255 style += " " + fillMode; 256 desc = "fill mode " + fillMode + ": "; 257 } else { 258 desc = "default fill mode: "; 259 } 260 new_div(style); 261 listen(); 262 263 await waitForPaintsFlushed(); 264 265 if (fillsBackwards) 266 omta_is("transform", { tx: 0 }, RunningOn.Compositor, 267 desc + "does affect value during delay (0s)"); 268 else 269 omta_is("transform", { tx: 30 }, RunningOn.MainThread, 270 desc + "doesn't affect value during delay (0s)"); 271 272 advance_clock(2000); 273 if (fillsBackwards) 274 omta_is("transform", { tx: 0 }, RunningOn.Compositor, 275 desc + "does affect value during delay (0s)"); 276 else 277 omta_is("transform", { tx: 30 }, RunningOn.MainThread, 278 desc + "does affect value during delay (0s)"); 279 280 check_events([], "before start in testFillMode"); 281 advance_clock(1000); 282 check_events([{ type: "animationstart", target: gDiv, 283 bubbles: true, cancelable: false, 284 animationName: "anim1", elapsedTime: 0.0, 285 pseudoElement: "" }], 286 "right after start in testFillMode"); 287 288 // If we have a backwards fill then at the start of the animation we will end 289 // up applying the same value as the fill value. Various optimizations in 290 // RestyleManager may filter out this meaning that the animation doesn't get 291 // added to the compositor thread until the first time the value changes. 292 // 293 // As a result we look for this first sample on either the compositor or the 294 // computed style 295 await waitForPaints(); 296 omta_is("transform", { tx: 0 }, RunningOn.Either, 297 desc + "affects value at start of animation"); 298 advance_clock(125); 299 // We might not add the animation to compositor until the second sample (due 300 // to the optimizations mentioned above) so we should wait for paints before 301 // proceeding 302 await waitForPaints(); 303 omta_is("transform", { tx: 2 }, RunningOn.Compositor, 304 desc + "affects value during animation"); 305 advance_clock(2375); 306 omta_is("transform", { tx: 40 }, RunningOn.Compositor, 307 desc + "affects value during animation"); 308 advance_clock(2500); 309 omta_is("transform", { tx: 80 }, RunningOn.Compositor, 310 desc + "affects value during animation"); 311 advance_clock(2500); 312 omta_is("transform", { tx: 90 }, RunningOn.Compositor, 313 desc + "affects value during animation"); 314 advance_clock(2375); 315 omta_is("transform", { tx: 99.5 }, RunningOn.Compositor, 316 desc + "affects value during animation"); 317 check_events([], "before end in testFillMode"); 318 advance_clock(125); 319 check_events([{ type: "animationend", target: gDiv, 320 bubbles: true, cancelable: false, 321 animationName: "anim1", elapsedTime: 10.0, 322 pseudoElement: "" }], 323 "right after end in testFillMode"); 324 325 // Currently the compositor will apply a forwards fill until it gets told by 326 // the main thread to clear the animation. As a result we should wait for 327 // paints to be flushed before checking that the animated value does *not* 328 // appear on the compositor thread. 329 await waitForPaints(); 330 if (fillsForwards) 331 omta_is("transform", { tx: 100 }, RunningOn.MainThread, 332 desc + "affects value at end of animation"); 333 advance_clock(10); 334 if (fillsForwards) 335 omta_is("transform", { tx: 100 }, RunningOn.MainThread, 336 desc + "affects value after animation"); 337 else 338 omta_is("transform", { tx: 30 }, RunningOn.MainThread, 339 desc + "does not affect value after animation"); 340 341 done_div(); 342 } 343 344 addAsyncAnimTest(function() { return testFillMode("", false, false); }); 345 addAsyncAnimTest(function() { return testFillMode("none", false, false); }); 346 addAsyncAnimTest(function() { return testFillMode("forwards", false, true); }); 347 addAsyncAnimTest(function() { return testFillMode("backwards", true, false); }); 348 addAsyncAnimTest(function() { return testFillMode("both", true, true); }); 349 350 // Test that animations continue running when the animation name 351 // list is changed. 352 // 353 // test_animations.html combines all these tests into one block but this is 354 // difficult for OMTA because currently there are only two properties to which 355 // we apply OMTA. Instead we break the test down into a few independent pieces 356 // in order to exercise the same functionality. 357 358 // Append to list 359 addAsyncAnimTest(async function() { 360 new_div("animation: anim1 linear 10s"); 361 await waitForPaintsFlushed(); 362 omta_is("transform", { tx: 0 }, RunningOn.Either, 363 "just anim1, translate at start"); 364 advance_clock(1000); 365 omta_is("transform", { tx: 16 }, RunningOn.Compositor, 366 "just anim1, translate at 1s"); 367 // append anim2 368 gDiv.style.animation = "anim1 linear 10s, anim2 linear 10s"; 369 await waitForPaintsFlushed(); 370 omta_is("transform", { tx: 16 }, RunningOn.Compositor, 371 "anim1 + anim2, translate at 1s"); 372 omta_is("opacity", 0, RunningOn.Compositor, 373 "anim1 + anim2, opacity at 1s"); 374 advance_clock(1000); 375 omta_is("transform", { tx: 32 }, RunningOn.Compositor, 376 "anim1 + anim2, translate at 2s"); 377 omta_is("opacity", 0.1, RunningOn.Compositor, 378 "anim1 + anim2, opacity at 2s"); 379 done_div(); 380 }); 381 382 // Prepend to list; delete from list 383 addAsyncAnimTest(async function() { 384 new_div("animation: anim1 linear 10s"); 385 await waitForPaintsFlushed(); 386 omta_is("transform", { tx: 0 }, RunningOn.Either, 387 "just anim1, translate at start"); 388 advance_clock(1000); 389 omta_is("transform", { tx: 16 }, RunningOn.Compositor, 390 "just anim1, translate at 1s"); 391 // prepend anim2 392 gDiv.style.animation = "anim2 linear 10s, anim1 linear 10s"; 393 await waitForPaintsFlushed(); 394 omta_is("transform", { tx: 16 }, RunningOn.Compositor, 395 "anim2 + anim1, translate at 1s"); 396 omta_is("opacity", 0, RunningOn.Compositor, 397 "anim2 + anim1, opacity at 1s"); 398 advance_clock(1000); 399 omta_is("transform", { tx: 32 }, RunningOn.Compositor, 400 "anim2 + anim1, translate at 2s"); 401 omta_is("opacity", 0.1, RunningOn.Compositor, 402 "anim2 + anim1, opacity at 2s"); 403 // remove anim2 from list 404 gDiv.style.animation = "anim1 linear 10s"; 405 await waitForPaintsFlushed(); 406 omta_is("transform", { tx: 32 }, RunningOn.Compositor, 407 "just anim1, translate at 2s"); 408 omta_is("opacity", 1, RunningOn.MainThread, "just anim1, opacity at 2s"); 409 advance_clock(1000); 410 omta_is("transform", { tx: 48 }, RunningOn.Compositor, 411 "just anim1, translate at 3s"); 412 omta_is("opacity", 1, RunningOn.MainThread, "just anim1, opacity at 3s"); 413 done_div(); 414 }); 415 416 // Swap elements 417 addAsyncAnimTest(async function() { 418 new_div("animation: anim1 linear 10s, anim2 linear 10s"); 419 await waitForPaintsFlushed(); 420 omta_is("transform", { tx: 0 }, RunningOn.Either, 421 "anim1 + anim2, translate at start"); 422 omta_is("opacity", 0, RunningOn.Compositor, 423 "anim1 + anim2, opacity at start"); 424 advance_clock(1000); 425 omta_is("transform", { tx: 16 }, RunningOn.Compositor, 426 "anim1 + anim2, translate at 1s"); 427 omta_is("opacity", 0.1, RunningOn.Compositor, 428 "anim1 + anim2, opacity at 1s"); 429 // swap anim1 and anim2, change duration of anim2 430 gDiv.style.animation = "anim2 linear 5s, anim1 linear 10s"; 431 await waitForPaintsFlushed(); 432 omta_is("transform", { tx: 16 }, RunningOn.Compositor, 433 "anim2 + anim1, translate at 1s"); 434 omta_is("opacity", 0.2, RunningOn.Compositor, 435 "anim2 + anim1, opacity at 1s"); 436 advance_clock(1000); 437 omta_is("transform", { tx: 32 }, RunningOn.Compositor, 438 "anim2 + anim1, translate at 2s"); 439 omta_is("opacity", 0.4, RunningOn.Compositor, 440 "anim2 + anim1, opacity at 2s"); 441 // list anim2 twice, last duration wins, original start time still applies 442 gDiv.style.animation = "anim2 linear 5s, anim1 linear 10s, anim2 linear 20s"; 443 await waitForPaintsFlushed(); 444 omta_is("transform", { tx: 32 }, RunningOn.Compositor, 445 "anim2 + anim1 + anim2, translate at 2s"); 446 is(SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "opacity"), "0.1", 447 "anim2 + anim1 + anim2, opacity at 2s"); 448 // drop one of the anim2, and list anim3 as well, which animates 449 // the same property as anim2 450 gDiv.style.animation = "anim1 linear 10s, anim2 linear 20s, anim3 linear 10s"; 451 await waitForPaintsFlushed(); 452 omta_is("transform", { tx: 32 }, RunningOn.Compositor, 453 "anim1 + anim2 + anim3, translate at 2s"); 454 is(SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "opacity"), "0", 455 "anim1 + anim2 + anim3, opacity at 2s"); 456 advance_clock(1000); 457 omta_is("transform", { tx: 48 }, RunningOn.Compositor, 458 "anim1 + anim2 + anim3, translate at 3s"); 459 is(SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "opacity"), "0.1", 460 "anim1 + anim2 + anim3, opacity at 3s"); 461 // now swap the anim3 and anim2 order 462 gDiv.style.animation = "anim1 linear 10s, anim3 linear 10s, anim2 linear 20s"; 463 await waitForPaintsFlushed(); 464 omta_is("transform", { tx: 48 }, RunningOn.Compositor, 465 "anim1 + anim3 + anim2, translate at 3s"); 466 is(SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "opacity"), "0.15", 467 "anim1 + anim3 + anim2, opacity at 3s"); 468 advance_clock(2000); // (unlike test_animations.html, we seek 2s forwards here 469 // since at 4s anim2 and anim3 produce the same result so 470 // we can't tell which won.) 471 omta_is("transform", { tx: 80 }, RunningOn.Compositor, 472 "anim1 + anim3 + anim2, translate at 5s"); 473 is(SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "opacity"), "0.25", 474 "anim1 + anim3 + anim2, opacity at 5s"); 475 // swap anim3 and anim2 back 476 gDiv.style.animation = "anim1 linear 10s, anim2 linear 20s, anim3 linear 10s"; 477 await waitForPaintsFlushed(); 478 omta_is("transform", { tx: 80 }, RunningOn.Compositor, 479 "anim1 + anim2 + anim3, translate at 5s"); 480 is(SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "opacity"), "0.3", 481 "anim1 + anim2 + anim3, opacity at 5s"); 482 // seek past end of anim1 483 advance_clock(5100); 484 await waitForPaints(); 485 omta_is("transform", { tx: 0 }, RunningOn.MainThread, 486 "anim1 + anim2 + anim3, translate at 10.1s"); 487 // Change the animation fill mode on the completed animation. 488 gDiv.style.animation = 489 "anim1 linear 10s forwards, anim2 linear 20s, anim3 linear 10s"; 490 await waitForPaintsFlushed(); 491 omta_is("transform", { tx: 100 }, RunningOn.MainThread, 492 "anim1 + anim2 + anim3, translate at 10.1s with fill mode"); 493 advance_clock(900); 494 omta_is("transform", { tx: 100 }, RunningOn.MainThread, 495 "anim1 + anim2 + anim3, translate at 11s with fill mode"); 496 // Change the animation duration on the completed animation, so it is 497 // no longer completed. 498 // XXX Not sure about this---there seems to be a bug in test_animations.html 499 // in that it drops the fill mode but the test comment says it has a fill mode 500 gDiv.style.animation = "anim1 linear 20s, anim2 linear 20s, anim3 linear 10s"; 501 await waitForPaintsFlushed(); 502 omta_is("transform", { tx: 82 }, RunningOn.Compositor, 503 "anim1 + anim2 + anim3, translate at 11s with fill mode"); 504 is(SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "opacity"), "0.9", 505 "anim1 + anim2 + anim3, opacity at 11s"); 506 done_div(); 507 }); 508 509 /* 510 * css3-animations: 3. Keyframes 511 * http://dev.w3.org/csswg/css3-animations/#keyframes 512 */ 513 514 // Test the rules on keyframes that lack a 0% or 100% rule: 515 // (simultaneously, test that reverse animations have their keyframes 516 // run backwards) 517 518 addAsyncAnimTest(async function() { 519 // 100px at 0%, 50px at 50%, 150px at 100% 520 new_div("transform: translate(100px); " + 521 "animation: kf1 ease 1s alternate infinite"); 522 await waitForPaintsFlushed(); 523 omta_is("transform", { tx: 100 }, RunningOn.Compositor, "no-0% at 0.0s"); 524 advance_clock(100); 525 omta_is_approx("transform", { tx: 100 - 50 * gTF.ease(0.2) }, 0.01, 526 RunningOn.Compositor, "no-0% at 0.1s"); 527 advance_clock(200); 528 omta_is_approx("transform", { tx: 100 - 50 * gTF.ease(0.6) }, 0.01, 529 RunningOn.Compositor, "no-0% at 0.3s"); 530 advance_clock(200); 531 omta_is("transform", { tx: 50 }, RunningOn.Compositor, "no-0% at 0.5s"); 532 advance_clock(200); 533 omta_is_approx("transform", { tx: 50 + 100 * gTF.ease(0.4) }, 0.01, 534 RunningOn.Compositor, "no-0% at 0.7s"); 535 advance_clock(200); 536 omta_is_approx("transform", { tx: 50 + 100 * gTF.ease(0.8) }, 0.01, 537 RunningOn.Compositor, "no-0% at 0.9s"); 538 advance_clock(100); 539 omta_is("transform", { tx: 150 }, RunningOn.Compositor, "no-0% at 1.0s"); 540 advance_clock(100); 541 omta_is_approx("transform", { tx: 50 + 100 * gTF.ease(0.8) }, 0.01, 542 RunningOn.Compositor, "no-0% at 1.1s"); 543 advance_clock(300); 544 omta_is_approx("transform", { tx: 50 + 100 * gTF.ease(0.2) }, 0.01, 545 RunningOn.Compositor, "no-0% at 1.4s"); 546 advance_clock(300); 547 omta_is_approx("transform", { tx: 100 - 50 * gTF.ease(0.6) }, 0.01, 548 RunningOn.Compositor, "no-0% at 1.7s"); 549 advance_clock(200); 550 omta_is_approx("transform", { tx: 100 - 50 * gTF.ease(0.2) }, 0.01, 551 RunningOn.Compositor, "no-0% at 1.9s"); 552 advance_clock(100); 553 omta_is("transform", { tx: 100 }, RunningOn.Compositor, "no-0% at 2.0s"); 554 done_div(); 555 556 // 150px at 0%, 50px at 50%, 100px at 100% 557 new_div("transform: translate(100px); " + 558 "animation: kf2 ease-in 1s alternate infinite"); 559 await waitForPaintsFlushed(); 560 omta_is("transform", { tx: 150 }, RunningOn.Compositor, "no-100% at 0.0s"); 561 advance_clock(100); 562 omta_is_approx("transform", { tx: 150 - 100 * gTF.ease_in(0.2) }, 0.01, 563 RunningOn.Compositor, "no-100% at 0.1s"); 564 advance_clock(200); 565 omta_is_approx("transform", { tx: 150 - 100 * gTF.ease_in(0.6) }, 0.01, 566 RunningOn.Compositor, "no-100% at 0.3s"); 567 advance_clock(200); 568 omta_is("transform", { tx: 50 }, RunningOn.Compositor, "no-100% at 0.5s"); 569 advance_clock(200); 570 omta_is_approx("transform", { tx: 50 + 50 * gTF.ease_in(0.4) }, 0.01, 571 RunningOn.Compositor, "no-100% at 0.7s"); 572 advance_clock(200); 573 omta_is_approx("transform", { tx: 50 + 50 * gTF.ease_in(0.8) }, 0.01, 574 RunningOn.Compositor, "no-100% at 0.9s"); 575 advance_clock(100); 576 omta_is("transform", { tx: 100 }, RunningOn.Compositor, "no-100% at 1.0s"); 577 advance_clock(100); 578 omta_is_approx("transform", { tx: 50 + 50 * gTF.ease_in(0.8) }, 0.01, 579 RunningOn.Compositor, "no-100% at 1.1s"); 580 advance_clock(300); 581 omta_is_approx("transform", { tx: 50 + 50 * gTF.ease_in(0.2) }, 0.01, 582 RunningOn.Compositor, "no-100% at 1.4s"); 583 advance_clock(300); 584 omta_is_approx("transform", { tx: 150 - 100 * gTF.ease_in(0.6) }, 0.01, 585 RunningOn.Compositor, "no-100% at 1.7s"); 586 advance_clock(200); 587 omta_is_approx("transform", { tx: 150 - 100 * gTF.ease_in(0.2) }, 0.01, 588 RunningOn.Compositor, "no-100% at 1.9s"); 589 advance_clock(100); 590 omta_is("transform", { tx: 150 }, RunningOn.Compositor, "no-100% at 2.0s"); 591 done_div(); 592 593 // 50px at 0%, 100px at 25%, 50px at 100% 594 new_div("transform: translate(50px); " + 595 "animation: kf3 ease-out 1s alternate infinite"); 596 await waitForPaintsFlushed(); 597 omta_is("transform", { tx: 50 }, RunningOn.Compositor, 598 "no-0%-no-100% at 0.0s"); 599 advance_clock(50); 600 omta_is_approx("transform", { tx: 50 + 50 * gTF.ease_out(0.2) }, 0.01, 601 RunningOn.Compositor, "no-0%-no-100% at 0.05s"); 602 advance_clock(100); 603 omta_is_approx("transform", { tx: 50 + 50 * gTF.ease_out(0.6) }, 0.01, 604 RunningOn.Compositor, "no-0%-no-100% at 0.15s"); 605 advance_clock(100); 606 omta_is("transform", { tx: 100 }, RunningOn.Compositor, 607 "no-0%-no-100% at 0.25s"); 608 advance_clock(300); 609 omta_is_approx("transform", { tx: 100 - 50 * gTF.ease_out(0.4) }, 0.01, 610 RunningOn.Compositor, "no-0%-no-100% at 0.55s"); 611 advance_clock(300); 612 omta_is_approx("transform", { tx: 100 - 50 * gTF.ease_out(0.8) }, 0.01, 613 RunningOn.Compositor, "no-0%-no-100% at 0.85s"); 614 advance_clock(150); 615 omta_is("transform", { tx: 50 }, RunningOn.Compositor, 616 "no-0%-no-100% at 1.0s"); 617 advance_clock(150); 618 omta_is_approx("transform", { tx: 100 - 50 * gTF.ease_out(0.8) }, 0.01, 619 RunningOn.Compositor, "no-0%-no-100% at 1.15s"); 620 advance_clock(450); 621 omta_is_approx("transform", { tx: 100 - 50 * gTF.ease_out(0.2) }, 0.01, 622 RunningOn.Compositor, "no-0%-no-100% at 1.6s"); 623 advance_clock(250); 624 omta_is_approx("transform", { tx: 50 + 50 * gTF.ease_out(0.6) }, 0.01, 625 RunningOn.Compositor, "no-0%-no-100% at 1.85s"); 626 advance_clock(100); 627 omta_is_approx("transform", { tx: 50 + 50 * gTF.ease_out(0.2) }, 0.01, 628 RunningOn.Compositor, "no-0%-no-100% at 1.95s"); 629 advance_clock(50); 630 omta_is("transform", { tx: 50 }, RunningOn.Compositor, 631 "no-0%-no-100% at 2.0s"); 632 done_div(); 633 634 // Test that non-animatable properties are ignored. 635 // Simultaneously, test that the block is still honored, and that 636 // we still override the value when two consecutive keyframes have 637 // the same value. 638 new_div("animation: kf4 ease 10s"); 639 await waitForPaintsFlushed(); 640 var cs = window.getComputedStyle(gDiv); 641 is(cs.display, "block", 642 "non-animatable properties should be ignored (linear, 0s)"); 643 omta_is("transform", { tx: 37 }, RunningOn.Compositor, 644 "animatable properties should still apply (linear, 0s)"); 645 advance_clock(1000); 646 is(cs.display, "block", 647 "non-animatable properties should be ignored (linear, 1s)"); 648 omta_is("transform", { tx: 37 }, RunningOn.Compositor, 649 "animatable properties should still apply (linear, 1s)"); 650 done_div(); 651 new_div("animation: kf4 step-start 10s"); 652 await waitForPaintsFlushed(); 653 cs = window.getComputedStyle(gDiv); 654 is(cs.display, "block", 655 "non-animatable properties should be ignored (step-start, 0s)"); 656 omta_is("transform", { tx: 37 }, RunningOn.Compositor, 657 "animatable properties should still apply (step-start, 0s)"); 658 advance_clock(1000); 659 is(cs.display, "block", 660 "non-animatable properties should be ignored (step-start, 1s)"); 661 omta_is("transform", { tx: 37 }, RunningOn.Compositor, 662 "animatable properties should still apply (step-start, 1s)"); 663 done_div(); 664 665 // Test cascading of the keyframes within an @keyframes rule. 666 new_div("animation: kf_cascade1 linear 10s"); 667 await waitForPaintsFlushed(); 668 // 0%: 30px 669 // 50%: 20px 670 // 75%: 20px 671 // 85%: 30px 672 // 85.1%: 60px 673 // 100%: 70px 674 omta_is("transform", { tx: 30 }, RunningOn.Compositor, "kf_cascade1 at 0s"); 675 advance_clock(2500); 676 omta_is("transform", { tx: 25 }, RunningOn.Compositor, "kf_cascade1 at 2.5s"); 677 advance_clock(2500); 678 omta_is("transform", { tx: 20 }, RunningOn.Compositor, "kf_cascade1 at 5s"); 679 advance_clock(2000); 680 omta_is("transform", { tx: 20 }, RunningOn.Compositor, "kf_cascade1 at 7s"); 681 advance_clock(500); 682 omta_is("transform", { tx: 20 }, RunningOn.Compositor, "kf_cascade1 at 7.5s"); 683 advance_clock(500); 684 omta_is("transform", { tx: 25 }, RunningOn.Compositor, "kf_cascade1 at 8s"); 685 advance_clock(500); 686 omta_is("transform", { tx: 30 }, RunningOn.Compositor, "kf_cascade1 at 8.5s"); 687 advance_clock(10); 688 // For some reason we get an error of 0.0003 for this test only 689 omta_is_approx("transform", { tx: 60 }, 0.001, RunningOn.Compositor, 690 "kf_cascade1 at 8.51s"); 691 advance_clock(745); 692 omta_is("transform", { tx: 65 }, RunningOn.Compositor, 693 "kf_cascade1 at 9.2505s"); 694 done_div(); 695 696 // Test cascading of the @keyframes rules themselves. 697 new_div("animation: kf_cascade2 linear 10s"); 698 await waitForPaintsFlushed(); 699 omta_is("opacity", 1, RunningOn.MainThread, 700 "last @keyframes rule with transform should win"); 701 omta_is("transform", { tx: 100 }, RunningOn.Compositor, 702 "last @keyframes rule with transform should win"); 703 done_div(); 704 }); 705 706 /* 707 * css3-animations: 3.1. Timing functions for keyframes 708 * http://dev.w3.org/csswg/css3-animations/#timing-functions-for-keyframes- 709 */ 710 711 addAsyncAnimTest(async function() { 712 new_div("animation: kf_tf1 ease-in 10s alternate infinite"); 713 await waitForPaintsFlushed(); 714 omta_is("transform", { tx: 20 }, RunningOn.Compositor, 715 "keyframe timing functions test at 0s (test needed for flush)"); 716 advance_clock(1000); 717 omta_is_approx("transform", { tx: 20 + 40 * gTF.ease(0.4) }, 0.01, 718 RunningOn.Compositor, "keyframe timing functions test at 1s"); 719 advance_clock(1000); 720 omta_is_approx("transform", { tx: 20 + 40 * gTF.ease(0.8) }, 0.01, 721 RunningOn.Compositor, "keyframe timing functions test at 2s"); 722 advance_clock(1000); 723 omta_is_approx("transform", { tx: 60 + 100 * gTF.ease_in(0.2) }, 0.01, 724 RunningOn.Compositor, "keyframe timing functions test at 3s"); 725 advance_clock(1000); 726 omta_is_approx("transform", { tx: 60 + 100 * gTF.ease_in(0.6) }, 0.01, 727 RunningOn.Compositor, "keyframe timing functions test at 4s"); 728 advance_clock(1000); 729 omta_is("transform", { tx: 160 }, RunningOn.Compositor, 730 "keyframe timing functions test at 5s"); 731 advance_clock(1010); // avoid floating-point error 732 omta_is_approx("transform", { tx: 160 - 40 * step_end(5)(0.4) }, 0.01, 733 RunningOn.Compositor, "keyframe timing functions test at 6s"); 734 advance_clock(1000); 735 omta_is_approx("transform", { tx: 160 - 40 * step_end(5)(0.8) }, 0.01, 736 RunningOn.Compositor, "keyframe timing functions test at 7s"); 737 advance_clock(990); 738 omta_is_approx("transform", { tx: 120 - 100 * gTF.linear(0.2) }, 0.01, 739 RunningOn.Compositor, "keyframe timing functions test at 8s"); 740 advance_clock(1000); 741 omta_is_approx("transform", { tx: 120 - 100 * gTF.linear(0.6) }, 0.01, 742 RunningOn.Compositor, "keyframe timing functions test at 9s"); 743 advance_clock(1000); 744 omta_is("transform", { tx: 20 }, RunningOn.Compositor, 745 "keyframe timing functions test at 10s"); 746 advance_clock(20000); 747 omta_is("transform", { tx: 20 }, RunningOn.Compositor, 748 "keyframe timing functions test at 30s"); 749 advance_clock(1000); 750 omta_is_approx("transform", { tx: 120 - 100 * gTF.linear(0.6) }, 0.01, 751 RunningOn.Compositor, 752 "keyframe timing functions test at 31s"); 753 advance_clock(1000); 754 omta_is_approx("transform", { tx: 120 - 100 * gTF.linear(0.2) }, 0.01, 755 RunningOn.Compositor, 756 "keyframe timing functions test at 32s"); 757 advance_clock(990); // avoid floating-point error 758 omta_is_approx("transform", { tx: 160 - 40 * step_end(5)(0.8) }, 0.01, 759 RunningOn.Compositor, 760 "keyframe timing functions test at 33s"); 761 advance_clock(1000); 762 omta_is_approx("transform", { tx: 160 - 40 * step_end(5)(0.4) }, 0.01, 763 RunningOn.Compositor, 764 "keyframe timing functions test at 34s"); 765 advance_clock(1010); 766 omta_is("transform", { tx: 160 }, RunningOn.Compositor, 767 "keyframe timing functions test at 35s"); 768 advance_clock(1000); 769 omta_is_approx("transform", { tx: 60 + 100 * gTF.ease_in(0.6) }, 0.01, 770 RunningOn.Compositor, 771 "keyframe timing functions test at 36s"); 772 advance_clock(1000); 773 omta_is_approx("transform", { tx: 60 + 100 * gTF.ease_in(0.2) }, 0.01, 774 RunningOn.Compositor, 775 "keyframe timing functions test at 37s"); 776 advance_clock(1000); 777 omta_is_approx("transform", { tx: 20 + 40 * gTF.ease(0.8) }, 0.01, 778 RunningOn.Compositor, 779 "keyframe timing functions test at 38s"); 780 advance_clock(1000); 781 omta_is_approx("transform", { tx: 20 + 40 * gTF.ease(0.4) }, 0.01, 782 RunningOn.Compositor, 783 "keyframe timing functions test at 39s"); 784 advance_clock(1000); 785 omta_is("transform", { tx: 20 }, RunningOn.Compositor, 786 "keyframe timing functions test at 40s"); 787 done_div(); 788 789 // spot-check the same thing without alternate 790 new_div("animation: kf_tf1 ease-in 10s infinite"); 791 await waitForPaintsFlushed(); 792 omta_is("transform", { tx: 20 }, RunningOn.Compositor, 793 "keyframe timing functions test at 0s (test needed for flush)"); 794 advance_clock(11000); 795 omta_is_approx("transform", { tx: 20 + 40 * gTF.ease(0.4) }, 0.01, 796 RunningOn.Compositor, 797 "keyframe timing functions test at 11s"); 798 advance_clock(3000); 799 omta_is_approx("transform", { tx: 60 + 100 * gTF.ease_in(0.6) }, 0.01, 800 RunningOn.Compositor, 801 "keyframe timing functions test at 14s"); 802 advance_clock(2010); // avoid floating-point error 803 omta_is_approx("transform", { tx: 160 - 40 * step_end(5)(0.4) }, 0.01, 804 RunningOn.Compositor, 805 "keyframe timing functions test at 16s"); 806 advance_clock(1990); 807 omta_is_approx("transform", { tx: 120 - 100 * gTF.linear(0.2) }, 0.01, 808 RunningOn.Compositor, 809 "keyframe timing functions test at 18s"); 810 done_div(); 811 }); 812 813 /* 814 * css3-animations: 3.2. The 'animation-name' Property 815 * http://dev.w3.org/csswg/css3-animations/#the-animation-name-property- 816 */ 817 818 // animation-name is reasonably well-tested up in the tests for Section 819 // 2, particularly the tests that "Test that animations continue running 820 // when the animation name list is changed." 821 822 // Test that 'animation-name: none' stops the animation, and setting 823 // it again starts a new one. 824 825 addAsyncAnimTest(async function() { 826 new_div("animation: anim2 ease-in-out 10s"); 827 await waitForPaintsFlushed(); 828 omta_is("opacity", 0, RunningOn.Compositor, 829 "after setting animation-name to anim2"); 830 advance_clock(1000); 831 omta_is_approx("opacity", gTF.ease_in_out(0.1), 0.01, RunningOn.Compositor, 832 "before changing animation-name to none"); 833 gDiv.style.animationName = "none"; 834 await waitForPaintsFlushed(); 835 omta_is("opacity", 1, RunningOn.MainThread, 836 "after changing animation-name to none"); 837 advance_clock(1000); 838 omta_is("opacity", 1, RunningOn.MainThread, 839 "after changing animation-name to none plus 1s"); 840 gDiv.style.animationName = "anim2"; 841 await waitForPaintsFlushed(); 842 omta_is("opacity", 0, RunningOn.Compositor, 843 "after changing animation-name to anim2"); 844 advance_clock(1000); 845 omta_is_approx("opacity", gTF.ease_in_out(0.1), 0.01, RunningOn.Compositor, 846 "at 1s in animation when animation-name no longer none again"); 847 gDiv.style.animationName = "none"; 848 await waitForPaintsFlushed(); 849 omta_is("opacity", 1, RunningOn.MainThread, 850 "after changing animation-name to none"); 851 advance_clock(1000); 852 omta_is("opacity", 1, RunningOn.MainThread, 853 "after changing animation-name to none plus 1s"); 854 done_div(); 855 }); 856 857 /* 858 * css3-animations: 3.3. The 'animation-duration' Property 859 * http://dev.w3.org/csswg/css3-animations/#the-animation-duration-property- 860 */ 861 862 // FIXME: test animation-duration of 0 (quite a bit, including interaction 863 // with fill-mode, count, and reversing), once I know what the right 864 // behavior is. 865 866 /* 867 * css3-animations: 3.4. The 'animation-timing-function' Property 868 * http://dev.w3.org/csswg/css3-animations/#animation-timing-function_tag 869 */ 870 871 // tested in tests for section 3.1 872 873 /* 874 * css3-animations: 3.5. The 'animation-iteration-count' Property 875 * http://dev.w3.org/csswg/css3-animations/#the-animation-iteration-count-property- 876 */ 877 addAsyncAnimTest(async function() { 878 new_div("animation: anim2 ease-in 10s 0.3 forwards"); 879 await waitForPaintsFlushed(); 880 omta_is("opacity", 0, RunningOn.Compositor, 881 "animation-iteration-count test 1 at 0s"); 882 advance_clock(2000); 883 omta_is_approx("opacity", gTF.ease_in(0.2), 0.01, RunningOn.Compositor, 884 "animation-iteration-count test 1 at 2s"); 885 advance_clock(900); 886 omta_is_approx("opacity", gTF.ease_in(0.29), 0.01, RunningOn.Compositor, 887 "animation-iteration-count test 1 at 2.9s"); 888 advance_clock(100); 889 // Animation has reached the end so allow it to be cleared from the compositor 890 await waitForPaints(); 891 // For transform animations we can tell whether a transform on the compositor 892 // thread was set by animation or not since there is a special flag for it. 893 // 894 // For opacity animations, however, there is no such flag so we'll get an 895 // "OMTA" opacity even when it wasn't set by animation. When we pause an 896 // opacity animation we don't worry about where it is reported to be running 897 // (main thread or compositor) so long as the result is correct, hence we 898 // check for "either" below. 899 omta_is_approx("opacity", gTF.ease_in(0.3), 0.01, RunningOn.Either, 900 "animation-iteration-count test 1 at 3s"); 901 advance_clock(100); 902 omta_is_approx("opacity", gTF.ease_in(0.3), 0.01, RunningOn.Either, 903 "animation-iteration-count test 1 at 3.1s"); 904 advance_clock(5000); 905 omta_is_approx("opacity", gTF.ease_in(0.3), 0.01, RunningOn.Either, 906 "animation-iteration-count test 1 at 8.1s"); 907 done_div(); 908 909 // The corresponding test in test_animations.html runs three animations in 910 // parallel but since we only have two properties that are OMTA-enabled at 911 // this time and no additive animation we split this test into two parts. 912 new_div("animation: anim2 ease-in 10s 0.3, " + 913 "anim4 ease-out 20s 1.2 alternate forwards"); 914 await waitForPaintsFlushed(); 915 omta_is("opacity", 0, RunningOn.Compositor, 916 "animation-iteration-count test 2 at 0s"); 917 omta_is("transform", { ty: 0 }, RunningOn.Compositor, 918 "animation-iteration-count test 3 at 0s"); 919 advance_clock(2000); 920 omta_is_approx("opacity", gTF.ease_in(0.2), 0.01, RunningOn.Compositor, 921 "animation-iteration-count test 2 at 2s"); 922 omta_is_approx("transform", { ty: 100 * gTF.ease_out(0.1) }, 0.01, 923 RunningOn.Compositor, 924 "animation-iteration-count test 3 at 2s"); 925 advance_clock(900); 926 omta_is_approx("opacity", gTF.ease_in(0.29), 0.01, RunningOn.Compositor, 927 "animation-iteration-count test 2 at 2.9s"); 928 advance_clock(200); 929 await waitForPaints(); 930 omta_is("opacity", 1, RunningOn.Either, 931 "animation-iteration-count test 2 at 3.1s"); 932 advance_clock(2000); 933 omta_is("opacity", 1, RunningOn.Either, 934 "animation-iteration-count test 2 at 5.1s"); 935 advance_clock(14700); 936 omta_is_approx("transform", { ty: 100 * gTF.ease_out(0.99) }, 0.01, 937 RunningOn.Compositor, 938 "animation-iteration-count test 3 at 19.8s"); 939 advance_clock(200); 940 omta_is("transform", { ty: 100 }, RunningOn.Compositor, 941 "animation-iteration-count test 3 at 20s"); 942 advance_clock(200); 943 omta_is_approx("transform", { ty: 100 * gTF.ease_out(0.99) }, 0.01, 944 RunningOn.Compositor, 945 "animation-iteration-count test 3 at 20.2s"); 946 advance_clock(3600); 947 omta_is_approx("transform", { ty: 100 * gTF.ease_out(0.81) }, 0.01, 948 RunningOn.Compositor, 949 "animation-iteration-count test 3 at 23.8s"); 950 advance_clock(200); 951 omta_is_approx("transform", { ty: 100 * gTF.ease_out(0.8) }, 0.01, 952 RunningOn.Compositor, 953 "animation-iteration-count test 3 at 24s"); 954 advance_clock(200); 955 await waitForPaints(); 956 omta_is("opacity", 1, RunningOn.Either, 957 "animation-iteration-count test 2 at 25s"); 958 omta_is_approx("transform", { ty: 100 * gTF.ease_out(0.8) }, 0.01, 959 RunningOn.MainThread, 960 "animation-iteration-count test 3 at 25s"); 961 done_div(); 962 963 new_div("animation: anim4 ease-in-out 5s 1.6 forwards"); 964 await waitForPaintsFlushed(); 965 omta_is("transform", { ty: 0 }, RunningOn.Compositor, 966 "animation-iteration-count test 4 at 0s"); 967 advance_clock(2000); 968 omta_is_approx("transform", { ty: 100 * gTF.ease_in_out(0.4) }, 0.01, 969 RunningOn.Compositor, 970 "animation-iteration-count test 4 at 2s"); 971 advance_clock(2900); 972 omta_is_approx("transform", { ty: 100 * gTF.ease_in_out(0.98) }, 0.01, 973 RunningOn.Compositor, 974 "animation-iteration-count test 4 at 4.9s"); 975 advance_clock(200); 976 omta_is_approx("transform", { ty: 100 * gTF.ease_in_out(0.02) }, 0.01, 977 RunningOn.Compositor, 978 "animation-iteration-count test 4 at 5.1s"); 979 advance_clock(2800); 980 omta_is_approx("transform", { ty: 100 * gTF.ease_in_out(0.58) }, 0.01, 981 RunningOn.Compositor, 982 "animation-iteration-count test 4 at 7.9s"); 983 advance_clock(100); 984 omta_is_approx("transform", { ty: 100 * gTF.ease_in_out(0.6) }, 0.01, 985 RunningOn.Compositor, 986 "animation-iteration-count test 4 at 8s"); 987 advance_clock(100); 988 await waitForPaints(); 989 omta_is_approx("transform", { ty: 100 * gTF.ease_in_out(0.6) }, 0.01, 990 RunningOn.Either, 991 "animation-iteration-count test 4 at 8.1s"); 992 advance_clock(16100); 993 omta_is_approx("transform", { ty: 100 * gTF.ease_in_out(0.6) }, 0.01, 994 RunningOn.Either, 995 "animation-iteration-count test 4 at 25s"); 996 done_div(); 997 }); 998 999 /* 1000 * css3-animations: 3.6. The 'animation-direction' Property 1001 * http://dev.w3.org/csswg/css3-animations/#the-animation-direction-property- 1002 */ 1003 1004 // Tested in tests for sections 3.1 and 3.5. 1005 1006 addAsyncAnimTest(async function() { 1007 new_div("animation: anim2 ease-in 10s infinite"); 1008 gDiv.style.animationDirection = "normal"; 1009 await waitForPaintsFlushed(); 1010 omta_is("opacity", 0, RunningOn.Compositor, 1011 "animation-direction test 1 (normal) at 0s"); 1012 gDiv.style.animationDirection = "reverse"; 1013 await waitForPaintsFlushed(); 1014 omta_is("opacity", 1, RunningOn.Compositor, 1015 "animation-direction test 1 (reverse) at 0s"); 1016 gDiv.style.animationDirection = "alternate"; 1017 await waitForPaintsFlushed(); 1018 omta_is("opacity", 0, RunningOn.Compositor, 1019 "animation-direction test 1 (alternate) at 0s"); 1020 gDiv.style.animationDirection = "alternate-reverse"; 1021 await waitForPaintsFlushed(); 1022 omta_is("opacity", 1, RunningOn.Compositor, 1023 "animation-direction test 1 (alternate-reverse) at 0s"); 1024 advance_clock(2000); 1025 gDiv.style.animationDirection = "normal"; 1026 await waitForPaintsFlushed(); 1027 omta_is_approx("opacity", gTF.ease_in(0.2), 0.01, RunningOn.Compositor, 1028 "animation-direction test 1 (normal) at 2s"); 1029 gDiv.style.animationDirection = "reverse"; 1030 await waitForPaintsFlushed(); 1031 omta_is_approx("opacity", gTF.ease_in(0.8), 0.01, RunningOn.Compositor, 1032 "animation-direction test 1 (reverse) at 2s"); 1033 gDiv.style.animationDirection = "alternate"; 1034 await waitForPaintsFlushed(); 1035 omta_is_approx("opacity", gTF.ease_in(0.2), 0.01, RunningOn.Compositor, 1036 "animation-direction test 1 (alternate) at 2s"); 1037 gDiv.style.animationDirection = "alternate-reverse"; 1038 await waitForPaintsFlushed(); 1039 omta_is_approx("opacity", gTF.ease_in(0.8), 0.01, RunningOn.Compositor, 1040 "animation-direction test 1 (alternate-reverse) at 2s"); 1041 advance_clock(5000); 1042 gDiv.style.animationDirection = "normal"; 1043 await waitForPaintsFlushed(); 1044 omta_is_approx("opacity", gTF.ease_in(0.7), 0.01, RunningOn.Compositor, 1045 "animation-direction test 1 (normal) at 7s"); 1046 gDiv.style.animationDirection = "reverse"; 1047 await waitForPaintsFlushed(); 1048 omta_is_approx("opacity", gTF.ease_in(0.3), 0.01, RunningOn.Compositor, 1049 "animation-direction test 1 (reverse) at 7s"); 1050 gDiv.style.animationDirection = "alternate"; 1051 await waitForPaintsFlushed(); 1052 omta_is_approx("opacity", gTF.ease_in(0.7), 0.01, RunningOn.Compositor, 1053 "animation-direction test 1 (alternate) at 7s"); 1054 gDiv.style.animationDirection = "alternate-reverse"; 1055 await waitForPaintsFlushed(); 1056 omta_is_approx("opacity", gTF.ease_in(0.3), 0.01, RunningOn.Compositor, 1057 "animation-direction test 1 (alternate-reverse) at 7s"); 1058 advance_clock(5000); 1059 gDiv.style.animationDirection = "normal"; 1060 await waitForPaintsFlushed(); 1061 omta_is_approx("opacity", gTF.ease_in(0.2), 0.01, RunningOn.Compositor, 1062 "animation-direction test 1 (normal) at 12s"); 1063 gDiv.style.animationDirection = "reverse"; 1064 await waitForPaintsFlushed(); 1065 omta_is_approx("opacity", gTF.ease_in(0.8), 0.01, RunningOn.Compositor, 1066 "animation-direction test 1 (reverse) at 12s"); 1067 gDiv.style.animationDirection = "alternate"; 1068 await waitForPaintsFlushed(); 1069 omta_is_approx("opacity", gTF.ease_in(0.8), 0.01, RunningOn.Compositor, 1070 "animation-direction test 1 (alternate) at 12s"); 1071 gDiv.style.animationDirection = "alternate-reverse"; 1072 await waitForPaintsFlushed(); 1073 omta_is_approx("opacity", gTF.ease_in(0.2), 0.01, RunningOn.Compositor, 1074 "animation-direction test 1 (alternate-reverse) at 12s"); 1075 advance_clock(10000); 1076 gDiv.style.animationDirection = "normal"; 1077 await waitForPaintsFlushed(); 1078 omta_is_approx("opacity", gTF.ease_in(0.2), 0.01, RunningOn.Compositor, 1079 "animation-direction test 1 (normal) at 22s"); 1080 gDiv.style.animationDirection = "reverse"; 1081 await waitForPaintsFlushed(); 1082 omta_is_approx("opacity", gTF.ease_in(0.8), 0.01, RunningOn.Compositor, 1083 "animation-direction test 1 (reverse) at 22s"); 1084 gDiv.style.animationDirection = "alternate"; 1085 await waitForPaintsFlushed(); 1086 omta_is_approx("opacity", gTF.ease_in(0.2), 0.01, RunningOn.Compositor, 1087 "animation-direction test 1 (alternate) at 22s"); 1088 gDiv.style.animationDirection = "alternate-reverse"; 1089 await waitForPaintsFlushed(); 1090 omta_is_approx("opacity", gTF.ease_in(0.8), 0.01, RunningOn.Compositor, 1091 "animation-direction test 1 (alternate-reverse) at 22s"); 1092 advance_clock(30000); 1093 gDiv.style.animationDirection = "normal"; 1094 await waitForPaintsFlushed(); 1095 omta_is_approx("opacity", gTF.ease_in(0.2), 0.01, RunningOn.Compositor, 1096 "animation-direction test 1 (normal) at 52s"); 1097 gDiv.style.animationDirection = "reverse"; 1098 await waitForPaintsFlushed(); 1099 omta_is_approx("opacity", gTF.ease_in(0.8), 0.01, RunningOn.Compositor, 1100 "animation-direction test 1 (reverse) at 52s"); 1101 gDiv.style.animationDirection = "alternate"; 1102 await waitForPaintsFlushed(); 1103 omta_is_approx("opacity", gTF.ease_in(0.8), 0.01, RunningOn.Compositor, 1104 "animation-direction test 1 (alternate) at 52s"); 1105 gDiv.style.animationDirection = "alternate-reverse"; 1106 await waitForPaintsFlushed(); 1107 omta_is_approx("opacity", gTF.ease_in(0.2), 0.01, RunningOn.Compositor, 1108 "animation-direction test 1 (alternate-reverse) at 52s"); 1109 done_div(); 1110 }); 1111 1112 /* 1113 * css3-animations: 3.7. The 'animation-play-state' Property 1114 * http://dev.w3.org/csswg/css3-animations/#the-animation-play-state-property- 1115 */ 1116 1117 addAsyncAnimTest(async function() { 1118 // simple test with just one animation 1119 new_div(""); 1120 gDiv.style.animationTimingFunction = "ease"; 1121 gDiv.style.animationName = "anim1"; 1122 gDiv.style.animationDuration = "1s"; 1123 gDiv.style.animationDirection = "alternate"; 1124 gDiv.style.animationIterationCount = "2"; 1125 await waitForPaintsFlushed(); 1126 omta_is("transform", { tx: 0 }, RunningOn.Compositor, 1127 "animation-play-state test 1, at 0s"); 1128 advance_clock(250); 1129 omta_is_approx("transform", { tx: 80 * gTF.ease(0.5) }, 0.01, 1130 RunningOn.Compositor, 1131 "animation-play-state test 1 at 250ms"); 1132 gDiv.style.animationPlayState = "paused"; 1133 await waitForPaintsFlushed(); 1134 omta_is_approx("transform", { tx: 80 * gTF.ease(0.5) }, 0.01, 1135 RunningOn.MainThread, 1136 "animation-play-state test 1 at 250ms"); 1137 advance_clock(250); 1138 omta_is_approx("transform", { tx: 80 * gTF.ease(0.5) }, 0.01, 1139 RunningOn.MainThread, 1140 "animation-play-state test 1 still at 500ms"); 1141 gDiv.style.animationPlayState = "running"; 1142 await waitForPaintsFlushed(); 1143 omta_is_approx("transform", { tx: 80 * gTF.ease(0.5) }, 0.01, 1144 RunningOn.Compositor, 1145 "animation-play-state test 1 still at 500ms"); 1146 advance_clock(500); 1147 omta_is_approx("transform", { tx: 80 + 20 * gTF.ease(0.5) }, 0.01, 1148 RunningOn.Compositor, 1149 "animation-play-state test 1 at 1000ms"); 1150 advance_clock(250); 1151 omta_is("transform", { tx: 100 }, RunningOn.Compositor, 1152 "animation-play-state test 1 at 1250ms"); 1153 advance_clock(250); 1154 omta_is_approx("transform", { tx: 80 + 20 * gTF.ease(0.5) }, 0.01, 1155 RunningOn.Compositor, 1156 "animation-play-state test 1 at 1500ms"); 1157 gDiv.style.animationPlayState = "paused"; 1158 await waitForPaintsFlushed(); 1159 omta_is_approx("transform", { tx: 80 + 20 * gTF.ease(0.5) }, 0.01, 1160 RunningOn.MainThread, 1161 "animation-play-state test 1 at 1500ms"); 1162 advance_clock(2000); 1163 omta_is_approx("transform", { tx: 80 + 20 * gTF.ease(0.5) }, 0.01, 1164 RunningOn.MainThread, 1165 "animation-play-state test 1 at 3500ms"); 1166 advance_clock(500); 1167 omta_is_approx("transform", { tx: 80 + 20 * gTF.ease(0.5) }, 0.01, 1168 RunningOn.MainThread, 1169 "animation-play-state test 1 at 4000ms"); 1170 gDiv.style.animationPlayState = ""; 1171 await waitForPaintsFlushed(); 1172 omta_is_approx("transform", { tx: 80 + 20 * gTF.ease(0.5) }, 0.01, 1173 RunningOn.Compositor, 1174 "animation-play-state test 1 at 4000ms"); 1175 advance_clock(500); 1176 omta_is_approx("transform", { tx: 80 * gTF.ease(0.5) }, 0.01, 1177 RunningOn.Compositor, 1178 "animation-play-state test 1 at 4500ms"); 1179 advance_clock(250); 1180 await waitForPaintsFlushed(); 1181 omta_is("transform", { tx: 0 }, RunningOn.MainThread, 1182 "animation-play-state test 1, at 4750ms"); 1183 advance_clock(250); 1184 omta_is("transform", { tx: 0 }, RunningOn.MainThread, 1185 "animation-play-state test 1, at 5000ms"); 1186 done_div(); 1187 1188 // The corresponding test in test_animations.html tests various cases of 1189 // pausing individual animations in a list of three different animations 1190 // but since there are only two OMTA properties we can animate 1191 // independently this test is substantially simpler. 1192 new_div(""); 1193 gDiv.style.animationTimingFunction = "ease-out, ease-in"; 1194 gDiv.style.animationName = "anim2, anim4"; 1195 gDiv.style.animationDuration = "1s, 2s"; 1196 gDiv.style.animationDirection = "alternate, normal"; 1197 gDiv.style.animationIterationCount = "4, 2"; 1198 await waitForPaintsFlushed(); 1199 omta_is("opacity", 0, RunningOn.Compositor, 1200 "animation-play-state test 2, at 0s"); 1201 omta_is("transform", { ty: 0 }, RunningOn.Compositor, 1202 "animation-play-state test 3, at 0s"); 1203 advance_clock(250); 1204 gDiv.style.animationPlayState = "paused, running"; // pause 1 1205 await waitForPaintsFlushed(); 1206 // As noted with the tests for animation-iteration-count, for opacity 1207 // animations we don't strictly check the finished animation is being animated 1208 // on the main thread, but simply that it is producing the correct result. 1209 omta_is_approx("opacity", gTF.ease_out(0.25), 0.01, RunningOn.MainThread, 1210 "animation-play-state test 2 at 250ms"); // paused 1211 omta_is_approx("transform", { ty: 100 * gTF.ease_in(0.125) }, 0.01, 1212 RunningOn.Compositor, 1213 "animation-play-state test 3 at 250ms"); 1214 advance_clock(250); 1215 omta_is_approx("opacity", gTF.ease_out(0.25), 0.01, RunningOn.MainThread, 1216 "animation-play-state test 2 at 500ms"); // paused 1217 omta_is_approx("transform", { ty: 100 * gTF.ease_in(0.25) }, 0.01, 1218 RunningOn.Compositor, 1219 "animation-play-state test 3 at 500ms"); 1220 advance_clock(250); 1221 gDiv.style.animationPlayState = "running, paused"; // unpause 1, pause 2 1222 await waitForPaintsFlushed(); 1223 advance_clock(250); 1224 omta_is_approx("opacity", gTF.ease_out(0.5), 0.01, RunningOn.Compositor, 1225 "animation-play-state test 2 at 1000ms"); 1226 omta_is_approx("transform", { ty: 100 * gTF.ease_in(0.375) }, 0.01, 1227 RunningOn.MainThread, 1228 "animation-play-state test 3 at 1000ms"); // paused 1229 gDiv.style.animationPlayState = "paused"; // pause all 1230 await waitForPaintsFlushed(); 1231 advance_clock(3000); 1232 omta_is_approx("opacity", gTF.ease_out(0.5), 0.01, RunningOn.MainThread, 1233 "animation-play-state test 2 at 4000ms"); // paused 1234 omta_is_approx("transform", { ty: 100 * gTF.ease_in(0.375) }, 0.01, 1235 RunningOn.MainThread, 1236 "animation-play-state test 3 at 4000ms"); // paused 1237 gDiv.style.animationPlayState = "running, paused"; // pause 2 1238 await waitForPaintsFlushed(); 1239 advance_clock(850); 1240 omta_is_approx("opacity", gTF.ease_out(0.65), 0.01, RunningOn.Compositor, 1241 "animation-play-state test 2 at 4850ms"); 1242 omta_is_approx("transform", { ty: 100 * gTF.ease_in(0.375) }, 0.01, 1243 RunningOn.MainThread, 1244 "animation-play-state test 3 at 4850ms"); 1245 advance_clock(300); 1246 omta_is_approx("opacity", gTF.ease_out(0.35), 0.01, RunningOn.Compositor, 1247 "animation-play-state test 2 at 5150ms"); 1248 omta_is_approx("transform", { ty: 100 * gTF.ease_in(0.375) }, 0.01, 1249 RunningOn.MainThread, 1250 "animation-play-state test 3 at 5150ms"); 1251 advance_clock(2300); 1252 omta_is_approx("opacity", gTF.ease_out(0.05), 0.01, RunningOn.Compositor, 1253 "animation-play-state test 2 at 7450ms"); 1254 omta_is_approx("transform", { ty: 100 * gTF.ease_in(0.375) }, 0.01, 1255 RunningOn.MainThread, 1256 "animation-play-state test 3 at 7450ms"); 1257 advance_clock(100); 1258 // test 2 has finished so wait for it to be removed from the 1259 // compositor (otherwise it will fill forwards) 1260 await waitForPaints(); 1261 omta_is("opacity", 1, RunningOn.Either, 1262 "animation-play-state test 2 at 7550ms"); 1263 omta_is_approx("transform", { ty: 100 * gTF.ease_in(0.375) }, 0.01, 1264 RunningOn.MainThread, 1265 "animation-play-state test 3 at 7550ms"); 1266 gDiv.style.animationPlayState = "running"; // unpause 2 1267 await waitForPaintsFlushed(); 1268 advance_clock(1000); 1269 omta_is("opacity", 1, RunningOn.Either, 1270 "animation-play-state test 2 at 7550ms"); 1271 omta_is_approx("transform", { ty: 100 * gTF.ease_in(0.875) }, 0.01, 1272 RunningOn.Compositor, 1273 "animation-play-state test 3 at 7550ms"); 1274 advance_clock(500); 1275 omta_is("opacity", 1, RunningOn.Either, 1276 "animation-play-state test 2 at 8050ms"); 1277 omta_is_approx("transform", { ty: 100 * gTF.ease_in(0.125) }, 0.01, 1278 RunningOn.Compositor, 1279 "animation-play-state test 3 at 8050ms"); 1280 advance_clock(1000); 1281 omta_is("opacity", 1, RunningOn.Either, 1282 "animation-play-state test 2 at 9050ms"); 1283 omta_is_approx("transform", { ty: 100 * gTF.ease_in(0.625) }, 0.01, 1284 RunningOn.Compositor, 1285 "animation-play-state test 3 at 9050ms"); 1286 advance_clock(500); 1287 omta_is("opacity", 1, RunningOn.Either, 1288 "animation-play-state test 2 at 9550ms"); 1289 omta_is_approx("transform", { ty: 100 * gTF.ease_in(0.875) }, 0.01, 1290 RunningOn.Compositor, 1291 "animation-play-state test 3 at 9550ms"); 1292 advance_clock(500); 1293 await waitForPaints(); 1294 omta_is("opacity", 1, RunningOn.Either, 1295 "animation-play-state test 2 at 10050ms"); 1296 omta_is("transform", { ty: 0 }, RunningOn.MainThread, 1297 "animation-play-state test 3 at 10050ms"); 1298 done_div(); 1299 }); 1300 1301 /* 1302 * css3-animations: 3.8. The 'animation-delay' Property 1303 * http://dev.w3.org/csswg/css3-animations/#the-animation-delay-property- 1304 */ 1305 1306 addAsyncAnimTest(async function() { 1307 // test positive delay 1308 new_div("animation: anim2 1s 0.5s ease-out"); 1309 await waitForPaintsFlushed(); 1310 // NOTE: getOMTAStyle() can't detect the animation is running on the 1311 // compositor or not during the delay phase, since no opacity style is 1312 // applied during the delay phase. 1313 omta_is("opacity", 1, RunningOn.Either, "positive delay test at 0ms"); 1314 advance_clock(400); 1315 omta_is("opacity", 1, RunningOn.Either, "positive delay test at 400ms"); 1316 advance_clock(100); 1317 await waitForPaints(); 1318 omta_is("opacity", 0, RunningOn.Compositor, "positive delay test at 500ms"); 1319 advance_clock(100); 1320 omta_is_approx("opacity", gTF.ease_out(0.1), 0.01, RunningOn.Compositor, 1321 "positive delay test at 500ms"); 1322 done_div(); 1323 1324 // test dynamic changes to delay (i.e., that we preserve the start time 1325 // that's before the delay) 1326 new_div("animation: anim2 1s 0.5s ease-out both"); 1327 await waitForPaintsFlushed(); 1328 // NOTE: As noted above, getOMTAStyle() can't detect the animation is running 1329 // on the compositor during the delay phase. 1330 omta_is("opacity", 0, RunningOn.Either, "dynamic delay delay test at 0ms"); 1331 advance_clock(400); 1332 omta_is("opacity", 0, RunningOn.Either, 1333 "dynamic delay delay test at 400ms (1)"); 1334 gDiv.style.animationDelay = "0.2s"; 1335 await waitForPaintsFlushed(); 1336 omta_is_approx("opacity", gTF.ease_out(0.2), 0.01, RunningOn.Compositor, 1337 "dynamic delay delay test at 400ms (2)"); 1338 gDiv.style.animationDelay = "0.6s"; 1339 await waitForPaintsFlushed(); 1340 advance_clock(200); 1341 omta_is("opacity", 0, RunningOn.Either, "dynamic delay delay test at 600ms"); 1342 advance_clock(200); 1343 await waitForPaints(); 1344 omta_is_approx("opacity", gTF.ease_out(0.2), 0.01, RunningOn.Compositor, 1345 "dynamic delay delay test at 800ms"); 1346 advance_clock(1000); 1347 await waitForPaints(); 1348 omta_is("opacity", 1, RunningOn.Either, 1349 "dynamic delay delay test at 1800ms (1)"); 1350 gDiv.style.animationDelay = "1.5s"; 1351 await waitForPaintsFlushed(); 1352 omta_is_approx("opacity", gTF.ease_out(0.3), 0.01, RunningOn.Compositor, 1353 "dynamic delay delay test at 1800ms (2)"); 1354 gDiv.style.animationDelay = "2s"; 1355 await waitForPaintsFlushed(); 1356 omta_is("opacity", 0, RunningOn.Either, 1357 "dynamic delay delay test at 1800ms (3)"); 1358 done_div(); 1359 1360 // test delay and play-state interaction 1361 new_div("animation: anim2 1s 0.5s ease-out"); 1362 await waitForPaintsFlushed(); 1363 // NOTE: As noted above, getOMTAStyle() can't detect the animation is running 1364 // on the compositor during the delay phase. 1365 omta_is("opacity", 1, RunningOn.Either, 1366 "delay and play-state delay test at 0ms"); 1367 advance_clock(400); 1368 omta_is("opacity", 1, RunningOn.Either, 1369 "delay and play-state delay test at 400ms"); 1370 gDiv.style.animationPlayState = "paused"; 1371 await waitForPaintsFlushed(); 1372 advance_clock(100); 1373 omta_is("opacity", 1, RunningOn.MainThread, // paused 1374 "delay and play-state delay test at 500ms"); 1375 advance_clock(500); 1376 omta_is("opacity", 1, RunningOn.MainThread, // paused 1377 "delay and play-state delay test at 1000ms"); 1378 gDiv.style.animationPlayState = "running"; 1379 await waitForPaintsFlushed(); 1380 advance_clock(100); 1381 await waitForPaints(); 1382 omta_is("opacity", 0, RunningOn.Compositor, 1383 "delay and play-state delay test at 1100ms"); 1384 advance_clock(100); 1385 omta_is_approx("opacity", gTF.ease_out(0.1), 0.01, RunningOn.Compositor, 1386 "delay and play-state delay test at 1200ms"); 1387 gDiv.style.animationPlayState = "paused"; 1388 await waitForPaintsFlushed(); 1389 advance_clock(100); 1390 omta_is_approx("opacity", gTF.ease_out(0.1), 0.01, RunningOn.Either, 1391 "delay and play-state delay test at 1300ms"); 1392 done_div(); 1393 1394 // test negative delay and implicit starting values 1395 new_div("transform: translate(1000px)"); 1396 await waitForPaintsFlushed(); 1397 advance_clock(300); 1398 gDiv.style.transform = "translate(100px)"; 1399 gDiv.style.animation = "kf1 1s -0.1s ease-in"; 1400 await waitForPaintsFlushed(); 1401 omta_is_approx("transform", { tx: 100 - 50 * gTF.ease_in(0.2) }, 1402 0.01, RunningOn.Compositor, 1403 "delay and implicit starting values test"); 1404 done_div(); 1405 1406 // test large negative delay that causes the animation to start 1407 // in the fourth iteration 1408 new_div("animation: anim2 1s -3.6s ease-in 5 alternate forwards"); 1409 listen(); 1410 await waitForPaintsFlushed(); 1411 omta_is_approx("opacity", gTF.ease_in(0.4), 0.01, RunningOn.Compositor, 1412 "large negative delay test at 0ms"); 1413 check_events([{ type: 'animationstart', target: gDiv, 1414 animationName: 'anim2', elapsedTime: 3.6, 1415 pseudoElement: "" }], 1416 "right after start in large negative delay test"); 1417 advance_clock(380); 1418 omta_is_approx("opacity", gTF.ease_in(0.02), 0.01, RunningOn.Compositor, 1419 "large negative delay test at 380ms"); 1420 check_events([]); 1421 advance_clock(20); 1422 omta_is("opacity", 0, RunningOn.Compositor, 1423 "large negative delay test at 400ms"); 1424 check_events([{ type: 'animationiteration', target: gDiv, 1425 animationName: 'anim2', elapsedTime: 4.0, 1426 pseudoElement: "" }], 1427 "right after start in large negative delay test"); 1428 advance_clock(800); 1429 omta_is_approx("opacity", gTF.ease_in(0.8), 0.01, RunningOn.Compositor, 1430 "large negative delay test at 1200ms"); 1431 check_events([]); 1432 advance_clock(200); 1433 omta_is("opacity", 1, RunningOn.Either, 1434 "large negative delay test at 1400ms"); 1435 check_events([{ type: 'animationend', target: gDiv, 1436 animationName: 'anim2', elapsedTime: 5.0, 1437 pseudoElement: "" }], 1438 "right after start in large negative delay test"); 1439 done_div(); 1440 }); 1441 1442 /* 1443 * css3-animations: 3.9. The 'animation-fill-mode' Property 1444 * http://dev.w3.org/csswg/css3-animations/#the-animation-fill-mode-property- 1445 */ 1446 1447 // animation-fill-mode is tested in the tests for section (2). 1448 1449 /* 1450 * css3-animations: 3.10. The 'animation' Shorthand Property 1451 * http://dev.w3.org/csswg/css3-animations/#the-animation-shorthand-property- 1452 */ 1453 1454 /** 1455 * Basic tests of animations on pseudo-elements 1456 */ 1457 addAsyncAnimTest(async function() { 1458 new_div(""); 1459 listen(); 1460 gDiv.id = "withbefore"; 1461 await waitForPaintsFlushed(); 1462 omta_is("transform", { ty: 0 }, RunningOn.Compositor, 1463 ":before test at 0ms", "::before"); 1464 advance_clock(400); 1465 omta_is("transform", { ty: 40 }, RunningOn.Compositor, 1466 ":before test at 400ms", "::before"); 1467 advance_clock(800); 1468 omta_is("transform", { ty: 80 }, RunningOn.Compositor, 1469 ":before test at 1200ms", "::before"); 1470 omta_is("transform", { ty: 0 }, RunningOn.MainThread, 1471 ":before animation should not affect element"); 1472 advance_clock(800); 1473 omta_is("transform", { ty: 0 }, RunningOn.Compositor, 1474 ":before test at 2000ms", "::before"); 1475 advance_clock(300); 1476 omta_is("transform", { ty: 30 }, RunningOn.Compositor, 1477 ":before test at 2300ms", "::before"); 1478 advance_clock(700); 1479 check_events([ { type: "animationstart", animationName: "anim4", 1480 elapsedTime: 0, pseudoElement: "::before" }, 1481 { type: "animationiteration", animationName: "anim4", 1482 elapsedTime: 1, pseudoElement: "::before" }, 1483 { type: "animationiteration", animationName: "anim4", 1484 elapsedTime: 2, pseudoElement: "::before" }, 1485 { type: "animationend", animationName: "anim4", 1486 elapsedTime: 3, pseudoElement: "::before" }]); 1487 done_div(); 1488 1489 new_div(""); 1490 listen(); 1491 gDiv.id = "withafter"; 1492 await waitForPaintsFlushed(); 1493 omta_is("transform", { ty: 0 }, RunningOn.Compositor, 1494 ":after test at 0ms", "::after"); 1495 advance_clock(400); 1496 omta_is("transform", { ty: 40 }, RunningOn.Compositor, 1497 ":after test at 400ms", "::after"); 1498 advance_clock(800); 1499 omta_is("transform", { ty: 80 }, RunningOn.Compositor, 1500 ":after test at 1200ms", "::after"); 1501 omta_is("transform", { ty: 0 }, RunningOn.MainThread, 1502 ":before animation should not affect element"); 1503 advance_clock(800); 1504 omta_is("transform", { ty: 0 }, RunningOn.Compositor, 1505 ":after test at 2000ms", "::after"); 1506 advance_clock(300); 1507 omta_is("transform", { ty: 30 }, RunningOn.Compositor, 1508 ":after test at 2300ms", "::after"); 1509 advance_clock(700); 1510 check_events([ { type: "animationstart", animationName: "anim4", 1511 elapsedTime: 0, pseudoElement: "::after" }, 1512 { type: "animationiteration", animationName: "anim4", 1513 elapsedTime: 1, pseudoElement: "::after" }, 1514 { type: "animationiteration", animationName: "anim4", 1515 elapsedTime: 2, pseudoElement: "::after" }, 1516 { type: "animationend", animationName: "anim4", 1517 elapsedTime: 3, pseudoElement: "::after" }]); 1518 done_div(); 1519 }); 1520 1521 /** 1522 * Test handling of properties that are present in only some of the 1523 * keyframes. 1524 */ 1525 addAsyncAnimTest(async function() { 1526 new_div("animation: multiprop 1s ease-in-out alternate infinite"); 1527 await waitForPaintsFlushed(); 1528 omta_is("transform", { tx: 10 }, RunningOn.Compositor, 1529 "multiprop transform at 0ms"); 1530 omta_is("opacity", 0.3, RunningOn.Compositor, "multiprop opacity at 0ms"); 1531 advance_clock(100); 1532 omta_is_approx("transform", { tx: 10 + 30 * gTF.ease(0.2) }, 0.01, 1533 RunningOn.Compositor, "multiprop transform at 100ms"); 1534 omta_is_approx("opacity", 0.3 + 0.2 * gTF.ease(0.4), 0.01, 1535 RunningOn.Compositor, "multiprop opacity at 100ms"); 1536 advance_clock(200); 1537 omta_is_approx("transform", { tx: 10 + 30 * gTF.ease(0.6) }, 0.01, 1538 RunningOn.Compositor, "multiprop transform at 300ms"); 1539 omta_is_approx("opacity", 0.5 + 0.1 * gTF.ease_out(0.1), 0.01, 1540 RunningOn.Compositor, "multiprop opacity at 300ms"); 1541 advance_clock(300); 1542 omta_is_approx("transform", { tx: 40 + 40 * gTF.ease_in_out(0.4) }, 0.01, 1543 RunningOn.Compositor, "multiprop transform at 600ms"); 1544 omta_is_approx("opacity", 0.5 + 0.1 * gTF.ease_out(0.7), 0.01, 1545 RunningOn.Compositor, "multiprop opacity at 600ms"); 1546 advance_clock(200); 1547 omta_is_approx("transform", { tx: 80 - 80 * gTF.ease_in(0.2) }, 0.01, 1548 RunningOn.Compositor, "multiprop transform at 800ms"); 1549 omta_is_approx("opacity", 0.6 + 0.4 * gTF.ease_in(0.2), 0.01, 1550 RunningOn.Compositor, "multiprop opacity at 800ms"); 1551 advance_clock(400); 1552 omta_is_approx("transform", { tx: 80 - 80 * gTF.ease_in(0.2) }, 0.01, 1553 RunningOn.Compositor, "multiprop transform at 1200ms"); 1554 omta_is_approx("opacity", 0.6 + 0.4 * gTF.ease_in(0.2), 0.01, 1555 RunningOn.Compositor, "multiprop opacity at 1200ms"); 1556 advance_clock(200); 1557 omta_is_approx("transform", { tx: 40 + 40 * gTF.ease_in_out(0.4) }, 0.01, 1558 RunningOn.Compositor, "multiprop transform at 1400ms"); 1559 omta_is_approx("opacity", 0.5 + 0.1 * gTF.ease_out(0.7), 0.01, 1560 RunningOn.Compositor, "multiprop opacity at 1400ms"); 1561 advance_clock(300); 1562 omta_is_approx("transform", { tx: 10 + 30 * gTF.ease(0.6) }, 0.01, 1563 RunningOn.Compositor, "multiprop transform at 1700ms"); 1564 omta_is_approx("opacity", 0.5 + 0.1 * gTF.ease_out(0.1), 0.01, 1565 RunningOn.Compositor, "multiprop opacity at 1700ms"); 1566 advance_clock(200); 1567 omta_is_approx("transform", { tx: 10 + 30 * gTF.ease(0.2) }, 0.01, 1568 RunningOn.Compositor, "multiprop transform at 1900ms"); 1569 omta_is_approx("opacity", 0.3 + 0.2 * gTF.ease(0.4), 0.01, 1570 RunningOn.Compositor, "multiprop opacity at 1900ms"); 1571 done_div(); 1572 }); 1573 1574 // Test for https://bugzilla.mozilla.org/show_bug.cgi?id=651456 -- make 1575 // sure that refreshing of animations doesn't break when we get two 1576 // refreshes with the same timestamp. 1577 addAsyncAnimTest(async function() { 1578 new_div("animation: anim2 1s linear"); 1579 await waitForPaintsFlushed(); 1580 omta_is("opacity", 0, RunningOn.Compositor, "bug 651456 at 0ms"); 1581 advance_clock(100); 1582 omta_is("opacity", 0.1, RunningOn.Compositor, "bug 651456 at 100ms (1)"); 1583 advance_clock(0); // still forces a refresh 1584 omta_is("opacity", 0.1, RunningOn.Compositor, "bug 651456 at 100ms (2)"); 1585 advance_clock(100); 1586 omta_is("opacity", 0.2, RunningOn.Compositor, "bug 651456 at 200ms"); 1587 done_div(); 1588 }); 1589 1590 // test_animations.html includes a test that UA !important rules override 1591 // animations. Unfortunately, there do not appear to be any UA !important rules 1592 // for opacity or transform except for one targetting a pseudo-element and 1593 // pseudo elements are not animated on the compositor. As a result we cannot 1594 // currently test this behavior. 1595 1596 // Test that author !important rules override animations, but 1597 // that animations override regular author rules. 1598 addAsyncAnimTest(async function() { 1599 new_div("animation: always_fifty 1s linear infinite; " + 1600 "transform: translate(200px)"); 1601 await waitForPaintsFlushed(); 1602 omta_is("transform", { tx: 50 }, RunningOn.Compositor, 1603 "animations override regular author rules"); 1604 done_div(); 1605 new_div("animation: always_fifty 1s linear infinite; " + 1606 "transform: translate(200px) ! important;"); 1607 await waitForPaintsFlushed(); 1608 omta_is("transform", { tx: 200 }, RunningOn.MainThread, 1609 "important author rules override animations"); 1610 done_div(); 1611 }); 1612 1613 // Test interaction of animations and restyling (Bug 686656). 1614 // This test depends on kf3 getting its 0% and 100% values from the 1615 // rules below it in the cascade; we're checking that the animation 1616 // isn't rebuilt when the restyles happen. 1617 addAsyncAnimTest(async function() { 1618 new_div("animation: kf3 1s linear forwards"); 1619 await waitForPaintsFlushed(); 1620 omta_is("transform", { tx: 0 }, RunningOn.Compositor, 1621 "bug 686656 test 1 at 0ms"); 1622 advance_clock(250); 1623 gDisplay.style.color = "blue"; 1624 await waitForPaintsFlushed(); 1625 omta_is("transform", { tx: 100 }, RunningOn.Compositor, 1626 "bug 686656 test 1 at 250ms"); 1627 advance_clock(375); 1628 omta_is("transform", { tx: 50 }, RunningOn.Compositor, 1629 "bug 686656 test 1 at 625ms"); 1630 advance_clock(375); 1631 await waitForPaints(); 1632 omta_is("transform", { tx: 0 }, RunningOn.MainThread, 1633 "bug 686656 test 1 at 1000ms"); 1634 done_div(); 1635 gDisplay.style.color = ""; 1636 }); 1637 1638 // Test interaction of animations and restyling (Bug 686656), 1639 // with reframing. 1640 // This test depends on kf3 getting its 0% and 100% values from the 1641 // rules below it in the cascade; we're checking that the animation 1642 // isn't rebuilt when the restyles happen. 1643 addAsyncAnimTest(async function() { 1644 new_div("animation: kf3 1s linear forwards"); 1645 await waitForPaintsFlushed(); 1646 omta_is("transform", { tx: 0 }, RunningOn.Compositor, 1647 "bug 686656 test 2 at 0ms"); 1648 advance_clock(250); 1649 gDisplay.style.overflow = "scroll"; 1650 await waitForPaintsFlushed(); 1651 omta_is("transform", { tx: 100 }, RunningOn.Compositor, 1652 "bug 686656 test 2 at 250ms"); 1653 advance_clock(375); 1654 omta_is("transform", { tx: 50 }, RunningOn.Compositor, 1655 "bug 686656 test 2 at 625ms"); 1656 advance_clock(375); 1657 await waitForPaints(); 1658 omta_is("transform", { tx: 0 }, RunningOn.MainThread, 1659 "bug 686656 test 2 at 1000ms"); 1660 done_div(); 1661 gDisplay.style.overflow = ""; 1662 }); 1663 1664 // Test that cascading between keyframes rules is per-property rather 1665 // than per-rule (bug ), and that the timing function isn't taken from a 1666 // rule that's skipped. (Bug 738003) 1667 addAsyncAnimTest(async function() { 1668 new_div("animation: cascade 1s linear forwards; position: relative"); 1669 await waitForPaintsFlushed(); 1670 omta_is("transform", { tx: 0 }, RunningOn.Compositor, 1671 "cascade test (transform) at 0ms"); 1672 omta_is("opacity", 0, RunningOn.Compositor, 1673 "cascade test (opacity) at 0ms"); 1674 advance_clock(125); 1675 omta_is("transform", { tx: 0 }, RunningOn.Compositor, 1676 "cascade test (transform) at 125ms"); 1677 omta_is("opacity", 0.5, RunningOn.Compositor, 1678 "cascade test (opacity) at 125ms"); 1679 advance_clock(125); 1680 omta_is("transform", { tx: 0 }, RunningOn.Compositor, 1681 "cascade test (transform) at 250ms"); 1682 omta_is("opacity", 1, RunningOn.Compositor, 1683 "cascade test (opacity) at 250ms"); 1684 advance_clock(125); 1685 omta_is("transform", { tx: 50 }, RunningOn.Compositor, 1686 "cascade test (transform) at 375ms"); 1687 omta_is("opacity", 1, RunningOn.Compositor, 1688 "cascade test (opacity) at 375ms"); 1689 advance_clock(125); 1690 omta_is("transform", { tx: 100 }, RunningOn.Compositor, 1691 "cascade test (transform) at 500ms"); 1692 omta_is("opacity", 1, RunningOn.Compositor, 1693 "cascade test (opacity) at 500ms"); 1694 advance_clock(125); 1695 omta_is("transform", { tx: 100 }, RunningOn.Compositor, 1696 "cascade test (transform) at 625ms"); 1697 omta_is("opacity", 0.5, RunningOn.Compositor, 1698 "cascade test (opacity) at 625ms"); 1699 advance_clock(125); 1700 omta_is("transform", { tx: 100 }, RunningOn.Compositor, 1701 "cascade test (transform) at 750ms"); 1702 omta_is("opacity", 0, RunningOn.Compositor, 1703 "cascade test (opacity) at 750ms"); 1704 advance_clock(125); 1705 omta_is("transform", { tx: 50 }, RunningOn.Compositor, 1706 "cascade test (transform) at 875ms"); 1707 omta_is("opacity", 0, RunningOn.Compositor, 1708 "cascade test (opacity) at 875ms"); 1709 advance_clock(125); 1710 await waitForPaints(); 1711 omta_is("transform", { tx: 0 }, RunningOn.MainThread, 1712 "cascade test (transform) at 1000ms"); 1713 omta_is("opacity", 0, RunningOn.Either, 1714 "cascade test (opacity) at 1000ms"); 1715 done_div(); 1716 }); 1717 1718 addAsyncAnimTest(async function() { 1719 new_div("animation: cascade2 8s linear forwards"); 1720 await waitForPaintsFlushed(); 1721 omta_is("transform", { tx: 0 }, RunningOn.Compositor, "cascade2 test at 0s"); 1722 advance_clock(1000); 1723 omta_is("transform", { tx: 25 }, RunningOn.Compositor, "cascade2 test at 1s"); 1724 advance_clock(1000); 1725 omta_is("transform", { tx: 50 }, RunningOn.Compositor, "cascade2 test at 2s"); 1726 advance_clock(1000); 1727 omta_is("transform", { tx: 25 }, RunningOn.Compositor, "cascade2 test at 3s"); 1728 advance_clock(1000); 1729 omta_is("transform", { tx: 0 }, RunningOn.Compositor, "cascade2 test at 4s"); 1730 advance_clock(3000); 1731 omta_is("transform", { tx: 75 }, RunningOn.Compositor, "cascade2 test at 7s"); 1732 advance_clock(1000); 1733 await waitForPaints(); 1734 omta_is("transform", { tx: 100 }, RunningOn.MainThread, 1735 "cascade2 test at 8s"); 1736 done_div(); 1737 }); 1738 1739 addAsyncAnimTest(async function() { 1740 new_div("animation: primitives1 2s linear forwards"); 1741 await waitForPaintsFlushed(); 1742 omta_is("transform", { }, RunningOn.Compositor, "primitives1 at 0s"); 1743 advance_clock(1000); 1744 omta_is("transform", [ -0.707107, 0.707107, -0.707107, -0.707107, 0, 0 ], 1745 RunningOn.Compositor, "primitives1 at 1s"); 1746 advance_clock(1000); 1747 await waitForPaints(); 1748 omta_is("transform", [ 0, -1, 1, 0, 0, 0 ], RunningOn.MainThread, 1749 "primitives1 at 0s"); 1750 done_div(); 1751 }); 1752 1753 addAsyncAnimTest(async function() { 1754 new_div("animation: important1 1s linear forwards"); 1755 await waitForPaintsFlushed(); 1756 omta_is("opacity", 0.5, RunningOn.Compositor, "important1 test at 0s"); 1757 advance_clock(500); 1758 omta_is("opacity", 0.65, RunningOn.Compositor, "important1 test at 0.5s"); 1759 advance_clock(500); 1760 await waitForPaints(); 1761 omta_is("opacity", 0.8, RunningOn.Either, "important1 test at 1s"); 1762 done_div(); 1763 }); 1764 1765 addAsyncAnimTest(async function() { 1766 new_div("animation: important2 1s linear forwards"); 1767 await waitForPaintsFlushed(); 1768 omta_is("opacity", 0.5, RunningOn.Compositor, 1769 "important2 (opacity) test at 0s"); 1770 omta_is("transform", { tx: 100 }, RunningOn.Compositor, 1771 "important2 (transform) test at 0s"); 1772 advance_clock(1000); 1773 await waitForPaints(); 1774 omta_is("opacity", 1, RunningOn.Either, 1775 "important2 (opacity) test at 1s"); 1776 omta_is("transform", { tx: 50 }, RunningOn.MainThread, 1777 "important2 (transform) test at 1s"); 1778 done_div(); 1779 }); 1780 1781 addAsyncAnimTest(async function() { 1782 // Test that it's the length of the 'animation-name' list that's used to 1783 // start animations. 1784 // note: anim2 animates opacity from 0 to 1 1785 // note: anim4 animates transform's y translation component from 0 to 100px 1786 new_div("animation-name: anim2, anim4; " + 1787 "animation-duration: 1s; " + 1788 "animation-timing-function: linear; " + 1789 "animation-delay: -250ms, -250ms, -750ms, -500ms;"); 1790 await waitForPaintsFlushed(); 1791 omta_is("opacity", 0.25, RunningOn.Compositor, 1792 "animation-name list length is the length that matters"); 1793 omta_is("transform", { ty: 25 }, RunningOn.Compositor, 1794 "animation-name list length is the length that matters"); 1795 done_div(); 1796 new_div("animation-name: anim2, anim4, anim2; " + 1797 "animation-duration: 1s; " + 1798 "animation-timing-function: linear; " + 1799 "animation-delay: -250ms, -250ms, -750ms, -500ms;"); 1800 await waitForPaintsFlushed(); 1801 omta_is("opacity", 0.75, RunningOn.Compositor, 1802 "animation-name list length is the length that matters, " + 1803 "and the last occurrence of a name wins"); 1804 omta_is("transform", { ty: 25 }, RunningOn.Compositor, 1805 "animation-name list length is the length that matters"); 1806 done_div(); 1807 }); 1808 1809 addAsyncAnimTest(async function() { 1810 var dyn_sheet_elt = document.createElement("style"); 1811 document.head.appendChild(dyn_sheet_elt); 1812 var dyn_sheet = dyn_sheet_elt.sheet; 1813 dyn_sheet.insertRule( 1814 "@keyframes dyn1 { from { transform: translate(0px) } " + 1815 "50% { transform: translate(50px) } " + 1816 "to { transform: translate(100px) } }", 0); 1817 dyn_sheet.insertRule( 1818 "@keyframes dyn2 { from { transform: translate(100px) } " + 1819 "to { transform: translate(200px) } }", 1); 1820 var dyn1 = dyn_sheet.cssRules[0]; 1821 var dyn2 = dyn_sheet.cssRules[1]; 1822 new_div("animation: dyn1 1s linear"); 1823 await waitForPaintsFlushed(); 1824 omta_is("transform", { tx: 0 }, RunningOn.Compositor, 1825 "dynamic rule change test, initial state"); 1826 advance_clock(250); 1827 omta_is("transform", { tx: 25 }, RunningOn.Compositor, 1828 "dynamic rule change test, 250ms"); 1829 dyn2.name = "dyn1"; 1830 await waitForPaintsFlushed(); 1831 omta_is("transform", { tx: 125 }, RunningOn.Compositor, 1832 "dynamic rule change test, change in @keyframes name applies"); 1833 dyn2.appendRule("50% { transform: translate(0px) }"); 1834 await waitForPaintsFlushed(); 1835 omta_is("transform", { tx: 50 }, RunningOn.Compositor, 1836 "dynamic rule change test, @keyframes appendRule"); 1837 // currently 0% { transform: translate(100px) } 1838 var dyn2_kf1 = dyn2.cssRules[0]; 1839 dyn2_kf1.style.transform = "translate(-100px)"; 1840 await waitForPaintsFlushed(); 1841 omta_is("transform", { tx: -50 }, RunningOn.Compositor, 1842 "dynamic rule change test, keyframe style set"); 1843 dyn2.name = "dyn2"; 1844 await waitForPaintsFlushed(); 1845 omta_is("transform", { tx: 25 }, RunningOn.Compositor, 1846 "dynamic rule change test, " + 1847 "change in @keyframes name applies (second time)"); 1848 // currently 50% { transform: translate(50px) } 1849 var dyn1_kf2 = dyn1.cssRules[1]; 1850 dyn1_kf2.keyText = "25%"; 1851 await waitForPaintsFlushed(); 1852 omta_is("transform", { tx: 50 }, RunningOn.Compositor, 1853 "dynamic rule change test, change in keyframe keyText"); 1854 dyn1.deleteRule("25%"); 1855 await waitForPaintsFlushed(); 1856 omta_is("transform", { tx: 25 }, RunningOn.Compositor, 1857 "dynamic rule change test, @keyframes deleteRule"); 1858 done_div(); 1859 dyn_sheet_elt.remove(); 1860 dyn_sheet_elt = null; 1861 dyn_sheet = null; 1862 }); 1863 1864 /* 1865 * Bug 1004361 - CSS animations with short duration sometimes don't dispatch 1866 * a start event 1867 */ 1868 addAsyncAnimTest(async function() { 1869 new_div("animation: anim2 1s 0.1s"); 1870 listen(); 1871 await waitForPaintsFlushed(); 1872 advance_clock(1200); // Skip past end of animation's entire active duration 1873 check_events([{ type: 'animationstart', target: gDiv, 1874 animationName: 'anim2', elapsedTime: 0, 1875 pseudoElement: "" }, 1876 { type: 'animationend', target: gDiv, 1877 animationName: 'anim2', elapsedTime: 1, 1878 pseudoElement: "" }], 1879 "events after skipping over animation interval"); 1880 done_div(); 1881 }); 1882 1883 /* 1884 * Bug 1007513 - AnimationEvent.elapsedTime should be animation time 1885 * 1886 * There is no OMTA-version of this test since it is specific to the 1887 * contents of animation events which are dispatched on the main thread. 1888 * 1889 * We *do* provide an OMTA-version of some tests regarding the *dispatch* of 1890 * events to catch possible regressions if in future event dispatch is tied 1891 * to animation throttling. 1892 */ 1893 1894 /* 1895 * Bug 1004365 - zero-duration animations 1896 */ 1897 1898 addAsyncAnimTest(async function() { 1899 new_div("transform: translate(0, 200px); animation: anim4 0s 1s both"); 1900 listen(); 1901 await waitForPaintsFlushed(); 1902 advance_clock(0); 1903 omta_is("transform", { ty: 0 }, RunningOn.Compositor, 1904 "transform during backwards fill of zero-duration animation"); 1905 advance_clock(2000); // Skip over animation 1906 await waitForPaints(); 1907 omta_is("transform", { ty: 100 }, RunningOn.MainThread, 1908 "transform during backwards fill of zero-duration animation"); 1909 check_events([{ type: 'animationstart', target: gDiv, 1910 animationName: 'anim4', elapsedTime: 0, 1911 pseudoElement: "" }, 1912 { type: 'animationend', target: gDiv, 1913 animationName: 'anim4', elapsedTime: 0, 1914 pseudoElement: "" }], 1915 "events after skipping over zero-duration animation"); 1916 done_div(); 1917 }); 1918 1919 addAsyncAnimTest(async function() { 1920 new_div("transform: translate(0, 200px); animation: anim4 0s 1s both"); 1921 listen(); 1922 await waitForPaintsFlushed(); 1923 advance_clock(0); 1924 // Seek to exactly the point where the animation starts and stops 1925 advance_clock(1000); 1926 await waitForPaints(); 1927 omta_is("transform", { ty: 100 }, RunningOn.MainThread, 1928 "transform during backwards fill of zero-duration animation"); 1929 check_events([{ type: 'animationstart', target: gDiv, 1930 animationName: 'anim4', elapsedTime: 0, 1931 pseudoElement: "" }, 1932 { type: 'animationend', target: gDiv, 1933 animationName: 'anim4', elapsedTime: 0, 1934 pseudoElement: "" }], 1935 "events after seeking to end of zero-duration animation"); 1936 // Check no further events are dispatched 1937 advance_clock(0); 1938 advance_clock(100); 1939 check_events([]); 1940 done_div(); 1941 }); 1942 1943 // We don't need to include all the animation-direction related tests 1944 // found in test_animations.html. We have already asserted above that 1945 // these zero-length animations do in fact run on the main thread and 1946 // we have checked that they dispatch events correctly. 1947 // The actual calculation of values on the main thread is covered by 1948 // test_animations.html 1949 1950 // We do however still want to test with an infinite repeat count and zero 1951 // duration to ensure this does not confuse the screening of OMTA animations. 1952 addAsyncAnimTest(async function() { 1953 new_div("transform: translate(0, 200px); " + 1954 "animation: anim4 0s 1s both infinite"); 1955 listen(); 1956 await waitForPaintsFlushed(); 1957 advance_clock(0); 1958 omta_is("transform", { ty: 0 }, RunningOn.Compositor, 1959 "transform during backwards fill of infinitely repeating " + 1960 "zero-duration animation"); 1961 advance_clock(2000); 1962 await waitForPaints(); 1963 omta_is("transform", { ty: 100 }, RunningOn.MainThread, 1964 "transform during forwards fill of infinitely repeating " + 1965 "zero-duration animation"); 1966 check_events([{ type: 'animationstart', target: gDiv, 1967 animationName: 'anim4', elapsedTime: 0, 1968 pseudoElement: "" }, 1969 { type: 'animationend', target: gDiv, 1970 animationName: 'anim4', elapsedTime: 0, 1971 pseudoElement: "" }], 1972 "events after seeking to end of infinitely repeating " + 1973 "zero-duration animation"); 1974 done_div(); 1975 }); 1976 1977 // Test with negative delay 1978 addAsyncAnimTest(async function() { 1979 new_div("transform: translate(0, 200px); " + 1980 "animation: anim4 0s -1s both reverse 12.7 linear"); 1981 listen(); 1982 await waitForPaintsFlushed(); 1983 advance_clock(0); 1984 omta_is("transform", { ty: 30 }, RunningOn.MainThread, 1985 "transform during forwards fill of reversed and repeated " + 1986 "zero-duration animation with negative delay"); 1987 check_events([{ type: 'animationstart', target: gDiv, 1988 animationName: 'anim4', elapsedTime: 0, 1989 pseudoElement: "" }, 1990 { type: 'animationend', target: gDiv, 1991 animationName: 'anim4', elapsedTime: 0, 1992 pseudoElement: "" }], 1993 "events after skipping over zero-duration animation " + 1994 "with negative delay"); 1995 done_div(); 1996 }); 1997 1998 /* 1999 * Bug 1004377 - Animations with empty keyframes rule 2000 */ 2001 2002 addAsyncAnimTest(async function() { 2003 new_div("margin-right: 200px; animation: empty 2s 1s both"); 2004 listen(); 2005 advance_clock(0); 2006 await waitForPaintsFlushed(); 2007 check_events([], "events during delay"); 2008 advance_clock(2000); // Skip to middle of animation 2009 gDiv.clientTop; // Trigger events 2010 check_events([{ type: 'animationstart', target: gDiv, 2011 animationName: 'empty', elapsedTime: 0, 2012 pseudoElement: "" }], 2013 "events during middle of animation with empty keyframes rule"); 2014 advance_clock(1000); // Skip to end of animation 2015 gDiv.clientTop; // Trigger events 2016 check_events([{ type: 'animationend', target: gDiv, 2017 animationName: 'empty', elapsedTime: 2, 2018 pseudoElement: "" }], 2019 "events at end of animation with empty keyframes rule"); 2020 done_div(); 2021 }); 2022 2023 // Test with a zero-duration animation and empty @keyframes rule 2024 addAsyncAnimTest(async function() { 2025 new_div("margin-right: 200px; animation: empty 0s 1s both"); 2026 listen(); 2027 await waitForPaintsFlushed(); 2028 advance_clock(1000); 2029 gDiv.clientTop; // Trigger events 2030 check_events([{ type: 'animationstart', target: gDiv, 2031 animationName: 'empty', elapsedTime: 0, 2032 pseudoElement: "" }, 2033 { type: 'animationend', target: gDiv, 2034 animationName: 'empty', elapsedTime: 0, 2035 pseudoElement: "" }], 2036 "events at end of zero-duration animation with " + 2037 "empty keyframes rule"); 2038 done_div(); 2039 }); 2040 2041 // Test with a keyframes rule that becomes empty 2042 addAsyncAnimTest(async function() { 2043 new_div("animation: nearlyempty 1s both linear"); 2044 await waitForPaintsFlushed(); 2045 advance_clock(500); 2046 omta_is("transform", { tx: 50 }, RunningOn.Compositor, 2047 "Animation is animating on compositor"); 2048 2049 // Update keyframes rule and check the result gets removed 2050 listen(); 2051 findKeyframesRule("nearlyempty").deleteRule("to"); 2052 await waitForPaintsFlushed(); 2053 omta_is("transform", { }, RunningOn.MainThread, 2054 "Animation with (now) empty keyframes rule is cleared " + 2055 "from compositor"); 2056 2057 // Check we still dispatch the end event however 2058 advance_clock(500); 2059 gDiv.clientTop; // Trigger events 2060 check_events([{ type: 'animationend', target: gDiv, 2061 animationName: 'nearlyempty', elapsedTime: 1, 2062 pseudoElement: "" }], 2063 "events at end of animation with newly " + 2064 "empty keyframes rule"); 2065 2066 done_div(); 2067 }); 2068 2069 // Test when we update to point to an empty animation 2070 addAsyncAnimTest(async function() { 2071 new_div("animation: always_fifty 1s both linear"); 2072 await waitForPaintsFlushed(); 2073 advance_clock(500); 2074 omta_is("transform", { tx: 50 }, RunningOn.Compositor, 2075 "Animation is animating on compositor"); 2076 2077 // Update animation name 2078 listen(); 2079 gDiv.style.animationName = "empty"; 2080 await waitForPaintsFlushed(); 2081 omta_is("transform", { }, RunningOn.MainThread, 2082 "Animation updated to use empty keyframes rule is cleared " + 2083 "from compositor"); 2084 2085 // Check events 2086 advance_clock(500); 2087 gDiv.clientTop; // Trigger events 2088 check_events([{ type: 'animationstart', target: gDiv, 2089 animationName: 'empty', elapsedTime: 0, 2090 pseudoElement: "" }], 2091 "events at start of animation updated to use " + 2092 "empty keyframes rule"); 2093 2094 done_div(); 2095 }); 2096 2097 // Bug 996796 patch 12 - test for correct visited styles during 2098 // animation-only style flush. 2099 addAsyncAnimTest(async function() { 2100 if (AppConstants.platform === "android") { 2101 todo(false, "no global history on GeckoView; can't run test"); 2102 return; 2103 } 2104 2105 var div1 = document.createElement("div"); 2106 div1.classList.add("target"); 2107 div1.style.height = "10px"; 2108 div1.style.animation = "anim2 linear 1s"; 2109 2110 const topLocation = 2111 await SpecialPowers.spawnChrome([], () => browsingContext.top.currentURI.spec); 2112 2113 var visitedLink = document.createElement("a"); 2114 visitedLink.setAttribute("href", topLocation); 2115 visitedLink.classList.add("visitedLink"); 2116 visitedLink.classList.add("target"); 2117 visitedLink.style.display = "block"; 2118 visitedLink.style.height = "10px"; 2119 visitedLink.style.animation = "anim2 linear 1s"; 2120 2121 var refVisitedLink = document.createElement("a"); 2122 refVisitedLink.setAttribute("href", topLocation); 2123 refVisitedLink.classList.add("visitedLink"); 2124 2125 gDisplay.appendChild(div1); 2126 gDisplay.appendChild(visitedLink); 2127 gDisplay.appendChild(refVisitedLink); 2128 2129 // Wait for visited link coloring. 2130 await waitForVisitedLinkColoring(refVisitedLink, 2131 "background-color", "rgb(0, 0, 255)"); 2132 2133 // Wait for animations to start. 2134 await waitForPaintsFlushed(); 2135 2136 var bgColor = SpecialPowers.DOMWindowUtils 2137 .getVisitedDependentComputedStyle(visitedLink, "", "background-color"); 2138 is(bgColor, "rgb(0, 0, 255)", "initial visited link background color"); 2139 2140 advance_clock(250); 2141 2142 // Trigger a style change on div1 that will force us to do a miniflush, 2143 // but which will not trigger a style change on visitedLink. 2144 div1.style.color = "blue"; 2145 advance_clock(250); 2146 2147 bgColor = SpecialPowers.DOMWindowUtils 2148 .getVisitedDependentComputedStyle(visitedLink, "", "background-color"); 2149 2150 is(bgColor, "rgb(0, 0, 255)", 2151 "visited link background color after animation-only flush"); 2152 2153 div1.remove(); 2154 visitedLink.remove(); 2155 refVisitedLink.remove(); 2156 }); 2157 2158 /* 2159 * Bug 962594 - Turn off CSS animations when the element is display:none, or 2160 * is in a display:none subtree. 2161 */ 2162 2163 // Check that it works if the animated element itself becomes display:none 2164 addAsyncAnimTest(async function() { 2165 new_div("animation: anim4 linear 10s"); 2166 await waitForPaintsFlushed(); 2167 omta_is("transform", { ty: 0 }, RunningOn.Compositor, 2168 "transform animation is running on compositor"); 2169 advance_clock(1000); 2170 omta_is("transform", { ty: 10 }, RunningOn.Compositor, 2171 "transform animation is at 1s on compositor"); 2172 gDiv.style.display = "none"; 2173 await waitForPaintsFlushed(); 2174 omta_is("transform", "none", RunningOn.MainThread, 2175 "transform animation stopped on compositor"); 2176 advance_clock(1000); 2177 omta_is("transform", "none", RunningOn.MainThread, 2178 "transform animation 1s after display:none"); 2179 gDiv.style.display = ""; 2180 await waitForPaintsFlushed(); 2181 omta_is("transform", { ty: 0 }, RunningOn.Compositor, 2182 "transform animation after display:block"); 2183 advance_clock(1000); 2184 omta_is("transform", { ty: 10 }, RunningOn.Compositor, 2185 "transform animation 1s after display:block"); 2186 done_div(); 2187 }); 2188 2189 // Check that it works if an ancestor of the animated element becomes display:none 2190 addAsyncAnimTest(async function() { 2191 new_div("animation: anim4 linear 10s"); 2192 var ancestor = document.createElement("div"); 2193 gDiv.parentNode.insertBefore(ancestor, gDiv); 2194 ancestor.appendChild(gDiv); 2195 await waitForPaintsFlushed(); 2196 omta_is("transform", { ty: 0 }, RunningOn.Compositor, 2197 "transform animation is running on compositor"); 2198 advance_clock(1000); 2199 omta_is("transform", { ty: 10 }, RunningOn.Compositor, 2200 "transform animation is at 1s on compositor"); 2201 gDiv.style.display = "none"; 2202 await waitForPaintsFlushed(); 2203 omta_is("transform", "none", RunningOn.MainThread, 2204 "transform animation stopped on compositor"); 2205 advance_clock(1000); 2206 omta_is("transform", "none", RunningOn.MainThread, 2207 "transform animation 1s after display:none"); 2208 gDiv.style.display = ""; 2209 await waitForPaintsFlushed(); 2210 omta_is("transform", { ty: 0 }, RunningOn.Compositor, 2211 "transform animation after display:block"); 2212 advance_clock(1000); 2213 omta_is("transform", { ty: 10 }, RunningOn.Compositor, 2214 "transform animation 1s after display:block"); 2215 ancestor.parentNode.insertBefore(gDiv, ancestor); 2216 ancestor.remove(); 2217 done_div(); 2218 }); 2219 2220 // Bug 1125455 - Transitions should not run when animations are running. 2221 addAsyncAnimTest(async function() { 2222 new_div("transition: opacity 2s linear; opacity: 0.8"); 2223 await waitForPaintsFlushed(); 2224 omta_is("opacity", 0.8, RunningOn.MainThread, 2225 "initial opacity"); 2226 gDiv.style.opacity = "0.2"; 2227 await waitForPaintsFlushed(); 2228 omta_is("opacity", 0.8, RunningOn.Compositor, 2229 "opacity transition at 0s"); 2230 advance_clock(500); 2231 omta_is("opacity", 0.65, RunningOn.Compositor, 2232 "opacity transition at 0.5s"); 2233 gDiv.style.animation = "opacitymid 2s linear"; 2234 await waitForPaintsFlushed(); 2235 omta_is("opacity", 0.2, RunningOn.Compositor, 2236 "opacity animation overriding transition at 0s"); 2237 advance_clock(500); 2238 omta_is("opacity", 0.35, RunningOn.Compositor, 2239 "opacity animation overriding transition at 0.5s"); 2240 done_div(); 2241 }); 2242 2243 // Bug 1320474 - keyframes-name may be a string, allows names that would 2244 // otherwise be excluded. 2245 // These tests don't need to be duplicated here as they relate purely to 2246 // the animation setup which is common to both main-thread and compositor 2247 // animations. 2248 2249 // Bug 847287 - Test that changes of when an animation is dynamically 2250 // overridden work correctly. 2251 addAsyncAnimTest(async function() { 2252 // anim2 and anim3 are both animations from opacity 0 to 1 2253 2254 new_div("animation: anim2 1s linear forwards; opacity: 0.5 ! important"); 2255 await waitForPaintsFlushed(); 2256 omta_is("opacity", 0.5, RunningOn.MainThread, 2257 "opacity overriding animation at start (0s)"); 2258 advance_clock(750); 2259 omta_is("opacity", 0.5, RunningOn.MainThread, 2260 "opacity overriding animation while running (750ms)"); 2261 advance_clock(1000); 2262 omta_is("opacity", 0.5, RunningOn.MainThread, 2263 "opacity overriding animation while filling (1750ms)"); 2264 done_div(); 2265 2266 new_div("animation: anim2 1s linear; opacity: 0.5 ! important"); 2267 await waitForPaintsFlushed(); 2268 omta_is("opacity", 0.5, RunningOn.MainThread, 2269 "opacity overriding animation at start (0s)"); 2270 advance_clock(750); 2271 omta_is("opacity", 0.5, RunningOn.MainThread, 2272 "opacity overriding animation while running (750ms)"); 2273 advance_clock(1000); 2274 omta_is("opacity", 0.5, RunningOn.MainThread, 2275 "opacity overriding animation after complete (1750ms)"); 2276 done_div(); 2277 2278 // One animation overriding another, and then not. 2279 new_div("animation: anim2 1s linear, anim3 500ms linear reverse"); 2280 await waitForPaintsFlushed(); 2281 omta_is("opacity", 1, RunningOn.Compositor, 2282 "anim3 overriding anim2 at start (0s)"); 2283 advance_clock(400); 2284 omta_is("opacity", 0.2, RunningOn.Compositor, 2285 "anim3 overriding anim2 at 400ms"); 2286 advance_clock(200); 2287 // Wait for paints because we're resending animations to the 2288 // compositor via an UpdateOpacityLayer hint, which does the resending 2289 // via painting. 2290 await waitForPaints(); 2291 omta_is("opacity", 0.6, RunningOn.Compositor, 2292 "anim2 at 600ms"); 2293 done_div(); 2294 2295 // One animation overriding another, and then not, but without a 2296 // restyle when the overriding one ends. 2297 new_div("animation: anim2 1s steps(8, end)"); 2298 await waitForPaintsFlushed(); 2299 omta_is("opacity", 0, RunningOn.Compositor, 2300 "anim2 at start (0s)"); 2301 advance_clock(300); 2302 omta_is("opacity", 0.25, RunningOn.Compositor, 2303 "anim2 at 300ms"); 2304 gDiv.style.animation = "anim2 1s steps(8, end), anim3 500ms steps(4, end)"; 2305 await waitForPaintsFlushed(); 2306 omta_is("opacity", 0, RunningOn.Compositor, 2307 "anim3 overriding anim2 at 300ms"); 2308 advance_clock(475); 2309 omta_is("opacity", 0.75, RunningOn.Compositor, 2310 "anim3 the same as anim2 at 775ms"); 2311 advance_clock(50); 2312 // Wait for paints because we're resending animations to the 2313 // compositor via an UpdateOpacityLayer hint, which does the resending 2314 // via painting. 2315 await waitForPaints(); 2316 omta_is("opacity", 0.75, RunningOn.Compositor, 2317 "anim2 at 825ms"); 2318 advance_clock(75); 2319 omta_is("opacity", 0.875, RunningOn.Compositor, 2320 "anim2 at 900ms"); 2321 done_div(); 2322 2323 // Exactly the same as the previous test, except with an extra 2324 // waitForPaintsFlushed(), since that extra one exposes other bugs. 2325 new_div("animation: anim2 1s steps(8, end)"); 2326 await waitForPaintsFlushed(); 2327 omta_is("opacity", 0, RunningOn.Compositor, 2328 "anim2 at start (0s)"); 2329 advance_clock(300); 2330 omta_is("opacity", 0.25, RunningOn.Compositor, 2331 "anim2 at 300ms"); 2332 gDiv.style.animation = "anim2 1s steps(8, end), anim3 500ms steps(4, end)"; 2333 await waitForPaintsFlushed(); 2334 omta_is("opacity", 0, RunningOn.Compositor, 2335 "anim3 overriding anim2 at 300ms"); 2336 advance_clock(475); 2337 omta_is("opacity", 0.75, RunningOn.Compositor, 2338 "anim3 the same as anim2 at 775ms"); 2339 // Extra waitForPaintsFlushed to expose bugs. 2340 await waitForPaintsFlushed(); 2341 advance_clock(50); 2342 // Wait for paints because we're resending animations to the 2343 // compositor via an UpdateOpacityLayer hint, which does the resending 2344 // via painting. 2345 await waitForPaints(); 2346 omta_is("opacity", 0.75, RunningOn.Compositor, 2347 "anim2 at 825ms"); 2348 advance_clock(75); 2349 omta_is("opacity", 0.875, RunningOn.Compositor, 2350 "anim2 at 900ms"); 2351 done_div(); 2352 2353 // Test that an interpolation that produces transform: none doesn't 2354 // crash. 2355 new_div("animation: transformnone 1s linear"); 2356 await waitForPaintsFlushed(); 2357 omta_is("transform", { tx: 50 }, RunningOn.Compositor, 2358 "transformnone animation at 0ms"); 2359 advance_clock(500); 2360 omta_is("transform", { tx: 0 }, RunningOn.Compositor, 2361 "transformnone animation at 500ms, interpolating none values"); 2362 done_div(); 2363 }); 2364 2365 addAsyncAnimTest(async function() { 2366 new_div("transform: translate(100px); transition: transform 10s 5s linear"); 2367 await waitForPaintsFlushed(); 2368 gDiv.style.transform = "translate(200px)"; 2369 await waitForPaintsFlushed(); 2370 // NOTE: As noted above, getOMTAStyle() can't detect the animation is running 2371 // on the compositor during the delay phase. 2372 omta_is("transform", { tx: 100 }, RunningOn.Either, 2373 "transition runs on compositor thread during delay"); 2374 // At the *very* start of the transition the start value of the transition 2375 // will match the underlying transform value. Various optimizations in 2376 // RestyleManager may recognize this a "no change" and filter out the 2377 // transition meaning that the animation doesn't get added to the compositor 2378 // thread until the first time the value changes. As a result, we fast-forward 2379 // a little past the beginning and then wait for the animation to be sent 2380 // to the compositor. 2381 advance_clock(5100); 2382 await waitForPaints(); 2383 omta_is("transform", { tx: 101 }, RunningOn.Compositor, 2384 "transition runs on compositor at start of active interval"); 2385 advance_clock(4900); 2386 omta_is("transform", { tx: 150 }, RunningOn.Compositor, 2387 "transition runs on compositor at during active interval"); 2388 advance_clock(5000); 2389 // Currently the compositor will apply a forwards fill until it gets told by 2390 // the main thread to clear the animation. As a result we should wait for 2391 // paints before checking that the animated value does *not* appear on the 2392 // compositor thread. 2393 await waitForPaints(); 2394 omta_is("transform", { tx: 200 }, RunningOn.MainThread, 2395 "transition runs on main thread at end of active interval"); 2396 2397 done_div(); 2398 }); 2399 2400 // Normal background-color animation. 2401 addAsyncAnimTest(async function() { 2402 new_div("background-color: rgb(255, 0, 0); " + 2403 "transition: background-color 10s linear"); 2404 await waitForPaintsFlushed(); 2405 2406 gDiv.style.backgroundColor = "rgb(0, 255, 0)"; 2407 await waitForPaintsFlushed(); 2408 2409 omta_is("background-color", "rgb(255, 0, 0)", RunningOn.Compositor, 2410 "background-color transition runs on compositor thread"); 2411 2412 advance_clock(5000); 2413 omta_is("background-color", "rgb(128, 128, 0)", RunningOn.Compositor, 2414 "background-color on compositor at 5s"); 2415 2416 done_div(); 2417 }); 2418 2419 // background-color animation with currentColor. 2420 addAsyncAnimTest(async function() { 2421 new_div("color: rgb(255, 0, 0); " + 2422 "background-color: currentColor; " + 2423 "transition: background-color 10s linear"); 2424 await waitForPaintsFlushed(); 2425 2426 gDiv.style.backgroundColor = "rgb(0, 255, 0)"; 2427 await waitForPaintsFlushed(); 2428 2429 omta_todo_is("background-color", "rgb(255, 0, 0)", RunningOn.TodoCompositor, 2430 "background-color transition starting with current-color runs on " + 2431 "compositor thread"); 2432 2433 advance_clock(5000); 2434 omta_todo_is("background-color", "rgb(128, 128, 0)", RunningOn.TodoCompositor, 2435 "background-color on compositor at 5s"); 2436 2437 done_div(); 2438 }); 2439 2440 // Tests that a background-color animation from inherited currentColor to 2441 // a normal color on the compositor is updated when the parent color is 2442 // changed. 2443 addAsyncAnimTest(async function() { 2444 new_div(""); 2445 const parent = document.createElement("div"); 2446 gDiv.parentNode.insertBefore(parent, gDiv); 2447 parent.style.color = "rgb(255, 0, 0)"; 2448 parent.appendChild(gDiv); 2449 2450 gDiv.animate({ backgroundColor: [ "currentColor", "rgb(0, 255, 0)" ] }, 1000); 2451 2452 await waitForPaintsFlushed(); 2453 2454 omta_todo_is("background-color", "rgb(255, 0, 0)", RunningOn.TodoCompositor, 2455 "background-color animation starting with current-color runs on " + 2456 "compositor thread"); 2457 2458 advance_clock(500); 2459 2460 omta_todo_is("background-color", "rgb(128, 128, 0)", RunningOn.TodoCompositor, 2461 "background-color on compositor at 5s"); 2462 2463 // Change the parent's color in the middle of the animation. 2464 parent.style.color = "rgb(0, 0, 255)"; 2465 await waitForPaintsFlushed(); 2466 2467 omta_todo_is("background-color", "rgb(0, 128, 128)", RunningOn.TodoCompositor, 2468 "background-color on compositor is reflected by the parent's " + 2469 "color change"); 2470 2471 done_div(); 2472 parent.remove(); 2473 }); 2474 2475 // Tests that a background-color animation from currentColor to a normal color 2476 // on <a> element is updated when the link is visited. 2477 addAsyncAnimTest(async function() { 2478 if (AppConstants.platform === "android") { 2479 todo(false, "no global history on GeckoView; can't run test"); 2480 return; 2481 } 2482 2483 [ gDiv ] = new_element("a", "display: block"); 2484 gDiv.setAttribute("href", "not-exist.html"); 2485 gDiv.classList.add("visited"); 2486 2487 const extraStyle = document.createElement('style'); 2488 document.head.appendChild(extraStyle); 2489 extraStyle.sheet.insertRule(".visited:visited { color: rgb(0, 0, 255); }", 0); 2490 extraStyle.sheet.insertRule(".visited:link { color: rgb(255, 0, 0); }", 1); 2491 2492 gDiv.animate({ backgroundColor: [ "currentColor", "rgb(0, 255, 0)" ] }, 1000); 2493 await waitForPaintsFlushed(); 2494 2495 omta_todo_is("background-color", "rgb(255, 0, 0)", RunningOn.TodoCompositor, 2496 "background-color animation starting with current-color runs on " + 2497 "compositor thread"); 2498 2499 advance_clock(500); 2500 2501 omta_todo_is("background-color", "rgb(128, 128, 0)", RunningOn.TodoCompositor, 2502 "background-color on compositor at 5s"); 2503 2504 const topLocation = 2505 await SpecialPowers.spawnChrome([], () => browsingContext.top.currentURI.spec); 2506 gDiv.setAttribute("href", topLocation); 2507 await waitForVisitedLinkColoring(gDiv, "color", "rgb(0, 0, 255)"); 2508 await waitForPaintsFlushed(); 2509 2510 // `omta_is` checks that the result on the compositor equals to the value by 2511 // getComputedValue() but getComputedValue lies for visited link values so 2512 // we use getOMTAStyle directly instead. 2513 todo_is(SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "background-color"), 2514 "rgb(0, 128, 128)", 2515 "background-color on <a> element after the link is visited"); 2516 2517 extraStyle.remove(); 2518 done_element(); 2519 gDiv = null; 2520 }); 2521 2522 // Normal translate animation. 2523 addAsyncAnimTest(async function() { 2524 new_div("translate: 100px; " + 2525 "transition: translate 10s linear"); 2526 await waitForPaintsFlushed(); 2527 2528 gDiv.style.translate = "200px"; 2529 await waitForPaintsFlushed(); 2530 2531 omta_is("translate", { compositorValue: { tx: 100 }, computed: "100px" }, 2532 RunningOn.Compositor, 2533 "translate transition runs on compositor thread"); 2534 2535 advance_clock(5000); 2536 omta_is("translate", { compositorValue: { tx: 150 }, computed: "150px" }, 2537 RunningOn.Compositor, "translate on compositor at 5s"); 2538 2539 done_div(); 2540 }); 2541 2542 // Normal rotate animation. 2543 addAsyncAnimTest(async function() { 2544 new_div("rotate: 0deg; " + 2545 "transition: rotate 10s linear"); 2546 await waitForPaintsFlushed(); 2547 2548 gDiv.style.rotate = "90deg"; 2549 await waitForPaintsFlushed(); 2550 2551 omta_is("rotate", { compositorValue: [ 1, 0, 0, 1, 0, 0 ], computed: "0deg"}, 2552 RunningOn.Compositor, "rotate transition runs on compositor thread"); 2553 2554 advance_clock(5000); 2555 omta_is("rotate", 2556 { compositorValue: [ Math.cos(Math.PI / 4), Math.sin(Math.PI / 4), 2557 -Math.sin(Math.PI / 4), Math.cos(Math.PI / 4), 2558 0, 0 ], 2559 computed: "45deg" }, RunningOn.Compositor, 2560 "rotate on compositor at 5s"); 2561 2562 done_div(); 2563 }); 2564 2565 // Normal scale animation. 2566 addAsyncAnimTest(async function() { 2567 new_div("scale: 1 1; " + 2568 "transition: scale 10s linear"); 2569 await waitForPaintsFlushed(); 2570 2571 gDiv.style.scale = "2 2"; 2572 await waitForPaintsFlushed(); 2573 2574 omta_is("scale", { compositorValue: [ 1, 0, 0, 1, 0, 0 ], computed: "1" }, 2575 RunningOn.Compositor, "scale transition runs on compositor thread"); 2576 2577 advance_clock(5000); 2578 omta_is("scale", 2579 { compositorValue: [ 1.5, 0, 0, 1.5, 0, 0 ], computed: "1.5" }, 2580 RunningOn.Compositor, "scale on compositor at 5s"); 2581 2582 done_div(); 2583 }); 2584 2585 // Normal multiple transform-like properties animation. 2586 addAsyncAnimTest(async function() { 2587 new_div("translate: 100px; " + 2588 "scale: 1 1; " + 2589 "transform: translate(200px); " + 2590 "transition: all 10s linear"); 2591 await waitForPaintsFlushed(); 2592 2593 gDiv.style.translate = "200px"; 2594 gDiv.style.scale = "2 2"; 2595 gDiv.style.transform = "translate(100px)"; 2596 await waitForPaintsFlushed(); 2597 2598 omta_is("transform", { compositorValue: { tx: 300 }, 2599 usesMultipleProperties: true }, 2600 RunningOn.Compositor, 2601 "transform-like properties transition runs on compositor thread"); 2602 2603 advance_clock(5000); 2604 2605 omta_is("transform", 2606 // The order is: translate, scale, transform. 2607 // So the translate() in transform should be multiplied by 1.5. 2608 { compositorValue: [ 1.5, 0, 0, 1.5, (150 + 150*1.5), 0 ], 2609 usesMultipleProperties: true }, 2610 RunningOn.Compositor, 2611 "transform-like properties on compositor at 5s"); 2612 2613 done_div(); 2614 }); 2615 2616 // Multiple transform-like properties animation. The non-animating properties 2617 // shouldn't be overridden by animating ones. 2618 addAsyncAnimTest(async function() { 2619 new_div("translate: 100px; " + 2620 "scale: 1 1; " + 2621 "transform: translate(200px); " + 2622 "transition: all 10s linear"); 2623 await waitForPaintsFlushed(); 2624 2625 // No transition on transform property. 2626 gDiv.style.translate = "200px"; 2627 gDiv.style.scale = "2 2"; 2628 await waitForPaintsFlushed(); 2629 2630 omta_is("transform", { compositorValue: { tx: 300 }, 2631 usesMultipleProperties: true }, 2632 RunningOn.Compositor, 2633 "transform-like properties transition runs on compositor thread"); 2634 2635 advance_clock(5000); 2636 2637 omta_is("transform", 2638 // The order is: translate, scale, transform. 2639 // So the translate() in transform should be multiplied by 1.5. 2640 { compositorValue: [ 1.5, 0, 0, 1.5, (150 + 200*1.5), 0 ], 2641 usesMultipleProperties: true }, 2642 RunningOn.Compositor, 2643 "transform-like properties on compositor at 5s"); 2644 2645 done_div(); 2646 }); 2647 2648 // Multiple transform-like properties animation with delay. The delayed 2649 // animating properties shouldn't be overridden. 2650 // 2651 // Note: 2652 // In delay phase, the SampleResult should be None, even though there is 2653 // an non-animating property which is also sent to the compositor. 2654 // If the SampleResult is Sampled in this case, we may get an incorrect result 2655 // ("scale" would be "1" because the final matrix is calculated by a default 2656 // scale value which overrides the scale css style). 2657 // That's why we shouldn't take non-animating properties into account on 2658 // SampleResult. 2659 addAsyncAnimTest(async function() { 2660 new_div("translate: 100px; " + 2661 "scale: 1.25 1.25; " + 2662 "animation: kf_scale 10s 2.5s linear"); 2663 await waitForPaintsFlushed(); 2664 2665 // All transform-like properties use DisplayItemType::TYPE_TRANSFORM, 2666 // so using "transform" is enough. 2667 var compositorStr = 2668 SpecialPowers.DOMWindowUtils.getOMTAStyle(gDiv, "transform"); 2669 ok(compositorStr === "", 2670 "transform-like properties should not run on the compositor at 0s " + 2671 "(in delay phase)"); 2672 var computedStr = window.getComputedStyle(gDiv).translate; 2673 ok(computedStr === "100px", 2674 "The computed value of translate property should be equal to 100px " + 2675 "in delay phase, got " + computedStr); 2676 computedStr = window.getComputedStyle(gDiv).scale; 2677 ok(computedStr === "1.25", 2678 "The computed value of scale property should be equal to 1.25 " + 2679 "in delay phase, got " + computedStr); 2680 2681 advance_clock(2500); 2682 2683 omta_is("transform", { compositorValue: [ 1.25, 0, 0, 1.25, 100, 0 ], 2684 usesMultipleProperties: true }, 2685 RunningOn.Compositor, 2686 "transform-like properties on compositor at 2.5s"); 2687 2688 advance_clock(5000); 2689 2690 omta_is("transform", 2691 { compositorValue: [ 1.75, 0, 0, 1.75, 100, 0 ], 2692 usesMultipleProperties: true }, 2693 RunningOn.Compositor, 2694 "transform-like properties on compositor at 7.5s"); 2695 2696 done_div(); 2697 }); 2698 2699 // Normal offset-path animation with path(). 2700 addAsyncAnimTest(async function() { 2701 new_div("offset-path: path('M50 50L100 100'); " + 2702 "offset-distance: 50%; " + 2703 "offset-rotate: 0deg; " + 2704 "transition: offset-path 10s linear"); 2705 await waitForPaintsFlushed(); 2706 2707 gDiv.style.offsetPath = "path('M50 50L200 200')"; 2708 await waitForPaintsFlushed(); 2709 2710 omta_is("offset-path", 2711 { compositorValue: { tx: 25, ty: 25 }, 2712 computed: 'path("M 50 50 L 100 100")' }, 2713 RunningOn.Compositor, 2714 "offset-path transition runs on compositor thread"); 2715 2716 advance_clock(5000); 2717 2718 omta_is("offset-path", 2719 { compositorValue: { tx: 50, ty: 50 }, 2720 computed: 'path("M 50 50 L 150 150")' }, 2721 RunningOn.Compositor, 2722 "offset-path on compositor at 5s"); 2723 2724 done_div(); 2725 }); 2726 2727 // Normal offset-path animation with ray(). 2728 addAsyncAnimTest(async function() { 2729 new_div("offset-path: ray(90deg); " + 2730 "offset-distance: 0%; " + 2731 "offset-position: auto; " + 2732 "transition: offset-path 10s linear"); 2733 await waitForPaintsFlushed(); 2734 2735 gDiv.style.offsetPath = "ray(180deg)"; 2736 await waitForPaintsFlushed(); 2737 2738 // At 0%, it's ray(90deg), so there is no rotation and only movement because 2739 // the default offset-anchor is 50%. 2740 omta_is("offset-path", 2741 { compositorValue: { tx: -50, ty: -50 }, 2742 computed: 'ray(90deg)' }, 2743 RunningOn.Compositor, 2744 "offset-path transition runs on compositor thread"); 2745 2746 advance_clock(5000); 2747 2748 // At 50%, ray() is 135deg. so the matrix is kind of rotate -45 deg: 2749 // [cos(-1/4 * pi), -sin(-1/4 * pi), sin(-1/4 * pi), cos(-1/4 * pi), -50, -50] 2750 // Note: the movement of (-50 -50) is from the default offset-anchor. 2751 omta_is("offset-path", 2752 { 2753 compositorValue: [ 2754 Math.cos(-Math.PI * 1/4), -Math.sin(-Math.PI * 1/4), 2755 Math.sin(-Math.PI * 1/4), Math.cos(-Math.PI * 1/4), 2756 -50, -50 2757 ], 2758 computed: 'ray(135deg)' 2759 }, 2760 RunningOn.Compositor, 2761 "offset-path on compositor at 5s"); 2762 2763 done_div(); 2764 }); 2765 2766 // Normal offset-path animation with polygon(). 2767 addAsyncAnimTest(async function() { 2768 new_div("offset-path: polygon(0px 0px, 100px 0px, 50px 100px); " + 2769 "offset-distance: 0%; " + 2770 "offset-rotate: 0deg; " + 2771 "offset-anchor: left top; " + 2772 "transition: offset-path 10s linear"); 2773 await waitForPaintsFlushed(); 2774 2775 gDiv.style.offsetPath = "polygon(50px 0px, 100px 0px, 50px 100px)"; 2776 await waitForPaintsFlushed(); 2777 2778 omta_is("offset-path", 2779 { compositorValue: { tx: 0 }, 2780 computed: 'polygon(0px 0px, 100px 0px, 50px 100px)' }, 2781 RunningOn.Compositor, 2782 "offset-path transition runs on compositor thread"); 2783 2784 advance_clock(5000); 2785 2786 omta_is("offset-path", 2787 { compositorValue: { tx: 25 }, 2788 computed: 'polygon(25px 0px, 100px 0px, 50px 100px)' }, 2789 RunningOn.Compositor, 2790 "offset-path on compositor at 5s"); 2791 2792 done_div(); 2793 }); 2794 2795 // Normal offset-distance animation with path(). 2796 addAsyncAnimTest(async function() { 2797 new_div("offset-path: path('M50 50v100'); " + 2798 "offset-distance: 0%; " + 2799 "offset-rotate: 0deg; " + 2800 "transition: offset-distance 10s linear"); 2801 await waitForPaintsFlushed(); 2802 2803 gDiv.style.offsetDistance = "100%"; 2804 await waitForPaintsFlushed(); 2805 2806 omta_is("offset-distance", 2807 { compositorValue: { ty: 0 }, computed: '0%' }, 2808 RunningOn.Compositor, 2809 "offset-distance transition runs on compositor thread"); 2810 2811 advance_clock(5000); 2812 2813 omta_is("offset-distance", 2814 { compositorValue: { ty: 50 }, computed: '50%' }, 2815 RunningOn.Compositor, 2816 "offset-distance on compositor at 5s"); 2817 2818 done_div(); 2819 }); 2820 2821 // Normal offset-distance animation with polygon(). 2822 addAsyncAnimTest(async function() { 2823 new_div("offset-path: polygon(0px 0px, 100px 0px, 100px 50px, 0px 50px); " + 2824 "offset-distance: 0%; " + 2825 "offset-rotate: 0deg; " + 2826 "offset-anchor: left top; " + 2827 "transition: offset-distance 10s linear"); 2828 await waitForPaintsFlushed(); 2829 2830 gDiv.style.offsetDistance = "100%"; 2831 await waitForPaintsFlushed(); 2832 2833 omta_is("offset-distance", 2834 { compositorValue: { tx: 0 }, computed: '0%' }, 2835 RunningOn.Compositor, 2836 "offset-distance transition runs on compositor thread"); 2837 2838 advance_clock(5000); 2839 2840 omta_is("offset-distance", 2841 { compositorValue: { tx: 100, ty: 50 }, computed: '50%' }, 2842 RunningOn.Compositor, 2843 "offset-distance on compositor at 5s"); 2844 2845 done_div(); 2846 }); 2847 2848 // Normal offset-rotate animation. 2849 addAsyncAnimTest(async function() { 2850 new_div("offset-path: path('M50 50v100'); " + 2851 "offset-rotate: auto; " + 2852 "transition: offset-rotate 10s linear"); 2853 await waitForPaintsFlushed(); 2854 2855 gDiv.style.offsetRotate = "auto 90deg"; 2856 await waitForPaintsFlushed(); 2857 2858 // The direction vector is 90deg (because the path go from top to bottom), and 2859 // offset-rotate is auto 0deg, so the entire rotation is 90deg. 2860 // The matrix is [cos(pi/2), sin(pi/2), -sin(pi/2), cos(pi/2), 0, 0]. 2861 omta_is("offset-rotate", 2862 { compositorValue: [ 0, 1, -1, 0, 0, 0 ], computed: 'auto' }, 2863 RunningOn.Compositor, 2864 "offset-rotate transition runs on compositor thread"); 2865 2866 advance_clock(5000); 2867 2868 // At 50%, offset-rotate is auto 45deg, so the entire rotation is 135deg 2869 // (= 90deg + 45deg = pi * 3/4), so the matrix is 2870 // [cos(pi * 3/4), sin(pi * 3/4), -sin(pi * 3/4), cos(pi * 3/4), 0, 0] 2871 omta_is("offset-rotate", 2872 { 2873 compositorValue: [ 2874 Math.cos(Math.PI * 3/4), Math.sin(Math.PI * 3/4), 2875 -Math.sin(Math.PI * 3/4), Math.cos(Math.PI * 3/4), 2876 0, 0 2877 ], 2878 computed: 'auto 45deg', 2879 }, 2880 RunningOn.Compositor, 2881 "offset-rotate on compositor at 5s"); 2882 2883 done_div(); 2884 }); 2885 2886 // Normal offset-anchor animation. 2887 addAsyncAnimTest(async function() { 2888 new_div("offset-path: path('M50 50v100'); " + 2889 "offset-rotate: 0deg; " + 2890 "offset-anchor: 0% 0%; " + 2891 "transition: offset-anchor 10s linear"); 2892 await waitForPaintsFlushed(); 2893 2894 gDiv.style.offsetAnchor = "100% 100%"; 2895 await waitForPaintsFlushed(); 2896 2897 omta_is("offset-anchor", 2898 { compositorValue: { tx: 50, ty: 50 }, computed: '0% 0%' }, 2899 RunningOn.Compositor, 2900 "offset-anchor transition runs on compositor thread"); 2901 2902 advance_clock(5000); 2903 2904 omta_is("offset-anchor", 2905 { compositorValue: { tx: 0, ty: 0 }, computed: '50% 50%' }, 2906 RunningOn.Compositor, 2907 "offset-anchor on compositor at 5s"); 2908 2909 done_div(); 2910 }); 2911 2912 // Normal offset-position animation. 2913 addAsyncAnimTest(async function() { 2914 new_div("offset-path: ray(0deg sides); " + 2915 "offset-rotate: 0deg; " + 2916 "offset-anchor: 0% 0%; " + 2917 "offset-position: 0px 0px; " + 2918 "transition: offset-position 10s linear"); 2919 await waitForPaintsFlushed(); 2920 2921 gDiv.style.offsetPosition = "100px 100px"; 2922 await waitForPaintsFlushed(); 2923 2924 omta_is("offset-position", 2925 { compositorValue: { tx: 0, ty: 0 }, computed: '0px 0px' }, 2926 RunningOn.Compositor, 2927 "offset-position transition runs on compositor thread"); 2928 2929 advance_clock(5000); 2930 2931 omta_is("offset-position", 2932 { compositorValue: { tx: 50, ty: 50 }, computed: '50px 50px' }, 2933 RunningOn.Compositor, 2934 "offset-position on compositor at 5s"); 2935 2936 done_div(); 2937 }); 2938 2939 // Normal multiple transform-like properties animation (including motion-path). 2940 addAsyncAnimTest(async function() { 2941 new_div("translate: 0px; " + 2942 "offset-path: path('M50 50v100');" + 2943 "offset-distance: 0%;" + 2944 "transform: translateX(0px); " + 2945 "transition: all 10s linear"); 2946 await waitForPaintsFlushed(); 2947 2948 gDiv.style.translate = "0px 100px"; 2949 gDiv.style.transform = "translateX(-100px)"; 2950 gDiv.style.offsetDistance = "100%"; 2951 await waitForPaintsFlushed(); 2952 2953 omta_is("transform", { compositorValue: [ 0, 1, -1, 0, 0, 0 ], 2954 usesMultipleProperties: true }, 2955 RunningOn.Compositor, 2956 "transform-like properties transition runs on compositor thread"); 2957 2958 advance_clock(5000); 2959 2960 omta_is("transform", { compositorValue: [ 0, 1, -1, 0, 0, 50 ], 2961 usesMultipleProperties: true }, 2962 RunningOn.Compositor, 2963 "transform-like properties transition runs on compositor thread"); 2964 2965 done_div(); 2966 }); 2967 2968 </script> 2969 </html>