- name: 2d.reset.basic
  desc: reset clears to transparent black
  code: |
    ctx.fillStyle = '#f00';
    ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
    ctx.reset();
    @assert pixel 0,0 == 0,0,0,0;
    @assert pixel 50,25 == 0,0,0,0;
    @assert pixel 25,50 == 0,0,0,0;
    @assert pixel 100,50 == 0,0,0,0;
    @assert pixel 0,50 == 0,0,0,0;
    @assert pixel 100,0 == 0,0,0,0;
    t.done();

- name: 2d.reset.after-rasterization
  desc: Reset after rasterizing a frame discards frame content.
  code: |
    ctx.fillStyle = 'rgba(255, 0, 0, 1)';
    ctx.fillRect(0, 0, {{ size[0] }}, {{ size[1] }});

    ctx.getImageData(0, 0, 1, 1);  // Force previous draw calls to be rendered.
    ctx.reset();

    ctx.fillStyle = 'rgba(0, 255, 0, 0.5)';
    ctx.fillRect(0, 0, {{ size[0] }}, {{ (size[1] / 2) | int }});
  reference: |
    ctx.fillStyle = 'rgba(0, 255, 0, 0.5)';
    ctx.fillRect(0, 0, {{ size[0] }}, {{ (size[1] / 2) | int }});

- name: 2d.reset.state
  desc: check that the state is reset
  code: |
    const default_value = ctx.{{ state_name }};

    ctx.{{ state_name }} = {{ new_value }};
    @assert ctx.{{ state_name }} == {{ new_value }};

    ctx.reset();
    @assert ctx.{{ state_name }} == default_value;

  variants:
  - letter_spacing:
      state_name: letterSpacing
      new_value: "'12px'"

    word_spacing:
      state_name: wordSpacing
      new_value: "'12px'"

    fill_style:
      state_name: fillStyle
      new_value: "'#ffffff'"

    stroke_style:
      state_name: strokeStyle
      new_value: "'#ffffff'"

    filter:
      state_name: filter
      new_value: "'blur(10px)'"

    font:
      state_name: font
      new_value: "'25px sans-serif'"

    global_alpha:
      state_name: globalAlpha
      new_value: 0.5

    global_composite_operation:
      state_name: globalCompositeOperation
      new_value: "'destination-over'"

    line_width:
      state_name: lineWidth
      new_value: 1

    line_cap:
      state_name: lineCap
      new_value: "'square'"

    line_join:
      state_name: lineJoin
      new_value: "'bevel'"

    miter_limit:
      state_name: miterLimit
      new_value: 1.0

    line_dash_offset:
      state_name: lineDashOffset
      new_value: 1.0

    shadow_offset_x:
      state_name: shadowOffsetX
      new_value: 10.0

    shadow_offset_y:
      state_name: shadowOffsetY
      new_value: 10.0

    shadow_blur:
      state_name: shadowBlur
      new_value: 10.0

    shadow_color:
      state_name: shadowColor
      new_value: "'#ff0000'"

    font:
      state_name: font
      new_value: "'16px sans-serif'"

    text_align:
      state_name: textAlign
      new_value: "'end'"

    text_baseline:
      state_name: textBaseline
      new_value: "'middle'"

    direction:
      state_name: direction
      new_value: "'rtl'"

    font_kerning:
      state_name: fontKerning
      new_value: "'normal'"

    font_stretch:
      state_name: fontStretch
      new_value: "'ultra-condensed'"

    font_variant_caps:
      state_name: fontVariantCaps
      new_value: "'unicase'"

    text_rendering:
      state_name: textRendering
      new_value: "'geometricPrecision'"

    image_smoothing_enabled:
      state_name: imageSmoothingEnabled
      new_value: "false"

    image_smoothing_quality:
      state_name: imageSmoothingQuality
      new_value: "'high'"

- name: 2d.reset.state.transformation_matrix
  desc: check that the state is reset
  code: |
    ctx.scale(2, 2);

    ctx.reset();
    @assert ctx.getTransform().isIdentity;

- name: 2d.reset.state.clip
  desc: check that the clip is reset
  size: [200, 200]
  code: |
    ctx.beginPath();
    ctx.rect(0, 0, 100, 100);
    ctx.clip();

    ctx.fillRect(0, 0, 200, 200);

    ctx.reset();

    ctx.fillRect(0, 0, 200, 200);
  reference: |
    ctx.fillRect(0, 0, 200, 200);

