Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Throw an exception in transferToImageBitmap if canvas layers are opened #42544

Merged
merged 1 commit into from
Oct 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

This file was deleted.

This file was deleted.

34 changes: 34 additions & 0 deletions html/canvas/offscreen/layers/2d.layer.transferToImageBitmap.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<!DOCTYPE html>
<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
<title>OffscreenCanvas test: 2d.layer.transferToImageBitmap</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/html/canvas/resources/canvas-tests.js"></script>

<h1>2d.layer.transferToImageBitmap</h1>
<p class="desc">Check that calling transferToImageBitmap in a layer throws an exception.</p>


<script>
var t = async_test("Check that calling transferToImageBitmap in a layer throws an exception.");
var t_pass = t.done.bind(t);
var t_fail = t.step_func(function(reason) {
throw reason;
});
t.step(function() {

var canvas = new OffscreenCanvas(100, 50);
var ctx = canvas.getContext('2d');

// `transferToImageBitmap` shouldn't throw on it's own.
canvas.transferToImageBitmap();
// Make sure the exception isn't caused by calling the function twice.
canvas.transferToImageBitmap();
// Calling again inside a layer should throw.
ctx.beginLayer();
assert_throws_dom("InvalidStateError",
() => canvas.transferToImageBitmap());
t.done();

});
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py.
// OffscreenCanvas test in a worker:2d.layer.transferToImageBitmap
// Description:Check that calling transferToImageBitmap in a layer throws an exception.
// Note:

importScripts("/resources/testharness.js");
importScripts("/html/canvas/resources/canvas-tests.js");

var t = async_test("Check that calling transferToImageBitmap in a layer throws an exception.");
var t_pass = t.done.bind(t);
var t_fail = t.step_func(function(reason) {
throw reason;
});
t.step(function() {

var canvas = new OffscreenCanvas(100, 50);
var ctx = canvas.getContext('2d');

// `transferToImageBitmap` shouldn't throw on it's own.
canvas.transferToImageBitmap();
// Make sure the exception isn't caused by calling the function twice.
canvas.transferToImageBitmap();
// Calling again inside a layer should throw.
ctx.beginLayer();
assert_throws_dom("InvalidStateError",
() => canvas.transferToImageBitmap());
t.done();
});
done();
31 changes: 20 additions & 11 deletions html/canvas/offscreen/layers/2d.layer.unclosed-nested.w.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,29 @@ <h1>2d.layer.unclosed-nested</h1>
const canvas = new OffscreenCanvas(200, 200);
const ctx = canvas.getContext('2d');

ctx.fillStyle = 'rgba(0, 0, 255, 1)';
ctx.fillRect(60, 60, 75, 50);
ctx.globalAlpha = 0.5;
// `transferToImageBitmap` is used to transfer the test result to the
// worker's parent, but `transferToImageBitmap` can't be called on canvas
// with unclosed layers. We can however draw to a separate offscreen canvas
// and write it to the main canvas using `drawImage`.
const canvas2 = new OffscreenCanvas(200, 200);
const ctx2 = canvas2.getContext('2d');

ctx.beginLayer();
ctx.fillStyle = 'rgba(225, 0, 0, 1)';
ctx.fillRect(50, 50, 75, 50);
ctx2.fillStyle = 'rgba(0, 0, 255, 1)';
ctx2.fillRect(60, 60, 75, 50);
ctx2.globalAlpha = 0.5;

ctx.beginLayer();
ctx.fillStyle = 'rgba(0, 255, 0, 1)';
ctx.fillRect(70, 70, 75, 50);
ctx2.beginLayer();
ctx2.fillStyle = 'rgba(225, 0, 0, 1)';
ctx2.fillRect(50, 50, 75, 50);

ctx.endLayer();
// Missing ctx.endLayer() here.
ctx2.beginLayer();
ctx2.fillStyle = 'rgba(0, 255, 0, 1)';
ctx2.fillRect(70, 70, 75, 50);

