tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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>