| OLD | NEW |
| 1 /* This is the helper function to run animation tests: | 1 /* This is the helper function to run animation tests: |
| 2 | 2 |
| 3 Test page requirements: | 3 Test page requirements: |
| 4 - The body must contain an empty div with id "result" | 4 - The body must contain an empty div with id "result" |
| 5 - Call this function directly from the <script> inside the test page | 5 - Call this function directly from the <script> inside the test page |
| 6 | 6 |
| 7 Function parameters: | 7 Function parameters: |
| 8 expected [required]: an array of arrays defining a set of CSS properties tha
t must have given values at specific times (see below) | 8 expected [required]: an array of arrays defining a set of CSS properties tha
t must have given values at specific times (see below) |
| 9 callbacks [optional]: a function to be executed immediately after animation
starts; | 9 callbacks [optional]: a function to be executed immediately after animation
starts; |
| 10 or, an object in the form {time: function} containing
functions to be | 10 or, an object in the form {time: function} containing
functions to be |
| (...skipping 22 matching lines...) Expand all Loading... |
| 33 If the CSS property name is "webkitTransform.N", expected value must be a nu
mber corresponding to the Nth element of the matrix | 33 If the CSS property name is "webkitTransform.N", expected value must be a nu
mber corresponding to the Nth element of the matrix |
| 34 | 34 |
| 35 */ | 35 */ |
| 36 | 36 |
| 37 function isCloseEnough(actual, desired, tolerance) | 37 function isCloseEnough(actual, desired, tolerance) |
| 38 { | 38 { |
| 39 var diff = Math.abs(actual - desired); | 39 var diff = Math.abs(actual - desired); |
| 40 return diff <= tolerance; | 40 return diff <= tolerance; |
| 41 } | 41 } |
| 42 | 42 |
| 43 function roundNumber(num, decimalPlaces) |
| 44 { |
| 45 return Math.round(num * Math.pow(10, decimalPlaces)) / Math.pow(10, decimalPla
ces); |
| 46 } |
| 47 |
| 43 function matrixStringToArray(s) | 48 function matrixStringToArray(s) |
| 44 { | 49 { |
| 45 if (s == "none") | 50 if (s == "none") |
| 46 return [ 1, 0, 0, 1, 0, 0 ]; | 51 return [ 1, 0, 0, 1, 0, 0 ]; |
| 47 var m = s.split("("); | 52 var m = s.split("("); |
| 48 m = m[1].split(")"); | 53 m = m[1].split(")"); |
| 49 return m[0].split(","); | 54 return m[0].split(","); |
| 50 } | 55 } |
| 51 | 56 |
| 52 function parseCrossFade(s) | 57 function parseCrossFade(s) |
| (...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 263 | 268 |
| 264 if (comparePropertyValue(property, computedValue, expectedValue, toleran
ce)) | 269 if (comparePropertyValue(property, computedValue, expectedValue, toleran
ce)) |
| 265 result += "PASS - \"" + property + "\" property for \"" + elementNam
e + "\" element at " + time + | 270 result += "PASS - \"" + property + "\" property for \"" + elementNam
e + "\" element at " + time + |
| 266 "s saw something close to: " + expectedValue + "<br>
"; | 271 "s saw something close to: " + expectedValue + "<br>
"; |
| 267 else | 272 else |
| 268 result += "FAIL - \"" + property + "\" property for \"" + elementNam
e + "\" element at " + time + | 273 result += "FAIL - \"" + property + "\" property for \"" + elementNam
e + "\" element at " + time + |
| 269 "s expected: " + expectedValue + " but saw: " + comp
utedValue + "<br>"; | 274 "s expected: " + expectedValue + " but saw: " + comp
utedValue + "<br>"; |
| 270 } | 275 } |
| 271 } | 276 } |
| 272 | 277 |
| 278 function compareRGB(rgb, expected, tolerance) |
| 279 { |
| 280 return (isCloseEnough(parseInt(rgb[0]), expected[0], tolerance) && |
| 281 isCloseEnough(parseInt(rgb[1]), expected[1], tolerance) && |
| 282 isCloseEnough(parseInt(rgb[2]), expected[2], tolerance)); |
| 283 } |
| 284 |
| 285 function parseCrossFade(s) |
| 286 { |
| 287 var matches = s.match("-webkit-cross-fade\\((.*)\\s*,\\s*(.*)\\s*,\\s*(.*)\\
)"); |
| 288 |
| 289 if (!matches) |
| 290 return null; |
| 291 |
| 292 return {"from": matches[1], "to": matches[2], "percent": parseFloat(matches[
3])} |
| 293 } |
| 294 |
| 295 function checkExpectedTransitionValue(expected, index) |
| 296 { |
| 297 expected[index].shift(); |
| 298 var time = expected[index][0]; |
| 299 var elementId = expected[index][1]; |
| 300 var property = expected[index][2]; |
| 301 var expectedValue = expected[index][3]; |
| 302 var tolerance = expected[index][4]; |
| 303 var postCompletionCallback = expected[index][5]; |
| 304 |
| 305 var computedValue; |
| 306 var pass = false; |
| 307 var transformRegExp = /^-webkit-transform(\.\d+)?$/; |
| 308 if (transformRegExp.test(property)) { |
| 309 computedValue = window.getComputedStyle(document.getElementById(elementI
d)).webkitTransform; |
| 310 if (typeof expectedValue == "string") |
| 311 pass = (computedValue == expectedValue); |
| 312 else if (typeof expectedValue == "number") { |
| 313 var m = computedValue.split("("); |
| 314 var m = m[1].split(","); |
| 315 pass = isCloseEnough(parseFloat(m[parseInt(property.substring(18))])
, expectedValue, tolerance); |
| 316 } else { |
| 317 var m = computedValue.split("("); |
| 318 var m = m[1].split(","); |
| 319 for (i = 0; i < expectedValue.length; ++i) { |
| 320 pass = isCloseEnough(parseFloat(m[i]), expectedValue[i], toleran
ce); |
| 321 if (!pass) |
| 322 break; |
| 323 } |
| 324 } |
| 325 } else if (property == "fill" || property == "stroke") { |
| 326 computedValue = window.getComputedStyle(document.getElementById(elementI
d)).getPropertyCSSValue(property).rgbColor; |
| 327 if (compareRGB([computedValue.red.cssText, computedValue.green.cssText,
computedValue.blue.cssText], expectedValue, tolerance)) |
| 328 pass = true; |
| 329 else { |
| 330 // We failed. Make sure computed value is something we can read in t
he error message |
| 331 computedValue = window.getComputedStyle(document.getElementById(elem
entId)).getPropertyCSSValue(property).cssText; |
| 332 } |
| 333 } else if (property == "stop-color" || property == "flood-color" || property
== "lighting-color") { |
| 334 computedValue = window.getComputedStyle(document.getElementById(elementI
d)).getPropertyCSSValue(property); |
| 335 // The computedValue cssText is rgb(num, num, num) |
| 336 var components = computedValue.cssText.split("(")[1].split(")")[0].split
(","); |
| 337 if (compareRGB(components, expectedValue, tolerance)) |
| 338 pass = true; |
| 339 else { |
| 340 // We failed. Make sure computed value is something we can read in t
he error message |
| 341 computedValue = computedValue.cssText; |
| 342 } |
| 343 } else if (property == "lineHeight") { |
| 344 computedValue = parseInt(window.getComputedStyle(document.getElementById
(elementId)).lineHeight); |
| 345 pass = isCloseEnough(computedValue, expectedValue, tolerance); |
| 346 } else if (property == "background-image" |
| 347 || property == "border-image-source" |
| 348 || property == "border-image" |
| 349 || property == "list-style-image" |
| 350 || property == "-webkit-mask-image" |
| 351 || property == "-webkit-mask-box-image") { |
| 352 if (property == "border-image" || property == "-webkit-mask-image" || pr
operty == "-webkit-mask-box-image") |
| 353 property += "-source"; |
| 354 |
| 355 computedValue = window.getComputedStyle(document.getElementById(elementI
d)).getPropertyCSSValue(property).cssText; |
| 356 computedCrossFade = parseCrossFade(computedValue); |
| 357 |
| 358 if (!computedCrossFade) { |
| 359 pass = false; |
| 360 } else { |
| 361 pass = isCloseEnough(computedCrossFade.percent, expectedValue, toler
ance); |
| 362 } |
| 363 } else { |
| 364 var computedStyle = window.getComputedStyle(document.getElementById(elem
entId)).getPropertyCSSValue(property); |
| 365 if (computedStyle.cssValueType == CSSValue.CSS_VALUE_LIST) { |
| 366 var values = []; |
| 367 for (var i = 0; i < computedStyle.length; ++i) { |
| 368 switch (computedStyle[i].cssValueType) { |
| 369 case CSSValue.CSS_PRIMITIVE_VALUE: |
| 370 values.push(computedStyle[i].getFloatValue(CSSPrimitiveValue
.CSS_NUMBER)); |
| 371 break; |
| 372 case CSSValue.CSS_CUSTOM: |
| 373 // arbitrarily pick shadow-x and shadow-y |
| 374 if (property == 'box-shadow' || property == 'text-shadow') { |
| 375 var text = computedStyle[i].cssText; |
| 376 // Shadow cssText looks like "rgb(0, 0, 255) 0px -3px 10px
0px" |
| 377 var shadowPositionRegExp = /\)\s*(-?\d+)px\s*(-?\d+)px/; |
| 378 var match = shadowPositionRegExp.exec(text); |
| 379 var shadowXY = [parseInt(match[1]), parseInt(match[2])]; |
| 380 values.push(shadowXY[0]); |
| 381 values.push(shadowXY[1]); |
| 382 } else |
| 383 values.push(computedStyle[i].cssText); |
| 384 break; |
| 385 } |
| 386 } |
| 387 computedValue = values.join(','); |
| 388 pass = true; |
| 389 for (var i = 0; i < values.length; ++i) |
| 390 pass &= isCloseEnough(values[i], expectedValue[i], tolerance); |
| 391 } else if (computedStyle.cssValueType == CSSValue.CSS_PRIMITIVE_VALUE) { |
| 392 switch (computedStyle.primitiveType) { |
| 393 case CSSPrimitiveValue.CSS_STRING: |
| 394 case CSSPrimitiveValue.CSS_IDENT: |
| 395 computedValue = computedStyle.getStringValue(); |
| 396 pass = computedValue == expectedValue; |
| 397 break; |
| 398 case CSSPrimitiveValue.CSS_RGBCOLOR: |
| 399 var rgbColor = computedStyle.getRGBColorValue(); |
| 400 computedValue = [rgbColor.red.getFloatValue(CSSPrimitiveValu
e.CSS_NUMBER), |
| 401 rgbColor.green.getFloatValue(CSSPrimitiveVa
lue.CSS_NUMBER), |
| 402 rgbColor.blue.getFloatValue(CSSPrimitiveVal
ue.CSS_NUMBER)]; // alpha is not exposed to JS |
| 403 pass = true; |
| 404 for (var i = 0; i < 3; ++i) |
| 405 pass &= isCloseEnough(computedValue[i], expectedValue[i]
, tolerance); |
| 406 break; |
| 407 case CSSPrimitiveValue.CSS_RECT: |
| 408 computedValue = computedStyle.getRectValue(); |
| 409 computedValue = [computedValue.top.getFloatValue(CSSPrimitiv
eValue.CSS_NUMBER), |
| 410 computedValue.right.getFloatValue(CSSPrimit
iveValue.CSS_NUMBER), |
| 411 computedValue.bottom.getFloatValue(CSSPrimi
tiveValue.CSS_NUMBER), |
| 412 computedValue.left.getFloatValue(CSSPrimiti
veValue.CSS_NUMBER)]; |
| 413 pass = true; |
| 414 for (var i = 0; i < 4; ++i) |
| 415 pass &= isCloseEnough(computedValue[i], expectedValue[i
], tolerance); |
| 416 break; |
| 417 case CSSPrimitiveValue.CSS_PERCENTAGE: |
| 418 computedValue = parseFloat(computedStyle.cssText); |
| 419 pass = isCloseEnough(computedValue, expectedValue, tolerance
); |
| 420 break; |
| 421 default: |
| 422 computedValue = computedStyle.getFloatValue(CSSPrimitiveValu
e.CSS_NUMBER); |
| 423 pass = isCloseEnough(computedValue, expectedValue, tolerance
); |
| 424 } |
| 425 } |
| 426 } |
| 427 |
| 428 if (pass) |
| 429 result += "PASS - \"" + property + "\" property for \"" + elementId + "\
" element at " + time + "s saw something close to: " + expectedValue + "<br>"; |
| 430 else |
| 431 result += "FAIL - \"" + property + "\" property for \"" + elementId + "\
" element at " + time + "s expected: " + expectedValue + " but saw: " + computed
Value + "<br>"; |
| 432 |
| 433 if (postCompletionCallback) |
| 434 result += postCompletionCallback(); |
| 435 } |
| 436 |
| 273 | 437 |
| 274 function getPropertyValue(property, elementId, iframeId) | 438 function getPropertyValue(property, elementId, iframeId) |
| 275 { | 439 { |
| 276 var computedValue; | 440 var computedValue; |
| 277 var element; | 441 var element; |
| 278 if (iframeId) | 442 if (iframeId) |
| 279 element = document.getElementById(iframeId).contentDocument.getElementBy
Id(elementId); | 443 element = document.getElementById(iframeId).contentDocument.getElementBy
Id(elementId); |
| 280 else | 444 else |
| 281 element = document.getElementById(elementId); | 445 element = document.getElementById(elementId); |
| 282 | 446 |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 395 if (hasPauseAnimationAPI) | 559 if (hasPauseAnimationAPI) |
| 396 runChecksWithPauseAPI(checks); | 560 runChecksWithPauseAPI(checks); |
| 397 else | 561 else |
| 398 runChecksWithRAF(checks); | 562 runChecksWithRAF(checks); |
| 399 } | 563 } |
| 400 | 564 |
| 401 var useResultElement = false; | 565 var useResultElement = false; |
| 402 var result = ""; | 566 var result = ""; |
| 403 var hasPauseAnimationAPI; | 567 var hasPauseAnimationAPI; |
| 404 var animStartTime; | 568 var animStartTime; |
| 569 var isTransitionsTest = false; |
| 570 |
| 571 var usePauseAPI = true; |
| 572 var dontUsePauseAPI = false; |
| 573 var shouldBeTransitioning = 'should-be-transitioning'; |
| 574 var shouldNotBeTransitioning = 'should-not-be-transitioning'; |
| 405 | 575 |
| 406 // FIXME: remove deprecatedEvent, disablePauseAnimationAPI and doPixelTest | 576 // FIXME: remove deprecatedEvent, disablePauseAnimationAPI and doPixelTest |
| 407 function runAnimationTest(expected, callbacks, deprecatedEvent, disablePauseAnim
ationAPI, doPixelTest) | 577 function runAnimationTest(expected, callbacks, deprecatedEvent, disablePauseAnim
ationAPI, doPixelTest) |
| 408 { | 578 { |
| 409 if (disablePauseAnimationAPI) | 579 if (disablePauseAnimationAPI) |
| 410 result += 'Warning this test is running in real-time and may be flaky.<b
r>'; | 580 result += 'Warning this test is running in real-time and may be flaky.<b
r>'; |
| 411 if (deprecatedEvent) | 581 if (deprecatedEvent) |
| 412 throw 'Event argument is deprecated!'; | 582 throw 'Event argument is deprecated!'; |
| 413 if (!expected) | 583 if (!expected) |
| 414 throw "Expected results are missing!"; | 584 throw "Expected results are missing!"; |
| 415 | 585 |
| 416 hasPauseAnimationAPI = 'internals' in window; | 586 hasPauseAnimationAPI = 'internals' in window; |
| 417 if (disablePauseAnimationAPI) | 587 if (disablePauseAnimationAPI) |
| 418 hasPauseAnimationAPI = false; | 588 hasPauseAnimationAPI = false; |
| 419 | 589 |
| 420 var checks = {}; | 590 var checks = {}; |
| 591 var trigger = function() {}; |
| 421 | 592 |
| 422 if (typeof callbacks == 'function') | 593 if (isTransitionsTest) { |
| 594 var transitionTrigger = callbacks; |
| 595 callbacks = null; |
| 596 trigger = function() { |
| 597 transitionTrigger(); |
| 598 document.body.offsetTop |
| 599 if (window.testRunner) |
| 600 testRunner.display(); |
| 601 }; |
| 602 } |
| 603 |
| 604 if (typeof callbacks == 'function') { |
| 423 checks[0] = [callbacks]; | 605 checks[0] = [callbacks]; |
| 424 else for (var time in callbacks) { | 606 } else for (var time in callbacks) { |
| 425 timeMs = Math.round(time * 1000); | 607 timeMs = Math.round(time * 1000); |
| 426 checks[timeMs] = [callbacks[time]]; | 608 checks[timeMs] = [callbacks[time]]; |
| 427 } | 609 } |
| 428 | 610 |
| 429 for (var i = 0; i < expected.length; i++) { | 611 for (var i = 0; i < expected.length; i++) { |
| 430 var expectation = expected[i]; | 612 var expectation = expected[i]; |
| 431 var timeMs = Math.round(expectation[1] * 1000); | 613 var timeMs = Math.round(expectation[1] * 1000); |
| 432 if (!checks[timeMs]) | 614 if (!checks[timeMs]) |
| 433 checks[timeMs] = []; | 615 checks[timeMs] = []; |
| 434 checks[timeMs].push(checkExpectedValue.bind(null, expected, i)); | 616 if (isTransitionsTest) |
| 617 checks[timeMs].push(checkExpectedTransitionValue.bind(null, expected
, i)); |
| 618 else |
| 619 checks[timeMs].push(checkExpectedValue.bind(null, expected, i)); |
| 435 } | 620 } |
| 436 | 621 |
| 437 var doPixelTest = Boolean(doPixelTest); | 622 var doPixelTest = Boolean(doPixelTest); |
| 438 useResultElement = doPixelTest; | 623 useResultElement = doPixelTest; |
| 439 | 624 |
| 440 if (window.testRunner) { | 625 if (window.testRunner) { |
| 441 testRunner.dumpAsText(doPixelTest); | 626 testRunner.dumpAsText(doPixelTest); |
| 442 testRunner.waitUntilDone(); | 627 testRunner.waitUntilDone(); |
| 443 } | 628 } |
| 444 | 629 |
| 445 var started = false; | 630 var started = false; |
| 446 document.addEventListener('webkitAnimationStart', function() { | 631 var target = isTransitionsTest ? window : document; |
| 632 var event = isTransitionsTest ? 'load' : 'webkitAnimationStart'; |
| 633 target.addEventListener(event, function() { |
| 447 if (!started) { | 634 if (!started) { |
| 448 started = true; | 635 started = true; |
| 636 trigger(); |
| 449 animStartTime = performance.now(); | 637 animStartTime = performance.now(); |
| 450 // delay to give hardware animations a chance to start | 638 // delay to give hardware animations a chance to start |
| 451 setTimeout(function() { | 639 setTimeout(function() { |
| 452 startTest(checks); | 640 startTest(checks); |
| 453 }, 0); | 641 }, 0); |
| 454 } | 642 } |
| 455 }, false); | 643 }, false); |
| 456 } | 644 } |
| 645 |
| 646 /* This is the helper function to run transition tests: |
| 647 |
| 648 Test page requirements: |
| 649 - The body must contain an empty div with id "result" |
| 650 - Call this function directly from the <script> inside the test page |
| 651 |
| 652 Function parameters: |
| 653 expected [required]: an array of arrays defining a set of CSS properties tha
t must have given values at specific times (see below) |
| 654 callback [optional]: a function to be executed just before the test starts (
none by default) |
| 655 |
| 656 Each sub-array must contain these items in this order: |
| 657 - the time in seconds at which to snapshot the CSS property |
| 658 - the id of the element on which to get the CSS property value |
| 659 - the name of the CSS property to get [1] |
| 660 - the expected value for the CSS property |
| 661 - the tolerance to use when comparing the effective CSS property value with
its expected value |
| 662 |
| 663 [1] If the CSS property name is "-webkit-transform", expected value must be
an array of 1 or more numbers corresponding to the matrix elements, |
| 664 or a string which will be compared directly (useful if the expected value is
"none") |
| 665 If the CSS property name is "-webkit-transform.N", expected value must be a
number corresponding to the Nth element of the matrix |
| 666 |
| 667 */ |
| 668 function runTransitionTest(expected, callback, usePauseAPI, doPixelTest) { |
| 669 expected = expected.map(function(expectation) { expectation.unshift(null); r
eturn expectation; }); |
| 670 isTransitionsTest = true; |
| 671 runAnimationTest(expected, callback, undefined, !usePauseAPI, doPixelTest); |
| 672 } |
| OLD | NEW |