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 Element.prototype.animate === 'function'; | |
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'; | |
77 cssTests.textContent = 'CSS Animations:'; | |
73 var afterTestCallback = null; | 78 var afterTestCallback = null; |
74 fragment.appendChild(style); | 79 fragment.appendChild(style); |
80 fragment.appendChild(cssTests); | |
81 | |
82 if (webAnimationsTest) { | |
83 var waTests = document.createElement('div'); | |
84 waTests.id = 'web-animations-tests'; | |
85 waTests.textContent = 'Web Animations API:'; | |
86 fragment.appendChild(waTests); | |
87 } | |
75 | 88 |
76 var updateScheduled = false; | 89 var updateScheduled = false; |
77 function maybeScheduleUpdate() { | 90 function maybeScheduleUpdate() { |
78 if (updateScheduled) { | 91 if (updateScheduled) { |
79 return; | 92 return; |
80 } | 93 } |
81 updateScheduled = true; | 94 updateScheduled = true; |
82 setTimeout(function() { | 95 setTimeout(function() { |
83 updateScheduled = false; | 96 updateScheduled = false; |
84 style.innerHTML = cssText; | 97 style.innerHTML = cssText; |
85 document.body.appendChild(fragment); | 98 document.body.appendChild(fragment); |
99 fragmentAttachedListeners.forEach(function(listener) {listener();}); | |
86 }, 0); | 100 }, 0); |
87 } | 101 } |
88 | 102 |
89 function dumpResults() { | 103 function dumpResults() { |
90 var targets = document.querySelectorAll('.target.active'); | 104 var targets = document.querySelectorAll('.target.active'); |
91 if (isRefTest) { | 105 if (isRefTest) { |
92 // Convert back to reference to avoid cases where the computed style is | 106 // Convert back to reference to avoid cases where the computed style is |
93 // out of sync with the compositor. | 107 // out of sync with the compositor. |
94 for (var i = 0; i < targets.length; i++) { | 108 for (var i = 0; i < targets.length; i++) { |
95 targets[i].convertToReference(); | 109 targets[i].convertToReference(); |
96 } | 110 } |
97 style.parentNode.removeChild(style); | 111 style.parentNode.removeChild(style); |
98 } else { | 112 } else { |
99 var resultString = ''; | 113 var cssResultString = 'CSS Animations:\n'; |
114 var waResultString = 'Web Animations API:\n'; | |
100 for (var i = 0; i < targets.length; i++) { | 115 for (var i = 0; i < targets.length; i++) { |
101 resultString += targets[i].getResultString() + '\n'; | 116 if (targets[i].isCSSTest) { |
117 cssResultString += targets[i].getResultString() + '\n'; | |
118 } else { | |
119 waResultString += targets[i].getResultString() + '\n'; | |
120 } | |
102 } | 121 } |
103 var results = document.createElement('div'); | 122 var results = document.createElement('pre'); |
104 results.style.whiteSpace = 'pre'; | 123 results.textContent = cssResultString + (webAnimationsTest ? '\n' + waResu ltString : ''); |
105 results.textContent = resultString; | |
106 results.id = 'results'; | 124 results.id = 'results'; |
107 document.body.appendChild(results); | 125 document.body.appendChild(results); |
108 } | 126 } |
109 } | 127 } |
110 | 128 |
111 function convertToReference() { | 129 function convertToReference() { |
112 console.assert(isRefTest); | 130 console.assert(isRefTest); |
113 var scripts = document.querySelectorAll('script'); | 131 var scripts = document.querySelectorAll('script'); |
114 for (var i = 0; i < scripts.length; i++) { | 132 for (var i = 0; i < scripts.length; i++) { |
115 scripts[i].parentNode.removeChild(scripts[i]); | 133 scripts[i].parentNode.removeChild(scripts[i]); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
149 | 167 |
150 function testInterpolationAt(fractions, params) { | 168 function testInterpolationAt(fractions, params) { |
151 if (!Array.isArray(fractions)) { | 169 if (!Array.isArray(fractions)) { |
152 fractions = [fractions]; | 170 fractions = [fractions]; |
153 } | 171 } |
154 assertInterpolation(params, fractions.map(function(fraction) { | 172 assertInterpolation(params, fractions.map(function(fraction) { |
155 return {at: fraction}; | 173 return {at: fraction}; |
156 })); | 174 })); |
157 } | 175 } |
158 | 176 |
159 function describeTest(params) { | 177 function createTestContainer(description, className) { |
160 return params.property + ': from [' + params.from + '] to [' + params.to + ' ]'; | 178 var testContainer = document.createElement('div'); |
179 testContainer.setAttribute('description', description); | |
180 testContainer.classList.add('test'); | |
181 if (className) { | |
182 testContainer.classList.add(className); | |
183 } | |
184 return testContainer; | |
185 } | |
186 | |
187 function convertPropertyToCamelCase(property) { | |
188 return property.replace(/^-/, '').replace(/-\w/g, function(m) {return m[1].t oUpperCase();}); | |
189 } | |
190 | |
191 function describeCSSTest(params) { | |
192 return 'CSS ' + params.property + ': from [' + params.from + '] to [' + para ms.to + ']'; | |
193 } | |
194 | |
195 function describeWATest(params) { | |
196 return 'element.animate() ' + convertPropertyToCamelCase(params.property) + ': from [' + params.from + '] to [' + params.to + ']'; | |
161 } | 197 } |
162 | 198 |
163 function assertInterpolation(params, expectations) { | 199 function assertInterpolation(params, expectations) { |
164 // If the prefixed property is not supported, try to unprefix it. | 200 // If the prefixed property is not supported, try to unprefix it. |
165 if (/^-[^-]+-/.test(params.property) && !CSS.supports(params.property, 'init ial')) { | 201 if (/^-[^-]+-/.test(params.property) && !CSS.supports(params.property, 'init ial')) { |
166 var unprefixed = params.property.replace(/^-[^-]+-/, ''); | 202 var unprefixed = params.property.replace(/^-[^-]+-/, ''); |
167 if (CSS.supports(unprefixed, 'initial')) { | 203 if (CSS.supports(unprefixed, 'initial')) { |
168 params.property = unprefixed; | 204 params.property = unprefixed; |
169 } | 205 } |
170 } | 206 } |
171 var testId = defineKeyframes(params); | 207 var testId = defineKeyframes(params); |
172 var nextCaseId = 0; | 208 var nextCaseId = 0; |
173 var testContainer = document.createElement('div'); | 209 var cssTestContainer = createTestContainer(describeCSSTest(params), testId); |
174 testContainer.setAttribute('description', describeTest(params)); | 210 cssTests.appendChild(cssTestContainer); |
175 testContainer.classList.add('test'); | 211 if (webAnimationsTest) { |
176 testContainer.classList.add(testId); | 212 var waTestContainer = createTestContainer(describeWATest(params), testId); |
177 fragment.appendChild(testContainer); | 213 waTests.appendChild(waTestContainer); |
214 } | |
178 expectations.forEach(function(expectation) { | 215 expectations.forEach(function(expectation) { |
179 testContainer.appendChild(makeInterpolationTest( | 216 cssTestContainer.appendChild(makeInterpolationTest( |
180 expectation.at, testId, 'case-' + ++nextCaseId, params, expectation.is )); | 217 true, expectation.at, testId, 'case-' + ++nextCaseId, params, expectat ion.is)); |
181 }); | 218 }); |
219 if (webAnimationsTest) { | |
220 expectations.forEach(function(expectation) { | |
221 waTestContainer.appendChild(makeInterpolationTest( | |
222 false, expectation.at, testId, 'case-' + ++nextCaseId, params, expec tation.is)); | |
223 }); | |
224 } | |
182 maybeScheduleUpdate(); | 225 maybeScheduleUpdate(); |
183 } | 226 } |
184 | 227 |
185 var nextKeyframeId = 0; | 228 var nextKeyframeId = 0; |
186 function defineKeyframes(params) { | 229 function defineKeyframes(params) { |
187 var testId = 'test-' + ++nextKeyframeId; | 230 var testId = 'test-' + ++nextKeyframeId; |
188 cssText += '@' + webkitPrefix + 'keyframes ' + testId + ' { \n' + | 231 cssText += '@' + webkitPrefix + 'keyframes ' + testId + ' { \n' + |
189 ' 0% { ' + params.property + ': ' + params.from + '; }\n' + | 232 ' 0% { ' + params.property + ': ' + params.from + '; }\n' + |
190 ' 100% { ' + params.property + ': ' + params.to + '; }\n' + | 233 ' 100% { ' + params.property + ': ' + params.to + '; }\n' + |
191 '}\n'; | 234 '}\n'; |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
236 var url = /url\(([^\)]*)\)/g.exec(matches[i])[1]; | 279 var url = /url\(([^\)]*)\)/g.exec(matches[i])[1]; |
237 var anchor = document.createElement('a'); | 280 var anchor = document.createElement('a'); |
238 anchor.href = url; | 281 anchor.href = url; |
239 anchor.pathname = '...' + anchor.pathname.substring(anchor.pathname.last IndexOf('/')); | 282 anchor.pathname = '...' + anchor.pathname.substring(anchor.pathname.last IndexOf('/')); |
240 value = value.replace(matches[i], 'url(' + anchor.href + ')'); | 283 value = value.replace(matches[i], 'url(' + anchor.href + ')'); |
241 } | 284 } |
242 } | 285 } |
243 return value; | 286 return value; |
244 } | 287 } |
245 | 288 |
246 function makeInterpolationTest(fraction, testId, caseId, params, expectation) { | 289 function makeInterpolationTest(cssTest, fraction, testId, caseId, params, expe ctation) { |
dstockwell
2014/03/20 05:47:24
Instead of a boolean parameter, cssTest could be '
alancutter (OOO until 2018)
2014/03/20 05:55:59
Done.
| |
247 console.assert(expectation === undefined || !isRefTest); | 290 console.assert(expectation === undefined || !isRefTest); |
248 var targetContainer = createTargetContainer(caseId); | 291 var targetContainer = createTargetContainer(caseId); |
249 var target = targetContainer.querySelector('.target') || targetContainer; | 292 var target = targetContainer.querySelector('.target') || targetContainer; |
250 target.classList.add('active'); | 293 target.classList.add('active'); |
251 var replicaContainer, replica; | 294 var replicaContainer, replica; |
252 if (expectation !== undefined) { | 295 if (expectation !== undefined) { |
253 replicaContainer = createTargetContainer(caseId); | 296 replicaContainer = createTargetContainer(caseId); |
254 replica = replicaContainer.querySelector('.target') || replicaContainer; | 297 replica = replicaContainer.querySelector('.target') || replicaContainer; |
255 replica.classList.add('replica'); | 298 replica.classList.add('replica'); |
256 replica.style.setProperty(params.property, expectation); | 299 replica.style.setProperty(params.property, expectation); |
257 } | 300 } |
301 target.isCSSTest = cssTest; | |
dstockwell
2014/03/20 05:47:24
here too
alancutter (OOO until 2018)
2014/03/20 05:55:59
Done.
| |
258 target.getResultString = function() { | 302 target.getResultString = function() { |
259 if (!CSS.supports(params.property, expectation)) { | 303 if (!CSS.supports(params.property, expectation)) { |
260 return 'FAIL: [' + params.property + ': ' + expectation + '] is not supp orted'; | 304 return 'FAIL: [' + params.property + ': ' + expectation + '] is not supp orted'; |
261 } | 305 } |
262 var value = getComputedStyle(this).getPropertyValue(params.property); | 306 var value = getComputedStyle(this).getPropertyValue(params.property); |
263 var result = ''; | 307 var result = ''; |
264 var reason = ''; | 308 var reason = ''; |
309 var property = cssTest ? params.property : convertPropertyToCamelCase(para ms.property); | |
265 if (expectation !== undefined) { | 310 if (expectation !== undefined) { |
266 var parsedExpectation = getComputedStyle(replica).getPropertyValue(param s.property); | 311 var parsedExpectation = getComputedStyle(replica).getPropertyValue(param s.property); |
267 var pass = normalizeValue(value) === normalizeValue(parsedExpectation); | 312 var pass = normalizeValue(value) === normalizeValue(parsedExpectation); |
268 result = pass ? 'PASS: ' : 'FAIL: '; | 313 result = pass ? 'PASS: ' : 'FAIL: '; |
269 reason = pass ? '' : ', expected [' + expectation + ']' + | 314 reason = pass ? '' : ', expected [' + expectation + ']' + |
270 (expectation === parsedExpectation ? '' : ' (parsed as [' + sanitize Urls(parsedExpectation) + '])'); | 315 (expectation === parsedExpectation ? '' : ' (parsed as [' + sanitize Urls(parsedExpectation) + '])'); |
271 value = pass ? expectation : sanitizeUrls(value); | 316 value = pass ? expectation : sanitizeUrls(value); |
272 } | 317 } |
273 return result + params.property + ' from [' + params.from + '] to ' + | 318 return result + property + ' from [' + params.from + '] to ' + |
274 '[' + params.to + '] was [' + value + ']' + | 319 '[' + params.to + '] was [' + value + ']' + |
275 ' at ' + fraction + reason; | 320 ' at ' + fraction + reason; |
276 }; | 321 }; |
277 target.convertToReference = function() { | 322 target.convertToReference = function() { |
278 this.style[params.property] = getComputedStyle(this).getPropertyValue(para ms.property); | 323 this.style[params.property] = getComputedStyle(this).getPropertyValue(para ms.property); |
279 }; | 324 }; |
280 var easing = createEasing(fraction); | 325 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++; | 326 testCount++; |
327 if (cssTest) { | |
328 cssText += '.' + testId + ' .' + caseId + '.active {\n' + | |
329 ' ' + webkitPrefix + 'animation: ' + testId + ' ' + durationSeconds + 's forwards;\n' + | |
330 ' ' + webkitPrefix + 'animation-timing-function: ' + easing + ';\n' + | |
331 ' ' + webkitPrefix + 'animation-iteration-count: ' + iterationCount + ';\n' + | |
332 ' ' + webkitPrefix + 'animation-delay: ' + delaySeconds + 's;\n' + | |
333 '}\n'; | |
334 } else { | |
335 var keyframes = [{}, {}]; | |
336 keyframes[0][convertPropertyToCamelCase(params.property)] = params.from; | |
337 keyframes[1][convertPropertyToCamelCase(params.property)] = params.to; | |
338 fragmentAttachedListeners.push(function() { | |
339 target.animate(keyframes, { | |
340 fill: 'forwards', | |
341 duration: 1, | |
342 easing: easing, | |
343 delay: -0.5, | |
344 iterations: 0.5, | |
345 }); | |
346 animationEnded(); | |
347 }); | |
348 } | |
288 var testFragment = document.createDocumentFragment(); | 349 var testFragment = document.createDocumentFragment(); |
289 testFragment.appendChild(targetContainer); | 350 testFragment.appendChild(targetContainer); |
290 replica && testFragment.appendChild(replicaContainer); | 351 replica && testFragment.appendChild(replicaContainer); |
291 testFragment.appendChild(document.createTextNode('\n')); | 352 testFragment.appendChild(document.createTextNode('\n')); |
292 return testFragment; | 353 return testFragment; |
293 } | 354 } |
294 | 355 |
295 var finished = false; | 356 var finished = false; |
296 function finishTest() { | 357 function finishTest() { |
297 finished = true; | 358 finished = true; |
(...skipping 13 matching lines...) Expand all Loading... | |
311 } | 372 } |
312 | 373 |
313 if (window.testRunner) { | 374 if (window.testRunner) { |
314 testRunner.waitUntilDone(); | 375 testRunner.waitUntilDone(); |
315 } | 376 } |
316 | 377 |
317 function isLastAnimationEvent() { | 378 function isLastAnimationEvent() { |
318 return !finished && animationEventCount === testCount; | 379 return !finished && animationEventCount === testCount; |
319 } | 380 } |
320 | 381 |
321 function endEventListener() { | 382 function animationEnded() { |
322 animationEventCount++; | 383 animationEventCount++; |
323 if (!isLastAnimationEvent()) { | 384 if (!isLastAnimationEvent()) { |
324 return; | 385 return; |
325 } | 386 } |
326 finishTest(); | 387 finishTest(); |
327 } | 388 } |
328 | 389 |
329 if (window.internals) { | 390 if (window.internals) { |
330 durationSeconds = 0; | 391 durationSeconds = 0; |
331 document.documentElement.addEventListener(endEvent, endEventListener); | 392 document.documentElement.addEventListener(endEvent, animationEnded); |
332 } else if (webkitPrefix) { | 393 } else if (webkitPrefix) { |
333 durationSeconds = 1e9; | 394 durationSeconds = 1e9; |
334 iterationCount = 1; | 395 iterationCount = 1; |
335 delaySeconds = -durationSeconds / 2; | 396 delaySeconds = -durationSeconds / 2; |
336 document.documentElement.addEventListener(startEvent, function() { | 397 document.documentElement.addEventListener(startEvent, function() { |
337 animationEventCount++; | 398 animationEventCount++; |
338 if (!isLastAnimationEvent()) { | 399 if (!isLastAnimationEvent()) { |
339 return; | 400 return; |
340 } | 401 } |
341 setTimeout(finishTest, 0); | 402 setTimeout(finishTest, 0); |
342 }); | 403 }); |
343 } else { | 404 } else { |
344 document.documentElement.addEventListener(endEvent, endEventListener); | 405 document.documentElement.addEventListener(endEvent, animationEnded); |
345 } | 406 } |
346 | 407 |
347 if (!window.testRunner) { | 408 if (!window.testRunner) { |
348 setTimeout(function() { | 409 setTimeout(function() { |
349 if (finished) { | 410 if (finished) { |
350 return; | 411 return; |
351 } | 412 } |
352 finishTest(); | 413 finishTest(); |
353 }, 10000); | 414 }, 10000); |
354 } | 415 } |
355 | 416 |
356 window.runAsRefTest = runAsRefTest; | 417 window.runAsRefTest = runAsRefTest; |
357 window.testInterpolationAt = testInterpolationAt; | 418 window.testInterpolationAt = testInterpolationAt; |
358 window.assertInterpolation = assertInterpolation; | 419 window.assertInterpolation = assertInterpolation; |
359 window.convertToReference = convertToReference; | 420 window.convertToReference = convertToReference; |
360 window.afterTest = afterTest; | 421 window.afterTest = afterTest; |
361 })(); | 422 })(); |
OLD | NEW |