tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_smilKeyTimes.xhtml (11195B)


      1 <html xmlns="http://www.w3.org/1999/xhtml">
      2 <head>
      3  <title>Test for SMIL keyTimes</title>
      4  <script src="/tests/SimpleTest/SimpleTest.js"></script>
      5  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
      6 </head>
      7 <body>
      8 <a target="_blank"
      9  href="https://bugzilla.mozilla.org/show_bug.cgi?id=557885">Mozilla Bug
     10  557885</a>
     11 <p id="display"></p>
     12 <div id="content">
     13 <svg id="svg" xmlns="http://www.w3.org/2000/svg" width="120px" height="120px">
     14  <circle cx="-100" cy="20" r="15" fill="blue" id="circle"/>
     15 </svg>
     16 </div>
     17 <pre id="test">
     18 <script class="testbody" type="text/javascript">
     19 <![CDATA[
     20 /** Test for SMIL keyTimes */
     21 
     22 var gSvg = document.getElementById("svg");
     23 SimpleTest.waitForExplicitFinish();
     24 
     25 function main()
     26 {
     27  gSvg.pauseAnimations();
     28 
     29  var testCases = Array();
     30 
     31  // Simple case
     32  testCases.push({
     33    'attr' : { 'values': '0; 50; 100',
     34               'keyTimes': '0; .8; 1' },
     35    'times': [ [ 4, 25 ],
     36               [ 8, 50 ],
     37               [ 9, 75 ],
     38               [ 10, 100 ] ]
     39  });
     40 
     41  // Parsing tests
     42  testCases.push(parseOk('  0 ; .8;1 ')); // extra whitespace
     43  testCases.push(parseNotOk(';0; .8; 1')); // leading semi-colon
     44  testCases.push(parseNotOk('; .8; 1')); // leading semi-colon
     45  testCases.push(parseOk('0; .8; 1;')); // trailing semi-colon
     46  testCases.push(parseNotOk('')); // empty string
     47  testCases.push(parseNotOk('  ')); // empty string
     48  testCases.push(parseNotOk('0; .8')); // too few values
     49  testCases.push(parseNotOk('0; .8; .9; 1')); // too many values
     50  testCases.push(parseNotOk('0; 1; .8')); // non-increasing
     51  testCases.push(parseNotOk('0; .8; .9')); // final value non-1 with
     52                                           // calcMode=linear
     53  testCases.push(parseOk('0; .8; .9', { 'calcMode': 'discrete' }));
     54  testCases.push(parseNotOk('0.01; .8; 1')); // first value not 0
     55  testCases.push(parseNotOk('0.01; .8; 1', { 'calcMode': 'discrete' }));
     56                                            // first value not 0
     57  testCases.push(parseNotOk('0; .8; 1.1')); // out of range
     58  testCases.push(parseNotOk('-0.1; .8; 1')); // out of range
     59 
     60 
     61  // 2 values
     62  testCases.push({
     63    'attr' : { 'values': '0; 50',
     64               'keyTimes': '0; 1' },
     65    'times': [ [ 6, 30 ] ]
     66  });
     67 
     68  // 1 value
     69  testCases.push({
     70    'attr' : { 'values': '50',
     71               'keyTimes': ' 0' },
     72    'times': [ [ 7, 50 ] ]
     73  });
     74 
     75  // 1 bad value
     76  testCases.push({
     77    'attr' : { 'values': '50',
     78               'keyTimes': '0.1' },
     79    'times': [ [ 0, -100 ] ]
     80  });
     81 
     82  // 1 value, calcMode=discrete
     83  testCases.push({
     84    'attr' : { 'values': '50',
     85               'calcMode': 'discrete',
     86               'keyTimes': ' 0' },
     87    'times': [ [ 7, 50 ] ]
     88  });
     89 
     90  // 1 bad value, calcMode=discrete
     91  testCases.push({
     92    'attr' : { 'values': '50',
     93               'calcMode': 'discrete',
     94               'keyTimes': '0.1' },
     95    'times': [ [ 0, -100 ] ]
     96  });
     97 
     98  // from-to
     99  testCases.push({
    100    'attr' : { 'from': '10',
    101               'to': '20',
    102               'keyTimes': '0.0; 1.0' },
    103    'times': [ [ 3.5, 13.5 ] ]
    104  });
    105 
    106  // from-to calcMode=discrete
    107  testCases.push({
    108    'attr' : { 'from': '10',
    109               'to': '20',
    110               'calcMode': 'discrete',
    111               'keyTimes': '0.0; 0.7' },
    112    'times': [ [ 0, 10 ],
    113               [ 6.9, 10 ],
    114               [ 7.0, 20 ],
    115               [ 10.0, 20 ],
    116               [ 11.0, 20 ] ]
    117  });
    118 
    119  // from-to calcMode=discrete one keyTime only
    120  testCases.push({
    121    'attr' : { 'values': '20',
    122               'calcMode': 'discrete',
    123               'keyTimes': '0' },
    124    'times': [ [ 0, 20 ],
    125               [ 6.9, 20 ],
    126               [ 7.0, 20 ],
    127               [ 10.0, 20 ],
    128               [ 11.0, 20 ] ]
    129  });
    130 
    131  // from-to calcMode=discrete one keyTime, mismatches no. values
    132  testCases.push({
    133    'attr' : { 'values': '10; 20',
    134               'calcMode': 'discrete',
    135               'keyTimes': '0' },
    136    'times': [ [ 0, -100 ] ]
    137  });
    138 
    139  // to
    140  testCases.push({
    141    'attr' : { 'to': '100',
    142               'keyTimes': '0.0; 1.0' },
    143    'times': [ [ 0, -100 ],
    144               [ 7, 40 ] ]
    145  });
    146 
    147  // to -- bad number of keyTimes (too many)
    148  testCases.push({
    149    'attr' : { 'to': '100',
    150               'keyTimes': '0.0; 0.5; 1.0' },
    151    'times': [ [ 2, -100 ] ]
    152  });
    153 
    154  // unfrozen to calcMode=discrete two keyTimes
    155  testCases.push({
    156    'attr' : { 'to': '100',
    157               'calcMode': 'discrete',
    158               'keyTimes': '0.0; 1.0',
    159               'fill': 'remove' },
    160    'times': [ [ 0, -100 ],
    161               [ 7, -100 ],
    162               [ 10, -100 ],
    163               [ 12, -100 ]]
    164  });
    165 
    166  // frozen to calcMode=discrete two keyTimes
    167  testCases.push({
    168    'attr' : { 'to': '100',
    169               'calcMode': 'discrete',
    170               'keyTimes': '0.0; 1.0' },
    171    'times': [ [ 0, -100 ],
    172               [ 7, -100 ],
    173               [ 10, 100 ],
    174               [ 12, 100 ] ]
    175  });
    176 
    177  // to calcMode=discrete -- bad number of keyTimes (one, expecting two)
    178  testCases.push({
    179    'attr' : { 'to': '100',
    180               'calcMode': 'discrete',
    181               'keyTimes': '0' },
    182    'times': [ [ 0, -100 ],
    183               [ 7, -100 ] ]
    184  });
    185 
    186  // values calcMode=discrete
    187  testCases.push({
    188    'attr' : { 'values': '0; 10; 20; 30',
    189               'calcMode': 'discrete',
    190               'keyTimes': '0;.2;.4;.6' },
    191    'times': [ [ 0, 0 ],
    192               [ 1.9, 0 ],
    193               [ 2, 10 ],
    194               [ 3.9, 10 ],
    195               [ 4.0, 20 ],
    196               [ 5.9, 20 ],
    197               [ 6.0, 30 ],
    198               [ 9.9, 30 ],
    199               [ 10.0, 30 ] ]
    200  });
    201 
    202  // The following two accumulate tests are from SMIL 3.0
    203  // (Note that this behaviour differs from that defined for SVG Tiny 1.2 which
    204  // specifically excludes the last value: "Note that in the case of discrete
    205  // animation, the frozen value that is used is the value of the animation just
    206  // before the end of the active duration.")
    207  // accumulate=none
    208  testCases.push({
    209    'attr' : { 'values': '0; 10; 20',
    210               'calcMode': 'discrete',
    211               'keyTimes': '0;.5;1',
    212               'fill': 'freeze',
    213               'repeatCount': '2',
    214               'accumulate': 'none' },
    215    'times': [ [ 0, 0 ],
    216               [ 5, 10 ],
    217               [ 10, 0 ],
    218               [ 15, 10 ],
    219               [ 20, 20 ],
    220               [ 25, 20 ] ]
    221  });
    222 
    223  // accumulate=sum
    224  testCases.push({
    225    'attr' : { 'values': '0; 10; 20',
    226               'calcMode': 'discrete',
    227               'keyTimes': '0;.5;1',
    228               'fill': 'freeze',
    229               'repeatCount': '2',
    230               'accumulate': 'sum' },
    231    'times': [ [ 0, 0 ],
    232               [ 5, 10 ],
    233               [ 10, 20 ],
    234               [ 15, 30 ],
    235               [ 20, 40 ],
    236               [ 25, 40 ] ]
    237  });
    238 
    239  // If the interpolation mode is paced, the keyTimes attribute is ignored.
    240  testCases.push({
    241    'attr' : { 'values': '0; 10; 20',
    242               'calcMode': 'paced',
    243               'keyTimes': '0;.2;1' },
    244    'times': [ [ 0, 0 ],
    245               [ 2, 4 ],
    246               [ 5, 10 ] ]
    247  });
    248 
    249  // SMIL 3 has:
    250  //   If the simple duration is indefinite and the interpolation mode is
    251  //   linear or spline, any keyTimes specification will be ignored.
    252  // However, since keyTimes represent "a proportional offset into the simple
    253  // duration of the animation element" surely discrete animation too cannot use
    254  // keyTimes when the simple duration is indefinite. Hence SVGT 1.2 is surely
    255  // more correct when it has:
    256  //   If the simple duration is indefinite, any 'keyTimes' specification will
    257  //   be ignored.
    258  // (linear)
    259  testCases.push({
    260    'attr' : { 'values': '0; 10; 20',
    261               'dur': 'indefinite',
    262               'keyTimes': '0;.2;1' },
    263    'times': [ [ 0, 0 ],
    264               [ 5, 0 ] ]
    265  });
    266  // (spline)
    267  testCases.push({
    268    'attr' : { 'values': '0; 10; 20',
    269               'dur': 'indefinite',
    270               'calcMode': 'spline',
    271               'keyTimes': '0;.2;1',
    272               'keySplines': '0 0 1 1; 0 0 1 1' },
    273    'times': [ [ 0, 0 ],
    274               [ 5, 0 ] ]
    275  });
    276  // (discrete)
    277  testCases.push({
    278    'attr' : { 'values': '0; 10; 20',
    279               'dur': 'indefinite',
    280               'calcMode': 'discrete',
    281               'keyTimes': '0;.2;1' },
    282    'times': [ [ 0, 0 ],
    283               [ 5, 0 ] ]
    284  });
    285 
    286  for (var i = 0; i < testCases.length; i++) {
    287    gSvg.setCurrentTime(0);
    288    var test = testCases[i];
    289 
    290    // Create animation elements
    291    var anim = createAnim(test.attr);
    292 
    293    // Run samples
    294    for (var j = 0; j < test.times.length; j++) {
    295      var times = test.times[j];
    296      gSvg.setCurrentTime(times[0]);
    297      checkSample(anim, times[1], times[0], i);
    298    }
    299 
    300    anim.remove();
    301  }
    302 
    303  // fallback to discrete for non-additive animation
    304  var attr = { 'values': 'butt; round; square',
    305               'attributeName': 'stroke-linecap',
    306               'calcMode': 'linear',
    307               'keyTimes': '0;.2;1',
    308               'fill': 'remove' };
    309  var anim = createAnim(attr);
    310  var samples = [ [ 0, 'butt' ],
    311                  [ 1.9, 'butt' ],
    312                  [ 2.0, 'round' ],
    313                  [ 9.9, 'round' ],
    314                  [ 10, 'butt' ] // fill=remove so we'll never set it to square
    315                ];
    316  for (var i = 0; i < samples.length; i++) {
    317    var sample = samples[i];
    318    gSvg.setCurrentTime(sample[0]);
    319    checkLineCapSample(anim, sample[1], sample[0],
    320      "[non-interpolatable fallback]");
    321  }
    322  anim.remove();
    323 
    324  SimpleTest.finish();
    325 }
    326 
    327 function parseOk(str, extra)
    328 {
    329  var attr = { 'values': '0; 50; 100',
    330               'keyTimes': str };
    331  if (typeof(extra) == "object") {
    332    for (name in extra) {
    333      attr[name] = extra[name];
    334    }
    335  }
    336  return {
    337    'attr' : attr,
    338    'times': [ [ 0, 0 ] ]
    339  };
    340 }
    341 
    342 function parseNotOk(str, extra)
    343 {
    344  var result = parseOk(str, extra);
    345  result.times = [ [ 0, -100 ] ];
    346  return result;
    347 }
    348 
    349 function createAnim(attr)
    350 {
    351  const svgns = "http://www.w3.org/2000/svg";
    352  var anim = document.createElementNS(svgns, 'animate');
    353  anim.setAttribute('attributeName','cx');
    354  anim.setAttribute('dur','10s');
    355  anim.setAttribute('begin','0s');
    356  anim.setAttribute('fill','freeze');
    357  for (name in attr) {
    358    anim.setAttribute(name, attr[name]);
    359  }
    360  return document.getElementById('circle').appendChild(anim);
    361 }
    362 
    363 function checkSample(anim, expectedValue, sampleTime, caseNum)
    364 {
    365  var msg = "Test case " + caseNum +
    366    " (keyTimes: '" + anim.getAttribute('keyTimes') + "'" +
    367    " calcMode: " + anim.getAttribute('calcMode') + "), " +
    368    "t=" + sampleTime +
    369    ": Unexpected sample value:";
    370  is(anim.targetElement.cx.animVal.value, expectedValue, msg);
    371 }
    372 
    373 function checkLineCapSample(anim, expectedValue, sampleTime, caseDescr)
    374 {
    375  var msg = "Test case " + caseDescr +
    376    " (keyTimes: '" + anim.getAttribute('keyTimes') + "'" +
    377    " calcMode: " + anim.getAttribute('calcMode') + "), " +
    378    "t=" + sampleTime +
    379    ": Unexpected sample value:";
    380  var actualValue =
    381    window.getComputedStyle(anim.targetElement).
    382    getPropertyValue('stroke-linecap');
    383  is(actualValue, expectedValue, msg);
    384 }
    385 
    386 window.addEventListener("load", main);
    387 ]]>
    388 </script>
    389 </pre>
    390 </body>
    391 </html>