1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/smil/test/test_smilKeyTimes.xhtml Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,391 @@ 1.4 +<html xmlns="http://www.w3.org/1999/xhtml"> 1.5 +<head> 1.6 + <title>Test for SMIL keyTimes</title> 1.7 + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> 1.8 + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> 1.9 +</head> 1.10 +<body> 1.11 +<a target="_blank" 1.12 + href="https://bugzilla.mozilla.org/show_bug.cgi?id=557885">Mozilla Bug 1.13 + 557885</a> 1.14 +<p id="display"></p> 1.15 +<div id="content" style="display: none"> 1.16 +<svg id="svg" xmlns="http://www.w3.org/2000/svg" width="120px" height="120px"> 1.17 + <circle cx="-100" cy="20" r="15" fill="blue" id="circle"/> 1.18 +</svg> 1.19 +</div> 1.20 +<pre id="test"> 1.21 +<script class="testbody" type="text/javascript"> 1.22 +<![CDATA[ 1.23 +/** Test for SMIL keyTimes **/ 1.24 + 1.25 +var gSvg = document.getElementById("svg"); 1.26 +SimpleTest.waitForExplicitFinish(); 1.27 + 1.28 +function main() 1.29 +{ 1.30 + gSvg.pauseAnimations(); 1.31 + 1.32 + var testCases = Array(); 1.33 + 1.34 + // Simple case 1.35 + testCases.push({ 1.36 + 'attr' : { 'values': '0; 50; 100', 1.37 + 'keyTimes': '0; .8; 1' }, 1.38 + 'times': [ [ 4, 25 ], 1.39 + [ 8, 50 ], 1.40 + [ 9, 75 ], 1.41 + [ 10, 100 ] ] 1.42 + }); 1.43 + 1.44 + // Parsing tests 1.45 + testCases.push(parseOk(' 0 ; .8;1 ')); // extra whitespace 1.46 + testCases.push(parseNotOk(';0; .8; 1')); // leading semi-colon 1.47 + testCases.push(parseNotOk('; .8; 1')); // leading semi-colon 1.48 + testCases.push(parseOk('0; .8; 1;')); // trailing semi-colon 1.49 + testCases.push(parseNotOk('')); // empty string 1.50 + testCases.push(parseNotOk(' ')); // empty string 1.51 + testCases.push(parseNotOk('0; .8')); // too few values 1.52 + testCases.push(parseNotOk('0; .8; .9; 1')); // too many values 1.53 + testCases.push(parseNotOk('0; 1; .8')); // non-increasing 1.54 + testCases.push(parseNotOk('0; .8; .9')); // final value non-1 with 1.55 + // calcMode=linear 1.56 + testCases.push(parseOk('0; .8; .9', { 'calcMode': 'discrete' })); 1.57 + testCases.push(parseNotOk('0.01; .8; 1')); // first value not 0 1.58 + testCases.push(parseNotOk('0.01; .8; 1', { 'calcMode': 'discrete' })); 1.59 + // first value not 0 1.60 + testCases.push(parseNotOk('0; .8; 1.1')); // out of range 1.61 + testCases.push(parseNotOk('-0.1; .8; 1')); // out of range 1.62 + 1.63 + 1.64 + // 2 values 1.65 + testCases.push({ 1.66 + 'attr' : { 'values': '0; 50', 1.67 + 'keyTimes': '0; 1' }, 1.68 + 'times': [ [ 6, 30 ] ] 1.69 + }); 1.70 + 1.71 + // 1 value 1.72 + testCases.push({ 1.73 + 'attr' : { 'values': '50', 1.74 + 'keyTimes': ' 0' }, 1.75 + 'times': [ [ 7, 50 ] ] 1.76 + }); 1.77 + 1.78 + // 1 bad value 1.79 + testCases.push({ 1.80 + 'attr' : { 'values': '50', 1.81 + 'keyTimes': '0.1' }, 1.82 + 'times': [ [ 0, -100 ] ] 1.83 + }); 1.84 + 1.85 + // 1 value, calcMode=discrete 1.86 + testCases.push({ 1.87 + 'attr' : { 'values': '50', 1.88 + 'calcMode': 'discrete', 1.89 + 'keyTimes': ' 0' }, 1.90 + 'times': [ [ 7, 50 ] ] 1.91 + }); 1.92 + 1.93 + // 1 bad value, calcMode=discrete 1.94 + testCases.push({ 1.95 + 'attr' : { 'values': '50', 1.96 + 'calcMode': 'discrete', 1.97 + 'keyTimes': '0.1' }, 1.98 + 'times': [ [ 0, -100 ] ] 1.99 + }); 1.100 + 1.101 + // from-to 1.102 + testCases.push({ 1.103 + 'attr' : { 'from': '10', 1.104 + 'to': '20', 1.105 + 'keyTimes': '0.0; 1.0' }, 1.106 + 'times': [ [ 3.5, 13.5 ] ] 1.107 + }); 1.108 + 1.109 + // from-to calcMode=discrete 1.110 + testCases.push({ 1.111 + 'attr' : { 'from': '10', 1.112 + 'to': '20', 1.113 + 'calcMode': 'discrete', 1.114 + 'keyTimes': '0.0; 0.7' }, 1.115 + 'times': [ [ 0, 10 ], 1.116 + [ 6.9, 10 ], 1.117 + [ 7.0, 20 ], 1.118 + [ 10.0, 20 ], 1.119 + [ 11.0, 20 ] ] 1.120 + }); 1.121 + 1.122 + // from-to calcMode=discrete one keyTime only 1.123 + testCases.push({ 1.124 + 'attr' : { 'values': '20', 1.125 + 'calcMode': 'discrete', 1.126 + 'keyTimes': '0' }, 1.127 + 'times': [ [ 0, 20 ], 1.128 + [ 6.9, 20 ], 1.129 + [ 7.0, 20 ], 1.130 + [ 10.0, 20 ], 1.131 + [ 11.0, 20 ] ] 1.132 + }); 1.133 + 1.134 + // from-to calcMode=discrete one keyTime, mismatches no. values 1.135 + testCases.push({ 1.136 + 'attr' : { 'values': '10; 20', 1.137 + 'calcMode': 'discrete', 1.138 + 'keyTimes': '0' }, 1.139 + 'times': [ [ 0, -100 ] ] 1.140 + }); 1.141 + 1.142 + // to 1.143 + testCases.push({ 1.144 + 'attr' : { 'to': '100', 1.145 + 'keyTimes': '0.0; 1.0' }, 1.146 + 'times': [ [ 0, -100 ], 1.147 + [ 7, 40 ] ] 1.148 + }); 1.149 + 1.150 + // to -- bad number of keyTimes (too many) 1.151 + testCases.push({ 1.152 + 'attr' : { 'to': '100', 1.153 + 'keyTimes': '0.0; 0.5; 1.0' }, 1.154 + 'times': [ [ 2, -100 ] ] 1.155 + }); 1.156 + 1.157 + // unfrozen to calcMode=discrete two keyTimes 1.158 + testCases.push({ 1.159 + 'attr' : { 'to': '100', 1.160 + 'calcMode': 'discrete', 1.161 + 'keyTimes': '0.0; 1.0', 1.162 + 'fill': 'remove' }, 1.163 + 'times': [ [ 0, -100 ], 1.164 + [ 7, -100 ], 1.165 + [ 10, -100 ], 1.166 + [ 12, -100 ]] 1.167 + }); 1.168 + 1.169 + // frozen to calcMode=discrete two keyTimes 1.170 + testCases.push({ 1.171 + 'attr' : { 'to': '100', 1.172 + 'calcMode': 'discrete', 1.173 + 'keyTimes': '0.0; 1.0' }, 1.174 + 'times': [ [ 0, -100 ], 1.175 + [ 7, -100 ], 1.176 + [ 10, 100 ], 1.177 + [ 12, 100 ] ] 1.178 + }); 1.179 + 1.180 + // to calcMode=discrete -- bad number of keyTimes (one, expecting two) 1.181 + testCases.push({ 1.182 + 'attr' : { 'to': '100', 1.183 + 'calcMode': 'discrete', 1.184 + 'keyTimes': '0' }, 1.185 + 'times': [ [ 0, -100 ], 1.186 + [ 7, -100 ] ] 1.187 + }); 1.188 + 1.189 + // values calcMode=discrete 1.190 + testCases.push({ 1.191 + 'attr' : { 'values': '0; 10; 20; 30', 1.192 + 'calcMode': 'discrete', 1.193 + 'keyTimes': '0;.2;.4;.6' }, 1.194 + 'times': [ [ 0, 0 ], 1.195 + [ 1.9, 0 ], 1.196 + [ 2, 10 ], 1.197 + [ 3.9, 10 ], 1.198 + [ 4.0, 20 ], 1.199 + [ 5.9, 20 ], 1.200 + [ 6.0, 30 ], 1.201 + [ 9.9, 30 ], 1.202 + [ 10.0, 30 ] ] 1.203 + }); 1.204 + 1.205 + // The following two accumulate tests are from SMIL 3.0 1.206 + // (Note that this behaviour differs from that defined for SVG Tiny 1.2 which 1.207 + // specifically excludes the last value: "Note that in the case of discrete 1.208 + // animation, the frozen value that is used is the value of the animation just 1.209 + // before the end of the active duration.") 1.210 + // accumulate=none 1.211 + testCases.push({ 1.212 + 'attr' : { 'values': '0; 10; 20', 1.213 + 'calcMode': 'discrete', 1.214 + 'keyTimes': '0;.5;1', 1.215 + 'fill': 'freeze', 1.216 + 'repeatCount': '2', 1.217 + 'accumulate': 'none' }, 1.218 + 'times': [ [ 0, 0 ], 1.219 + [ 5, 10 ], 1.220 + [ 10, 0 ], 1.221 + [ 15, 10 ], 1.222 + [ 20, 20 ], 1.223 + [ 25, 20 ] ] 1.224 + }); 1.225 + 1.226 + // accumulate=sum 1.227 + testCases.push({ 1.228 + 'attr' : { 'values': '0; 10; 20', 1.229 + 'calcMode': 'discrete', 1.230 + 'keyTimes': '0;.5;1', 1.231 + 'fill': 'freeze', 1.232 + 'repeatCount': '2', 1.233 + 'accumulate': 'sum' }, 1.234 + 'times': [ [ 0, 0 ], 1.235 + [ 5, 10 ], 1.236 + [ 10, 20 ], 1.237 + [ 15, 30 ], 1.238 + [ 20, 40 ], 1.239 + [ 25, 40 ] ] 1.240 + }); 1.241 + 1.242 + // If the interpolation mode is paced, the keyTimes attribute is ignored. 1.243 + testCases.push({ 1.244 + 'attr' : { 'values': '0; 10; 20', 1.245 + 'calcMode': 'paced', 1.246 + 'keyTimes': '0;.2;1' }, 1.247 + 'times': [ [ 0, 0 ], 1.248 + [ 2, 4 ], 1.249 + [ 5, 10 ] ] 1.250 + }); 1.251 + 1.252 + // SMIL 3 has: 1.253 + // If the simple duration is indefinite and the interpolation mode is 1.254 + // linear or spline, any keyTimes specification will be ignored. 1.255 + // However, since keyTimes represent "a proportional offset into the simple 1.256 + // duration of the animation element" surely discrete animation too cannot use 1.257 + // keyTimes when the simple duration is indefinite. Hence SVGT 1.2 is surely 1.258 + // more correct when it has: 1.259 + // If the simple duration is indefinite, any 'keyTimes' specification will 1.260 + // be ignored. 1.261 + // (linear) 1.262 + testCases.push({ 1.263 + 'attr' : { 'values': '0; 10; 20', 1.264 + 'dur': 'indefinite', 1.265 + 'keyTimes': '0;.2;1' }, 1.266 + 'times': [ [ 0, 0 ], 1.267 + [ 5, 0 ] ] 1.268 + }); 1.269 + // (spline) 1.270 + testCases.push({ 1.271 + 'attr' : { 'values': '0; 10; 20', 1.272 + 'dur': 'indefinite', 1.273 + 'calcMode': 'spline', 1.274 + 'keyTimes': '0;.2;1', 1.275 + 'keySplines': '0 0 1 1; 0 0 1 1' }, 1.276 + 'times': [ [ 0, 0 ], 1.277 + [ 5, 0 ] ] 1.278 + }); 1.279 + // (discrete) 1.280 + testCases.push({ 1.281 + 'attr' : { 'values': '0; 10; 20', 1.282 + 'dur': 'indefinite', 1.283 + 'calcMode': 'discrete', 1.284 + 'keyTimes': '0;.2;1' }, 1.285 + 'times': [ [ 0, 0 ], 1.286 + [ 5, 0 ] ] 1.287 + }); 1.288 + 1.289 + for (var i = 0; i < testCases.length; i++) { 1.290 + gSvg.setCurrentTime(0); 1.291 + var test = testCases[i]; 1.292 + 1.293 + // Create animation elements 1.294 + var anim = createAnim(test.attr); 1.295 + 1.296 + // Run samples 1.297 + for (var j = 0; j < test.times.length; j++) { 1.298 + var times = test.times[j]; 1.299 + gSvg.setCurrentTime(times[0]); 1.300 + checkSample(anim, times[1], times[0], i); 1.301 + } 1.302 + 1.303 + anim.parentNode.removeChild(anim); 1.304 + } 1.305 + 1.306 + // fallback to discrete for non-additive animation 1.307 + var attr = { 'values': 'butt; round; square', 1.308 + 'attributeName': 'stroke-linecap', 1.309 + 'calcMode': 'linear', 1.310 + 'keyTimes': '0;.2;1', 1.311 + 'fill': 'remove' }; 1.312 + var anim = createAnim(attr); 1.313 + var samples = [ [ 0, 'butt' ], 1.314 + [ 1.9, 'butt' ], 1.315 + [ 2.0, 'round' ], 1.316 + [ 9.9, 'round' ], 1.317 + [ 10, 'butt' ] // fill=remove so we'll never set it to square 1.318 + ]; 1.319 + for (var i = 0; i < samples.length; i++) { 1.320 + var sample = samples[i]; 1.321 + gSvg.setCurrentTime(sample[0]); 1.322 + checkLineCapSample(anim, sample[1], sample[0], 1.323 + "[non-interpolatable fallback]"); 1.324 + } 1.325 + anim.parentNode.removeChild(anim); 1.326 + 1.327 + SimpleTest.finish(); 1.328 +} 1.329 + 1.330 +function parseOk(str, extra) 1.331 +{ 1.332 + var attr = { 'values': '0; 50; 100', 1.333 + 'keyTimes': str }; 1.334 + if (typeof(extra) == "object") { 1.335 + for (name in extra) { 1.336 + attr[name] = extra[name]; 1.337 + } 1.338 + } 1.339 + return { 1.340 + 'attr' : attr, 1.341 + 'times': [ [ 0, 0 ] ] 1.342 + }; 1.343 +} 1.344 + 1.345 +function parseNotOk(str, extra) 1.346 +{ 1.347 + var result = parseOk(str, extra); 1.348 + result.times = [ [ 0, -100 ] ]; 1.349 + return result; 1.350 +} 1.351 + 1.352 +function createAnim(attr) 1.353 +{ 1.354 + const svgns = "http://www.w3.org/2000/svg"; 1.355 + var anim = document.createElementNS(svgns, 'animate'); 1.356 + anim.setAttribute('attributeName','cx'); 1.357 + anim.setAttribute('dur','10s'); 1.358 + anim.setAttribute('begin','0s'); 1.359 + anim.setAttribute('fill','freeze'); 1.360 + for (name in attr) { 1.361 + anim.setAttribute(name, attr[name]); 1.362 + } 1.363 + return document.getElementById('circle').appendChild(anim); 1.364 +} 1.365 + 1.366 +function checkSample(anim, expectedValue, sampleTime, caseNum) 1.367 +{ 1.368 + var msg = "Test case " + caseNum + 1.369 + " (keyTimes: '" + anim.getAttribute('keyTimes') + "'" + 1.370 + " calcMode: " + anim.getAttribute('calcMode') + "), " + 1.371 + "t=" + sampleTime + 1.372 + ": Unexpected sample value:"; 1.373 + is(anim.targetElement.cx.animVal.value, expectedValue, msg); 1.374 +} 1.375 + 1.376 +function checkLineCapSample(anim, expectedValue, sampleTime, caseDescr) 1.377 +{ 1.378 + var msg = "Test case " + caseDescr + 1.379 + " (keyTimes: '" + anim.getAttribute('keyTimes') + "'" + 1.380 + " calcMode: " + anim.getAttribute('calcMode') + "), " + 1.381 + "t=" + sampleTime + 1.382 + ": Unexpected sample value:"; 1.383 + var actualValue = 1.384 + window.getComputedStyle(anim.targetElement, null). 1.385 + getPropertyValue('stroke-linecap'); 1.386 + is(actualValue, expectedValue, msg); 1.387 +} 1.388 + 1.389 +window.addEventListener("load", main, false); 1.390 +]]> 1.391 +</script> 1.392 +</pre> 1.393 +</body> 1.394 +</html>