ctx2.endLayer();
// Missing ctx2.endLayer() here.

ctx.drawImage(canvas2, 0, 0);

const bitmap = canvas.transferToImageBitmap();
self.postMessage(bitmap, bitmap);
Expand Down
23 changes: 16 additions & 7 deletions html/canvas/offscreen/layers/2d.layer.unclosed.w.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,23 @@ <h1>2d.layer.unclosed</h1>
const canvas = new OffscreenCanvas(200, 200);
const ctx = canvas.getContext('2d');

ctx.fillStyle = 'purple';
ctx.fillRect(60, 60, 75, 50);
ctx.globalAlpha = 0.5;
// `transferToImageBitmap` is used to transfer the test result to the
// worker's parent, but `transferToImageBitmap` can't be called on canvas
// with unclosed layers. We can however draw to a separate offscreen canvas
// and write it to the main canvas using `drawImage`.
const canvas2 = new OffscreenCanvas(200, 200);
const ctx2 = canvas2.getContext('2d');

ctx.beginLayer({filter: {name: 'dropShadow', dx: -2, dy: 2}});
ctx.fillRect(40, 40, 75, 50);
ctx.fillStyle = 'grey';
ctx.fillRect(50, 50, 75, 50);
ctx2.fillStyle = 'purple';
ctx2.fillRect(60, 60, 75, 50);
ctx2.globalAlpha = 0.5;

ctx2.beginLayer({filter: {name: 'dropShadow', dx: -2, dy: 2}});
ctx2.fillRect(40, 40, 75, 50);
ctx2.fillStyle = 'grey';
ctx2.fillRect(50, 50, 75, 50);

ctx.drawImage(canvas2, 0, 0);

const bitmap = canvas.transferToImageBitmap();
self.postMessage(bitmap, bitmap);
Expand Down
110 changes: 57 additions & 53 deletions html/canvas/tools/yaml-new/layers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -312,14 +312,29 @@
desc: Check that layers are rendered even if not closed.
size: [200, 200]
code: |
ctx.fillStyle = 'purple';
ctx.fillRect(60, 60, 75, 50);
ctx.globalAlpha = 0.5;
{% set ns = namespace(ctx='ctx') %}
{% if canvas_type == 'worker' %}
// `transferToImageBitmap` is used to transfer the test result to the
// worker's parent, but `transferToImageBitmap` can't be called on canvas
// with unclosed layers. We can however draw to a separate offscreen canvas
// and write it to the main canvas using `drawImage`.
const canvas2 = new OffscreenCanvas({{ size[0] }}, {{ size[1] }});
const ctx2 = canvas2.getContext('2d');
{% set ns.ctx = 'ctx2' %}
{% endif %}

ctx.beginLayer({filter: {name: 'dropShadow', dx: -2, dy: 2}});
ctx.fillRect(40, 40, 75, 50);
ctx.fillStyle = 'grey';
ctx.fillRect(50, 50, 75, 50);
{{ ns.ctx }}.fillStyle = 'purple';
{{ ns.ctx }}.fillRect(60, 60, 75, 50);
{{ ns.ctx }}.globalAlpha = 0.5;

{{ ns.ctx }}.beginLayer({filter: {name: 'dropShadow', dx: -2, dy: 2}});
{{ ns.ctx }}.fillRect(40, 40, 75, 50);
{{ ns.ctx }}.fillStyle = 'grey';
{{ ns.ctx }}.fillRect(50, 50, 75, 50);

{% if canvas_type == 'worker' %}
ctx.drawImage(canvas2, 0, 0);
{% endif %}
reference: |
ctx.fillStyle = 'purple';
ctx.fillRect(60, 60, 75, 50);
Expand All @@ -336,20 +351,35 @@
desc: Check that layers are rendered even if not closed.
size: [200, 200]
code: |
ctx.fillStyle = 'rgba(0, 0, 255, 1)';
ctx.fillRect(60, 60, 75, 50);
ctx.globalAlpha = 0.5;
{% set ns = namespace(ctx='ctx') %}
{% if canvas_type == 'worker' %}
// `transferToImageBitmap` is used to transfer the test result to the
// worker's parent, but `transferToImageBitmap` can't be called on canvas
// with unclosed layers. We can however draw to a separate offscreen canvas
// and write it to the main canvas using `drawImage`.
const canvas2 = new OffscreenCanvas({{ size[0] }}, {{ size[1] }});
const ctx2 = canvas2.getContext('2d');
{% set ns.ctx = 'ctx2' %}
{% endif %}

