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