diff options
Diffstat (limited to 'dom/smil/test/test_smilKeyTimes.xhtml')
-rw-r--r-- | dom/smil/test/test_smilKeyTimes.xhtml | 391 |
1 files changed, 391 insertions, 0 deletions
diff --git a/dom/smil/test/test_smilKeyTimes.xhtml b/dom/smil/test/test_smilKeyTimes.xhtml new file mode 100644 index 000000000..85266ed19 --- /dev/null +++ b/dom/smil/test/test_smilKeyTimes.xhtml @@ -0,0 +1,391 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> + <title>Test for SMIL keyTimes</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=557885">Mozilla Bug + 557885</a> +<p id="display"></p> +<div id="content"> +<svg id="svg" xmlns="http://www.w3.org/2000/svg" width="120px" height="120px"> + <circle cx="-100" cy="20" r="15" fill="blue" id="circle"/> +</svg> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> +<![CDATA[ +/** Test for SMIL keyTimes **/ + +var gSvg = document.getElementById("svg"); +SimpleTest.waitForExplicitFinish(); + +function main() +{ + gSvg.pauseAnimations(); + + var testCases = Array(); + + // Simple case + testCases.push({ + 'attr' : { 'values': '0; 50; 100', + 'keyTimes': '0; .8; 1' }, + 'times': [ [ 4, 25 ], + [ 8, 50 ], + [ 9, 75 ], + [ 10, 100 ] ] + }); + + // Parsing tests + testCases.push(parseOk(' 0 ; .8;1 ')); // extra whitespace + testCases.push(parseNotOk(';0; .8; 1')); // leading semi-colon + testCases.push(parseNotOk('; .8; 1')); // leading semi-colon + testCases.push(parseOk('0; .8; 1;')); // trailing semi-colon + testCases.push(parseNotOk('')); // empty string + testCases.push(parseNotOk(' ')); // empty string + testCases.push(parseNotOk('0; .8')); // too few values + testCases.push(parseNotOk('0; .8; .9; 1')); // too many values + testCases.push(parseNotOk('0; 1; .8')); // non-increasing + testCases.push(parseNotOk('0; .8; .9')); // final value non-1 with + // calcMode=linear + testCases.push(parseOk('0; .8; .9', { 'calcMode': 'discrete' })); + testCases.push(parseNotOk('0.01; .8; 1')); // first value not 0 + testCases.push(parseNotOk('0.01; .8; 1', { 'calcMode': 'discrete' })); + // first value not 0 + testCases.push(parseNotOk('0; .8; 1.1')); // out of range + testCases.push(parseNotOk('-0.1; .8; 1')); // out of range + + + // 2 values + testCases.push({ + 'attr' : { 'values': '0; 50', + 'keyTimes': '0; 1' }, + 'times': [ [ 6, 30 ] ] + }); + + // 1 value + testCases.push({ + 'attr' : { 'values': '50', + 'keyTimes': ' 0' }, + 'times': [ [ 7, 50 ] ] + }); + + // 1 bad value + testCases.push({ + 'attr' : { 'values': '50', + 'keyTimes': '0.1' }, + 'times': [ [ 0, -100 ] ] + }); + + // 1 value, calcMode=discrete + testCases.push({ + 'attr' : { 'values': '50', + 'calcMode': 'discrete', + 'keyTimes': ' 0' }, + 'times': [ [ 7, 50 ] ] + }); + + // 1 bad value, calcMode=discrete + testCases.push({ + 'attr' : { 'values': '50', + 'calcMode': 'discrete', + 'keyTimes': '0.1' }, + 'times': [ [ 0, -100 ] ] + }); + + // from-to + testCases.push({ + 'attr' : { 'from': '10', + 'to': '20', + 'keyTimes': '0.0; 1.0' }, + 'times': [ [ 3.5, 13.5 ] ] + }); + + // from-to calcMode=discrete + testCases.push({ + 'attr' : { 'from': '10', + 'to': '20', + 'calcMode': 'discrete', + 'keyTimes': '0.0; 0.7' }, + 'times': [ [ 0, 10 ], + [ 6.9, 10 ], + [ 7.0, 20 ], + [ 10.0, 20 ], + [ 11.0, 20 ] ] + }); + + // from-to calcMode=discrete one keyTime only + testCases.push({ + 'attr' : { 'values': '20', + 'calcMode': 'discrete', + 'keyTimes': '0' }, + 'times': [ [ 0, 20 ], + [ 6.9, 20 ], + [ 7.0, 20 ], + [ 10.0, 20 ], + [ 11.0, 20 ] ] + }); + + // from-to calcMode=discrete one keyTime, mismatches no. values + testCases.push({ + 'attr' : { 'values': '10; 20', + 'calcMode': 'discrete', + 'keyTimes': '0' }, + 'times': [ [ 0, -100 ] ] + }); + + // to + testCases.push({ + 'attr' : { 'to': '100', + 'keyTimes': '0.0; 1.0' }, + 'times': [ [ 0, -100 ], + [ 7, 40 ] ] + }); + + // to -- bad number of keyTimes (too many) + testCases.push({ + 'attr' : { 'to': '100', + 'keyTimes': '0.0; 0.5; 1.0' }, + 'times': [ [ 2, -100 ] ] + }); + + // unfrozen to calcMode=discrete two keyTimes + testCases.push({ + 'attr' : { 'to': '100', + 'calcMode': 'discrete', + 'keyTimes': '0.0; 1.0', + 'fill': 'remove' }, + 'times': [ [ 0, -100 ], + [ 7, -100 ], + [ 10, -100 ], + [ 12, -100 ]] + }); + + // frozen to calcMode=discrete two keyTimes + testCases.push({ + 'attr' : { 'to': '100', + 'calcMode': 'discrete', + 'keyTimes': '0.0; 1.0' }, + 'times': [ [ 0, -100 ], + [ 7, -100 ], + [ 10, 100 ], + [ 12, 100 ] ] + }); + + // to calcMode=discrete -- bad number of keyTimes (one, expecting two) + testCases.push({ + 'attr' : { 'to': '100', + 'calcMode': 'discrete', + 'keyTimes': '0' }, + 'times': [ [ 0, -100 ], + [ 7, -100 ] ] + }); + + // values calcMode=discrete + testCases.push({ + 'attr' : { 'values': '0; 10; 20; 30', + 'calcMode': 'discrete', + 'keyTimes': '0;.2;.4;.6' }, + 'times': [ [ 0, 0 ], + [ 1.9, 0 ], + [ 2, 10 ], + [ 3.9, 10 ], + [ 4.0, 20 ], + [ 5.9, 20 ], + [ 6.0, 30 ], + [ 9.9, 30 ], + [ 10.0, 30 ] ] + }); + + // The following two accumulate tests are from SMIL 3.0 + // (Note that this behaviour differs from that defined for SVG Tiny 1.2 which + // specifically excludes the last value: "Note that in the case of discrete + // animation, the frozen value that is used is the value of the animation just + // before the end of the active duration.") + // accumulate=none + testCases.push({ + 'attr' : { 'values': '0; 10; 20', + 'calcMode': 'discrete', + 'keyTimes': '0;.5;1', + 'fill': 'freeze', + 'repeatCount': '2', + 'accumulate': 'none' }, + 'times': [ [ 0, 0 ], + [ 5, 10 ], + [ 10, 0 ], + [ 15, 10 ], + [ 20, 20 ], + [ 25, 20 ] ] + }); + + // accumulate=sum + testCases.push({ + 'attr' : { 'values': '0; 10; 20', + 'calcMode': 'discrete', + 'keyTimes': '0;.5;1', + 'fill': 'freeze', + 'repeatCount': '2', + 'accumulate': 'sum' }, + 'times': [ [ 0, 0 ], + [ 5, 10 ], + [ 10, 20 ], + [ 15, 30 ], + [ 20, 40 ], + [ 25, 40 ] ] + }); + + // If the interpolation mode is paced, the keyTimes attribute is ignored. + testCases.push({ + 'attr' : { 'values': '0; 10; 20', + 'calcMode': 'paced', + 'keyTimes': '0;.2;1' }, + 'times': [ [ 0, 0 ], + [ 2, 4 ], + [ 5, 10 ] ] + }); + + // SMIL 3 has: + // If the simple duration is indefinite and the interpolation mode is + // linear or spline, any keyTimes specification will be ignored. + // However, since keyTimes represent "a proportional offset into the simple + // duration of the animation element" surely discrete animation too cannot use + // keyTimes when the simple duration is indefinite. Hence SVGT 1.2 is surely + // more correct when it has: + // If the simple duration is indefinite, any 'keyTimes' specification will + // be ignored. + // (linear) + testCases.push({ + 'attr' : { 'values': '0; 10; 20', + 'dur': 'indefinite', + 'keyTimes': '0;.2;1' }, + 'times': [ [ 0, 0 ], + [ 5, 0 ] ] + }); + // (spline) + testCases.push({ + 'attr' : { 'values': '0; 10; 20', + 'dur': 'indefinite', + 'calcMode': 'spline', + 'keyTimes': '0;.2;1', + 'keySplines': '0 0 1 1; 0 0 1 1' }, + 'times': [ [ 0, 0 ], + [ 5, 0 ] ] + }); + // (discrete) + testCases.push({ + 'attr' : { 'values': '0; 10; 20', + 'dur': 'indefinite', + 'calcMode': 'discrete', + 'keyTimes': '0;.2;1' }, + 'times': [ [ 0, 0 ], + [ 5, 0 ] ] + }); + + for (var i = 0; i < testCases.length; i++) { + gSvg.setCurrentTime(0); + var test = testCases[i]; + + // Create animation elements + var anim = createAnim(test.attr); + + // Run samples + for (var j = 0; j < test.times.length; j++) { + var times = test.times[j]; + gSvg.setCurrentTime(times[0]); + checkSample(anim, times[1], times[0], i); + } + + anim.parentNode.removeChild(anim); + } + + // fallback to discrete for non-additive animation + var attr = { 'values': 'butt; round; square', + 'attributeName': 'stroke-linecap', + 'calcMode': 'linear', + 'keyTimes': '0;.2;1', + 'fill': 'remove' }; + var anim = createAnim(attr); + var samples = [ [ 0, 'butt' ], + [ 1.9, 'butt' ], + [ 2.0, 'round' ], + [ 9.9, 'round' ], + [ 10, 'butt' ] // fill=remove so we'll never set it to square + ]; + for (var i = 0; i < samples.length; i++) { + var sample = samples[i]; + gSvg.setCurrentTime(sample[0]); + checkLineCapSample(anim, sample[1], sample[0], + "[non-interpolatable fallback]"); + } + anim.parentNode.removeChild(anim); + + SimpleTest.finish(); +} + +function parseOk(str, extra) +{ + var attr = { 'values': '0; 50; 100', + 'keyTimes': str }; + if (typeof(extra) == "object") { + for (name in extra) { + attr[name] = extra[name]; + } + } + return { + 'attr' : attr, + 'times': [ [ 0, 0 ] ] + }; +} + +function parseNotOk(str, extra) +{ + var result = parseOk(str, extra); + result.times = [ [ 0, -100 ] ]; + return result; +} + +function createAnim(attr) +{ + const svgns = "http://www.w3.org/2000/svg"; + var anim = document.createElementNS(svgns, 'animate'); + anim.setAttribute('attributeName','cx'); + anim.setAttribute('dur','10s'); + anim.setAttribute('begin','0s'); + anim.setAttribute('fill','freeze'); + for (name in attr) { + anim.setAttribute(name, attr[name]); + } + return document.getElementById('circle').appendChild(anim); +} + +function checkSample(anim, expectedValue, sampleTime, caseNum) +{ + var msg = "Test case " + caseNum + + " (keyTimes: '" + anim.getAttribute('keyTimes') + "'" + + " calcMode: " + anim.getAttribute('calcMode') + "), " + + "t=" + sampleTime + + ": Unexpected sample value:"; + is(anim.targetElement.cx.animVal.value, expectedValue, msg); +} + +function checkLineCapSample(anim, expectedValue, sampleTime, caseDescr) +{ + var msg = "Test case " + caseDescr + + " (keyTimes: '" + anim.getAttribute('keyTimes') + "'" + + " calcMode: " + anim.getAttribute('calcMode') + "), " + + "t=" + sampleTime + + ": Unexpected sample value:"; + var actualValue = + window.getComputedStyle(anim.targetElement, null). + getPropertyValue('stroke-linecap'); + is(actualValue, expectedValue, msg); +} + +window.addEventListener("load", main, false); +]]> +</script> +</pre> +</body> +</html> |