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