- name: 2d.canvas.host.reference
  desc: canvas refers back to its canvas
  code: |
    @assert ctx.canvas === canvas;
    t.done();

- name: 2d.canvas.host.readonly
  desc: canvas is readonly
  code: |
    var offscreenCanvas2 = new OffscreenCanvas(100, 50);
    var d = ctx.canvas;
    @assert offscreenCanvas2 !== d;
    ctx.canvas = offscreenCanvas2;
    @assert ctx.canvas === d;
    t.done();

- name: 2d.canvas.context.exists
  desc: The 2D context is implemented
  code: |
    var offscreenCanvas2 = new OffscreenCanvas(100, 50);
    @assert offscreenCanvas2.getContext('2d') !== null;
    t.done();

- name: 2d.canvas.context.extraargs.create
  desc: The 2D context doesn't throw with extra getContext arguments (new context)
  code: |
    @assert (new OffscreenCanvas(100, 50)).getContext('2d', false, {}, [], 1, "2") !== null;
    @assert (new OffscreenCanvas(100, 50)).getContext('2d', 123) !== null;
    @assert (new OffscreenCanvas(100, 50)).getContext('2d', "test") !== null;
    @assert (new OffscreenCanvas(100, 50)).getContext('2d', undefined) !== null;
    @assert (new OffscreenCanvas(100, 50)).getContext('2d', null) !== null;
    @assert (new OffscreenCanvas(100, 50)).getContext('2d', Symbol.hasInstance) !== null;
    t.done();

- name: 2d.canvas.context.extraargs.cache
  desc: The 2D context doesn't throw with extra getContext arguments (cached)
  code: |
    @assert canvas.getContext('2d', false, {}, [], 1, "2") !== null;
    @assert canvas.getContext('2d', 123) !== null;
    @assert canvas.getContext('2d', "test") !== null;
    @assert canvas.getContext('2d', undefined) !== null;
    @assert canvas.getContext('2d', null) !== null;
    @assert canvas.getContext('2d', Symbol.hasInstance) !== null;
    t.done();

- name: 2d.canvas.context.unique
  desc: getContext('2d') returns the same object
  code: |
    var offscreenCanvas2 = new OffscreenCanvas(100, 50);
    @assert offscreenCanvas2.getContext('2d') === offscreenCanvas2.getContext('2d');
    t.done();

- name: 2d.canvas.context.shared
  desc: getContext('2d') returns objects which share canvas state
  code: |
    var ctx2 = canvas.getContext('2d');
    ctx.fillStyle = '#f00';
    ctx2.fillStyle = '#0f0';
    ctx.fillRect(0, 0, 100, 50);
    @assert pixel 50,25 == 0,255,0,255;
    t.done();

- name: 2d.canvas.context.emptystring
  desc: getContext with empty string returns null
  code: |
    var offscreenCanvas2 = new OffscreenCanvas(100, 50);
    @assert throws TypeError offscreenCanvas2.getContext("");
    t.done();

- name: 2d.canvas.context.unrecognised.badname
  desc: getContext with unrecognised context name returns null
  code: |
    var offscreenCanvas2 = new OffscreenCanvas(100, 50);
    @assert throws TypeError offscreenCanvas2.getContext('This is not an implemented context in any real browser');
    t.done();

- name: 2d.canvas.context.unrecognised.badsuffix
  desc: Context name "2d" plus a suffix is unrecognised
  code: |
    var offscreenCanvas2 = new OffscreenCanvas(100, 50);
    @assert throws TypeError offscreenCanvas2.getContext("2d#");
    t.done();

- name: 2d.canvas.context.unrecognised.nullsuffix
  desc: Context name "2d" plus a "\0" suffix is unrecognised
  code: |
    var offscreenCanvas2 = new OffscreenCanvas(100, 50);
    @assert throws TypeError offscreenCanvas2.getContext("2d\0");
    t.done();

- name: 2d.canvas.context.unrecognised.unicode
  desc: Context name which kind of looks like "2d" is unrecognised
  code: |
    var offscreenCanvas2 = new OffscreenCanvas(100, 50);
    @assert throws TypeError offscreenCanvas2.getContext("2\uFF44");
    t.done();

- name: 2d.canvas.context.casesensitive
  desc: Context name "2D" is unrecognised; matching is case sensitive
  code: |
    var offscreenCanvas2 = new OffscreenCanvas(100, 50);
    @assert throws TypeError offscreenCanvas2.getContext('2D');
    t.done();

- name: 2d.canvas.context.arguments.missing
  code: |
    var offscreenCanvas2 = new OffscreenCanvas(100, 50);
    @assert throws TypeError offscreenCanvas2.getContext(); @moz-todo
    t.done();


- name: 2d.canvas.host.initial.color
  desc: Initial state is transparent black
  code: |
    @assert pixel 20,20 == 0,0,0,0;
    t.done();

- name: 2d.canvas.host.initial.reset.different
  desc: Changing size resets canvas to transparent black
  code: |
    ctx.fillStyle = '#f00';
    ctx.fillRect(0, 0, 50, 50);
    @assert pixel 20,20 == 255,0,0,255;
    canvas.width = 50;
    @assert pixel 20,20 == 0,0,0,0;
    t.done();

