Skip to content

Commit

Permalink
Bug 1860278 [wpt PR 42662] - Throw an exception in putImageData if ca…
Browse files Browse the repository at this point in the history
…nvas layers are opened, a=testonly

Automatic update from web-platform-tests
Throw an exception in putImageData if canvas layers are opened

This API is incompatible with how the 2D canvas is rasterized when
it contains unclosed layers. Because layers can have filters that get
applied on their final content, they can't be presented until they are
closed. Instead, we normally keep the layer content alive after a
flush, so that it can be presented in a later frame when the layer is
finally closed.

putImageData however is supposed to write to the canvas bitmap
wholesale, bypassing all render states. This means that we can't write
to the layer's content because the written pixels would then get
filtered when the layer is closed. We can't write to the main canvas
either because these pixels would later be overwritten by the layer's
result with draw calls that potentially happened before (e.g. in the
sequence `beginLayer(); fillRect(); putImageData(); endLayer();`,
`fillRect()` would write over `putImageData()`.

This behavior is part of the current 2D Canvas Layer spec draft:
Explainer: https:/fserb/canvas2D/blob/master/spec/layers.md
Spec draft: whatwg/html#9537

Change-Id: I266a3155c32919a68dbbb093e4aff9b1dd13a3b5
Bug: 1484741
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4943172
Reviewed-by: Fernando Serboncini <[email protected]>
Commit-Queue: Jean-Philippe Gravel <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1212741}

--

wpt-commits: 6e6f9fbb0746983001d7fe80ab717567c2f73bfc
wpt-pr: 42662
  • Loading branch information
graveljp authored and moz-wptsync-bot committed Oct 31, 2023
1 parent f9d40ce commit 66cd434
Show file tree
Hide file tree
Showing 9 changed files with 116 additions and 191 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<!DOCTYPE html>
<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
<title>Canvas test: 2d.layer.putImageData</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/html/canvas/resources/canvas-tests.js"></script>
<link rel="stylesheet" href="/html/canvas/resources/canvas-tests.css">
<body class="show_output">

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


<p class="output">Actual output:</p>
<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>

<ul id="d"></ul>
<script>
var t = async_test("Check that calling putImageData in a layer throws an exception.");
_addTest(function(canvas, ctx) {

const canvas2 = new OffscreenCanvas(100, 50);
const ctx2 = canvas2.getContext('2d')
const data = ctx2.getImageData(0, 0, 1, 1);
// `putImageData` shouldn't throw on it's own.
ctx.putImageData(data, 0, 0);
// Make sure the exception isn't caused by calling the function twice.
ctx.putImageData(data, 0, 0);
// Calling again inside a layer should throw.
ctx.beginLayer();
assert_throws_dom("InvalidStateError", () => ctx.putImageData(data, 0, 0));

});
</script>

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<!DOCTYPE html>
<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
<title>OffscreenCanvas test: 2d.layer.putImageData</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.putImageData</h1>
<p class="desc">Check that calling putImageData in a layer throws an exception.</p>


<script>
var t = async_test("Check that calling putImageData 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');

const canvas2 = new OffscreenCanvas(100, 50);
const ctx2 = canvas2.getContext('2d')
const data = ctx2.getImageData(0, 0, 1, 1);
// `putImageData` shouldn't throw on it's own.
ctx.putImageData(data, 0, 0);
// Make sure the exception isn't caused by calling the function twice.
ctx.putImageData(data, 0, 0);
// Calling again inside a layer should throw.
ctx.beginLayer();
assert_throws_dom("InvalidStateError", () => ctx.putImageData(data, 0, 0));
t.done();

});
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py.
// OffscreenCanvas test in a worker:2d.layer.putImageData
// Description:Check that calling putImageData 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 putImageData 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');

const canvas2 = new OffscreenCanvas(100, 50);
const ctx2 = canvas2.getContext('2d')
const data = ctx2.getImageData(0, 0, 1, 1);
// `putImageData` shouldn't throw on it's own.
ctx.putImageData(data, 0, 0);
// Make sure the exception isn't caused by calling the function twice.
ctx.putImageData(data, 0, 0);
// Calling again inside a layer should throw.
ctx.beginLayer();
assert_throws_dom("InvalidStateError", () => ctx.putImageData(data, 0, 0));
t.done();
});
done();

This file was deleted.

This file was deleted.

This file was deleted.

19 changes: 14 additions & 5 deletions testing/web-platform/tests/html/canvas/tools/yaml-new/layers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -459,11 +459,6 @@
test_type: "promise"
flush_canvas: |-
await new Promise(resolve => requestAnimationFrame(resolve));
putImageData:
flush_canvas: |-
const canvas2 = new OffscreenCanvas({{ size[0] }}, {{ size[1] }});
const ctx2 = canvas2.getContext('2d');
ctx.putImageData(ctx2.getImageData(0, 0, 1, 1), 0, 0);
toBlob:
test_type: "promise"
canvasType: ['HTMLCanvas']
Expand All @@ -473,6 +468,20 @@
canvasType: ['HTMLCanvas']
flush_canvas: canvas.toDataURL();

- name: 2d.layer.putImageData
desc: Check that calling putImageData in a layer throws an exception.
code: |
const canvas2 = new OffscreenCanvas({{ size[0] }}, {{ size[1] }});
const ctx2 = canvas2.getContext('2d')
const data = ctx2.getImageData(0, 0, 1, 1);
// `putImageData` shouldn't throw on it's own.
ctx.putImageData(data, 0, 0);
// Make sure the exception isn't caused by calling the function twice.
ctx.putImageData(data, 0, 0);
// Calling again inside a layer should throw.
ctx.beginLayer();
assert_throws_dom("InvalidStateError", () => ctx.putImageData(data, 0, 0));
- name: 2d.layer.transferToImageBitmap
desc: Check that calling transferToImageBitmap in a layer throws an exception.
canvasType: ['OffscreenCanvas', 'Worker']
Expand Down

0 comments on commit 66cd434

Please sign in to comment.