| 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 |