ctx.beginLayer();
ctx.fillStyle = 'rgba(225, 0, 0, 1)';
ctx.fillRect(50, 50, 75, 50);
{{ ns.ctx }}.fillStyle = 'rgba(0, 0, 255, 1)';
{{ ns.ctx }}.fillRect(60, 60, 75, 50);
{{ ns.ctx }}.globalAlpha = 0.5;

ctx.beginLayer();
ctx.fillStyle = 'rgba(0, 255, 0, 1)';
ctx.fillRect(70, 70, 75, 50);
{{ ns.ctx }}.beginLayer();
{{ ns.ctx }}.fillStyle = 'rgba(225, 0, 0, 1)';
{{ ns.ctx }}.fillRect(50, 50, 75, 50);

ctx.endLayer();
// Missing ctx.endLayer() here.
{{ ns.ctx }}.beginLayer();
{{ ns.ctx }}.fillStyle = 'rgba(0, 255, 0, 1)';
{{ ns.ctx }}.fillRect(70, 70, 75, 50);

{{ ns.ctx }}.endLayer();
// Missing {{ ns.ctx }}.endLayer() here.

{% if canvas_type == 'worker' %}
ctx.drawImage(canvas2, 0, 0);
{% endif %}
reference: |
const canvas1 = document.createElement('canvas');
const ctx1 = canvas1.getContext('2d');
Expand Down Expand Up @@ -443,44 +473,18 @@
canvasType: ['HTMLCanvas']
flush_canvas: canvas.toDataURL();


- name: 2d.layer.render-opportunities.transferToImageBitmap
desc: Checks that transferToImageBitmap flushes and rebuilds the state stack.
size: [200, 200]
- name: 2d.layer.transferToImageBitmap
desc: Check that calling transferToImageBitmap in a layer throws an exception.
canvasType: ['OffscreenCanvas', 'Worker']
code: |
ctx.fillStyle = 'purple';
ctx.fillRect(60, 60, 75, 50);
ctx.globalAlpha = 0.5;

ctx.beginLayer({filter: {name: 'dropShadow', dx: -2, dy: 2}});
ctx.fillRect(40, 40, 75, 50);
ctx.fillStyle = 'grey';
ctx.fillRect(50, 50, 75, 50);

// Force a flush and restoration of the state stack.
// `transferToImageBitmap` clears the frame but preserves render states.
// `transferToImageBitmap` shouldn't throw on it's own.
canvas.transferToImageBitmap();

ctx.fillRect(70, 70, 75, 50);
ctx.fillStyle = 'orange';
ctx.fillRect(80, 80, 75, 50);
ctx.endLayer();

ctx.fillRect(80, 40, 75, 50);
reference: |
ctx.fillStyle = 'purple';
ctx.globalAlpha = 0.5;

ctx.beginLayer({filter: {name: 'dropShadow', dx: -2, dy: 2}});
ctx.fillStyle = 'grey';
ctx.fillRect(70, 70, 75, 50);
ctx.fillStyle = 'orange';
ctx.fillRect(80, 80, 75, 50);
ctx.endLayer();

ctx.fillRect(80, 40, 75, 50);

// Make sure the exception isn't caused by calling the function twice.
canvas.transferToImageBitmap();
// Calling again inside a layer should throw.
ctx.beginLayer();
assert_throws_dom("InvalidStateError",
() => canvas.transferToImageBitmap());

- name: 2d.layer.several-complex
desc: >-
Expand Down