tor-browser

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

fill-and-stroke-styles.yaml (81698B)


      1 # Try most of the CSS3 Color <color> values.
      2 # http://www.w3.org/TR/css3-color/#colorunits
      3 - name: 2d.fillStyle.parse
      4  macros: |
      5    {% macro js_format(color) %}
      6      {% set r, g, b, a = color %}
      7      {{- '%d,%d,%d,%d' | format(r, g, b, a) -}}
      8    {% endmacro %}
      9 
     10    {% macro cairo_format(color) %}
     11      {% set r, g, b, a = color %}
     12      {{- '%f, %f, %f, %f' |
     13          format(r / 255.0, g / 255.0, b / 255.0, a / 255.0) -}}
     14    {% endmacro %}
     15  code: |
     16    {% import 'macros' as m %}
     17    ctx.fillStyle = '#f00';
     18    ctx.fillStyle = '{{ string }}';
     19    ctx.fillRect(0, 0, 100, 50);
     20    @assert pixel 50,25 == {{ m.js_format(color) }};
     21  expected: |
     22    {% import 'macros' as m %}
     23    size 100 50
     24    cr.set_source_rgba({{ m.cairo_format(color) }})
     25    cr.rectangle(0, 0, 100, 50)
     26    cr.fill()
     27  big_float: '1{% for i in range(39) %}0{% endfor %}'
     28  big_double: '1{% for i in range(310) %}0{% endfor %}'
     29  variants:
     30  - html4: {string: 'limE', color: [0, 255, 0, 255]}
     31    hex3: {string: '#0f0', color: [0, 255, 0, 255]}
     32    hex4: {string: '#0f0f', color: [0, 255, 0, 255]}
     33    hex6: {string: '#00fF00', color: [0, 255, 0, 255]}
     34    hex8: {string: '#00ff00ff', color: [0, 255, 0, 255]}
     35    rgb-num: {string: 'rgb(0,255,0)', color: [0, 255, 0, 255]}
     36    rgb-clamp-1: {string: 'rgb(-1000, 1000, -1000)', color: [0, 255, 0, 255],
     37                  notes: 'Assumes colors are clamped to [0,255].'}
     38    rgb-clamp-2: {string: 'rgb(-200%, 200%, -200%)', color: [0, 255, 0, 255],
     39                  notes: 'Assumes colors are clamped to [0,255].'}
     40    rgb-clamp-3: {string: 'rgb(-2147483649, 4294967298, -18446744073709551619)',
     41                  color: [0, 255, 0, 255],
     42                  notes: 'Assumes colors are clamped to [0,255].'}
     43    rgb-clamp-4:
     44      string: 'rgb(-{{ big_float }}, {{ big_float }}, -{{ big_float }})'
     45      color: [0, 255, 0, 255]
     46      notes: 'Assumes colors are clamped to [0,255].'
     47    rgb-clamp-5:
     48      string: 'rgb(-{{ big_double }}, {{ big_double }}, -{{ big_double }})'
     49      color: [0, 255, 0, 255]
     50      notes: 'Assumes colors are clamped to [0,255].'
     51    rgb-percent:
     52      string: 'rgb(0% ,100% ,0%)'
     53      color: [0, 255, 0, 255]
     54      notes: >-
     55        CSS3 Color says "The integer value 255 corresponds to 100%". (In
     56        particular, it is not 254...)
     57    # See CSS2.1 4.2 "Unexpected end of style sheet".
     58    rgb-eof: {string: 'rgb(0, 255, 0', color: [0, 255, 0, 255]}
     59    rgba-solid-1: {string: 'rgba(  0  ,  255  ,  0  ,  1  )',
     60                   color: [0, 255, 0, 255]}
     61    rgba-solid-2: {string: 'rgba(  0  ,  255  ,  0  ,  1.0  )',
     62                   color: [0, 255, 0, 255]}
     63    rgba-solid-3: {string: 'rgba(  0  ,  255  ,  0  , +1  )',
     64                   color: [0, 255, 0, 255]}
     65    rgba-solid-4: {string: 'rgba( -0  ,  255  , +0  ,  1  )',
     66                   color: [0, 255, 0, 255]}
     67    rgba-num-1: {string: 'rgba(  0  ,  255  ,  0  ,  .499  )',
     68                 color: [0, 255, 0, 127]}
     69    rgba-num-2: {string: 'rgba(  0  ,  255  ,  0  ,  0.499  )',
     70                 color: [0, 255, 0, 127]}
     71    rgba-percent:
     72      string: 'rgba(0%,100%,0%,0.499)'
     73      # 0.499*255 rounds to 127, both down and nearest, so it should be safe.
     74      color: [0, 255, 0, 127]
     75    rgba-clamp-1: {string: 'rgba(0, 255, 0, -2)', color: [0, 0, 0, 0]}
     76    rgba-clamp-2: {string: 'rgba(0, 255, 0, 2)', color: [0, 255, 0, 255]}
     77    rgba-eof: {string: 'rgba(0, 255, 0, 1', color: [0, 255, 0, 255]}
     78    transparent-1: {string: 'transparent', color: [0, 0, 0, 0]}
     79    transparent-2: {string: 'TrAnSpArEnT', color: [0, 0, 0, 0]}
     80    hsl-1: {string: 'hsl(120, 100%, 50%)', color: [0, 255, 0, 255]}
     81    hsl-2: {string: 'hsl( -240 , 100% , 50% )', color: [0, 255, 0, 255]}
     82    hsl-3: {string: 'hsl(360120, 100%, 50%)', color: [0, 255, 0, 255]}
     83    hsl-4: {string: 'hsl(-360240, 100%, 50%)', color: [0, 255, 0, 255]}
     84    hsl-5: {string: 'hsl(120.0, 100.0%, 50.0%)', color: [0, 255, 0, 255]}
     85    hsl-6: {string: 'hsl(+120, +100%, +50%)', color: [0, 255, 0, 255]}
     86    hsl-clamp-negative-saturation: {string: 'hsl(120, -200%, 49.9%)',
     87                                    color: [127, 127, 127, 255]}
     88    hsla-1: {string: 'hsla(120, 100%, 50%, 0.499)', color: [0, 255, 0, 127]}
     89    hsla-2: {string: 'hsla( 120.0 , 100.0% , 50.0% , 1 )',
     90             color: [0, 255, 0, 255]}
     91    hsla-clamp-negative-saturation: {string: 'hsla(120, -200%, 49.9%, 1)',
     92                                     color: [127, 127, 127, 255]}
     93    hsla-clamp-alpha-1: {string: 'hsla(120, 100%, 50%, 2)',
     94                         color: [0, 255, 0, 255]}
     95    hsla-clamp-alpha-2: {string: 'hsla(120, 100%, 0%, -2)',
     96                         color: [0, 0, 0, 0]}
     97    svg-1: {string: 'gray', color: [128, 128, 128, 255]}
     98    svg-2: {string: 'grey', color: [128, 128, 128, 255]}
     99    # css-color-4 rgb() color function.
    100    # https://drafts.csswg.org/css-color/#numeric-rgb
    101    css-color-4-rgb-1: {string: 'rgb(0, 255.0, 0)', color: [0, 255, 0, 255]}
    102    css-color-4-rgb-2: {string: 'rgb(0, 255, 0, 0.2)', color: [0, 255, 0, 51]}
    103    css-color-4-rgb-3: {string: 'rgb(0, 255, 0, 20%)', color: [0, 255, 0, 51]}
    104    css-color-4-rgb-4: {string: 'rgb(0 255 0)', color: [0, 255, 0, 255]}
    105    css-color-4-rgb-5: {string: 'rgb(0 255 0 / 0.2)', color: [0, 255, 0, 51]}
    106    css-color-4-rgb-6: {string: 'rgb(0 255 0 / 20%)', color: [0, 255, 0, 51]}
    107    css-color-4-rgba-1: {string: 'rgba(0, 255.0, 0)', color: [0, 255, 0, 255]}
    108    css-color-4-rgba-2: {string: 'rgba(0, 255, 0, 0.2)', color: [0, 255, 0, 51]}
    109    css-color-4-rgba-3: {string: 'rgba(0, 255, 0, 20%)', color: [0, 255, 0, 51]}
    110    css-color-4-rgba-4: {string: 'rgba(0 255 0)', color: [0, 255, 0, 255]}
    111    css-color-4-rgba-5: {string: 'rgba(0 255 0 / 0.2)', color: [0, 255, 0, 51]}
    112    css-color-4-rgba-6: {string: 'rgba(0 255 0 / 20%)', color: [0, 255, 0, 51]}
    113    # css-color-4 hsl() color function.
    114    # https://drafts.csswg.org/css-color/#the-hsl-notation
    115    css-color-4-hsl-1: {string: 'hsl(120 100.0% 50.0%)',
    116                        color: [0, 255, 0, 255]}
    117    css-color-4-hsl-2: {string: 'hsl(120 100.0% 50.0% / 0.2)',
    118                        color: [0, 255, 0, 51]}
    119    css-color-4-hsl-3: {string: 'hsl(120.0, 100.0%, 50.0%, 0.2)',
    120                        color: [0, 255, 0, 51]}
    121    css-color-4-hsl-4: {string: 'hsl(120.0, 100.0%, 50.0%, 20%)',
    122                        color: [0, 255, 0, 51]}
    123    css-color-4-hsl-5: {string: 'hsl(120deg, 100.0%, 50.0%, 0.2)',
    124                        color: [0, 255, 0, 51]}
    125    css-color-4-hsl-6: {string: 'hsl(120deg, 100.0%, 50.0%)',
    126                        color: [0, 255, 0, 255]}
    127    css-color-4-hsl-7: {string: 'hsl(133.33333333grad, 100.0%, 50.0%)',
    128                        color: [0, 255, 0, 255]}
    129    css-color-4-hsl-8: {string: 'hsl(2.0943951024rad, 100.0%, 50.0%)',
    130                        color: [0, 255, 0, 255]}
    131    css-color-4-hsl-9: {string: 'hsl(0.3333333333turn, 100.0%, 50.0%)',
    132                        color: [0, 255, 0, 255]}
    133    css-color-4-hsla-1: {string: 'hsl(120 100.0% 50.0%)',
    134                         color: [0, 255, 0, 255]}
    135    css-color-4-hsla-2: {string: 'hsl(120 100.0% 50.0% / 0.2)',
    136                         color: [0, 255, 0, 51]}
    137    css-color-4-hsla-3: {string: 'hsl(120.0, 100.0%, 50.0%, 0.2)',
    138                         color: [0, 255, 0, 51]}
    139    css-color-4-hsla-4: {string: 'hsl(120.0, 100.0%, 50.0%, 20%)',
    140                         color: [0, 255, 0, 51]}
    141    css-color-4-hsla-5: {string: 'hsl(120deg, 100.0%, 50.0%, 0.2)',
    142                         color: [0, 255, 0, 51]}
    143    css-color-4-hsla-6: {string: 'hsl(120deg, 100.0%, 50.0%)',
    144                         color: [0, 255, 0, 255]}
    145    css-color-4-hsla-7: {string: 'hsl(133.33333333grad, 100.0%, 50.0%)',
    146                         color: [0, 255, 0, 255]}
    147    css-color-4-hsla-8: {string: 'hsl(2.0943951024rad, 100.0%, 50.0%)',
    148                         color: [0, 255, 0, 255]}
    149    css-color-4-hsla-9: {string: 'hsl(0.3333333333turn, 100.0%, 50.0%)',
    150                         color: [0, 255, 0, 255]}
    151    # currentColor is handled later.
    152 
    153 # Test that invalid colors are ignored.
    154 - name: 2d.fillStyle.parse.invalid
    155  code: |
    156    ctx.fillStyle = '#0f0';
    157    try { ctx.fillStyle = '{{ string }}'; } catch (e) { } \-
    158        // this shouldn't throw, but it shouldn't matter here if it does
    159    ctx.fillRect(0, 0, 100, 50);
    160    @assert pixel 50,25 == 0,255,0,255;
    161  expected: 'green'
    162  variants:
    163  - hex1: {string: '#f'}
    164    hex2: {string: '#f0'}
    165    hex3: {string: '#g00'}
    166    hex4: {string: '#fg00'}
    167    hex5: {string: '#ff000'}
    168    hex6: {string: '#fg0000'}
    169    hex7: {string: '#ff0000f'}
    170    hex8: {string: '#fg0000ff'}
    171    rgb-1: {string: 'rgb(255.0, 0, 0,)'}
    172    rgb-2: {string: 'rgb(100%, 0, 0)'}
    173    rgb-3: {string: 'rgb(255, - 1, 0)'}
    174    rgba-1: {string: 'rgba(100%, 0, 0, 1)'}
    175    rgba-2: {string: 'rgba(255, 0, 0, 1. 0)'}
    176    rgba-3: {string: 'rgba(255, 0, 0, 1.)'}
    177    rgba-4: {string: 'rgba(255, 0, 0, '}
    178    rgba-5: {string: 'rgba(255, 0, 0, 1,)'}
    179    hsl-1: {string: 'hsl(0%, 100%, 50%)'}
    180    hsl-2: {string: 'hsl(z, 100%, 50%)'}
    181    hsl-3: {string: 'hsl(0, 0, 50%)'}
    182    hsl-4: {string: 'hsl(0, 100%, 0)'}
    183    hsl-5: {string: 'hsl(0, 100.%, 50%)'}
    184    hsl-6: {string: 'hsl(0, 100%, 50%,)'}
    185    hsla-1: {string: 'hsla(0%, 100%, 50%, 1)'}
    186    hsla-2: {string: 'hsla(0, 0, 50%, 1)'}
    187    hsla-3: {string: 'hsla(0, 0, 50%, 1,)'}
    188    name-1: {string: 'darkbrown'}
    189    name-2: {string: 'firebrick1'}
    190    name-3: {string: 'red blue'}
    191    name-4: {string: '"red"'}
    192    name-5: {string: '"red'}
    193    # css-color-4 color function.
    194    # Comma and comma-less expressions should not mix together.
    195    css-color-4-rgb-1: {string: 'rgb(255, 0, 0 / 1)'}
    196    css-color-4-rgb-2: {string: 'rgb(255 0 0, 1)'}
    197    css-color-4-rgb-3: {string: 'rgb(255, 0 0)'}
    198    css-color-4-rgba-1: {string: 'rgba(255, 0, 0 / 1)'}
    199    css-color-4-rgba-2: {string: 'rgba(255 0 0, 1)'}
    200    css-color-4-rgba-3: {string: 'rgba(255, 0 0)'}
    201    css-color-4-hsl-1: {string: 'hsl(0, 100%, 50% / 1)'}
    202    css-color-4-hsl-2: {string: 'hsl(0 100% 50%, 1)'}
    203    css-color-4-hsl-3: {string: 'hsl(0, 100% 50%)'}
    204    css-color-4-hsla-1: {string: 'hsla(0, 100%, 50% / 1)'}
    205    css-color-4-hsla-2: {string: 'hsla(0 100% 50%, 1)'}
    206    css-color-4-hsla-3: {string: 'hsla(0, 100% 50%)'}
    207    # Trailing slash.
    208    css-color-4-rgb-4: {string: 'rgb(0 0 0 /)'}
    209    css-color-4-rgb-5: {string: 'rgb(0, 0, 0 /)'}
    210    css-color-4-hsl-4: {string: 'hsl(0 100% 50% /)'}
    211    css-color-4-hsl-5: {string: 'hsl(0, 100%, 50% /)'}
    212    # Malformed functions.
    213    css-color-4-rgb-6: {string: 'rgb(from #ffffff r g b) 100%'}
    214    css-color-4-rgb-7: {string: 'rgb(from #ffffff r g b) currentColor'}
    215    css-color-4-hsl-6: {string: 'hsl(from #ffffff h s l) red'}
    216    css-color-4-hsl-7: {string: 'hsl(from #ffffff h s l) /'}
    217 
    218 # Implemented as a negative test because we don't know what color it's meant to
    219 # be.
    220 - name: 2d.fillStyle.parse.system
    221  code: |
    222    ctx.fillStyle = '#f00';
    223    ctx.fillStyle = 'ThreeDDarkShadow';
    224    @assert ctx.fillStyle =~ /^#(?!(FF0000|ff0000|f00)$)/; // test that it's \-
    225        not red
    226 
    227 - name: 2d.fillStyle.parse.current.basic
    228  desc: currentColor is computed from the canvas element
    229  canvas_types: ['HtmlCanvas']
    230  code: |
    231    canvas.setAttribute('style', 'color: #0f0');
    232    ctx.fillStyle = '#f00';
    233    ctx.fillStyle = 'currentColor';
    234    ctx.fillRect(0, 0, 100, 50);
    235    @assert pixel 50,25 == 0,255,0,255;
    236  expected: green
    237 
    238 - name: 2d.fillStyle.parse.current.changed
    239  desc: currentColor is computed when the attribute is set, not when it is painted
    240  canvas_types: ['HtmlCanvas']
    241  code: |
    242    canvas.setAttribute('style', 'color: #0f0');
    243    ctx.fillStyle = '#f00';
    244    ctx.fillStyle = 'currentColor';
    245    canvas.setAttribute('style', 'color: #f00');
    246    ctx.fillRect(0, 0, 100, 50);
    247    @assert pixel 50,25 == 0,255,0,255;
    248  expected: green
    249 
    250 - name: 2d.fillStyle.parse.current.removed
    251  desc: currentColor is solid black when the canvas element is not in a document
    252  canvas_types: ['HtmlCanvas']
    253  code: |
    254    // Try not to let it undetectably incorrectly pick up opaque-black
    255    // from other parts of the document:
    256    document.body.parentNode.setAttribute('style', 'color: #f00');
    257    document.body.setAttribute('style', 'color: #f00');
    258    canvas.setAttribute('style', 'color: #f00');
    259 
    260    var canvas2 = document.createElement('canvas');
    261    var ctx2 = canvas2.getContext('2d');
    262    ctx2.fillStyle = '#f00';
    263    ctx2.fillStyle = 'currentColor';
    264    ctx2.fillRect(0, 0, 100, 50);
    265    ctx.drawImage(canvas2, 0, 0);
    266 
    267    document.body.parentNode.removeAttribute('style');
    268    document.body.removeAttribute('style');
    269 
    270    @assert pixel 50,25 == 0,0,0,255;
    271  expected: |
    272    size 100 50
    273    cr.set_source_rgb(0, 0, 0)
    274    cr.rectangle(0, 0, 100, 50)
    275    cr.fill()
    276 
    277 - name: 2d.fillStyle.invalidstring
    278  code: |
    279    ctx.fillStyle = '#f00';
    280    ctx.fillRect(0, 0, 100, 50);
    281    ctx.fillStyle = '#0f0';
    282    ctx.fillStyle = 'invalid';
    283    ctx.fillRect(0, 0, 100, 50);
    284    @assert pixel 50,25 == 0,255,0,255;
    285  expected: green
    286 
    287 - name: 2d.fillStyle.invalidtype
    288  code: |
    289    ctx.fillStyle = '#f00';
    290    ctx.fillRect(0, 0, 100, 50);
    291    ctx.fillStyle = '#0f0';
    292    ctx.fillStyle = null;
    293    ctx.fillRect(0, 0, 100, 50);
    294    @assert pixel 50,25 == 0,255,0,255;
    295  expected: green
    296 
    297 - name: 2d.fillStyle.get.solid
    298  code: |
    299    ctx.fillStyle = '#fa0';
    300    @assert ctx.fillStyle === '#ffaa00';
    301 
    302 - name: 2d.fillStyle.get.semitransparent
    303  code: |
    304    ctx.fillStyle = 'rgba(255,255,255,0.45)';
    305    @assert ctx.fillStyle =~ /^rgba\(255, 255, 255, 0\.4\d+\)$/;
    306 
    307 - name: 2d.fillStyle.get.halftransparent
    308  code: |
    309    ctx.fillStyle = 'rgba(255,255,255,0.5)';
    310    @assert ctx.fillStyle === 'rgba(255, 255, 255, 0.5)';
    311 
    312 - name: 2d.fillStyle.get.transparent
    313  code: |
    314    ctx.fillStyle = 'rgba(0,0,0,0)';
    315    @assert ctx.fillStyle === 'rgba(0, 0, 0, 0)';
    316 
    317 - name: 2d.fillStyle.default
    318  code: |
    319    @assert ctx.fillStyle === '#000000';
    320 
    321 - name: 2d.fillStyle.toStringFunctionCallback
    322  desc: Passing a function in to ctx.fillStyle or ctx.strokeStyle with a toString callback works as specified
    323  code: |
    324    ctx.fillStyle = { toString: function() { return "#008000"; } };
    325    @assert ctx.fillStyle === "#008000";
    326    ctx.fillStyle = {};
    327    @assert ctx.fillStyle === "#008000";
    328    ctx.fillStyle = 800000;
    329    @assert ctx.fillStyle === "#008000";
    330    @assert throws TypeError ctx.fillStyle = { toString: function() { throw new TypeError; } };
    331    ctx.strokeStyle = { toString: function() { return "#008000"; } };
    332    @assert ctx.strokeStyle === "#008000";
    333    ctx.strokeStyle = {};
    334    @assert ctx.strokeStyle === "#008000";
    335    ctx.strokeStyle = 800000;
    336    @assert ctx.strokeStyle === "#008000";
    337    @assert throws TypeError ctx.strokeStyle = { toString: function() { throw new TypeError; } };
    338 
    339 - name: 2d.strokeStyle.default
    340  code: |
    341    @assert ctx.strokeStyle === '#000000';
    342 
    343 
    344 - name: 2d.gradient.object.type
    345  desc: window.CanvasGradient exists and has the right properties
    346  notes: &bindings Defined in "Web IDL" (draft)
    347  code: |
    348    {% set root = 'self' if canvas_type == 'Worker' else 'window' %}
    349    @assert {{ root }}.CanvasGradient !== undefined;
    350    @assert {{ root }}.CanvasGradient.prototype.addColorStop !== undefined;
    351 
    352 - name: 2d.gradient.object.return
    353  desc: createLinearGradient() and createRadialGradient() returns objects implementing
    354    CanvasGradient
    355  code: |
    356    {% set root = 'self' if canvas_type == 'Worker' else 'window' %}
    357    {{ root }}.CanvasGradient.prototype.thisImplementsCanvasGradient = true;
    358 
    359    var g1 = ctx.createLinearGradient(0, 0, 100, 0);
    360    @assert g1.addColorStop !== undefined;
    361    @assert g1.thisImplementsCanvasGradient === true;
    362 
    363    var g2 = ctx.createRadialGradient(0, 0, 10, 0, 0, 20);
    364    @assert g2.addColorStop !== undefined;
    365    @assert g2.thisImplementsCanvasGradient === true;
    366 
    367 - name: 2d.gradient.interpolate.solid
    368  code: |
    369    var g = ctx.createLinearGradient(0, 0, 100, 0);
    370    g.addColorStop(0, '#0f0');
    371    g.addColorStop(1, '#0f0');
    372    ctx.fillStyle = g;
    373    ctx.fillRect(0, 0, 100, 50);
    374    @assert pixel 50,25 == 0,255,0,255;
    375  expected: green
    376 
    377 - name: 2d.gradient.interpolate.color
    378  code: |
    379    var g = ctx.createLinearGradient(0, 0, 100, 0);
    380    g.addColorStop(0, '#ff0');
    381    g.addColorStop(1, '#00f');
    382    ctx.fillStyle = g;
    383    ctx.fillRect(0, 0, 100, 50);
    384    @assert pixel 25,25 ==~ 191,191,63,255 +/- 3;
    385    @assert pixel 50,25 ==~ 127,127,127,255 +/- 3;
    386    @assert pixel 75,25 ==~ 63,63,191,255 +/- 3;
    387  expected: |
    388    size 100 50
    389    g = cairo.LinearGradient(0, 0, 100, 0)
    390    g.add_color_stop_rgb(0, 1,1,0)
    391    g.add_color_stop_rgb(1, 0,0,1)
    392    cr.set_source(g)
    393    cr.rectangle(0, 0, 100, 50)
    394    cr.fill()
    395 
    396 - name: 2d.gradient.interpolate.alpha
    397  code: |
    398    ctx.fillStyle = '#ff0';
    399    ctx.fillRect(0, 0, 100, 50);
    400    var g = ctx.createLinearGradient(0, 0, 100, 0);
    401    g.addColorStop(0, 'rgba(0,0,255, 0)');
    402    g.addColorStop(1, 'rgba(0,0,255, 1)');
    403    ctx.fillStyle = g;
    404    ctx.fillRect(0, 0, 100, 50);
    405    @assert pixel 25,25 ==~ 191,191,63,255 +/- 3;
    406    @assert pixel 50,25 ==~ 127,127,127,255 +/- 3;
    407    @assert pixel 75,25 ==~ 63,63,191,255 +/- 3;
    408  expected: |
    409    size 100 50
    410    g = cairo.LinearGradient(0, 0, 100, 0)
    411    g.add_color_stop_rgb(0, 1,1,0)
    412    g.add_color_stop_rgb(1, 0,0,1)
    413    cr.set_source(g)
    414    cr.rectangle(0, 0, 100, 50)
    415    cr.fill()
    416 
    417 - name: 2d.gradient.interpolate.coloralpha
    418  code: |
    419    var g = ctx.createLinearGradient(0, 0, 100, 0);
    420    g.addColorStop(0, 'rgba(255,255,0, 0)');
    421    g.addColorStop(1, 'rgba(0,0,255, 1)');
    422    ctx.fillStyle = g;
    423    ctx.fillRect(0, 0, 100, 50);
    424    @assert pixel 25,25 ==~ 190,190,65,65 +/- 3;
    425    @assert pixel 50,25 ==~ 126,126,128,128 +/- 3;
    426    @assert pixel 75,25 ==~ 62,62,192,192 +/- 3;
    427  expected: |
    428    size 100 50
    429    g = cairo.LinearGradient(0, 0, 100, 0)
    430    g.add_color_stop_rgba(0, 1,1,0, 0)
    431    g.add_color_stop_rgba(1, 0,0,1, 1)
    432    cr.set_source(g)
    433    cr.rectangle(0, 0, 100, 50)
    434    cr.fill()
    435 
    436 - name: 2d.gradient.interpolate.outside
    437  code: |
    438    ctx.fillStyle = '#f00';
    439    ctx.fillRect(0, 0, 100, 50);
    440 
    441    var g = ctx.createLinearGradient(25, 0, 75, 0);
    442    g.addColorStop(0.4, '#0f0');
    443    g.addColorStop(0.6, '#0f0');
    444 
    445    ctx.fillStyle = g;
    446    ctx.fillRect(0, 0, 100, 50);
    447    @assert pixel 20,25 ==~ 0,255,0,255;
    448    @assert pixel 50,25 ==~ 0,255,0,255;
    449    @assert pixel 80,25 ==~ 0,255,0,255;
    450  expected: green
    451 
    452 - name: 2d.gradient.interpolate.zerosize.fill
    453  code: |
    454    ctx.fillStyle = '#0f0';
    455    ctx.fillRect(0, 0, 100, 50);
    456 
    457    var g = ctx.createLinearGradient(50, 25, 50, 25); // zero-length line (undefined direction)
    458    g.addColorStop(0, '#f00');
    459    g.addColorStop(1, '#f00');
    460    ctx.fillStyle = g;
    461    ctx.rect(0, 0, 100, 50);
    462    ctx.fill();
    463    @assert pixel 40,20 == 0,255,0,255;
    464  expected: green
    465 
    466 - name: 2d.gradient.interpolate.zerosize.stroke
    467  code: |
    468    ctx.fillStyle = '#0f0';
    469    ctx.fillRect(0, 0, 100, 50);
    470 
    471    var g = ctx.createLinearGradient(50, 25, 50, 25); // zero-length line (undefined direction)
    472    g.addColorStop(0, '#f00');
    473    g.addColorStop(1, '#f00');
    474    ctx.strokeStyle = g;
    475    ctx.rect(20, 20, 60, 10);
    476    ctx.stroke();
    477    @assert pixel 19,19 == 0,255,0,255;
    478    @assert pixel 20,19 == 0,255,0,255;
    479    @assert pixel 21,19 == 0,255,0,255;
    480    @assert pixel 19,20 == 0,255,0,255;
    481    @assert pixel 20,20 == 0,255,0,255;
    482    @assert pixel 21,20 == 0,255,0,255;
    483    @assert pixel 19,21 == 0,255,0,255;
    484    @assert pixel 20,21 == 0,255,0,255;
    485    @assert pixel 21,21 == 0,255,0,255;
    486  expected: green
    487 
    488 - name: 2d.gradient.interpolate.zerosize.fillRect
    489  code: |
    490    ctx.fillStyle = '#0f0';
    491    ctx.fillRect(0, 0, 100, 50);
    492 
    493    var g = ctx.createLinearGradient(50, 25, 50, 25); // zero-length line (undefined direction)
    494    g.addColorStop(0, '#f00');
    495    g.addColorStop(1, '#f00');
    496    ctx.fillStyle = g;
    497    ctx.fillRect(0, 0, 100, 50);
    498    @assert pixel 40,20 == 0,255,0,255; @moz-todo
    499  expected: green
    500 
    501 - name: 2d.gradient.interpolate.zerosize.strokeRect
    502  code: |
    503    ctx.fillStyle = '#0f0';
    504    ctx.fillRect(0, 0, 100, 50);
    505 
    506    var g = ctx.createLinearGradient(50, 25, 50, 25); // zero-length line (undefined direction)
    507    g.addColorStop(0, '#f00');
    508    g.addColorStop(1, '#f00');
    509    ctx.strokeStyle = g;
    510    ctx.strokeRect(20, 20, 60, 10);
    511    @assert pixel 19,19 == 0,255,0,255;
    512    @assert pixel 20,19 == 0,255,0,255;
    513    @assert pixel 21,19 == 0,255,0,255;
    514    @assert pixel 19,20 == 0,255,0,255;
    515    @assert pixel 20,20 == 0,255,0,255;
    516    @assert pixel 21,20 == 0,255,0,255;
    517    @assert pixel 19,21 == 0,255,0,255;
    518    @assert pixel 20,21 == 0,255,0,255;
    519    @assert pixel 21,21 == 0,255,0,255;
    520  expected: green
    521 
    522 - name: 2d.gradient.interpolate.zerosize.fillText
    523  code: |
    524    ctx.fillStyle = '#0f0';
    525    ctx.fillRect(0, 0, 100, 50);
    526 
    527    var g = ctx.createLinearGradient(50, 25, 50, 25); // zero-length line (undefined direction)
    528    g.addColorStop(0, '#f00');
    529    g.addColorStop(1, '#f00');
    530    ctx.fillStyle = g;
    531    ctx.font = '100px sans-serif';
    532    ctx.fillText("AA", 0, 50);
    533    _assertGreen(ctx, 100, 50);
    534  expected: green
    535 
    536 - name: 2d.gradient.interpolate.zerosize.strokeText
    537  code: |
    538    ctx.fillStyle = '#0f0';
    539    ctx.fillRect(0, 0, 100, 50);
    540 
    541    var g = ctx.createLinearGradient(50, 25, 50, 25); // zero-length line (undefined direction)
    542    g.addColorStop(0, '#f00');
    543    g.addColorStop(1, '#f00');
    544    ctx.strokeStyle = g;
    545    ctx.font = '100px sans-serif';
    546    ctx.strokeText("AA", 0, 50);
    547    _assertGreen(ctx, 100, 50);
    548  expected: green
    549 
    550 
    551 - name: 2d.gradient.interpolate.vertical
    552  code: |
    553    var g = ctx.createLinearGradient(0, 0, 0, 50);
    554    g.addColorStop(0, '#ff0');
    555    g.addColorStop(1, '#00f');
    556    ctx.fillStyle = g;
    557    ctx.fillRect(0, 0, 100, 50);
    558    @assert pixel 50,12 ==~ 191,191,63,255 +/- 10;
    559    @assert pixel 50,25 ==~ 127,127,127,255 +/- 5;
    560    @assert pixel 50,37 ==~ 63,63,191,255 +/- 10;
    561  expected: |
    562    size 100 50
    563    g = cairo.LinearGradient(0, 0, 0, 50)
    564    g.add_color_stop_rgb(0, 1,1,0)
    565    g.add_color_stop_rgb(1, 0,0,1)
    566    cr.set_source(g)
    567    cr.rectangle(0, 0, 100, 50)
    568    cr.fill()
    569 
    570 - name: 2d.gradient.interpolate.multiple
    571  code: |
    572    canvas.width = 200;
    573    var g = ctx.createLinearGradient(0, 0, 200, 0);
    574    g.addColorStop(0, '#ff0');
    575    g.addColorStop(0.5, '#0ff');
    576    g.addColorStop(1, '#f0f');
    577    ctx.fillStyle = g;
    578    ctx.fillRect(0, 0, 200, 50);
    579    @assert pixel 50,25 ==~ 127,255,127,255 +/- 3;
    580    @assert pixel 100,25 ==~ 0,255,255,255 +/- 3;
    581    @assert pixel 150,25 ==~ 127,127,255,255 +/- 3;
    582  expected: |
    583    size 200 50
    584    g = cairo.LinearGradient(0, 0, 200, 0)
    585    g.add_color_stop_rgb(0.0, 1,1,0)
    586    g.add_color_stop_rgb(0.5, 0,1,1)
    587    g.add_color_stop_rgb(1.0, 1,0,1)
    588    cr.set_source(g)
    589    cr.rectangle(0, 0, 200, 50)
    590    cr.fill()
    591 
    592 - name: 2d.gradient.interpolate.overlap
    593  code: |
    594    canvas.width = 200;
    595    var g = ctx.createLinearGradient(0, 0, 200, 0);
    596    g.addColorStop(0, '#f00');
    597    g.addColorStop(0, '#ff0');
    598    g.addColorStop(0.25, '#00f');
    599    g.addColorStop(0.25, '#0f0');
    600    g.addColorStop(0.25, '#0f0');
    601    g.addColorStop(0.25, '#0f0');
    602    g.addColorStop(0.25, '#ff0');
    603    g.addColorStop(0.5, '#00f');
    604    g.addColorStop(0.5, '#0f0');
    605    g.addColorStop(0.75, '#00f');
    606    g.addColorStop(0.75, '#f00');
    607    g.addColorStop(0.75, '#ff0');
    608    g.addColorStop(0.5, '#0f0');
    609    g.addColorStop(0.5, '#0f0');
    610    g.addColorStop(0.5, '#ff0');
    611    g.addColorStop(1, '#00f');
    612    ctx.fillStyle = g;
    613    ctx.fillRect(0, 0, 200, 50);
    614    @assert pixel 49,25 ==~ 0,0,255,255 +/- 16;
    615    @assert pixel 51,25 ==~ 255,255,0,255 +/- 16;
    616    @assert pixel 99,25 ==~ 0,0,255,255 +/- 16;
    617    @assert pixel 101,25 ==~ 255,255,0,255 +/- 16;
    618    @assert pixel 149,25 ==~ 0,0,255,255 +/- 16;
    619    @assert pixel 151,25 ==~ 255,255,0,255 +/- 16;
    620  expected: |
    621    size 200 50
    622    g = cairo.LinearGradient(0, 0, 50, 0)
    623    g.add_color_stop_rgb(0, 1,1,0)
    624    g.add_color_stop_rgb(1, 0,0,1)
    625    cr.set_source(g)
    626    cr.rectangle(0, 0, 50, 50)
    627    cr.fill()
    628 
    629    g = cairo.LinearGradient(50, 0, 100, 0)
    630    g.add_color_stop_rgb(0, 1,1,0)
    631    g.add_color_stop_rgb(1, 0,0,1)
    632    cr.set_source(g)
    633    cr.rectangle(50, 0, 50, 50)
    634    cr.fill()
    635 
    636    g = cairo.LinearGradient(100, 0, 150, 0)
    637    g.add_color_stop_rgb(0, 1,1,0)
    638    g.add_color_stop_rgb(1, 0,0,1)
    639    cr.set_source(g)
    640    cr.rectangle(100, 0, 50, 50)
    641    cr.fill()
    642 
    643    g = cairo.LinearGradient(150, 0, 200, 0)
    644    g.add_color_stop_rgb(0, 1,1,0)
    645    g.add_color_stop_rgb(1, 0,0,1)
    646    cr.set_source(g)
    647    cr.rectangle(150, 0, 50, 50)
    648    cr.fill()
    649 
    650 - name: 2d.gradient.interpolate.overlap2
    651  code: |
    652    var g = ctx.createLinearGradient(0, 0, 100, 0);
    653    var ps = [ 0, 1/10, 1/4, 1/3, 1/2, 3/4, 1 ];
    654    for (var p = 0; p < ps.length; ++p)
    655    {
    656            g.addColorStop(ps[p], '#0f0');
    657            for (var i = 0; i < 15; ++i)
    658                    g.addColorStop(ps[p], '#f00');
    659            g.addColorStop(ps[p], '#0f0');
    660    }
    661    ctx.fillStyle = g;
    662    ctx.fillRect(0, 0, 100, 50);
    663    @assert pixel 1,25 == 0,255,0,255;
    664    @assert pixel 30,25 == 0,255,0,255;
    665    @assert pixel 40,25 == 0,255,0,255;
    666    @assert pixel 60,25 == 0,255,0,255;
    667    @assert pixel 80,25 == 0,255,0,255;
    668  expected: green
    669 
    670 - name: 2d.gradient.empty
    671  code: |
    672    ctx.fillStyle = '#0f0';
    673    ctx.fillRect(0, 0, 100, 50);
    674    var g = ctx.createLinearGradient(0, 0, 0, 50);
    675    ctx.fillStyle = g;
    676    ctx.fillRect(0, 0, 100, 50);
    677    @assert pixel 50,25 ==~ 0,255,0,255;
    678  expected: green
    679 
    680 - name: 2d.gradient.object.update
    681  code: |
    682    var g = ctx.createLinearGradient(-100, 0, 200, 0);
    683    g.addColorStop(0, '#f00');
    684    g.addColorStop(1, '#f00');
    685    ctx.fillStyle = g;
    686    ctx.fillRect(0, 0, 100, 50);
    687    g.addColorStop(0.1, '#0f0');
    688    g.addColorStop(0.9, '#0f0');
    689    ctx.fillRect(0, 0, 100, 50);
    690    @assert pixel 50,25 ==~ 0,255,0,255;
    691  expected: green
    692 
    693 - name: 2d.gradient.object.compare
    694  code: |
    695    var g1 = ctx.createLinearGradient(0, 0, 100, 0);
    696    var g2 = ctx.createLinearGradient(0, 0, 100, 0);
    697    @assert g1 !== g2;
    698    ctx.fillStyle = g1;
    699    @assert ctx.fillStyle === g1;
    700 
    701 - name: 2d.gradient.object.crosscanvas
    702  code: |
    703    ctx.fillStyle = '#f00';
    704    ctx.fillRect(0, 0, 100, 50);
    705    var g = {{ create_canvas }}.getContext('2d').createLinearGradient(0, 0, 100, 0);
    706    g.addColorStop(0, '#0f0');
    707    g.addColorStop(1, '#0f0');
    708    ctx.fillStyle = g;
    709    ctx.fillRect(0, 0, 100, 50);
    710    @assert pixel 50,25 ==~ 0,255,0,255;
    711  expected: green
    712  append_variants_to_name: false
    713  variants:
    714  - HtmlCanvas:
    715      canvas_types: ['HtmlCanvas']
    716      create_canvas: document.createElement('canvas')
    717    OffscreenCanvas:
    718      canvas_types: ['OffscreenCanvas', 'Worker']
    719      create_canvas: new OffscreenCanvas(100, 50)
    720 
    721 - name: 2d.gradient.object.current
    722  canvas_types: ['HtmlCanvas']
    723  code: |
    724    canvas.setAttribute('style', 'color: #f00');
    725 
    726    ctx.fillStyle = '#f00';
    727    ctx.fillRect(0, 0, 100, 50);
    728 
    729    var g = ctx.createLinearGradient(0, 0, 100, 0);
    730    g.addColorStop(0, 'currentColor');
    731    g.addColorStop(1, 'currentColor');
    732    ctx.fillStyle = g;
    733    ctx.fillRect(0, 0, 100, 50);
    734    @assert pixel 50,25 ==~ 0,0,0,255;
    735  expected: |
    736    size 100 50
    737    cr.set_source_rgb(0, 0, 0)
    738    cr.rectangle(0, 0, 100, 50)
    739    cr.fill()
    740 
    741 - name: 2d.gradient.object.invalidoffset
    742  code: |
    743    var g = ctx.createLinearGradient(0, 0, 100, 0);
    744    @assert throws INDEX_SIZE_ERR g.addColorStop(-1, '#000');
    745    @assert throws INDEX_SIZE_ERR g.addColorStop(2, '#000');
    746    @assert throws TypeError g.addColorStop(Infinity, '#000');
    747    @assert throws TypeError g.addColorStop(-Infinity, '#000');
    748    @assert throws TypeError g.addColorStop(NaN, '#000');
    749 
    750 - name: 2d.gradient.object.invalidcolor
    751  code: |
    752    var g = ctx.createLinearGradient(0, 0, 100, 0);
    753    @assert throws SYNTAX_ERR g.addColorStop(0, "");
    754    @assert throws SYNTAX_ERR g.addColorStop(0, 'rgb(NaN%, NaN%, NaN%)');
    755    @assert throws SYNTAX_ERR g.addColorStop(0, 'null');
    756    @assert throws SYNTAX_ERR g.addColorStop(0, 'undefined');
    757    @assert throws SYNTAX_ERR g.addColorStop(0, null);
    758    @assert throws SYNTAX_ERR g.addColorStop(0, undefined);
    759 
    760    var g = ctx.createRadialGradient(0, 0, 0, 100, 0, 0);
    761    @assert throws SYNTAX_ERR g.addColorStop(0, "");
    762    @assert throws SYNTAX_ERR g.addColorStop(0, 'rgb(NaN%, NaN%, NaN%)');
    763    @assert throws SYNTAX_ERR g.addColorStop(0, 'null');
    764    @assert throws SYNTAX_ERR g.addColorStop(0, 'undefined');
    765    @assert throws SYNTAX_ERR g.addColorStop(0, null);
    766    @assert throws SYNTAX_ERR g.addColorStop(0, undefined);
    767 
    768 
    769 - name: 2d.gradient.linear.nonfinite
    770  desc: createLinearGradient() throws TypeError if arguments are not finite
    771  notes: *bindings
    772  code: |
    773    @nonfinite @assert throws TypeError ctx.createLinearGradient(<0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <1 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>);
    774 
    775 - name: 2d.gradient.linear.transform.1
    776  desc: Linear gradient coordinates are relative to the coordinate space at the time
    777    of filling
    778  code: |
    779    var g = ctx.createLinearGradient(0, 0, 200, 0);
    780    g.addColorStop(0, '#f00');
    781    g.addColorStop(0.25, '#0f0');
    782    g.addColorStop(0.75, '#0f0');
    783    g.addColorStop(1, '#f00');
    784    ctx.fillStyle = g;
    785    ctx.translate(-50, 0);
    786    ctx.fillRect(50, 0, 100, 50);
    787    @assert pixel 25,25 == 0,255,0,255;
    788    @assert pixel 50,25 == 0,255,0,255;
    789    @assert pixel 75,25 == 0,255,0,255;
    790  expected: green
    791 
    792 - name: 2d.gradient.linear.transform.2
    793  desc: Linear gradient coordinates are relative to the coordinate space at the time
    794    of filling
    795  code: |
    796    ctx.translate(100, 0);
    797    var g = ctx.createLinearGradient(0, 0, 200, 0);
    798    g.addColorStop(0, '#f00');
    799    g.addColorStop(0.25, '#0f0');
    800    g.addColorStop(0.75, '#0f0');
    801    g.addColorStop(1, '#f00');
    802    ctx.fillStyle = g;
    803    ctx.translate(-150, 0);
    804    ctx.fillRect(50, 0, 100, 50);
    805    @assert pixel 25,25 == 0,255,0,255;
    806    @assert pixel 50,25 == 0,255,0,255;
    807    @assert pixel 75,25 == 0,255,0,255;
    808  expected: green
    809 
    810 - name: 2d.gradient.linear.transform.3
    811  desc: Linear gradient transforms do not experience broken caching effects
    812  code: |
    813    var g = ctx.createLinearGradient(0, 0, 200, 0);
    814    g.addColorStop(0, '#f00');
    815    g.addColorStop(0.25, '#0f0');
    816    g.addColorStop(0.75, '#0f0');
    817    g.addColorStop(1, '#f00');
    818    ctx.fillStyle = g;
    819    ctx.fillRect(0, 0, 100, 50);
    820    ctx.translate(-50, 0);
    821    ctx.fillRect(50, 0, 100, 50);
    822    @assert pixel 25,25 == 0,255,0,255;
    823    @assert pixel 50,25 == 0,255,0,255;
    824    @assert pixel 75,25 == 0,255,0,255;
    825  expected: green
    826 
    827 - name: 2d.gradient.radial.negative
    828  desc: createRadialGradient() throws INDEX_SIZE_ERR if either radius is negative
    829  code: |
    830    @assert throws INDEX_SIZE_ERR ctx.createRadialGradient(0, 0, -0.1, 0, 0, 1);
    831    @assert throws INDEX_SIZE_ERR ctx.createRadialGradient(0, 0, 1, 0, 0, -0.1);
    832    @assert throws INDEX_SIZE_ERR ctx.createRadialGradient(0, 0, -0.1, 0, 0, -0.1);
    833 
    834 - name: 2d.gradient.radial.nonfinite
    835  desc: createRadialGradient() throws TypeError if arguments are not finite
    836  notes: *bindings
    837  code: |
    838    @nonfinite @assert throws TypeError ctx.createRadialGradient(<0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <1 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <1 Infinity -Infinity NaN>);
    839 
    840 - name: 2d.gradient.radial.inside1
    841  code: |
    842    ctx.fillStyle = '#f00';
    843    ctx.fillRect(0, 0, 100, 50);
    844 
    845    var g = ctx.createRadialGradient(50, 25, 100, 50, 25, 200);
    846    g.addColorStop(0, '#0f0');
    847    g.addColorStop(1, '#f00');
    848    ctx.fillStyle = g;
    849    ctx.fillRect(0, 0, 100, 50);
    850 
    851    @assert pixel 1,1 == 0,255,0,255;
    852    @assert pixel 50,1 == 0,255,0,255;
    853    @assert pixel 98,1 == 0,255,0,255;
    854    @assert pixel 1,25 == 0,255,0,255;
    855    @assert pixel 50,25 == 0,255,0,255;
    856    @assert pixel 98,25 ==~ 0,255,0,255 +/- 1;
    857    @assert pixel 1,48 == 0,255,0,255;
    858    @assert pixel 50,48 ==~ 0,255,0,255 +/- 1;
    859    @assert pixel 98,48 == 0,255,0,255;
    860  expected: green
    861 
    862 - name: 2d.gradient.radial.inside2
    863  code: |
    864    ctx.fillStyle = '#f00';
    865    ctx.fillRect(0, 0, 100, 50);
    866 
    867    var g = ctx.createRadialGradient(50, 25, 200, 50, 25, 100);
    868    g.addColorStop(0, '#f00');
    869    g.addColorStop(1, '#0f0');
    870    ctx.fillStyle = g;
    871    ctx.fillRect(0, 0, 100, 50);
    872 
    873    @assert pixel 1,1 == 0,255,0,255;
    874    @assert pixel 50,1 == 0,255,0,255;
    875    @assert pixel 98,1 == 0,255,0,255;
    876    @assert pixel 1,25 == 0,255,0,255;
    877    @assert pixel 50,25 == 0,255,0,255;
    878    @assert pixel 98,25 ==~ 0,255,0,255 +/- 1;
    879    @assert pixel 1,48 == 0,255,0,255;
    880    @assert pixel 50,48 ==~ 0,255,0,255 +/- 1;
    881    @assert pixel 98,48 == 0,255,0,255;
    882  expected: green
    883 
    884 - name: 2d.gradient.radial.inside3
    885  code: |
    886    ctx.fillStyle = '#f00';
    887    ctx.fillRect(0, 0, 100, 50);
    888 
    889    var g = ctx.createRadialGradient(50, 25, 200, 50, 25, 100);
    890    g.addColorStop(0, '#f00');
    891    g.addColorStop(0.993, '#f00');
    892    g.addColorStop(1, '#0f0');
    893    ctx.fillStyle = g;
    894    ctx.fillRect(0, 0, 100, 50);
    895 
    896    @assert pixel 1,1 == 0,255,0,255;
    897    @assert pixel 50,1 == 0,255,0,255;
    898    @assert pixel 98,1 == 0,255,0,255;
    899    @assert pixel 1,25 == 0,255,0,255;
    900    @assert pixel 50,25 == 0,255,0,255;
    901    @assert pixel 98,25 ==~ 0,255,0,255 +/- 1;
    902    @assert pixel 1,48 == 0,255,0,255;
    903    @assert pixel 50,48 ==~ 0,255,0,255 +/- 1;
    904    @assert pixel 98,48 == 0,255,0,255;
    905  expected: green
    906 
    907 - name: 2d.gradient.radial.outside1
    908  code: |
    909    ctx.fillStyle = '#f00';
    910    ctx.fillRect(0, 0, 100, 50);
    911 
    912    var g = ctx.createRadialGradient(200, 25, 10, 200, 25, 20);
    913    g.addColorStop(0, '#f00');
    914    g.addColorStop(1, '#0f0');
    915    ctx.fillStyle = g;
    916    ctx.fillRect(0, 0, 100, 50);
    917 
    918    @assert pixel 1,1 == 0,255,0,255;
    919    @assert pixel 50,1 == 0,255,0,255;
    920    @assert pixel 98,1 == 0,255,0,255;
    921    @assert pixel 1,25 == 0,255,0,255;
    922    @assert pixel 50,25 == 0,255,0,255;
    923    @assert pixel 98,25 ==~ 0,255,0,255 +/- 1;
    924    @assert pixel 1,48 == 0,255,0,255;
    925    @assert pixel 50,48 ==~ 0,255,0,255 +/- 1;
    926    @assert pixel 98,48 == 0,255,0,255;
    927  expected: green
    928 
    929 - name: 2d.gradient.radial.outside2
    930  code: |
    931    ctx.fillStyle = '#f00';
    932    ctx.fillRect(0, 0, 100, 50);
    933 
    934    var g = ctx.createRadialGradient(200, 25, 20, 200, 25, 10);
    935    g.addColorStop(0, '#0f0');
    936    g.addColorStop(1, '#f00');
    937    ctx.fillStyle = g;
    938    ctx.fillRect(0, 0, 100, 50);
    939 
    940    @assert pixel 1,1 == 0,255,0,255;
    941    @assert pixel 50,1 == 0,255,0,255;
    942    @assert pixel 98,1 == 0,255,0,255;
    943    @assert pixel 1,25 == 0,255,0,255;
    944    @assert pixel 50,25 == 0,255,0,255;
    945    @assert pixel 98,25 ==~ 0,255,0,255 +/- 1;
    946    @assert pixel 1,48 == 0,255,0,255;
    947    @assert pixel 50,48 ==~ 0,255,0,255 +/- 1;
    948    @assert pixel 98,48 == 0,255,0,255;
    949  expected: green
    950 
    951 - name: 2d.gradient.radial.outside3
    952  code: |
    953    ctx.fillStyle = '#f00';
    954    ctx.fillRect(0, 0, 100, 50);
    955 
    956    var g = ctx.createRadialGradient(200, 25, 20, 200, 25, 10);
    957    g.addColorStop(0, '#0f0');
    958    g.addColorStop(0.001, '#f00');
    959    g.addColorStop(1, '#f00');
    960    ctx.fillStyle = g;
    961    ctx.fillRect(0, 0, 100, 50);
    962 
    963    @assert pixel 1,1 == 0,255,0,255;
    964    @assert pixel 50,1 == 0,255,0,255;
    965    @assert pixel 98,1 == 0,255,0,255;
    966    @assert pixel 1,25 == 0,255,0,255;
    967    @assert pixel 50,25 == 0,255,0,255;
    968    @assert pixel 98,25 ==~ 0,255,0,255 +/- 1;
    969    @assert pixel 1,48 == 0,255,0,255;
    970    @assert pixel 50,48 ==~ 0,255,0,255 +/- 1;
    971    @assert pixel 98,48 == 0,255,0,255;
    972  expected: green
    973 
    974 - name: 2d.gradient.radial.touch1
    975  code: |
    976    ctx.fillStyle = '#0f0';
    977    ctx.fillRect(0, 0, 100, 50);
    978 
    979    var g = ctx.createRadialGradient(150, 25, 50, 200, 25, 100);
    980    g.addColorStop(0, '#f00');
    981    g.addColorStop(1, '#f00');
    982    ctx.fillStyle = g;
    983    ctx.fillRect(0, 0, 100, 50);
    984 
    985    @assert pixel 1,1 == 0,255,0,255; @moz-todo
    986    @assert pixel 50,1 == 0,255,0,255; @moz-todo
    987    @assert pixel 98,1 == 0,255,0,255; @moz-todo
    988    @assert pixel 1,25 == 0,255,0,255; @moz-todo
    989    @assert pixel 50,25 == 0,255,0,255; @moz-todo
    990    @assert pixel 98,25 ==~ 0,255,0,255 +/- 1; @moz-todo
    991    @assert pixel 1,48 == 0,255,0,255; @moz-todo
    992    @assert pixel 50,48 ==~ 0,255,0,255 +/- 1; @moz-todo
    993    @assert pixel 98,48 == 0,255,0,255; @moz-todo
    994  expected: green
    995 
    996 - name: 2d.gradient.radial.touch2
    997  code: |
    998    ctx.fillStyle = '#f00';
    999    ctx.fillRect(0, 0, 100, 50);
   1000 
   1001    var g = ctx.createRadialGradient(-80, 25, 70, 0, 25, 150);
   1002    g.addColorStop(0, '#f00');
   1003    g.addColorStop(0.01, '#0f0');
   1004    g.addColorStop(0.99, '#0f0');
   1005    g.addColorStop(1, '#f00');
   1006    ctx.fillStyle = g;
   1007    ctx.fillRect(0, 0, 100, 50);
   1008 
   1009    @assert pixel 1,1 == 0,255,0,255;
   1010    @assert pixel 50,1 == 0,255,0,255;
   1011    @assert pixel 98,1 == 0,255,0,255;
   1012    @assert pixel 1,25 == 0,255,0,255;
   1013    @assert pixel 50,25 == 0,255,0,255;
   1014    @assert pixel 98,25 ==~ 0,255,0,255 +/- 1;
   1015    @assert pixel 1,48 == 0,255,0,255;
   1016    @assert pixel 50,48 ==~ 0,255,0,255 +/- 1;
   1017    @assert pixel 98,48 == 0,255,0,255;
   1018  expected: green
   1019 
   1020 - name: 2d.gradient.radial.touch3
   1021  code: |
   1022    ctx.fillStyle = '#0f0';
   1023    ctx.fillRect(0, 0, 100, 50);
   1024 
   1025    var g = ctx.createRadialGradient(120, -15, 25, 140, -30, 50);
   1026    g.addColorStop(0, '#f00');
   1027    g.addColorStop(1, '#f00');
   1028    ctx.fillStyle = g;
   1029    ctx.fillRect(0, 0, 100, 50);
   1030 
   1031    @assert pixel 1,1 == 0,255,0,255; @moz-todo
   1032    @assert pixel 50,1 == 0,255,0,255; @moz-todo
   1033    @assert pixel 98,1 == 0,255,0,255; @moz-todo
   1034    @assert pixel 1,25 == 0,255,0,255; @moz-todo
   1035    @assert pixel 50,25 == 0,255,0,255; @moz-todo
   1036    @assert pixel 98,25 ==~ 0,255,0,255 +/- 1; @moz-todo
   1037    @assert pixel 1,48 == 0,255,0,255; @moz-todo
   1038    @assert pixel 50,48 ==~ 0,255,0,255 +/- 1; @moz-todo
   1039    @assert pixel 98,48 == 0,255,0,255; @moz-todo
   1040  expected: green
   1041 
   1042 - name: 2d.gradient.radial.equal
   1043  code: |
   1044    ctx.fillStyle = '#0f0';
   1045    ctx.fillRect(0, 0, 100, 50);
   1046 
   1047    var g = ctx.createRadialGradient(50, 25, 20, 50, 25, 20);
   1048    g.addColorStop(0, '#f00');
   1049    g.addColorStop(1, '#f00');
   1050    ctx.fillStyle = g;
   1051    ctx.fillRect(0, 0, 100, 50);
   1052 
   1053    @assert pixel 1,1 == 0,255,0,255; @moz-todo
   1054    @assert pixel 50,1 == 0,255,0,255; @moz-todo
   1055    @assert pixel 98,1 == 0,255,0,255; @moz-todo
   1056    @assert pixel 1,25 == 0,255,0,255; @moz-todo
   1057    @assert pixel 50,25 == 0,255,0,255; @moz-todo
   1058    @assert pixel 98,25 ==~ 0,255,0,255 +/- 1; @moz-todo
   1059    @assert pixel 1,48 == 0,255,0,255; @moz-todo
   1060    @assert pixel 50,48 ==~ 0,255,0,255 +/- 1; @moz-todo
   1061    @assert pixel 98,48 == 0,255,0,255; @moz-todo
   1062  expected: green
   1063 
   1064 - name: 2d.gradient.radial.cone.behind
   1065  code: |
   1066    ctx.fillStyle = '#0f0';
   1067    ctx.fillRect(0, 0, 100, 50);
   1068 
   1069    var g = ctx.createRadialGradient(120, 25, 10, 211, 25, 100);
   1070    g.addColorStop(0, '#f00');
   1071    g.addColorStop(1, '#f00');
   1072    ctx.fillStyle = g;
   1073    ctx.fillRect(0, 0, 100, 50);
   1074 
   1075    @assert pixel 1,1 == 0,255,0,255; @moz-todo
   1076    @assert pixel 50,1 == 0,255,0,255; @moz-todo
   1077    @assert pixel 98,1 == 0,255,0,255; @moz-todo
   1078    @assert pixel 1,25 == 0,255,0,255; @moz-todo
   1079    @assert pixel 50,25 == 0,255,0,255; @moz-todo
   1080    @assert pixel 98,25 ==~ 0,255,0,255 +/- 1; @moz-todo
   1081    @assert pixel 1,48 == 0,255,0,255; @moz-todo
   1082    @assert pixel 50,48 ==~ 0,255,0,255 +/- 1; @moz-todo
   1083    @assert pixel 98,48 == 0,255,0,255; @moz-todo
   1084  expected: green
   1085 
   1086 - name: 2d.gradient.radial.cone.front
   1087  code: |
   1088    ctx.fillStyle = '#f00';
   1089    ctx.fillRect(0, 0, 100, 50);
   1090 
   1091    var g = ctx.createRadialGradient(311, 25, 10, 210, 25, 100);
   1092    g.addColorStop(0, '#f00');
   1093    g.addColorStop(1, '#0f0');
   1094    ctx.fillStyle = g;
   1095    ctx.fillRect(0, 0, 100, 50);
   1096 
   1097    @assert pixel 1,1 == 0,255,0,255;
   1098    @assert pixel 50,1 == 0,255,0,255;
   1099    @assert pixel 98,1 == 0,255,0,255;
   1100    @assert pixel 1,25 == 0,255,0,255;
   1101    @assert pixel 50,25 == 0,255,0,255;
   1102    @assert pixel 98,25 ==~ 0,255,0,255 +/- 1;
   1103    @assert pixel 1,48 == 0,255,0,255;
   1104    @assert pixel 50,48 ==~ 0,255,0,255 +/- 1;
   1105    @assert pixel 98,48 == 0,255,0,255;
   1106  expected: green
   1107 
   1108 - name: 2d.gradient.radial.cone.bottom
   1109  code: |
   1110    ctx.fillStyle = '#f00';
   1111    ctx.fillRect(0, 0, 100, 50);
   1112 
   1113    var g = ctx.createRadialGradient(210, 25, 100, 230, 25, 101);
   1114    g.addColorStop(0, '#0f0');
   1115    g.addColorStop(1, '#f00');
   1116    ctx.fillStyle = g;
   1117    ctx.fillRect(0, 0, 100, 50);
   1118 
   1119    @assert pixel 1,1 == 0,255,0,255;
   1120    @assert pixel 50,1 == 0,255,0,255;
   1121    @assert pixel 98,1 == 0,255,0,255;
   1122    @assert pixel 1,25 == 0,255,0,255;
   1123    @assert pixel 50,25 == 0,255,0,255;
   1124    @assert pixel 98,25 ==~ 0,255,0,255 +/- 1;
   1125    @assert pixel 1,48 == 0,255,0,255;
   1126    @assert pixel 50,48 ==~ 0,255,0,255 +/- 1;
   1127    @assert pixel 98,48 == 0,255,0,255;
   1128  expected: green
   1129 
   1130 - name: 2d.gradient.radial.cone.top
   1131  code: |
   1132    ctx.fillStyle = '#f00';
   1133    ctx.fillRect(0, 0, 100, 50);
   1134 
   1135    var g = ctx.createRadialGradient(230, 25, 100, 100, 25, 101);
   1136    g.addColorStop(0, '#f00');
   1137    g.addColorStop(1, '#0f0');
   1138    ctx.fillStyle = g;
   1139    ctx.fillRect(0, 0, 100, 50);
   1140 
   1141    @assert pixel 1,1 == 0,255,0,255;
   1142    @assert pixel 50,1 == 0,255,0,255;
   1143    @assert pixel 98,1 == 0,255,0,255;
   1144    @assert pixel 1,25 == 0,255,0,255;
   1145    @assert pixel 50,25 == 0,255,0,255;
   1146    @assert pixel 98,25 ==~ 0,255,0,255 +/- 1;
   1147    @assert pixel 1,48 == 0,255,0,255;
   1148    @assert pixel 50,48 ==~ 0,255,0,255 +/- 1;
   1149    @assert pixel 98,48 == 0,255,0,255;
   1150  expected: green
   1151 
   1152 - name: 2d.gradient.radial.cone.beside
   1153  code: |
   1154    ctx.fillStyle = '#0f0';
   1155    ctx.fillRect(0, 0, 100, 50);
   1156 
   1157    var g = ctx.createRadialGradient(0, 100, 40, 100, 100, 50);
   1158    g.addColorStop(0, '#f00');
   1159    g.addColorStop(1, '#f00');
   1160    ctx.fillStyle = g;
   1161    ctx.fillRect(0, 0, 100, 50);
   1162 
   1163    @assert pixel 1,1 == 0,255,0,255; @moz-todo
   1164    @assert pixel 50,1 == 0,255,0,255; @moz-todo
   1165    @assert pixel 98,1 == 0,255,0,255; @moz-todo
   1166    @assert pixel 1,25 == 0,255,0,255; @moz-todo
   1167    @assert pixel 50,25 == 0,255,0,255; @moz-todo
   1168    @assert pixel 98,25 ==~ 0,255,0,255 +/- 1; @moz-todo
   1169    @assert pixel 1,48 == 0,255,0,255; @moz-todo
   1170    @assert pixel 50,48 ==~ 0,255,0,255 +/- 1; @moz-todo
   1171    @assert pixel 98,48 == 0,255,0,255; @moz-todo
   1172  expected: green
   1173 
   1174 - name: 2d.gradient.radial.cone.cylinder
   1175  code: |
   1176    ctx.fillStyle = '#f00';
   1177    ctx.fillRect(0, 0, 100, 50);
   1178 
   1179    var g = ctx.createRadialGradient(210, 25, 100, 230, 25, 100);
   1180    g.addColorStop(0, '#0f0');
   1181    g.addColorStop(1, '#f00');
   1182    ctx.fillStyle = g;
   1183    ctx.fillRect(0, 0, 100, 50);
   1184 
   1185    @assert pixel 1,1 == 0,255,0,255;
   1186    @assert pixel 50,1 == 0,255,0,255;
   1187    @assert pixel 98,1 == 0,255,0,255;
   1188    @assert pixel 1,25 == 0,255,0,255;
   1189    @assert pixel 50,25 == 0,255,0,255;
   1190    @assert pixel 98,25 ==~ 0,255,0,255 +/- 1;
   1191    @assert pixel 1,48 == 0,255,0,255;
   1192    @assert pixel 50,48 ==~ 0,255,0,255 +/- 1;
   1193    @assert pixel 98,48 == 0,255,0,255;
   1194  expected: green
   1195 
   1196 - name: 2d.gradient.radial.cone.shape1
   1197  code: |
   1198    var tol = 1; // tolerance to avoid antialiasing artifacts
   1199 
   1200    ctx.fillStyle = '#0f0';
   1201    ctx.fillRect(0, 0, 100, 50);
   1202 
   1203    ctx.fillStyle = '#f00';
   1204    ctx.beginPath();
   1205    ctx.moveTo(30+tol, 40);
   1206    ctx.lineTo(110, -20+tol);
   1207    ctx.lineTo(110, 100-tol);
   1208    ctx.fill();
   1209 
   1210    var g = ctx.createRadialGradient(30+10*5/2, 40, 10*3/2, 30+10*15/4, 40, 10*9/4);
   1211    g.addColorStop(0, '#0f0');
   1212    g.addColorStop(1, '#0f0');
   1213    ctx.fillStyle = g;
   1214    ctx.fillRect(0, 0, 100, 50);
   1215 
   1216    @assert pixel 1,1 == 0,255,0,255;
   1217    @assert pixel 50,1 == 0,255,0,255;
   1218    @assert pixel 98,1 == 0,255,0,255;
   1219    @assert pixel 1,25 == 0,255,0,255;
   1220    @assert pixel 50,25 == 0,255,0,255;
   1221    @assert pixel 98,25 ==~ 0,255,0,255 +/- 1;
   1222    @assert pixel 1,48 == 0,255,0,255;
   1223    @assert pixel 50,48 ==~ 0,255,0,255 +/- 1;
   1224    @assert pixel 98,48 == 0,255,0,255;
   1225  expected: green
   1226 
   1227 - name: 2d.gradient.radial.cone.shape2
   1228  code: |
   1229    var tol = 1; // tolerance to avoid antialiasing artifacts
   1230 
   1231    ctx.fillStyle = '#0f0';
   1232    ctx.fillRect(0, 0, 100, 50);
   1233 
   1234    var g = ctx.createRadialGradient(30+10*5/2, 40, 10*3/2, 30+10*15/4, 40, 10*9/4);
   1235    g.addColorStop(0, '#f00');
   1236    g.addColorStop(1, '#f00');
   1237    ctx.fillStyle = g;
   1238    ctx.fillRect(0, 0, 100, 50);
   1239 
   1240    ctx.fillStyle = '#0f0';
   1241    ctx.beginPath();
   1242    ctx.moveTo(30-tol, 40);
   1243    ctx.lineTo(110, -20-tol);
   1244    ctx.lineTo(110, 100+tol);
   1245    ctx.fill();
   1246 
   1247    @assert pixel 1,1 == 0,255,0,255; @moz-todo
   1248    @assert pixel 50,1 == 0,255,0,255; @moz-todo
   1249    @assert pixel 98,1 == 0,255,0,255;
   1250    @assert pixel 1,25 == 0,255,0,255; @moz-todo
   1251    @assert pixel 50,25 == 0,255,0,255;
   1252    @assert pixel 98,25 ==~ 0,255,0,255 +/- 1;
   1253    @assert pixel 1,48 == 0,255,0,255; @moz-todo
   1254    @assert pixel 50,48 ==~ 0,255,0,255 +/- 1;
   1255    @assert pixel 98,48 == 0,255,0,255;
   1256  expected: green
   1257 
   1258 - name: 2d.gradient.radial.transform.1
   1259  desc: Radial gradient coordinates are relative to the coordinate space at the time
   1260    of filling
   1261  code: |
   1262    var g = ctx.createRadialGradient(0, 0, 0, 0, 0, 11.2);
   1263    g.addColorStop(0, '#0f0');
   1264    g.addColorStop(0.5, '#0f0');
   1265    g.addColorStop(0.51, '#f00');
   1266    g.addColorStop(1, '#f00');
   1267    ctx.fillStyle = g;
   1268    ctx.translate(50, 25);
   1269    ctx.scale(10, 10);
   1270    ctx.fillRect(-5, -2.5, 10, 5);
   1271    @assert pixel 25,25 == 0,255,0,255;
   1272    @assert pixel 50,25 == 0,255,0,255;
   1273    @assert pixel 75,25 == 0,255,0,255;
   1274  expected: green
   1275 
   1276 - name: 2d.gradient.radial.transform.2
   1277  desc: Radial gradient coordinates are relative to the coordinate space at the time
   1278    of filling
   1279  code: |
   1280    ctx.translate(100, 0);
   1281    var g = ctx.createRadialGradient(0, 0, 0, 0, 0, 11.2);
   1282    g.addColorStop(0, '#0f0');
   1283    g.addColorStop(0.5, '#0f0');
   1284    g.addColorStop(0.51, '#f00');
   1285    g.addColorStop(1, '#f00');
   1286    ctx.fillStyle = g;
   1287    ctx.translate(-50, 25);
   1288    ctx.scale(10, 10);
   1289    ctx.fillRect(-5, -2.5, 10, 5);
   1290    @assert pixel 25,25 == 0,255,0,255;
   1291    @assert pixel 50,25 == 0,255,0,255;
   1292    @assert pixel 75,25 == 0,255,0,255;
   1293  expected: green
   1294 
   1295 - name: 2d.gradient.radial.transform.3
   1296  desc: Radial gradient transforms do not experience broken caching effects
   1297  code: |
   1298    var g = ctx.createRadialGradient(0, 0, 0, 0, 0, 11.2);
   1299    g.addColorStop(0, '#0f0');
   1300    g.addColorStop(0.5, '#0f0');
   1301    g.addColorStop(0.51, '#f00');
   1302    g.addColorStop(1, '#f00');
   1303    ctx.fillStyle = g;
   1304    ctx.fillRect(0, 0, 100, 50);
   1305    ctx.translate(50, 25);
   1306    ctx.scale(10, 10);
   1307    ctx.fillRect(-5, -2.5, 10, 5);
   1308    @assert pixel 25,25 == 0,255,0,255;
   1309    @assert pixel 50,25 == 0,255,0,255;
   1310    @assert pixel 75,25 == 0,255,0,255;
   1311  expected: green
   1312 
   1313 - name: 2d.gradient.conic.positive.rotation
   1314  desc: Conic gradient with positive rotation
   1315  code: |
   1316    const g = ctx.createConicGradient(3*Math.PI/2, 50, 25);
   1317    // It's red in the upper right region and green on the lower left region
   1318    g.addColorStop(0, "#f00");
   1319    g.addColorStop(0.25, "#0f0");
   1320    g.addColorStop(0.50, "#0f0");
   1321    g.addColorStop(0.75, "#f00");
   1322    ctx.fillStyle = g;
   1323    ctx.fillRect(0, 0, 100, 50);
   1324    @assert pixel 25,15 ==~ 255,0,0,255 +/- 3;
   1325    @assert pixel 75,40 ==~ 0,255,0,255 +/- 3;
   1326  expected: green
   1327 
   1328 - name: 2d.gradient.conic.negative.rotation
   1329  desc: Conic gradient with negative rotation
   1330  code: |
   1331    const g = ctx.createConicGradient(-Math.PI/2, 50, 25);
   1332    // It's red in the upper right region and green on the lower left region
   1333    g.addColorStop(0, "#f00");
   1334    g.addColorStop(0.25, "#0f0");
   1335    g.addColorStop(0.50, "#0f0");
   1336    g.addColorStop(0.75, "#f00");
   1337    ctx.fillStyle = g;
   1338    ctx.fillRect(0, 0, 100, 50);
   1339    @assert pixel 25,15 ==~ 255,0,0,255 +/- 3;
   1340    @assert pixel 75,40 ==~ 0,255,0,255 +/- 3;
   1341  expected: green
   1342 
   1343 - name: 2d.gradient.conic.invalid.inputs
   1344  desc: Conic gradient function with invalid inputs
   1345  code: |
   1346    @nonfinite @assert throws TypeError ctx.createConicGradient(<0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <1 Infinity -Infinity NaN>);
   1347 
   1348    const g = ctx.createConicGradient(0, 0, 25);
   1349    @nonfinite @assert throws TypeError g.addColorStop(<Infinity -Infinity NaN>, <'#f00'>);
   1350    @nonfinite @assert throws SYNTAX_ERR g.addColorStop(<0>, <Infinity -Infinity NaN>);
   1351 
   1352 - name: 2d.pattern.basic.type
   1353  images:
   1354  - green.png
   1355  code: |
   1356    {% set root = 'self' if canvas_type == 'Worker' else 'window' %}
   1357    @assert {{ root }}.CanvasPattern !== undefined;
   1358 
   1359    {{ root }}.CanvasPattern.prototype.thisImplementsCanvasPattern = true;
   1360 
   1361    {{ load_image }}
   1362    var pattern = ctx.createPattern(img, 'no-repeat');
   1363    @assert pattern.thisImplementsCanvasPattern;
   1364  variants: &load-image-variant-definition
   1365  - HtmlCanvas:
   1366      append_variants_to_name: false
   1367      canvas_types: ['HtmlCanvas']
   1368      load_image: var img = document.getElementById('{{ (images or svgimages)[0] }}');
   1369    OffscreenCanvas:
   1370      append_variants_to_name: false
   1371      canvas_types: ['OffscreenCanvas', 'Worker']
   1372      test_type: promise
   1373      load_image: |-
   1374        var response = await fetch('/images/{{ (images or svgimages)[0] }}')
   1375        var blob = await response.blob();
   1376        var img = await createImageBitmap(blob);
   1377 
   1378 - name: 2d.pattern.basic.image
   1379  images:
   1380  - green.png
   1381  code: |
   1382    ctx.fillStyle = '#f00';
   1383    ctx.fillRect(0, 0, 100, 50);
   1384    {{ load_image }}
   1385    var pattern = ctx.createPattern(img, 'no-repeat');
   1386    ctx.fillStyle = pattern;
   1387    ctx.fillRect(0, 0, 100, 50);
   1388 
   1389    @assert pixel 1,1 == 0,255,0,255;
   1390    @assert pixel 98,1 == 0,255,0,255;
   1391    @assert pixel 1,48 == 0,255,0,255;
   1392    @assert pixel 98,48 == 0,255,0,255;
   1393  expected: green
   1394  variants: *load-image-variant-definition
   1395 
   1396 - name: 2d.pattern.basic.canvas
   1397  code: |
   1398    ctx.fillStyle = '#f00';
   1399    ctx.fillRect(0, 0, 100, 50);
   1400 
   1401    {{ create_canvas2 }}
   1402    var ctx2 = canvas2.getContext('2d');
   1403    ctx2.fillStyle = '#0f0';
   1404    ctx2.fillRect(0, 0, 100, 50);
   1405 
   1406    var pattern = ctx.createPattern(canvas2, 'no-repeat');
   1407    ctx.fillStyle = pattern;
   1408    ctx.fillRect(0, 0, 100, 50);
   1409 
   1410    @assert pixel 1,1 == 0,255,0,255;
   1411    @assert pixel 50,1 == 0,255,0,255;
   1412    @assert pixel 98,1 == 0,255,0,255;
   1413    @assert pixel 1,25 == 0,255,0,255;
   1414    @assert pixel 50,25 == 0,255,0,255;
   1415    @assert pixel 98,25 == 0,255,0,255;
   1416    @assert pixel 1,48 == 0,255,0,255;
   1417    @assert pixel 50,48 == 0,255,0,255;
   1418    @assert pixel 98,48 == 0,255,0,255;
   1419  expected: green
   1420  variants: &create-canvas2-variant-definition
   1421  - HtmlCanvas:
   1422      append_variants_to_name: false
   1423      canvas_types: ['HtmlCanvas']
   1424      create_canvas2: |-
   1425        var canvas2 = document.createElement('canvas');
   1426        canvas2.width = 100;
   1427        canvas2.height = 50;
   1428    OffscreenCanvas:
   1429      append_variants_to_name: false
   1430      canvas_types: ['OffscreenCanvas', 'Worker']
   1431      create_canvas2: |-
   1432        var canvas2 = new OffscreenCanvas(100, 50);
   1433 
   1434 - name: 2d.pattern.basic.zerocanvas
   1435  code: |
   1436    canvas.width = 0;
   1437    canvas.height = 10;
   1438    @assert canvas.width === 0;
   1439    @assert canvas.height === 10;
   1440    @assert throws INVALID_STATE_ERR ctx.createPattern(canvas, 'repeat');
   1441 
   1442    canvas.width = 10;
   1443    canvas.height = 0;
   1444    @assert canvas.width === 10;
   1445    @assert canvas.height === 0;
   1446    @assert throws INVALID_STATE_ERR ctx.createPattern(canvas, 'repeat');
   1447 
   1448    canvas.width = 0;
   1449    canvas.height = 0;
   1450    @assert canvas.width === 0;
   1451    @assert canvas.height === 0;
   1452    @assert throws INVALID_STATE_ERR ctx.createPattern(canvas, 'repeat');
   1453 
   1454 - name: 2d.pattern.basic.nocontext
   1455  code: |
   1456    {{ create_canvas2 }}
   1457    var pattern = ctx.createPattern(canvas2, 'no-repeat');
   1458 
   1459    ctx.fillStyle = '#0f0';
   1460    ctx.fillRect(0, 0, 100, 50);
   1461    ctx.fillStyle = '#f00';
   1462    ctx.fillStyle = pattern;
   1463    ctx.fillRect(0, 0, 100, 50);
   1464 
   1465    @assert pixel 1,1 == 0,255,0,255;
   1466    @assert pixel 98,1 == 0,255,0,255;
   1467    @assert pixel 1,48 == 0,255,0,255;
   1468    @assert pixel 98,48 == 0,255,0,255;
   1469  expected: green
   1470  variants: *create-canvas2-variant-definition
   1471 
   1472 - name: 2d.pattern.transform.identity
   1473  code: |
   1474    {{ create_canvas2 }}
   1475    var pattern = ctx.createPattern(canvas2, 'no-repeat');
   1476    pattern.setTransform(new DOMMatrix());
   1477 
   1478    ctx.fillStyle = '#0f0';
   1479    ctx.fillRect(0, 0, 100, 50);
   1480    ctx.fillStyle = '#f00';
   1481    ctx.fillStyle = pattern;
   1482    ctx.fillRect(0, 0, 100, 50);
   1483 
   1484    @assert pixel 1,1 == 0,255,0,255;
   1485    @assert pixel 98,1 == 0,255,0,255;
   1486    @assert pixel 1,48 == 0,255,0,255;
   1487    @assert pixel 98,48 == 0,255,0,255;
   1488  expected: green
   1489  variants: *create-canvas2-variant-definition
   1490 
   1491 - name: 2d.pattern.transform.infinity
   1492  code: |
   1493    {{ create_canvas2 }}
   1494    var pattern = ctx.createPattern(canvas2, 'no-repeat');
   1495    pattern.setTransform({a: Infinity});
   1496 
   1497    ctx.fillStyle = '#0f0';
   1498    ctx.fillRect(0, 0, 100, 50);
   1499    ctx.fillStyle = '#f00';
   1500    ctx.fillStyle = pattern;
   1501    ctx.fillRect(0, 0, 100, 50);
   1502 
   1503    @assert pixel 1,1 == 0,255,0,255;
   1504    @assert pixel 98,1 == 0,255,0,255;
   1505    @assert pixel 1,48 == 0,255,0,255;
   1506    @assert pixel 98,48 == 0,255,0,255;
   1507  expected: green
   1508  variants: *create-canvas2-variant-definition
   1509 
   1510 - name: 2d.pattern.transform.invalid
   1511  code: |
   1512    {{ create_canvas2 }}
   1513    var pattern = ctx.createPattern(canvas2, 'no-repeat');
   1514    @assert throws TypeError pattern.setTransform({a: 1, m11: 2});
   1515  variants: *create-canvas2-variant-definition
   1516 
   1517 - name: 2d.pattern.image.undefined
   1518  notes: *bindings
   1519  code: |
   1520    @assert throws TypeError ctx.createPattern(undefined, 'repeat');
   1521 
   1522 - name: 2d.pattern.image.null
   1523  notes: *bindings
   1524  code: |
   1525    @assert throws TypeError ctx.createPattern(null, 'repeat');
   1526 
   1527 - name: 2d.pattern.image.string
   1528  notes: *bindings
   1529  code: |
   1530    @assert throws TypeError ctx.createPattern('../images/red.png', 'repeat');
   1531 
   1532 - name: 2d.pattern.image.incomplete.nosrc
   1533  canvas_types: ['HtmlCanvas']
   1534  code: |
   1535    var img = new Image();
   1536    @assert ctx.createPattern(img, 'repeat') === null;
   1537 
   1538 - name: 2d.pattern.image.incomplete.immediate
   1539  canvas_types: ['HtmlCanvas']
   1540  images:
   1541  - red.png
   1542  code: |
   1543    var img = new Image();
   1544    img.src = '../images/red.png';
   1545    // This triggers the "update the image data" algorithm.
   1546    // The image will not go to the "completely available" state
   1547    // until a fetch task in the networking task source is processed,
   1548    // so the image must not be fully decodable yet:
   1549    @assert ctx.createPattern(img, 'repeat') === null; @moz-todo
   1550 
   1551 - name: 2d.pattern.image.incomplete.reload
   1552  canvas_types: ['HtmlCanvas']
   1553  images:
   1554  - yellow.png
   1555  - red.png
   1556  code: |
   1557    var img = document.getElementById('yellow.png');
   1558    img.src = '../images/red.png';
   1559    // This triggers the "update the image data" algorithm,
   1560    // and resets the image to the "unavailable" state.
   1561    // The image will not go to the "completely available" state
   1562    // until a fetch task in the networking task source is processed,
   1563    // so the image must not be fully decodable yet:
   1564    @assert ctx.createPattern(img, 'repeat') === null; @moz-todo
   1565 
   1566 - name: 2d.pattern.image.incomplete.emptysrc
   1567  canvas_types: ['HtmlCanvas']
   1568  images:
   1569  - red.png
   1570  mozilla: {throws: !!null ''}
   1571  code: |
   1572    var img = document.getElementById('red.png');
   1573    img.src = "";
   1574    @assert ctx.createPattern(img, 'repeat') === null;
   1575 
   1576 - name: 2d.pattern.image.incomplete.removedsrc
   1577  canvas_types: ['HtmlCanvas']
   1578  images:
   1579  - red.png
   1580  mozilla: {throws: !!null ''}
   1581  code: |
   1582    var img = document.getElementById('red.png');
   1583    img.removeAttribute('src');
   1584    @assert ctx.createPattern(img, 'repeat') === null;
   1585 
   1586 - name: 2d.pattern.image.broken
   1587  canvas_types: ['HtmlCanvas']
   1588  images:
   1589  - broken.png
   1590  code: |
   1591    var img = document.getElementById('broken.png');
   1592    @assert throws INVALID_STATE_ERR ctx.createPattern(img, 'repeat');
   1593 
   1594 - name: 2d.pattern.image.nonexistent
   1595  canvas_types: ['HtmlCanvas']
   1596  images:
   1597  - no-such-image-really.png
   1598  code: |
   1599    var img = document.getElementById('no-such-image-really.png');
   1600    @assert throws INVALID_STATE_ERR ctx.createPattern(img, 'repeat');
   1601 
   1602 - name: 2d.pattern.svgimage.nonexistent
   1603  canvas_types: ['HtmlCanvas']
   1604  svgimages:
   1605  - no-such-image-really.png
   1606  code: |
   1607    var img = document.getElementById('no-such-image-really.png');
   1608    @assert throws INVALID_STATE_ERR ctx.createPattern(img, 'repeat');
   1609 
   1610 - name: 2d.pattern.image.nonexistent-but-loading
   1611  canvas_types: ['HtmlCanvas']
   1612  code: |
   1613    var img = document.createElement("img");
   1614    img.src = "/images/no-such-image-really.png";
   1615    @assert ctx.createPattern(img, 'repeat') === null;
   1616    var img = document.createElementNS("http://www.w3.org/2000/svg", "image");
   1617    img.src = "/images/no-such-image-really.png";
   1618    @assert ctx.createPattern(img, 'repeat') === null;
   1619 
   1620 - name: 2d.pattern.image.nosrc
   1621  canvas_types: ['HtmlCanvas']
   1622  code: |
   1623    var img = document.createElement("img");
   1624    @assert ctx.createPattern(img, 'repeat') === null;
   1625    var img = document.createElementNS("http://www.w3.org/2000/svg", "image");
   1626    @assert ctx.createPattern(img, 'repeat') === null;
   1627 
   1628 - name: 2d.pattern.image.zerowidth
   1629  canvas_types: ['HtmlCanvas']
   1630  images:
   1631  - red-zerowidth.svg
   1632  code: |
   1633    var img = document.getElementById('red-zerowidth.svg');
   1634    @assert ctx.createPattern(img, 'repeat') === null;
   1635 
   1636 - name: 2d.pattern.image.zeroheight
   1637  canvas_types: ['HtmlCanvas']
   1638  images:
   1639  - red-zeroheight.svg
   1640  code: |
   1641    var img = document.getElementById('red-zeroheight.svg');
   1642    @assert ctx.createPattern(img, 'repeat') === null;
   1643 
   1644 - name: 2d.pattern.svgimage.zerowidth
   1645  canvas_types: ['HtmlCanvas']
   1646  svgimages:
   1647  - red-zerowidth.svg
   1648  code: |
   1649    var img = document.getElementById('red-zerowidth.svg');
   1650    @assert ctx.createPattern(img, 'repeat') === null;
   1651 
   1652 - name: 2d.pattern.svgimage.zeroheight
   1653  canvas_types: ['HtmlCanvas']
   1654  svgimages:
   1655  - red-zeroheight.svg
   1656  code: |
   1657    var img = document.getElementById('red-zeroheight.svg');
   1658    @assert ctx.createPattern(img, 'repeat') === null;
   1659 
   1660 - name: 2d.pattern.repeat.empty
   1661  images:
   1662  - green-1x1.png
   1663  code: |
   1664    ctx.fillStyle = '#f00';
   1665    ctx.fillRect(0, 0, 100, 50);
   1666    {{ load_image }}
   1667    var pattern = ctx.createPattern(img, "");
   1668    ctx.fillStyle = pattern;
   1669    ctx.fillRect(0, 0, 200, 50);
   1670 
   1671    @assert pixel 1,1 == 0,255,0,255;
   1672    @assert pixel 98,1 == 0,255,0,255;
   1673    @assert pixel 1,48 == 0,255,0,255;
   1674    @assert pixel 98,48 == 0,255,0,255;
   1675  expected: green
   1676  variants: *load-image-variant-definition
   1677 
   1678 - name: 2d.pattern.repeat.null
   1679  code: |
   1680    @assert ctx.createPattern(canvas, null) != null;
   1681 
   1682 - name: 2d.pattern.repeat.undefined
   1683  code: |
   1684    @assert throws SYNTAX_ERR ctx.createPattern(canvas, undefined);
   1685 
   1686 - name: 2d.pattern.repeat.unrecognised
   1687  code: |
   1688    @assert throws SYNTAX_ERR ctx.createPattern(canvas, "invalid");
   1689 
   1690 - name: 2d.pattern.repeat.unrecognisednull
   1691  code: |
   1692    @assert throws SYNTAX_ERR ctx.createPattern(canvas, "null");
   1693 
   1694 - name: 2d.pattern.repeat.case
   1695  code: |
   1696    @assert throws SYNTAX_ERR ctx.createPattern(canvas, "Repeat");
   1697 
   1698 - name: 2d.pattern.repeat.nullsuffix
   1699  code: |
   1700    @assert throws SYNTAX_ERR ctx.createPattern(canvas, "repeat\0");
   1701 
   1702 - name: 2d.pattern.modify.image1
   1703  canvas_types: ['HtmlCanvas']
   1704  images:
   1705  - green.png
   1706  code: |
   1707    var img = document.getElementById('green.png');
   1708    var pattern = ctx.createPattern(img, 'no-repeat');
   1709    deferTest();
   1710    img.onload = t.step_func_done(function ()
   1711    {
   1712        ctx.fillStyle = pattern;
   1713        ctx.fillRect(0, 0, 100, 50);
   1714 
   1715        @assert pixel 1,1 == 0,255,0,255;
   1716        @assert pixel 98,1 == 0,255,0,255;
   1717        @assert pixel 1,48 == 0,255,0,255;
   1718        @assert pixel 98,48 == 0,255,0,255;
   1719    });
   1720    img.src = '/images/red.png';
   1721  expected: green
   1722 
   1723 - name: 2d.pattern.modify.image2
   1724  canvas_types: ['HtmlCanvas']
   1725  images:
   1726  - green.png
   1727  code: |
   1728    var img = document.getElementById('green.png');
   1729    var pattern = ctx.createPattern(img, 'no-repeat');
   1730    ctx.fillStyle = pattern;
   1731    ctx.fillRect(0, 0, 100, 50);
   1732    ctx.fillStyle = '#00f';
   1733    ctx.fillRect(0, 0, 100, 50);
   1734    deferTest();
   1735    img.onload = t.step_func_done(function ()
   1736    {
   1737        ctx.fillStyle = pattern;
   1738        ctx.fillRect(0, 0, 100, 50);
   1739 
   1740        @assert pixel 1,1 == 0,255,0,255;
   1741        @assert pixel 98,1 == 0,255,0,255;
   1742        @assert pixel 1,48 == 0,255,0,255;
   1743        @assert pixel 98,48 == 0,255,0,255;
   1744    });
   1745    img.src = '/images/red.png';
   1746  expected: green
   1747 
   1748 - name: 2d.pattern.modify.canvas1
   1749  canvas_types: ['HtmlCanvas']
   1750  code: |
   1751    {{ create_canvas2 }}
   1752    var ctx2 = canvas2.getContext('2d');
   1753    ctx2.fillStyle = '#0f0';
   1754    ctx2.fillRect(0, 0, 100, 50);
   1755 
   1756    var pattern = ctx.createPattern(canvas2, 'no-repeat');
   1757 
   1758    ctx2.fillStyle = '#f00';
   1759    ctx2.fillRect(0, 0, 100, 50);
   1760 
   1761    ctx.fillStyle = pattern;
   1762    ctx.fillRect(0, 0, 100, 50);
   1763 
   1764    @assert pixel 1,1 == 0,255,0,255;
   1765    @assert pixel 98,1 == 0,255,0,255;
   1766    @assert pixel 1,48 == 0,255,0,255;
   1767    @assert pixel 98,48 == 0,255,0,255;
   1768  expected: green
   1769  variants: *create-canvas2-variant-definition
   1770 
   1771 - name: 2d.pattern.modify.canvas2
   1772  code: |
   1773    {{ create_canvas2 }}
   1774    var ctx2 = canvas2.getContext('2d');
   1775    ctx2.fillStyle = '#0f0';
   1776    ctx2.fillRect(0, 0, 100, 50);
   1777 
   1778    var pattern = ctx.createPattern(canvas2, 'no-repeat');
   1779    ctx.fillStyle = pattern;
   1780    ctx.fillRect(0, 0, 100, 50);
   1781    ctx.fillStyle = '#f00';
   1782    ctx.fillRect(0, 0, 100, 50);
   1783 
   1784    ctx2.fillStyle = '#f00';
   1785    ctx2.fillRect(0, 0, 100, 50);
   1786 
   1787    ctx.fillStyle = pattern;
   1788    ctx.fillRect(0, 0, 100, 50);
   1789 
   1790    @assert pixel 1,1 == 0,255,0,255;
   1791    @assert pixel 98,1 == 0,255,0,255;
   1792    @assert pixel 1,48 == 0,255,0,255;
   1793    @assert pixel 98,48 == 0,255,0,255;
   1794  expected: green
   1795  variants: *create-canvas2-variant-definition
   1796 
   1797 - name: 2d.pattern.crosscanvas
   1798  images:
   1799  - green.png
   1800  code: |
   1801    {{ load_image }}
   1802 
   1803    var pattern = {{ create_canvas }}.getContext('2d').createPattern(img, 'no-repeat');
   1804    ctx.fillStyle = '#f00';
   1805    ctx.fillRect(0, 0, 100, 50);
   1806    ctx.fillStyle = pattern;
   1807    ctx.fillRect(0, 0, 100, 50);
   1808 
   1809    @assert pixel 50,25 == 0,255,0,255;
   1810  expected: green
   1811  append_variants_to_name: false
   1812  variants:
   1813  - HtmlCanvas:
   1814      canvas_types: ['HtmlCanvas']
   1815      load_image: var img = document.getElementById('{{ images[0] }}');
   1816      create_canvas: document.createElement('canvas')
   1817    OffscreenCanvas:
   1818      canvas_types: ['OffscreenCanvas', 'Worker']
   1819      test_type: promise
   1820      load_image: |-
   1821        var response = await fetch('/images/{{ images[0] }}')
   1822        var blob = await response.blob();
   1823        var img = await createImageBitmap(blob);
   1824      create_canvas: new OffscreenCanvas(100, 50)
   1825 
   1826 - name: 2d.pattern.paint.norepeat.basic
   1827  images:
   1828  - green.png
   1829  code: |
   1830    ctx.fillStyle = '#f00';
   1831    ctx.fillRect(0, 0, 100, 50);
   1832 
   1833    {{ load_image }}
   1834    var pattern = ctx.createPattern(img, 'no-repeat');
   1835    ctx.fillStyle = pattern;
   1836    ctx.fillRect(0, 0, 100, 50);
   1837 
   1838    @assert pixel 1,1 == 0,255,0,255;
   1839    @assert pixel 98,1 == 0,255,0,255;
   1840    @assert pixel 1,48 == 0,255,0,255;
   1841    @assert pixel 98,48 == 0,255,0,255;
   1842  expected: green
   1843  variants: *load-image-variant-definition
   1844 
   1845 - name: 2d.pattern.paint.norepeat.outside
   1846  images:
   1847  - red.png
   1848  code: |
   1849    ctx.fillStyle = '#f00';
   1850    ctx.fillRect(0, 0, 100, 50);
   1851 
   1852    {{ load_image }}
   1853    var pattern = ctx.createPattern(img, 'no-repeat');
   1854    ctx.fillStyle = '#0f0';
   1855    ctx.fillRect(0, 0, 100, 50);
   1856 
   1857    ctx.fillStyle = pattern;
   1858    ctx.fillRect(0, -50, 100, 50);
   1859    ctx.fillRect(-100, 0, 100, 50);
   1860    ctx.fillRect(0, 50, 100, 50);
   1861    ctx.fillRect(100, 0, 100, 50);
   1862 
   1863    @assert pixel 1,1 == 0,255,0,255;
   1864    @assert pixel 98,1 == 0,255,0,255;
   1865    @assert pixel 1,48 == 0,255,0,255;
   1866    @assert pixel 98,48 == 0,255,0,255;
   1867  expected: green
   1868  variants: *load-image-variant-definition
   1869 
   1870 - name: 2d.pattern.paint.norepeat.outside_arc
   1871  images:
   1872  - red-16x16.png
   1873  code: |
   1874    ctx.fillStyle = '#f00';
   1875    ctx.fillRect(0, 0, 100, 50);
   1876    {{ load_image }}
   1877    var pattern = ctx.createPattern(img, 'no-repeat');
   1878    ctx.fillStyle = '#0f0';
   1879    ctx.fillRect(0, 0, 100, 50);
   1880    ctx.fillStyle = pattern;
   1881    ctx.beginPath();
   1882    ctx.arc(0, 0, 50, 0, Math.PI * 2);
   1883    ctx.closePath();
   1884    ctx.fill();
   1885    ctx.fillStyle = '#0f0';
   1886    ctx.fillRect(0, 0, 16, 16);
   1887    @assert pixel 1,1 == 0,255,0,255;
   1888    @assert pixel 20,1 == 0,255,0,255;
   1889    @assert pixel 1,20 == 0,255,0,255;
   1890    @assert pixel 48,48 == 0,255,0,255;
   1891  expected: green
   1892  variants: *load-image-variant-definition
   1893 
   1894 - name: 2d.pattern.paint.norepeat.coord1
   1895  images:
   1896  - green.png
   1897  code: |
   1898    ctx.fillStyle = '#0f0';
   1899    ctx.fillRect(0, 0, 50, 50);
   1900    ctx.fillStyle = '#f00';
   1901    ctx.fillRect(50, 0, 50, 50);
   1902 
   1903    {{ load_image }}
   1904    var pattern = ctx.createPattern(img, 'no-repeat');
   1905    ctx.fillStyle = pattern;
   1906    ctx.translate(50, 0);
   1907    ctx.fillRect(-50, 0, 100, 50);
   1908 
   1909    @assert pixel 1,1 == 0,255,0,255;
   1910    @assert pixel 98,1 == 0,255,0,255;
   1911    @assert pixel 1,48 == 0,255,0,255;
   1912    @assert pixel 98,48 == 0,255,0,255;
   1913  expected: green
   1914  variants: *load-image-variant-definition
   1915 
   1916 - name: 2d.pattern.paint.norepeat.coord2
   1917  images:
   1918  - green.png
   1919  code: |
   1920    {{ load_image }}
   1921    var pattern = ctx.createPattern(img, 'no-repeat');
   1922    ctx.fillStyle = pattern;
   1923    ctx.fillRect(0, 0, 50, 50);
   1924 
   1925    ctx.fillStyle = '#f00';
   1926    ctx.fillRect(50, 0, 50, 50);
   1927 
   1928    ctx.fillStyle = pattern;
   1929    ctx.translate(50, 0);
   1930    ctx.fillRect(-50, 0, 100, 50);
   1931 
   1932    @assert pixel 1,1 == 0,255,0,255;
   1933    @assert pixel 98,1 == 0,255,0,255;
   1934    @assert pixel 1,48 == 0,255,0,255;
   1935    @assert pixel 98,48 == 0,255,0,255;
   1936  expected: green
   1937  variants: *load-image-variant-definition
   1938 
   1939 - name: 2d.pattern.paint.norepeat.coord3
   1940  images:
   1941  - red.png
   1942  code: |
   1943    ctx.fillStyle = '#0f0';
   1944    ctx.fillRect(0, 0, 100, 50);
   1945 
   1946    {{ load_image }}
   1947    var pattern = ctx.createPattern(img, 'no-repeat');
   1948    ctx.fillStyle = pattern;
   1949    ctx.translate(50, 25);
   1950    ctx.fillRect(-50, -25, 100, 50);
   1951 
   1952    ctx.fillStyle = '#0f0';
   1953    ctx.fillRect(0, 0, 50, 25);
   1954 
   1955    @assert pixel 1,1 == 0,255,0,255;
   1956    @assert pixel 98,1 == 0,255,0,255;
   1957    @assert pixel 1,48 == 0,255,0,255;
   1958    @assert pixel 98,48 == 0,255,0,255;
   1959  expected: green
   1960  variants: *load-image-variant-definition
   1961 
   1962 - name: 2d.pattern.paint.repeat.basic
   1963  images:
   1964  - green-16x16.png
   1965  code: |
   1966    ctx.fillStyle = '#f00';
   1967    ctx.fillRect(0, 0, 100, 50);
   1968 
   1969    {{ load_image }}
   1970    var pattern = ctx.createPattern(img, 'repeat');
   1971    ctx.fillStyle = pattern;
   1972    ctx.fillRect(0, 0, 100, 50);
   1973 
   1974    @assert pixel 1,1 == 0,255,0,255;
   1975    @assert pixel 98,1 == 0,255,0,255;
   1976    @assert pixel 1,48 == 0,255,0,255;
   1977    @assert pixel 98,48 == 0,255,0,255;
   1978  expected: green
   1979  variants: *load-image-variant-definition
   1980 
   1981 - name: 2d.pattern.paint.repeat.outside
   1982  images:
   1983  - green-16x16.png
   1984  code: |
   1985    ctx.fillStyle = '#f00';
   1986    ctx.fillRect(0, 0, 100, 50);
   1987 
   1988    {{ load_image }}
   1989    var pattern = ctx.createPattern(img, 'repeat');
   1990    ctx.fillStyle = pattern;
   1991    ctx.translate(50, 25);
   1992    ctx.fillRect(-50, -25, 100, 50);
   1993 
   1994    @assert pixel 1,1 == 0,255,0,255;
   1995    @assert pixel 98,1 == 0,255,0,255;
   1996    @assert pixel 1,48 == 0,255,0,255;
   1997    @assert pixel 98,48 == 0,255,0,255;
   1998  expected: green
   1999  variants: *load-image-variant-definition
   2000 
   2001 - name: 2d.pattern.paint.repeat.coord1
   2002  images:
   2003  - rgrg-256x256.png
   2004  code: |
   2005    ctx.fillStyle = '#f00';
   2006    ctx.fillRect(0, 0, 100, 50);
   2007 
   2008    {{ load_image }}
   2009    var pattern = ctx.createPattern(img, 'repeat');
   2010    ctx.fillStyle = pattern;
   2011    ctx.translate(-128, -78);
   2012    ctx.fillRect(128, 78, 100, 50);
   2013 
   2014    @assert pixel 1,1 == 0,255,0,255;
   2015    @assert pixel 98,1 == 0,255,0,255;
   2016    @assert pixel 1,48 == 0,255,0,255;
   2017    @assert pixel 98,48 == 0,255,0,255;
   2018  expected: green
   2019  variants: *load-image-variant-definition
   2020 
   2021 - name: 2d.pattern.paint.repeat.coord2
   2022  images:
   2023  - ggrr-256x256.png
   2024  code: |
   2025    {{ load_image }}
   2026    var pattern = ctx.createPattern(img, 'repeat');
   2027    ctx.fillStyle = pattern;
   2028    ctx.fillRect(0, 0, 100, 50);
   2029 
   2030    @assert pixel 1,1 == 0,255,0,255;
   2031    @assert pixel 98,1 == 0,255,0,255;
   2032    @assert pixel 1,48 == 0,255,0,255;
   2033    @assert pixel 98,48 == 0,255,0,255;
   2034  expected: green
   2035  variants: *load-image-variant-definition
   2036 
   2037 - name: 2d.pattern.paint.repeat.coord3
   2038  images:
   2039  - rgrg-256x256.png
   2040  code: |
   2041    {{ load_image }}
   2042    var pattern = ctx.createPattern(img, 'repeat');
   2043    ctx.fillStyle = pattern;
   2044    ctx.fillRect(0, 0, 100, 50);
   2045 
   2046    ctx.translate(-128, -78);
   2047    ctx.fillRect(128, 78, 100, 50);
   2048 
   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    @assert pixel 98,48 == 0,255,0,255;
   2053  expected: green
   2054  variants: *load-image-variant-definition
   2055 
   2056 - name: 2d.pattern.paint.repeatx.basic
   2057  images:
   2058  - green-16x16.png
   2059  code: |
   2060    ctx.fillStyle = '#0f0';
   2061    ctx.fillRect(0, 0, 100, 50);
   2062    ctx.fillStyle = '#f00';
   2063    ctx.fillRect(0, 0, 100, 16);
   2064 
   2065    {{ load_image }}
   2066    var pattern = ctx.createPattern(img, 'repeat-x');
   2067    ctx.fillStyle = pattern;
   2068    ctx.fillRect(0, 0, 100, 50);
   2069 
   2070    @assert pixel 1,1 == 0,255,0,255;
   2071    @assert pixel 98,1 == 0,255,0,255;
   2072    @assert pixel 1,48 == 0,255,0,255;
   2073    @assert pixel 98,48 == 0,255,0,255;
   2074  expected: green
   2075  variants: *load-image-variant-definition
   2076 
   2077 - name: 2d.pattern.paint.repeatx.outside
   2078  images:
   2079  - red-16x16.png
   2080  code: |
   2081    ctx.fillStyle = '#0f0';
   2082    ctx.fillRect(0, 0, 100, 50);
   2083 
   2084    {{ load_image }}
   2085    var pattern = ctx.createPattern(img, 'repeat-x');
   2086    ctx.fillStyle = pattern;
   2087    ctx.fillRect(0, 0, 100, 50);
   2088 
   2089    ctx.fillStyle = '#0f0';
   2090    ctx.fillRect(0, 0, 100, 16);
   2091 
   2092    @assert pixel 1,1 == 0,255,0,255;
   2093    @assert pixel 98,1 == 0,255,0,255;
   2094    @assert pixel 1,48 == 0,255,0,255;
   2095    @assert pixel 98,48 == 0,255,0,255;
   2096  expected: green
   2097  variants: *load-image-variant-definition
   2098 
   2099 - name: 2d.pattern.paint.repeatx.coord1
   2100  images:
   2101  - red-16x16.png
   2102  code: |
   2103    ctx.fillStyle = '#0f0';
   2104    ctx.fillRect(0, 0, 100, 50);
   2105 
   2106    {{ load_image }}
   2107    var pattern = ctx.createPattern(img, 'repeat-x');
   2108    ctx.fillStyle = pattern;
   2109    ctx.translate(0, 16);
   2110    ctx.fillRect(0, -16, 100, 50);
   2111 
   2112    ctx.fillStyle = '#0f0';
   2113    ctx.fillRect(0, 0, 100, 16);
   2114 
   2115    @assert pixel 1,1 == 0,255,0,255;
   2116    @assert pixel 98,1 == 0,255,0,255;
   2117    @assert pixel 1,25 == 0,255,0,255;
   2118    @assert pixel 98,25 == 0,255,0,255;
   2119    @assert pixel 1,48 == 0,255,0,255;
   2120    @assert pixel 98,48 == 0,255,0,255;
   2121  expected: green
   2122  variants: *load-image-variant-definition
   2123 
   2124 - name: 2d.pattern.paint.repeaty.basic
   2125  images:
   2126  - green-16x16.png
   2127  code: |
   2128    ctx.fillStyle = '#0f0';
   2129    ctx.fillRect(0, 0, 100, 50);
   2130    ctx.fillStyle = '#f00';
   2131    ctx.fillRect(0, 0, 16, 50);
   2132 
   2133    {{ load_image }}
   2134    var pattern = ctx.createPattern(img, 'repeat-y');
   2135    ctx.fillStyle = pattern;
   2136    ctx.fillRect(0, 0, 100, 50);
   2137 
   2138    @assert pixel 1,1 == 0,255,0,255;
   2139    @assert pixel 98,1 == 0,255,0,255;
   2140    @assert pixel 1,48 == 0,255,0,255;
   2141    @assert pixel 98,48 == 0,255,0,255;
   2142  expected: green
   2143  variants: *load-image-variant-definition
   2144 
   2145 - name: 2d.pattern.paint.repeaty.outside
   2146  images:
   2147  - red-16x16.png
   2148  code: |
   2149    ctx.fillStyle = '#0f0';
   2150    ctx.fillRect(0, 0, 100, 50);
   2151 
   2152    {{ load_image }}
   2153    var pattern = ctx.createPattern(img, 'repeat-y');
   2154    ctx.fillStyle = pattern;
   2155    ctx.fillRect(0, 0, 100, 50);
   2156 
   2157    ctx.fillStyle = '#0f0';
   2158    ctx.fillRect(0, 0, 16, 50);
   2159 
   2160    @assert pixel 1,1 == 0,255,0,255;
   2161    @assert pixel 98,1 == 0,255,0,255;
   2162    @assert pixel 1,48 == 0,255,0,255;
   2163    @assert pixel 98,48 == 0,255,0,255;
   2164  expected: green
   2165  variants: *load-image-variant-definition
   2166 
   2167 - name: 2d.pattern.paint.repeaty.coord1
   2168  images:
   2169  - red-16x16.png
   2170  code: |
   2171    ctx.fillStyle = '#0f0';
   2172    ctx.fillRect(0, 0, 100, 50);
   2173 
   2174    {{ load_image }}
   2175    var pattern = ctx.createPattern(img, 'repeat-y');
   2176    ctx.fillStyle = pattern;
   2177    ctx.translate(48, 0);
   2178    ctx.fillRect(-48, 0, 100, 50);
   2179 
   2180    ctx.fillStyle = '#0f0';
   2181    ctx.fillRect(0, 0, 16, 50);
   2182 
   2183    @assert pixel 1,1 == 0,255,0,255;
   2184    @assert pixel 50,1 == 0,255,0,255;
   2185    @assert pixel 98,1 == 0,255,0,255;
   2186    @assert pixel 1,48 == 0,255,0,255;
   2187    @assert pixel 50,48 == 0,255,0,255;
   2188    @assert pixel 98,48 == 0,255,0,255;
   2189  expected: green
   2190  variants: *load-image-variant-definition
   2191 
   2192 - name: 2d.pattern.paint.orientation.image
   2193  desc: Image patterns do not get flipped when painted
   2194  images:
   2195  - rrgg-256x256.png
   2196  code: |
   2197    ctx.fillStyle = '#f00';
   2198    ctx.fillRect(0, 0, 100, 50);
   2199 
   2200    {{ load_image }}
   2201    var pattern = ctx.createPattern(img, 'no-repeat');
   2202    ctx.fillStyle = pattern;
   2203    ctx.save();
   2204    ctx.translate(0, -103);
   2205    ctx.fillRect(0, 103, 100, 50);
   2206    ctx.restore();
   2207 
   2208    ctx.fillStyle = '#0f0';
   2209    ctx.fillRect(0, 0, 100, 25);
   2210 
   2211    @assert pixel 1,1 == 0,255,0,255;
   2212    @assert pixel 98,1 == 0,255,0,255;
   2213    @assert pixel 1,48 == 0,255,0,255;
   2214    @assert pixel 98,48 == 0,255,0,255;
   2215  expected: green
   2216  variants: *load-image-variant-definition
   2217 
   2218 - name: 2d.pattern.paint.orientation.canvas
   2219  desc: Canvas patterns do not get flipped when painted
   2220  code: |
   2221    ctx.fillStyle = '#f00';
   2222    ctx.fillRect(0, 0, 100, 50);
   2223 
   2224    {{ create_canvas2 }}
   2225    var ctx2 = canvas2.getContext('2d');
   2226    ctx2.fillStyle = '#f00';
   2227    ctx2.fillRect(0, 0, 100, 25);
   2228    ctx2.fillStyle = '#0f0';
   2229    ctx2.fillRect(0, 25, 100, 25);
   2230 
   2231    var pattern = ctx.createPattern(canvas2, 'no-repeat');
   2232    ctx.fillStyle = pattern;
   2233    ctx.fillRect(0, 0, 100, 50);
   2234    ctx.fillStyle = '#0f0';
   2235    ctx.fillRect(0, 0, 100, 25);
   2236 
   2237    @assert pixel 1,1 == 0,255,0,255;
   2238    @assert pixel 98,1 == 0,255,0,255;
   2239    @assert pixel 1,48 == 0,255,0,255;
   2240    @assert pixel 98,48 == 0,255,0,255;
   2241  expected: green
   2242  variants: *create-canvas2-variant-definition
   2243 
   2244 - name: 2d.pattern.animated.gif
   2245  desc: createPattern() of an animated GIF draws the first frame
   2246  canvas_types: ['HtmlCanvas']
   2247  images:
   2248  - anim-gr.gif
   2249  code: |
   2250    deferTest();
   2251    step_timeout(function () {
   2252        var pattern = ctx.createPattern(document.getElementById('anim-gr.gif'), 'repeat');
   2253        ctx.fillStyle = pattern;
   2254        ctx.fillRect(0, 0, 50, 50);
   2255        step_timeout(t.step_func_done(function () {
   2256            ctx.fillRect(50, 0, 50, 50);
   2257            @assert pixel 25,25 ==~ 0,255,0,255;
   2258            @assert pixel 75,25 ==~ 0,255,0,255;
   2259        }), 250);
   2260    }, 250);
   2261  expected: green
   2262 
   2263 - name: 2d.fillStyle.CSSRGB
   2264  desc: CSSRGB works as color input
   2265  canvas_types: ['HtmlCanvas', 'OffscreenCanvas']
   2266  code: |
   2267    ctx.fillStyle = new CSSRGB(1, 0, 1);
   2268    @assert ctx.fillStyle === '#ff00ff';
   2269    ctx.fillRect(0, 0, 100, 50);
   2270    @assert pixel 50,25 == 255,0,255,255;
   2271 
   2272    const color = new CSSRGB(0, CSS.percent(50), 0);
   2273    ctx.fillStyle = color;
   2274    @assert ctx.fillStyle === '#008000';
   2275    ctx.fillRect(0, 0, 100, 50);
   2276    @assert pixel 50,25 == 0,128,0,255;
   2277    color.g = 0;
   2278    ctx.fillStyle = color;
   2279    @assert ctx.fillStyle === '#000000';
   2280    ctx.fillRect(0, 0, 100, 50);
   2281    @assert pixel 50,25 == 0,0,0,255;
   2282 
   2283    color.alpha = 0;
   2284    ctx.fillStyle = color;
   2285    @assert ctx.fillStyle === 'rgba(0, 0, 0, 0)';
   2286    ctx.reset();
   2287    color.alpha = 0.5;
   2288    ctx.fillStyle = color;
   2289    ctx.fillRect(0, 0, 100, 50);
   2290    @assert pixel 50,25 == 0,0,0,128;
   2291 
   2292    color.alpha = 1;
   2293    color.g = 1;
   2294    ctx.fillStyle = color;
   2295    ctx.fillRect(0, 0, 100, 50);
   2296  expected: green
   2297 
   2298 - name: 2d.fillStyle.CSSHSL
   2299  desc: CSSHSL works as color input
   2300  canvas_types: ['HtmlCanvas', 'OffscreenCanvas']
   2301  code: |
   2302    ctx.fillStyle = new CSSHSL(CSS.deg(180), 0.5, 0.5);
   2303    ctx.fillRect(0, 0, 100, 50);
   2304    @assert pixel 50,25 ==~ 64,191,191,255 +/- 3;
   2305 
   2306    const color = new CSSHSL(CSS.deg(180), 1, 1);
   2307    ctx.fillStyle = color;
   2308    @assert ctx.fillStyle === '#ffffff';
   2309    ctx.fillRect(0, 0, 100, 50);
   2310    @assert pixel 50,25 == 255,255,255,255;
   2311    color.l = 0.5;
   2312    ctx.fillStyle = color;
   2313    @assert ctx.fillStyle === '#00ffff';
   2314    ctx.fillRect(0, 0, 100, 50);
   2315    @assert pixel 50,25 == 0,255,255,255;
   2316 
   2317    color.h = CSS.deg(120);
   2318    color.s = 1;
   2319    color.l = 0.5;
   2320    ctx.fillStyle = color;
   2321    ctx.fillRect(0, 0, 100, 50);
   2322  expected: green
   2323 
   2324 - name: 2d.fillStyle.colormix
   2325  desc: color-mix works as color input
   2326  canvas_types: ['HtmlCanvas', 'OffscreenCanvas', 'Worker']
   2327  code: |
   2328    ctx.fillStyle = "color-mix(in srgb, red, blue)";
   2329    @assert ctx.fillStyle === 'color(srgb 0.5 0 0.5)';
   2330    ctx.fillStyle = "color-mix(in srgb, red, color(srgb 1 0 0))";
   2331    @assert ctx.fillStyle === 'color(srgb 1 0 0)';
   2332 
   2333 - name: 2d.fillStyle.colormix.currentcolor
   2334  desc: color-mix works as color input with currentcolor
   2335  canvas_types: ['HtmlCanvas']
   2336  code: |
   2337    canvas.setAttribute('style', 'color: magenta');
   2338    ctx.fillStyle = "color-mix(in srgb, black, currentcolor)";
   2339    @assert ctx.fillStyle === 'color(srgb 0.5 0 0.5)';
   2340    ctx.strokeStyle = "color-mix(in srgb, black, currentcolor)";
   2341    @assert ctx.strokeStyle === 'color(srgb 0.5 0 0.5)';
   2342 
   2343 - name: 2d.strokeStyle.colormix
   2344  desc: color-mix works as color input
   2345  canvas_types: ['HtmlCanvas', 'OffscreenCanvas']
   2346  code: |
   2347    ctx.strokeStyle = "color-mix(in srgb, red, blue)";
   2348    @assert ctx.strokeStyle === 'color(srgb 0.5 0 0.5)';
   2349    ctx.strokeStyle = "color-mix(in srgb, red, color(srgb 1 0 0))";
   2350    @assert ctx.strokeStyle === 'color(srgb 1 0 0)';
   2351 
   2352 - name: 2d.gradient.colormix
   2353  desc: color-mix works as CanvasGradient color input
   2354  canvas_types: ['HtmlCanvas']
   2355  code: |
   2356    var g = ctx.createLinearGradient(0, 0, 100, 0);
   2357    g.addColorStop(0, '#f00');
   2358    g.addColorStop(1, 'color-mix(in srgb, #0f0, #00f)');
   2359    ctx.fillStyle = g;
   2360    ctx.fillRect(0, 0, 100, 50);
   2361    @assert pixel 25,25 ==~ 212,81,61,255 +/- 3;
   2362    @assert pixel 50,25 ==~ 167,106,88,255 +/- 3;
   2363    @assert pixel 75,25 ==~ 113,120,109,255 +/- 3;
   2364 
   2365 - name: 2d.fillStyle.relativecolor
   2366  desc: Relative color works as color input
   2367  canvas_types: ['HtmlCanvas', 'OffscreenCanvas', 'Worker']
   2368  code: |
   2369    ctx.fillStyle = "rgb(from red g r b)";
   2370    @assert ctx.fillStyle === 'color(srgb 0 1 0)';
   2371    ctx.fillStyle = "color(from color(srgb 0.25 0.5 0.75 / 0.5) srgb r g b / alpha)";
   2372    @assert ctx.fillStyle === 'color(srgb 0.25 0.5 0.75 / 0.5)';
   2373 
   2374 - name: 2d.fillStyle.relativecolor.currentcolor
   2375  desc: Relative color works as color input with currentcolor
   2376  canvas_types: ['HtmlCanvas']
   2377  code: |
   2378    canvas.setAttribute('style', 'color: magenta');
   2379    ctx.fillStyle = "rgb(from currentcolor g r b)";
   2380    @assert ctx.fillStyle === 'color(srgb 0 1 1)';
   2381    ctx.strokeStyle = "rgb(from currentcolor g r b)";
   2382    @assert ctx.strokeStyle === 'color(srgb 0 1 1)';
   2383 
   2384 - name: 2d.strokeStyle.relativecolor
   2385  desc: Relative color works as color input
   2386  canvas_types: ['HtmlCanvas', 'OffscreenCanvas', 'Worker']
   2387  code: |
   2388    ctx.strokeStyle = "rgb(from red g r b)";
   2389    @assert ctx.strokeStyle === 'color(srgb 0 1 0)';
   2390    ctx.strokeStyle = "color(from color(srgb 0.25 0.5 0.75 / 0.5) srgb r g b / alpha)";
   2391    @assert ctx.strokeStyle === 'color(srgb 0.25 0.5 0.75 / 0.5)';
   2392 
   2393 - name: 2d.gradient.relativecolor
   2394  desc: Relative color works as CanvasGradient color input
   2395  canvas_types: ['HtmlCanvas', 'OffscreenCanvas', 'Worker']
   2396  code: |
   2397    var g = ctx.createLinearGradient(0, 0, 100, 0);
   2398    g.addColorStop(0, '#f00');
   2399    g.addColorStop(1, 'rgb(from red g r b)');
   2400    ctx.fillStyle = g;
   2401    ctx.fillRect(0, 0, 100, 50);
   2402    @assert pixel 25,25 ==~ 236,116,0,255 +/- 3;
   2403    @assert pixel 50,25 ==~ 208,170,0,255 +/- 3;
   2404    @assert pixel 75,25 ==~ 159,214,0,255 +/- 3;
   2405 
   2406 - name: 2d.gradient.colorInterpolationMethod
   2407  desc: CSS color spaces work as a CanvasGradient color interpolation methods
   2408  fuzzy: maxDifference=0-1; totalPixels=0-60000
   2409  code: |
   2410    var g = ctx.createLinearGradient(0, 0, 100, 0);
   2411    g.addColorStop(0, 'color(srgb 1 0 0)');
   2412    g.addColorStop(1, 'color(srgb 0 1 0)');
   2413    g.colorInterpolationMethod = '{{ variant_name }}';
   2414    ctx.fillStyle = g;
   2415    ctx.fillRect(0, 0, 100, 50);
   2416  html_reference: |
   2417    <style>
   2418      #swatch-{{ variant_name }} {
   2419        width: 100%;
   2420        height: 100%;
   2421        background: linear-gradient(to right in {{ variant_name }},
   2422          color(srgb 1 0 0), color(srgb 0 1 0));
   2423      }
   2424    </style>
   2425    <div id="swatch-{{ variant_name }}"></div>
   2426  variants_layout: [single_file]
   2427  grid_width: 5
   2428  variants:
   2429  - srgb:
   2430    hsl:
   2431    hwb:
   2432    srgb-linear:
   2433    display-p3-linear:
   2434    display-p3:
   2435    a98-rgb:
   2436    prophoto-rgb:
   2437    rec2020:
   2438    lab:
   2439    oklab:
   2440    lch:
   2441    oklch:
   2442    xyz:
   2443    xyz-d50:
   2444    xyz-d65:
   2445 
   2446 - name: 2d.gradient.hueInterpolationMethod
   2447  desc: CSS hue interpolation methods work for CanvasGradients
   2448  fuzzy: maxDifference=0-1; totalPixels=0-60000
   2449  code: |
   2450    // Generate two gradients, one from red to green, the other from red to blue.
   2451    // In the first instance "shorter" is equivalent to "increasing".
   2452    // In the second, "shorter" is equivalent to "decreasing".
   2453 
   2454    var g = ctx.createLinearGradient(0, 0, 100, 0);
   2455    g.addColorStop(0, 'color(srgb 1 0 0)');
   2456    g.addColorStop(1, 'color(srgb 0 1 0)');
   2457    g.colorInterpolationMethod = '{{ variant_names[1] }}';
   2458    g.hueInterpolationMethod = '{{ variant_names[0] }}';
   2459    ctx.fillStyle = g;
   2460    ctx.fillRect(0, 0, 100, 25);
   2461 
   2462    var g2 = ctx.createLinearGradient(0, 0, 100, 0);
   2463    g2.addColorStop(0, 'color(srgb 1 0 0)');
   2464    g2.addColorStop(1, 'color(srgb 0 0 1)');
   2465    g2.colorInterpolationMethod = '{{ variant_names[1] }}';
   2466    g2.hueInterpolationMethod = '{{ variant_names[0] }}';
   2467    ctx.fillStyle = g2;
   2468    ctx.fillRect(0, 25, 100, 25);
   2469  html_reference: |
   2470    <style>
   2471      .swatch {
   2472        width: 100%;
   2473        height: 50%;
   2474      }
   2475    </style>
   2476    <div class="swatch" style="background:
   2477      linear-gradient(to right in {{ variant_names[1] }} {{ variant_names[0] }}
   2478        hue, color(srgb 1 0 0), color(srgb 0 1 0));
   2479    "></div>
   2480    <div class="swatch" style="background:
   2481      linear-gradient(to right in {{ variant_names[1] }} {{ variant_names[0] }}
   2482        hue, color(srgb 1 0 0), color(srgb 0 0 1));
   2483    "></div>
   2484  variants_layout: [single_file, single_file]
   2485  variants:
   2486  # Hue interpolation methods
   2487  - shorter:
   2488    longer:
   2489    increasing:
   2490    decreasing:
   2491  # Polar color interpolation spaces
   2492  - hsl:
   2493    hwb:
   2494    lch:
   2495    oklch: