| OLD | NEW | 
|---|
|  | (Empty) | 
| 1 /* This is the helper function to run transition tests: |  | 
| 2 |  | 
| 3 Test page requirements: |  | 
| 4 - The body must contain an empty div with id "result" |  | 
| 5 - Call this function directly from the <script> inside the test page |  | 
| 6 |  | 
| 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) |  | 
| 9     callback [optional]: a function to be executed just before the test starts (
     none by default) |  | 
| 10 |  | 
| 11     Each sub-array must contain these items in this order: |  | 
| 12     - the time in seconds at which to snapshot the CSS property |  | 
| 13     - the id of the element on which to get the CSS property value |  | 
| 14     - the name of the CSS property to get [1] |  | 
| 15     - the expected value for the CSS property |  | 
| 16     - the tolerance to use when comparing the effective CSS property value with 
     its expected value |  | 
| 17 |  | 
| 18     [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, |  | 
| 19     or a string which will be compared directly (useful if the expected value is
      "none") |  | 
| 20     If the CSS property name is "-webkit-transform.N", expected value must be a 
     number corresponding to the Nth element of the matrix |  | 
| 21 |  | 
| 22 */ |  | 
| 23 |  | 
| 24 const usePauseAPI = true; |  | 
| 25 const dontUsePauseAPI = false; |  | 
| 26 |  | 
| 27 const shouldBeTransitioning = true; |  | 
| 28 const shouldNotBeTransitioning = false; |  | 
| 29 |  | 
| 30 function roundNumber(num, decimalPlaces) |  | 
| 31 { |  | 
| 32   return Math.round(num * Math.pow(10, decimalPlaces)) / Math.pow(10, decimalPla
     ces); |  | 
| 33 } |  | 
| 34 |  | 
| 35 function isCloseEnough(actual, desired, tolerance) |  | 
| 36 { |  | 
| 37     var diff = Math.abs(actual - desired); |  | 
| 38     return diff <= tolerance; |  | 
| 39 } |  | 
| 40 |  | 
| 41 function isShadow(property) |  | 
| 42 { |  | 
| 43   return (property == '-webkit-box-shadow' || property == 'text-shadow'); |  | 
| 44 } |  | 
| 45 |  | 
| 46 function getShadowXY(cssValue) |  | 
| 47 { |  | 
| 48     var text = cssValue.cssText; |  | 
| 49     // Shadow cssText looks like "rgb(0, 0, 255) 0px -3px 10px 0px" |  | 
| 50     var shadowPositionRegExp = /\)\s*(-?\d+)px\s*(-?\d+)px/; |  | 
| 51     var result = shadowPositionRegExp.exec(text); |  | 
| 52     return [parseInt(result[1]), parseInt(result[2])]; |  | 
| 53 } |  | 
| 54 |  | 
| 55 function compareRGB(rgb, expected, tolerance) |  | 
| 56 { |  | 
| 57     return (isCloseEnough(parseInt(rgb[0]), expected[0], tolerance) && |  | 
| 58             isCloseEnough(parseInt(rgb[1]), expected[1], tolerance) && |  | 
| 59             isCloseEnough(parseInt(rgb[2]), expected[2], tolerance)); |  | 
| 60 } |  | 
| 61 |  | 
| 62 function parseCrossFade(s) |  | 
| 63 { |  | 
| 64     var matches = s.match("-webkit-cross-fade\\((.*)\\s*,\\s*(.*)\\s*,\\s*(.*)\\
     )"); |  | 
| 65 |  | 
| 66     if (!matches) |  | 
| 67         return null; |  | 
| 68 |  | 
| 69     return {"from": matches[1], "to": matches[2], "percent": parseFloat(matches[
     3])} |  | 
| 70 } |  | 
| 71 |  | 
| 72 function checkExpectedValue(expected, index) |  | 
| 73 { |  | 
| 74     var time = expected[index][0]; |  | 
| 75     var elementId = expected[index][1]; |  | 
| 76     var property = expected[index][2]; |  | 
| 77     var expectedValue = expected[index][3]; |  | 
| 78     var tolerance = expected[index][4]; |  | 
| 79     var postCompletionCallback = expected[index][5]; |  | 
| 80 |  | 
| 81     var computedValue; |  | 
| 82     var pass = false; |  | 
| 83     var transformRegExp = /^-webkit-transform(\.\d+)?$/; |  | 
| 84     if (transformRegExp.test(property)) { |  | 
| 85         computedValue = window.getComputedStyle(document.getElementById(elementI
     d)).webkitTransform; |  | 
| 86         if (typeof expectedValue == "string") |  | 
| 87             pass = (computedValue == expectedValue); |  | 
| 88         else if (typeof expectedValue == "number") { |  | 
| 89             var m = computedValue.split("("); |  | 
| 90             var m = m[1].split(","); |  | 
| 91             pass = isCloseEnough(parseFloat(m[parseInt(property.substring(18))])
     , expectedValue, tolerance); |  | 
| 92         } else { |  | 
| 93             var m = computedValue.split("("); |  | 
| 94             var m = m[1].split(","); |  | 
| 95             for (i = 0; i < expectedValue.length; ++i) { |  | 
| 96                 pass = isCloseEnough(parseFloat(m[i]), expectedValue[i], toleran
     ce); |  | 
| 97                 if (!pass) |  | 
| 98                     break; |  | 
| 99             } |  | 
| 100         } |  | 
| 101     } else if (property == "fill" || property == "stroke") { |  | 
| 102         computedValue = window.getComputedStyle(document.getElementById(elementI
     d)).getPropertyCSSValue(property).rgbColor; |  | 
| 103         if (compareRGB([computedValue.red.cssText, computedValue.green.cssText, 
     computedValue.blue.cssText], expectedValue, tolerance)) |  | 
| 104             pass = true; |  | 
| 105         else { |  | 
| 106             // We failed. Make sure computed value is something we can read in t
     he error message |  | 
| 107             computedValue = window.getComputedStyle(document.getElementById(elem
     entId)).getPropertyCSSValue(property).cssText; |  | 
| 108         } |  | 
| 109     } else if (property == "stop-color" || property == "flood-color" || property
      == "lighting-color") { |  | 
| 110         computedValue = window.getComputedStyle(document.getElementById(elementI
     d)).getPropertyCSSValue(property); |  | 
| 111         // The computedValue cssText is rgb(num, num, num) |  | 
| 112         var components = computedValue.cssText.split("(")[1].split(")")[0].split
     (","); |  | 
| 113         if (compareRGB(components, expectedValue, tolerance)) |  | 
| 114             pass = true; |  | 
| 115         else { |  | 
| 116             // We failed. Make sure computed value is something we can read in t
     he error message |  | 
| 117             computedValue = computedValue.cssText; |  | 
| 118         } |  | 
| 119     } else if (property == "lineHeight") { |  | 
| 120         computedValue = parseInt(window.getComputedStyle(document.getElementById
     (elementId)).lineHeight); |  | 
| 121         pass = isCloseEnough(computedValue, expectedValue, tolerance); |  | 
| 122     } else if (property == "background-image" |  | 
| 123                || property == "border-image-source" |  | 
| 124                || property == "border-image" |  | 
| 125                || property == "list-style-image" |  | 
| 126                || property == "-webkit-mask-image" |  | 
| 127                || property == "-webkit-mask-box-image") { |  | 
| 128         if (property == "border-image" || property == "-webkit-mask-image" || pr
     operty == "-webkit-mask-box-image") |  | 
| 129             property += "-source"; |  | 
| 130 |  | 
| 131         computedValue = window.getComputedStyle(document.getElementById(elementI
     d)).getPropertyCSSValue(property).cssText; |  | 
| 132         computedCrossFade = parseCrossFade(computedValue); |  | 
| 133 |  | 
| 134         if (!computedCrossFade) { |  | 
| 135             pass = false; |  | 
| 136         } else { |  | 
| 137             pass = isCloseEnough(computedCrossFade.percent, expectedValue, toler
     ance); |  | 
| 138         } |  | 
| 139     } else { |  | 
| 140         var computedStyle = window.getComputedStyle(document.getElementById(elem
     entId)).getPropertyCSSValue(property); |  | 
| 141         if (computedStyle.cssValueType == CSSValue.CSS_VALUE_LIST) { |  | 
| 142             var values = []; |  | 
| 143             for (var i = 0; i < computedStyle.length; ++i) { |  | 
| 144                 switch (computedStyle[i].cssValueType) { |  | 
| 145                   case CSSValue.CSS_PRIMITIVE_VALUE: |  | 
| 146                     values.push(computedStyle[i].getFloatValue(CSSPrimitiveValue
     .CSS_NUMBER)); |  | 
| 147                     break; |  | 
| 148                   case CSSValue.CSS_CUSTOM: |  | 
| 149                     // arbitrarily pick shadow-x and shadow-y |  | 
| 150                     if (isShadow) { |  | 
| 151                       var shadowXY = getShadowXY(computedStyle[i]); |  | 
| 152                       values.push(shadowXY[0]); |  | 
| 153                       values.push(shadowXY[1]); |  | 
| 154                     } else |  | 
| 155                       values.push(computedStyle[i].cssText); |  | 
| 156                     break; |  | 
| 157                 } |  | 
| 158             } |  | 
| 159             computedValue = values.join(','); |  | 
| 160             pass = true; |  | 
| 161             for (var i = 0; i < values.length; ++i) |  | 
| 162                 pass &= isCloseEnough(values[i], expectedValue[i], tolerance); |  | 
| 163         } else if (computedStyle.cssValueType == CSSValue.CSS_PRIMITIVE_VALUE) { |  | 
| 164             switch (computedStyle.primitiveType) { |  | 
| 165                 case CSSPrimitiveValue.CSS_STRING: |  | 
| 166                 case CSSPrimitiveValue.CSS_IDENT: |  | 
| 167                     computedValue = computedStyle.getStringValue(); |  | 
| 168                     pass = computedValue == expectedValue; |  | 
| 169                     break; |  | 
| 170                 case CSSPrimitiveValue.CSS_RGBCOLOR: |  | 
| 171                     var rgbColor = computedStyle.getRGBColorValue(); |  | 
| 172                     computedValue = [rgbColor.red.getFloatValue(CSSPrimitiveValu
     e.CSS_NUMBER), |  | 
| 173                                      rgbColor.green.getFloatValue(CSSPrimitiveVa
     lue.CSS_NUMBER), |  | 
| 174                                      rgbColor.blue.getFloatValue(CSSPrimitiveVal
     ue.CSS_NUMBER)]; // alpha is not exposed to JS |  | 
| 175                     pass = true; |  | 
| 176                     for (var i = 0; i < 3; ++i) |  | 
| 177                         pass &= isCloseEnough(computedValue[i], expectedValue[i]
     , tolerance); |  | 
| 178                     break; |  | 
| 179                 case CSSPrimitiveValue.CSS_RECT: |  | 
| 180                     computedValue = computedStyle.getRectValue(); |  | 
| 181                     computedValue = [computedValue.top.getFloatValue(CSSPrimitiv
     eValue.CSS_NUMBER), |  | 
| 182                                      computedValue.right.getFloatValue(CSSPrimit
     iveValue.CSS_NUMBER), |  | 
| 183                                      computedValue.bottom.getFloatValue(CSSPrimi
     tiveValue.CSS_NUMBER), |  | 
| 184                                      computedValue.left.getFloatValue(CSSPrimiti
     veValue.CSS_NUMBER)]; |  | 
| 185                      pass = true; |  | 
| 186                      for (var i = 0; i < 4; ++i) |  | 
| 187                          pass &= isCloseEnough(computedValue[i], expectedValue[i
     ], tolerance); |  | 
| 188                     break; |  | 
| 189                 case CSSPrimitiveValue.CSS_PERCENTAGE: |  | 
| 190                     computedValue = parseFloat(computedStyle.cssText); |  | 
| 191                     pass = isCloseEnough(computedValue, expectedValue, tolerance
     ); |  | 
| 192                     break; |  | 
| 193                 default: |  | 
| 194                     computedValue = computedStyle.getFloatValue(CSSPrimitiveValu
     e.CSS_NUMBER); |  | 
| 195                     pass = isCloseEnough(computedValue, expectedValue, tolerance
     ); |  | 
| 196             } |  | 
| 197         } |  | 
| 198     } |  | 
| 199 |  | 
| 200     if (pass) |  | 
| 201         result += "PASS - \"" + property + "\" property for \"" + elementId + "\
     " element at " + time + "s saw something close to: " + expectedValue + "<br>"; |  | 
| 202     else |  | 
| 203         result += "FAIL - \"" + property + "\" property for \"" + elementId + "\
     " element at " + time + "s expected: " + expectedValue + " but saw: " + computed
     Value + "<br>"; |  | 
| 204 |  | 
| 205     if (postCompletionCallback) |  | 
| 206       result += postCompletionCallback(); |  | 
| 207 } |  | 
| 208 |  | 
| 209 function endTest() |  | 
| 210 { |  | 
| 211     document.getElementById('result').innerHTML = result; |  | 
| 212 |  | 
| 213     if (window.testRunner) |  | 
| 214         testRunner.notifyDone(); |  | 
| 215 } |  | 
| 216 |  | 
| 217 function checkExpectedValueCallback(expected, index) |  | 
| 218 { |  | 
| 219     return function() { checkExpectedValue(expected, index); }; |  | 
| 220 } |  | 
| 221 |  | 
| 222 function runTest(expected, usePauseAPI) |  | 
| 223 { |  | 
| 224     var maxTime = 0; |  | 
| 225     for (var i = 0; i < expected.length; ++i) { |  | 
| 226         var time = expected[i][0]; |  | 
| 227         var elementId = expected[i][1]; |  | 
| 228         var property = expected[i][2]; |  | 
| 229         if (!property.indexOf("-webkit-transform.")) |  | 
| 230             property = "-webkit-transform"; |  | 
| 231 |  | 
| 232         var tryToPauseTransition = expected[i][6]; |  | 
| 233         if (tryToPauseTransition === undefined) |  | 
| 234           tryToPauseTransition = shouldBeTransitioning; |  | 
| 235 |  | 
| 236         if (hasPauseTransitionAPI && usePauseAPI) { |  | 
| 237             if (tryToPauseTransition) { |  | 
| 238               var element = document.getElementById(elementId); |  | 
| 239               internals.pauseAnimations(time); |  | 
| 240             } |  | 
| 241             checkExpectedValue(expected, i); |  | 
| 242         } else { |  | 
| 243             if (time > maxTime) |  | 
| 244                 maxTime = time; |  | 
| 245 |  | 
| 246             window.setTimeout(checkExpectedValueCallback(expected, i), time * 10
     00); |  | 
| 247         } |  | 
| 248     } |  | 
| 249 |  | 
| 250     if (maxTime > 0) |  | 
| 251         window.setTimeout(endTest, maxTime * 1000 + 50); |  | 
| 252     else |  | 
| 253         endTest(); |  | 
| 254 } |  | 
| 255 |  | 
| 256 function waitForAnimationStart(callback, delay) |  | 
| 257 { |  | 
| 258     var delayTimeout = delay ? 1000 * delay + 10 : 0; |  | 
| 259     // Why the two setTimeouts? Well, for hardware animations we need to ensure 
     that the hardware animation |  | 
| 260     // has started before we try to pause it, and timers fire before animations 
     get committed in the runloop. |  | 
| 261     window.setTimeout(function() { |  | 
| 262         window.setTimeout(function() { |  | 
| 263             callback(); |  | 
| 264         }, 0); |  | 
| 265     }, delayTimeout); |  | 
| 266 } |  | 
| 267 |  | 
| 268 function startTest(expected, usePauseAPI, callback) |  | 
| 269 { |  | 
| 270     if (callback) |  | 
| 271         callback(); |  | 
| 272 |  | 
| 273     waitForAnimationStart(function() { |  | 
| 274         runTest(expected, usePauseAPI); |  | 
| 275     }); |  | 
| 276 } |  | 
| 277 |  | 
| 278 var result = ""; |  | 
| 279 var hasPauseTransitionAPI; |  | 
| 280 |  | 
| 281 function runTransitionTest(expected, callback, usePauseAPI, doPixelTest) |  | 
| 282 { |  | 
| 283     hasPauseTransitionAPI = 'internals' in window; |  | 
| 284 |  | 
| 285     if (window.testRunner) { |  | 
| 286         if (!doPixelTest) |  | 
| 287             testRunner.dumpAsText(); |  | 
| 288         testRunner.waitUntilDone(); |  | 
| 289     } |  | 
| 290 |  | 
| 291     if (!expected) |  | 
| 292         throw("Expected results are missing!"); |  | 
| 293 |  | 
| 294     window.addEventListener("load", function() { startTest(expected, usePauseAPI
     , callback); }, false); |  | 
| 295 } |  | 
| OLD | NEW | 
|---|