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>