tor-browser

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

test_missing-keyframe-on-compositor.html (21699B)


      1 <!doctype html>
      2 <meta charset=utf-8>
      3 <script src="/resources/testharness.js"></script>
      4 <script src="/resources/testharnessreport.js"></script>
      5 <script src="../testcommon.js"></script>
      6 <script src="/tests/SimpleTest/paint_listener.js"></script>
      7 <style>
      8 div {
      9  /* Element needs geometry to be eligible for layerization */
     10  width: 100px;
     11  height: 100px;
     12  background-color: white;
     13 }
     14 </style>
     15 <body>
     16 <div id="log"></div>
     17 <script>
     18 'use strict';
     19 
     20 if (!SpecialPowers.DOMWindowUtils.layerManagerRemote ||
     21    !SpecialPowers.getBoolPref(
     22      'layers.offmainthreadcomposition.async-animations')) {
     23  // If OMTA is disabled, nothing to run.
     24  done();
     25 }
     26 
     27 function waitForPaintsFlushed() {
     28  return new Promise(function(resolve, reject) {
     29    waitForAllPaintsFlushed(resolve);
     30  });
     31 }
     32 
     33 // Note that promise tests run in sequence so this ensures the document is
     34 // loaded before any of the other tests run.
     35 promise_test(t => {
     36  // Without this, the first test case fails on Android.
     37  return waitForDocumentLoad();
     38 }, 'Ensure document has been loaded');
     39 
     40 promise_test(t => {
     41  var div;
     42  return useTestRefreshMode(t).then(() => {
     43    div = addDiv(t, { style: 'opacity: 0.1' });
     44    div.animate({ opacity: 1 }, 100 * MS_PER_SEC);
     45    return waitForPaintsFlushed();
     46  }).then(() => {
     47    var opacity =
     48      SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'opacity');
     49    assert_equals(opacity, '0.1',
     50                  'The initial opacity value should be the base value');
     51  });
     52 }, 'Initial opacity value for animation with no no keyframe at offset 0');
     53 
     54 promise_test(t => {
     55  var div;
     56  return useTestRefreshMode(t).then(() => {
     57    div = addDiv(t, { style: 'opacity: 0.1' });
     58    div.animate({ opacity: [ 0.5, 1 ] }, 100 * MS_PER_SEC);
     59    div.animate({ opacity: 1 }, 100 * MS_PER_SEC);
     60 
     61    return waitForPaintsFlushed();
     62  }).then(() => {
     63    var opacity =
     64      SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'opacity');
     65    assert_equals(opacity, '0.5',
     66                  'The initial opacity value should be the value of ' +
     67                  'lower-priority animation value');
     68  });
     69 }, 'Initial opacity value for animation with no keyframe at offset 0 when ' +
     70   'there is a lower-priority animation');
     71 
     72 promise_test(t => {
     73  var div;
     74  return useTestRefreshMode(t).then(() => {
     75    div = addDiv(t, { style: 'opacity: 0.1; transition: opacity 100s linear' });
     76    getComputedStyle(div).opacity;
     77 
     78    div.style.opacity = '0.5';
     79    getComputedStyle(div).opacity;
     80 
     81    div.animate({ opacity: 1 }, 100 * MS_PER_SEC);
     82 
     83    return waitForPaintsFlushed();
     84  }).then(() => {
     85    var opacity =
     86      SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'opacity');
     87    assert_equals(opacity, '0.1',
     88                  'The initial opacity value should be the initial value of ' +
     89                  'the transition');
     90  });
     91 }, 'Initial opacity value for animation with no keyframe at offset 0 when ' +
     92   'there is a transition on the same property');
     93 
     94 promise_test(t => {
     95  var div;
     96  return useTestRefreshMode(t).then(() => {
     97    div = addDiv(t, { style: 'opacity: 0' });
     98    div.animate([{ offset: 0, opacity: 1 }], 100 * MS_PER_SEC);
     99 
    100    return waitForPaintsFlushed();
    101  }).then(() => {
    102    SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(50 * MS_PER_SEC);
    103 
    104    var opacity =
    105      SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'opacity');
    106    assert_equals(opacity, '0.5',
    107                  'Opacity value at 50% should be composed onto the base ' +
    108                  'value');
    109  });
    110 }, 'Opacity value for animation with no keyframe at offset 1 at 50% ');
    111 
    112 promise_test(t => {
    113  var div;
    114  return useTestRefreshMode(t).then(() => {
    115    div = addDiv(t, { style: 'opacity: 0' });
    116    div.animate({ opacity: [ 0.5, 0.5 ] }, 100 * MS_PER_SEC);
    117    div.animate([{ offset: 0, opacity: 1 }], 100 * MS_PER_SEC);
    118 
    119    return waitForPaintsFlushed();
    120  }).then(() => {
    121    SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(50 * MS_PER_SEC);
    122 
    123    var opacity =
    124      SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'opacity');
    125    assert_equals(opacity, '0.75', // (0.5 + 1) * 0.5
    126                  'Opacity value at 50% should be composed onto the value ' +
    127                  'of middle of lower-priority animation');
    128  });
    129 }, 'Opacity value for animation with no keyframe at offset 1 at 50% when ' +
    130   'there is a lower-priority animation');
    131 
    132 promise_test(t => {
    133  var div;
    134  return useTestRefreshMode(t).then(() => {
    135    div = addDiv(t, { style: 'opacity: 0; transition: opacity 100s linear' });
    136    getComputedStyle(div).opacity;
    137 
    138    div.style.opacity = '0.5';
    139    getComputedStyle(div).opacity;
    140 
    141    div.animate([{ offset: 0, opacity: 1 }], 100 * MS_PER_SEC);
    142 
    143    return waitForPaintsFlushed();
    144  }).then(() => {
    145    SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(50 * MS_PER_SEC);
    146 
    147    var opacity =
    148      SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'opacity');
    149    assert_equals(opacity, '0.625', // ((0 + 0.5) * 0.5 + 1) * 0.5
    150                  'Opacity value at 50% should be composed onto the value ' +
    151                  'of middle of transition');
    152  });
    153 }, 'Opacity value for animation with no keyframe at offset 1 at 50% when ' +
    154   'there is a transition on the same property');
    155 
    156 promise_test(t => {
    157  var div;
    158  var lowerAnimation;
    159  return useTestRefreshMode(t).then(() => {
    160    div = addDiv(t);
    161    lowerAnimation = div.animate({ opacity: [ 0.5, 1 ] }, 100 * MS_PER_SEC);
    162    var higherAnimation = div.animate({ opacity: 1 }, 100 * MS_PER_SEC);
    163 
    164    return waitForPaintsFlushed();
    165  }).then(() => {
    166    lowerAnimation.pause();
    167    return waitForPaintsFlushed();
    168  }).then(() => {
    169    SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(50 * MS_PER_SEC);
    170 
    171    var opacity =
    172      SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'opacity');
    173    // The underlying value is the value that is staying at 0ms of the
    174    // lowerAnimation, that is 0.5.
    175    // (0.5 + 1.0) * (50 * MS_PER_SEC / 100 * MS_PER_SEC) = 0.75.
    176    assert_equals(opacity, '0.75',
    177                  'Composed opacity value should be composed onto the value ' +
    178                  'of lower-priority paused animation');
    179  });
    180 }, 'Opacity value for animation with no keyframe at offset 0 at 50% when ' +
    181   'composed onto a paused underlying animation');
    182 
    183 promise_test(t => {
    184  var div;
    185  var lowerAnimation;
    186  return useTestRefreshMode(t).then(() => {
    187    div = addDiv(t);
    188    lowerAnimation = div.animate({ opacity: [ 0.5, 1 ] }, 100 * MS_PER_SEC);
    189    var higherAnimation = div.animate({ opacity: 1 }, 100 * MS_PER_SEC);
    190 
    191    return waitForPaintsFlushed();
    192  }).then(() => {
    193    lowerAnimation.playbackRate = 0;
    194    return waitForPaintsFlushed();
    195  }).then(() => {
    196    SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(50 * MS_PER_SEC);
    197 
    198    var opacity =
    199      SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'opacity');
    200    // The underlying value is the value that is staying at 0ms of the
    201    // lowerAnimation, that is 0.5.
    202    // (0.5 + 1.0) * (50 * MS_PER_SEC / 100 * MS_PER_SEC) = 0.75.
    203    assert_equals(opacity, '0.75',
    204                  'Composed opacity value should be composed onto the value ' +
    205                  'of lower-priority zero playback rate animation');
    206  });
    207 }, 'Opacity value for animation with no keyframe at offset 0 at 50% when ' +
    208   'composed onto a zero playback rate underlying animation');
    209 
    210 promise_test(t => {
    211  var div;
    212  var lowerAnimation;
    213  return useTestRefreshMode(t).then(() => {
    214    div = addDiv(t);
    215    lowerAnimation = div.animate({ opacity: [ 1, 0.5 ] }, 100 * MS_PER_SEC);
    216    var higherAnimation = div.animate({ opacity: 1 }, 100 * MS_PER_SEC);
    217 
    218    return waitForPaintsFlushed();
    219  }).then(() => {
    220    lowerAnimation.effect.updateTiming({
    221      duration: 0,
    222      fill: 'forwards',
    223    });
    224    return waitForPaintsFlushed();
    225  }).then(() => {
    226    SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(50 * MS_PER_SEC);
    227 
    228    var opacity =
    229      SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'opacity');
    230    // The underlying value is the value that is filling forwards state of the
    231    // lowerAnimation, that is 0.5.
    232    // (0.5 + 1.0) * (50 * MS_PER_SEC / 100 * MS_PER_SEC) = 0.75.
    233    assert_equals(opacity, '0.75',
    234                  'Composed opacity value should be composed onto the value ' +
    235                  'of lower-priority zero active duration animation');
    236  });
    237 }, 'Opacity value for animation with no keyframe at offset 0 at 50% when ' +
    238   'composed onto a zero active duration underlying animation');
    239 
    240 promise_test(t => {
    241  var div;
    242  return useTestRefreshMode(t).then(() => {
    243    div = addDiv(t, { style: 'transform: translateX(100px)' });
    244    div.animate({ transform: 'translateX(200px)' }, 100 * MS_PER_SEC);
    245 
    246    return waitForPaintsFlushed();
    247  }).then(() => {
    248    var transform =
    249      SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform');
    250    assert_matrix_equals(transform, 'matrix(1, 0, 0, 1, 100, 0)',
    251      'The initial transform value should be the base value');
    252  });
    253 }, 'Initial transform value for animation with no keyframe at offset 0');
    254 
    255 promise_test(t => {
    256  var div;
    257  return useTestRefreshMode(t).then(() => {
    258    div = addDiv(t, { style: 'transform: translateX(100px)' });
    259    div.animate({ transform: [ 'translateX(200px)', 'translateX(300px)' ] },
    260                100 * MS_PER_SEC);
    261    div.animate({ transform: 'translateX(400px)' }, 100 * MS_PER_SEC);
    262 
    263    return waitForPaintsFlushed();
    264  }).then(() => {
    265    var transform =
    266      SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform');
    267    assert_matrix_equals(transform, 'matrix(1, 0, 0, 1, 200, 0)',
    268      'The initial transform value should be lower-priority animation value');
    269  });
    270 }, 'Initial transform value for animation with no keyframe at offset 0 when ' +
    271   'there is a lower-priority animation');
    272 
    273 promise_test(t => {
    274  var div;
    275  return useTestRefreshMode(t).then(() => {
    276    div = addDiv(t, { style: 'transform: translateX(100px);' +
    277                             'transition: transform 100s linear' });
    278    getComputedStyle(div).transform;
    279 
    280    div.style.transform = 'translateX(200px)';
    281    getComputedStyle(div).transform;
    282 
    283    div.animate({ transform: 'translateX(400px)' }, 100 * MS_PER_SEC);
    284 
    285    return waitForPaintsFlushed();
    286  }).then(() => {
    287    var transform =
    288      SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform');
    289    assert_matrix_equals(transform, 'matrix(1, 0, 0, 1, 100, 0)',
    290      'The initial transform value should be the initial value of the ' +
    291      'transition');
    292  });
    293 }, 'Initial transform value for animation with no keyframe at offset 0 when ' +
    294   'there is a transition');
    295 
    296 promise_test(t => {
    297  var div;
    298  return useTestRefreshMode(t).then(() => {
    299    div = addDiv(t, { style: 'transform: translateX(100px)' });
    300    div.animate([{ offset: 0, transform: 'translateX(200pX)' }],
    301                100 * MS_PER_SEC);
    302 
    303    return waitForPaintsFlushed();
    304  }).then(() => {
    305    SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(50 * MS_PER_SEC);
    306 
    307    var transform =
    308      SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform');
    309    assert_matrix_equals(transform, 'matrix(1, 0, 0, 1, 150, 0)',
    310      'Transform value at 50% should be the base value');
    311  });
    312 }, 'Transform value for animation with no keyframe at offset 1 at 50%');
    313 
    314 promise_test(t => {
    315  var div;
    316  return useTestRefreshMode(t).then(() => {
    317    div = addDiv(t, { style: 'transform: translateX(100px)' });
    318    div.animate({ transform: [ 'translateX(200px)', 'translateX(200px)' ] },
    319                100 * MS_PER_SEC);
    320    div.animate([{ offset: 0, transform: 'translateX(300px)' }],
    321                100 * MS_PER_SEC);
    322 
    323    return waitForPaintsFlushed();
    324  }).then(() => {
    325    SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(50 * MS_PER_SEC);
    326 
    327    var transform =
    328      SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform');
    329    assert_matrix_equals(transform, 'matrix(1, 0, 0, 1, 250, 0)',
    330      'The final transform value should be the base value');
    331  });
    332 }, 'Transform value for animation with no keyframe at offset 1 at 50% when ' +
    333   'there is a lower-priority animation');
    334 
    335 promise_test(t => {
    336  var div;
    337  return useTestRefreshMode(t).then(() => {
    338    div = addDiv(t, { style: 'transform: translateX(100px);' +
    339                             'transition: transform 100s linear' });
    340    getComputedStyle(div).transform;
    341 
    342    div.style.transform = 'translateX(200px)';
    343    getComputedStyle(div).transform;
    344 
    345    div.animate([{ offset: 0, transform: 'translateX(300px)' }],
    346                100 * MS_PER_SEC);
    347 
    348    return waitForPaintsFlushed();
    349  }).then(() => {
    350    SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(50 * MS_PER_SEC);
    351 
    352    var transform =
    353      SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform');
    354                                                   // (150px + 300px) * 0.5
    355    assert_matrix_equals(transform, 'matrix(1, 0, 0, 1, 225, 0)',
    356      'The final transform value should be the final value of the transition');
    357  });
    358 }, 'Transform value for animation with no keyframe at offset 1 at 50% when ' +
    359   'there is a transition');
    360 
    361 promise_test(t => {
    362  var div;
    363  var lowerAnimation;
    364  return useTestRefreshMode(t).then(() => {
    365    div = addDiv(t);
    366    lowerAnimation =
    367      div.animate({ transform: [ 'translateX(100px)', 'translateX(200px)' ] },
    368                  100 * MS_PER_SEC);
    369    var higherAnimation = div.animate({ transform: 'translateX(300px)' },
    370                                      100 * MS_PER_SEC);
    371 
    372    return waitForPaintsFlushed();
    373  }).then(() => {
    374    lowerAnimation.pause();
    375    return waitForPaintsFlushed();
    376  }).then(() => {
    377    SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(50 * MS_PER_SEC);
    378 
    379    var transform =
    380      SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform');
    381    // The underlying value is the value that is staying at 0ms of the
    382    // lowerAnimation, that is 100px.
    383    // (100px + 300px) * (50 * MS_PER_SEC / 100 * MS_PER_SEC) = 200px.
    384    assert_matrix_equals(transform, 'matrix(1, 0, 0, 1, 200, 0)',
    385      'Composed transform value should be composed onto the value of ' +
    386      'lower-priority paused animation');
    387  });
    388 }, 'Transform value for animation with no keyframe at offset 0 at 50% when ' +
    389   'composed onto a paused underlying animation');
    390 
    391 promise_test(t => {
    392  var div;
    393  var lowerAnimation;
    394  return useTestRefreshMode(t).then(() => {
    395    div = addDiv(t);
    396    lowerAnimation =
    397      div.animate({ transform: [ 'translateX(100px)', 'translateX(200px)' ] },
    398                  100 * MS_PER_SEC);
    399    var higherAnimation = div.animate({ transform: 'translateX(300px)' },
    400                                      100 * MS_PER_SEC);
    401 
    402    return waitForPaintsFlushed();
    403  }).then(() => {
    404    lowerAnimation.playbackRate = 0;
    405    return waitForPaintsFlushed();
    406  }).then(() => {
    407    SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(50 * MS_PER_SEC);
    408 
    409    var transform =
    410      SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform');
    411    // The underlying value is the value that is staying at 0ms of the
    412    // lowerAnimation, that is 100px.
    413    // (100px + 300px) * (50 * MS_PER_SEC / 100 * MS_PER_SEC) = 200px.
    414    assert_matrix_equals(transform, 'matrix(1, 0, 0, 1, 200, 0)',
    415      'Composed transform value should be composed onto the value of ' +
    416      'lower-priority zero playback rate animation');
    417  });
    418 }, 'Transform value for animation with no keyframe at offset 0 at 50% when ' +
    419   'composed onto a zero playback rate underlying animation');
    420 
    421 promise_test(t => {
    422  var div;
    423  return useTestRefreshMode(t).then(() => {
    424    div = addDiv(t);
    425    var lowerAnimation =
    426      div.animate({ transform: [ 'translateX(100px)', 'translateX(200px)' ] },
    427                  { duration: 10 * MS_PER_SEC,
    428                    fill: 'forwards' });
    429    var higherAnimation = div.animate({ transform: 'translateX(300px)' },
    430                                      100 * MS_PER_SEC);
    431 
    432    return waitForPaintsFlushed();
    433  }).then(() => {
    434    SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(50 * MS_PER_SEC);
    435 
    436    // We need to wait for a paint so that we can send the state of the lower
    437    // animation that is actually finished at this point.
    438    return waitForPaintsFlushed();
    439  }).then(() => {
    440    var transform =
    441      SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform');
    442    // (200px + 300px) * (50 * MS_PER_SEC / 100 * MS_PER_SEC) = 250px.
    443    assert_matrix_equals(transform, 'matrix(1, 0, 0, 1, 250, 0)',
    444      'Composed transform value should be composed onto the value of ' +
    445      'lower-priority animation with fill:forwards');
    446  });
    447 }, 'Transform value for animation with no keyframe at offset 0 at 50% when ' +
    448   'composed onto a underlying animation with fill:forwards');
    449 
    450 promise_test(t => {
    451  var div;
    452  return useTestRefreshMode(t).then(() => {
    453    div = addDiv(t);
    454    var lowerAnimation =
    455      div.animate({ transform: [ 'translateX(100px)', 'translateX(200px)' ] },
    456                  { duration: 10 * MS_PER_SEC,
    457                    endDelay: -5 * MS_PER_SEC,
    458                    fill: 'forwards' });
    459    var higherAnimation = div.animate({ transform: 'translateX(300px)' },
    460                                      100 * MS_PER_SEC);
    461 
    462    return waitForPaintsFlushed();
    463  }).then(() => {
    464    SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(50 * MS_PER_SEC);
    465 
    466    // We need to wait for a paint just like the above test.
    467    return waitForPaintsFlushed();
    468  }).then(() => {
    469    var transform =
    470      SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform');
    471    // (150px + 300px) * (50 * MS_PER_SEC / 100 * MS_PER_SEC) = 225px.
    472    assert_matrix_equals(transform, 'matrix(1, 0, 0, 1, 225, 0)',
    473      'Composed transform value should be composed onto the value of ' +
    474      'lower-priority animation with fill:forwards and negative endDelay');
    475  });
    476 }, 'Transform value for animation with no keyframe at offset 0 at 50% when ' +
    477   'composed onto a underlying animation with fill:forwards and negative ' +
    478   'endDelay');
    479 
    480 promise_test(t => {
    481  var div;
    482  return useTestRefreshMode(t).then(() => {
    483    div = addDiv(t);
    484    var lowerAnimation =
    485      div.animate({ transform: [ 'translateX(100px)', 'translateX(200px)' ] },
    486                  { duration: 10 * MS_PER_SEC,
    487                    endDelay: 100 * MS_PER_SEC,
    488                    fill: 'forwards' });
    489    var higherAnimation = div.animate({ transform: 'translateX(300px)' },
    490                                      100 * MS_PER_SEC);
    491 
    492    return waitForPaintsFlushed();
    493  }).then(() => {
    494    SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(50 * MS_PER_SEC);
    495 
    496    var transform =
    497      SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform');
    498    // (200px + 300px) * 0.5
    499    assert_matrix_equals(transform, 'matrix(1, 0, 0, 1, 250, 0)',
    500      'Composed transform value should be composed onto the value of ' +
    501      'lower-priority animation with fill:forwards during positive endDelay');
    502  });
    503 }, 'Transform value for animation with no keyframe at offset 0 at 50% when ' +
    504   'composed onto a underlying animation with fill:forwards during positive ' +
    505   'endDelay');
    506 
    507 promise_test(t => {
    508  var div;
    509  return useTestRefreshMode(t).then(() => {
    510    div = addDiv(t, { style: 'transform: translateX(100px)' });
    511    div.animate({ transform: 'translateX(200px)' },
    512                { duration: 100 * MS_PER_SEC, delay: 50 * MS_PER_SEC });
    513 
    514    return waitForPaintsFlushed();
    515  }).then(() => {
    516    SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(100 * MS_PER_SEC);
    517 
    518    var transform =
    519      SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform');
    520    assert_matrix_equals(transform, 'matrix(1, 0, 0, 1, 150, 0)',
    521      'Transform value for animation with positive delay should be composed ' +
    522      'onto the base style');
    523  });
    524 }, 'Transform value for animation with no keyframe at offset 0 and with ' +
    525   'positive delay');
    526 
    527 promise_test(t => {
    528  var div;
    529  return useTestRefreshMode(t).then(() => {
    530    div = addDiv(t, { style: 'transform: translateX(100px)' });
    531 
    532    div.animate([{ offset: 0, transform: 'translateX(200px)'}],
    533                { duration: 100 * MS_PER_SEC,
    534                  iterationStart: 1,
    535                  iterationComposite: 'accumulate' });
    536 
    537    return waitForPaintsFlushed();
    538  }).then(() => {
    539    var transform =
    540      SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform');
    541    assert_matrix_equals(transform, 'matrix(1, 0, 0, 1, 300, 0)',
    542      'Transform value for animation with no keyframe at offset 1 and its ' +
    543      'iterationComposite is accumulate');
    544  });
    545 }, 'Transform value for animation with no keyframe at offset 1 and its ' +
    546   'iterationComposite is accumulate');
    547 
    548 promise_test(t => {
    549  var div;
    550  return useTestRefreshMode(t).then(() => {
    551    div = addDiv(t);
    552    var lowerAnimation =
    553      div.animate({ transform: [ 'translateX(100px)', 'translateX(200px)' ] },
    554                  100 * MS_PER_SEC);
    555    var higherAnimation = div.animate({ transform: 'translateX(300px)' },
    556                                      100 * MS_PER_SEC);
    557 
    558    lowerAnimation.timeline = null;
    559    // Set current time at 50% duration.
    560    lowerAnimation.currentTime = 50 * MS_PER_SEC;
    561 
    562    return waitForPaintsFlushed();
    563  }).then(() => {
    564    SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(50 * MS_PER_SEC);
    565 
    566    var transform =
    567      SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform');
    568    // (150px + 300px) * (50 * MS_PER_SEC / 100 * MS_PER_SEC) = 225px.
    569    assert_matrix_equals(transform, 'matrix(1, 0, 0, 1, 225, 0)',
    570      'Composed transform value should be composed onto the value of ' +
    571      'lower-priority animation without timeline');
    572  });
    573 }, 'Transform value for animation with no keyframe at offset 0 at 50% when ' +
    574   'composed onto an animation without timeline');
    575 
    576 </script>
    577 </body>