tor-browser

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

the-canvas.yaml (18144B)


      1 - name: 2d.canvas.host.reference
      2  desc: canvas refers back to its canvas
      3  code: |
      4    @assert ctx.canvas === canvas;
      5 
      6 - name: 2d.canvas.host.readonly
      7  desc: Canvas objects are readonly
      8  code: |
      9    var canvas2 = {{ new_canvas }};
     10    var d = ctx.canvas;
     11    @assert canvas2 !== d;
     12    ctx.canvas = canvas2;
     13    @assert ctx.canvas === d;
     14  variants: &new-canvas-definition
     15   - HtmlCanvas:
     16       append_variants_to_name: false
     17       canvas_types: ['HtmlCanvas']
     18       new_canvas: |-
     19         document.createElement('canvas')
     20     OffscreenCanvas:
     21       append_variants_to_name: false
     22       canvas_types: ['OffscreenCanvas', 'Worker']
     23       new_canvas: |-
     24         new OffscreenCanvas(100, 50)
     25 
     26 - name: 2d.canvas.host.size.attributes
     27  canvas_types: ['HtmlCanvas']
     28  code: |
     29    {{ set_attributes -}}
     30    @assert canvas.width === {{ result_size[0] }};
     31    @assert canvas.height === {{ result_size[1] }};
     32    {% if result_size[0] != 300 %}
     33      {# With "100%", Opera gets canvas.width = 100 but renders at 100% of the
     34        frame width, so check the CSS display width -#}
     35      @assert window.getComputedStyle(canvas, null)\-
     36          .getPropertyValue("width") === "{{ result_size[0] }}px";
     37    {% endif -%}
     38 
     39    {% set attrib_size = escaped_size or input_size %}
     40    @assert canvas.getAttribute('width') === '{{ attrib_size }}';
     41    @assert canvas.getAttribute('height') === '{{ attrib_size }}';
     42  expected: |
     43    {% if result_size[0] != 0 -%}
     44      size {{ result_size[0] }} {{ result_size[1] }}
     45    {% endif %}
     46  variants:
     47  - parse:
     48      desc: Parsing of non-negative integers
     49      size: ['{{ input_size }}', '{{ input_size }}']
     50    setAttribute:
     51      desc: Parsing of non-negative integers in setAttribute
     52      size: [ 50, 50 ]
     53      set_attributes: |
     54        canvas.setAttribute('width', '{{ escaped_size or input_size }}');
     55        canvas.setAttribute('height', '{{ escaped_size or input_size }}');
     56  - zero:
     57      input_size: '0'
     58      result_size: [0, 0]
     59    empty:
     60      input_size: ''
     61      result_size: [300, 150]
     62    onlyspace:
     63      input_size: '  '
     64      result_size: [300, 150]
     65    space:
     66      input_size: '  100'
     67      result_size: [100, 100]
     68    whitespace:
     69      input_size: "
\n\t\x0c100"
     70      escaped_size: "\\r\\n\\t\\x0c100"
     71      result_size: [100, 100]
     72    plus:
     73      input_size: '+100'
     74      result_size: [100, 100]
     75    minus:
     76      input_size: '-100'
     77      result_size: [300, 150]
     78    octal:
     79      input_size: '0100'
     80      result_size: [100, 100]
     81    hex:
     82      input_size: '0x100'
     83      result_size: [0, 0]
     84    exp:
     85      input_size: '100e1'
     86      result_size: [100, 100]
     87    decimal:
     88      input_size: '100.999'
     89      result_size: [100, 100]
     90    percent:
     91      input_size: '100%'
     92      result_size: [100, 100]
     93    em:
     94      input_size: '100em'
     95      result_size: [100, 100]
     96    junk:
     97      input_size: '#!?'
     98      result_size: [300, 150]
     99    trailingjunk:
    100      input_size: '100#!?'
    101      result_size: [100, 100]
    102 
    103 - name: 2d.canvas.host.size.attributes.parse
    104  desc: Parsing of non-negative integers
    105  canvas_types: ['OffscreenCanvas', 'Worker']
    106  code: |
    107    {% if result_size == 'exception' %}
    108    @assert throws TypeError canvas.width = '{{ input_size }}';
    109    {% else %}
    110    canvas.width = '{{ input_size }}';
    111    canvas.height = '{{ input_size }}';
    112    @assert canvas.width === {{ result_size }};
    113    @assert canvas.height === {{ result_size }};
    114    {% endif %}
    115  variants:
    116  - zero:
    117      input_size: '0'
    118      result_size: 0
    119    empty:
    120      input_size: ''
    121      result_size: 0
    122    onlyspace:
    123      input_size: '  '
    124      result_size: 0
    125    space:
    126      input_size: '  100'
    127      result_size: 100
    128    whitespace:
    129      input_size: "\t\f100"
    130      result_size: 100
    131    plus:
    132      input_size: '+100'
    133      result_size: 100
    134    minus:
    135      input_size: '-100'
    136      result_size: 'exception'
    137    octal:
    138      input_size: '0100'
    139      result_size: 100
    140    hex:
    141      input_size: '0x100'
    142      result_size: 0x100
    143    exp:
    144      input_size: '100e1'
    145      result_size: 1000.0
    146    decimal:
    147      input_size: '100.999'
    148      result_size: 100
    149    percent:
    150      input_size: '100%'
    151      result_size: 'exception'
    152    em:
    153      input_size: '100em'
    154      result_size: 'exception'
    155    junk:
    156      input_size: '#!?'
    157      result_size: 'exception'
    158    trailingjunk:
    159      input_size: '100#!?'
    160      result_size: 'exception'
    161 
    162 - name: 2d.canvas.host.type.delete
    163  canvas_types: ['HtmlCanvas']
    164  desc: window.HTMLCanvasElement interface object is [[Configurable]]
    165  code: |
    166    @assert delete window.HTMLCanvasElement === true;
    167    @assert window.HTMLCanvasElement === undefined;
    168 
    169 - name: 2d.canvas.host.type.delete
    170  canvas_types: ['OffscreenCanvas', 'Worker']
    171  desc: OffscreenCanvas interface object is [[Configurable]]
    172  code: |
    173    {% set root = 'self' if canvas_type == 'Worker' else 'window' %}
    174    @assert delete {{ root }}.OffscreenCanvas === true;
    175    @assert {{ root }}.OffscreenCanvas === undefined;
    176 
    177 - name: 2d.canvas.host.type.name
    178  canvas_types: ['HtmlCanvas']
    179  desc: HTMLCanvasElement type and toString
    180  code: |
    181    @assert Object.prototype.toString.call(canvas) === '[object HTMLCanvasElement]';
    182 
    183 - name: 2d.canvas.host.type.name
    184  canvas_types: ['OffscreenCanvas', 'Worker']
    185  desc: OffscreenCanvas type and toString
    186  code: |
    187    @assert Object.prototype.toString.call(canvas) === '[object OffscreenCanvas]';
    188 
    189 - name: 2d.canvas.context.exists
    190  desc: The 2D context is implemented
    191  code: |
    192    @assert canvas.getContext('2d') !== null;
    193 
    194 - name: 2d.canvas.context.extraargs.create
    195  desc: The 2D context doesn't throw with extra getContext arguments (new context)
    196  code: |
    197    @assert {{ new_canvas }}.getContext('2d', false, {}, [], 1, "2") !== null;
    198    @assert {{ new_canvas }}.getContext('2d', 123) !== null;
    199    @assert {{ new_canvas }}.getContext('2d', "test") !== null;
    200    @assert {{ new_canvas }}.getContext('2d', undefined) !== null;
    201    @assert {{ new_canvas }}.getContext('2d', null) !== null;
    202    @assert {{ new_canvas }}.getContext('2d', Symbol.hasInstance) !== null;
    203  variants: *new-canvas-definition
    204 
    205 - name: 2d.canvas.context.invalid.args
    206  desc: Calling getContext with invalid arguments.
    207  canvas_types: ['HtmlCanvas']
    208  code: |
    209    @assert canvas.getContext('') === null;
    210    @assert canvas.getContext('2d#') === null;
    211    @assert canvas.getContext('This is clearly not a valid context name.') === null;
    212    @assert canvas.getContext('2d\0') === null;
    213    @assert canvas.getContext('2\uFF44') === null;
    214    @assert canvas.getContext('2D') === null;
    215    @assert throws TypeError canvas.getContext();
    216    @assert canvas.getContext('null') === null;
    217    @assert canvas.getContext('undefined') === null;
    218 
    219 - name: 2d.canvas.context.invalid.args
    220  desc: Calling getContext with invalid arguments.
    221  canvas_types: ['OffscreenCanvas', 'Worker']
    222  code: |
    223    @assert throws TypeError canvas.getContext('');
    224    @assert throws TypeError canvas.getContext('This is not an implemented context in any real browser');
    225    @assert throws TypeError canvas.getContext('2d#');
    226    @assert throws TypeError canvas.getContext('2d\0');
    227    @assert throws TypeError canvas.getContext('2\uFF44');
    228    @assert throws TypeError canvas.getContext('2D');
    229    @assert throws TypeError canvas.getContext();
    230    @assert throws TypeError canvas.getContext('null');
    231    @assert throws TypeError canvas.getContext('undefined');
    232 
    233 
    234 - name: 2d.canvas.context.extraargs.cache
    235  desc: The 2D context doesn't throw with extra getContext arguments (cached)
    236  code: |
    237    @assert canvas.getContext('2d', false, {}, [], 1, '2') !== null;
    238    @assert canvas.getContext('2d', 123) !== null;
    239    @assert canvas.getContext('2d', 'test') !== null;
    240    @assert canvas.getContext('2d', undefined) !== null;
    241    @assert canvas.getContext('2d', null) !== null;
    242    @assert canvas.getContext('2d', Symbol.hasInstance) !== null;
    243 
    244 - name: 2d.canvas.context.unique
    245  desc: getContext('2d') returns the same object
    246  code: |
    247    @assert canvas.getContext('2d') === canvas.getContext('2d');
    248 
    249 - name: 2d.canvas.context.shared
    250  desc: getContext('2d') returns objects which share canvas state
    251  code: |
    252    var ctx2 = canvas.getContext('2d');
    253    ctx.fillStyle = '#f00';
    254    ctx2.fillStyle = '#0f0';
    255    ctx.fillRect(0, 0, 100, 50);
    256    @assert pixel 50,25 == 0,255,0,255;
    257  expected: green
    258 
    259 - name: 2d.canvas.host.initial.color
    260  desc: Initial state is transparent black
    261  code: |
    262    @assert pixel 20,20 == 0,0,0,0;
    263 
    264 - name: 2d.canvas.host.initial.reset.different
    265  desc: Changing size resets canvas to transparent black
    266  code: |
    267    ctx.fillStyle = '#f00';
    268    ctx.fillRect(0, 0, 50, 50);
    269    @assert pixel 20,20 == 255,0,0,255;
    270    canvas.width = 50;
    271    @assert pixel 20,20 == 0,0,0,0;
    272 
    273 - name: 2d.canvas.host.initial.reset.same
    274  desc: Setting size (not changing the value) resets canvas to transparent black
    275  code: |
    276    canvas.width = 100;
    277    ctx.fillStyle = '#f00';
    278    ctx.fillRect(0, 0, 50, 50);
    279    @assert pixel 20,20 == 255,0,0,255;
    280    canvas.width = 100;
    281    @assert pixel 20,20 == 0,0,0,0;
    282 
    283 
    284 - name: 2d.canvas.host.initial.reset.path
    285  desc: Resetting the canvas state resets the current path
    286  code: |
    287    canvas.width = 100;
    288    ctx.rect(0, 0, 100, 50);
    289    canvas.width = 100;
    290    ctx.fillStyle = '#f00';
    291    ctx.fill();
    292    @assert pixel 20,20 == 0,0,0,0;
    293 
    294 - name: 2d.canvas.host.initial.reset.clip
    295  desc: Resetting the canvas state resets the current clip region
    296  code: |
    297    canvas.width = 100;
    298    ctx.rect(0, 0, 1, 1);
    299    ctx.clip();
    300    canvas.width = 100;
    301    ctx.fillStyle = '#0f0';
    302    ctx.fillRect(0, 0, 100, 50);
    303    @assert pixel 20,20 == 0,255,0,255;
    304 
    305 - name: 2d.canvas.host.initial.reset.transform
    306  desc: Resetting the canvas state resets the current transformation matrix
    307  code: |
    308    canvas.width = 100;
    309    ctx.scale(0.1, 0.1);
    310    canvas.width = 100;
    311    ctx.fillStyle = '#0f0';
    312    ctx.fillRect(0, 0, 100, 50);
    313    @assert pixel 20,20 == 0,255,0,255;
    314 
    315 - name: 2d.canvas.host.initial.reset.gradient
    316  desc: Resetting the canvas state does not invalidate any existing gradients
    317  code: |
    318    canvas.width = 50;
    319    var g = ctx.createLinearGradient(0, 0, 100, 0);
    320    g.addColorStop(0, '#0f0');
    321    g.addColorStop(1, '#0f0');
    322    canvas.width = 100;
    323    ctx.fillStyle = '#f00';
    324    ctx.fillRect(0, 0, 100, 50);
    325    ctx.fillStyle = g;
    326    ctx.fillRect(0, 0, 100, 50);
    327    @assert pixel 50,25 == 0,255,0,255;
    328 
    329 - name: 2d.canvas.host.initial.reset.pattern
    330  desc: Resetting the canvas state does not invalidate any existing patterns
    331  code: |
    332    canvas.width = 30;
    333    ctx.fillStyle = '#0f0';
    334    ctx.fillRect(0, 0, 30, 50);
    335    var p = ctx.createPattern(canvas, 'repeat-x');
    336    canvas.width = 100;
    337    ctx.fillStyle = '#f00';
    338    ctx.fillRect(0, 0, 100, 50);
    339    ctx.fillStyle = p;
    340    ctx.fillRect(0, 0, 100, 50);
    341    @assert pixel 50,25 == 0,255,0,255;
    342 
    343 - name: 2d.canvas.host.size.attributes.idl.set.zero
    344  desc: Setting width/height IDL attributes to 0
    345  code: |
    346    canvas.width = 0;
    347    canvas.height = 0;
    348    @assert canvas.width === 0;
    349    @assert canvas.height === 0;
    350 
    351 - name: 2d.canvas.host.size.attributes.idl
    352  desc: Getting/setting width/height IDL attributes
    353  code: |
    354    canvas.width = '100';
    355    canvas.height = '100';
    356    @assert canvas.width === 100;
    357    @assert canvas.height === 100;
    358    canvas.width = 301.999;
    359    canvas.height = 301.001;
    360    @assert canvas.width === 301;
    361    @assert canvas.height === 301;
    362    canvas.width = "+1.5e2";
    363    canvas.height = "0x96";
    364    @assert canvas.width === 150;
    365    @assert canvas.height === 150;
    366 
    367 - name: 2d.canvas.host.size.invalid.attributes.idl
    368  canvas_types: ['OffscreenCanvas', 'Worker']
    369  desc: Getting/setting width/height IDL attributes
    370  code: |
    371    @assert throws TypeError canvas.width = 200 - Math.pow(2, 32);
    372    @assert throws TypeError canvas.height = 200 - Math.pow(2, 32);
    373    @assert throws TypeError canvas.width = '400x';
    374    @assert throws TypeError canvas.height = 'foo';
    375 
    376 - name: 2d.canvas.host.size.invalid.attributes.idl
    377  canvas_types: ['HtmlCanvas']
    378  desc: Getting/setting width/height IDL attributes
    379  code: |
    380    canvas.width = 200 - Math.pow(2, 32);
    381    canvas.height = 200 - Math.pow(2, 32);
    382    @assert canvas.width === 200;
    383    @assert canvas.height === 200;
    384    canvas.width = '400x';
    385    canvas.height = 'foo';
    386    @assert canvas.width === 0;
    387    @assert canvas.height === 0;
    388 
    389 - name: 2d.canvas.host.size.attributes.default
    390  desc: Default width/height when attributes are missing
    391  code: |
    392    @assert canvas.width === 100;
    393    @assert canvas.height === 50;
    394 
    395 - name: 2d.canvas.host.size.attributes.removed
    396  size: [120, 50]
    397  canvas_types: ['HtmlCanvas']
    398  desc: Removing content attributes reverts to default size
    399  code: |
    400    @assert canvas.width === 120;
    401    canvas.removeAttribute('width');
    402    @assert canvas.width === 300;
    403 
    404 
    405 - name: 2d.canvas.host.size.attributes.reflect.setidl
    406  desc: Setting IDL attributes updates IDL and content attributes
    407  code: |
    408    canvas.width = 120;
    409    canvas.height = 60;
    410    @assert canvas.width === 120;
    411    @assert canvas.height === 60;
    412    {% if canvas_type == 'HtmlCanvas' %}
    413    @assert canvas.getAttribute('width') === '120';
    414    @assert canvas.getAttribute('height') === '60';
    415    {% endif %}
    416 
    417 - name: 2d.canvas.host.size.attributes.reflect.setidlzero
    418  desc: Setting IDL attributes to 0 updates IDL and content attributes
    419  code: |
    420    canvas.width = 0;
    421    canvas.height = 0;
    422    {% if canvas_type == 'HtmlCanvas' %}
    423    _assertSame(canvas.getAttribute('width'), '0', "canvas.getAttribute('width')", "'0'");
    424    _assertSame(canvas.getAttribute('height'), '0', "canvas.getAttribute('height')", "'0'");
    425    {% endif %}
    426    @assert canvas.width === 0;
    427    @assert canvas.height === 0;
    428 
    429 - name: 2d.canvas.host.size.attributes.reflect.setcontent
    430  canvas_types: ['HtmlCanvas']
    431  desc: Setting content attributes updates IDL and content attributes
    432  code: |
    433    canvas.setAttribute('width', '120');
    434    canvas.setAttribute('height', '60');
    435    @assert canvas.getAttribute('width') === '120';
    436    @assert canvas.getAttribute('height') === '60';
    437    @assert canvas.width === 120;
    438    @assert canvas.height === 60;
    439 
    440 - name: 2d.canvas.host.size.large
    441  notes: Not sure how reasonable this is, but the spec doesn't say there's an upper
    442    limit on the size.
    443  code: |
    444    var n = 2147483647; // 2^31 - 1, which should be supported by any sensible definition of "long"
    445    canvas.width = n;
    446    canvas.height = n;
    447    @assert canvas.width === n;
    448    @assert canvas.height === n;
    449 
    450 - name: 2d.canvas.context.prototype
    451  desc: checks CanvasRenderingContext2D prototype
    452  canvas_types: ['HtmlCanvas']
    453  code: |
    454    @assert Object.getPrototypeOf(CanvasRenderingContext2D.prototype) === Object.prototype;
    455    @assert Object.getPrototypeOf(ctx) === CanvasRenderingContext2D.prototype;
    456 
    457 - name: 2d.canvas.context.prototype
    458  desc: checks OffscreenCanvasRenderingContext2D prototype
    459  canvas_types: ['OffscreenCanvas', 'Worker']
    460  code: |
    461    @assert Object.getPrototypeOf(OffscreenCanvasRenderingContext2D.prototype) === Object.prototype;
    462    @assert Object.getPrototypeOf(ctx) === OffscreenCanvasRenderingContext2D.prototype;
    463 
    464 - name: 2d.canvas.host.scaled
    465  desc: CSS-scaled canvases get drawn correctly
    466  canvas_types: ['HtmlCanvas']
    467  size: [50, 25]
    468  canvas: 'style="width: 100px; height: 50px"'
    469  manual:
    470  code: |
    471    ctx.fillStyle = '#00f';
    472    ctx.fillRect(0, 0, 50, 25);
    473    ctx.fillStyle = '#0ff';
    474    ctx.fillRect(0, 0, 25, 10);
    475  expected: |
    476    size 100 50
    477    cr.set_source_rgb(0, 0, 1)
    478    cr.rectangle(0, 0, 100, 50)
    479    cr.fill()
    480    cr.set_source_rgb(0, 1, 1)
    481    cr.rectangle(0, 0, 50, 20)
    482    cr.fill()
    483 
    484 - name: 2d.canvas.context.type.exists
    485  desc: The 2D context interface is a property of '{{ root }}'
    486  notes: &bindings Defined in "Web IDL" (draft)
    487  code: |
    488    @assert {{ root }}.{{ context_object }};
    489  variants: &get-context-definition
    490    - HtmlCanvas:
    491        append_variants_to_name: false
    492        canvas_types: ['HtmlCanvas']
    493        root: window
    494        context_object: CanvasRenderingContext2D
    495      OffscreenCanvas:
    496        append_variants_to_name: false
    497        canvas_types: ['OffscreenCanvas']
    498        root: window
    499        context_object: OffscreenCanvasRenderingContext2D
    500      Worker:
    501        append_variants_to_name: false
    502        canvas_types: ['Worker']
    503        root: self
    504        context_object: OffscreenCanvasRenderingContext2D
    505 
    506 - name: 2d.canvas.context.type.extend
    507  desc: Interface methods can be added
    508  notes: *bindings
    509  code: |
    510    {{ root }}.{{ context_object }}.prototype.fillRectGreen = function (x, y, w, h)
    511    {
    512        this.fillStyle = '#0f0';
    513        this.fillRect(x, y, w, h);
    514    };
    515    ctx.fillStyle = '#f00';
    516    ctx.fillRectGreen(0, 0, 100, 50);
    517    @assert pixel 50,25 == 0,255,0,255;
    518  expected: green
    519  variants: *get-context-definition
    520 
    521 - name: 2d.canvas.context.type.replace
    522  desc: Interface methods can be overridden
    523  notes: *bindings
    524  code: |
    525    var fillRect = {{ root }}.{{ context_object }}.prototype.fillRect;
    526    {{ root }}.{{ context_object }}.prototype.fillRect = function (x, y, w, h)
    527    {
    528        this.fillStyle = '#0f0';
    529        fillRect.call(this, x, y, w, h);
    530    };
    531    ctx.fillStyle = '#f00';
    532    ctx.fillRect(0, 0, 100, 50);
    533    @assert pixel 50,25 == 0,255,0,255;
    534  expected: green
    535  variants: *get-context-definition
    536 
    537 - name: 2d.canvas.context.type.prototype
    538  desc: window.CanvasRenderingContext2D.prototype are not [[Writable]] and not [[Configurable]],
    539    and its methods are [[Configurable]].
    540  notes: *bindings
    541  code: |
    542    @assert {{ root }}.{{ context_object }}.prototype;
    543    @assert {{ root }}.{{ context_object }}.prototype.fill;
    544    {{ root }}.{{ context_object }}.prototype = null;
    545    @assert {{ root }}.{{ context_object }}.prototype;
    546    delete {{ root }}.{{ context_object }}.prototype;
    547    @assert {{ root }}.{{ context_object }}.prototype;
    548    {{ root }}.{{ context_object }}.prototype.fill = 1;
    549    @assert {{ root }}.{{ context_object }}.prototype.fill === 1;
    550    delete {{ root }}.{{ context_object }}.prototype.fill;
    551    @assert {{ root }}.{{ context_object }}.prototype.fill === undefined;
    552  variants: *get-context-definition