- name: 2d.reset.state.line_dash
  desc: check that the line dash is reset
  code: |
    ctx.setLineDash([1, 2]);

    ctx.reset();
    @assert ctx.getLineDash().length == 0;

- name: 2d.reset.render.drop_shadow
  desc: check that drop shadows are correctly rendered after reset
  size: [500, 500]
  code: |
    ctx.shadowOffsetX = 10;
    ctx.shadowOffsetY = 10;
    ctx.shadowColor = "red";
    ctx.shadowBlur = 10;

    ctx.reset();

    ctx.fillRect(100, 100, 100, 100);
  reference: |
    ctx.fillRect(100, 100, 100, 100);

- name: 2d.reset.render.text
  desc: check that text is correctly rendered after reset
  size: [400, 400]
  code: |
    ctx.font = "24px serif";
    ctx.textAlign = "center";
    ctx.textBaseline = "hanging";
    ctx.direction = "rtl";
    ctx.letterSpacing = "10px";
    ctx.fontKerning = "none";
    ctx.fontStretch = "semi-condensed";
    ctx.fontVariantCaps = "titling-caps";
    ctx.textRendering = "optimizeLegibility";
    ctx.wordSpacing = "20px";

    ctx.reset();

    ctx.fillText("Lorem ipsum dolor sit amet, consectetur adipiscing elit", 0, 10);
  reference: |
    ctx.fillText("Lorem ipsum dolor sit amet, consectetur adipiscing elit", 0, 10);

- name: 2d.reset.render.line
  desc: check that lines are correctly rendered after reset
  size: [400, 400]
  code: |
    ctx.lineWidth = 10;
    ctx.lineCap = "round";
    ctx.lineJoin = "bevel";
    ctx.lineDashOffset = 10;
    ctx.setLineDash([20]);

    ctx.reset();

    ctx.beginPath();
    ctx.moveTo(100, 100);
    ctx.lineTo(100, 300);
    ctx.lineTo(300, 300);
    ctx.lineTo(300, 100);
    ctx.stroke();
  reference: |
    ctx.beginPath();
    ctx.moveTo(100, 100);
    ctx.lineTo(100, 300);
    ctx.lineTo(300, 300);
    ctx.lineTo(300, 100);
    ctx.stroke();

- name: 2d.reset.render.miter_limit
  desc: check that the lines are correctly rendered with the default miter limit after reset
  size: [400, 400]
  code: |
    ctx.miterLimit = 6;

    ctx.reset();

    ctx.lineWidth = 10;

    ctx.beginPath();
    ctx.moveTo(0, 100);
    for (let i = 0; i < 24; i++) {
      const dy = i % 2 === 0 ? 25 : -25;
      ctx.lineTo(Math.pow(i, 1.5) * 2, 75 + dy);
    }
    ctx.stroke();
  reference: |
    ctx.lineWidth = 10;

    ctx.beginPath();
    ctx.moveTo(0, 100);
    for (let i = 0; i < 24; i++) {
      const dy = i % 2 === 0 ? 25 : -25;
      ctx.lineTo(Math.pow(i, 1.5) * 2, 75 + dy);
    }
    ctx.stroke();

- name: 2d.reset.render.global_composite_operation
  desc: check that canvas correctly renders rectangles with the default global composite operation after reset
  size: [400, 400]
  code: |
    ctx.globalCompositeOperation = "xor";

    ctx.reset();

    ctx.fillRect(10, 10, 100, 100);
    ctx.fillRect(50, 50, 100, 100);
  reference: |
    ctx.fillRect(10, 10, 100, 100);
    ctx.fillRect(50, 50, 100, 100);

- name: 2d.reset.render.misc
  desc: check that canvas correctly renders rectangles after reset (states not covered by other tests)
  size: [400, 400]
  code: |
    ctx.fillStyle = "red";
    ctx.strokeStyle = "red";
    ctx.globalAlpha = 0.5;
    ctx.filter = "blur(2px)";

    ctx.reset();

    ctx.fillRect(0, 0, 100, 100);
    ctx.strokeRect(150, 150, 100, 100);
  reference: |
    ctx.fillRect(0, 0, 100, 100);
    ctx.strokeRect(150, 150, 100, 100);
