test_transitions.html (28460B)
1 <!DOCTYPE HTML> 2 <html> 3 <!-- 4 https://bugzilla.mozilla.org/show_bug.cgi?id=435441 5 --> 6 <head> 7 <title>Test for Bug 435441</title> 8 <script src="/tests/SimpleTest/SimpleTest.js"></script> 9 <script type="application/javascript" src="animation_utils.js"></script> 10 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> 11 <style type="text/css"> 12 13 #display p { margin-top: 0; margin-bottom: 0; } 14 #display .before, #display .after { 15 width: -moz-fit-content; border: 1px solid black; 16 } 17 #display .before::before, #display .after::after { 18 display: block; 19 width: 0; 20 text-indent: 0; 21 } 22 #display .before.started::before, #display .after.started::after { 23 width: 100px; 24 text-indent: 100px; 25 transition: 8s width ease-in-out, 8s text-indent ease-in-out; 26 } 27 #display .before::before { 28 content: "Before"; 29 } 30 #display .after::after { 31 content: "After"; 32 } 33 34 </style> 35 </head> 36 <body> 37 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=435441">Mozilla Bug 435441</a> 38 <div id="display"> 39 40 </div> 41 <pre id="test"> 42 <script type="application/javascript"> 43 44 /** Test for Bug 435441 */ 45 46 // Run tests simultaneously so we don't have to take up too much time. 47 SimpleTest.waitForExplicitFinish(); 48 SimpleTest.requestFlakyTimeout("untriaged"); 49 var gTestsRunning = 0; 50 function TestStarted() { ++gTestsRunning; } 51 function TestFinished() { if (--gTestsRunning == 0) SimpleTest.finish(); } 52 53 // An array of arrays of functions to be called at the outer index number 54 // of seconds after the present. 55 var gFutureCalls = []; 56 57 function add_future_call(index, func) 58 { 59 if (!(index in gFutureCalls)) { 60 gFutureCalls[index] = []; 61 } 62 gFutureCalls[index].push(func); 63 TestStarted(); 64 } 65 var gStartTime1, gStartTime2; 66 var gCurrentTime; 67 var gSetupComplete = false; 68 69 function process_future_calls(index) 70 { 71 var calls = gFutureCalls[index]; 72 if (!calls) 73 return; 74 gCurrentTime = Date.now(); 75 for (var i = 0; i < calls.length; ++i) { 76 calls[i](); 77 TestFinished(); 78 } 79 } 80 81 var timingFunctions = { 82 // a map from the value of 'transition-timing-function' to an array of 83 // the portions this function yields at 0 (always 0), 1/4, 1/2, and 84 // 3/4 and all (always 1) of the way through the time of the 85 // transition. Each portion is represented as a value and an 86 // acceptable error tolerance (based on a time error of 1%) for that 87 // value. 88 89 // ease 90 "ease": bezier(0.25, 0.1, 0.25, 1), 91 "cubic-bezier(0.25, 0.1, 0.25, 1.0)": bezier(0.25, 0.1, 0.25, 1), 92 93 // linear and various synonyms for it 94 "linear": function(x) { return x; }, 95 "cubic-bezier(0.0, 0.0, 1.0, 1.0)": function(x) { return x; }, 96 "cubic-bezier(0, 0, 1, 1)": function(x) { return x; }, 97 "cubic-bezier(0, 0, 0, 0.0)": function(x) { return x; }, 98 "cubic-bezier(1.0, 1, 0, 0)": function(x) { return x; }, 99 100 // ease-in 101 "ease-in": bezier(0.42, 0, 1, 1), 102 "cubic-bezier(0.42, 0, 1.0, 1.0)": bezier(0.42, 0, 1, 1), 103 104 // ease-out 105 "ease-out": bezier(0, 0, 0.58, 1), 106 "cubic-bezier(0, 0, 0.58, 1.0)": bezier(0, 0, 0.58, 1), 107 108 // ease-in-out 109 "ease-in-out": bezier(0.42, 0, 0.58, 1), 110 "cubic-bezier(0.42, 0, 0.58, 1.0)": bezier(0.42, 0, 0.58, 1), 111 112 // other cubic-bezier values 113 "cubic-bezier(0.4, 0.1, 0.7, 0.95)": bezier(0.4, 0.1, 0.7, 0.95), 114 "cubic-bezier(1, 0, 0, 1)": bezier(1, 0, 0, 1), 115 "cubic-bezier(0, 1, 1, 0)": bezier(0, 1, 1, 0), 116 117 }; 118 119 var div = document.getElementById("display"); 120 121 // Set up all the elements on which we are going to initiate transitions. 122 123 // We have two reference elements to check the expected timing range. 124 // They both have 16s linear transitions from 0 to 1000px. 125 // This means they move through 62.5 pixels per second. 126 const REF_PX_PER_SEC = 62.5; 127 function make_reference_p() { 128 let p = document.createElement("p"); 129 p.appendChild(document.createTextNode("reference")); 130 p.style.textIndent = "0px"; 131 p.style.transition = "16s text-indent linear"; 132 div.appendChild(p); 133 return p; 134 } 135 var earlyref = make_reference_p(); 136 var earlyrefcs = getComputedStyle(earlyref, ""); 137 138 // Test all timing functions using a set of 8-second transitions, which 139 // we check at times 0, 2s, 4s, 6s, and 8s. 140 var tftests = []; 141 for (let tf in timingFunctions) { 142 let p = document.createElement("p"); 143 let t = document.createTextNode("transition-timing-function: " + tf); 144 p.appendChild(t); 145 p.style.textIndent = "0px"; 146 p.style.transition = "8s text-indent linear"; 147 p.style.transitionTimingFunction = tf; 148 div.appendChild(p); 149 is(getComputedStyle(p, "").textIndent, "0px", 150 "should be zero before changing value"); 151 tftests.push([ p, tf ]); 152 } 153 154 // Check that the timing function continues even when we restyle in the 155 // middle. 156 var interrupt_tests = []; 157 for (var restyleParent of [true, false]) { 158 for (let itime = 2; itime < 8; itime += 2) { 159 let p = document.createElement("p"); 160 let t = document.createTextNode("interrupt on " + 161 (restyleParent ? "parent" : "node itself") + 162 " at " + itime + "s"); 163 p.appendChild(t); 164 p.style.textIndent = "0px"; 165 p.style.transition = "8s text-indent cubic-bezier(0, 1, 1, 0)"; 166 if (restyleParent) { 167 let d = document.createElement("div"); 168 d.appendChild(p); 169 div.appendChild(d); 170 } else { 171 div.appendChild(p); 172 } 173 is(getComputedStyle(p, "").textIndent, "0px", 174 "should be zero before changing value"); 175 setTimeout("interrupt_tests[" + interrupt_tests.length + "]" + 176 "[0]" + (restyleParent ? ".parentNode" : "") + 177 ".style.color = 'blue';" + 178 "check_interrupt_tests()", itime*1000); 179 interrupt_tests.push([ p, itime ]); 180 } 181 } 182 183 // Test transition-delay values of -4s through 4s on a 4s transition 184 // with 'ease-out' timing function. 185 var delay_tests = {}; 186 for (let d = -4; d <= 4; ++d) { 187 let p = document.createElement("p"); 188 let delay = d + "s"; 189 let t = document.createTextNode("transition-delay: " + delay); 190 p.appendChild(t); 191 p.style.marginLeft = "0px"; 192 p.style.transition = "4s margin-left ease-out " + delay; 193 div.appendChild(p); 194 is(getComputedStyle(p, "").marginLeft, "0px", 195 "should be zero before changing value"); 196 delay_tests[d] = p; 197 } 198 199 // Test transition-delay values of -4s through 4s on a 4s transition 200 // with duration of zero. 201 var delay_zero_tests = {}; 202 for (let d = -4; d <= 4; ++d) { 203 let p = document.createElement("p"); 204 let delay = d + "s"; 205 let t = document.createTextNode("transition-delay: " + delay); 206 p.appendChild(t); 207 p.style.marginLeft = "0px"; 208 p.style.transition = "0s margin-left linear " + delay; 209 div.appendChild(p); 210 is(getComputedStyle(p, "").marginLeft, "0px", 211 "should be zero before changing value"); 212 delay_zero_tests[d] = p; 213 } 214 215 // Test that changing the value on an already-running transition to the 216 // value it currently happens to have resets the transition. 217 function make_reset_test(transition, description) 218 { 219 let p = document.createElement("p"); 220 let t = document.createTextNode(description); 221 p.appendChild(t); 222 p.style.marginLeft = "0px"; 223 p.style.transition = transition; 224 div.appendChild(p); 225 is(getComputedStyle(p, "").marginLeft, "0px", 226 "should be zero before changing value"); 227 return p; 228 } 229 var reset_test = make_reset_test("4s margin-left ease-out 4s", "transition-delay reset to starting point"); 230 var reset_test_reference = make_reset_test("4s margin-left linear -3s", "reference for previous test (reset test)"); 231 232 // Test that transitions on descendants start correctly when the 233 // inherited value is itself transitioning. In other words, when 234 // ancestor and descendant both have a transition for the same property, 235 // and the descendant inherits the property from the ancestor, the 236 // descendant's transition starts as specified, based on the concepts of 237 // the before-change style, the after-change style, and the 238 // after-transition style. 239 var descendant_tests = [ 240 { parent_transition: "", 241 child_transition: "4s text-indent" }, 242 { parent_transition: "4s text-indent", 243 child_transition: "" }, 244 { parent_transition: "4s text-indent", 245 child_transition: "16s text-indent" }, 246 { parent_transition: "4s text-indent", 247 child_transition: "1s text-indent" }, 248 { parent_transition: "8s letter-spacing", 249 child_transition: "4s text-indent" }, 250 { parent_transition: "4s text-indent", 251 child_transition: "8s letter-spacing" }, 252 { parent_transition: "4s text-indent", 253 child_transition: "8s all" }, 254 { parent_transition: "8s text-indent", 255 child_transition: "4s all" }, 256 // examples with positive and negative delay 257 { parent_transition: "4s text-indent 1s", 258 child_transition: "8s text-indent" }, 259 { parent_transition: "4s text-indent -1s", 260 child_transition: "8s text-indent" } 261 ]; 262 263 for (let i in descendant_tests) { 264 let test = descendant_tests[i]; 265 test.parentNode = document.createElement("div"); 266 test.childNode = document.createElement("p"); 267 test.parentNode.appendChild(test.childNode); 268 test.childNode.appendChild(document.createTextNode( 269 "parent with \"" + test.parent_transition + "\" and " + 270 "child with \"" + test.child_transition + "\"")); 271 test.parentNode.style.transition = test.parent_transition; 272 test.childNode.style.transition = test.child_transition; 273 test.parentNode.style.textIndent = "50px"; // transition from 50 to 150 274 test.parentNode.style.letterSpacing = "10px"; // transition from 10 to 5 275 div.appendChild(test.parentNode); 276 var parentCS = getComputedStyle(test.parentNode, ""); 277 var childCS = getComputedStyle(test.childNode, ""); 278 is(parentCS.textIndent, "50px", 279 "parent text-indent should be 50px before changing"); 280 is(parentCS.letterSpacing, "10px", 281 "parent letter-spacing should be 10px before changing"); 282 is(childCS.textIndent, "50px", 283 "child text-indent should be 50px before changing"); 284 is(childCS.letterSpacing, "10px", 285 "child letter-spacing should be 10px before changing"); 286 test.childCS = childCS; 287 } 288 289 // For all of these transitions, the transition for margin-left should 290 // have a duration of 8s, and the default timing function (ease) and 291 // delay (0). 292 // This is because we're implementing the proposal in 293 // http://lists.w3.org/Archives/Public/www-style/2009Aug/0109.html 294 var number_tests = [ 295 { style: "transition: 4s margin, 8s margin-left" }, 296 { style: "transition: 4s margin-left, 8s margin" }, 297 { style: "transition-property: margin-left; " + 298 "transition-duration: 8s, 2s" }, 299 { style: "transition-property: margin-left, margin-left; " + 300 "transition-duration: 2s, 8s" }, 301 { style: "transition-property: margin-left, margin-left, margin-left; " + 302 "transition-duration: 8s, 2s" }, 303 { style: "transition-property: margin-left; " + 304 "transition-duration: 8s, 16s" }, 305 { style: "transition-property: margin-left, margin-left; " + 306 "transition-duration: 16s, 8s" }, 307 { style: "transition-property: margin-left, margin-left, margin-left; " + 308 "transition-duration: 8s, 16s" }, 309 { style: "transition-property: text-indent,word-spacing,margin-left; " + 310 "transition-duration: 8s; " + 311 "transition-delay: 0, 8s" }, 312 { style: "transition-property: text-indent,word-spacing,margin-left; " + 313 "transition-duration: 8s, 16s; " + 314 "transition-delay: 8s, 8s, 0, 8s, 8s, 8s" }, 315 ]; 316 317 for (let i in number_tests) { 318 let test = number_tests[i]; 319 let p = document.createElement("p"); 320 p.setAttribute("style", test.style); 321 let t = document.createTextNode(test.style); 322 p.appendChild(t); 323 p.style.marginLeft = "100px"; 324 div.appendChild(p); 325 is(getComputedStyle(p, "").marginLeft, "100px", 326 "should be 100px before changing value"); 327 test.node = p; 328 } 329 330 // Test transitions that are also from-display:none, to-display:none, and 331 // display:none throughout. 332 var from_none_test, to_none_test, always_none_test; 333 function make_display_test(initially_none, text) 334 { 335 let p = document.createElement("p"); 336 p.appendChild(document.createTextNode(text)); 337 p.style.textIndent = "0px"; 338 p.style.transition = "8s text-indent ease-in-out"; 339 if (initially_none) 340 p.style.display = "none"; 341 div.appendChild(p); 342 return p; 343 } 344 from_none_test = make_display_test(true, "transition from display:none"); 345 to_none_test = make_display_test(false, "transition to display:none"); 346 always_none_test = make_display_test(true, "transition always display:none"); 347 var display_tests = [ from_none_test, to_none_test, always_none_test ]; 348 349 // Test transitions on pseudo-elements 350 var before_test, after_test; 351 function make_pseudo_elem_test(pseudo) 352 { 353 let p = document.createElement("p"); 354 p.className = pseudo; 355 div.appendChild(p); 356 return {"pseudo": pseudo, element: p}; 357 } 358 before_test = make_pseudo_elem_test("before"); 359 after_test = make_pseudo_elem_test("after"); 360 var pseudo_element_tests = [ before_test, after_test ]; 361 362 // FIXME (Bug 522599): Test a transition that reverses partway through. 363 364 var lateref = make_reference_p(); 365 var laterefcs = getComputedStyle(lateref, ""); 366 367 // flush style changes 368 var x = getComputedStyle(div, "").width; 369 370 // Start our timer as close as possible to when we start the first 371 // transition. 372 // Do not use setInterval because once it gets off in time, it stays off. 373 for (let i = 1; i <= 8; ++i) { 374 setTimeout(process_future_calls, i * 1000, i); 375 } 376 gStartTime1 = Date.now(); // set before any transitions have started 377 378 // Start all the transitions. 379 earlyref.style.textIndent = "1000px"; 380 for (let test in tftests) { 381 let p = tftests[test][0]; 382 p.style.textIndent = "100px"; 383 } 384 for (let test in interrupt_tests) { 385 let p = interrupt_tests[test][0]; 386 p.style.textIndent = "100px"; 387 } 388 for (let d in delay_tests) { 389 let p = delay_tests[d]; 390 p.style.marginLeft = "100px"; 391 } 392 for (let d in delay_zero_tests) { 393 let p = delay_zero_tests[d]; 394 p.style.marginLeft = "100px"; 395 } 396 reset_test.style.marginLeft = "100px"; 397 reset_test_reference.style.marginLeft = "100px"; 398 for (let i in descendant_tests) { 399 let test = descendant_tests[i]; 400 test.parentNode.style.textIndent = "150px"; 401 test.parentNode.style.letterSpacing = "5px"; 402 } 403 for (let i in number_tests) { 404 let test = number_tests[i]; 405 test.node.style.marginLeft = "50px"; 406 } 407 from_none_test.style.textIndent = "100px"; 408 from_none_test.style.display = ""; 409 to_none_test.style.textIndent = "100px"; 410 to_none_test.style.display = "none"; 411 always_none_test.style.textIndent = "100px"; 412 for (let i in pseudo_element_tests) { 413 let test = pseudo_element_tests[i]; 414 test.element.classList.add("started"); 415 } 416 lateref.style.textIndent = "1000px"; 417 418 // flush style changes 419 x = getComputedStyle(div, "").width; 420 421 gStartTime2 = Date.now(); // set after all transitions have started 422 gCurrentTime = gStartTime2; 423 424 /** 425 * Assert that a transition whose timing function yields the bezier 426 * |func|, running from |start_time| to |end_time| (both in seconds 427 * relative to when the transitions were started) should have produced 428 * computed value |cval| given that the transition was from 429 * |start_value| to |end_value| (both numbers in CSS pixels). 430 */ 431 function check_transition_value(func, start_time, end_time, 432 start_value, end_value, cval, desc, 433 xfail) 434 { 435 /** 436 * Compute the value at a given time |elapsed|, by normalizing the 437 * input to the timing function using start_time and end_time and 438 * then turning the output into a value using start_value and 439 * end_value. 440 * 441 * The |error_direction| argument should be either -1, 0, or 1, 442 * suggesting adding on a little bit of error, to allow for the 443 * cubic-bezier calculation being an approximation. The amount of 444 * error is proportional to the slope of the timing function, since 445 * the error is added to the *input* of the timing function (after 446 * normalization to 0-1 based on start_time and end_time). 447 */ 448 function value_at(elapsed, error_direction) { 449 var time_portion = (elapsed - start_time) / (end_time - start_time); 450 if (time_portion < 0) 451 time_portion = 0; 452 else if (time_portion > 1) 453 time_portion = 1; 454 // Assume a small error since bezier computation can be off slightly. 455 // (This test's computation is probably more accurate than Mozilla's.) 456 var value_portion = func(time_portion + error_direction * 0.0005); 457 if (value_portion < 0) 458 value_portion = 0; 459 else if (value_portion > 1) 460 value_portion = 1; 461 var value = (1 - value_portion) * start_value + value_portion * end_value; 462 if (start_value > end_value) 463 error_direction = -error_direction; 464 // Computed values get rounded to 1/60th of a pixel. 465 return value + error_direction * 0.02; 466 } 467 468 var time_range; // in seconds 469 var uns_range; // |range| before being sorted (so errors give it 470 // in the original order 471 if (!gSetupComplete) { 472 // No timers involved 473 time_range = [0, 0]; 474 if (start_time < 0) { 475 uns_range = [ value_at(0, -1), value_at(0, 1) ]; 476 } else { 477 var val = value_at(0, 0); 478 uns_range = [val, val]; 479 } 480 } else { 481 time_range = [ px_to_num(earlyrefcs.textIndent) / REF_PX_PER_SEC, 482 px_to_num(laterefcs.textIndent) / REF_PX_PER_SEC ]; 483 // seconds 484 uns_range = [ value_at(time_range[0], -1), 485 value_at(time_range[1], 1) ]; 486 } 487 var range = uns_range.concat(). /* concat to clone array */ 488 sort(function compareNumbers(a,b) { return a - b; }); 489 var actual = px_to_num(cval); 490 491 var fn = ok; 492 if (xfail && xfail(range)) 493 fn = todo; 494 495 fn(range[0] <= actual && actual <= range[1], 496 desc + ": computed value " + cval + " should be between " + 497 uns_range[0].toFixed(6) + "px and " + uns_range[1].toFixed(6) + 498 "px at time between " + time_range[0] + "s and " + time_range[1] + "s."); 499 } 500 501 function check_ref_range() 502 { 503 // This is the only test where we compare the progress of the 504 // transitions to an actual time; we need considerable tolerance at 505 // the low end (we are using half a second). 506 var expected_range = [ (gCurrentTime - gStartTime2 - 40) / 16, 507 (Date.now() - gStartTime1 + 20) / 16 ]; 508 if (expected_range[0] > 1000) { 509 expected_range[0] = 1000; 510 } 511 if (expected_range[1] > 1000) { 512 expected_range[1] = 1000; 513 } 514 function check(desc, value) { 515 // The timing on the unit test VMs is not reliable, so make this 516 // test report PASS when it succeeds and TODO when it fails. 517 var passed = expected_range[0] <= value && value <= expected_range[1]; 518 (passed ? ok : todo)(passed, 519 desc + ": computed value " + value + "px should be between " + 520 expected_range[0].toFixed(6) + "px and " + 521 expected_range[1].toFixed(6) + "px at time between " + 522 expected_range[0]/REF_PX_PER_SEC + "s and " + 523 expected_range[1]/REF_PX_PER_SEC + "s."); 524 } 525 check("early reference", px_to_num(earlyrefcs.textIndent)); 526 check("late reference", px_to_num(laterefcs.textIndent)); 527 } 528 529 for (let i = 1; i <= 8; ++i) { 530 add_future_call(i, check_ref_range); 531 } 532 533 function check_tf_test() 534 { 535 for (var test in tftests) { 536 var p = tftests[test][0]; 537 var tf = tftests[test][1]; 538 539 check_transition_value(timingFunctions[tf], 0, 8, 0, 100, 540 getComputedStyle(p, "").textIndent, 541 "timing function test for timing function " + tf); 542 543 } 544 545 check_interrupt_tests(); 546 } 547 548 check_tf_test(); 549 add_future_call(2, check_tf_test); 550 add_future_call(4, check_tf_test); 551 add_future_call(6, check_tf_test); 552 add_future_call(8, check_tf_test); 553 554 function check_interrupt_tests() 555 { 556 for (let test in interrupt_tests) { 557 var p = interrupt_tests[test][0]; 558 var itime = interrupt_tests[test][1]; 559 560 check_transition_value(timingFunctions["cubic-bezier(0, 1, 1, 0)"], 561 0, 8, 0, 100, 562 getComputedStyle(p, "").textIndent, 563 "interrupt " + 564 (p.parentNode == div ? "" : "on parent ") + 565 "test for time " + itime + "s"); 566 } 567 } 568 569 // check_interrupt_tests is called from check_tf_test and from 570 // where we reset the interrupts 571 572 function check_delay_test(time) 573 { 574 let tf = timingFunctions["ease-out"]; 575 for (let d in delay_tests) { 576 let p = delay_tests[d]; 577 578 check_transition_value(tf, Number(d), Number(d) + 4, 0, 100, 579 getComputedStyle(p, "").marginLeft, 580 "delay test for delay " + d + "s"); 581 } 582 } 583 584 check_delay_test(0); 585 for (let i = 1; i <= 8; ++i) { 586 add_future_call(i, check_delay_test); 587 } 588 589 function check_delay_zero_test(time) 590 { 591 for (let d in delay_zero_tests) { 592 let p = delay_zero_tests[d]; 593 594 time_range = [ px_to_num(earlyrefcs.textIndent) / REF_PX_PER_SEC, 595 px_to_num(laterefcs.textIndent) / REF_PX_PER_SEC ]; 596 var m = getComputedStyle(p, "").marginLeft; 597 var desc = "delay_zero test for delay " + d + "s"; 598 if (time_range[0] < d && time_range[1] < d) { 599 is(m, "0px", desc); 600 } else if ((time_range[0] > d && time_range[1] > d) || 601 (d == 0 && time == 0)) { 602 is(m, "100px", desc); 603 } 604 } 605 } 606 607 check_delay_zero_test(0); 608 for (let i = 1; i <= 8; ++i) { 609 add_future_call(i, check_delay_zero_test); 610 } 611 612 function reset_reset_test(time) 613 { 614 reset_test.style.marginLeft = "0px"; 615 } 616 function check_reset_test(time) 617 { 618 is(getComputedStyle(reset_test, "").marginLeft, "0px", 619 "reset test value at time " + time + "s."); 620 } 621 check_reset_test(0); 622 // reset the reset test right now so we don't have to worry about clock skew 623 // To make sure that this is valid, check that a pretty-much-identical test is 624 // already transitioning. 625 is(getComputedStyle(reset_test_reference, "").marginLeft, "75px", 626 "reset test reference value"); 627 reset_reset_test(); 628 check_reset_test(0); 629 for (let i = 1; i <= 8; ++i) { 630 (function(j) { 631 add_future_call(j, function() { check_reset_test(j); }); 632 })(i); 633 } 634 635 check_descendant_tests(); 636 add_future_call(2, check_descendant_tests); 637 add_future_call(6, check_descendant_tests); 638 639 function check_descendant_tests() { 640 // text-indent: transition from 50px to 150px 641 // letter-spacing: transition from 10px to 5px 642 var values = {}; 643 values["text-indent"] = [ 50, 150 ]; 644 values["letter-spacing"] = [ 10, 5 ]; 645 let tf = timingFunctions.ease; 646 647 var time = px_to_num(earlyrefcs.textIndent) / REF_PX_PER_SEC; 648 649 for (let i in descendant_tests) { 650 let test = descendant_tests[i]; 651 652 /* ti=text-indent, ls=letter-spacing */ 653 var child_ti_duration = 0; 654 var child_ls_duration = 0; 655 var child_ti_delay = 0; 656 var child_ls_delay = 0; 657 658 if (test.parent_transition != "") { 659 var props = test.parent_transition.split(" "); 660 var duration = parseInt(props[0]); 661 var delay = (props.length > 2) ? parseInt(props[2]) : 0; 662 var property = props[1]; 663 if (property == "text-indent") { 664 child_ti_duration = duration; 665 child_ti_delay = delay; 666 } else if (property == "letter-spacing") { 667 child_ls_duration = duration; 668 child_ls_delay = delay; 669 } else { 670 ok(false, "fix this test (unexpected transition-property " + 671 property + " on parent)"); 672 } 673 } 674 675 if (test.child_transition != "") { 676 var props = test.child_transition.split(" "); 677 var duration = parseInt(props[0]); 678 var delay = (props.length > 2) ? parseInt(props[2]) : 0; 679 var property = props[1]; 680 if (property != "text-indent" && property != "letter-spacing" && 681 property != "all") { 682 ok(false, "fix this test (unexpected transition-property " + 683 property + " on child)"); 684 } 685 686 // Override the parent's transition with the child's as long 687 // as the child transition is still running. 688 if (property != "letter-spacing" && duration + delay > time) { 689 child_ti_duration = duration; 690 child_ti_delay = delay; 691 } 692 if (property != "text-indent" && duration + delay > time) { 693 child_ls_duration = duration; 694 child_ls_delay = delay; 695 } 696 } 697 698 var time_portions = { 699 "text-indent": 700 { duration: child_ti_duration, delay: child_ti_delay }, 701 "letter-spacing": 702 { duration: child_ls_duration, delay: child_ls_delay }, 703 }; 704 705 for (var prop in {"text-indent": true, "letter-spacing": true}) { 706 var time_portion = time_portions[prop]; 707 708 if (time_portion.duration == 0) { 709 time_portion.duration = 0.01; 710 time_portion.delay = -1; 711 } 712 713 check_transition_value(tf, time_portion.delay, 714 time_portion.delay + time_portion.duration, 715 values[prop][0], values[prop][1], 716 test.childCS.getPropertyValue(prop), 717 `descendant test #${Number(i)+1}, property ${prop}`); 718 } 719 } 720 } 721 722 function check_number_tests() 723 { 724 let tf = timingFunctions.ease; 725 for (let d in number_tests) { 726 let test = number_tests[d]; 727 let p = test.node; 728 729 check_transition_value(tf, 0, 8, 100, 50, 730 getComputedStyle(p, "").marginLeft, 731 "number of transitions test for style " + 732 test.style); 733 } 734 } 735 736 check_number_tests(0); 737 add_future_call(2, check_number_tests); 738 add_future_call(4, check_number_tests); 739 add_future_call(6, check_number_tests); 740 add_future_call(8, check_number_tests); 741 742 function check_display_tests(time) 743 { 744 for (let i in display_tests) { 745 let p = display_tests[i]; 746 747 // There is no transition if the old or new style is display:none, so 748 // the computed value is always the end value. 749 var computedValue = getComputedStyle(p, "").textIndent; 750 is(computedValue, "100px", 751 "display test for test with " + p.childNodes[0].data + 752 ": computed value " + computedValue + " should be 100px."); 753 } 754 } 755 756 check_display_tests(0); 757 add_future_call(2, function() { check_display_tests(2); }); 758 add_future_call(4, function() { check_display_tests(4); }); 759 add_future_call(6, function() { check_display_tests(6); }); 760 add_future_call(8, function() { check_display_tests(8); }); 761 762 function check_pseudo_element_tests(time) 763 { 764 let tf = timingFunctions["ease-in-out"]; 765 for (let i in pseudo_element_tests) { 766 let test = pseudo_element_tests[i]; 767 768 check_transition_value(tf, 0, 8, 0, 100, 769 getComputedStyle(test.element, "").width, 770 "::"+test.pseudo+" test"); 771 check_transition_value(tf, 0, 8, 0, 100, 772 getComputedStyle(test.element, 773 "::"+test.pseudo).textIndent, 774 "::"+test.pseudo+" indent test"); 775 } 776 } 777 check_pseudo_element_tests(0); 778 add_future_call(2, function() { check_pseudo_element_tests(2); }); 779 add_future_call(4, function() { check_pseudo_element_tests(4); }); 780 add_future_call(6, function() { check_pseudo_element_tests(6); }); 781 add_future_call(8, function() { check_pseudo_element_tests(8); }); 782 783 gSetupComplete = true; 784 </script> 785 </pre> 786 </body> 787 </html>