tor-browser

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

path-objects.yaml (104855B)


      1 - name: 2d.path.initial
      2  #mozilla: { bug: TODO }
      3  code: |
      4    ctx.fillStyle = '#0f0';
      5    ctx.fillRect(0, 0, 100, 50);
      6    ctx.closePath();
      7    ctx.fillStyle = '#f00';
      8    ctx.fill();
      9    @assert pixel 50,25 == 0,255,0,255;
     10  expected: green
     11 
     12 - name: 2d.path.beginPath
     13  code: |
     14    ctx.fillStyle = '#0f0';
     15    ctx.fillRect(0, 0, 100, 50);
     16    ctx.rect(0, 0, 100, 50);
     17    ctx.beginPath();
     18    ctx.fillStyle = '#f00';
     19    ctx.fill();
     20    @assert pixel 50,25 == 0,255,0,255;
     21  expected: green
     22 
     23 - name: 2d.path.moveTo.basic
     24  code: |
     25    ctx.fillStyle = '#f00';
     26    ctx.fillRect(0, 0, 100, 50);
     27    ctx.rect(0, 0, 10, 50);
     28    ctx.moveTo(100, 0);
     29    ctx.lineTo(10, 0);
     30    ctx.lineTo(10, 50);
     31    ctx.lineTo(100, 50);
     32    ctx.fillStyle = '#0f0';
     33    ctx.fill();
     34    @assert pixel 90,25 == 0,255,0,255;
     35  expected: green
     36 
     37 - name: 2d.path.moveTo.newsubpath
     38  code: |
     39    ctx.fillStyle = '#0f0';
     40    ctx.fillRect(0, 0, 100, 50);
     41    ctx.beginPath();
     42    ctx.moveTo(0, 0);
     43    ctx.moveTo(100, 0);
     44    ctx.moveTo(100, 50);
     45    ctx.moveTo(0, 50);
     46    ctx.fillStyle = '#f00';
     47    ctx.fill();
     48    @assert pixel 50,25 == 0,255,0,255;
     49  expected: green
     50 
     51 - name: 2d.path.moveTo.multiple
     52  code: |
     53    ctx.fillStyle = '#f00';
     54    ctx.fillRect(0, 0, 100, 50);
     55    ctx.moveTo(0, 25);
     56    ctx.moveTo(100, 25);
     57    ctx.moveTo(0, 25);
     58    ctx.lineTo(100, 25);
     59    ctx.strokeStyle = '#0f0';
     60    ctx.lineWidth = 50;
     61    ctx.stroke();
     62    @assert pixel 50,25 == 0,255,0,255;
     63  expected: green
     64 
     65 - name: 2d.path.moveTo.nonfinite
     66  desc: moveTo() with Infinity/NaN is ignored
     67  code: |
     68    ctx.moveTo(0, 0);
     69    ctx.lineTo(100, 0);
     70    @nonfinite ctx.moveTo(<0 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>);
     71    ctx.lineTo(100, 50);
     72    ctx.lineTo(0, 50);
     73    ctx.fillStyle = '#0f0';
     74    ctx.fill();
     75    @assert pixel 50,25 == 0,255,0,255;
     76  expected: green
     77 
     78 - name: 2d.path.closePath.empty
     79  code: |
     80    ctx.fillStyle = '#0f0';
     81    ctx.fillRect(0, 0, 100, 50);
     82    ctx.closePath();
     83    ctx.fillStyle = '#f00';
     84    ctx.fill();
     85    @assert pixel 50,25 == 0,255,0,255;
     86  expected: green
     87 
     88 - name: 2d.path.closePath.newline
     89  code: |
     90    ctx.fillStyle = '#f00';
     91    ctx.fillRect(0, 0, 100, 50);
     92    ctx.strokeStyle = '#0f0';
     93    ctx.lineWidth = 50;
     94    ctx.moveTo(-100, 25);
     95    ctx.lineTo(-100, -100);
     96    ctx.lineTo(200, -100);
     97    ctx.lineTo(200, 25);
     98    ctx.closePath();
     99    ctx.stroke();
    100    @assert pixel 50,25 == 0,255,0,255;
    101  expected: green
    102 
    103 - name: 2d.path.closePath.nextpoint
    104  code: |
    105    ctx.fillStyle = '#f00';
    106    ctx.fillRect(0, 0, 100, 50);
    107    ctx.strokeStyle = '#0f0';
    108    ctx.lineWidth = 50;
    109    ctx.moveTo(-100, 25);
    110    ctx.lineTo(-100, -1000);
    111    ctx.closePath();
    112    ctx.lineTo(1000, 25);
    113    ctx.stroke();
    114    @assert pixel 50,25 == 0,255,0,255;
    115  expected: green
    116 
    117 - name: 2d.path.lineTo.ensuresubpath.1
    118  desc: If there is no subpath, the point is added and nothing is drawn
    119  code: |
    120    ctx.fillStyle = '#0f0';
    121    ctx.fillRect(0, 0, 100, 50);
    122    ctx.strokeStyle = '#f00';
    123    ctx.lineWidth = 50;
    124    ctx.beginPath();
    125    ctx.lineTo(100, 50);
    126    ctx.stroke();
    127    @assert pixel 50,25 == 0,255,0,255;
    128  expected: green
    129 
    130 - name: 2d.path.lineTo.ensuresubpath.2
    131  desc: If there is no subpath, the point is added and used for subsequent drawing
    132  code: |
    133    ctx.fillStyle = '#f00';
    134    ctx.fillRect(0, 0, 100, 50);
    135    ctx.strokeStyle = '#0f0';
    136    ctx.lineWidth = 50;
    137    ctx.beginPath();
    138    ctx.lineTo(0, 25);
    139    ctx.lineTo(100, 25);
    140    ctx.stroke();
    141    @assert pixel 50,25 == 0,255,0,255;
    142  expected: green
    143 
    144 - name: 2d.path.lineTo.basic
    145  code: |
    146    ctx.fillStyle = '#f00';
    147    ctx.fillRect(0, 0, 100, 50);
    148    ctx.strokeStyle = '#0f0';
    149    ctx.lineWidth = 50;
    150    ctx.beginPath();
    151    ctx.moveTo(0, 25);
    152    ctx.lineTo(100, 25);
    153    ctx.stroke();
    154    @assert pixel 50,25 == 0,255,0,255;
    155  expected: green
    156 
    157 - name: 2d.path.lineTo.nextpoint
    158  code: |
    159    ctx.fillStyle = '#f00';
    160    ctx.fillRect(0, 0, 100, 50);
    161    ctx.strokeStyle = '#0f0';
    162    ctx.lineWidth = 50;
    163    ctx.beginPath();
    164    ctx.moveTo(-100, -100);
    165    ctx.lineTo(0, 25);
    166    ctx.lineTo(100, 25);
    167    ctx.stroke();
    168    @assert pixel 50,25 == 0,255,0,255;
    169  expected: green
    170 
    171 - name: 2d.path.lineTo.nonfinite
    172  desc: lineTo() with Infinity/NaN is ignored
    173  code: |
    174    ctx.moveTo(0, 0);
    175    ctx.lineTo(100, 0);
    176    @nonfinite ctx.lineTo(<0 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>);
    177    ctx.lineTo(100, 50);
    178    ctx.lineTo(0, 50);
    179    ctx.fillStyle = '#0f0';
    180    ctx.fill();
    181    @assert pixel 50,25 == 0,255,0,255;
    182    @assert pixel 90,45 == 0,255,0,255;
    183  expected: green
    184 
    185 - name: 2d.path.lineTo.nonfinite.details
    186  desc: lineTo() with Infinity/NaN for first arg still converts the second arg
    187  code: |
    188    for (var arg1 of [Infinity, -Infinity, NaN]) {
    189      var converted = false;
    190      ctx.lineTo(arg1, { valueOf: function() { converted = true; return 0; } });
    191      @assert converted;
    192    }
    193  expected: clear
    194 
    195 - name: 2d.path.quadraticCurveTo.ensuresubpath.1
    196  desc: If there is no subpath, the first control point is added (and nothing is drawn
    197    up to it)
    198  code: |
    199    ctx.fillStyle = '#0f0';
    200    ctx.fillRect(0, 0, 100, 50);
    201    ctx.strokeStyle = '#f00';
    202    ctx.lineWidth = 50;
    203    ctx.beginPath();
    204    ctx.quadraticCurveTo(100, 50, 200, 50);
    205    ctx.stroke();
    206    @assert pixel 50,25 == 0,255,0,255;
    207    @assert pixel 95,45 == 0,255,0,255; @moz-todo
    208  expected: green
    209 
    210 - name: 2d.path.quadraticCurveTo.ensuresubpath.2
    211  desc: If there is no subpath, the first control point is added
    212  code: |
    213    ctx.fillStyle = '#f00';
    214    ctx.fillRect(0, 0, 100, 50);
    215    ctx.strokeStyle = '#0f0';
    216    ctx.lineWidth = 50;
    217    ctx.beginPath();
    218    ctx.quadraticCurveTo(0, 25, 100, 25);
    219    ctx.stroke();
    220    @assert pixel 50,25 == 0,255,0,255;
    221    @assert pixel 5,45 == 0,255,0,255; @moz-todo
    222  expected: green
    223 
    224 - name: 2d.path.quadraticCurveTo.basic
    225  code: |
    226    ctx.fillStyle = '#f00';
    227    ctx.fillRect(0, 0, 100, 50);
    228    ctx.strokeStyle = '#0f0';
    229    ctx.lineWidth = 50;
    230    ctx.beginPath();
    231    ctx.moveTo(0, 25);
    232    ctx.quadraticCurveTo(100, 25, 100, 25);
    233    ctx.stroke();
    234    @assert pixel 50,25 == 0,255,0,255;
    235  expected: green
    236 
    237 - name: 2d.path.quadraticCurveTo.shape
    238  code: |
    239    ctx.fillStyle = '#f00';
    240    ctx.fillRect(0, 0, 100, 50);
    241    ctx.strokeStyle = '#0f0';
    242    ctx.lineWidth = 55;
    243    ctx.beginPath();
    244    ctx.moveTo(-1000, 1050);
    245    ctx.quadraticCurveTo(0, -1000, 1200, 1050);
    246    ctx.stroke();
    247    @assert pixel 50,25 == 0,255,0,255;
    248    @assert pixel 1,1 == 0,255,0,255;
    249    @assert pixel 98,1 == 0,255,0,255;
    250    @assert pixel 1,48 == 0,255,0,255;
    251    @assert pixel 98,48 == 0,255,0,255;
    252  expected: green
    253 
    254 - name: 2d.path.quadraticCurveTo.scaled
    255  code: |
    256    ctx.fillStyle = '#f00';
    257    ctx.fillRect(0, 0, 100, 50);
    258    ctx.scale(1000, 1000);
    259    ctx.strokeStyle = '#0f0';
    260    ctx.lineWidth = 0.055;
    261    ctx.beginPath();
    262    ctx.moveTo(-1, 1.05);
    263    ctx.quadraticCurveTo(0, -1, 1.2, 1.05);
    264    ctx.stroke();
    265    @assert pixel 50,25 == 0,255,0,255;
    266    @assert pixel 1,1 == 0,255,0,255;
    267    @assert pixel 98,1 == 0,255,0,255;
    268    @assert pixel 1,48 == 0,255,0,255;
    269    @assert pixel 98,48 == 0,255,0,255;
    270  expected: green
    271 
    272 - name: 2d.path.quadraticCurveTo.nonfinite
    273  desc: quadraticCurveTo() with Infinity/NaN is ignored
    274  code: |
    275    ctx.moveTo(0, 0);
    276    ctx.lineTo(100, 0);
    277    @nonfinite ctx.quadraticCurveTo(<0 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>);
    278    ctx.lineTo(100, 50);
    279    ctx.lineTo(0, 50);
    280    ctx.fillStyle = '#0f0';
    281    ctx.fill();
    282    @assert pixel 50,25 == 0,255,0,255;
    283    @assert pixel 90,45 == 0,255,0,255;
    284  expected: green
    285 
    286 - name: 2d.path.bezierCurveTo.ensuresubpath.1
    287  desc: If there is no subpath, the first control point is added (and nothing is drawn
    288    up to it)
    289  code: |
    290    ctx.fillStyle = '#0f0';
    291    ctx.fillRect(0, 0, 100, 50);
    292    ctx.strokeStyle = '#f00';
    293    ctx.lineWidth = 50;
    294    ctx.beginPath();
    295    ctx.bezierCurveTo(100, 50, 200, 50, 200, 50);
    296    ctx.stroke();
    297    @assert pixel 50,25 == 0,255,0,255;
    298    @assert pixel 95,45 == 0,255,0,255;
    299  expected: green
    300 
    301 - name: 2d.path.bezierCurveTo.ensuresubpath.2
    302  desc: If there is no subpath, the first control point is added
    303  code: |
    304    ctx.fillStyle = '#f00';
    305    ctx.fillRect(0, 0, 100, 50);
    306    ctx.strokeStyle = '#0f0';
    307    ctx.lineWidth = 50;
    308    ctx.beginPath();
    309    ctx.bezierCurveTo(0, 25, 100, 25, 100, 25);
    310    ctx.stroke();
    311    @assert pixel 50,25 == 0,255,0,255;
    312    @assert pixel 5,45 == 0,255,0,255;
    313  expected: green
    314 
    315 - name: 2d.path.bezierCurveTo.basic
    316  code: |
    317    ctx.fillStyle = '#f00';
    318    ctx.fillRect(0, 0, 100, 50);
    319    ctx.strokeStyle = '#0f0';
    320    ctx.lineWidth = 50;
    321    ctx.beginPath();
    322    ctx.moveTo(0, 25);
    323    ctx.bezierCurveTo(100, 25, 100, 25, 100, 25);
    324    ctx.stroke();
    325    @assert pixel 50,25 == 0,255,0,255;
    326  expected: green
    327 
    328 - name: 2d.path.bezierCurveTo.shape
    329  code: |
    330    ctx.fillStyle = '#f00';
    331    ctx.fillRect(0, 0, 100, 50);
    332    ctx.strokeStyle = '#0f0';
    333    ctx.lineWidth = 55;
    334    ctx.beginPath();
    335    ctx.moveTo(-2000, 3100);
    336    ctx.bezierCurveTo(-2000, -1000, 2100, -1000, 2100, 3100);
    337    ctx.stroke();
    338    @assert pixel 50,25 == 0,255,0,255;
    339    @assert pixel 1,1 == 0,255,0,255;
    340    @assert pixel 98,1 == 0,255,0,255;
    341    @assert pixel 1,48 == 0,255,0,255;
    342    @assert pixel 98,48 == 0,255,0,255;
    343  expected: green
    344 
    345 - name: 2d.path.bezierCurveTo.scaled
    346  code: |
    347    ctx.fillStyle = '#f00';
    348    ctx.fillRect(0, 0, 100, 50);
    349    ctx.scale(1000, 1000);
    350    ctx.strokeStyle = '#0f0';
    351    ctx.lineWidth = 0.055;
    352    ctx.beginPath();
    353    ctx.moveTo(-2, 3.1);
    354    ctx.bezierCurveTo(-2, -1, 2.1, -1, 2.1, 3.1);
    355    ctx.stroke();
    356    @assert pixel 50,25 == 0,255,0,255;
    357    @assert pixel 1,1 == 0,255,0,255;
    358    @assert pixel 98,1 == 0,255,0,255;
    359    @assert pixel 1,48 == 0,255,0,255;
    360    @assert pixel 98,48 == 0,255,0,255;
    361  expected: green
    362 
    363 - name: 2d.path.bezierCurveTo.nonfinite
    364  desc: bezierCurveTo() with Infinity/NaN is ignored
    365  code: |
    366    ctx.moveTo(0, 0);
    367    ctx.lineTo(100, 0);
    368    @nonfinite ctx.bezierCurveTo(<0 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>);
    369    ctx.lineTo(100, 50);
    370    ctx.lineTo(0, 50);
    371    ctx.fillStyle = '#0f0';
    372    ctx.fill();
    373    @assert pixel 50,25 == 0,255,0,255;
    374    @assert pixel 90,45 == 0,255,0,255;
    375  expected: green
    376 
    377 - name: 2d.path.arcTo.ensuresubpath.1
    378  desc: If there is no subpath, the first control point is added (and nothing is drawn
    379    up to it)
    380  code: |
    381    ctx.fillStyle = '#0f0';
    382    ctx.fillRect(0, 0, 100, 50);
    383    ctx.lineWidth = 50;
    384    ctx.strokeStyle = '#f00';
    385    ctx.beginPath();
    386    ctx.arcTo(100, 50, 200, 50, 0.1);
    387    ctx.stroke();
    388    @assert pixel 50,25 == 0,255,0,255;
    389  expected: green
    390 
    391 - name: 2d.path.arcTo.ensuresubpath.2
    392  desc: If there is no subpath, the first control point is added
    393  code: |
    394    ctx.fillStyle = '#f00';
    395    ctx.fillRect(0, 0, 100, 50);
    396    ctx.lineWidth = 50;
    397    ctx.strokeStyle = '#0f0';
    398    ctx.beginPath();
    399    ctx.arcTo(0, 25, 50, 250, 0.1); // adds (x1,y1), draws nothing
    400    ctx.lineTo(100, 25);
    401    ctx.stroke();
    402    @assert pixel 50,25 == 0,255,0,255;
    403  expected: green
    404 
    405 - name: 2d.path.arcTo.ensuresubpath.3
    406  desc: If there is no subpath, the first control point is added (and nothing is drawn
    407    up to it)
    408  code: |
    409    ctx.fillStyle = '#0f0';
    410    ctx.fillRect(0, 0, 100, 50);
    411    ctx.strokeStyle = '#f00';
    412    ctx.lineWidth = 100;
    413    ctx.beginPath();
    414    ctx.arcTo(50, 0, 50, 100, 100);
    415    ctx.stroke();
    416    @assert pixel 50,25 == 0,255,0,255;
    417  expected: green
    418 
    419 - name: 2d.path.arcTo.coincide.1
    420  desc: arcTo() has no effect if P0 = P1
    421  code: |
    422    ctx.fillStyle = '#f00';
    423    ctx.fillRect(0, 0, 100, 50);
    424    ctx.lineWidth = 50;
    425 
    426    ctx.strokeStyle = '#0f0';
    427    ctx.beginPath();
    428    ctx.moveTo(0, 25);
    429    ctx.arcTo(0, 25, 50, 1000, 1);
    430    ctx.lineTo(100, 25);
    431    ctx.stroke();
    432 
    433    ctx.strokeStyle = '#f00';
    434    ctx.beginPath();
    435    ctx.moveTo(50, 25);
    436    ctx.arcTo(50, 25, 100, 25, 1);
    437    ctx.stroke();
    438 
    439    @assert pixel 50,1 == 0,255,0,255;
    440    @assert pixel 50,25 == 0,255,0,255;
    441    @assert pixel 50,48 == 0,255,0,255;
    442  expected: green
    443 
    444 - name: 2d.path.arcTo.coincide.2
    445  desc: arcTo() draws a straight line to P1 if P1 = P2
    446  code: |
    447    ctx.fillStyle = '#f00';
    448    ctx.fillRect(0, 0, 100, 50);
    449    ctx.lineWidth = 50;
    450    ctx.strokeStyle = '#0f0';
    451    ctx.beginPath();
    452    ctx.moveTo(0, 25);
    453    ctx.arcTo(100, 25, 100, 25, 1);
    454    ctx.stroke();
    455 
    456    @assert pixel 50,25 == 0,255,0,255;
    457  expected: green
    458 
    459 - name: 2d.path.arcTo.collinear.1
    460  desc: arcTo() with all points on a line, and P1 between P0/P2, draws a straight
    461    line to P1
    462  code: |
    463    ctx.fillStyle = '#f00';
    464    ctx.fillRect(0, 0, 100, 50);
    465    ctx.lineWidth = 50;
    466 
    467    ctx.strokeStyle = '#0f0';
    468    ctx.beginPath();
    469    ctx.moveTo(0, 25);
    470    ctx.arcTo(100, 25, 200, 25, 1);
    471    ctx.stroke();
    472 
    473    ctx.strokeStyle = '#f00';
    474    ctx.beginPath();
    475    ctx.moveTo(-100, 25);
    476    ctx.arcTo(0, 25, 100, 25, 1);
    477    ctx.stroke();
    478 
    479    @assert pixel 50,25 == 0,255,0,255;
    480  expected: green
    481 
    482 - name: 2d.path.arcTo.collinear.2
    483  desc: arcTo() with all points on a line, and P2 between P0/P1, draws a straight
    484    line to P1
    485  code: |
    486    ctx.fillStyle = '#f00';
    487    ctx.fillRect(0, 0, 100, 50);
    488    ctx.lineWidth = 50;
    489 
    490    ctx.strokeStyle = '#0f0';
    491    ctx.beginPath();
    492    ctx.moveTo(0, 25);
    493    ctx.arcTo(100, 25, 10, 25, 1);
    494    ctx.stroke();
    495 
    496    ctx.strokeStyle = '#f00';
    497    ctx.beginPath();
    498    ctx.moveTo(100, 25);
    499    ctx.arcTo(200, 25, 110, 25, 1);
    500    ctx.stroke();
    501 
    502    @assert pixel 50,25 == 0,255,0,255;
    503  expected: green
    504 
    505 - name: 2d.path.arcTo.collinear.3
    506  desc: arcTo() with all points on a line, and P0 between P1/P2, draws a straight
    507    line to P1
    508  code: |
    509    ctx.fillStyle = '#f00';
    510    ctx.fillRect(0, 0, 100, 50);
    511    ctx.lineWidth = 50;
    512 
    513    ctx.strokeStyle = '#0f0';
    514    ctx.beginPath();
    515    ctx.moveTo(0, 25);
    516    ctx.arcTo(100, 25, -100, 25, 1);
    517    ctx.stroke();
    518 
    519    ctx.strokeStyle = '#f00';
    520    ctx.beginPath();
    521    ctx.moveTo(100, 25);
    522    ctx.arcTo(200, 25, 0, 25, 1);
    523    ctx.stroke();
    524 
    525    ctx.beginPath();
    526    ctx.moveTo(-100, 25);
    527    ctx.arcTo(0, 25, -200, 25, 1);
    528    ctx.stroke();
    529 
    530    @assert pixel 50,25 == 0,255,0,255;
    531  expected: green
    532 
    533 - name: 2d.path.arcTo.shape.curve1
    534  desc: arcTo() curves in the right kind of shape
    535  code: |
    536    var tol = 1.5; // tolerance to avoid antialiasing artifacts
    537 
    538    ctx.fillStyle = '#0f0';
    539    ctx.fillRect(0, 0, 100, 50);
    540 
    541    ctx.strokeStyle = '#f00';
    542    ctx.lineWidth = 10;
    543    ctx.beginPath();
    544    ctx.moveTo(10, 25);
    545    ctx.arcTo(75, 25, 75, 60, 20);
    546    ctx.stroke();
    547 
    548    ctx.fillStyle = '#0f0';
    549    ctx.beginPath();
    550    ctx.rect(10, 20, 45, 10);
    551    ctx.moveTo(80, 45);
    552    ctx.arc(55, 45, 25+tol, 0, -Math.PI/2, true);
    553    ctx.arc(55, 45, 15-tol, -Math.PI/2, 0, false);
    554    ctx.fill();
    555 
    556    @assert pixel 50,25 == 0,255,0,255;
    557    @assert pixel 55,19 == 0,255,0,255;
    558    @assert pixel 55,20 == 0,255,0,255;
    559    @assert pixel 55,21 == 0,255,0,255;
    560    @assert pixel 64,22 == 0,255,0,255;
    561    @assert pixel 65,21 == 0,255,0,255;
    562    @assert pixel 72,28 == 0,255,0,255;
    563    @assert pixel 73,27 == 0,255,0,255;
    564    @assert pixel 78,36 == 0,255,0,255;
    565    @assert pixel 79,35 == 0,255,0,255;
    566    @assert pixel 80,44 == 0,255,0,255;
    567    @assert pixel 80,45 == 0,255,0,255;
    568    @assert pixel 80,46 == 0,255,0,255;
    569    @assert pixel 65,45 == 0,255,0,255;
    570  expected: green
    571 
    572 - name: 2d.path.arcTo.shape.curve2
    573  desc: arcTo() curves in the right kind of shape
    574  code: |
    575    var tol = 1.5; // tolerance to avoid antialiasing artifacts
    576 
    577    ctx.fillStyle = '#0f0';
    578    ctx.fillRect(0, 0, 100, 50);
    579 
    580    ctx.fillStyle = '#f00';
    581    ctx.beginPath();
    582    ctx.rect(10, 20, 45, 10);
    583    ctx.moveTo(80, 45);
    584    ctx.arc(55, 45, 25-tol, 0, -Math.PI/2, true);
    585    ctx.arc(55, 45, 15+tol, -Math.PI/2, 0, false);
    586    ctx.fill();
    587 
    588    ctx.strokeStyle = '#0f0';
    589    ctx.lineWidth = 10;
    590    ctx.beginPath();
    591    ctx.moveTo(10, 25);
    592    ctx.arcTo(75, 25, 75, 60, 20);
    593    ctx.stroke();
    594 
    595    @assert pixel 50,25 == 0,255,0,255;
    596    @assert pixel 55,19 == 0,255,0,255;
    597    @assert pixel 55,20 == 0,255,0,255;
    598    @assert pixel 55,21 == 0,255,0,255;
    599    @assert pixel 64,22 == 0,255,0,255;
    600    @assert pixel 65,21 == 0,255,0,255;
    601    @assert pixel 72,28 == 0,255,0,255;
    602    @assert pixel 73,27 == 0,255,0,255;
    603    @assert pixel 78,36 == 0,255,0,255;
    604    @assert pixel 79,35 == 0,255,0,255;
    605    @assert pixel 80,44 == 0,255,0,255;
    606    @assert pixel 80,45 == 0,255,0,255;
    607    @assert pixel 80,46 == 0,255,0,255;
    608  expected: green
    609 
    610 - name: 2d.path.arcTo.shape.start
    611  desc: arcTo() draws a straight line from P0 to P1
    612  code: |
    613    ctx.fillStyle = '#f00';
    614    ctx.fillRect(0, 0, 100, 50);
    615    ctx.strokeStyle = '#0f0';
    616    ctx.lineWidth = 50;
    617    ctx.beginPath();
    618    ctx.moveTo(0, 25);
    619    ctx.arcTo(200, 25, 200, 50, 10);
    620    ctx.stroke();
    621 
    622    @assert pixel 1,1 == 0,255,0,255;
    623    @assert pixel 1,48 == 0,255,0,255;
    624    @assert pixel 50,25 == 0,255,0,255;
    625    @assert pixel 98,1 == 0,255,0,255;
    626    @assert pixel 98,48 == 0,255,0,255;
    627  expected: green
    628 
    629 - name: 2d.path.arcTo.shape.end
    630  desc: arcTo() does not draw anything from P1 to P2
    631  code: |
    632    ctx.fillStyle = '#0f0';
    633    ctx.fillRect(0, 0, 100, 50);
    634    ctx.strokeStyle = '#f00';
    635    ctx.lineWidth = 50;
    636    ctx.beginPath();
    637    ctx.moveTo(-100, -100);
    638    ctx.arcTo(-100, 25, 200, 25, 10);
    639    ctx.stroke();
    640 
    641    @assert pixel 1,1 == 0,255,0,255;
    642    @assert pixel 1,48 == 0,255,0,255;
    643    @assert pixel 50,25 == 0,255,0,255;
    644    @assert pixel 98,1 == 0,255,0,255;
    645    @assert pixel 98,48 == 0,255,0,255;
    646  expected: green
    647 
    648 - name: 2d.path.arcTo.negative
    649  desc: arcTo() with negative radius throws an exception
    650  code: |
    651    @assert throws INDEX_SIZE_ERR ctx.arcTo(0, 0, 0, 0, -1);
    652    var path = new Path2D();
    653    @assert throws INDEX_SIZE_ERR path.arcTo(10, 10, 20, 20, -5);
    654 
    655 - name: 2d.path.arcTo.zero.1
    656  desc: arcTo() with zero radius draws a straight line from P0 to P1
    657  code: |
    658    ctx.fillStyle = '#f00';
    659    ctx.fillRect(0, 0, 100, 50);
    660    ctx.lineWidth = 50;
    661 
    662    ctx.strokeStyle = '#0f0';
    663    ctx.beginPath();
    664    ctx.moveTo(0, 25);
    665    ctx.arcTo(100, 25, 100, 100, 0);
    666    ctx.stroke();
    667 
    668    ctx.strokeStyle = '#f00';
    669    ctx.beginPath();
    670    ctx.moveTo(0, -25);
    671    ctx.arcTo(50, -25, 50, 50, 0);
    672    ctx.stroke();
    673 
    674    @assert pixel 50,25 == 0,255,0,255;
    675  expected: green
    676 
    677 - name: 2d.path.arcTo.zero.2
    678  desc: arcTo() with zero radius draws a straight line from P0 to P1, even when all
    679    points are collinear
    680  code: |
    681    ctx.fillStyle = '#f00';
    682    ctx.fillRect(0, 0, 100, 50);
    683    ctx.lineWidth = 50;
    684 
    685    ctx.strokeStyle = '#0f0';
    686    ctx.beginPath();
    687    ctx.moveTo(0, 25);
    688    ctx.arcTo(100, 25, -100, 25, 0);
    689    ctx.stroke();
    690 
    691    ctx.strokeStyle = '#f00';
    692    ctx.beginPath();
    693    ctx.moveTo(100, 25);
    694    ctx.arcTo(200, 25, 50, 25, 0);
    695    ctx.stroke();
    696 
    697    @assert pixel 50,25 == 0,255,0,255;
    698  expected: green
    699 
    700 - name: 2d.path.arcTo.transformation
    701  desc: arcTo joins up to the last subpath point correctly
    702  code: |
    703    ctx.fillStyle = '#f00';
    704    ctx.fillRect(0, 0, 100, 50);
    705 
    706    ctx.fillStyle = '#0f0';
    707    ctx.beginPath();
    708    ctx.moveTo(0, 50);
    709    ctx.translate(100, 0);
    710    ctx.arcTo(50, 50, 50, 0, 50);
    711    ctx.lineTo(-100, 0);
    712    ctx.fill();
    713 
    714    @assert pixel 0,0 == 0,255,0,255;
    715    @assert pixel 50,0 == 0,255,0,255;
    716    @assert pixel 99,0 == 0,255,0,255;
    717    @assert pixel 0,25 == 0,255,0,255;
    718    @assert pixel 50,25 == 0,255,0,255;
    719    @assert pixel 99,25 == 0,255,0,255;
    720    @assert pixel 0,49 == 0,255,0,255;
    721    @assert pixel 50,49 == 0,255,0,255;
    722    @assert pixel 99,49 == 0,255,0,255;
    723  expected: green
    724 
    725 - name: 2d.path.arcTo.scale
    726  desc: arcTo scales the curve, not just the control points
    727  code: |
    728    ctx.fillStyle = '#f00';
    729    ctx.fillRect(0, 0, 100, 50);
    730 
    731    ctx.fillStyle = '#0f0';
    732    ctx.beginPath();
    733    ctx.moveTo(0, 50);
    734    ctx.translate(100, 0);
    735    ctx.scale(0.1, 1);
    736    ctx.arcTo(50, 50, 50, 0, 50);
    737    ctx.lineTo(-1000, 0);
    738    ctx.fill();
    739 
    740    @assert pixel 0,0 == 0,255,0,255;
    741    @assert pixel 50,0 == 0,255,0,255;
    742    @assert pixel 99,0 == 0,255,0,255;
    743    @assert pixel 0,25 == 0,255,0,255;
    744    @assert pixel 50,25 == 0,255,0,255;
    745    @assert pixel 99,25 == 0,255,0,255;
    746    @assert pixel 0,49 == 0,255,0,255;
    747    @assert pixel 50,49 == 0,255,0,255;
    748    @assert pixel 99,49 == 0,255,0,255;
    749  expected: green
    750 
    751 - name: 2d.path.arcTo.nonfinite
    752  desc: arcTo() with Infinity/NaN is ignored
    753  code: |
    754    ctx.moveTo(0, 0);
    755    ctx.lineTo(100, 0);
    756    @nonfinite ctx.arcTo(<0 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>);
    757    ctx.lineTo(100, 50);
    758    ctx.lineTo(0, 50);
    759    ctx.fillStyle = '#0f0';
    760    ctx.fill();
    761    @assert pixel 50,25 == 0,255,0,255;
    762    @assert pixel 90,45 == 0,255,0,255;
    763  expected: green
    764 
    765 
    766 - name: 2d.path.arc.empty
    767  desc: arc() with an empty path does not draw a straight line to the start point
    768  code: |
    769    ctx.fillStyle = '#0f0';
    770    ctx.fillRect(0, 0, 100, 50);
    771    ctx.lineWidth = 50;
    772    ctx.strokeStyle = '#f00';
    773    ctx.beginPath();
    774    ctx.arc(200, 25, 5, 0, 2*Math.PI, true);
    775    ctx.stroke();
    776    @assert pixel 50,25 == 0,255,0,255;
    777  expected: green
    778 
    779 - name: 2d.path.arc.nonempty
    780  desc: arc() with a non-empty path does draw a straight line to the start point
    781  code: |
    782    ctx.fillStyle = '#f00';
    783    ctx.fillRect(0, 0, 100, 50);
    784    ctx.lineWidth = 50;
    785    ctx.strokeStyle = '#0f0';
    786    ctx.beginPath();
    787    ctx.moveTo(0, 25);
    788    ctx.arc(200, 25, 5, 0, 2*Math.PI, true);
    789    ctx.stroke();
    790    @assert pixel 50,25 == 0,255,0,255;
    791  expected: green
    792 
    793 - name: 2d.path.arc.end
    794  desc: arc() adds the end point of the arc to the subpath
    795  code: |
    796    ctx.fillStyle = '#f00';
    797    ctx.fillRect(0, 0, 100, 50);
    798    ctx.lineWidth = 50;
    799    ctx.strokeStyle = '#0f0';
    800    ctx.beginPath();
    801    ctx.moveTo(-100, 0);
    802    ctx.arc(-100, 0, 25, -Math.PI/2, Math.PI/2, true);
    803    ctx.lineTo(100, 25);
    804    ctx.stroke();
    805    @assert pixel 50,25 == 0,255,0,255;
    806  expected: green
    807 
    808 - name: 2d.path.arc.default
    809  desc: arc() with missing last argument defaults to clockwise
    810  code: |
    811    ctx.fillStyle = '#0f0';
    812    ctx.fillRect(0, 0, 100, 50);
    813    ctx.fillStyle = '#f00';
    814    ctx.beginPath();
    815    ctx.moveTo(100, 0);
    816    ctx.arc(100, 0, 150, -Math.PI, Math.PI/2);
    817    ctx.fill();
    818    @assert pixel 50,25 == 0,255,0,255;
    819  expected: green
    820 
    821 - name: 2d.path.arc.angle.1
    822  desc: arc() draws pi/2 .. -pi anticlockwise correctly
    823  code: |
    824    ctx.fillStyle = '#0f0';
    825    ctx.fillRect(0, 0, 100, 50);
    826    ctx.fillStyle = '#f00';
    827    ctx.beginPath();
    828    ctx.moveTo(100, 0);
    829    ctx.arc(100, 0, 150, Math.PI/2, -Math.PI, true);
    830    ctx.fill();
    831    @assert pixel 50,25 == 0,255,0,255;
    832  expected: green
    833 
    834 - name: 2d.path.arc.angle.2
    835  desc: arc() draws -3pi/2 .. -pi anticlockwise correctly
    836  code: |
    837    ctx.fillStyle = '#0f0';
    838    ctx.fillRect(0, 0, 100, 50);
    839    ctx.fillStyle = '#f00';
    840    ctx.beginPath();
    841    ctx.moveTo(100, 0);
    842    ctx.arc(100, 0, 150, -3*Math.PI/2, -Math.PI, true);
    843    ctx.fill();
    844    @assert pixel 50,25 == 0,255,0,255;
    845  expected: green
    846 
    847 - name: 2d.path.arc.angle.3
    848  desc: arc() wraps angles mod 2pi when anticlockwise and end > start+2pi
    849  code: |
    850    ctx.fillStyle = '#0f0';
    851    ctx.fillRect(0, 0, 100, 50);
    852    ctx.fillStyle = '#f00';
    853    ctx.beginPath();
    854    ctx.moveTo(100, 0);
    855    ctx.arc(100, 0, 150, (512+1/2)*Math.PI, (1024-1)*Math.PI, true);
    856    ctx.fill();
    857    @assert pixel 50,25 == 0,255,0,255;
    858  expected: green
    859 
    860 - name: 2d.path.arc.angle.4
    861  desc: arc() draws a full circle when clockwise and end > start+2pi
    862  code: |
    863    ctx.fillStyle = '#f00';
    864    ctx.fillRect(0, 0, 100, 50);
    865    ctx.fillStyle = '#0f0';
    866    ctx.beginPath();
    867    ctx.moveTo(50, 25);
    868    ctx.arc(50, 25, 60, (512+1/2)*Math.PI, (1024-1)*Math.PI, false);
    869    ctx.fill();
    870    @assert pixel 1,1 == 0,255,0,255;
    871    @assert pixel 98,1 == 0,255,0,255;
    872    @assert pixel 1,48 == 0,255,0,255;
    873    @assert pixel 98,48 == 0,255,0,255;
    874  expected: green
    875 
    876 - name: 2d.path.arc.angle.5
    877  desc: arc() wraps angles mod 2pi when clockwise and start > end+2pi
    878  code: |
    879    ctx.fillStyle = '#0f0';
    880    ctx.fillRect(0, 0, 100, 50);
    881    ctx.fillStyle = '#f00';
    882    ctx.beginPath();
    883    ctx.moveTo(100, 0);
    884    ctx.arc(100, 0, 150, (1024-1)*Math.PI, (512+1/2)*Math.PI, false);
    885    ctx.fill();
    886    @assert pixel 50,25 == 0,255,0,255;
    887  expected: green
    888 
    889 - name: 2d.path.arc.angle.6
    890  desc: arc() draws a full circle when anticlockwise and start > end+2pi
    891  code: |
    892    ctx.fillStyle = '#f00';
    893    ctx.fillRect(0, 0, 100, 50);
    894    ctx.fillStyle = '#0f0';
    895    ctx.beginPath();
    896    ctx.moveTo(50, 25);
    897    ctx.arc(50, 25, 60, (1024-1)*Math.PI, (512+1/2)*Math.PI, true);
    898    ctx.fill();
    899    @assert pixel 1,1 == 0,255,0,255;
    900    @assert pixel 98,1 == 0,255,0,255;
    901    @assert pixel 1,48 == 0,255,0,255;
    902    @assert pixel 98,48 == 0,255,0,255;
    903  expected: green
    904 
    905 - name: 2d.path.arc.zero.1
    906  desc: arc() draws nothing when startAngle = endAngle and anticlockwise
    907  code: |
    908    ctx.fillStyle = '#0f0';
    909    ctx.fillRect(0, 0, 100, 50);
    910    ctx.strokeStyle = '#f00';
    911    ctx.lineWidth = 100;
    912    ctx.beginPath();
    913    ctx.arc(50, 25, 50, 0, 0, true);
    914    ctx.stroke();
    915    @assert pixel 50,20 == 0,255,0,255;
    916  expected: green
    917 
    918 - name: 2d.path.arc.zero.2
    919  desc: arc() draws nothing when startAngle = endAngle and clockwise
    920  code: |
    921    ctx.fillStyle = '#0f0';
    922    ctx.fillRect(0, 0, 100, 50);
    923    ctx.strokeStyle = '#f00';
    924    ctx.lineWidth = 100;
    925    ctx.beginPath();
    926    ctx.arc(50, 25, 50, 0, 0, false);
    927    ctx.stroke();
    928    @assert pixel 50,20 == 0,255,0,255;
    929  expected: green
    930 
    931 - name: 2d.path.arc.twopie.1
    932  desc: arc() draws nothing when end = start + 2pi-e and anticlockwise
    933  code: |
    934    ctx.fillStyle = '#0f0';
    935    ctx.fillRect(0, 0, 100, 50);
    936    ctx.strokeStyle = '#f00';
    937    ctx.lineWidth = 100;
    938    ctx.beginPath();
    939    ctx.arc(50, 25, 50, 0, 2*Math.PI - 1e-4, true);
    940    ctx.stroke();
    941    @assert pixel 50,20 == 0,255,0,255;
    942  expected: green
    943 
    944 - name: 2d.path.arc.twopie.2
    945  desc: arc() draws a full circle when end = start + 2pi-e and clockwise
    946  code: |
    947    ctx.fillStyle = '#f00';
    948    ctx.fillRect(0, 0, 100, 50);
    949    ctx.strokeStyle = '#0f0';
    950    ctx.lineWidth = 100;
    951    ctx.beginPath();
    952    ctx.arc(50, 25, 50, 0, 2*Math.PI - 1e-4, false);
    953    ctx.stroke();
    954    @assert pixel 50,20 == 0,255,0,255;
    955  expected: green
    956 
    957 - name: 2d.path.arc.twopie.3
    958  desc: arc() draws a full circle when end = start + 2pi+e and anticlockwise
    959  code: |
    960    ctx.fillStyle = '#f00';
    961    ctx.fillRect(0, 0, 100, 50);
    962    ctx.strokeStyle = '#0f0';
    963    ctx.lineWidth = 100;
    964    ctx.beginPath();
    965    ctx.arc(50, 25, 50, 0, 2*Math.PI + 1e-4, true);
    966    ctx.stroke();
    967    @assert pixel 50,20 == 0,255,0,255;
    968  expected: green
    969 
    970 - name: 2d.path.arc.twopie.4
    971  desc: arc() draws nothing when end = start + 2pi+e and clockwise
    972  code: |
    973    ctx.fillStyle = '#f00';
    974    ctx.fillRect(0, 0, 100, 50);
    975    ctx.strokeStyle = '#0f0';
    976    ctx.lineWidth = 100;
    977    ctx.beginPath();
    978    ctx.arc(50, 25, 50, 0, 2*Math.PI + 1e-4, false);
    979    ctx.stroke();
    980    @assert pixel 50,20 == 0,255,0,255;
    981  expected: green
    982 
    983 - name: 2d.path.arc.twopie.5
    984  desc: arc() draws correctly when start = 2 and end = start + 2pi+e and clockwise
    985  code: |
    986    ctx.fillStyle = '#fff';
    987    ctx.fillRect(0, 0, 100, 50);
    988    ctx.fillStyle = '#000';
    989    ctx.beginPath();
    990    ctx.moveTo(50, 25);
    991    ctx.arc(50, 25, 50, 2, 2 + 2*Math.PI, false);
    992    ctx.closePath();
    993    ctx.fill();
    994    @assert pixel 95,25 == 0,0,0,255;
    995 
    996 - name: 2d.path.arc.twopie.6
    997  desc: arc() draws correctly when start = 5 and end = start + 2pi+e and clockwise
    998  code: |
    999    ctx.fillStyle = '#fff';
   1000    ctx.fillRect(0, 0, 100, 50);
   1001    ctx.fillStyle = '#000';
   1002    ctx.beginPath();
   1003    ctx.moveTo(50, 25);
   1004    ctx.arc(50, 25, 50, 5, 5 + 2*Math.PI, false);
   1005    ctx.closePath();
   1006    ctx.fill();
   1007    @assert pixel 5,25 == 0,0,0,255;
   1008 
   1009 - name: 2d.path.arc.shape.1
   1010  desc: arc() from 0 to pi does not draw anything in the wrong half
   1011  code: |
   1012    ctx.fillStyle = '#0f0';
   1013    ctx.fillRect(0, 0, 100, 50);
   1014    ctx.lineWidth = 50;
   1015    ctx.strokeStyle = '#f00';
   1016    ctx.beginPath();
   1017    ctx.arc(50, 50, 50, 0, Math.PI, false);
   1018    ctx.stroke();
   1019    @assert pixel 50,25 == 0,255,0,255;
   1020    @assert pixel 1,1 == 0,255,0,255;
   1021    @assert pixel 98,1 == 0,255,0,255;
   1022    @assert pixel 1,48 == 0,255,0,255;
   1023    @assert pixel 20,48 == 0,255,0,255;
   1024    @assert pixel 98,48 == 0,255,0,255;
   1025  expected: green
   1026 
   1027 - name: 2d.path.arc.shape.2
   1028  desc: arc() from 0 to pi draws stuff in the right half
   1029  code: |
   1030    ctx.fillStyle = '#f00';
   1031    ctx.fillRect(0, 0, 100, 50);
   1032    ctx.lineWidth = 100;
   1033    ctx.strokeStyle = '#0f0';
   1034    ctx.beginPath();
   1035    ctx.arc(50, 50, 50, 0, Math.PI, true);
   1036    ctx.stroke();
   1037    @assert pixel 50,25 == 0,255,0,255;
   1038    @assert pixel 1,1 == 0,255,0,255;
   1039    @assert pixel 98,1 == 0,255,0,255;
   1040    @assert pixel 1,48 == 0,255,0,255;
   1041    @assert pixel 20,48 == 0,255,0,255;
   1042    @assert pixel 98,48 == 0,255,0,255;
   1043  expected: green
   1044 
   1045 - name: 2d.path.arc.shape.3
   1046  desc: arc() from 0 to -pi/2 does not draw anything in the wrong quadrant
   1047  code: |
   1048    ctx.fillStyle = '#0f0';
   1049    ctx.fillRect(0, 0, 100, 50);
   1050    ctx.lineWidth = 100;
   1051    ctx.strokeStyle = '#f00';
   1052    ctx.beginPath();
   1053    ctx.arc(0, 50, 50, 0, -Math.PI/2, false);
   1054    ctx.stroke();
   1055    @assert pixel 50,25 == 0,255,0,255;
   1056    @assert pixel 1,1 == 0,255,0,255;
   1057    @assert pixel 98,1 == 0,255,0,255;
   1058    @assert pixel 1,48 == 0,255,0,255; @moz-todo
   1059    @assert pixel 98,48 == 0,255,0,255;
   1060  expected: green
   1061 
   1062 - name: 2d.path.arc.shape.4
   1063  desc: arc() from 0 to -pi/2 draws stuff in the right quadrant
   1064  code: |
   1065    ctx.fillStyle = '#f00';
   1066    ctx.fillRect(0, 0, 100, 50);
   1067    ctx.lineWidth = 150;
   1068    ctx.strokeStyle = '#0f0';
   1069    ctx.beginPath();
   1070    ctx.arc(-50, 50, 100, 0, -Math.PI/2, true);
   1071    ctx.stroke();
   1072    @assert pixel 50,25 == 0,255,0,255;
   1073    @assert pixel 1,1 == 0,255,0,255;
   1074    @assert pixel 98,1 == 0,255,0,255;
   1075    @assert pixel 1,48 == 0,255,0,255;
   1076    @assert pixel 98,48 == 0,255,0,255;
   1077  expected: green
   1078 
   1079 - name: 2d.path.arc.shape.5
   1080  desc: arc() from 0 to 5pi does not draw crazy things
   1081  code: |
   1082    ctx.fillStyle = '#0f0';
   1083    ctx.fillRect(0, 0, 100, 50);
   1084    ctx.lineWidth = 200;
   1085    ctx.strokeStyle = '#f00';
   1086    ctx.beginPath();
   1087    ctx.arc(300, 0, 100, 0, 5*Math.PI, false);
   1088    ctx.stroke();
   1089    @assert pixel 50,25 == 0,255,0,255;
   1090    @assert pixel 1,1 == 0,255,0,255;
   1091    @assert pixel 98,1 == 0,255,0,255;
   1092    @assert pixel 1,48 == 0,255,0,255;
   1093    @assert pixel 98,48 == 0,255,0,255;
   1094  expected: green
   1095 
   1096 - name: 2d.path.arc.selfintersect.1
   1097  desc: arc() with lineWidth > 2*radius is drawn sensibly
   1098  code: |
   1099    ctx.fillStyle = '#0f0';
   1100    ctx.fillRect(0, 0, 100, 50);
   1101    ctx.lineWidth = 200;
   1102    ctx.strokeStyle = '#f00';
   1103    ctx.beginPath();
   1104    ctx.arc(100, 50, 25, 0, -Math.PI/2, true);
   1105    ctx.stroke();
   1106    ctx.beginPath();
   1107    ctx.arc(0, 0, 25, 0, -Math.PI/2, true);
   1108    ctx.stroke();
   1109    @assert pixel 1,1 == 0,255,0,255; @moz-todo
   1110    @assert pixel 50,25 == 0,255,0,255;
   1111  expected: green
   1112 
   1113 - name: 2d.path.arc.selfintersect.2
   1114  desc: arc() with lineWidth > 2*radius is drawn sensibly
   1115  code: |
   1116    ctx.fillStyle = '#f00';
   1117    ctx.fillRect(0, 0, 100, 50);
   1118    ctx.lineWidth = 180;
   1119    ctx.strokeStyle = '#0f0';
   1120    ctx.beginPath();
   1121    ctx.arc(-50, 50, 25, 0, -Math.PI/2, true);
   1122    ctx.stroke();
   1123    ctx.beginPath();
   1124    ctx.arc(100, 0, 25, 0, -Math.PI/2, true);
   1125    ctx.stroke();
   1126    @assert pixel 50,25 == 0,255,0,255;
   1127    @assert pixel 90,10 == 0,255,0,255;
   1128    @assert pixel 97,1 == 0,255,0,255;
   1129    @assert pixel 97,2 == 0,255,0,255;
   1130    @assert pixel 97,3 == 0,255,0,255;
   1131    @assert pixel 2,48 == 0,255,0,255;
   1132  expected: green
   1133 
   1134 - name: 2d.path.arc.negative
   1135  desc: arc() with negative radius throws INDEX_SIZE_ERR
   1136  code: |
   1137    @assert throws INDEX_SIZE_ERR ctx.arc(0, 0, -1, 0, 0, true);
   1138    var path = new Path2D();
   1139    @assert throws INDEX_SIZE_ERR path.arc(10, 10, -5, 0, 1, false);
   1140 
   1141 - name: 2d.path.arc.zeroradius
   1142  desc: arc() with zero radius draws a line to the start point
   1143  code: |
   1144    ctx.fillStyle = '#f00'
   1145    ctx.fillRect(0, 0, 100, 50);
   1146    ctx.lineWidth = 50;
   1147    ctx.strokeStyle = '#0f0';
   1148    ctx.beginPath();
   1149    ctx.moveTo(0, 25);
   1150    ctx.arc(200, 25, 0, 0, Math.PI, true);
   1151    ctx.stroke();
   1152    @assert pixel 50,25 == 0,255,0,255;
   1153  expected: green
   1154 
   1155 - name: 2d.path.arc.scale.1
   1156  desc: Non-uniformly scaled arcs are the right shape
   1157  code: |
   1158    ctx.fillStyle = '#f00';
   1159    ctx.fillRect(0, 0, 100, 50);
   1160    ctx.scale(2, 0.5);
   1161    ctx.fillStyle = '#0f0';
   1162    ctx.beginPath();
   1163    ctx.arc(25, 50, 56, 0, 2*Math.PI, false);
   1164    ctx.fill();
   1165    ctx.fillStyle = '#f00';
   1166    ctx.beginPath();
   1167    ctx.moveTo(-25, 50);
   1168    ctx.arc(-25, 50, 24, 0, 2*Math.PI, false);
   1169    ctx.moveTo(75, 50);
   1170    ctx.arc(75, 50, 24, 0, 2*Math.PI, false);
   1171    ctx.moveTo(25, -25);
   1172    ctx.arc(25, -25, 24, 0, 2*Math.PI, false);
   1173    ctx.moveTo(25, 125);
   1174    ctx.arc(25, 125, 24, 0, 2*Math.PI, false);
   1175    ctx.fill();
   1176 
   1177    @assert pixel 0,0 == 0,255,0,255;
   1178    @assert pixel 50,0 == 0,255,0,255;
   1179    @assert pixel 99,0 == 0,255,0,255;
   1180    @assert pixel 0,25 == 0,255,0,255;
   1181    @assert pixel 50,25 == 0,255,0,255;
   1182    @assert pixel 99,25 == 0,255,0,255;
   1183    @assert pixel 0,49 == 0,255,0,255;
   1184    @assert pixel 50,49 == 0,255,0,255;
   1185    @assert pixel 99,49 == 0,255,0,255;
   1186  expected: green
   1187 
   1188 - name: 2d.path.arc.scale.2
   1189  desc: Highly scaled arcs are the right shape
   1190  code: |
   1191    ctx.fillStyle = '#f00';
   1192    ctx.fillRect(0, 0, 100, 50);
   1193    ctx.scale(100, 100);
   1194    ctx.strokeStyle = '#0f0';
   1195    ctx.lineWidth = 1.2;
   1196    ctx.beginPath();
   1197    ctx.arc(0, 0, 0.6, 0, Math.PI/2, false);
   1198    ctx.stroke();
   1199 
   1200    @assert pixel 1,1 == 0,255,0,255;
   1201    @assert pixel 50,1 == 0,255,0,255;
   1202    @assert pixel 98,1 == 0,255,0,255;
   1203    @assert pixel 1,25 == 0,255,0,255;
   1204    @assert pixel 50,25 == 0,255,0,255;
   1205    @assert pixel 98,25 == 0,255,0,255;
   1206    @assert pixel 1,48 == 0,255,0,255;
   1207    @assert pixel 50,48 == 0,255,0,255;
   1208    @assert pixel 98,48 == 0,255,0,255;
   1209  expected: green
   1210 
   1211 - name: 2d.path.arc.nonfinite
   1212  desc: arc() with Infinity/NaN is ignored
   1213  code: |
   1214    ctx.fillStyle = '#f00';
   1215    ctx.fillRect(0, 0, 100, 50);
   1216    ctx.moveTo(0, 0);
   1217    ctx.lineTo(100, 0);
   1218    @nonfinite ctx.arc(<0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <2*Math.PI Infinity -Infinity NaN>, <true>);
   1219    ctx.lineTo(100, 50);
   1220    ctx.lineTo(0, 50);
   1221    ctx.fillStyle = '#0f0';
   1222    ctx.fill();
   1223    @assert pixel 50,25 == 0,255,0,255;
   1224    @assert pixel 90,45 == 0,255,0,255;
   1225  expected: green
   1226 
   1227 - name: 2d.path.closed.arc
   1228  desc: line caps should not be drawn on closed arcs
   1229  size: [300, 300]
   1230  code: |
   1231    ctx.beginPath();
   1232    ctx.strokeStyle = 'red';
   1233    ctx.lineWidth = 20;
   1234    ctx.lineCap = 'square';
   1235    ctx.arc(150, 150, 50, 0, 2 * Math.PI);
   1236    ctx.closePath();
   1237    ctx.stroke();
   1238    // The pixel (209, 148) is part of the line cap, but not part of the circle.
   1239    // Linecap is not drawn if the circle is closed, so the pixel is not red.
   1240    assert_not_equals(ctx.getImageData(209, 148, 1, 1).data, [255, 0, 0, 255])
   1241 
   1242 - name: 2d.path.open.arc
   1243  desc: line caps should be drawn on open arcs
   1244  size: [300, 300]
   1245  code: |
   1246    ctx.beginPath();
   1247    ctx.strokeStyle = 'red';
   1248    ctx.lineWidth = 20;
   1249    ctx.lineCap = 'square';
   1250    ctx.arc(150, 150, 50, 0, 2 * Math.PI);
   1251    ctx.stroke();
   1252    // The pixel (209, 148) is part of the line cap, but not part of the circle.
   1253    // Linecap is drawn with 360 degree arc, so the pixel is red.
   1254    @assert pixel 209,148 ==~ 255,0,0,255 +/- 1;
   1255 
   1256 - name: 2d.path.rect.basic
   1257  code: |
   1258    ctx.fillStyle = '#f00';
   1259    ctx.fillRect(0, 0, 100, 50);
   1260    ctx.fillStyle = '#0f0';
   1261    ctx.rect(0, 0, 100, 50);
   1262    ctx.fill();
   1263    @assert pixel 50,25 == 0,255,0,255;
   1264  expected: green
   1265 
   1266 - name: 2d.path.rect.newsubpath
   1267  code: |
   1268    ctx.fillStyle = '#0f0';
   1269    ctx.fillRect(0, 0, 100, 50);
   1270    ctx.beginPath();
   1271    ctx.strokeStyle = '#f00';
   1272    ctx.lineWidth = 50;
   1273    ctx.moveTo(-100, 25);
   1274    ctx.lineTo(-50, 25);
   1275    ctx.rect(200, 25, 1, 1);
   1276    ctx.stroke();
   1277    @assert pixel 50,25 == 0,255,0,255;
   1278  expected: green
   1279 
   1280 - name: 2d.path.rect.closed
   1281  code: |
   1282    ctx.fillStyle = '#f00';
   1283    ctx.fillRect(0, 0, 100, 50);
   1284    ctx.strokeStyle = '#0f0';
   1285    ctx.lineWidth = 200;
   1286    ctx.lineJoin = 'miter';
   1287    ctx.rect(100, 50, 100, 100);
   1288    ctx.stroke();
   1289    @assert pixel 50,25 == 0,255,0,255;
   1290  expected: green
   1291 
   1292 - name: 2d.path.rect.end.1
   1293  code: |
   1294    ctx.fillStyle = '#f00';
   1295    ctx.fillRect(0, 0, 100, 50);
   1296    ctx.strokeStyle = '#0f0';
   1297    ctx.lineWidth = 100;
   1298    ctx.rect(200, 100, 400, 1000);
   1299    ctx.lineTo(-2000, -1000);
   1300    ctx.stroke();
   1301    @assert pixel 50,25 == 0,255,0,255;
   1302  expected: green
   1303 
   1304 - name: 2d.path.rect.end.2
   1305  code: |
   1306    ctx.fillStyle = '#f00';
   1307    ctx.fillRect(0, 0, 100, 50);
   1308    ctx.strokeStyle = '#0f0';
   1309    ctx.lineWidth = 450;
   1310    ctx.lineCap = 'round';
   1311    ctx.lineJoin = 'bevel';
   1312    ctx.rect(150, 150, 2000, 2000);
   1313    ctx.lineTo(160, 160);
   1314    ctx.stroke();
   1315    @assert pixel 1,1 == 0,255,0,255;
   1316    @assert pixel 98,1 == 0,255,0,255;
   1317    @assert pixel 1,48 == 0,255,0,255;
   1318    @assert pixel 98,48 == 0,255,0,255;
   1319  expected: green
   1320 
   1321 - name: 2d.path.rect.zero.1
   1322  code: |
   1323    ctx.fillStyle = '#f00';
   1324    ctx.fillRect(0, 0, 100, 50);
   1325    ctx.strokeStyle = '#0f0';
   1326    ctx.lineWidth = 100;
   1327    ctx.beginPath();
   1328    ctx.rect(0, 50, 100, 0);
   1329    ctx.stroke();
   1330    @assert pixel 50,25 == 0,255,0,255;
   1331  expected: green
   1332 
   1333 - name: 2d.path.rect.zero.2
   1334  code: |
   1335    ctx.fillStyle = '#f00';
   1336    ctx.fillRect(0, 0, 100, 50);
   1337    ctx.strokeStyle = '#0f0';
   1338    ctx.lineWidth = 100;
   1339    ctx.beginPath();
   1340    ctx.rect(50, -100, 0, 250);
   1341    ctx.stroke();
   1342    @assert pixel 50,25 == 0,255,0,255;
   1343  expected: green
   1344 
   1345 - name: 2d.path.rect.zero.3
   1346  code: |
   1347    ctx.fillStyle = '#0f0';
   1348    ctx.fillRect(0, 0, 100, 50);
   1349    ctx.strokeStyle = '#f00';
   1350    ctx.lineWidth = 100;
   1351    ctx.beginPath();
   1352    ctx.rect(50, 25, 0, 0);
   1353    ctx.stroke();
   1354    @assert pixel 50,25 == 0,255,0,255;
   1355  expected: green
   1356 
   1357 - name: 2d.path.rect.zero.4
   1358  code: |
   1359    ctx.fillStyle = '#f00';
   1360    ctx.fillRect(0, 0, 100, 50);
   1361    ctx.strokeStyle = '#0f0';
   1362    ctx.lineWidth = 50;
   1363    ctx.rect(100, 25, 0, 0);
   1364    ctx.lineTo(0, 25);
   1365    ctx.stroke();
   1366    @assert pixel 50,25 == 0,255,0,255;
   1367  expected: green
   1368 
   1369 - name: 2d.path.rect.zero.5
   1370  code: |
   1371    ctx.fillStyle = '#0f0';
   1372    ctx.fillRect(0, 0, 100, 50);
   1373    ctx.strokeStyle = '#f00';
   1374    ctx.lineWidth = 50;
   1375    ctx.moveTo(0, 0);
   1376    ctx.rect(100, 25, 0, 0);
   1377    ctx.stroke();
   1378    @assert pixel 50,25 == 0,255,0,255;
   1379  expected: green
   1380 
   1381 - name: 2d.path.rect.zero.6
   1382  #mozilla: { bug: TODO }
   1383  code: |
   1384    ctx.fillStyle = '#0f0';
   1385    ctx.fillRect(0, 0, 100, 50);
   1386    ctx.strokeStyle = '#f00';
   1387    ctx.lineJoin = 'miter';
   1388    ctx.miterLimit = 1.5;
   1389    ctx.lineWidth = 200;
   1390    ctx.beginPath();
   1391    ctx.rect(100, 25, 1000, 0);
   1392    ctx.stroke();
   1393    @assert pixel 50,25 == 0,255,0,255; @moz-todo
   1394  expected: green
   1395 
   1396 - name: 2d.path.rect.negative
   1397  code: |
   1398    ctx.fillStyle = '#f00';
   1399    ctx.fillRect(0, 0, 100, 50);
   1400    ctx.beginPath();
   1401    ctx.fillStyle = '#0f0';
   1402    ctx.rect(0, 0, 50, 25);
   1403    ctx.rect(100, 0, -50, 25);
   1404    ctx.rect(0, 50, 50, -25);
   1405    ctx.rect(100, 50, -50, -25);
   1406    ctx.fill();
   1407    @assert pixel 25,12 == 0,255,0,255;
   1408    @assert pixel 75,12 == 0,255,0,255;
   1409    @assert pixel 25,37 == 0,255,0,255;
   1410    @assert pixel 75,37 == 0,255,0,255;
   1411 
   1412 - name: 2d.path.rect.winding
   1413  code: |
   1414    ctx.fillStyle = '#0f0';
   1415    ctx.fillRect(0, 0, 100, 50);
   1416    ctx.beginPath();
   1417    ctx.fillStyle = '#f00';
   1418    ctx.rect(0, 0, 50, 50);
   1419    ctx.rect(100, 50, -50, -50);
   1420    ctx.rect(0, 25, 100, -25);
   1421    ctx.rect(100, 25, -100, 25);
   1422    ctx.fill();
   1423    @assert pixel 25,12 == 0,255,0,255;
   1424    @assert pixel 75,12 == 0,255,0,255;
   1425    @assert pixel 25,37 == 0,255,0,255;
   1426    @assert pixel 75,37 == 0,255,0,255;
   1427 
   1428 - name: 2d.path.rect.selfintersect
   1429  #mozilla: { bug: TODO }
   1430  code: |
   1431    ctx.fillStyle = '#f00';
   1432    ctx.fillRect(0, 0, 100, 50);
   1433    ctx.strokeStyle = '#0f0';
   1434    ctx.lineWidth = 90;
   1435    ctx.beginPath();
   1436    ctx.rect(45, 20, 10, 10);
   1437    ctx.stroke();
   1438    @assert pixel 50,25 == 0,255,0,255; @moz-todo
   1439  expected: green
   1440 
   1441 - name: 2d.path.rect.nonfinite
   1442  desc: rect() with Infinity/NaN is ignored
   1443  code: |
   1444    ctx.moveTo(0, 0);
   1445    ctx.lineTo(100, 0);
   1446    @nonfinite ctx.rect(<0 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>, <1 Infinity -Infinity NaN>, <1 Infinity -Infinity NaN>);
   1447    ctx.lineTo(100, 50);
   1448    ctx.lineTo(0, 50);
   1449    ctx.fillStyle = '#0f0';
   1450    ctx.fill();
   1451    @assert pixel 50,25 == 0,255,0,255;
   1452    @assert pixel 90,45 == 0,255,0,255;
   1453  expected: green
   1454 
   1455 - name: 2d.path.roundrect.newsubpath
   1456  code: |
   1457    ctx.fillStyle = '#0f0';
   1458    ctx.fillRect(0, 0, 100, 50);
   1459    ctx.beginPath();
   1460    ctx.strokeStyle = '#f00';
   1461    ctx.lineWidth = 50;
   1462    ctx.moveTo(-100, 25);
   1463    ctx.lineTo(-50, 25);
   1464    ctx.roundRect(200, 25, 1, 1, [0]);
   1465    ctx.stroke();
   1466    @assert pixel 50,25 == 0,255,0,255;
   1467  expected: green
   1468 
   1469 - name: 2d.path.roundrect.closed
   1470  code: |
   1471    ctx.fillStyle = '#f00';
   1472    ctx.fillRect(0, 0, 100, 50);
   1473    ctx.strokeStyle = '#0f0';
   1474    ctx.lineWidth = 200;
   1475    ctx.lineJoin = 'miter';
   1476    ctx.roundRect(100, 50, 100, 100, [0]);
   1477    ctx.stroke();
   1478    @assert pixel 50,25 == 0,255,0,255;
   1479  expected: green
   1480 
   1481 - name: 2d.path.roundrect.end.1
   1482  code: |
   1483    ctx.fillStyle = '#f00';
   1484    ctx.fillRect(0, 0, 100, 50);
   1485    ctx.strokeStyle = '#0f0';
   1486    ctx.lineWidth = 100;
   1487    ctx.roundRect(200, 100, 400, 1000, [0]);
   1488    ctx.lineTo(-2000, -1000);
   1489    ctx.stroke();
   1490    @assert pixel 50,25 == 0,255,0,255;
   1491  expected: green
   1492 
   1493 - name: 2d.path.roundrect.end.2
   1494  code: |
   1495    ctx.fillStyle = '#f00';
   1496    ctx.fillRect(0, 0, 100, 50);
   1497    ctx.strokeStyle = '#0f0';
   1498    ctx.lineWidth = 450;
   1499    ctx.lineCap = 'round';
   1500    ctx.lineJoin = 'bevel';
   1501    ctx.roundRect(150, 150, 2000, 2000, [0]);
   1502    ctx.lineTo(160, 160);
   1503    ctx.stroke();
   1504    @assert pixel 1,1 == 0,255,0,255;
   1505    @assert pixel 98,1 == 0,255,0,255;
   1506    @assert pixel 1,48 == 0,255,0,255;
   1507    @assert pixel 98,48 == 0,255,0,255;
   1508  expected: green
   1509 
   1510 - name: 2d.path.roundrect.end.3
   1511  code: |
   1512    ctx.fillStyle = '#f00';
   1513    ctx.fillRect(0, 0, 100, 50);
   1514    ctx.strokeStyle = '#0f0';
   1515    ctx.lineWidth = 100;
   1516    ctx.roundRect(101, 51, 2000, 2000, [500, 500, 500, 500]);
   1517    ctx.lineTo(-1, -1);
   1518    ctx.stroke();
   1519    @assert pixel 1,1 == 0,255,0,255;
   1520    @assert pixel 98,1 == 0,255,0,255;
   1521    @assert pixel 1,48 == 0,255,0,255;
   1522    @assert pixel 98,48 == 0,255,0,255;
   1523  expected: green
   1524 
   1525 - name: 2d.path.roundrect.end.4
   1526  code: |
   1527    ctx.fillStyle = '#0f0';
   1528    ctx.fillRect(0, 0, 100, 50);
   1529    ctx.strokeStyle = '#f00';
   1530    ctx.lineWidth = 10;
   1531    ctx.roundRect(-1, -1, 2000, 2000, [1000, 1000, 1000, 1000]);
   1532    ctx.lineTo(-150, -150);
   1533    ctx.stroke();
   1534    @assert pixel 1,1 == 0,255,0,255;
   1535    @assert pixel 98,1 == 0,255,0,255;
   1536    @assert pixel 1,48 == 0,255,0,255;
   1537    @assert pixel 98,48 == 0,255,0,255;
   1538  expected: green
   1539 
   1540 - name: 2d.path.roundrect.zero.1
   1541  code: |
   1542    ctx.fillStyle = '#f00';
   1543    ctx.fillRect(0, 0, 100, 50);
   1544    ctx.strokeStyle = '#0f0';
   1545    ctx.lineWidth = 100;
   1546    ctx.beginPath();
   1547    ctx.roundRect(0, 50, 100, 0, [0]);
   1548    ctx.stroke();
   1549    @assert pixel 50,25 == 0,255,0,255;
   1550  expected: green
   1551 
   1552 - name: 2d.path.roundrect.zero.2
   1553  code: |
   1554    ctx.fillStyle = '#f00';
   1555    ctx.fillRect(0, 0, 100, 50);
   1556    ctx.strokeStyle = '#0f0';
   1557    ctx.lineWidth = 100;
   1558    ctx.beginPath();
   1559    ctx.roundRect(50, -100, 0, 250, [0]);
   1560    ctx.stroke();
   1561    @assert pixel 50,25 == 0,255,0,255;
   1562  expected: green
   1563 
   1564 - name: 2d.path.roundrect.zero.3
   1565  code: |
   1566    ctx.fillStyle = '#0f0';
   1567    ctx.fillRect(0, 0, 100, 50);
   1568    ctx.strokeStyle = '#f00';
   1569    ctx.lineWidth = 100;
   1570    ctx.beginPath();
   1571    ctx.roundRect(50, 25, 0, 0, [0]);
   1572    ctx.stroke();
   1573    @assert pixel 50,25 == 0,255,0,255;
   1574  expected: green
   1575 
   1576 - name: 2d.path.roundrect.zero.4
   1577  code: |
   1578    ctx.fillStyle = '#f00';
   1579    ctx.fillRect(0, 0, 100, 50);
   1580    ctx.strokeStyle = '#0f0';
   1581    ctx.lineWidth = 50;
   1582    ctx.roundRect(100, 25, 0, 0, [0]);
   1583    ctx.lineTo(0, 25);
   1584    ctx.stroke();
   1585    @assert pixel 50,25 == 0,255,0,255;
   1586  expected: green
   1587 
   1588 - name: 2d.path.roundrect.zero.5
   1589  code: |
   1590    ctx.fillStyle = '#0f0';
   1591    ctx.fillRect(0, 0, 100, 50);
   1592    ctx.strokeStyle = '#f00';
   1593    ctx.lineWidth = 50;
   1594    ctx.moveTo(0, 0);
   1595    ctx.roundRect(100, 25, 0, 0, [0]);
   1596    ctx.stroke();
   1597    @assert pixel 50,25 == 0,255,0,255;
   1598  expected: green
   1599 
   1600 - name: 2d.path.roundrect.zero.6
   1601  code: |
   1602    ctx.fillStyle = '#0f0';
   1603    ctx.fillRect(0, 0, 100, 50);
   1604    ctx.strokeStyle = '#f00';
   1605    ctx.lineJoin = 'miter';
   1606    ctx.miterLimit = 1.5;
   1607    ctx.lineWidth = 200;
   1608    ctx.beginPath();
   1609    ctx.roundRect(100, 25, 1000, 0, [0]);
   1610    ctx.stroke();
   1611    @assert pixel 50,25 == 0,255,0,255;
   1612  expected: green
   1613 
   1614 - name: 2d.path.roundrect.negative
   1615  code: |
   1616    ctx.fillStyle = '#f00';
   1617    ctx.fillRect(0, 0, 100, 50);
   1618    ctx.beginPath();
   1619    ctx.fillStyle = '#0f0';
   1620    ctx.roundRect(0, 0, 50, 25, [10, 0, 0, 0]);
   1621    ctx.roundRect(100, 0, -50, 25, [10, 0, 0, 0]);
   1622    ctx.roundRect(0, 50, 50, -25, [10, 0, 0, 0]);
   1623    ctx.roundRect(100, 50, -50, -25, [10, 0, 0, 0]);
   1624    ctx.fill();
   1625    // All rects drawn
   1626    @assert pixel 25,12 == 0,255,0,255;
   1627    @assert pixel 75,12 == 0,255,0,255;
   1628    @assert pixel 25,37 == 0,255,0,255;
   1629    @assert pixel 75,37 == 0,255,0,255;
   1630    // Correct corners are rounded.
   1631    @assert pixel 1,1 == 255,0,0,255;
   1632    @assert pixel 98,1 == 255,0,0,255;
   1633    @assert pixel 1,48 == 255,0,0,255;
   1634    @assert pixel 98,48 == 255,0,0,255;
   1635 
   1636 - name: 2d.path.roundrect.winding
   1637  code: |
   1638    ctx.fillStyle = '#0f0';
   1639    ctx.fillRect(0, 0, 100, 50);
   1640    ctx.beginPath();
   1641    ctx.fillStyle = '#f00';
   1642    ctx.roundRect(0, 0, 50, 50, [0]);
   1643    ctx.roundRect(100, 50, -50, -50, [0]);
   1644    ctx.roundRect(0, 25, 100, -25, [0]);
   1645    ctx.roundRect(100, 25, -100, 25, [0]);
   1646    ctx.fill();
   1647    @assert pixel 25,12 == 0,255,0,255;
   1648    @assert pixel 75,12 == 0,255,0,255;
   1649    @assert pixel 25,37 == 0,255,0,255;
   1650    @assert pixel 75,37 == 0,255,0,255;
   1651 
   1652 - name: 2d.path.roundrect.selfintersect
   1653  code: |
   1654    ctx.fillStyle = '#f00';
   1655    ctx.roundRect(0, 0, 100, 50, [0]);
   1656    ctx.strokeStyle = '#0f0';
   1657    ctx.lineWidth = 90;
   1658    ctx.beginPath();
   1659    ctx.roundRect(45, 20, 10, 10, [0]);
   1660    ctx.stroke();
   1661    @assert pixel 50,25 == 0,255,0,255;
   1662  expected: green
   1663 
   1664 - name: 2d.path.roundrect.nonfinite
   1665  desc: roundRect() with Infinity/NaN is ignored
   1666  code: |
   1667    ctx.fillStyle = '#f00';
   1668    ctx.fillRect(0, 0, 100, 50)
   1669    ctx.moveTo(0, 0);
   1670    ctx.lineTo(100, 0);
   1671    @nonfinite ctx.roundRect(<0 Infinity -Infinity NaN>, <50 Infinity -Infinity NaN>, <1 Infinity -Infinity NaN>, <1 Infinity -Infinity NaN>, <[0] [Infinity] [-Infinity] [NaN] [Infinity,0] [-Infinity,0] [NaN,0] [0,Infinity] [0,-Infinity] [0,NaN] [Infinity,0,0] [-Infinity,0,0] [NaN,0,0] [0,Infinity,0] [0,-Infinity,0] [0,NaN,0] [0,0,Infinity] [0,0,-Infinity] [0,0,NaN] [Infinity,0,0,0] [-Infinity,0,0,0] [NaN,0,0,0] [0,Infinity,0,0] [0,-Infinity,0,0] [0,NaN,0,0] [0,0,Infinity,0] [0,0,-Infinity,0] [0,0,NaN,0] [0,0,0,Infinity] [0,0,0,-Infinity] [0,0,0,NaN]>);
   1672    ctx.roundRect(0, 0, 100, 100, [new DOMPoint(10, Infinity)]);
   1673    ctx.roundRect(0, 0, 100, 100, [new DOMPoint(10, -Infinity)]);
   1674    ctx.roundRect(0, 0, 100, 100, [new DOMPoint(10, NaN)]);
   1675    ctx.roundRect(0, 0, 100, 100, [new DOMPoint(Infinity, 10)]);
   1676    ctx.roundRect(0, 0, 100, 100, [new DOMPoint(-Infinity, 10)]);
   1677    ctx.roundRect(0, 0, 100, 100, [new DOMPoint(NaN, 10)]);
   1678    ctx.roundRect(0, 0, 100, 100, [{x: 10, y: Infinity}]);
   1679    ctx.roundRect(0, 0, 100, 100, [{x: 10, y: -Infinity}]);
   1680    ctx.roundRect(0, 0, 100, 100, [{x: 10, y: NaN}]);
   1681    ctx.roundRect(0, 0, 100, 100, [{x: Infinity, y: 10}]);
   1682    ctx.roundRect(0, 0, 100, 100, [{x: -Infinity, y: 10}]);
   1683    ctx.roundRect(0, 0, 100, 100, [{x: NaN, y: 10}]);
   1684    ctx.lineTo(100, 50);
   1685    ctx.lineTo(0, 50);
   1686    ctx.fillStyle = '#0f0';
   1687    ctx.fill();
   1688    @assert pixel 50,25 == 0,255,0,255;
   1689    @assert pixel 90,45 == 0,255,0,255;
   1690  expected: green
   1691 
   1692 - name: 2d.path.roundrect.4.radii.1.double
   1693  desc: Verify that when four radii are given to roundRect(), the first radius, specified as a double, applies to the top-left corner.
   1694  code: |
   1695    ctx.fillStyle = '#f00';
   1696    ctx.fillRect(0, 0, 100, 50);
   1697    ctx.roundRect(0, 0, 100, 50, [20, 0, 0, 0]);
   1698    ctx.fillStyle = '#0f0';
   1699    ctx.fill();
   1700    @assert pixel 1,1 == 255,0,0,255;
   1701    @assert pixel 98,1 == 0,255,0,255;
   1702    @assert pixel 98,48 == 0,255,0,255;
   1703    @assert pixel 1,48 == 0,255,0,255;
   1704 
   1705 - name: 2d.path.roundrect.4.radii.1.dompoint
   1706  desc: Verify that when four radii are given to roundRect(), the first radius, specified as a DOMPoint, applies to the top-left corner.
   1707  code: |
   1708    ctx.fillStyle = '#f00';
   1709    ctx.fillRect(0, 0, 100, 50);
   1710    ctx.roundRect(0, 0, 100, 50, [new DOMPoint(40, 20), 0, 0, 0]);
   1711    ctx.fillStyle = '#0f0';
   1712    ctx.fill();
   1713 
   1714    // top-left corner
   1715    @assert pixel 20,1 == 255,0,0,255;
   1716    @assert pixel 41,1 == 0,255,0,255;
   1717    @assert pixel 1,10 == 255,0,0,255;
   1718    @assert pixel 1,21 == 0,255,0,255;
   1719 
   1720    // other corners
   1721    @assert pixel 98,1 == 0,255,0,255;
   1722    @assert pixel 98,48 == 0,255,0,255;
   1723    @assert pixel 1,48 == 0,255,0,255;
   1724 
   1725 - name: 2d.path.roundrect.4.radii.1.dompointinit
   1726  desc: Verify that when four radii are given to roundRect(), the first radius, specified as a DOMPointInit, applies to the top-left corner.
   1727  code: |
   1728    ctx.fillStyle = '#f00';
   1729    ctx.fillRect(0, 0, 100, 50);
   1730    ctx.roundRect(0, 0, 100, 50, [{x: 40, y: 20}, 0, 0, 0]);
   1731    ctx.fillStyle = '#0f0';
   1732    ctx.fill();
   1733 
   1734    // top-left corner
   1735    @assert pixel 20,1 == 255,0,0,255;
   1736    @assert pixel 41,1 == 0,255,0,255;
   1737    @assert pixel 1,10 == 255,0,0,255;
   1738    @assert pixel 1,21 == 0,255,0,255;
   1739 
   1740    // other corners
   1741    @assert pixel 98,1 == 0,255,0,255;
   1742    @assert pixel 98,48 == 0,255,0,255;
   1743    @assert pixel 1,48 == 0,255,0,255;
   1744 
   1745 - name: 2d.path.roundrect.4.radii.2.double
   1746  desc: Verify that when four radii are given to roundRect(), the second radius, specified as a double, applies to the top-right corner.
   1747  code: |
   1748    ctx.fillStyle = '#f00';
   1749    ctx.fillRect(0, 0, 100, 50);
   1750    ctx.roundRect(0, 0, 100, 50, [0, 20, 0, 0]);
   1751    ctx.fillStyle = '#0f0';
   1752    ctx.fill();
   1753    @assert pixel 1,1 == 0,255,0,255;
   1754    @assert pixel 98,1 == 255,0,0,255;
   1755    @assert pixel 98,48 == 0,255,0,255;
   1756    @assert pixel 1,48 == 0,255,0,255;
   1757 
   1758 - name: 2d.path.roundrect.4.radii.2.dompoint
   1759  desc: Verify that when four radii are given to roundRect(), the second radius, specified as a DOMPoint, applies to the top-right corner.
   1760  code: |
   1761    ctx.fillStyle = '#f00';
   1762    ctx.fillRect(0, 0, 100, 50);
   1763    ctx.roundRect(0, 0, 100, 50, [0, new DOMPoint(40, 20), 0, 0]);
   1764    ctx.fillStyle = '#0f0';
   1765    ctx.fill();
   1766 
   1767    // top-right corner
   1768    @assert pixel 79,1 == 255,0,0,255;
   1769    @assert pixel 58,1 == 0,255,0,255;
   1770    @assert pixel 98,10 == 255,0,0,255;
   1771    @assert pixel 98,21 == 0,255,0,255;
   1772 
   1773    // other corners
   1774    @assert pixel 1,1 == 0,255,0,255;
   1775    @assert pixel 98,48 == 0,255,0,255;
   1776    @assert pixel 1,48 == 0,255,0,255;
   1777 
   1778 - name: 2d.path.roundrect.4.radii.2.dompointinit
   1779  desc: Verify that when four radii are given to roundRect(), the second radius, specified as a DOMPointInit, applies to the top-right corner.
   1780  code: |
   1781    ctx.fillStyle = '#f00';
   1782    ctx.fillRect(0, 0, 100, 50);
   1783    ctx.roundRect(0, 0, 100, 50, [0, {x: 40, y: 20}, 0, 0]);
   1784    ctx.fillStyle = '#0f0';
   1785    ctx.fill();
   1786 
   1787    // top-right corner
   1788    @assert pixel 79,1 == 255,0,0,255;
   1789    @assert pixel 58,1 == 0,255,0,255;
   1790    @assert pixel 98,10 == 255,0,0,255;
   1791    @assert pixel 98,21 == 0,255,0,255;
   1792 
   1793    // other corners
   1794    @assert pixel 1,1 == 0,255,0,255;
   1795    @assert pixel 98,48 == 0,255,0,255;
   1796    @assert pixel 1,48 == 0,255,0,255;
   1797 
   1798 - name: 2d.path.roundrect.4.radii.3.double
   1799  desc: Verify that when four radii are given to roundRect(), the third radius, specified as a double, applies to the bottom-right corner.
   1800  code: |
   1801    ctx.fillStyle = '#f00';
   1802    ctx.fillRect(0, 0, 100, 50);
   1803    ctx.roundRect(0, 0, 100, 50, [0, 0, 20, 0]);
   1804    ctx.fillStyle = '#0f0';
   1805    ctx.fill();
   1806    @assert pixel 1,1 == 0,255,0,255;
   1807    @assert pixel 98,1 == 0,255,0,255;
   1808    @assert pixel 98,48 == 255,0,0,255;
   1809    @assert pixel 1,48 == 0,255,0,255;
   1810 
   1811 - name: 2d.path.roundrect.4.radii.3.dompoint
   1812  desc: Verify that when four radii are given to roundRect(), the third radius, specified as a DOMPoint, applies to the bottom-right corner.
   1813  code: |
   1814    ctx.fillStyle = '#f00';
   1815    ctx.fillRect(0, 0, 100, 50);
   1816    ctx.roundRect(0, 0, 100, 50, [0, 0, new DOMPoint(40, 20), 0]);
   1817    ctx.fillStyle = '#0f0';
   1818    ctx.fill();
   1819 
   1820    // bottom-right corner
   1821    @assert pixel 79,48 == 255,0,0,255;
   1822    @assert pixel 58,48 == 0,255,0,255;
   1823    @assert pixel 98,39 == 255,0,0,255;
   1824    @assert pixel 98,28 == 0,255,0,255;
   1825 
   1826    // other corners
   1827    @assert pixel 1,1 == 0,255,0,255;
   1828    @assert pixel 98,1 == 0,255,0,255;
   1829    @assert pixel 1,48 == 0,255,0,255;
   1830 
   1831 - name: 2d.path.roundrect.4.radii.3.dompointinit
   1832  desc: Verify that when four radii are given to roundRect(), the third radius, specified as a DOMPointInit, applies to the bottom-right corner.
   1833  code: |
   1834    ctx.fillStyle = '#f00';
   1835    ctx.fillRect(0, 0, 100, 50);
   1836    ctx.roundRect(0, 0, 100, 50, [0, 0, {x: 40, y: 20}, 0]);
   1837    ctx.fillStyle = '#0f0';
   1838    ctx.fill();
   1839 
   1840    // bottom-right corner
   1841    @assert pixel 79,48 == 255,0,0,255;
   1842    @assert pixel 58,48 == 0,255,0,255;
   1843    @assert pixel 98,39 == 255,0,0,255;
   1844    @assert pixel 98,28 == 0,255,0,255;
   1845 
   1846    // other corners
   1847    @assert pixel 1,1 == 0,255,0,255;
   1848    @assert pixel 98,1 == 0,255,0,255;
   1849    @assert pixel 1,48 == 0,255,0,255;
   1850 
   1851 - name: 2d.path.roundrect.4.radii.4.double
   1852  desc: Verify that when four radii are given to roundRect(), the fourth radius, specified as a double, applies to the bottom-left corner.
   1853  code: |
   1854    ctx.fillStyle = '#f00';
   1855    ctx.fillRect(0, 0, 100, 50);
   1856    ctx.roundRect(0, 0, 100, 50, [0, 0, 0, 20]);
   1857    ctx.fillStyle = '#0f0';
   1858    ctx.fill();
   1859    @assert pixel 1,1 == 0,255,0,255;
   1860    @assert pixel 98,1 == 0,255,0,255;
   1861    @assert pixel 98,48 == 0,255,0,255;
   1862    @assert pixel 1,48 == 255,0,0,255;
   1863 
   1864 - name: 2d.path.roundrect.4.radii.4.dompoint
   1865  desc: Verify that when four radii are given to roundRect(), the fourth radius, specified as a DOMPoint, applies to the bottom-left corner.
   1866  code: |
   1867    ctx.fillStyle = '#f00';
   1868    ctx.fillRect(0, 0, 100, 50);
   1869    ctx.roundRect(0, 0, 100, 50, [0, 0, 0, new DOMPoint(40, 20)]);
   1870    ctx.fillStyle = '#0f0';
   1871    ctx.fill();
   1872 
   1873    // bottom-left corner
   1874    @assert pixel 20,48 == 255,0,0,255;
   1875    @assert pixel 41,48 == 0,255,0,255;
   1876    @assert pixel 1,39 == 255,0,0,255;
   1877    @assert pixel 1,28 == 0,255,0,255;
   1878 
   1879    // other corners
   1880    @assert pixel 1,1 == 0,255,0,255;
   1881    @assert pixel 98,1 == 0,255,0,255;
   1882    @assert pixel 98,48 == 0,255,0,255;
   1883 
   1884 - name: 2d.path.roundrect.4.radii.4.dompointinit
   1885  desc: Verify that when four radii are given to roundRect(), the fourth radius, specified as a DOMPointInit, applies to the bottom-left corner.
   1886  code: |
   1887    ctx.fillStyle = '#f00';
   1888    ctx.fillRect(0, 0, 100, 50);
   1889    ctx.roundRect(0, 0, 100, 50, [0, 0, 0, {x: 40, y: 20}]);
   1890    ctx.fillStyle = '#0f0';
   1891    ctx.fill();
   1892 
   1893    // bottom-left corner
   1894    @assert pixel 20,48 == 255,0,0,255;
   1895    @assert pixel 41,48 == 0,255,0,255;
   1896    @assert pixel 1,39 == 255,0,0,255;
   1897    @assert pixel 1,28 == 0,255,0,255;
   1898 
   1899    // other corners
   1900    @assert pixel 1,1 == 0,255,0,255;
   1901    @assert pixel 98,1 == 0,255,0,255;
   1902    @assert pixel 98,48 == 0,255,0,255;
   1903 
   1904 - name: 2d.path.roundrect.3.radii.1.double
   1905  desc: Verify that when three radii are given to roundRect(), the first radius, specified as a double, applies to the top-left corner.
   1906  code: |
   1907    ctx.fillStyle = '#f00';
   1908    ctx.fillRect(0, 0, 100, 50);
   1909    ctx.roundRect(0, 0, 100, 50, [20, 0, 0]);
   1910    ctx.fillStyle = '#0f0';
   1911    ctx.fill();
   1912    @assert pixel 1,1 == 255,0,0,255;
   1913    @assert pixel 98,1 == 0,255,0,255;
   1914    @assert pixel 98,48 == 0,255,0,255;
   1915    @assert pixel 1,48 == 0,255,0,255;
   1916 
   1917 - name: 2d.path.roundrect.3.radii.1.dompoint
   1918  desc: Verify that when three radii are given to roundRect(), the first radius, specified as a DOMPoint, applies to the top-left corner.
   1919  code: |
   1920    ctx.fillStyle = '#f00';
   1921    ctx.fillRect(0, 0, 100, 50);
   1922    ctx.roundRect(0, 0, 100, 50, [new DOMPoint(40, 20), 0, 0]);
   1923    ctx.fillStyle = '#0f0';
   1924    ctx.fill();
   1925 
   1926    // top-left corner
   1927    @assert pixel 20,1 == 255,0,0,255;
   1928    @assert pixel 41,1 == 0,255,0,255;
   1929    @assert pixel 1,10 == 255,0,0,255;
   1930    @assert pixel 1,21 == 0,255,0,255;
   1931 
   1932    // other corners
   1933    @assert pixel 98,1 == 0,255,0,255;
   1934    @assert pixel 98,48 == 0,255,0,255;
   1935    @assert pixel 1,48 == 0,255,0,255;
   1936 
   1937 - name: 2d.path.roundrect.3.radii.1.dompointinit
   1938  desc: Verify that when three radii are given to roundRect(), the first radius, specified as a DOMPointInit, applies to the top-left corner.
   1939  code: |
   1940    ctx.fillStyle = '#f00';
   1941    ctx.fillRect(0, 0, 100, 50);
   1942    ctx.roundRect(0, 0, 100, 50, [{x: 40, y: 20}, 0, 0]);
   1943    ctx.fillStyle = '#0f0';
   1944    ctx.fill();
   1945 
   1946    // top-left corner
   1947    @assert pixel 20,1 == 255,0,0,255;
   1948    @assert pixel 41,1 == 0,255,0,255;
   1949    @assert pixel 1,10 == 255,0,0,255;
   1950    @assert pixel 1,21 == 0,255,0,255;
   1951 
   1952    // other corners
   1953    @assert pixel 98,1 == 0,255,0,255;
   1954    @assert pixel 98,48 == 0,255,0,255;
   1955    @assert pixel 1,48 == 0,255,0,255;
   1956 
   1957 - name: 2d.path.roundrect.3.radii.2.double
   1958  desc: Verify that when three radii are given to roundRect(), the second radius, specified as a double, applies to the top-right and bottom-left corners.
   1959  code: |
   1960    ctx.fillStyle = '#f00';
   1961    ctx.fillRect(0, 0, 100, 50);
   1962    ctx.roundRect(0, 0, 100, 50, [0, 20, 0]);
   1963    ctx.fillStyle = '#0f0';
   1964    ctx.fill();
   1965    @assert pixel 1,1 == 0,255,0,255;
   1966    @assert pixel 98,1 == 255,0,0,255;
   1967    @assert pixel 98,48 == 0,255,0,255;
   1968    @assert pixel 1,48 == 255,0,0,255;
   1969 
   1970 - name: 2d.path.roundrect.3.radii.2.dompoint
   1971  desc: Verify that when three radii are given to roundRect(), the second radius, specified as a DOMPoint, applies to the top-right and bottom-left corners.
   1972  code: |
   1973    ctx.fillStyle = '#f00';
   1974    ctx.fillRect(0, 0, 100, 50);
   1975    ctx.roundRect(0, 0, 100, 50, [0, new DOMPoint(40, 20), 0]);
   1976    ctx.fillStyle = '#0f0';
   1977    ctx.fill();
   1978 
   1979    // top-right corner
   1980    @assert pixel 79,1 == 255,0,0,255;
   1981    @assert pixel 58,1 == 0,255,0,255;
   1982    @assert pixel 98,10 == 255,0,0,255;
   1983    @assert pixel 98,21 == 0,255,0,255;
   1984 
   1985    // bottom-left corner
   1986    @assert pixel 20,48 == 255,0,0,255;
   1987    @assert pixel 41,48 == 0,255,0,255;
   1988    @assert pixel 1,39 == 255,0,0,255;
   1989    @assert pixel 1,28 == 0,255,0,255;
   1990 
   1991    // other corners
   1992    @assert pixel 1,1 == 0,255,0,255;
   1993    @assert pixel 98,48 == 0,255,0,255;
   1994 
   1995 - name: 2d.path.roundrect.3.radii.2.dompointinit
   1996  desc: Verify that when three radii are given to roundRect(), the second radius, specified as a DOMPoint, applies to the top-right and bottom-left corners.
   1997  code: |
   1998    ctx.fillStyle = '#f00';
   1999    ctx.fillRect(0, 0, 100, 50);
   2000    ctx.roundRect(0, 0, 100, 50, [0, {x: 40, y: 20}, 0]);
   2001    ctx.fillStyle = '#0f0';
   2002    ctx.fill();
   2003 
   2004    // top-right corner
   2005    @assert pixel 79,1 == 255,0,0,255;
   2006    @assert pixel 58,1 == 0,255,0,255;
   2007    @assert pixel 98,10 == 255,0,0,255;
   2008    @assert pixel 98,21 == 0,255,0,255;
   2009 
   2010    // bottom-left corner
   2011    @assert pixel 20,48 == 255,0,0,255;
   2012    @assert pixel 41,48 == 0,255,0,255;
   2013    @assert pixel 1,39 == 255,0,0,255;
   2014    @assert pixel 1,28 == 0,255,0,255;
   2015 
   2016    // other corners
   2017    @assert pixel 1,1 == 0,255,0,255;
   2018    @assert pixel 98,48 == 0,255,0,255;
   2019 
   2020 - name: 2d.path.roundrect.3.radii.3.double
   2021  desc: Verify that when three radii are given to roundRect(), the third radius, specified as a double, applies to the bottom-right corner.
   2022  code: |
   2023    ctx.fillStyle = '#f00';
   2024    ctx.fillRect(0, 0, 100, 50);
   2025    ctx.roundRect(0, 0, 100, 50, [0, 0, 20]);
   2026    ctx.fillStyle = '#0f0';
   2027    ctx.fill();
   2028    @assert pixel 1,1 == 0,255,0,255;
   2029    @assert pixel 98,1 == 0,255,0,255;
   2030    @assert pixel 98,48 == 255,0,0,255;
   2031    @assert pixel 1,48 == 0,255,0,255;
   2032 
   2033 - name: 2d.path.roundrect.3.radii.3.dompoint
   2034  desc: Verify that when three radii are given to roundRect(), the third radius, specified as a DOMPoint, applies to the bottom-right corner.
   2035  code: |
   2036    ctx.fillStyle = '#f00';
   2037    ctx.fillRect(0, 0, 100, 50);
   2038    ctx.roundRect(0, 0, 100, 50, [0, 0, new DOMPoint(40, 20)]);
   2039    ctx.fillStyle = '#0f0';
   2040    ctx.fill();
   2041 
   2042    // bottom-right corner
   2043    @assert pixel 79,48 == 255,0,0,255;
   2044    @assert pixel 58,48 == 0,255,0,255;
   2045    @assert pixel 98,39 == 255,0,0,255;
   2046    @assert pixel 98,28 == 0,255,0,255;
   2047 
   2048    // other corners
   2049    @assert pixel 1,1 == 0,255,0,255;
   2050    @assert pixel 98,1 == 0,255,0,255;
   2051    @assert pixel 1,48 == 0,255,0,255;
   2052 
   2053 - name: 2d.path.roundrect.3.radii.3.dompointinit
   2054  desc: Verify that when three radii are given to roundRect(), the third radius, specified as a DOMPointInit, applies to the bottom-right corner.
   2055  code: |
   2056    ctx.fillStyle = '#f00';
   2057    ctx.fillRect(0, 0, 100, 50);
   2058    ctx.roundRect(0, 0, 100, 50, [0, 0, {x: 40, y: 20}]);
   2059    ctx.fillStyle = '#0f0';
   2060    ctx.fill();
   2061 
   2062    // bottom-right corner
   2063    @assert pixel 79,48 == 255,0,0,255;
   2064    @assert pixel 58,48 == 0,255,0,255;
   2065    @assert pixel 98,39 == 255,0,0,255;
   2066    @assert pixel 98,28 == 0,255,0,255;
   2067 
   2068    // other corners
   2069    @assert pixel 1,1 == 0,255,0,255;
   2070    @assert pixel 98,1 == 0,255,0,255;
   2071    @assert pixel 1,48 == 0,255,0,255;
   2072 
   2073 - name: 2d.path.roundrect.2.radii.1.double
   2074  desc: Verify that when two radii are given to roundRect(), the first radius, specified as a double, applies to the top-left and bottom-right corners.
   2075  code: |
   2076    ctx.fillStyle = '#f00';
   2077    ctx.fillRect(0, 0, 100, 50);
   2078    ctx.roundRect(0, 0, 100, 50, [20, 0]);
   2079    ctx.fillStyle = '#0f0';
   2080    ctx.fill();
   2081    @assert pixel 1,1 == 255,0,0,255;
   2082    @assert pixel 98,1 == 0,255,0,255;
   2083    @assert pixel 98,48 == 255,0,0,255;
   2084    @assert pixel 1,48 == 0,255,0,255;
   2085 
   2086 - name: 2d.path.roundrect.2.radii.1.dompoint
   2087  desc: Verify that when two radii are given to roundRect(), the first radius, specified as a DOMPoint, applies to the top-left and bottom-right corners.
   2088  code: |
   2089    ctx.fillStyle = '#f00';
   2090    ctx.fillRect(0, 0, 100, 50);
   2091    ctx.roundRect(0, 0, 100, 50, [new DOMPoint(40, 20), 0]);
   2092    ctx.fillStyle = '#0f0';
   2093    ctx.fill();
   2094 
   2095    // top-left corner
   2096    @assert pixel 20,1 == 255,0,0,255;
   2097    @assert pixel 41,1 == 0,255,0,255;
   2098    @assert pixel 1,10 == 255,0,0,255;
   2099    @assert pixel 1,21 == 0,255,0,255;
   2100 
   2101    // bottom-right corner
   2102    @assert pixel 79,48 == 255,0,0,255;
   2103    @assert pixel 58,48 == 0,255,0,255;
   2104    @assert pixel 98,39 == 255,0,0,255;
   2105    @assert pixel 98,28 == 0,255,0,255;
   2106 
   2107    // other corners
   2108    @assert pixel 98,1 == 0,255,0,255;
   2109    @assert pixel 1,48 == 0,255,0,255;
   2110 
   2111 - name: 2d.path.roundrect.2.radii.1.dompointinit
   2112  desc: Verify that when two radii are given to roundRect(), the first radius, specified as a DOMPointInit, applies to the top-left and bottom-right corners.
   2113  code: |
   2114    ctx.fillStyle = '#f00';
   2115    ctx.fillRect(0, 0, 100, 50);
   2116    ctx.roundRect(0, 0, 100, 50, [{x: 40, y: 20}, 0]);
   2117    ctx.fillStyle = '#0f0';
   2118    ctx.fill();
   2119 
   2120    // top-left corner
   2121    @assert pixel 20,1 == 255,0,0,255;
   2122    @assert pixel 41,1 == 0,255,0,255;
   2123    @assert pixel 1,10 == 255,0,0,255;
   2124    @assert pixel 1,21 == 0,255,0,255;
   2125 
   2126    // bottom-right corner
   2127    @assert pixel 79,48 == 255,0,0,255;
   2128    @assert pixel 58,48 == 0,255,0,255;
   2129    @assert pixel 98,39 == 255,0,0,255;
   2130    @assert pixel 98,28 == 0,255,0,255;
   2131 
   2132    // other corners
   2133    @assert pixel 98,1 == 0,255,0,255;
   2134    @assert pixel 1,48 == 0,255,0,255;
   2135 
   2136 - name: 2d.path.roundrect.2.radii.2.double
   2137  desc: Verify that when two radii are given to roundRect(), the second radius, specified as a double, applies to the top-right and bottom-left corners.
   2138  code: |
   2139    ctx.fillStyle = '#f00';
   2140    ctx.fillRect(0, 0, 100, 50);
   2141    ctx.roundRect(0, 0, 100, 50, [0, 20]);
   2142    ctx.fillStyle = '#0f0';
   2143    ctx.fill();
   2144    @assert pixel 1,1 == 0,255,0,255;
   2145    @assert pixel 98,1 == 255,0,0,255;
   2146    @assert pixel 98,48 == 0,255,0,255;
   2147    @assert pixel 1,48 == 255,0,0,255;
   2148 
   2149 - name: 2d.path.roundrect.2.radii.2.dompoint
   2150  desc: Verify that when two radii are given to roundRect(), the second radius, specified as a DOMPoint, applies to the top-right and bottom-left corners.
   2151  code: |
   2152    ctx.fillStyle = '#f00';
   2153    ctx.fillRect(0, 0, 100, 50);
   2154    ctx.roundRect(0, 0, 100, 50, [0, new DOMPoint(40, 20)]);
   2155    ctx.fillStyle = '#0f0';
   2156    ctx.fill();
   2157 
   2158    // top-right corner
   2159    @assert pixel 79,1 == 255,0,0,255;
   2160    @assert pixel 58,1 == 0,255,0,255;
   2161    @assert pixel 98,10 == 255,0,0,255;
   2162    @assert pixel 98,21 == 0,255,0,255;
   2163 
   2164    // bottom-left corner
   2165    @assert pixel 20,48 == 255,0,0,255;
   2166    @assert pixel 41,48 == 0,255,0,255;
   2167    @assert pixel 1,39 == 255,0,0,255;
   2168    @assert pixel 1,28 == 0,255,0,255;
   2169 
   2170    // other corners
   2171    @assert pixel 1,1 == 0,255,0,255;
   2172    @assert pixel 98,48 == 0,255,0,255;
   2173 
   2174 - name: 2d.path.roundrect.2.radii.2.dompointinit
   2175  desc: Verify that when two radii are given to roundRect(), the second radius, specified as a DOMPointInit, applies to the top-right and bottom-left corners.
   2176  code: |
   2177    ctx.fillStyle = '#f00';
   2178    ctx.fillRect(0, 0, 100, 50);
   2179    ctx.roundRect(0, 0, 100, 50, [0, {x: 40, y: 20}]);
   2180    ctx.fillStyle = '#0f0';
   2181    ctx.fill();
   2182 
   2183    // top-right corner
   2184    @assert pixel 79,1 == 255,0,0,255;
   2185    @assert pixel 58,1 == 0,255,0,255;
   2186    @assert pixel 98,10 == 255,0,0,255;
   2187    @assert pixel 98,21 == 0,255,0,255;
   2188 
   2189    // bottom-left corner
   2190    @assert pixel 20,48 == 255,0,0,255;
   2191    @assert pixel 41,48 == 0,255,0,255;
   2192    @assert pixel 1,39 == 255,0,0,255;
   2193    @assert pixel 1,28 == 0,255,0,255;
   2194 
   2195    // other corners
   2196    @assert pixel 1,1 == 0,255,0,255;
   2197    @assert pixel 98,48 == 0,255,0,255;
   2198 
   2199 - name: 2d.path.roundrect.1.radius.double
   2200  desc: Verify that when one radius is given to roundRect(), specified as a double, it applies to all corners.
   2201  code: |
   2202    ctx.fillStyle = '#f00';
   2203    ctx.fillRect(0, 0, 100, 50);
   2204    ctx.roundRect(0, 0, 100, 50, [20]);
   2205    ctx.fillStyle = '#0f0';
   2206    ctx.fill();
   2207    @assert pixel 1,1 == 255,0,0,255;
   2208    @assert pixel 98,1 == 255,0,0,255;
   2209    @assert pixel 98,48 == 255,0,0,255;
   2210    @assert pixel 1,48 == 255,0,0,255;
   2211 
   2212 - name: 2d.path.roundrect.1.radius.double.single.argument
   2213  desc: Verify that when one radius is given to roundRect() as a non-array argument, specified as a double, it applies to all corners.
   2214  code: |
   2215    ctx.fillStyle = '#f00';
   2216    ctx.fillRect(0, 0, 100, 50);
   2217    ctx.roundRect(0, 0, 100, 50, 20);
   2218    ctx.fillStyle = '#0f0';
   2219    ctx.fill();
   2220    @assert pixel 1,1 == 255,0,0,255;
   2221    @assert pixel 98,1 == 255,0,0,255;
   2222    @assert pixel 98,48 == 255,0,0,255;
   2223    @assert pixel 1,48 == 255,0,0,255;
   2224 
   2225 - name: 2d.path.roundrect.1.radius.dompoint
   2226  desc: Verify that when one radius is given to roundRect(), specified as a DOMPoint, it applies to all corners.
   2227  code: |
   2228    ctx.fillStyle = '#f00';
   2229    ctx.fillRect(0, 0, 100, 50);
   2230    ctx.roundRect(0, 0, 100, 50, [new DOMPoint(40, 20)]);
   2231    ctx.fillStyle = '#0f0';
   2232    ctx.fill();
   2233 
   2234    // top-left corner
   2235    @assert pixel 20,1 == 255,0,0,255;
   2236    @assert pixel 41,1 == 0,255,0,255;
   2237    @assert pixel 1,10 == 255,0,0,255;
   2238    @assert pixel 1,21 == 0,255,0,255;
   2239 
   2240    // top-right corner
   2241    @assert pixel 79,1 == 255,0,0,255;
   2242    @assert pixel 58,1 == 0,255,0,255;
   2243    @assert pixel 98,10 == 255,0,0,255;
   2244    @assert pixel 98,21 == 0,255,0,255;
   2245 
   2246    // bottom-right corner
   2247    @assert pixel 79,48 == 255,0,0,255;
   2248    @assert pixel 58,48 == 0,255,0,255;
   2249    @assert pixel 98,39 == 255,0,0,255;
   2250    @assert pixel 98,28 == 0,255,0,255;
   2251 
   2252    // bottom-left corner
   2253    @assert pixel 20,48 == 255,0,0,255;
   2254    @assert pixel 41,48 == 0,255,0,255;
   2255    @assert pixel 1,39 == 255,0,0,255;
   2256    @assert pixel 1,28 == 0,255,0,255;
   2257 
   2258 - name: 2d.path.roundrect.1.radius.dompoint.single.argument
   2259  desc: Verify that when one radius is given to roundRect() as a non-array argument, specified as a DOMPoint, it applies to all corners.
   2260  code: |
   2261    ctx.fillStyle = '#f00';
   2262    ctx.fillRect(0, 0, 100, 50);
   2263    ctx.roundRect(0, 0, 100, 50, new DOMPoint(40, 20));
   2264    ctx.fillStyle = '#0f0';
   2265    ctx.fill();
   2266 
   2267    // top-left corner
   2268    @assert pixel 20,1 == 255,0,0,255;
   2269    @assert pixel 41,1 == 0,255,0,255;
   2270    @assert pixel 1,10 == 255,0,0,255;
   2271    @assert pixel 1,21 == 0,255,0,255;
   2272 
   2273    // top-right corner
   2274    @assert pixel 79,1 == 255,0,0,255;
   2275    @assert pixel 58,1 == 0,255,0,255;
   2276    @assert pixel 98,10 == 255,0,0,255;
   2277    @assert pixel 98,21 == 0,255,0,255;
   2278 
   2279    // bottom-right corner
   2280    @assert pixel 79,48 == 255,0,0,255;
   2281    @assert pixel 58,48 == 0,255,0,255;
   2282    @assert pixel 98,39 == 255,0,0,255;
   2283    @assert pixel 98,28 == 0,255,0,255;
   2284 
   2285    // bottom-left corner
   2286    @assert pixel 20,48 == 255,0,0,255;
   2287    @assert pixel 41,48 == 0,255,0,255;
   2288    @assert pixel 1,39 == 255,0,0,255;
   2289    @assert pixel 1,28 == 0,255,0,255;
   2290 
   2291 - name: 2d.path.roundrect.1.radius.dompointinit
   2292  desc: Verify that when one radius is given to roundRect(), specified as a DOMPointInit, applies to all corners.
   2293  code: |
   2294    ctx.fillStyle = '#f00';
   2295    ctx.fillRect(0, 0, 100, 50);
   2296    ctx.roundRect(0, 0, 100, 50, [{x: 40, y: 20}]);
   2297    ctx.fillStyle = '#0f0';
   2298    ctx.fill();
   2299 
   2300    // top-left corner
   2301    @assert pixel 20,1 == 255,0,0,255;
   2302    @assert pixel 41,1 == 0,255,0,255;
   2303    @assert pixel 1,10 == 255,0,0,255;
   2304    @assert pixel 1,21 == 0,255,0,255;
   2305 
   2306    // top-right corner
   2307    @assert pixel 79,1 == 255,0,0,255;
   2308    @assert pixel 58,1 == 0,255,0,255;
   2309    @assert pixel 98,10 == 255,0,0,255;
   2310    @assert pixel 98,21 == 0,255,0,255;
   2311 
   2312    // bottom-right corner
   2313    @assert pixel 79,48 == 255,0,0,255;
   2314    @assert pixel 58,48 == 0,255,0,255;
   2315    @assert pixel 98,39 == 255,0,0,255;
   2316    @assert pixel 98,28 == 0,255,0,255;
   2317 
   2318    // bottom-left corner
   2319    @assert pixel 20,48 == 255,0,0,255;
   2320    @assert pixel 41,48 == 0,255,0,255;
   2321    @assert pixel 1,39 == 255,0,0,255;
   2322    @assert pixel 1,28 == 0,255,0,255;
   2323 
   2324 - name: 2d.path.roundrect.1.radius.dompointinit.single.argument
   2325  desc: Verify that when one radius is given to roundRect() as a non-array argument, specified as a DOMPointInit, applies to all corners.
   2326  code: |
   2327    ctx.fillStyle = '#f00';
   2328    ctx.fillRect(0, 0, 100, 50);
   2329    ctx.roundRect(0, 0, 100, 50, {x: 40, y: 20});
   2330    ctx.fillStyle = '#0f0';
   2331    ctx.fill();
   2332 
   2333    // top-left corner
   2334    @assert pixel 20,1 == 255,0,0,255;
   2335    @assert pixel 41,1 == 0,255,0,255;
   2336    @assert pixel 1,10 == 255,0,0,255;
   2337    @assert pixel 1,21 == 0,255,0,255;
   2338 
   2339    // top-right corner
   2340    @assert pixel 79,1 == 255,0,0,255;
   2341    @assert pixel 58,1 == 0,255,0,255;
   2342    @assert pixel 98,10 == 255,0,0,255;
   2343    @assert pixel 98,21 == 0,255,0,255;
   2344 
   2345    // bottom-right corner
   2346    @assert pixel 79,48 == 255,0,0,255;
   2347    @assert pixel 58,48 == 0,255,0,255;
   2348    @assert pixel 98,39 == 255,0,0,255;
   2349    @assert pixel 98,28 == 0,255,0,255;
   2350 
   2351    // bottom-left corner
   2352    @assert pixel 20,48 == 255,0,0,255;
   2353    @assert pixel 41,48 == 0,255,0,255;
   2354    @assert pixel 1,39 == 255,0,0,255;
   2355    @assert pixel 1,28 == 0,255,0,255;
   2356 
   2357 - name: 2d.path.roundrect.radius.intersecting.1
   2358  desc: Check that roundRects with intersecting corner arcs are rendered correctly.
   2359  code: |
   2360    ctx.fillStyle = '#f00';
   2361    ctx.fillRect(0, 0, 100, 50);
   2362    ctx.roundRect(0, 0, 100, 50, [40, 40, 40, 40]);
   2363    ctx.fillStyle = '#0f0';
   2364    ctx.fill();
   2365    @assert pixel 2,25 == 0,255,0,255;
   2366    @assert pixel 50,1 == 0,255,0,255;
   2367    @assert pixel 50,25 == 0,255,0,255;
   2368    @assert pixel 50,48 == 0,255,0,255;
   2369    @assert pixel 97,25 == 0,255,0,255;
   2370    @assert pixel 1,1 == 255,0,0,255;
   2371    @assert pixel 98,1 == 255,0,0,255;
   2372    @assert pixel 1,48 == 255,0,0,255;
   2373    @assert pixel 98,48 == 255,0,0,255;
   2374 
   2375 - name: 2d.path.roundrect.radius.intersecting.2
   2376  desc: Check that roundRects with intersecting corner arcs are rendered correctly.
   2377  code: |
   2378    ctx.fillStyle = '#f00';
   2379    ctx.fillRect(0, 0, 100, 50);
   2380    ctx.roundRect(0, 0, 100, 50, [1000, 1000, 1000, 1000]);
   2381    ctx.fillStyle = '#0f0';
   2382    ctx.fill();
   2383    @assert pixel 2,25 == 0,255,0,255;
   2384    @assert pixel 50,1 == 0,255,0,255;
   2385    @assert pixel 50,25 == 0,255,0,255;
   2386    @assert pixel 50,48 == 0,255,0,255;
   2387    @assert pixel 97,25 == 0,255,0,255;
   2388    @assert pixel 1,1 == 255,0,0,255;
   2389    @assert pixel 98,1 == 255,0,0,255;
   2390    @assert pixel 1,48 == 255,0,0,255;
   2391    @assert pixel 98,48 == 255,0,0,255;
   2392 
   2393 - name: 2d.path.roundrect.radius.none
   2394  desc: Check that roundRect throws an RangeError if radii is an empty array.
   2395  code: |
   2396    assert_throws_js(RangeError, () => { ctx.roundRect(0, 0, 100, 50, [])});
   2397 
   2398 - name: 2d.path.roundrect.radius.noargument
   2399  desc: Check that roundRect draws a rectangle when no radii are provided.
   2400  code: |
   2401    ctx.fillStyle = '#f00';
   2402    ctx.fillRect(0, 0, 100, 50);
   2403    ctx.roundRect(10, 10, 80, 30);
   2404    ctx.fillStyle = '#0f0';
   2405    ctx.fill();
   2406    // upper left corner (10, 10)
   2407    @assert pixel 10,9 == 255,0,0,255;
   2408    @assert pixel 9,10 == 255,0,0,255;
   2409    @assert pixel 10,10 == 0,255,0,255;
   2410 
   2411    // upper right corner (89, 10)
   2412    @assert pixel 90,10 == 255,0,0,255;
   2413    @assert pixel 89,9 == 255,0,0,255;
   2414    @assert pixel 89,10 == 0,255,0,255;
   2415 
   2416    // lower right corner (89, 39)
   2417    @assert pixel 89,40 == 255,0,0,255;
   2418    @assert pixel 90,39 == 255,0,0,255;
   2419    @assert pixel 89,39 == 0,255,0,255;
   2420 
   2421    // lower left corner (10, 30)
   2422    @assert pixel 9,39 == 255,0,0,255;
   2423    @assert pixel 10,40 == 255,0,0,255;
   2424    @assert pixel 10,39 == 0,255,0,255;
   2425 
   2426 - name: 2d.path.roundrect.radius.toomany
   2427  desc: Check that roundRect throws an IndeSizeError if radii has more than four items.
   2428  code: |
   2429    assert_throws_js(RangeError, () => { ctx.roundRect(0, 0, 100, 50, [0, 0, 0, 0, 0])});
   2430 
   2431 - name: 2d.path.roundrect.radius.negative
   2432  desc: roundRect() with negative radius throws an exception
   2433  code: |
   2434    assert_throws_js(RangeError, () => { ctx.roundRect(0, 0, 0, 0, [-1])});
   2435    assert_throws_js(RangeError, () => { ctx.roundRect(0, 0, 0, 0, [1, -1])});
   2436    assert_throws_js(RangeError, () => { ctx.roundRect(0, 0, 0, 0, [new DOMPoint(-1, 1), 1])});
   2437    assert_throws_js(RangeError, () => { ctx.roundRect(0, 0, 0, 0, [new DOMPoint(1, -1)])});
   2438    assert_throws_js(RangeError, () => { ctx.roundRect(0, 0, 0, 0, [{x: -1, y: 1}, 1])});
   2439    assert_throws_js(RangeError, () => { ctx.roundRect(0, 0, 0, 0, [{x: 1, y: -1}])});
   2440 
   2441 - name: 2d.path.roundrect.badinput
   2442  desc: roundRect() throws or does not throw errors given the strange inputs.
   2443  code: |
   2444    ctx.roundRect(0, 0, 100, 100, { foo: "bar" });  //=> DOMPointInit
   2445    ctx.roundRect(0, 0, 100, 100, undefined);       //=> "missing" -> 0
   2446    ctx.roundRect(0, 0, 100, 100, [[]]);            //=> « DOMPointInit »
   2447    ctx.roundRect(0, 0, 100, 100, [[25]]);          //=> « DOMPointInit »
   2448    ctx.roundRect(0, 0, 100, 100, [undefined]);     //=> « DOMPointInit »
   2449    @assert throws TypeError ctx.roundRect(0, 0, 100, 100, 0n);
   2450    @assert throws TypeError ctx.roundRect(0, 0, 100, 100, { x: 0n });
   2451    @assert throws TypeError ctx.roundRect(0, 0, 100, 100, [{ x: 0n }]);
   2452 
   2453 - name: 2d.path.ellipse.basics
   2454  desc: Verify canvas throws error when drawing ellipse with negative radii.
   2455  code: |
   2456    ctx.ellipse(10, 10, 10, 5, 0, 0, 1, false);
   2457    ctx.ellipse(10, 10, 10, 0, 0, 0, 1, false);
   2458    ctx.ellipse(10, 10, -0, 5, 0, 0, 1, false);
   2459    @assert throws INDEX_SIZE_ERR ctx.ellipse(10, 10, -2, 5, 0, 0, 1, false);
   2460    @assert throws INDEX_SIZE_ERR ctx.ellipse(10, 10, 0, -1.5, 0, 0, 1, false);
   2461    @assert throws INDEX_SIZE_ERR ctx.ellipse(10, 10, -2, -5, 0, 0, 1, false);
   2462    ctx.ellipse(80, 0, 10, 4294967277, Math.PI / -84, -Math.PI / 2147483436, false);
   2463 
   2464 - name: 2d.path.fill.overlap
   2465  code: |
   2466    ctx.fillStyle = '#000';
   2467    ctx.fillRect(0, 0, 100, 50);
   2468 
   2469    ctx.fillStyle = 'rgba(0, 255, 0, 0.5)';
   2470    ctx.rect(0, 0, 100, 50);
   2471    ctx.closePath();
   2472    ctx.rect(10, 10, 80, 30);
   2473    ctx.fill();
   2474 
   2475    @assert pixel 50,25 ==~ 0,127,0,255 +/- 1;
   2476  expected: |
   2477    size 100 50
   2478    cr.set_source_rgb(0, 0.5, 0)
   2479    cr.rectangle(0, 0, 100, 50)
   2480    cr.fill()
   2481 
   2482 - name: 2d.path.fill.winding.evenodd.1
   2483  desc: evenodd winding number rule works in fill
   2484  code: |
   2485    ctx.fillStyle = '#0f0';
   2486    ctx.fillRect(0, 0, 100, 50);
   2487 
   2488    ctx.beginPath();
   2489    ctx.rect(0, 0, 100, 50);
   2490    ctx.rect(0, 0, 100, 50);
   2491 
   2492    ctx.fillStyle = "#f00";
   2493    ctx.fill("evenodd");
   2494 
   2495    @assert pixel 50,25 == 0,255,0,255;
   2496 
   2497 - name: 2d.path.fill.winding.evenodd.2
   2498  desc: evenodd winding number rule works in fill
   2499  code: |
   2500    ctx.fillStyle = '#0f0';
   2501    ctx.fillRect(0, 0, 100, 50);
   2502 
   2503    let path = new Path2D();
   2504    path.rect(0, 0, 100, 50);
   2505    path.rect(0, 0, 100, 50);
   2506    path.closePath();
   2507 
   2508    ctx.fillStyle = "#f00";
   2509    ctx.fill(path, "evenodd");
   2510 
   2511    @assert pixel 50,25 == 0,255,0,255;
   2512 
   2513 - name: 2d.path.fill.winding.add
   2514  code: |
   2515    ctx.fillStyle = '#f00';
   2516    ctx.fillRect(0, 0, 100, 50);
   2517 
   2518    ctx.fillStyle = '#0f0';
   2519    ctx.moveTo(-10, -10);
   2520    ctx.lineTo(110, -10);
   2521    ctx.lineTo(110, 60);
   2522    ctx.lineTo(-10, 60);
   2523    ctx.lineTo(-10, -10);
   2524    ctx.lineTo(0, 0);
   2525    ctx.lineTo(100, 0);
   2526    ctx.lineTo(100, 50);
   2527    ctx.lineTo(0, 50);
   2528    ctx.fill();
   2529 
   2530    @assert pixel 50,25 == 0,255,0,255;
   2531  expected: green
   2532 
   2533 - name: 2d.path.fill.winding.subtract.1
   2534  code: |
   2535    ctx.fillStyle = '#0f0';
   2536    ctx.fillRect(0, 0, 100, 50);
   2537 
   2538    ctx.fillStyle = '#f00';
   2539    ctx.moveTo(-10, -10);
   2540    ctx.lineTo(110, -10);
   2541    ctx.lineTo(110, 60);
   2542    ctx.lineTo(-10, 60);
   2543    ctx.lineTo(-10, -10);
   2544    ctx.lineTo(0, 0);
   2545    ctx.lineTo(0, 50);
   2546    ctx.lineTo(100, 50);
   2547    ctx.lineTo(100, 0);
   2548    ctx.fill();
   2549 
   2550    @assert pixel 50,25 == 0,255,0,255;
   2551  expected: green
   2552 
   2553 - name: 2d.path.fill.winding.subtract.2
   2554  code: |
   2555    ctx.fillStyle = '#0f0';
   2556    ctx.fillRect(0, 0, 100, 50);
   2557 
   2558    ctx.fillStyle = '#f00';
   2559    ctx.moveTo(-10, -10);
   2560    ctx.lineTo(110, -10);
   2561    ctx.lineTo(110, 60);
   2562    ctx.lineTo(-10, 60);
   2563    ctx.moveTo(0, 0);
   2564    ctx.lineTo(0, 50);
   2565    ctx.lineTo(100, 50);
   2566    ctx.lineTo(100, 0);
   2567    ctx.fill();
   2568 
   2569    @assert pixel 50,25 == 0,255,0,255;
   2570  expected: green
   2571 
   2572 - name: 2d.path.fill.winding.subtract.3
   2573  code: |
   2574    ctx.fillStyle = '#f00';
   2575    ctx.fillRect(0, 0, 100, 50);
   2576 
   2577    ctx.fillStyle = '#0f0';
   2578    ctx.moveTo(-10, -10);
   2579    ctx.lineTo(110, -10);
   2580    ctx.lineTo(110, 60);
   2581    ctx.lineTo(-10, 60);
   2582    ctx.lineTo(-10, -10);
   2583    ctx.lineTo(-20, -20);
   2584    ctx.lineTo(120, -20);
   2585    ctx.lineTo(120, 70);
   2586    ctx.lineTo(-20, 70);
   2587    ctx.lineTo(-20, -20);
   2588    ctx.lineTo(0, 0);
   2589    ctx.lineTo(0, 50);
   2590    ctx.lineTo(100, 50);
   2591    ctx.lineTo(100, 0);
   2592    ctx.fill();
   2593 
   2594    @assert pixel 50,25 == 0,255,0,255;
   2595  expected: green
   2596 
   2597 - name: 2d.path.fill.closed.basic
   2598  code: |
   2599    ctx.fillStyle = '#f00';
   2600    ctx.fillRect(0, 0, 100, 50);
   2601 
   2602    ctx.fillStyle = '#0f0';
   2603    ctx.moveTo(0, 0);
   2604    ctx.lineTo(100, 0);
   2605    ctx.lineTo(100, 50);
   2606    ctx.lineTo(0, 50);
   2607    ctx.fill();
   2608 
   2609    @assert pixel 50,25 == 0,255,0,255;
   2610  expected: green
   2611 
   2612 - name: 2d.path.fill.closed.unaffected
   2613  code: |
   2614    ctx.fillStyle = '#00f';
   2615    ctx.fillRect(0, 0, 100, 50);
   2616 
   2617    ctx.moveTo(0, 0);
   2618    ctx.lineTo(100, 0);
   2619    ctx.lineTo(100, 50);
   2620    ctx.fillStyle = '#f00';
   2621    ctx.fill();
   2622    ctx.lineTo(0, 50);
   2623    ctx.fillStyle = '#0f0';
   2624    ctx.fill();
   2625 
   2626    @assert pixel 90,10 == 0,255,0,255;
   2627    @assert pixel 10,40 == 0,255,0,255;
   2628  expected: green
   2629 
   2630 - name: 2d.path.stroke.overlap
   2631  desc: Stroked subpaths are combined before being drawn
   2632  code: |
   2633    ctx.fillStyle = '#000';
   2634    ctx.fillRect(0, 0, 100, 50);
   2635 
   2636    ctx.strokeStyle = 'rgba(0, 255, 0, 0.5)';
   2637    ctx.lineWidth = 50;
   2638    ctx.moveTo(0, 20);
   2639    ctx.lineTo(100, 20);
   2640    ctx.moveTo(0, 30);
   2641    ctx.lineTo(100, 30);
   2642    ctx.stroke();
   2643 
   2644    @assert pixel 50,25 ==~ 0,127,0,255 +/- 1;
   2645  expected: |
   2646    size 100 50
   2647    cr.set_source_rgb(0, 0.5, 0)
   2648    cr.rectangle(0, 0, 100, 50)
   2649    cr.fill()
   2650 
   2651 - name: 2d.path.stroke.union
   2652  desc: Strokes in opposite directions are unioned, not subtracted
   2653  code: |
   2654    ctx.fillStyle = '#f00';
   2655    ctx.fillRect(0, 0, 100, 50);
   2656 
   2657    ctx.strokeStyle = '#0f0';
   2658    ctx.lineWidth = 40;
   2659    ctx.moveTo(0, 10);
   2660    ctx.lineTo(100, 10);
   2661    ctx.moveTo(100, 40);
   2662    ctx.lineTo(0, 40);
   2663    ctx.stroke();
   2664 
   2665    @assert pixel 50,25 == 0,255,0,255;
   2666  expected: green
   2667 
   2668 - name: 2d.path.stroke.unaffected
   2669  desc: Stroking does not start a new path or subpath
   2670  code: |
   2671    ctx.fillStyle = '#f00';
   2672    ctx.fillRect(0, 0, 100, 50);
   2673 
   2674    ctx.lineWidth = 50;
   2675    ctx.moveTo(-100, 25);
   2676    ctx.lineTo(-100, -100);
   2677    ctx.lineTo(200, -100);
   2678    ctx.lineTo(200, 25);
   2679    ctx.strokeStyle = '#f00';
   2680    ctx.stroke();
   2681 
   2682    ctx.closePath();
   2683    ctx.strokeStyle = '#0f0';
   2684    ctx.stroke();
   2685 
   2686    @assert pixel 50,25 == 0,255,0,255;
   2687  expected: green
   2688 
   2689 - name: 2d.path.stroke.scale1
   2690  desc: Stroke line widths are scaled by the current transformation matrix
   2691  code: |
   2692    ctx.fillStyle = '#f00';
   2693    ctx.fillRect(0, 0, 100, 50);
   2694 
   2695    ctx.beginPath();
   2696    ctx.rect(25, 12.5, 50, 25);
   2697    ctx.save();
   2698    ctx.scale(50, 25);
   2699    ctx.strokeStyle = '#0f0';
   2700    ctx.stroke();
   2701    ctx.restore();
   2702 
   2703    ctx.beginPath();
   2704    ctx.rect(-25, -12.5, 150, 75);
   2705    ctx.save();
   2706    ctx.scale(50, 25);
   2707    ctx.strokeStyle = '#f00';
   2708    ctx.stroke();
   2709    ctx.restore();
   2710 
   2711    @assert pixel 0,0 == 0,255,0,255;
   2712    @assert pixel 50,0 == 0,255,0,255;
   2713    @assert pixel 99,0 == 0,255,0,255;
   2714    @assert pixel 0,25 == 0,255,0,255;
   2715    @assert pixel 50,25 == 0,255,0,255;
   2716    @assert pixel 99,25 == 0,255,0,255;
   2717    @assert pixel 0,49 == 0,255,0,255;
   2718    @assert pixel 50,49 == 0,255,0,255;
   2719    @assert pixel 99,49 == 0,255,0,255;
   2720  expected: green
   2721 
   2722 - name: 2d.path.stroke.scale2
   2723  desc: Stroke line widths are scaled by the current transformation matrix
   2724  code: |
   2725    ctx.fillStyle = '#f00';
   2726    ctx.fillRect(0, 0, 100, 50);
   2727 
   2728    ctx.beginPath();
   2729    ctx.rect(25, 12.5, 50, 25);
   2730    ctx.save();
   2731    ctx.rotate(Math.PI/2);
   2732    ctx.scale(25, 50);
   2733    ctx.strokeStyle = '#0f0';
   2734    ctx.stroke();
   2735    ctx.restore();
   2736 
   2737    ctx.beginPath();
   2738    ctx.rect(-25, -12.5, 150, 75);
   2739    ctx.save();
   2740    ctx.rotate(Math.PI/2);
   2741    ctx.scale(25, 50);
   2742    ctx.strokeStyle = '#f00';
   2743    ctx.stroke();
   2744    ctx.restore();
   2745 
   2746    @assert pixel 0,0 == 0,255,0,255;
   2747    @assert pixel 50,0 == 0,255,0,255;
   2748    @assert pixel 99,0 == 0,255,0,255;
   2749    @assert pixel 0,25 == 0,255,0,255;
   2750    @assert pixel 50,25 == 0,255,0,255;
   2751    @assert pixel 99,25 == 0,255,0,255;
   2752    @assert pixel 0,49 == 0,255,0,255;
   2753    @assert pixel 50,49 == 0,255,0,255;
   2754    @assert pixel 99,49 == 0,255,0,255;
   2755  expected: green
   2756 
   2757 - name: 2d.path.stroke.skew
   2758  desc: Strokes lines are skewed by the current transformation matrix
   2759  code: |
   2760    ctx.fillStyle = '#f00';
   2761    ctx.fillRect(0, 0, 100, 50);
   2762 
   2763    ctx.save();
   2764    ctx.beginPath();
   2765    ctx.moveTo(49, -50);
   2766    ctx.lineTo(201, -50);
   2767    ctx.rotate(Math.PI/4);
   2768    ctx.scale(1, 283);
   2769    ctx.strokeStyle = '#0f0';
   2770    ctx.stroke();
   2771    ctx.restore();
   2772 
   2773    ctx.save();
   2774    ctx.beginPath();
   2775    ctx.translate(-150, 0);
   2776    ctx.moveTo(49, -50);
   2777    ctx.lineTo(199, -50);
   2778    ctx.rotate(Math.PI/4);
   2779    ctx.scale(1, 142);
   2780    ctx.strokeStyle = '#f00';
   2781    ctx.stroke();
   2782    ctx.restore();
   2783 
   2784    ctx.save();
   2785    ctx.beginPath();
   2786    ctx.translate(-150, 0);
   2787    ctx.moveTo(49, -50);
   2788    ctx.lineTo(199, -50);
   2789    ctx.rotate(Math.PI/4);
   2790    ctx.scale(1, 142);
   2791    ctx.strokeStyle = '#f00';
   2792    ctx.stroke();
   2793    ctx.restore();
   2794 
   2795    @assert pixel 0,0 == 0,255,0,255;
   2796    @assert pixel 50,0 == 0,255,0,255;
   2797    @assert pixel 99,0 == 0,255,0,255;
   2798    @assert pixel 0,25 == 0,255,0,255;
   2799    @assert pixel 50,25 == 0,255,0,255;
   2800    @assert pixel 99,25 == 0,255,0,255;
   2801    @assert pixel 0,49 == 0,255,0,255;
   2802    @assert pixel 50,49 == 0,255,0,255;
   2803    @assert pixel 99,49 == 0,255,0,255;
   2804  expected: green
   2805 
   2806 - name: 2d.path.stroke.empty
   2807  desc: Empty subpaths are not stroked
   2808  code: |
   2809    ctx.fillStyle = '#0f0';
   2810    ctx.fillRect(0, 0, 100, 50);
   2811 
   2812    ctx.strokeStyle = '#f00';
   2813    ctx.lineWidth = 100;
   2814    ctx.lineCap = 'round';
   2815    ctx.lineJoin = 'round';
   2816 
   2817    ctx.beginPath();
   2818    ctx.moveTo(40, 25);
   2819    ctx.moveTo(60, 25);
   2820    ctx.stroke();
   2821 
   2822    @assert pixel 50,25 == 0,255,0,255;
   2823  expected: green
   2824 
   2825 - name: 2d.path.stroke.prune.line
   2826  desc: Zero-length line segments from lineTo are removed before stroking
   2827  code: |
   2828    ctx.fillStyle = '#0f0';
   2829    ctx.fillRect(0, 0, 100, 50);
   2830 
   2831    ctx.strokeStyle = '#f00';
   2832    ctx.lineWidth = 100;
   2833    ctx.lineCap = 'round';
   2834    ctx.lineJoin = 'round';
   2835 
   2836    ctx.beginPath();
   2837    ctx.moveTo(50, 25);
   2838    ctx.lineTo(50, 25);
   2839    ctx.stroke();
   2840 
   2841    @assert pixel 50,25 == 0,255,0,255; @moz-todo
   2842  expected: green
   2843 
   2844 - name: 2d.path.stroke.prune.closed
   2845  desc: Zero-length line segments from closed paths are removed before stroking
   2846  code: |
   2847    ctx.fillStyle = '#0f0';
   2848    ctx.fillRect(0, 0, 100, 50);
   2849 
   2850    ctx.strokeStyle = '#f00';
   2851    ctx.lineWidth = 100;
   2852    ctx.lineCap = 'round';
   2853    ctx.lineJoin = 'round';
   2854 
   2855    ctx.beginPath();
   2856    ctx.moveTo(50, 25);
   2857    ctx.lineTo(50, 25);
   2858    ctx.closePath();
   2859    ctx.stroke();
   2860 
   2861    @assert pixel 50,25 == 0,255,0,255; @moz-todo
   2862  expected: green
   2863 
   2864 - name: 2d.path.stroke.prune.curve
   2865  desc: Zero-length line segments from quadraticCurveTo and bezierCurveTo are removed
   2866    before stroking
   2867  code: |
   2868    ctx.fillStyle = '#0f0';
   2869    ctx.fillRect(0, 0, 100, 50);
   2870 
   2871    ctx.strokeStyle = '#f00';
   2872    ctx.lineWidth = 100;
   2873    ctx.lineCap = 'round';
   2874    ctx.lineJoin = 'round';
   2875 
   2876    ctx.beginPath();
   2877    ctx.moveTo(50, 25);
   2878    ctx.quadraticCurveTo(50, 25, 50, 25);
   2879    ctx.stroke();
   2880 
   2881    ctx.beginPath();
   2882    ctx.moveTo(50, 25);
   2883    ctx.bezierCurveTo(50, 25, 50, 25, 50, 25);
   2884    ctx.stroke();
   2885 
   2886    @assert pixel 50,25 == 0,255,0,255; @moz-todo
   2887  expected: green
   2888 
   2889 - name: 2d.path.stroke.prune.arc
   2890  desc: Zero-length line segments from arcTo and arc are removed before stroking
   2891  code: |
   2892    ctx.fillStyle = '#0f0';
   2893    ctx.fillRect(0, 0, 100, 50);
   2894 
   2895    ctx.strokeStyle = '#f00';
   2896    ctx.lineWidth = 100;
   2897    ctx.lineCap = 'round';
   2898    ctx.lineJoin = 'round';
   2899 
   2900    ctx.beginPath();
   2901    ctx.moveTo(50, 25);
   2902    ctx.arcTo(50, 25, 150, 25, 10);
   2903    ctx.stroke();
   2904 
   2905    ctx.beginPath();
   2906    ctx.moveTo(60, 25);
   2907    ctx.arc(50, 25, 10, 0, 0, false);
   2908    ctx.stroke();
   2909 
   2910    @assert pixel 50,25 == 0,255,0,255; @moz-todo
   2911  expected: green
   2912 
   2913 - name: 2d.path.stroke.prune.rect
   2914  desc: Zero-length line segments from rect and strokeRect are removed before stroking
   2915  code: |
   2916    ctx.fillStyle = '#0f0';
   2917    ctx.fillRect(0, 0, 100, 50);
   2918 
   2919    ctx.strokeStyle = '#f00';
   2920    ctx.lineWidth = 100;
   2921    ctx.lineCap = 'round';
   2922    ctx.lineJoin = 'round';
   2923 
   2924    ctx.beginPath();
   2925    ctx.rect(50, 25, 0, 0);
   2926    ctx.stroke();
   2927 
   2928    ctx.strokeRect(50, 25, 0, 0);
   2929 
   2930    @assert pixel 50,25 == 0,255,0,255; @moz-todo
   2931  expected: green
   2932 
   2933 - name: 2d.path.stroke.prune.corner
   2934  desc: Zero-length line segments are removed before stroking with miters
   2935  code: |
   2936    ctx.fillStyle = '#0f0';
   2937    ctx.fillRect(0, 0, 100, 50);
   2938 
   2939    ctx.strokeStyle = '#f00';
   2940    ctx.lineWidth = 400;
   2941    ctx.lineJoin = 'miter';
   2942    ctx.miterLimit = 1.4;
   2943 
   2944    ctx.beginPath();
   2945    ctx.moveTo(-1000, 200);
   2946    ctx.lineTo(-100, 200);
   2947    ctx.lineTo(-100, 200);
   2948    ctx.lineTo(-100, 200);
   2949    ctx.lineTo(-100, 1000);
   2950    ctx.stroke();
   2951 
   2952    @assert pixel 50,25 == 0,255,0,255;
   2953  expected: green
   2954 
   2955 - name: 2d.path.transformation.basic
   2956  code: |
   2957    ctx.fillStyle = '#f00';
   2958    ctx.fillRect(0, 0, 100, 50);
   2959 
   2960    ctx.translate(-100, 0);
   2961    ctx.rect(100, 0, 100, 50);
   2962    ctx.translate(0, -100);
   2963    ctx.fillStyle = '#0f0';
   2964    ctx.fill();
   2965 
   2966    @assert pixel 50,25 == 0,255,0,255;
   2967  expected: green
   2968 
   2969 - name: 2d.path.transformation.multiple
   2970  # TODO: change this name
   2971  desc: Transformations are applied while building paths, not when drawing
   2972  code: |
   2973    ctx.fillStyle = '#0f0';
   2974    ctx.fillRect(0, 0, 100, 50);
   2975 
   2976    ctx.fillStyle = '#f00';
   2977    ctx.translate(-100, 0);
   2978    ctx.rect(0, 0, 100, 50);
   2979    ctx.fill();
   2980    ctx.translate(100, 0);
   2981    ctx.fill();
   2982 
   2983    ctx.beginPath();
   2984    ctx.strokeStyle = '#f00';
   2985    ctx.lineWidth = 50;
   2986    ctx.translate(0, -50);
   2987    ctx.moveTo(0, 25);
   2988    ctx.lineTo(100, 25);
   2989    ctx.stroke();
   2990    ctx.translate(0, 50);
   2991    ctx.stroke();
   2992 
   2993    @assert pixel 50,25 == 0,255,0,255;
   2994  expected: green
   2995 
   2996 - name: 2d.path.transformation.changing
   2997  desc: Transformations are applied while building paths, not when drawing
   2998  code: |
   2999    ctx.fillStyle = '#f00';
   3000    ctx.fillRect(0, 0, 100, 50);
   3001    ctx.fillStyle = '#0f0';
   3002    ctx.moveTo(0, 0);
   3003    ctx.translate(100, 0);
   3004    ctx.lineTo(0, 0);
   3005    ctx.translate(0, 50);
   3006    ctx.lineTo(0, 0);
   3007    ctx.translate(-100, 0);
   3008    ctx.lineTo(0, 0);
   3009    ctx.translate(1000, 1000);
   3010    ctx.rotate(Math.PI/2);
   3011    ctx.scale(0.1, 0.1);
   3012    ctx.fill();
   3013 
   3014    @assert pixel 50,25 == 0,255,0,255;
   3015  expected: green
   3016 
   3017 
   3018 - name: 2d.path.clip.empty
   3019  code: |
   3020    ctx.fillStyle = '#0f0';
   3021    ctx.fillRect(0, 0, 100, 50);
   3022 
   3023    ctx.beginPath();
   3024    ctx.clip();
   3025 
   3026    ctx.fillStyle = '#f00';
   3027    ctx.fillRect(0, 0, 100, 50);
   3028 
   3029    @assert pixel 50,25 == 0,255,0,255;
   3030  expected: green
   3031 
   3032 - name: 2d.path.clip.basic.1
   3033  code: |
   3034    ctx.fillStyle = '#f00';
   3035    ctx.fillRect(0, 0, 100, 50);
   3036 
   3037    ctx.beginPath();
   3038    ctx.rect(0, 0, 100, 50);
   3039    ctx.clip();
   3040 
   3041    ctx.fillStyle = '#0f0';
   3042    ctx.fillRect(0, 0, 100, 50);
   3043 
   3044    @assert pixel 50,25 == 0,255,0,255;
   3045  expected: green
   3046 
   3047 - name: 2d.path.clip.basic.2
   3048  code: |
   3049    ctx.fillStyle = '#0f0';
   3050    ctx.fillRect(0, 0, 100, 50);
   3051 
   3052    ctx.beginPath();
   3053    ctx.rect(-100, 0, 100, 50);
   3054    ctx.clip();
   3055 
   3056    ctx.fillStyle = '#f00';
   3057    ctx.fillRect(0, 0, 100, 50);
   3058 
   3059    @assert pixel 50,25 == 0,255,0,255;
   3060  expected: green
   3061 
   3062 - name: 2d.path.clip.intersect
   3063  code: |
   3064    ctx.fillStyle = '#0f0';
   3065    ctx.fillRect(0, 0, 100, 50);
   3066 
   3067    ctx.beginPath();
   3068    ctx.rect(0, 0, 50, 50);
   3069    ctx.clip();
   3070    ctx.beginPath();
   3071    ctx.rect(50, 0, 50, 50)
   3072    ctx.clip();
   3073 
   3074    ctx.fillStyle = '#f00';
   3075    ctx.fillRect(0, 0, 100, 50);
   3076 
   3077    @assert pixel 50,25 == 0,255,0,255;
   3078  expected: green
   3079 
   3080 - name: 2d.path.clip.winding.evenodd.1
   3081  desc: evenodd winding number rule works in clip
   3082  code: |
   3083    ctx.fillStyle = '#0f0';
   3084    ctx.fillRect(0, 0, 100, 50);
   3085 
   3086    ctx.beginPath();
   3087    ctx.rect(0, 0, 100, 50);
   3088    ctx.rect(0, 0, 100, 50);
   3089 
   3090    ctx.fillStyle = "#f00";
   3091    ctx.clip("evenodd");
   3092    ctx.fillRect(0, 0, 100, 50);
   3093 
   3094    @assert pixel 50,25 == 0,255,0,255;
   3095 
   3096 - name: 2d.path.clip.winding.evenodd.2
   3097  desc: evenodd winding number rule works in clip
   3098  code: |
   3099    ctx.fillStyle = '#0f0';
   3100    ctx.fillRect(0, 0, 100, 50);
   3101 
   3102    let path = new Path2D();
   3103    path.rect(0, 0, 100, 50);
   3104    path.rect(0, 0, 100, 50);
   3105    path.closePath();
   3106 
   3107    ctx.fillStyle = "#f00";
   3108    ctx.clip(path, "evenodd");
   3109    ctx.fillRect(0, 0, 100, 50);
   3110 
   3111    @assert pixel 50,25 == 0,255,0,255;
   3112 
   3113 - name: 2d.path.clip.winding.1
   3114  code: |
   3115    ctx.fillStyle = '#0f0';
   3116    ctx.fillRect(0, 0, 100, 50);
   3117 
   3118    ctx.beginPath();
   3119    ctx.moveTo(-10, -10);
   3120    ctx.lineTo(110, -10);
   3121    ctx.lineTo(110, 60);
   3122    ctx.lineTo(-10, 60);
   3123    ctx.lineTo(-10, -10);
   3124    ctx.lineTo(0, 0);
   3125    ctx.lineTo(0, 50);
   3126    ctx.lineTo(100, 50);
   3127    ctx.lineTo(100, 0);
   3128    ctx.clip();
   3129 
   3130    ctx.fillStyle = '#f00';
   3131    ctx.fillRect(0, 0, 100, 50);
   3132 
   3133    @assert pixel 50,25 == 0,255,0,255;
   3134  expected: green
   3135 
   3136 - name: 2d.path.clip.winding.2
   3137  code: |
   3138    ctx.fillStyle = '#f00';
   3139    ctx.fillRect(0, 0, 100, 50);
   3140 
   3141    ctx.beginPath();
   3142    ctx.moveTo(-10, -10);
   3143    ctx.lineTo(110, -10);
   3144    ctx.lineTo(110, 60);
   3145    ctx.lineTo(-10, 60);
   3146    ctx.lineTo(-10, -10);
   3147    ctx.clip();
   3148 
   3149    ctx.beginPath();
   3150    ctx.moveTo(0, 0);
   3151    ctx.lineTo(0, 50);
   3152    ctx.lineTo(100, 50);
   3153    ctx.lineTo(100, 0);
   3154    ctx.lineTo(0, 0);
   3155    ctx.clip();
   3156 
   3157    ctx.fillStyle = '#0f0';
   3158    ctx.fillRect(0, 0, 100, 50);
   3159 
   3160    @assert pixel 50,25 == 0,255,0,255;
   3161  expected: green
   3162 
   3163 - name: 2d.path.clip.unaffected
   3164  code: |
   3165    ctx.fillStyle = '#f00';
   3166    ctx.fillRect(0, 0, 100, 50);
   3167 
   3168    ctx.fillStyle = '#0f0';
   3169 
   3170    ctx.beginPath();
   3171    ctx.moveTo(0, 0);
   3172    ctx.lineTo(0, 50);
   3173    ctx.lineTo(100, 50);
   3174    ctx.lineTo(100, 0);
   3175    ctx.clip();
   3176 
   3177    ctx.lineTo(0, 0);
   3178    ctx.fill();
   3179 
   3180    @assert pixel 50,25 == 0,255,0,255;
   3181  expected: green
   3182 
   3183 
   3184 
   3185 - name: 2d.path.isPointInPath.basic.1
   3186  desc: isPointInPath() detects whether the point is inside the path
   3187  code: |
   3188    ctx.rect(0, 0, 20, 20);
   3189    @assert ctx.isPointInPath(10, 10) === true;
   3190    @assert ctx.isPointInPath(30, 10) === false;
   3191 
   3192 - name: 2d.path.isPointInPath.basic.2
   3193  desc: isPointInPath() detects whether the point is inside the path
   3194  code: |
   3195    ctx.rect(20, 0, 20, 20);
   3196    @assert ctx.isPointInPath(10, 10) === false;
   3197    @assert ctx.isPointInPath(30, 10) === true;
   3198 
   3199 - name: 2d.path.isPointInPath.edge
   3200  desc: isPointInPath() counts points on the path as being inside
   3201  code: |
   3202    ctx.rect(0, 0, 20, 20);
   3203    @assert ctx.isPointInPath(0, 0) === true;
   3204    @assert ctx.isPointInPath(10, 0) === true;
   3205    @assert ctx.isPointInPath(20, 0) === true;
   3206    @assert ctx.isPointInPath(20, 10) === true;
   3207    @assert ctx.isPointInPath(20, 20) === true;
   3208    @assert ctx.isPointInPath(10, 20) === true;
   3209    @assert ctx.isPointInPath(0, 20) === true;
   3210    @assert ctx.isPointInPath(0, 10) === true;
   3211    @assert ctx.isPointInPath(10, -0.01) === false;
   3212    @assert ctx.isPointInPath(10, 20.01) === false;
   3213    @assert ctx.isPointInPath(-0.01, 10) === false;
   3214    @assert ctx.isPointInPath(20.01, 10) === false;
   3215 
   3216 - name: 2d.path.isPointInPath.empty
   3217  desc: isPointInPath() works when there is no path
   3218  code: |
   3219    @assert ctx.isPointInPath(0, 0) === false;
   3220 
   3221 - name: 2d.path.isPointInPath.subpath
   3222  desc: isPointInPath() uses the current path, not just the subpath
   3223  code: |
   3224    ctx.rect(0, 0, 20, 20);
   3225    ctx.beginPath();
   3226    ctx.rect(20, 0, 20, 20);
   3227    ctx.closePath();
   3228    ctx.rect(40, 0, 20, 20);
   3229    @assert ctx.isPointInPath(10, 10) === false;
   3230    @assert ctx.isPointInPath(30, 10) === true;
   3231    @assert ctx.isPointInPath(50, 10) === true;
   3232 
   3233 - name: 2d.path.isPointInPath.outside
   3234  desc: isPointInPath() works on paths outside the canvas
   3235  code: |
   3236    ctx.rect(0, -100, 20, 20);
   3237    ctx.rect(20, -10, 20, 20);
   3238    @assert ctx.isPointInPath(10, -110) === false;
   3239    @assert ctx.isPointInPath(10, -90) === true;
   3240    @assert ctx.isPointInPath(10, -70) === false;
   3241    @assert ctx.isPointInPath(30, -20) === false;
   3242    @assert ctx.isPointInPath(30, 0) === true;
   3243    @assert ctx.isPointInPath(30, 20) === false;
   3244 
   3245 - name: 2d.path.isPointInPath.unclosed
   3246  desc: isPointInPath() works on unclosed subpaths
   3247  code: |
   3248    ctx.moveTo(0, 0);
   3249    ctx.lineTo(20, 0);
   3250    ctx.lineTo(20, 20);
   3251    ctx.lineTo(0, 20);
   3252    @assert ctx.isPointInPath(10, 10) === true;
   3253    @assert ctx.isPointInPath(30, 10) === false;
   3254 
   3255 - name: 2d.path.isPointInPath.arc
   3256  desc: isPointInPath() works on arcs
   3257  code: |
   3258    ctx.arc(50, 25, 10, 0, Math.PI, false);
   3259    @assert ctx.isPointInPath(50, 10) === false;
   3260    @assert ctx.isPointInPath(50, 20) === false;
   3261    @assert ctx.isPointInPath(50, 30) === true;
   3262    @assert ctx.isPointInPath(50, 40) === false;
   3263    @assert ctx.isPointInPath(30, 20) === false;
   3264    @assert ctx.isPointInPath(70, 20) === false;
   3265    @assert ctx.isPointInPath(30, 30) === false;
   3266    @assert ctx.isPointInPath(70, 30) === false;
   3267 
   3268 - name: 2d.path.isPointInPath.bigarc
   3269  desc: isPointInPath() works on unclosed arcs larger than 2pi
   3270  opera: {bug: 320937}
   3271  code: |
   3272    ctx.arc(50, 25, 10, 0, 7, false);
   3273    @assert ctx.isPointInPath(50, 10) === false;
   3274    @assert ctx.isPointInPath(50, 20) === true;
   3275    @assert ctx.isPointInPath(50, 30) === true;
   3276    @assert ctx.isPointInPath(50, 40) === false;
   3277    @assert ctx.isPointInPath(30, 20) === false;
   3278    @assert ctx.isPointInPath(70, 20) === false;
   3279    @assert ctx.isPointInPath(30, 30) === false;
   3280    @assert ctx.isPointInPath(70, 30) === false;
   3281 
   3282 - name: 2d.path.isPointInPath.bezier
   3283  desc: isPointInPath() works on Bezier curves
   3284  code: |
   3285    ctx.moveTo(25, 25);
   3286    ctx.bezierCurveTo(50, -50, 50, 100, 75, 25);
   3287    @assert ctx.isPointInPath(25, 20) === false;
   3288    @assert ctx.isPointInPath(25, 30) === false;
   3289    @assert ctx.isPointInPath(30, 20) === true;
   3290    @assert ctx.isPointInPath(30, 30) === false;
   3291    @assert ctx.isPointInPath(40, 2) === false;
   3292    @assert ctx.isPointInPath(40, 20) === true;
   3293    @assert ctx.isPointInPath(40, 30) === false;
   3294    @assert ctx.isPointInPath(40, 47) === false;
   3295    @assert ctx.isPointInPath(45, 20) === true;
   3296    @assert ctx.isPointInPath(45, 30) === false;
   3297    @assert ctx.isPointInPath(55, 20) === false;
   3298    @assert ctx.isPointInPath(55, 30) === true;
   3299    @assert ctx.isPointInPath(60, 2) === false;
   3300    @assert ctx.isPointInPath(60, 20) === false;
   3301    @assert ctx.isPointInPath(60, 30) === true;
   3302    @assert ctx.isPointInPath(60, 47) === false;
   3303    @assert ctx.isPointInPath(70, 20) === false;
   3304    @assert ctx.isPointInPath(70, 30) === true;
   3305    @assert ctx.isPointInPath(75, 20) === false;
   3306    @assert ctx.isPointInPath(75, 30) === false;
   3307 
   3308 - name: 2d.path.isPointInPath.winding
   3309  desc: isPointInPath() uses the non-zero winding number rule
   3310  code: |
   3311    // Create a square ring, using opposite windings to make a hole in the centre
   3312    ctx.moveTo(0, 0);
   3313    ctx.lineTo(50, 0);
   3314    ctx.lineTo(50, 50);
   3315    ctx.lineTo(0, 50);
   3316    ctx.lineTo(0, 0);
   3317    ctx.lineTo(10, 10);
   3318    ctx.lineTo(10, 40);
   3319    ctx.lineTo(40, 40);
   3320    ctx.lineTo(40, 10);
   3321    ctx.lineTo(10, 10);
   3322 
   3323    @assert ctx.isPointInPath(5, 5) === true;
   3324    @assert ctx.isPointInPath(25, 5) === true;
   3325    @assert ctx.isPointInPath(45, 5) === true;
   3326    @assert ctx.isPointInPath(5, 25) === true;
   3327    @assert ctx.isPointInPath(25, 25) === false;
   3328    @assert ctx.isPointInPath(45, 25) === true;
   3329    @assert ctx.isPointInPath(5, 45) === true;
   3330    @assert ctx.isPointInPath(25, 45) === true;
   3331    @assert ctx.isPointInPath(45, 45) === true;
   3332 
   3333 - name: 2d.path.isPointInPath.transform.1
   3334  desc: isPointInPath() handles transformations correctly
   3335  code: |
   3336    ctx.translate(50, 0);
   3337    ctx.rect(0, 0, 20, 20);
   3338    @assert ctx.isPointInPath(-40, 10) === false;
   3339    @assert ctx.isPointInPath(10, 10) === false;
   3340    @assert ctx.isPointInPath(49, 10) === false;
   3341    @assert ctx.isPointInPath(51, 10) === true;
   3342    @assert ctx.isPointInPath(69, 10) === true;
   3343    @assert ctx.isPointInPath(71, 10) === false;
   3344 
   3345 - name: 2d.path.isPointInPath.transform.2
   3346  desc: isPointInPath() handles transformations correctly
   3347  code: |
   3348    ctx.rect(50, 0, 20, 20);
   3349    ctx.translate(50, 0);
   3350    @assert ctx.isPointInPath(-40, 10) === false;
   3351    @assert ctx.isPointInPath(10, 10) === false;
   3352    @assert ctx.isPointInPath(49, 10) === false;
   3353    @assert ctx.isPointInPath(51, 10) === true;
   3354    @assert ctx.isPointInPath(69, 10) === true;
   3355    @assert ctx.isPointInPath(71, 10) === false;
   3356 
   3357 - name: 2d.path.isPointInPath.transform.3
   3358  desc: isPointInPath() handles transformations correctly
   3359  code: |
   3360    ctx.scale(-1, 1);
   3361    ctx.rect(-70, 0, 20, 20);
   3362    @assert ctx.isPointInPath(-40, 10) === false;
   3363    @assert ctx.isPointInPath(10, 10) === false;
   3364    @assert ctx.isPointInPath(49, 10) === false;
   3365    @assert ctx.isPointInPath(51, 10) === true;
   3366    @assert ctx.isPointInPath(69, 10) === true;
   3367    @assert ctx.isPointInPath(71, 10) === false;
   3368 
   3369 - name: 2d.path.isPointInPath.transform.4
   3370  desc: isPointInPath() handles transformations correctly
   3371  code: |
   3372    ctx.translate(50, 0);
   3373    ctx.rect(50, 0, 20, 20);
   3374    ctx.translate(0, 50);
   3375    @assert ctx.isPointInPath(60, 10) === false;
   3376    @assert ctx.isPointInPath(110, 10) === true;
   3377    @assert ctx.isPointInPath(110, 60) === false;
   3378 
   3379 - name: 2d.path.isPointInPath.nonfinite
   3380  desc: isPointInPath() returns false for non-finite arguments
   3381  code: |
   3382    ctx.rect(-100, -50, 200, 100);
   3383    @assert ctx.isPointInPath(Infinity, 0) === false;
   3384    @assert ctx.isPointInPath(-Infinity, 0) === false;
   3385    @assert ctx.isPointInPath(NaN, 0) === false;
   3386    @assert ctx.isPointInPath(0, Infinity) === false;
   3387    @assert ctx.isPointInPath(0, -Infinity) === false;
   3388    @assert ctx.isPointInPath(0, NaN) === false;
   3389    @assert ctx.isPointInPath(NaN, NaN) === false;
   3390 
   3391 
   3392 - name: 2d.path.isPointInStroke.scaleddashes
   3393  desc: isPointInStroke() should return correct results on dashed paths at high scale
   3394    factors
   3395  code: |
   3396    var scale = 20;
   3397    ctx.setLineDash([10, 21.4159]); // dash from t=0 to t=10 along the circle
   3398    ctx.scale(scale, scale);
   3399    ctx.ellipse(6, 10, 5, 5, 0, 2*Math.PI, false);
   3400    ctx.stroke();
   3401 
   3402    // hit-test the beginning of the dash (t=0)
   3403    @assert ctx.isPointInStroke(11*scale, 10*scale) === true;
   3404    // hit-test the middle of the dash (t=5)
   3405    @assert ctx.isPointInStroke(8.70*scale, 14.21*scale) === true;
   3406    // hit-test the end of the dash (t=9.8)
   3407    @assert ctx.isPointInStroke(4.10*scale, 14.63*scale) === true;
   3408    // hit-test past the end of the dash (t=10.2)
   3409    @assert ctx.isPointInStroke(3.74*scale, 14.46*scale) === false;
   3410 
   3411 - name: 2d.path.isPointInPath.basic
   3412  desc: Verify the winding rule in isPointInPath works for for rect path.
   3413  code: |
   3414    canvas.width = 200;
   3415    canvas.height = 200;
   3416 
   3417    // Testing default isPointInPath
   3418    ctx.beginPath();
   3419    ctx.rect(0, 0, 100, 100);
   3420    ctx.rect(25, 25, 50, 50);
   3421    @assert ctx.isPointInPath(50, 50) === true;
   3422    @assert ctx.isPointInPath(NaN, 50) === false;
   3423    @assert ctx.isPointInPath(50, NaN) === false;
   3424 
   3425    // Testing nonzero isPointInPath
   3426    ctx.beginPath();
   3427    ctx.rect(0, 0, 100, 100);
   3428    ctx.rect(25, 25, 50, 50);
   3429    @assert ctx.isPointInPath(50, 50, 'nonzero') === true;
   3430 
   3431    // Testing evenodd isPointInPath
   3432    ctx.beginPath();
   3433    ctx.rect(0, 0, 100, 100);
   3434    ctx.rect(25, 25, 50, 50);
   3435    @assert ctx.isPointInPath(50, 50, 'evenodd') === false;
   3436 
   3437    // Testing extremely large scale
   3438    ctx.save();
   3439    ctx.scale(Number.MAX_VALUE, Number.MAX_VALUE);
   3440    ctx.beginPath();
   3441    ctx.rect(-10, -10, 20, 20);
   3442    @assert ctx.isPointInPath(0, 0, 'nonzero') === true;
   3443    @assert ctx.isPointInPath(0, 0, 'evenodd') === true;
   3444    ctx.restore();
   3445 
   3446    // Check with non-invertible ctm.
   3447    ctx.save();
   3448    ctx.scale(0, 0);
   3449    ctx.beginPath();
   3450    ctx.rect(-10, -10, 20, 20);
   3451    @assert ctx.isPointInPath(0, 0, 'nonzero') === false;
   3452    @assert ctx.isPointInPath(0, 0, 'evenodd') === false;
   3453    ctx.restore();
   3454 
   3455 - name: 2d.path.isPointInpath.multi.path
   3456  desc: Verify the winding rule in isPointInPath works for path object.
   3457  code: |
   3458    canvas.width = 200;
   3459    canvas.height = 200;
   3460 
   3461    // Testing default isPointInPath with Path object');
   3462    path = new Path2D();
   3463    path.rect(0, 0, 100, 100);
   3464    path.rect(25, 25, 50, 50);
   3465    @assert ctx.isPointInPath(path, 50, 50) === true;
   3466    @assert ctx.isPointInPath(path, 50, 50, undefined) === true;
   3467    @assert ctx.isPointInPath(path, NaN, 50) === false;
   3468    @assert ctx.isPointInPath(path, 50, NaN) === false;
   3469 
   3470    // Testing nonzero isPointInPath with Path object');
   3471    path = new Path2D();
   3472    path.rect(0, 0, 100, 100);
   3473    path.rect(25, 25, 50, 50);
   3474    @assert ctx.isPointInPath(path, 50, 50, 'nonzero') === true;
   3475 
   3476    // Testing evenodd isPointInPath with Path object');
   3477    path = new Path2D();
   3478    path.rect(0, 0, 100, 100);
   3479    path.rect(25, 25, 50, 50);
   3480    assert_false(ctx.isPointInPath(path, 50, 50, 'evenodd'));
   3481 
   3482 - name: 2d.path.isPointInpath.invalid
   3483  desc: Verify isPointInPath throws exceptions with invalid inputs.
   3484  code: |
   3485    canvas.width = 200;
   3486    canvas.height = 200;
   3487    path = new Path2D();
   3488    path.rect(0, 0, 100, 100);
   3489    path.rect(25, 25, 50, 50);
   3490    // Testing invalid enumeration isPointInPath (w/ and w/o Path object');
   3491    @assert throws TypeError ctx.isPointInPath(path, 50, 50, 'gazonk');
   3492    @assert throws TypeError ctx.isPointInPath(50, 50, 'gazonk');
   3493 
   3494    // Testing invalid type isPointInPath with Path object');
   3495    @assert throws TypeError ctx.isPointInPath(null, 50, 50);
   3496    @assert throws TypeError ctx.isPointInPath(null, 50, 50, 'nonzero');
   3497    @assert throws TypeError ctx.isPointInPath(null, 50, 50, 'evenodd');
   3498    @assert throws TypeError ctx.isPointInPath(null, 50, 50, null);
   3499    @assert throws TypeError ctx.isPointInPath(path, 50, 50, null);
   3500    @assert throws TypeError ctx.isPointInPath(undefined, 50, 50);
   3501    @assert throws TypeError ctx.isPointInPath(undefined, 50, 50, 'nonzero');
   3502    @assert throws TypeError ctx.isPointInPath(undefined, 50, 50, 'evenodd');
   3503    @assert throws TypeError ctx.isPointInPath(undefined, 50, 50, undefined);
   3504    @assert throws TypeError ctx.isPointInPath([], 50, 50);
   3505    @assert throws TypeError ctx.isPointInPath([], 50, 50, 'nonzero');
   3506    @assert throws TypeError ctx.isPointInPath([], 50, 50, 'evenodd');
   3507    @assert throws TypeError ctx.isPointInPath({}, 50, 50);
   3508    @assert throws TypeError ctx.isPointInPath({}, 50, 50, 'nonzero');
   3509    @assert throws TypeError ctx.isPointInPath({}, 50, 50, 'evenodd');