layout/style/test/test_transitions.html

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/style/test/test_transitions.html	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,783 @@
     1.4 +<!DOCTYPE HTML>
     1.5 +<html>
     1.6 +<!--
     1.7 +https://bugzilla.mozilla.org/show_bug.cgi?id=435441
     1.8 +-->
     1.9 +<head>
    1.10 +  <title>Test for Bug 435441</title>
    1.11 +  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
    1.12 +  <script type="application/javascript" src="animation_utils.js"></script>
    1.13 +  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
    1.14 +  <style type="text/css">
    1.15 +
    1.16 +  #display p { margin-top: 0; margin-bottom: 0; }
    1.17 +  #display .before, #display .after {
    1.18 +    width: -moz-fit-content; border: 1px solid black;
    1.19 +  }
    1.20 +  #display .before::before, #display .after::after {
    1.21 +    display: block;
    1.22 +    width: 0;
    1.23 +    text-indent: 0;
    1.24 +  }
    1.25 +  #display .before.started::before, #display .after.started::after {
    1.26 +    width: 100px;
    1.27 +    text-indent: 100px;
    1.28 +    transition: 8s width ease-in-out, 8s text-indent ease-in-out;
    1.29 +  }
    1.30 +  #display .before::before {
    1.31 +    content: "Before";
    1.32 +  }
    1.33 +  #display .after::after {
    1.34 +    content: "After";
    1.35 +  }
    1.36 +
    1.37 +  </style>
    1.38 +</head>
    1.39 +<body>
    1.40 +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=435441">Mozilla Bug 435441</a>
    1.41 +<div id="display">
    1.42 +
    1.43 +</div>
    1.44 +<pre id="test">
    1.45 +<script type="application/javascript">
    1.46 +
    1.47 +/** Test for Bug 435441 **/
    1.48 +
    1.49 +// Run tests simultaneously so we don't have to take up too much time.
    1.50 +SimpleTest.waitForExplicitFinish();
    1.51 +var gTestsRunning = 0;
    1.52 +function TestStarted() { ++gTestsRunning; }
    1.53 +function TestFinished() { if (--gTestsRunning == 0) SimpleTest.finish(); }
    1.54 +
    1.55 +// An array of arrays of functions to be called at the outer index number
    1.56 +// of seconds after the present.
    1.57 +var gFutureCalls = [];
    1.58 +
    1.59 +function add_future_call(index, func)
    1.60 +{
    1.61 +    if (!(index in gFutureCalls)) {
    1.62 +        gFutureCalls[index] = [];
    1.63 +    }
    1.64 +    gFutureCalls[index].push(func);
    1.65 +    TestStarted();
    1.66 +}
    1.67 +var gStartTime1, gStartTime2;
    1.68 +var gCurrentTime;
    1.69 +var gSetupComplete = false;
    1.70 +
    1.71 +function process_future_calls(index)
    1.72 +{
    1.73 +    var calls = gFutureCalls[index];
    1.74 +    if (!calls)
    1.75 +        return;
    1.76 +    gCurrentTime = Date.now();
    1.77 +    for (var i = 0; i < calls.length; ++i) {
    1.78 +        calls[i]();
    1.79 +        TestFinished();
    1.80 +    }
    1.81 +}
    1.82 +
    1.83 +var timingFunctions = {
    1.84 +  // a map from the value of 'transition-timing-function' to an array of
    1.85 +  // the portions this function yields at 0 (always 0), 1/4, 1/2, and
    1.86 +  // 3/4 and all (always 1) of the way through the time of the
    1.87 +  // transition.  Each portion is represented as a value and an
    1.88 +  // acceptable error tolerance (based on a time error of 1%) for that
    1.89 +  // value.
    1.90 +
    1.91 +  // ease
    1.92 +  "ease": bezier(0.25, 0.1, 0.25, 1),
    1.93 +  "cubic-bezier(0.25, 0.1, 0.25, 1.0)": bezier(0.25, 0.1, 0.25, 1),
    1.94 +
    1.95 +  // linear and various synonyms for it
    1.96 +  "linear": function(x) { return x; },
    1.97 +  "cubic-bezier(0.0, 0.0, 1.0, 1.0)": function(x) { return x; },
    1.98 +  "cubic-bezier(0, 0, 1, 1)": function(x) { return x; },
    1.99 +  "cubic-bezier(0, 0, 0, 0.0)": function(x) { return x; },
   1.100 +  "cubic-bezier(1.0, 1, 0, 0)": function(x) { return x; },
   1.101 +
   1.102 +  // ease-in
   1.103 +  "ease-in": bezier(0.42, 0, 1, 1),
   1.104 +  "cubic-bezier(0.42, 0, 1.0, 1.0)": bezier(0.42, 0, 1, 1),
   1.105 +
   1.106 +  // ease-out
   1.107 +  "ease-out": bezier(0, 0, 0.58, 1),
   1.108 +  "cubic-bezier(0, 0, 0.58, 1.0)": bezier(0, 0, 0.58, 1),
   1.109 +
   1.110 +  // ease-in-out
   1.111 +  "ease-in-out": bezier(0.42, 0, 0.58, 1),
   1.112 +  "cubic-bezier(0.42, 0, 0.58, 1.0)": bezier(0.42, 0, 0.58, 1),
   1.113 +
   1.114 +  // other cubic-bezier values
   1.115 +  "cubic-bezier(0.4, 0.1, 0.7, 0.95)": bezier(0.4, 0.1, 0.7, 0.95),
   1.116 +  "cubic-bezier(1, 0, 0, 1)": bezier(1, 0, 0, 1),
   1.117 +  "cubic-bezier(0, 1, 1, 0)": bezier(0, 1, 1, 0),
   1.118 +
   1.119 +};
   1.120 +
   1.121 +var div = document.getElementById("display");
   1.122 +
   1.123 +// Set up all the elements on which we are going to start transitions.
   1.124 +
   1.125 +// We have two reference elements to check the expected timing range.
   1.126 +// They both have 8s linear transitions from 0 to 1000px.
   1.127 +function make_reference_p() {
   1.128 +    var p = document.createElement("p");
   1.129 +    p.appendChild(document.createTextNode("reference"));
   1.130 +    p.style.textIndent = "0px";
   1.131 +    p.style.transition = "8s text-indent linear";
   1.132 +    div.appendChild(p);
   1.133 +    return p;
   1.134 +}
   1.135 +var earlyref = make_reference_p();
   1.136 +var earlyrefcs = getComputedStyle(earlyref, "");
   1.137 +
   1.138 +// Test all timing functions using a set of 8-second transitions, which
   1.139 +// we check at times 0, 2s, 4s, 6s, and 8s.
   1.140 +var tftests = [];
   1.141 +for (var tf in timingFunctions) {
   1.142 +    var p = document.createElement("p");
   1.143 +    var t = document.createTextNode("transition-timing-function: " + tf);
   1.144 +    p.appendChild(t);
   1.145 +    p.style.textIndent = "0px";
   1.146 +    p.style.transition = "8s text-indent linear";
   1.147 +    p.style.transitionTimingFunction = tf;
   1.148 +    div.appendChild(p);
   1.149 +    is(getComputedStyle(p, "").textIndent, "0px",
   1.150 +       "should be zero before changing value");
   1.151 +    tftests.push([ p, tf ]);
   1.152 +}
   1.153 +
   1.154 +// Check that the timing function continues even when we restyle in the
   1.155 +// middle.
   1.156 +var interrupt_tests = [];
   1.157 +for (var restyleParent of [true, false]) {
   1.158 +    for (var itime = 2; itime < 8; itime += 2) {
   1.159 +        var p = document.createElement("p");
   1.160 +        var t = document.createTextNode("interrupt on " +
   1.161 +                                        (restyleParent ? "parent" : "node itself") +
   1.162 +                                        " at " + itime + "s");
   1.163 +        p.appendChild(t);
   1.164 +        p.style.textIndent = "0px";
   1.165 +        p.style.transition = "8s text-indent cubic-bezier(0, 1, 1, 0)";
   1.166 +        if (restyleParent) {
   1.167 +          var d = document.createElement("div");
   1.168 +          d.appendChild(p);
   1.169 +          div.appendChild(d);
   1.170 +        } else {
   1.171 +          div.appendChild(p);
   1.172 +        }
   1.173 +        is(getComputedStyle(p, "").textIndent, "0px",
   1.174 +           "should be zero before changing value");
   1.175 +        setTimeout("interrupt_tests[" + interrupt_tests.length + "]" +
   1.176 +                   "[0]" + (restyleParent ? ".parentNode" : "") +
   1.177 +                   ".style.color = 'blue';" +
   1.178 +                   "check_interrupt_tests()", itime*1000);
   1.179 +        interrupt_tests.push([ p, itime ]);
   1.180 +    }
   1.181 +}
   1.182 +
   1.183 +// Test transition-delay values of -4s through 4s on a 4s transition
   1.184 +// with 'ease-out' timing function.
   1.185 +var delay_tests = {};
   1.186 +for (var d = -4; d <= 4; ++d) {
   1.187 +    var p = document.createElement("p");
   1.188 +    var delay = d + "s";
   1.189 +    var t = document.createTextNode("transition-delay: " + delay);
   1.190 +    p.appendChild(t);
   1.191 +    p.style.marginLeft = "0px";
   1.192 +    p.style.transition = "4s margin-left ease-out " + delay;
   1.193 +    div.appendChild(p);
   1.194 +    is(getComputedStyle(p, "").marginLeft, "0px",
   1.195 +       "should be zero before changing value");
   1.196 +    delay_tests[d] = p;
   1.197 +}
   1.198 +
   1.199 +// Test transition-delay values of -4s through 4s on a 4s transition
   1.200 +// with duration of zero.
   1.201 +var delay_zero_tests = {};
   1.202 +for (var d = -4; d <= 4; ++d) {
   1.203 +    var p = document.createElement("p");
   1.204 +    var delay = d + "s";
   1.205 +    var t = document.createTextNode("transition-delay: " + delay);
   1.206 +    p.appendChild(t);
   1.207 +    p.style.marginLeft = "0px";
   1.208 +    p.style.transition = "0s margin-left linear " + delay;
   1.209 +    div.appendChild(p);
   1.210 +    is(getComputedStyle(p, "").marginLeft, "0px",
   1.211 +       "should be zero before changing value");
   1.212 +    delay_zero_tests[d] = p;
   1.213 +}
   1.214 +
   1.215 +// Test that changing the value on an already-running transition to the
   1.216 +// value it currently happens to have resets the transition.
   1.217 +function make_reset_test(transition, description)
   1.218 +{
   1.219 +    var p = document.createElement("p");
   1.220 +    var t = document.createTextNode(description);
   1.221 +    p.appendChild(t);
   1.222 +    p.style.marginLeft = "0px";
   1.223 +    p.style.transition = transition;
   1.224 +    div.appendChild(p);
   1.225 +    is(getComputedStyle(p, "").marginLeft, "0px",
   1.226 +       "should be zero before changing value");
   1.227 +    return p;
   1.228 +}
   1.229 +var reset_test = make_reset_test("4s margin-left ease-out 4s", "transition-delay reset to starting point");
   1.230 +var reset_test_reference = make_reset_test("4s margin-left linear -3s", "reference for previous test (reset test)");
   1.231 +
   1.232 +// Test that transitions on descendants do not trigger when the
   1.233 +// inherited value is itself transitioning.  In other words, when
   1.234 +// ancestor and descendant both have a transition for the same property,
   1.235 +// and the descendant inherits the property from the ancestor, the
   1.236 +// descendant's transition is ignored (as part of the idea of not
   1.237 +// starting transitions on changes that result from animation).
   1.238 +// See http://lists.w3.org/Archives/Public/www-style/2009Jun/0121.html
   1.239 +// and http://lists.w3.org/Archives/Public/www-style/2009Jul/0050.html
   1.240 +var descendant_tests = [
   1.241 +    { parent_transition: "",
   1.242 +      child_transition: "4s text-indent" },
   1.243 +    { parent_transition: "4s text-indent",
   1.244 +      child_transition: "" },
   1.245 +    { parent_transition: "4s text-indent",
   1.246 +      child_transition: "16s text-indent" },
   1.247 +    { parent_transition: "4s text-indent",
   1.248 +      child_transition: "1s text-indent" },
   1.249 +    { parent_transition: "8s letter-spacing",
   1.250 +      child_transition: "4s text-indent" },
   1.251 +    { parent_transition: "4s text-indent",
   1.252 +      child_transition: "8s letter-spacing" },
   1.253 +    { parent_transition: "4s text-indent",
   1.254 +      child_transition: "8s all" },
   1.255 +    { parent_transition: "8s text-indent",
   1.256 +      child_transition: "4s all" },
   1.257 +    // examples with positive and negative delay
   1.258 +    { parent_transition: "4s text-indent 1s",
   1.259 +      child_transition: "8s text-indent" },
   1.260 +    { parent_transition: "4s text-indent -1s",
   1.261 +      child_transition: "8s text-indent" }
   1.262 +];
   1.263 +
   1.264 +for (var i in descendant_tests) {
   1.265 +    var test = descendant_tests[i];
   1.266 +    test.parentNode = document.createElement("div");
   1.267 +    test.childNode = document.createElement("p");
   1.268 +    test.parentNode.appendChild(test.childNode);
   1.269 +    test.childNode.appendChild(document.createTextNode(
   1.270 +        "parent with \"" + test.parent_transition + "\" and " +
   1.271 +        "child with \"" + test.child_transition + "\""));
   1.272 +    test.parentNode.style.transition = test.parent_transition;
   1.273 +    test.childNode.style.transition = test.child_transition;
   1.274 +    test.parentNode.style.textIndent = "50px"; // transition from 50 to 150
   1.275 +    test.parentNode.style.letterSpacing = "10px"; // transition from 10 to 5
   1.276 +    div.appendChild(test.parentNode);
   1.277 +    var parentCS = getComputedStyle(test.parentNode, "");
   1.278 +    var childCS = getComputedStyle(test.childNode, "");
   1.279 +    is(parentCS.textIndent, "50px",
   1.280 +       "parent text-indent should be 50px before changing");
   1.281 +    is(parentCS.letterSpacing, "10px",
   1.282 +       "parent letter-spacing should be 10px before changing");
   1.283 +    is(childCS.textIndent, "50px",
   1.284 +       "child text-indent should be 50px before changing");
   1.285 +    is(childCS.letterSpacing, "10px",
   1.286 +       "child letter-spacing should be 10px before changing");
   1.287 +    test.childCS = childCS;
   1.288 +}
   1.289 +
   1.290 +// For all of these transitions, the transition for margin-left should
   1.291 +// have a duration of 8s, and the default timing function (ease) and
   1.292 +// delay (0).
   1.293 +// This is because we're implementing the proposal in
   1.294 +// http://lists.w3.org/Archives/Public/www-style/2009Aug/0109.html
   1.295 +var number_tests = [
   1.296 +  { style: "transition: 4s margin, 8s margin-left" },
   1.297 +  { style: "transition: 4s margin-left, 8s margin" },
   1.298 +  { style: "transition-property: margin-left; " +
   1.299 +             "transition-duration: 8s, 2s" },
   1.300 +  { style: "transition-property: margin-left, margin-left; " + 
   1.301 +             "transition-duration: 2s, 8s" },
   1.302 +  { style: "transition-property: margin-left, margin-left, margin-left; " +
   1.303 +             "transition-duration: 8s, 2s" },
   1.304 +  { style: "transition-property: margin-left; " +
   1.305 +             "transition-duration: 8s, 16s" },
   1.306 +  { style: "transition-property: margin-left, margin-left; " + 
   1.307 +             "transition-duration: 16s, 8s" },
   1.308 +  { style: "transition-property: margin-left, margin-left, margin-left; " +
   1.309 +             "transition-duration: 8s, 16s" },
   1.310 +  { style: "transition-property: text-indent,word-spacing,margin-left; " +
   1.311 +             "transition-duration: 8s; " +
   1.312 +             "transition-delay: 0, 8s" },
   1.313 +  { style: "transition-property: text-indent,word-spacing,margin-left; " +
   1.314 +             "transition-duration: 8s, 16s; " +
   1.315 +             "transition-delay: 8s, 8s, 0, 8s, 8s, 8s" },
   1.316 +];
   1.317 +
   1.318 +for (var i in number_tests) {
   1.319 +    var test = number_tests[i];
   1.320 +    var p = document.createElement("p");
   1.321 +    p.setAttribute("style", test.style);
   1.322 +    var t = document.createTextNode(test.style);
   1.323 +    p.appendChild(t);
   1.324 +    p.style.marginLeft = "100px";
   1.325 +    div.appendChild(p);
   1.326 +    is(getComputedStyle(p, "").marginLeft, "100px",
   1.327 +       "should be 100px before changing value");
   1.328 +    test.node = p;
   1.329 +}
   1.330 +
   1.331 +// Test transitions that are also from-display:none, to-display:none, and
   1.332 +// display:none throughout.
   1.333 +var from_none_test, to_none_test, always_none_test;
   1.334 +function make_display_test(initially_none, text)
   1.335 +{
   1.336 +    var p = document.createElement("p");
   1.337 +    p.appendChild(document.createTextNode(text));
   1.338 +    p.style.textIndent = "0px";
   1.339 +    p.style.transition = "8s text-indent ease-in-out";
   1.340 +    if (initially_none)
   1.341 +        p.style.display = "none";
   1.342 +    div.appendChild(p);
   1.343 +    return p;
   1.344 +}
   1.345 +from_none_test   = make_display_test(true,  "transition from display:none");
   1.346 +to_none_test     = make_display_test(false, "transition to display:none");
   1.347 +always_none_test = make_display_test(true,  "transition always display:none");
   1.348 +var display_tests = [ from_none_test, to_none_test, always_none_test ];
   1.349 +
   1.350 +// Test transitions on pseudo-elements
   1.351 +var before_test, after_test;
   1.352 +function make_pseudo_elem_test(pseudo)
   1.353 +{
   1.354 +    var p = document.createElement("p");
   1.355 +    p.className = pseudo;
   1.356 +    div.appendChild(p);
   1.357 +    return {"pseudo": pseudo, element: p};
   1.358 +}
   1.359 +before_test = make_pseudo_elem_test("before");
   1.360 +after_test = make_pseudo_elem_test("after");
   1.361 +var pseudo_element_tests = [ before_test, after_test ];
   1.362 +
   1.363 +// FIXME (Bug 522599): Test a transition that reverses partway through.
   1.364 +
   1.365 +var lateref = make_reference_p();
   1.366 +var laterefcs = getComputedStyle(lateref, "");
   1.367 +
   1.368 +// flush style changes
   1.369 +var x = getComputedStyle(div, "").color;
   1.370 +
   1.371 +// Start our timer as close as possible to when we start the first
   1.372 +// transition.
   1.373 +// Do not use setInterval because once it gets off in time, it stays off.
   1.374 +for (var i = 1; i <= 8; ++i) {
   1.375 +    setTimeout(process_future_calls, i * 1000, i);
   1.376 +}
   1.377 +gStartTime1 = Date.now(); // set before any transitions have started
   1.378 +
   1.379 +// Start all the transitions.
   1.380 +earlyref.style.textIndent = "1000px";
   1.381 +for (var test in tftests) {
   1.382 +    var p = tftests[test][0];
   1.383 +    p.style.textIndent = "100px";
   1.384 +}
   1.385 +for (var test in interrupt_tests) {
   1.386 +    var p = interrupt_tests[test][0];
   1.387 +    p.style.textIndent = "100px";
   1.388 +}
   1.389 +for (var d in delay_tests) {
   1.390 +    var p = delay_tests[d];
   1.391 +    p.style.marginLeft = "100px";
   1.392 +}
   1.393 +for (var d in delay_zero_tests) {
   1.394 +    var p = delay_zero_tests[d];
   1.395 +    p.style.marginLeft = "100px";
   1.396 +}
   1.397 +reset_test.style.marginLeft = "100px";
   1.398 +reset_test_reference.style.marginLeft = "100px";
   1.399 +for (var i in descendant_tests) {
   1.400 +    var test = descendant_tests[i];
   1.401 +    test.parentNode.style.textIndent = "150px";
   1.402 +    test.parentNode.style.letterSpacing = "5px";
   1.403 +}
   1.404 +for (var i in number_tests) {
   1.405 +    var test = number_tests[i];
   1.406 +    test.node.style.marginLeft = "50px";
   1.407 +}
   1.408 +from_none_test.style.textIndent = "100px";
   1.409 +from_none_test.style.display = "";
   1.410 +to_none_test.style.textIndent = "100px";
   1.411 +to_none_test.style.display = "none";
   1.412 +always_none_test.style.textIndent = "100px";
   1.413 +for (var i in pseudo_element_tests) {
   1.414 +    var test = pseudo_element_tests[i];
   1.415 +    test.element.classList.add("started");
   1.416 +}
   1.417 +lateref.style.textIndent = "1000px";
   1.418 +
   1.419 +// flush style changes
   1.420 +x = getComputedStyle(div, "").color;
   1.421 +
   1.422 +gStartTime2 = Date.now(); // set after all transitions have started
   1.423 +gCurrentTime = gStartTime2;
   1.424 +
   1.425 +/**
   1.426 + * Assert that a transition whose timing function yields the bezier
   1.427 + * |func|, running from |start_time| to |end_time| (both in seconds
   1.428 + * relative to when the transitions were started) should have produced
   1.429 + * computed value |cval| given that the transition was from
   1.430 + * |start_value| to |end_value| (both numbers in CSS pixels).
   1.431 + */
   1.432 +function check_transition_value(func, start_time, end_time,
   1.433 +                                start_value, end_value, cval, desc,
   1.434 +                                xfail)
   1.435 +{
   1.436 +    /**
   1.437 +     * Compute the value at a given time |elapsed|, by normalizing the
   1.438 +     * input to the timing function using start_time and end_time and
   1.439 +     * then turning the output into a value using start_value and
   1.440 +     * end_value.
   1.441 +     *
   1.442 +     * The |error_direction| argument should be either -1, 0, or 1,
   1.443 +     * suggesting adding on a little bit of error, to allow for the
   1.444 +     * cubic-bezier calculation being an approximation.  The amount of
   1.445 +     * error is proportional to the slope of the timing function, since
   1.446 +     * the error is added to the *input* of the timing function (after
   1.447 +     * normalization to 0-1 based on start_time and end_time).
   1.448 +     */
   1.449 +    function value_at(elapsed, error_direction) {
   1.450 +        var time_portion = (elapsed - start_time) / (end_time - start_time);
   1.451 +        if (time_portion < 0)
   1.452 +            time_portion = 0;
   1.453 +        else if (time_portion > 1)
   1.454 +            time_portion = 1;
   1.455 +        // Assume a small error since bezier computation can be off slightly.
   1.456 +        // (This test's computation is probably more accurate than Mozilla's.)
   1.457 +        var value_portion = func(time_portion + error_direction * 0.0005);
   1.458 +        if (value_portion < 0)
   1.459 +            value_portion = 0;
   1.460 +        else if (value_portion > 1)
   1.461 +            value_portion = 1;
   1.462 +        var value = (1 - value_portion) * start_value + value_portion * end_value;
   1.463 +        if (start_value > end_value)
   1.464 +            error_direction = -error_direction;
   1.465 +        // Computed values get rounded to 1/60th of a pixel.
   1.466 +        return value + error_direction * 0.02;
   1.467 +    }
   1.468 +
   1.469 +    var time_range; // in seconds
   1.470 +    var uns_range; // |range| before being sorted (so errors give it
   1.471 +                   // in the original order
   1.472 +    if (!gSetupComplete) {
   1.473 +        // No timers involved
   1.474 +        time_range = [0, 0];
   1.475 +        if (start_time < 0) {
   1.476 +            uns_range = [ value_at(0, -1), value_at(0, 1) ];
   1.477 +        } else {
   1.478 +            var val = value_at(0, 0);
   1.479 +            uns_range = [val, val];
   1.480 +        }
   1.481 +    } else {
   1.482 +        time_range = [ px_to_num(earlyrefcs.textIndent) / 125,
   1.483 +                       px_to_num(laterefcs.textIndent) / 125 ];
   1.484 +        // seconds
   1.485 +        uns_range = [ value_at(time_range[0], -1),
   1.486 +                      value_at(time_range[1], 1) ];
   1.487 +    }
   1.488 +    var range = uns_range.concat(). /* concat to clone array */
   1.489 +                  sort(function compareNumbers(a,b) { return a - b; });
   1.490 +    var actual = px_to_num(cval);
   1.491 +
   1.492 +    var fn = ok;
   1.493 +    if (xfail && xfail(range))
   1.494 +      fn = todo;
   1.495 +
   1.496 +    fn(range[0] <= actual && actual <= range[1],
   1.497 +       desc + ": computed value " + cval + " should be between " +
   1.498 +       uns_range[0].toFixed(6) + "px and " + uns_range[1].toFixed(6) +
   1.499 +       "px at time between " + time_range[0] + "s and " + time_range[1] + "s.");
   1.500 +}
   1.501 +
   1.502 +function check_ref_range()
   1.503 +{
   1.504 +    // This is the only test where we compare the progress of the
   1.505 +    // transitions to an actual time; we need considerable tolerance at
   1.506 +    // the low end (we are using half a second).
   1.507 +    var expected_range = [ (gCurrentTime - gStartTime2 - 40) / 8,
   1.508 +                           (Date.now() - gStartTime1 + 20) / 8 ];
   1.509 +    if (expected_range[0] > 1000) {
   1.510 +        expected_range[0] = 1000;
   1.511 +    }
   1.512 +    if (expected_range[1] > 1000) {
   1.513 +        expected_range[1] = 1000;
   1.514 +    }
   1.515 +    function check(desc, value) {
   1.516 +        // The timing on the unit test VMs is not reliable, so make this
   1.517 +        // test report PASS when it succeeds and TODO when it fails.
   1.518 +        var passed = expected_range[0] <= value && value <= expected_range[1];
   1.519 +        (passed ? ok : todo)(passed,
   1.520 +           desc + ": computed value " + value + "px should be between " +
   1.521 +           expected_range[0].toFixed(6) + "px and " +
   1.522 +           expected_range[1].toFixed(6) + "px at time between " +
   1.523 +           expected_range[0]/125 + "s and " + expected_range[1]/125 + "s.");
   1.524 +    }
   1.525 +    check("early reference", px_to_num(earlyrefcs.textIndent));
   1.526 +    check("late reference", px_to_num(laterefcs.textIndent));
   1.527 +}
   1.528 +
   1.529 +for (var i = 1; i <= 8; ++i) {
   1.530 +    add_future_call(i, check_ref_range);
   1.531 +}
   1.532 +
   1.533 +function check_tf_test()
   1.534 +{
   1.535 +    for (var test in tftests) {
   1.536 +        var p = tftests[test][0];
   1.537 +        var tf = tftests[test][1];
   1.538 +
   1.539 +        check_transition_value(timingFunctions[tf], 0, 8, 0, 100,
   1.540 +                               getComputedStyle(p, "").textIndent,
   1.541 +                               "timing function test for timing function " + tf);
   1.542 +
   1.543 +    }
   1.544 +
   1.545 +    check_interrupt_tests();
   1.546 +}
   1.547 +
   1.548 +check_tf_test();
   1.549 +add_future_call(2, check_tf_test);
   1.550 +add_future_call(4, check_tf_test);
   1.551 +add_future_call(6, check_tf_test);
   1.552 +add_future_call(8, check_tf_test);
   1.553 +
   1.554 +function check_interrupt_tests()
   1.555 +{
   1.556 +    for (var test in interrupt_tests) {
   1.557 +        var p = interrupt_tests[test][0];
   1.558 +        var itime = interrupt_tests[test][1];
   1.559 +
   1.560 +        check_transition_value(timingFunctions["cubic-bezier(0, 1, 1, 0)"],
   1.561 +                               0, 8, 0, 100,
   1.562 +                               getComputedStyle(p, "").textIndent,
   1.563 +                               "interrupt " +
   1.564 +                               (p.parentNode == div ? "" : "on parent ") +
   1.565 +                               "test for time " + itime + "s");
   1.566 +    }
   1.567 +}
   1.568 +
   1.569 +// check_interrupt_tests is called from check_tf_test and from
   1.570 +// where we reset the interrupts
   1.571 +
   1.572 +function check_delay_test(time)
   1.573 +{
   1.574 +    var tf = timingFunctions["ease-out"];
   1.575 +    for (var d in delay_tests) {
   1.576 +        var p = delay_tests[d];
   1.577 +
   1.578 +        check_transition_value(tf, Number(d), Number(d) + 4, 0, 100,
   1.579 +                               getComputedStyle(p, "").marginLeft,
   1.580 +                               "delay test for delay " + d + "s");
   1.581 +    }
   1.582 +}
   1.583 +
   1.584 +check_delay_test(0);
   1.585 +for (var i = 1; i <= 8; ++i) {
   1.586 +    add_future_call(i, check_delay_test);
   1.587 +}
   1.588 +
   1.589 +function check_delay_zero_test(time)
   1.590 +{
   1.591 +    for (var d in delay_zero_tests) {
   1.592 +        var p = delay_zero_tests[d];
   1.593 +
   1.594 +        time_range = [ px_to_num(earlyrefcs.textIndent) / 125,
   1.595 +                       px_to_num(laterefcs.textIndent) / 125 ];
   1.596 +        var m = getComputedStyle(p, "").marginLeft;
   1.597 +        var desc = "delay_zero test for delay " + d + "s";
   1.598 +        if (time_range[0] < d && time_range[1] < d) {
   1.599 +            is(m, "0px", desc);
   1.600 +        } else if ((time_range[0] > d && time_range[1] > d) ||
   1.601 +                   (d == 0 && time == 0)) {
   1.602 +            is(m, "100px", desc);
   1.603 +        }
   1.604 +    }
   1.605 +}
   1.606 +
   1.607 +check_delay_zero_test(0);
   1.608 +for (var i = 1; i <= 8; ++i) {
   1.609 +    add_future_call(i, check_delay_zero_test);
   1.610 +}
   1.611 +
   1.612 +function reset_reset_test(time)
   1.613 +{
   1.614 +    reset_test.style.marginLeft = "0px";
   1.615 +}
   1.616 +function check_reset_test(time)
   1.617 +{
   1.618 +    is(getComputedStyle(reset_test, "").marginLeft, "0px",
   1.619 +       "reset test value at time " + time + "s.");
   1.620 +}
   1.621 +check_reset_test(0);
   1.622 +// reset the reset test right now so we don't have to worry about clock skew
   1.623 +// To make sure that this is valid, check that a pretty-much-identical test is
   1.624 +// already transitioning.
   1.625 +is(getComputedStyle(reset_test_reference, "").marginLeft, "75px",
   1.626 +   "reset test reference value");
   1.627 +reset_reset_test();
   1.628 +check_reset_test(0);
   1.629 +for (var i = 1; i <= 8; ++i) {
   1.630 +    (function(j) {
   1.631 +        add_future_call(j, function() { check_reset_test(j); });
   1.632 +    })(i);
   1.633 +}
   1.634 +
   1.635 +check_descendant_tests();
   1.636 +add_future_call(2, check_descendant_tests);
   1.637 +add_future_call(6, check_descendant_tests);
   1.638 +
   1.639 +function check_descendant_tests() {
   1.640 +    // text-indent: transition from 50px to 150px
   1.641 +    // letter-spacing: transition from 10px to 5px
   1.642 +    var values = {};
   1.643 +    values["text-indent"] = [ 50, 150 ];
   1.644 +    values["letter-spacing"] = [ 10, 5 ];
   1.645 +    var tf = timingFunctions["ease"];
   1.646 +
   1.647 +    for (var i in descendant_tests) {
   1.648 +        var test = descendant_tests[i];
   1.649 +
   1.650 +        /* ti=text-indent, ls=letter-spacing */
   1.651 +        var child_ti_duration = 0;
   1.652 +        var child_ls_duration = 0;
   1.653 +        var child_ti_delay = 0;
   1.654 +        var child_ls_delay = 0;
   1.655 +
   1.656 +        if (test.parent_transition != "") {
   1.657 +            var props = test.parent_transition.split(" ");
   1.658 +            var duration = parseInt(props[0]);
   1.659 +            var delay = (props.length > 2) ? parseInt(props[2]) : 0;
   1.660 +            var property = props[1];
   1.661 +            if (property == "text-indent") {
   1.662 +                child_ti_duration = duration;
   1.663 +                child_ti_delay = delay;
   1.664 +            } else if (property == "letter-spacing") {
   1.665 +                child_ls_duration = duration;
   1.666 +                child_ls_delay = delay;
   1.667 +            } else {
   1.668 +                ok(false, "fix this test (unexpected transition-property " +
   1.669 +                          property + " on parent)");
   1.670 +            }
   1.671 +        }
   1.672 +
   1.673 +        if (test.child_transition != "") {
   1.674 +            var props = test.child_transition.split(" ");
   1.675 +            var duration = parseInt(props[0]);
   1.676 +            var delay = (props.length > 2) ? parseInt(props[2]) : 0;
   1.677 +            var property = props[1];
   1.678 +            if (property != "text-indent" && property != "letter-spacing" &&
   1.679 +                property != "all") {
   1.680 +                ok(false, "fix this test (unexpected transition-property " +
   1.681 +                          property + " on child)");
   1.682 +            }
   1.683 +
   1.684 +            if (property != "letter-spacing" && child_ti_duration == 0) {
   1.685 +                child_ti_duration = duration;
   1.686 +                child_ti_delay = delay;
   1.687 +            }
   1.688 +            if (property != "text-indent" && child_ls_duration == 0) {
   1.689 +                child_ls_duration = duration;
   1.690 +                child_ls_delay = delay;
   1.691 +            }
   1.692 +        }
   1.693 +
   1.694 +        var time_portions = {
   1.695 +          "text-indent":
   1.696 +            { duration: child_ti_duration, delay: child_ti_delay },
   1.697 +          "letter-spacing":
   1.698 +            { duration: child_ls_duration, delay: child_ls_delay },
   1.699 +        };
   1.700 +
   1.701 +        for (var prop in {"text-indent": true, "letter-spacing": true}) {
   1.702 +            var time_portion = time_portions[prop];
   1.703 +
   1.704 +            if (time_portion.duration == 0) {
   1.705 +                time_portion.duration = 0.01;
   1.706 +                time_portion.delay = -1;
   1.707 +            }
   1.708 +
   1.709 +            check_transition_value(tf, time_portion.delay,
   1.710 +                                   time_portion.delay + time_portion.duration,
   1.711 +                                   values[prop][0], values[prop][1],
   1.712 +                                   test.childCS.getPropertyValue(prop),
   1.713 +                                   "descendant test, property " + prop);
   1.714 +        }
   1.715 +    }
   1.716 +}
   1.717 +
   1.718 +function check_number_tests()
   1.719 +{
   1.720 +    var tf = timingFunctions["ease"];
   1.721 +    for (var d in number_tests) {
   1.722 +        var test = number_tests[d];
   1.723 +        var p = test.node;
   1.724 +
   1.725 +        check_transition_value(tf, 0, 8, 100, 50,
   1.726 +                               getComputedStyle(p, "").marginLeft,
   1.727 +                               "number of transitions test for style " +
   1.728 +                                 test.style);
   1.729 +    }
   1.730 +}
   1.731 +
   1.732 +check_number_tests(0);
   1.733 +add_future_call(2, check_number_tests);
   1.734 +add_future_call(4, check_number_tests);
   1.735 +add_future_call(6, check_number_tests);
   1.736 +add_future_call(8, check_number_tests);
   1.737 +
   1.738 +function check_display_tests(time)
   1.739 +{
   1.740 +    var tf = timingFunctions["ease-in-out"];
   1.741 +    for (var i in display_tests) {
   1.742 +        var p = display_tests[i];
   1.743 +
   1.744 +        check_transition_value(tf, 0, 8, 0, 100,
   1.745 +                               getComputedStyle(p, "").textIndent,
   1.746 +                               "display test for test with " +
   1.747 +                                 p.childNodes[0].data,
   1.748 +        // TODO: Making transitions work on 'display:none' elements is
   1.749 +        // still not implemented.
   1.750 +                               function(range) { return p != to_none_test &&
   1.751 +                                                 range[1] < 100 });
   1.752 +    }
   1.753 +}
   1.754 +
   1.755 +check_display_tests(0);
   1.756 +add_future_call(2, function() { check_display_tests(2); });
   1.757 +add_future_call(4, function() { check_display_tests(4); });
   1.758 +add_future_call(6, function() { check_display_tests(6); });
   1.759 +add_future_call(8, function() { check_display_tests(8); });
   1.760 +
   1.761 +function check_pseudo_element_tests(time)
   1.762 +{
   1.763 +    var tf = timingFunctions["ease-in-out"];
   1.764 +    for (var i in pseudo_element_tests) {
   1.765 +        var test = pseudo_element_tests[i];
   1.766 +
   1.767 +        check_transition_value(tf, 0, 8, 0, 100,
   1.768 +                               getComputedStyle(test.element, "").width,
   1.769 +                               "::"+test.pseudo+" test");
   1.770 +        check_transition_value(tf, 0, 8, 0, 100,
   1.771 +                               getComputedStyle(test.element,
   1.772 +                                                "::"+test.pseudo).textIndent,
   1.773 +                               "::"+test.pseudo+" indent test");
   1.774 +    }
   1.775 +}
   1.776 +check_pseudo_element_tests(0);
   1.777 +add_future_call(2, function() { check_pseudo_element_tests(2); });
   1.778 +add_future_call(4, function() { check_pseudo_element_tests(4); });
   1.779 +add_future_call(6, function() { check_pseudo_element_tests(6); });
   1.780 +add_future_call(8, function() { check_pseudo_element_tests(8); });
   1.781 +
   1.782 +gSetupComplete = true;
   1.783 +</script>
   1.784 +</pre>
   1.785 +</body>
   1.786 +</html>

mercurial