<!DOCTYPE HTML> <html> <!-- https://bugzilla.mozilla.org/show_bug.cgi?id=975261 --> <head> <meta charset="utf-8"> <title>Test OMTA animations start correctly (Bug 975261)</title> <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> <script type="application/javascript" src="/tests/SimpleTest/paint_listener.js"></script> <script type="application/javascript" src="animation_utils.js"></script> <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> <style type="text/css"> @keyframes anim-opacity { 0% { opacity: 0.5 } 100% { opacity: 0.5 } } @keyframes anim-opacity-2 { 0% { opacity: 0.0 } 100% { opacity: 1.0 } } @keyframes anim-transform { 0% { transform: translate(50px); } 100% { transform: translate(50px); } } @keyframes anim-transform-2 { 0% { transform: translate(0px); } 100% { transform: translate(100px); } } .target { /* These two lines are needed so that an opacity/transform layer * already exists when the animation is applied. */ opacity: 0.99; transform: translate(99px); /* Element needs geometry in order to be animated on the * compositor. */ width: 100px; height: 100px; background-color: white; } </style> </head> <body> <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=975261">Mozilla Bug 975261</a> <div id="display"></div> <pre id="test"> <script type="application/javascript"> "use strict"; var gUtils = SpecialPowers.DOMWindowUtils; SimpleTest.waitForExplicitFinish(); runOMTATest(testDelay, SimpleTest.finish); function newTarget() { var target = document.createElement("div"); target.classList.add("target"); document.getElementById("display").appendChild(target); return target; } function testDelay() { gUtils.advanceTimeAndRefresh(0); var target = newTarget(); target.setAttribute("style", "animation: 10s 10s anim-opacity linear"); gUtils.advanceTimeAndRefresh(0); waitForAllPaints(function() { gUtils.advanceTimeAndRefresh(10100); waitForAllPaints(function() { var opacity = gUtils.getOMTAStyle(target, "opacity"); is(opacity, "0.5", "opacity is set on compositor thread after delayed start"); target.removeAttribute("style"); gUtils.restoreNormalRefresh(); testTransform(); }); }); } function testTransform() { gUtils.advanceTimeAndRefresh(0); var target = newTarget(); target.setAttribute("style", "animation: 10s 10s anim-transform linear"); gUtils.advanceTimeAndRefresh(0); waitForAllPaints(function() { gUtils.advanceTimeAndRefresh(10100); waitForAllPaints(function() { var transform = gUtils.getOMTAStyle(target, "transform"); ok(matricesRoughlyEqual(convertTo3dMatrix(transform), convertTo3dMatrix("matrix(1, 0, 0, 1, 50, 0)")), "transform is set on compositor thread after delayed start"); target.remove(); gUtils.restoreNormalRefresh(); testBackwardsFill(); }); }); } function testBackwardsFill() { gUtils.advanceTimeAndRefresh(0); var target = newTarget(); target.setAttribute("style", "transform: translate(30px); " + "animation: 10s 10s anim-transform-2 linear backwards"); gUtils.advanceTimeAndRefresh(0); waitForAllPaints(function() { gUtils.advanceTimeAndRefresh(10000); waitForAllPaints(function() { gUtils.advanceTimeAndRefresh(100); waitForAllPaints(function() { var transform = gUtils.getOMTAStyle(target, "transform"); ok(matricesRoughlyEqual(convertTo3dMatrix(transform), convertTo3dMatrix("matrix(1, 0, 0, 1, 1, 0)")), "transform is set on compositor thread after delayed start " + "with backwards fill"); target.remove(); gUtils.restoreNormalRefresh(); testTransitionTakingOver(); }); }); }); } function testTransitionTakingOver() { gUtils.advanceTimeAndRefresh(0); var parent = newTarget(); var child = newTarget(); parent.appendChild(child); parent.style.opacity = "0.0"; parent.style.animation = "10s anim-opacity-2 linear"; child.style.opacity = "inherit"; child.style.transition = "10s opacity linear"; var childCS = getComputedStyle(child, ""); gUtils.advanceTimeAndRefresh(0); waitForAllPaints(function() { gUtils.advanceTimeAndRefresh(4000); waitForAllPaints(function() { child.style.opacity = "1.0"; var opacity = gUtils.getOMTAStyle(child, "opacity"); // FIXME Bug 1039799 (or lower priority followup): Animations // inherited from an animating parent element don't get shipped to // the compositor thread. todo_is(opacity, "0.4", "transition that interrupted animation is correct"); // Trigger to start the transition, without this the transition will // be pending in advanceTimeAndRefresh(0) so the transition will not // be sent to the compositor until we call advanceTimeAndRefresh with // a positive time value. getComputedStyle(child).opacity; gUtils.advanceTimeAndRefresh(0); waitForAllPaints(function() { var opacity = gUtils.getOMTAStyle(child, "opacity"); is(opacity, "0.4", "transition that interrupted animation is correct"); gUtils.advanceTimeAndRefresh(5000); waitForAllPaints(function() { opacity = gUtils.getOMTAStyle(child, "opacity"); is(opacity, "0.7", "transition that interrupted animation is correct"); is(childCS.opacity, "0.7", "transition that interrupted animation is correct"); parent.remove(); gUtils.restoreNormalRefresh(); SimpleTest.finish(); }); }); }); }); } </script> </pre> </body> </html>