| OLD | NEW |
| 1 /* This is the helper function to run animation tests: | 1 /* This is the helper script for 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 runAnimationTest and runTransitionTest 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 |
| 11 called at the specified times (in seconds) during anim
ation. | 11 called at the specified times (in seconds) during anim
ation. |
| 12 trigger [optional]: a function to trigger transitions at the start of the te
st | 12 trigger [optional]: a function to be executed just before the test starts (n
one by default) |
| 13 doPixelTest [optional]: whether to dump pixels during the test (false by def
ault) |
| 14 disablePauseAnimationAPI [optional]: whether to disable the pause API and ru
n a RAF-based test (false by default) |
| 13 | 15 |
| 14 Each sub-array must contain these items in this order: | 16 Each sub-array must contain these items in this order: |
| 15 - the time in seconds at which to snapshot the CSS property | 17 - the time in seconds at which to snapshot the CSS property |
| 16 - the id of the element on which to get the CSS property value [1] | 18 - the id of the element on which to get the CSS property value [1] |
| 17 - the name of the CSS property to get [2] | 19 - the name of the CSS property to get [2] |
| 18 - the expected value for the CSS property | 20 - the expected value for the CSS property [3] |
| 19 - the tolerance to use when comparing the effective CSS property value with
its expected value | 21 - the tolerance to use when comparing the effective CSS property value with
its expected value |
| 20 | 22 |
| 21 [1] If a single string is passed, it is the id of the element to test. If an
array with 2 elements is passed they | 23 [1] If a single string is passed, it is the id of the element to test. If an
array with 2 elements is passed they |
| 22 are the ids of 2 elements, whose values are compared for equality. In this c
ase the expected value is ignored | 24 are the ids of 2 elements, whose values are compared for equality. In this c
ase the expected value is ignored |
| 23 but the tolerance is used in the comparison. | 25 but the tolerance is used in the comparison. |
| 24 | 26 |
| 25 If a string with a '.' is passed, this is an element in an iframe. The strin
g before the dot is the iframe id | 27 If a string with a '.' is passed, this is an element in an iframe. The strin
g before the dot is the iframe id |
| 26 and the string after the dot is the element name in that iframe. | 28 and the string after the dot is the element name in that iframe. |
| 27 | 29 |
| 28 [2] If the CSS property name is "webkitTransform", expected value must be an
array of 1 or more numbers corresponding to the matrix elements, | 30 [2] Appending ".N" to the CSS property name (e.g. "transform.N") makes |
| 29 or a string which will be compared directly (useful if the expected value is
"none") | 31 us only check the Nth numeric substring of the computed style. |
| 30 If the CSS property name is "webkitTransform.N", expected value must be a nu
mber corresponding to the Nth element of the matrix | 32 |
| 33 [3] The expected value has several supported formats. If an array is given, |
| 34 we extract numeric substrings from the computed style and compare the |
| 35 number of these as well as the values. If a number is given, we treat it as |
| 36 an array of length one. If a string is given, we compare numeric substrings |
| 37 with the computed style with the given tolerance and also the remaining |
| 38 non-numeric substrings. |
| 31 | 39 |
| 32 */ | 40 */ |
| 33 | 41 |
| 34 // Set to true to log debug information in failing tests. Note that these logs | 42 // Set to true to log debug information in failing tests. Note that these logs |
| 35 // contain timestamps, so are non-deterministic and will introduce flakiness if | 43 // contain timestamps, so are non-deterministic and will introduce flakiness if |
| 36 // any expected results include failures. | 44 // any expected results include failures. |
| 37 var ENABLE_ERROR_LOGGING = false; | 45 var ENABLE_ERROR_LOGGING = false; |
| 38 | 46 |
| 39 function isCloseEnough(actual, desired, tolerance) | 47 function isCloseEnough(actual, expected, tolerance) |
| 40 { | 48 { |
| 41 if (typeof desired === "string") | 49 return Math.abs(actual - expected) <= tolerance; |
| 42 return actual === desired; | |
| 43 var diff = Math.abs(actual - desired); | |
| 44 return diff <= tolerance; | |
| 45 } | 50 } |
| 46 | 51 |
| 47 function roundNumber(num, decimalPlaces) | 52 function roundNumber(num, decimalPlaces) |
| 48 { | 53 { |
| 49 return Math.round(num * Math.pow(10, decimalPlaces)) / Math.pow(10, decimalPla
ces); | 54 return Math.round(num * Math.pow(10, decimalPlaces)) / Math.pow(10, decimalPla
ces); |
| 50 } | 55 } |
| 51 | 56 |
| 52 function matrixStringToArray(s) | |
| 53 { | |
| 54 if (s == "none") | |
| 55 return [ 1, 0, 0, 1, 0, 0 ]; | |
| 56 var m = s.split("("); | |
| 57 m = m[1].split(")"); | |
| 58 return m[0].split(","); | |
| 59 } | |
| 60 | |
| 61 function parseCrossFade(s) | |
| 62 { | |
| 63 var matches = s.match("-webkit-cross-fade\\((.*)\\s*,\\s*(.*)\\s*,\\s*(.*)\\
)"); | |
| 64 | |
| 65 if (!matches) | |
| 66 return null; | |
| 67 | |
| 68 return {"from": matches[1], "to": matches[2], "percent": parseFloat(matches[
3])} | |
| 69 } | |
| 70 | |
| 71 function parseBasicShape(s) | |
| 72 { | |
| 73 var functionParse = s.match(/(\w+)\((.+)\)/); | |
| 74 if (!functionParse) | |
| 75 return null; | |
| 76 | |
| 77 var name = functionParse[1]; | |
| 78 var params = functionParse[2]; | |
| 79 params = params.split(/\s*[,\s]\s*/); | |
| 80 | |
| 81 // Parse numbers and normalize percentages | |
| 82 for (var i = 0; i < params.length; ++i) { | |
| 83 var param = params[i]; | |
| 84 if (!/$\d/.test(param)) | |
| 85 continue; | |
| 86 params[i] = parseFloat(params[i]); | |
| 87 if (param.indexOf('%') != -1) | |
| 88 params[i] = params[i] / 100; | |
| 89 } | |
| 90 | |
| 91 return {"shape": name, "params": params}; | |
| 92 } | |
| 93 | |
| 94 function basicShapeParametersMatch(paramList1, paramList2, tolerance) | |
| 95 { | |
| 96 if (paramList1.shape != paramList2.shape | |
| 97 || paramList1.params.length != paramList2.params.length) | |
| 98 return false; | |
| 99 for (var i = 0; i < paramList1.params.length; ++i) { | |
| 100 var param1 = paramList1.params[i], | |
| 101 param2 = paramList2.params[i]; | |
| 102 var match = isCloseEnough(param1, param2, tolerance); | |
| 103 if (!match) | |
| 104 return false; | |
| 105 } | |
| 106 return true; | |
| 107 } | |
| 108 | |
| 109 // Return an array of numeric filter params in 0-1. | |
| 110 function getFilterParameters(s) | |
| 111 { | |
| 112 var filterResult = s.match(/(\w+)\((.+)\)/); | |
| 113 if (!filterResult) | |
| 114 throw new Error("There's no filter in \"" + s + "\""); | |
| 115 var filterParams = filterResult[2]; | |
| 116 var paramList = filterParams.split(' '); // FIXME: the spec may allow comma
separation at some point. | |
| 117 | |
| 118 // Normalize percentage values. | |
| 119 for (var i = 0; i < paramList.length; ++i) { | |
| 120 var param = paramList[i]; | |
| 121 paramList[i] = parseFloat(paramList[i]); | |
| 122 if (param.indexOf('%') != -1) | |
| 123 paramList[i] = paramList[i] / 100; | |
| 124 } | |
| 125 | |
| 126 return paramList; | |
| 127 } | |
| 128 | |
| 129 function filterParametersMatch(paramList1, paramList2, tolerance) | |
| 130 { | |
| 131 if (paramList1.length != paramList2.length) | |
| 132 return false; | |
| 133 for (var i = 0; i < paramList1.length; ++i) { | |
| 134 var param1 = paramList1[i], | |
| 135 param2 = paramList2[i]; | |
| 136 var match = isCloseEnough(param1, param2, tolerance); | |
| 137 if (!match) | |
| 138 return false; | |
| 139 } | |
| 140 return true; | |
| 141 } | |
| 142 | |
| 143 function checkExpectedValue(expected, index) | 57 function checkExpectedValue(expected, index) |
| 144 { | 58 { |
| 145 log('Checking expectation: ' + JSON.stringify(expected[index])); | 59 log('Checking expectation: ' + JSON.stringify(expected[index])); |
| 146 var time = expected[index][0]; | 60 var time = expected[index][0]; |
| 147 var elementId = expected[index][1]; | 61 var elementId = expected[index][1]; |
| 148 var property = expected[index][2]; | 62 var specifiedProperty = expected[index][2]; |
| 149 var expectedValue = expected[index][3]; | 63 var expectedValue = expected[index][3]; |
| 150 var tolerance = expected[index][4]; | 64 var tolerance = expected[index][4]; |
| 65 var postCompletionCallback = expected[index][5]; |
| 66 |
| 67 var expectedIndex = specifiedProperty.split(".")[1]; |
| 68 var property = specifiedProperty.split(".")[0]; |
| 151 | 69 |
| 152 // Check for a pair of element Ids | 70 // Check for a pair of element Ids |
| 153 var compareElements = false; | |
| 154 var elementId2; | |
| 155 if (typeof elementId != "string") { | 71 if (typeof elementId != "string") { |
| 156 if (elementId.length != 2) | 72 if (elementId.length != 2) |
| 157 return; | 73 return; |
| 158 | 74 |
| 159 elementId2 = elementId[1]; | 75 var elementId2 = elementId[1]; |
| 160 elementId = elementId[0]; | 76 elementId = elementId[0]; |
| 161 | 77 |
| 162 compareElements = true; | 78 var computedValue = getPropertyValue(property, elementId); |
| 163 } | 79 var computedValue2 = getPropertyValue(property, elementId2); |
| 164 | 80 |
| 165 // Check for a dot separated string | 81 if (comparePropertyValue(computedValue, computedValue2, tolerance, expec
tedIndex)) |
| 166 var iframeId; | 82 result += "PASS - \"" + specifiedProperty + "\" property for \"" + e
lementId + "\" and \"" + elementId2 + |
| 167 if (!compareElements) { | 83 "\" elements at " + time + "s are close enough to ea
ch other" + "<br>"; |
| 84 else |
| 85 result += "FAIL - \"" + specifiedProperty + "\" property for \"" + e
lementId + "\" and \"" + elementId2 + |
| 86 "\" elements at " + time + "s saw: \"" + computedVal
ue + "\" and \"" + computedValue2 + |
| 87 "\" which are not close enough to ea
ch other" + "<br>"; |
| 88 } else { |
| 89 var elementName = elementId; |
| 168 var array = elementId.split('.'); | 90 var array = elementId.split('.'); |
| 91 var iframeId; |
| 169 if (array.length == 2) { | 92 if (array.length == 2) { |
| 170 iframeId = array[0]; | 93 iframeId = array[0]; |
| 171 elementId = array[1]; | 94 elementId = array[1]; |
| 172 } | 95 } |
| 173 } | |
| 174 | 96 |
| 175 var computedValue, computedValue2; | 97 var computedValue = getPropertyValue(property, elementId, iframeId); |
| 176 if (compareElements) { | |
| 177 computedValue = getPropertyValue(property, elementId, iframeId); | |
| 178 computedValue2 = getPropertyValue(property, elementId2, iframeId); | |
| 179 | 98 |
| 180 if (comparePropertyValue(property, computedValue, computedValue2, tolera
nce)) | 99 if (comparePropertyValue(computedValue, expectedValue, tolerance, expect
edIndex)) |
| 181 result += "PASS - \"" + property + "\" property for \"" + elementId
+ "\" and \"" + elementId2 + | 100 result += "PASS - \"" + specifiedProperty + "\" property for \"" + e
lementName + "\" element at " + time + |
| 182 "\" elements at " + time + "s are close enough to ea
ch other" + "<br>"; | |
| 183 else | |
| 184 result += "FAIL - \"" + property + "\" property for \"" + elementId
+ "\" and \"" + elementId2 + | |
| 185 "\" elements at " + time + "s saw: \"" + computedVal
ue + "\" and \"" + computedValue2 + | |
| 186 "\" which are not close enough to ea
ch other" + "<br>"; | |
| 187 } else { | |
| 188 var elementName; | |
| 189 if (iframeId) | |
| 190 elementName = iframeId + '.' + elementId; | |
| 191 else | |
| 192 elementName = elementId; | |
| 193 | |
| 194 computedValue = getPropertyValue(property, elementId, iframeId); | |
| 195 | |
| 196 if (comparePropertyValue(property, computedValue, expectedValue, toleran
ce)) | |
| 197 result += "PASS - \"" + property + "\" property for \"" + elementNam
e + "\" element at " + time + | |
| 198 "s saw something close to: " + expectedValue + "<br>
"; | 101 "s saw something close to: " + expectedValue + "<br>
"; |
| 199 else | 102 else |
| 200 result += "FAIL - \"" + property + "\" property for \"" + elementNam
e + "\" element at " + time + | 103 result += "FAIL - \"" + specifiedProperty + "\" property for \"" + e
lementName + "\" element at " + time + |
| 201 "s expected: " + expectedValue + " but saw: " + comp
utedValue + "<br>"; | 104 "s expected: " + expectedValue + " but saw: " + comp
utedValue + "<br>"; |
| 202 } | 105 } |
| 203 } | |
| 204 | |
| 205 function compareRGB(rgb, expected, tolerance) | |
| 206 { | |
| 207 return (isCloseEnough(parseInt(rgb[0]), expected[0], tolerance) && | |
| 208 isCloseEnough(parseInt(rgb[1]), expected[1], tolerance) && | |
| 209 isCloseEnough(parseInt(rgb[2]), expected[2], tolerance)); | |
| 210 } | |
| 211 | |
| 212 function checkExpectedTransitionValue(expected, index) | |
| 213 { | |
| 214 log('Checking expectation: ' + JSON.stringify(expected[index])); | |
| 215 var time = expected[index][0]; | |
| 216 var elementId = expected[index][1]; | |
| 217 var property = expected[index][2]; | |
| 218 var expectedValue = expected[index][3]; | |
| 219 var tolerance = expected[index][4]; | |
| 220 var postCompletionCallback = expected[index][5]; | |
| 221 | |
| 222 var computedValue; | |
| 223 var pass = false; | |
| 224 var transformRegExp = /^-webkit-transform(\.\d+)?$/; | |
| 225 if (transformRegExp.test(property)) { | |
| 226 computedValue = window.getComputedStyle(document.getElementById(elementI
d)).webkitTransform; | |
| 227 if (typeof expectedValue === "string" || computedValue === "none") | |
| 228 pass = (computedValue == expectedValue); | |
| 229 else if (typeof expectedValue === "number") { | |
| 230 var m = computedValue.split("("); | |
| 231 var m = m[1].split(","); | |
| 232 pass = isCloseEnough(parseFloat(m[parseInt(property.substring(18))])
, expectedValue, tolerance); | |
| 233 } else { | |
| 234 var m = computedValue.split("("); | |
| 235 var m = m[1].split(","); | |
| 236 for (i = 0; i < expectedValue.length; ++i) { | |
| 237 pass = isCloseEnough(parseFloat(m[i]), expectedValue[i], toleran
ce); | |
| 238 if (!pass) | |
| 239 break; | |
| 240 } | |
| 241 } | |
| 242 } else if (property == "fill" || property == "stroke" || property == "stop-c
olor" || property == "flood-color" || property == "lighting-color") { | |
| 243 computedValue = window.getComputedStyle(document.getElementById(elementI
d)).getPropertyCSSValue(property); | |
| 244 // The computedValue cssText is rgb(num, num, num) | |
| 245 var components = computedValue.cssText.split("(")[1].split(")")[0].split
(","); | |
| 246 if (compareRGB(components, expectedValue, tolerance)) | |
| 247 pass = true; | |
| 248 else { | |
| 249 // We failed. Make sure computed value is something we can read in t
he error message | |
| 250 computedValue = computedValue.cssText; | |
| 251 } | |
| 252 } else if (property == "lineHeight") { | |
| 253 computedValue = parseInt(window.getComputedStyle(document.getElementById
(elementId)).lineHeight); | |
| 254 pass = isCloseEnough(computedValue, expectedValue, tolerance); | |
| 255 } else if (property == "background-image" | |
| 256 || property == "border-image-source" | |
| 257 || property == "border-image" | |
| 258 || property == "list-style-image" | |
| 259 || property == "-webkit-mask-image" | |
| 260 || property == "-webkit-mask-box-image") { | |
| 261 if (property == "border-image" || property == "-webkit-mask-image" || pr
operty == "-webkit-mask-box-image") | |
| 262 property += "-source"; | |
| 263 | |
| 264 computedValue = window.getComputedStyle(document.getElementById(elementI
d)).getPropertyCSSValue(property).cssText; | |
| 265 computedCrossFade = parseCrossFade(computedValue); | |
| 266 | |
| 267 if (!computedCrossFade) { | |
| 268 pass = false; | |
| 269 } else { | |
| 270 pass = isCloseEnough(computedCrossFade.percent, expectedValue, toler
ance); | |
| 271 } | |
| 272 } else if (property == "object-position") { | |
| 273 computedValue = window.getComputedStyle(document.getElementById(elementI
d)).objectPosition; | |
| 274 var actualArray = computedValue.split(" "); | |
| 275 var expectedArray = expectedValue.split(" "); | |
| 276 if (actualArray.length != expectedArray.length) { | |
| 277 pass = false; | |
| 278 } else { | |
| 279 for (i = 0; i < expectedArray.length; ++i) { | |
| 280 pass = isCloseEnough(parseFloat(actualArray[i]), parseFloat(expe
ctedArray[i]), tolerance); | |
| 281 if (!pass) | |
| 282 break; | |
| 283 } | |
| 284 } | |
| 285 } else if (property === "shape-outside") { | |
| 286 computedValue = window.getComputedStyle(document.getElementById(elementI
d)).getPropertyValue(property); | |
| 287 var actualShape = parseBasicShape(computedValue); | |
| 288 var expectedShape = parseBasicShape(expectedValue); | |
| 289 pass = basicShapeParametersMatch(actualShape, expectedShape, tolerance); | |
| 290 } else { | |
| 291 var computedStyle = window.getComputedStyle(document.getElementById(elem
entId)).getPropertyCSSValue(property); | |
| 292 if (computedStyle.cssValueType == CSSValue.CSS_VALUE_LIST) { | |
| 293 var values = []; | |
| 294 for (var i = 0; i < computedStyle.length; ++i) { | |
| 295 switch (computedStyle[i].cssValueType) { | |
| 296 case CSSValue.CSS_PRIMITIVE_VALUE: | |
| 297 if (computedStyle[i].primitiveType == CSSPrimitiveValue.CSS_
STRING) | |
| 298 values.push(computedStyle[i].getStringValue()); | |
| 299 else | |
| 300 values.push(computedStyle[i].getFloatValue(CSSPrimitiveV
alue.CSS_NUMBER)); | |
| 301 break; | |
| 302 case CSSValue.CSS_CUSTOM: | |
| 303 // arbitrarily pick shadow-x and shadow-y | |
| 304 if (property == 'box-shadow' || property == 'text-shadow') { | |
| 305 var text = computedStyle[i].cssText; | |
| 306 // Shadow cssText looks like "rgb(0, 0, 255) 0px -3px 10px
0px" and can be fractional. | |
| 307 var shadowPositionRegExp = /\)\s*(-?[\d.]+)px\s*(-?[\d.]+)
px/; | |
| 308 var match = shadowPositionRegExp.exec(text); | |
| 309 var shadowXY = [parseInt(match[1]), parseInt(match[2])]; | |
| 310 values.push(shadowXY[0]); | |
| 311 values.push(shadowXY[1]); | |
| 312 } else | |
| 313 values.push(computedStyle[i].cssText); | |
| 314 break; | |
| 315 } | |
| 316 } | |
| 317 computedValue = values.join(','); | |
| 318 pass = true; | |
| 319 for (var i = 0; i < values.length; ++i) | |
| 320 pass &= isCloseEnough(values[i], expectedValue[i], tolerance); | |
| 321 } else if (computedStyle.cssValueType == CSSValue.CSS_PRIMITIVE_VALUE) { | |
| 322 switch (computedStyle.primitiveType) { | |
| 323 case CSSPrimitiveValue.CSS_STRING: | |
| 324 case CSSPrimitiveValue.CSS_IDENT: | |
| 325 computedValue = computedStyle.getStringValue(); | |
| 326 pass = computedValue == expectedValue; | |
| 327 break; | |
| 328 case CSSPrimitiveValue.CSS_RGBCOLOR: | |
| 329 var rgbColor = computedStyle.getRGBColorValue(); | |
| 330 computedValue = [rgbColor.red.getFloatValue(CSSPrimitiveValu
e.CSS_NUMBER), | |
| 331 rgbColor.green.getFloatValue(CSSPrimitiveVa
lue.CSS_NUMBER), | |
| 332 rgbColor.blue.getFloatValue(CSSPrimitiveVal
ue.CSS_NUMBER)]; // alpha is not exposed to JS | |
| 333 pass = true; | |
| 334 for (var i = 0; i < 3; ++i) | |
| 335 pass &= isCloseEnough(computedValue[i], expectedValue[i]
, tolerance); | |
| 336 break; | |
| 337 case CSSPrimitiveValue.CSS_RECT: | |
| 338 computedValue = computedStyle.getRectValue(); | |
| 339 computedValue = [computedValue.top.getFloatValue(CSSPrimitiv
eValue.CSS_NUMBER), | |
| 340 computedValue.right.getFloatValue(CSSPrimit
iveValue.CSS_NUMBER), | |
| 341 computedValue.bottom.getFloatValue(CSSPrimi
tiveValue.CSS_NUMBER), | |
| 342 computedValue.left.getFloatValue(CSSPrimiti
veValue.CSS_NUMBER)]; | |
| 343 pass = true; | |
| 344 for (var i = 0; i < 4; ++i) | |
| 345 pass &= isCloseEnough(computedValue[i], expectedValue[i
], tolerance); | |
| 346 break; | |
| 347 case CSSPrimitiveValue.CSS_PERCENTAGE: | |
| 348 computedValue = parseFloat(computedStyle.cssText); | |
| 349 pass = isCloseEnough(computedValue, expectedValue, tolerance
); | |
| 350 break; | |
| 351 default: | |
| 352 computedValue = computedStyle.getFloatValue(CSSPrimitiveValu
e.CSS_NUMBER); | |
| 353 pass = isCloseEnough(computedValue, expectedValue, tolerance
); | |
| 354 } | |
| 355 } | |
| 356 } | |
| 357 | |
| 358 if (pass) | |
| 359 result += "PASS - \"" + property + "\" property for \"" + elementId + "\
" element at " + time + "s saw something close to: " + expectedValue + "<br>"; | |
| 360 else | |
| 361 result += "FAIL - \"" + property + "\" property for \"" + elementId + "\
" element at " + time + "s expected: " + expectedValue + " but saw: " + computed
Value + "<br>"; | |
| 362 | 106 |
| 363 if (postCompletionCallback) | 107 if (postCompletionCallback) |
| 364 result += postCompletionCallback(); | 108 result += postCompletionCallback(); |
| 365 } | 109 } |
| 366 | 110 |
| 367 | |
| 368 function getPropertyValue(property, elementId, iframeId) | 111 function getPropertyValue(property, elementId, iframeId) |
| 369 { | 112 { |
| 370 var computedValue; | 113 var context = iframeId ? document.getElementById(iframeId).contentDocument :
document; |
| 371 var element; | 114 var element = context.getElementById(elementId); |
| 372 if (iframeId) | 115 return window.getComputedStyle(element)[property]; |
| 373 element = document.getElementById(iframeId).contentDocument.getElementBy
Id(elementId); | 116 } |
| 374 else | |
| 375 element = document.getElementById(elementId); | |
| 376 | 117 |
| 377 if (property == "lineHeight") | 118 // splitValue("calc(12.5px + 10%)") -> [["calc(", "px + ", "%)"], [12.5, 10]] |
| 378 computedValue = parseInt(window.getComputedStyle(element).lineHeight); | 119 function splitValue(value) |
| 379 else if (property == "backgroundImage" | 120 { |
| 380 || property == "borderImageSource" | 121 var substrings = value.split(/(-?\d+(?:\.\d+)?(?:e-?\d+)?)/g); |
| 381 || property == "listStyleImage" | 122 var strings = []; |
| 382 || property == "webkitMaskImage" | 123 var numbers = []; |
| 383 || property == "webkitMaskBoxImage" | 124 for (var i = 0; i < substrings.length; i++) { |
| 384 || property == "webkitFilter" | 125 if (i % 2 == 0) |
| 385 || property == "webkitClipPath" | 126 strings.push(substrings[i]); |
| 386 || !property.indexOf("webkitTransform")) { | 127 else |
| 387 computedValue = window.getComputedStyle(element)[property.split(".")[0]]
; | 128 numbers.push(parseFloat(substrings[i])); |
| 129 } |
| 130 return [strings, numbers]; |
| 131 } |
| 132 |
| 133 function comparePropertyValue(computedValue, expectedValue, tolerance, expectedI
ndex) |
| 134 { |
| 135 computedValue = splitValue(computedValue); |
| 136 var computedStrings = computedValue[0]; |
| 137 var computedNumbers = computedValue[1]; |
| 138 |
| 139 var expectedStrings, expectedNumbers; |
| 140 |
| 141 if (expectedIndex !== undefined) |
| 142 return isCloseEnough(computedNumbers[expectedIndex], expectedValue, tole
rance); |
| 143 |
| 144 if (typeof expectedValue === "string") { |
| 145 expectedValue = splitValue(expectedValue); |
| 146 |
| 147 expectedStrings = expectedValue[0]; |
| 148 if (computedStrings.length !== expectedStrings.length) |
| 149 return false; |
| 150 for (var i = 0; i < expectedStrings.length; i++) |
| 151 if (expectedStrings[i] !== computedStrings[i]) |
| 152 return false; |
| 153 |
| 154 expectedNumbers = expectedValue[1]; |
| 155 } else if (typeof expectedValue === "number") { |
| 156 expectedNumbers = [expectedValue]; |
| 388 } else { | 157 } else { |
| 389 var computedStyle = window.getComputedStyle(element).getPropertyCSSValue
(property); | 158 expectedNumbers = expectedValue; |
| 390 try { | |
| 391 computedValue = computedStyle.getFloatValue(CSSPrimitiveValue.CSS_NU
MBER); | |
| 392 } catch (e) { | |
| 393 computedValue = computedStyle.cssText; | |
| 394 } | |
| 395 } | 159 } |
| 396 | 160 |
| 397 return computedValue; | 161 if (computedNumbers.length !== expectedNumbers.length) |
| 398 } | 162 return false; |
| 163 for (var i = 0; i < expectedNumbers.length; i++) |
| 164 if (!isCloseEnough(computedNumbers[i], expectedNumbers[i], tolerance)) |
| 165 return false; |
| 399 | 166 |
| 400 function comparePropertyValue(property, computedValue, expectedValue, tolerance) | 167 return true; |
| 401 { | |
| 402 var result = true; | |
| 403 | |
| 404 if (!property.indexOf("webkitTransform")) { | |
| 405 if (typeof expectedValue == "string") | |
| 406 result = (computedValue == expectedValue); | |
| 407 else if (typeof expectedValue == "number") { | |
| 408 var m = matrixStringToArray(computedValue); | |
| 409 result = isCloseEnough(parseFloat(m[parseInt(property.substring(16))
]), expectedValue, tolerance); | |
| 410 } else { | |
| 411 var m = matrixStringToArray(computedValue); | |
| 412 for (i = 0; i < expectedValue.length; ++i) { | |
| 413 result = isCloseEnough(parseFloat(m[i]), expectedValue[i], toler
ance); | |
| 414 if (!result) | |
| 415 break; | |
| 416 } | |
| 417 } | |
| 418 } else if (property == "webkitFilter") { | |
| 419 var filterParameters = getFilterParameters(computedValue); | |
| 420 var filter2Parameters = getFilterParameters(expectedValue); | |
| 421 result = filterParametersMatch(filterParameters, filter2Parameters, tole
rance); | |
| 422 } else if (property == "webkitClipPath") { | |
| 423 var clipPathParameters = parseBasicShape(computedValue); | |
| 424 var clipPathParameters2 = parseBasicShape(expectedValue); | |
| 425 if (!clipPathParameters || !clipPathParameters2) | |
| 426 result = false; | |
| 427 result = basicShapeParametersMatch(clipPathParameters, clipPathParameter
s2, tolerance); | |
| 428 } else if (property == "backgroundImage" | |
| 429 || property == "borderImageSource" | |
| 430 || property == "listStyleImage" | |
| 431 || property == "webkitMaskImage" | |
| 432 || property == "webkitMaskBoxImage") { | |
| 433 var computedCrossFade = parseCrossFade(computedValue); | |
| 434 | |
| 435 if (!computedCrossFade) { | |
| 436 result = false; | |
| 437 } else { | |
| 438 if (typeof expectedValue == "string") { | |
| 439 var computedCrossFade2 = parseCrossFade(expectedValue); | |
| 440 result = isCloseEnough(computedCrossFade.percent, computedCrossF
ade2.percent, tolerance) && computedCrossFade.from == computedCrossFade2.from &&
computedCrossFade.to == computedCrossFade2.to; | |
| 441 } else { | |
| 442 result = isCloseEnough(computedCrossFade.percent, expectedValue,
tolerance) | |
| 443 } | |
| 444 } | |
| 445 } else { | |
| 446 if (typeof expectedValue == "string") | |
| 447 result = (computedValue == expectedValue); | |
| 448 else | |
| 449 result = isCloseEnough(computedValue, expectedValue, tolerance); | |
| 450 } | |
| 451 return result; | |
| 452 } | 168 } |
| 453 | 169 |
| 454 function endTest() | 170 function endTest() |
| 455 { | 171 { |
| 456 log('Ending test'); | 172 log('Ending test'); |
| 457 var resultElement = useResultElement ? document.getElementById('result') : d
ocument.documentElement; | 173 var resultElement = useResultElement ? document.getElementById('result') : d
ocument.documentElement; |
| 458 if (ENABLE_ERROR_LOGGING && result.indexOf('FAIL') >= 0) | 174 if (ENABLE_ERROR_LOGGING && result.indexOf('FAIL') >= 0) |
| 459 result += '<br>Log:<br>' + logMessages.join('<br>'); | 175 result += '<br>Log:<br>' + logMessages.join('<br>'); |
| 460 resultElement.innerHTML = result; | 176 resultElement.innerHTML = result; |
| 461 | 177 |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 545 } else for (var time in callbacks) { | 261 } else for (var time in callbacks) { |
| 546 timeMs = Math.round(time * 1000); | 262 timeMs = Math.round(time * 1000); |
| 547 checks[timeMs] = [callbacks[time]]; | 263 checks[timeMs] = [callbacks[time]]; |
| 548 } | 264 } |
| 549 | 265 |
| 550 for (var i = 0; i < expected.length; i++) { | 266 for (var i = 0; i < expected.length; i++) { |
| 551 var expectation = expected[i]; | 267 var expectation = expected[i]; |
| 552 var timeMs = Math.round(expectation[0] * 1000); | 268 var timeMs = Math.round(expectation[0] * 1000); |
| 553 if (!checks[timeMs]) | 269 if (!checks[timeMs]) |
| 554 checks[timeMs] = []; | 270 checks[timeMs] = []; |
| 555 if (isTransitionsTest) | 271 checks[timeMs].push(checkExpectedValue.bind(null, expected, i)); |
| 556 checks[timeMs].push(checkExpectedTransitionValue.bind(null, expected
, i)); | |
| 557 else | |
| 558 checks[timeMs].push(checkExpectedValue.bind(null, expected, i)); | |
| 559 } | 272 } |
| 560 | 273 |
| 561 var doPixelTest = Boolean(doPixelTest); | 274 var doPixelTest = Boolean(doPixelTest); |
| 562 useResultElement = doPixelTest; | 275 useResultElement = doPixelTest; |
| 563 | 276 |
| 564 if (window.testRunner) { | 277 if (window.testRunner) { |
| 565 if (doPixelTest) { | 278 if (doPixelTest) { |
| 566 testRunner.dumpAsTextWithPixelResults(); | 279 testRunner.dumpAsTextWithPixelResults(); |
| 567 } else { | 280 } else { |
| 568 testRunner.dumpAsText(); | 281 testRunner.dumpAsText(); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 591 var startTestImmediately = Boolean(startTestImmediately); | 304 var startTestImmediately = Boolean(startTestImmediately); |
| 592 if (startTestImmediately) { | 305 if (startTestImmediately) { |
| 593 begin(); | 306 begin(); |
| 594 } else { | 307 } else { |
| 595 var target = isTransitionsTest ? window : document; | 308 var target = isTransitionsTest ? window : document; |
| 596 var event = isTransitionsTest ? 'load' : 'webkitAnimationStart'; | 309 var event = isTransitionsTest ? 'load' : 'webkitAnimationStart'; |
| 597 target.addEventListener(event, begin, false); | 310 target.addEventListener(event, begin, false); |
| 598 } | 311 } |
| 599 } | 312 } |
| 600 | 313 |
| 601 /* This is the helper function to run transition tests: | |
| 602 | |
| 603 Test page requirements: | |
| 604 - The body must contain an empty div with id "result" | |
| 605 - Call this function directly from the <script> inside the test page | |
| 606 | |
| 607 Function parameters: | |
| 608 expected [required]: an array of arrays defining a set of CSS properties tha
t must have given values at specific times (see below) | |
| 609 trigger [optional]: a function to be executed just before the test starts (n
one by default) | |
| 610 callbacks [optional]: an object in the form {timeS: function} specifing call
backs to be made during the test | |
| 611 doPixelTest [optional]: whether to dump pixels during the test (false by def
ault) | |
| 612 disablePauseAnimationAPI [optional]: whether to disable the pause API and ru
n a RAF-based test (false by default) | |
| 613 | |
| 614 Each sub-array must contain these items in this order: | |
| 615 - the time in seconds at which to snapshot the CSS property | |
| 616 - the id of the element on which to get the CSS property value | |
| 617 - the name of the CSS property to get [1] | |
| 618 - the expected value for the CSS property | |
| 619 - the tolerance to use when comparing the effective CSS property value with
its expected value | |
| 620 | |
| 621 [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, | |
| 622 or a string which will be compared directly (useful if the expected value is
"none") | |
| 623 If the CSS property name is "-webkit-transform.N", expected value must be a
number corresponding to the Nth element of the matrix | |
| 624 | |
| 625 */ | |
| 626 function runTransitionTest(expected, trigger, callbacks, doPixelTest, disablePau
seAnimationAPI) { | 314 function runTransitionTest(expected, trigger, callbacks, doPixelTest, disablePau
seAnimationAPI) { |
| 627 isTransitionsTest = true; | 315 isTransitionsTest = true; |
| 628 runAnimationTest(expected, callbacks, trigger, disablePauseAnimationAPI, doP
ixelTest); | 316 runAnimationTest(expected, callbacks, trigger, disablePauseAnimationAPI, doP
ixelTest); |
| 629 } | 317 } |
| OLD | NEW |