- name: 2d.canvas.host.initial.reset.same
  desc: Setting size (not changing the value) resets canvas to transparent black
  code: |
    canvas.width = 100;
    ctx.fillStyle = '#f00';
    ctx.fillRect(0, 0, 50, 50);
    @assert pixel 20,20 == 255,0,0,255;
    canvas.width = 100;
    @assert pixel 20,20 == 0,0,0,0;
    t.done();

- name: 2d.canvas.host.initial.reset.path
  desc: Resetting the canvas state resets the current path
  code: |
    canvas.width = 100;
    ctx.rect(0, 0, 100, 50);
    canvas.width = 100;
    ctx.fillStyle = '#f00';
    ctx.fill();
    @assert pixel 20,20 == 0,0,0,0;
    t.done();

- name: 2d.canvas.host.initial.reset.clip
  desc: Resetting the canvas state resets the current clip region
  code: |
    canvas.width = 100;
    ctx.rect(0, 0, 1, 1);
    ctx.clip();
    canvas.width = 100;
    ctx.fillStyle = '#0f0';
    ctx.fillRect(0, 0, 100, 50);
    @assert pixel 20,20 == 0,255,0,255;
    t.done();

- name: 2d.canvas.host.initial.reset.transform
  desc: Resetting the canvas state resets the current transformation matrix
  code: |
    canvas.width = 100;
    ctx.scale(0.1, 0.1);
    canvas.width = 100;
    ctx.fillStyle = '#0f0';
    ctx.fillRect(0, 0, 100, 50);
    @assert pixel 20,20 == 0,255,0,255;
    t.done();

- name: 2d.canvas.host.initial.reset.gradient
  desc: Resetting the canvas state does not invalidate any existing gradients
  code: |
    canvas.width = 50;
    var g = ctx.createLinearGradient(0, 0, 100, 0);
    g.addColorStop(0, '#0f0');
    g.addColorStop(1, '#0f0');
    canvas.width = 100;
    ctx.fillStyle = '#f00';
    ctx.fillRect(0, 0, 100, 50);
    ctx.fillStyle = g;
    ctx.fillRect(0, 0, 100, 50);
    @assert pixel 50,25 == 0,255,0,255;
    t.done();

- name: 2d.canvas.host.initial.reset.pattern
  desc: Resetting the canvas state does not invalidate any existing patterns
  code: |
    canvas.width = 30;
    ctx.fillStyle = '#0f0';
    ctx.fillRect(0, 0, 30, 50);
    var p = ctx.createPattern(canvas, 'repeat-x');
    canvas.width = 100;
    ctx.fillStyle = '#f00';
    ctx.fillRect(0, 0, 100, 50);
    ctx.fillStyle = p;
    ctx.fillRect(0, 0, 100, 50);
    @assert pixel 50,25 == 0,255,0,255;
    t.done();

- name: 2d.canvas.host.size.attributes.idl.set.zero
  desc: Setting width/height IDL attributes to 0
  code: |
    canvas.width = 0;
    canvas.height = 0;
    @assert canvas.width === 0;
    @assert canvas.height === 0;
    t.done();

- name: 2d.canvas.host.size.attributes.idl
  desc: Getting/setting width/height IDL attributes
  webidl:
  - es-unsigned-long
  code: |
    canvas.width = "100";
    canvas.height = "100";
    @assert canvas.width === 100;
    @assert canvas.height === 100;
    canvas.width = "+1.5e2";
    canvas.height = "0x96";
    @assert canvas.width === 150;
    @assert canvas.height === 150;
    canvas.width = 301.999;
    canvas.height = 301.001;
    @assert canvas.width === 301;
    @assert canvas.height === 301;
    @assert throws TypeError canvas.width = "400x";
    @assert throws TypeError canvas.height = "foo";
    @assert canvas.width === 301;
    @assert canvas.height === 301;
    t.done();

- name: 2d.canvas.host.size.attributes.default
  desc: Default width/height when attributes are missing
  code: |
    @assert canvas.width === 100;
    @assert canvas.height === 50;
    t.done();

- name: 2d.canvas.host.size.attributes.reflect.setidl
  desc: Setting IDL attributes updates IDL and content attributes
  code: |
    canvas.width = 120;
    canvas.height = 60;
    @assert canvas.width === 120;
    @assert canvas.height === 60;
    t.done();

- name: 2d.canvas.host.size.attributes.reflect.setidlzero
  desc: Setting IDL attributes to 0 updates IDL and content attributes
  code: |
    canvas.width = 0;
    canvas.height = 0;
    @assert canvas.width === 0;
    @assert canvas.height === 0;
    t.done();

- name: 2d.canvas.host.size.large
  notes: Not sure how reasonable this is, but the spec doesn't say there's an upper
    limit on the size.
  code: |
    var n = 2147483647; // 2^31 - 1, which should be supported by any sensible definition of "long"
    canvas.width = n;
    canvas.height = n;
    @assert canvas.width === n;
    @assert canvas.height === n;
    t.done();
