Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 46 * results. This function may not be used in a ref test. | 46 * results. This function may not be used in a ref test. |
| 47 * * convertToReference - This is intended to be used interactively to | 47 * * convertToReference - This is intended to be used interactively to |
| 48 * construct a reference given the results of a test. To build a | 48 * construct a reference given the results of a test. To build a |
| 49 * reference, run the test, open the inspector and trigger this | 49 * reference, run the test, open the inspector and trigger this |
| 50 * function, then copy/paste the results. | 50 * function, then copy/paste the results. |
| 51 */ | 51 */ |
| 52 'use strict'; | 52 'use strict'; |
| 53 (function() { | 53 (function() { |
| 54 var webkitPrefix = 'webkitAnimation' in document.documentElement.style ? '-web kit-' : ''; | 54 var webkitPrefix = 'webkitAnimation' in document.documentElement.style ? '-web kit-' : ''; |
| 55 var isRefTest = false; | 55 var isRefTest = false; |
| 56 var webAnimationsTest = typeof document.head.animate === 'function'; | |
|
dstockwell
2014/03/20 00:35:45
Element.prototype.animate
alancutter (OOO until 2018)
2014/03/20 04:59:56
Done.
| |
| 56 var startEvent = webkitPrefix ? 'webkitAnimationStart' : 'animationstart'; | 57 var startEvent = webkitPrefix ? 'webkitAnimationStart' : 'animationstart'; |
| 57 var endEvent = webkitPrefix ? 'webkitAnimationEnd' : 'animationend'; | 58 var endEvent = webkitPrefix ? 'webkitAnimationEnd' : 'animationend'; |
| 58 var testCount = 0; | 59 var testCount = 0; |
| 59 var animationEventCount = 0; | 60 var animationEventCount = 0; |
| 60 // FIXME: This should be 0, but 0 duration animations are broken in at least | 61 // FIXME: This should be 0, but 0 duration animations are broken in at least |
| 61 // pre-Web-Animations Blink, WebKit and Gecko. | 62 // pre-Web-Animations Blink, WebKit and Gecko. |
| 62 var durationSeconds = 0.001; | 63 var durationSeconds = 0.001; |
| 63 var iterationCount = 0.5; | 64 var iterationCount = 0.5; |
| 64 var delaySeconds = 0; | 65 var delaySeconds = 0; |
| 65 var cssText = '.test:hover:before {\n' + | 66 var cssText = '.test:hover:before {\n' + |
| 66 ' content: attr(description);\n' + | 67 ' content: attr(description);\n' + |
| 67 ' position: absolute;\n' + | 68 ' position: absolute;\n' + |
| 68 ' z-index: 1000;\n' + | 69 ' z-index: 1000;\n' + |
| 69 ' background: gold;\n' + | 70 ' background: gold;\n' + |
| 70 '}\n'; | 71 '}\n'; |
| 71 var fragment = document.createDocumentFragment(); | 72 var fragment = document.createDocumentFragment(); |
| 73 var fragmentAttachedListeners = []; | |
| 72 var style = document.createElement('style'); | 74 var style = document.createElement('style'); |
| 75 var cssTests = document.createElement('div'); | |
| 76 cssTests.id = 'css-tests'; | |
| 73 var afterTestCallback = null; | 77 var afterTestCallback = null; |
| 74 fragment.appendChild(style); | 78 fragment.appendChild(style); |
| 79 fragment.appendChild(cssTests); | |
| 80 | |
| 81 if (webAnimationsTest) { | |
| 82 var waTests = document.createElement('div'); | |
| 83 waTests.id = 'web-animations-tests'; | |
| 84 fragment.appendChild(waTests); | |
| 85 } | |
| 75 | 86 |
| 76 var updateScheduled = false; | 87 var updateScheduled = false; |
| 77 function maybeScheduleUpdate() { | 88 function maybeScheduleUpdate() { |
| 78 if (updateScheduled) { | 89 if (updateScheduled) { |
| 79 return; | 90 return; |
| 80 } | 91 } |
| 81 updateScheduled = true; | 92 updateScheduled = true; |
| 82 setTimeout(function() { | 93 setTimeout(function() { |
| 83 updateScheduled = false; | 94 updateScheduled = false; |
| 84 style.innerHTML = cssText; | 95 style.innerHTML = cssText; |
| 85 document.body.appendChild(fragment); | 96 document.body.appendChild(fragment); |
| 97 fragmentAttachedListeners.forEach(function(listener) {listener();}); | |
| 86 }, 0); | 98 }, 0); |
| 87 } | 99 } |
| 88 | 100 |
| 89 function dumpResults() { | 101 function dumpResults() { |
| 90 var targets = document.querySelectorAll('.target.active'); | 102 var targets = document.querySelectorAll('.target.active'); |
| 91 if (isRefTest) { | 103 if (isRefTest) { |
| 92 // Convert back to reference to avoid cases where the computed style is | 104 // Convert back to reference to avoid cases where the computed style is |
| 93 // out of sync with the compositor. | 105 // out of sync with the compositor. |
| 94 for (var i = 0; i < targets.length; i++) { | 106 for (var i = 0; i < targets.length; i++) { |
| 95 targets[i].convertToReference(); | 107 targets[i].convertToReference(); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 149 | 161 |
| 150 function testInterpolationAt(fractions, params) { | 162 function testInterpolationAt(fractions, params) { |
| 151 if (!Array.isArray(fractions)) { | 163 if (!Array.isArray(fractions)) { |
| 152 fractions = [fractions]; | 164 fractions = [fractions]; |
| 153 } | 165 } |
| 154 assertInterpolation(params, fractions.map(function(fraction) { | 166 assertInterpolation(params, fractions.map(function(fraction) { |
| 155 return {at: fraction}; | 167 return {at: fraction}; |
| 156 })); | 168 })); |
| 157 } | 169 } |
| 158 | 170 |
| 159 function describeTest(params) { | 171 function createTestContainer(description, className) { |
| 160 return params.property + ': from [' + params.from + '] to [' + params.to + ' ]'; | 172 var testContainer = document.createElement('div'); |
| 173 testContainer.setAttribute('description', description); | |
| 174 testContainer.classList.add('test'); | |
| 175 if (className) { | |
| 176 testContainer.classList.add(className); | |
| 177 } | |
| 178 return testContainer; | |
| 179 } | |
| 180 | |
| 181 function convertPropertyToCamelCase(property) { | |
| 182 return property.replace(/^-/, '').replace(/-\w/g, function(m) {return m[1].t oUpperCase();}); | |
| 183 } | |
| 184 | |
| 185 function describeCSSTest(params) { | |
| 186 return 'CSS ' + params.property + ': from [' + params.from + '] to [' + para ms.to + ']'; | |
| 187 } | |
| 188 | |
| 189 function describeWATest(params) { | |
| 190 return 'element.animate() ' + convertPropertyToCamelCase(params.property) + ': from [' + params.from + '] to [' + params.to + ']'; | |
| 161 } | 191 } |
| 162 | 192 |
| 163 function assertInterpolation(params, expectations) { | 193 function assertInterpolation(params, expectations) { |
| 164 // If the prefixed property is not supported, try to unprefix it. | 194 // If the prefixed property is not supported, try to unprefix it. |
| 165 if (/^-[^-]+-/.test(params.property) && !CSS.supports(params.property, 'init ial')) { | 195 if (/^-[^-]+-/.test(params.property) && !CSS.supports(params.property, 'init ial')) { |
| 166 var unprefixed = params.property.replace(/^-[^-]+-/, ''); | 196 var unprefixed = params.property.replace(/^-[^-]+-/, ''); |
| 167 if (CSS.supports(unprefixed, 'initial')) { | 197 if (CSS.supports(unprefixed, 'initial')) { |
| 168 params.property = unprefixed; | 198 params.property = unprefixed; |
| 169 } | 199 } |
| 170 } | 200 } |
| 171 var testId = defineKeyframes(params); | 201 var testId = defineKeyframes(params); |
| 172 var nextCaseId = 0; | 202 var nextCaseId = 0; |
| 173 var testContainer = document.createElement('div'); | 203 var cssTestContainer = createTestContainer(describeCSSTest(params), testId); |
| 174 testContainer.setAttribute('description', describeTest(params)); | 204 cssTests.appendChild(cssTestContainer); |
| 175 testContainer.classList.add('test'); | 205 if (webAnimationsTest) { |
| 176 testContainer.classList.add(testId); | 206 var waTestContainer = createTestContainer(describeWATest(params), testId); |
| 177 fragment.appendChild(testContainer); | 207 waTests.appendChild(waTestContainer); |
| 208 } | |
| 178 expectations.forEach(function(expectation) { | 209 expectations.forEach(function(expectation) { |
| 179 testContainer.appendChild(makeInterpolationTest( | 210 cssTestContainer.appendChild(makeInterpolationTest( |
| 180 expectation.at, testId, 'case-' + ++nextCaseId, params, expectation.is )); | 211 true, expectation.at, testId, 'case-' + ++nextCaseId, params, expectat ion.is)); |
| 181 }); | 212 }); |
| 213 if (webAnimationsTest) { | |
| 214 expectations.forEach(function(expectation) { | |
| 215 waTestContainer.appendChild(makeInterpolationTest( | |
| 216 false, expectation.at, testId, 'case-' + ++nextCaseId, params, expec tation.is)); | |
| 217 }); | |
| 218 } | |
| 182 maybeScheduleUpdate(); | 219 maybeScheduleUpdate(); |
| 183 } | 220 } |
| 184 | 221 |
| 185 var nextKeyframeId = 0; | 222 var nextKeyframeId = 0; |
| 186 function defineKeyframes(params) { | 223 function defineKeyframes(params) { |
| 187 var testId = 'test-' + ++nextKeyframeId; | 224 var testId = 'test-' + ++nextKeyframeId; |
| 188 cssText += '@' + webkitPrefix + 'keyframes ' + testId + ' { \n' + | 225 cssText += '@' + webkitPrefix + 'keyframes ' + testId + ' { \n' + |
| 189 ' 0% { ' + params.property + ': ' + params.from + '; }\n' + | 226 ' 0% { ' + params.property + ': ' + params.from + '; }\n' + |
| 190 ' 100% { ' + params.property + ': ' + params.to + '; }\n' + | 227 ' 100% { ' + params.property + ': ' + params.to + '; }\n' + |
| 191 '}\n'; | 228 '}\n'; |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 236 var url = /url\(([^\)]*)\)/g.exec(matches[i])[1]; | 273 var url = /url\(([^\)]*)\)/g.exec(matches[i])[1]; |
| 237 var anchor = document.createElement('a'); | 274 var anchor = document.createElement('a'); |
| 238 anchor.href = url; | 275 anchor.href = url; |
| 239 anchor.pathname = '...' + anchor.pathname.substring(anchor.pathname.last IndexOf('/')); | 276 anchor.pathname = '...' + anchor.pathname.substring(anchor.pathname.last IndexOf('/')); |
| 240 value = value.replace(matches[i], 'url(' + anchor.href + ')'); | 277 value = value.replace(matches[i], 'url(' + anchor.href + ')'); |
| 241 } | 278 } |
| 242 } | 279 } |
| 243 return value; | 280 return value; |
| 244 } | 281 } |
| 245 | 282 |
| 246 function makeInterpolationTest(fraction, testId, caseId, params, expectation) { | 283 function makeInterpolationTest(cssTest, fraction, testId, caseId, params, expe ctation) { |
| 247 console.assert(expectation === undefined || !isRefTest); | 284 console.assert(expectation === undefined || !isRefTest); |
| 248 var targetContainer = createTargetContainer(caseId); | 285 var targetContainer = createTargetContainer(caseId); |
| 249 var target = targetContainer.querySelector('.target') || targetContainer; | 286 var target = targetContainer.querySelector('.target') || targetContainer; |
| 250 target.classList.add('active'); | 287 target.classList.add('active'); |
| 251 var replicaContainer, replica; | 288 var replicaContainer, replica; |
| 252 if (expectation !== undefined) { | 289 if (expectation !== undefined) { |
| 253 replicaContainer = createTargetContainer(caseId); | 290 replicaContainer = createTargetContainer(caseId); |
| 254 replica = replicaContainer.querySelector('.target') || replicaContainer; | 291 replica = replicaContainer.querySelector('.target') || replicaContainer; |
| 255 replica.classList.add('replica'); | 292 replica.classList.add('replica'); |
| 256 replica.style.setProperty(params.property, expectation); | 293 replica.style.setProperty(params.property, expectation); |
| 257 } | 294 } |
| 258 target.getResultString = function() { | 295 target.getResultString = function() { |
| 259 if (!CSS.supports(params.property, expectation)) { | 296 if (!CSS.supports(params.property, expectation)) { |
| 260 return 'FAIL: [' + params.property + ': ' + expectation + '] is not supp orted'; | 297 return 'FAIL: [' + params.property + ': ' + expectation + '] is not supp orted'; |
| 261 } | 298 } |
| 262 var value = getComputedStyle(this).getPropertyValue(params.property); | 299 var value = getComputedStyle(this).getPropertyValue(params.property); |
| 263 var result = ''; | 300 var result = ''; |
| 264 var reason = ''; | 301 var reason = ''; |
| 302 var property = cssTest ? params.property : convertPropertyToCamelCase(para ms.property); | |
| 265 if (expectation !== undefined) { | 303 if (expectation !== undefined) { |
| 266 var parsedExpectation = getComputedStyle(replica).getPropertyValue(param s.property); | 304 var parsedExpectation = getComputedStyle(replica).getPropertyValue(param s.property); |
| 267 var pass = normalizeValue(value) === normalizeValue(parsedExpectation); | 305 var pass = normalizeValue(value) === normalizeValue(parsedExpectation); |
| 268 result = pass ? 'PASS: ' : 'FAIL: '; | 306 result = pass ? 'PASS: ' : 'FAIL: '; |
| 269 reason = pass ? '' : ', expected [' + expectation + ']' + | 307 reason = pass ? '' : ', expected [' + expectation + ']' + |
| 270 (expectation === parsedExpectation ? '' : ' (parsed as [' + sanitize Urls(parsedExpectation) + '])'); | 308 (expectation === parsedExpectation ? '' : ' (parsed as [' + sanitize Urls(parsedExpectation) + '])'); |
| 271 value = pass ? expectation : sanitizeUrls(value); | 309 value = pass ? expectation : sanitizeUrls(value); |
| 272 } | 310 } |
| 273 return result + params.property + ' from [' + params.from + '] to ' + | 311 return result + property + ' from [' + params.from + '] to ' + |
| 274 '[' + params.to + '] was [' + value + ']' + | 312 '[' + params.to + '] was [' + value + ']' + |
| 275 ' at ' + fraction + reason; | 313 ' at ' + fraction + reason; |
| 276 }; | 314 }; |
| 277 target.convertToReference = function() { | 315 target.convertToReference = function() { |
| 278 this.style[params.property] = getComputedStyle(this).getPropertyValue(para ms.property); | 316 this.style[params.property] = getComputedStyle(this).getPropertyValue(para ms.property); |
| 279 }; | 317 }; |
| 280 var easing = createEasing(fraction); | 318 var easing = createEasing(fraction); |
| 281 cssText += '.' + testId + ' .' + caseId + '.active {\n' + | |
| 282 ' ' + webkitPrefix + 'animation: ' + testId + ' ' + durationSeconds + ' s forwards;\n' + | |
| 283 ' ' + webkitPrefix + 'animation-timing-function: ' + easing + ';\n' + | |
| 284 ' ' + webkitPrefix + 'animation-iteration-count: ' + iterationCount + ' ;\n' + | |
| 285 ' ' + webkitPrefix + 'animation-delay: ' + delaySeconds + 's;\n' + | |
| 286 '}\n'; | |
| 287 testCount++; | 319 testCount++; |
| 320 if (cssTest) { | |
| 321 cssText += '.' + testId + ' .' + caseId + '.active {\n' + | |
| 322 ' ' + webkitPrefix + 'animation: ' + testId + ' ' + durationSeconds + 's forwards;\n' + | |
| 323 ' ' + webkitPrefix + 'animation-timing-function: ' + easing + ';\n' + | |
| 324 ' ' + webkitPrefix + 'animation-iteration-count: ' + iterationCount + ';\n' + | |
| 325 ' ' + webkitPrefix + 'animation-delay: ' + delaySeconds + 's;\n' + | |
| 326 '}\n'; | |
| 327 } else { | |
| 328 var keyframes = [{}, {}]; | |
| 329 keyframes[0][convertPropertyToCamelCase(params.property)] = params.from; | |
| 330 keyframes[1][convertPropertyToCamelCase(params.property)] = params.to; | |
| 331 fragmentAttachedListeners.push(function() { | |
| 332 target.animate(keyframes, { | |
| 333 fill: 'forwards', | |
| 334 duration: 1, | |
| 335 easing: easing, | |
| 336 delay: -0.5, | |
| 337 iterations: 0.5, | |
| 338 }); | |
| 339 animationEnded(); | |
| 340 }); | |
| 341 } | |
| 288 var testFragment = document.createDocumentFragment(); | 342 var testFragment = document.createDocumentFragment(); |
| 289 testFragment.appendChild(targetContainer); | 343 testFragment.appendChild(targetContainer); |
| 290 replica && testFragment.appendChild(replicaContainer); | 344 replica && testFragment.appendChild(replicaContainer); |
| 291 testFragment.appendChild(document.createTextNode('\n')); | 345 testFragment.appendChild(document.createTextNode('\n')); |
| 292 return testFragment; | 346 return testFragment; |
| 293 } | 347 } |
| 294 | 348 |
| 295 var finished = false; | 349 var finished = false; |
| 296 function finishTest() { | 350 function finishTest() { |
| 297 finished = true; | 351 finished = true; |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 311 } | 365 } |
| 312 | 366 |
| 313 if (window.testRunner) { | 367 if (window.testRunner) { |
| 314 testRunner.waitUntilDone(); | 368 testRunner.waitUntilDone(); |
| 315 } | 369 } |
| 316 | 370 |
| 317 function isLastAnimationEvent() { | 371 function isLastAnimationEvent() { |
| 318 return !finished && animationEventCount === testCount; | 372 return !finished && animationEventCount === testCount; |
| 319 } | 373 } |
| 320 | 374 |
| 321 function endEventListener() { | 375 function animationEnded() { |
| 322 animationEventCount++; | 376 animationEventCount++; |
| 323 if (!isLastAnimationEvent()) { | 377 if (!isLastAnimationEvent()) { |
| 324 return; | 378 return; |
| 325 } | 379 } |
| 326 finishTest(); | 380 finishTest(); |
| 327 } | 381 } |
| 328 | 382 |
| 329 if (window.internals) { | 383 if (window.internals) { |
| 330 durationSeconds = 0; | 384 durationSeconds = 0; |
| 331 document.documentElement.addEventListener(endEvent, endEventListener); | 385 document.documentElement.addEventListener(endEvent, animationEnded); |
| 332 } else if (webkitPrefix) { | 386 } else if (webkitPrefix) { |
| 333 durationSeconds = 1e9; | 387 durationSeconds = 1e9; |
| 334 iterationCount = 1; | 388 iterationCount = 1; |
| 335 delaySeconds = -durationSeconds / 2; | 389 delaySeconds = -durationSeconds / 2; |
| 336 document.documentElement.addEventListener(startEvent, function() { | 390 document.documentElement.addEventListener(startEvent, function() { |
| 337 animationEventCount++; | 391 animationEventCount++; |
| 338 if (!isLastAnimationEvent()) { | 392 if (!isLastAnimationEvent()) { |
| 339 return; | 393 return; |
| 340 } | 394 } |
| 341 setTimeout(finishTest, 0); | 395 setTimeout(finishTest, 0); |
| 342 }); | 396 }); |
| 343 } else { | 397 } else { |
| 344 document.documentElement.addEventListener(endEvent, endEventListener); | 398 document.documentElement.addEventListener(endEvent, animationEnded); |
| 345 } | 399 } |
| 346 | 400 |
| 347 if (!window.testRunner) { | 401 if (!window.testRunner) { |
| 348 setTimeout(function() { | 402 setTimeout(function() { |
| 349 if (finished) { | 403 if (finished) { |
| 350 return; | 404 return; |
| 351 } | 405 } |
| 352 finishTest(); | 406 finishTest(); |
| 353 }, 10000); | 407 }, 10000); |
| 354 } | 408 } |
| 355 | 409 |
| 356 window.runAsRefTest = runAsRefTest; | 410 window.runAsRefTest = runAsRefTest; |
| 357 window.testInterpolationAt = testInterpolationAt; | 411 window.testInterpolationAt = testInterpolationAt; |
| 358 window.assertInterpolation = assertInterpolation; | 412 window.assertInterpolation = assertInterpolation; |
| 359 window.convertToReference = convertToReference; | 413 window.convertToReference = convertToReference; |
| 360 window.afterTest = afterTest; | 414 window.afterTest = afterTest; |
| 361 })(); | 415 })(); |
| OLD | NEW |