Skip to content

Commit

Permalink
Throw exceptions for malformed operations while layers are opened
Browse files Browse the repository at this point in the history
Since layers are only filtered and composited into their parent bitmap
once the layer is closed, operations that access bitmap pixels are
malformed if there are layers open.

This can happen when reading the pixels from the canvas (for example
with `getImageData`) or directly overwriting pixels (with
`putImageData`).

With this change, exceptions are thrown for these operations when used
with open layers. Promises also fail in the case of `createImageBitmap`
and `convertToBlob`. Some APIs already had this behavior, but this CL
extends that logic to all APIs accessing bitmap pixels.

The existing tests for unclosed layers had to be moved to manual, since
for the offscreen and worker cases the generator uses methods that now
throw exceptions.

Bug: 1396372
Change-Id: I3e187c9ae4f68135219a6178adf079616c470f9b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5075139
Reviewed-by: Jean-Philippe Gravel <jpgravel@chromium.org>
Commit-Queue: Andres Ricardo Perez Rojas <andresrperez@chromium.org>
Reviewed-by: Aaron Krajeski <aaronhk@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1250893}
  • Loading branch information
AndresRPerez12 authored and chromium-wpt-export-bot committed Jan 23, 2024
1 parent c3f8abb commit 75a3cea
Show file tree
Hide file tree
Showing 57 changed files with 696 additions and 1,158 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<!DOCTYPE html>
<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
<html class="reftest-wait">
<title>Canvas test: 2d.layer.render-opportunities.toBlob</title>
<h1>2d.layer.render-opportunities.toBlob</h1>
<title>Canvas test: 2d.layer.flush-on-frame-presentation</title>
<h1>2d.layer.flush-on-frame-presentation</h1>
<p class="desc">Check that layers state stack is flushed and rebuilt on frame renders.</p>
<canvas id="canvas" width="200" height="200">
<p class="fallback">FAIL (fallback content)</p>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<!DOCTYPE html>
<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
<html class="reftest-wait">
<link rel="match" href="2d.layer.render-opportunities.requestAnimationFrame-expected.html">
<title>Canvas test: 2d.layer.render-opportunities.requestAnimationFrame</title>
<h1>2d.layer.render-opportunities.requestAnimationFrame</h1>
<link rel="match" href="2d.layer.flush-on-frame-presentation-expected.html">
<title>Canvas test: 2d.layer.flush-on-frame-presentation</title>
<h1>2d.layer.flush-on-frame-presentation</h1>
<p class="desc">Check that layers state stack is flushed and rebuilt on frame renders.</p>
<canvas id="canvas" width="200" height="200">
<p class="fallback">FAIL (fallback content)</p>
Expand Down
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>Canvas test: 2d.layer.malformed-operations-with-promises.createImageBitmap</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.malformed-operations-with-promises.createImageBitmap</h1>
<p class="desc">Check that exceptions are thrown for operations that are malformed while layers are open.</p>


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

<ul id="d"></ul>
<script>
promise_test(async t => {

var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');

// Shouldn't throw on its own.
await createImageBitmap(canvas);
// Make sure the exception isn't caused by calling the function twice.
await createImageBitmap(canvas);
// Calling again inside a layer should throw.
ctx.beginLayer();
await promise_rejects_dom(t, 'InvalidStateError', createImageBitmap(canvas));

}, "Check that exceptions are thrown for operations that are malformed while layers are open.");
</script>

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>Canvas test: 2d.layer.malformed-operations-with-promises.toBlob</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.malformed-operations-with-promises.toBlob</h1>
<p class="desc">Check that exceptions are thrown for operations that are malformed while layers are open.</p>


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

<ul id="d"></ul>
<script>
promise_test(async t => {

var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');

// Shouldn't throw on its own.
await new Promise(resolve => canvas.toBlob(resolve));
// Make sure the exception isn't caused by calling the function twice.
await new Promise(resolve => canvas.toBlob(resolve));
// Calling again inside a layer should throw.
ctx.beginLayer();
await promise_rejects_dom(t, 'InvalidStateError', new Promise(resolve => canvas.toBlob(resolve)));

}, "Check that exceptions are thrown for operations that are malformed while layers are open.");
</script>

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.malformed-operations.drawImage</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.malformed-operations.drawImage</h1>
<p class="desc">Check that exceptions are thrown for operations that are malformed while layers are open.</p>


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

<ul id="d"></ul>
<script>
var t = async_test("Check that exceptions are thrown for operations that are malformed while layers are open.");
_addTest(function(canvas, ctx) {

const canvas2 = new OffscreenCanvas(200, 200);
const ctx2 = canvas2.getContext('2d');
// Shouldn't throw on its own.
ctx2.drawImage(canvas, 0, 0);
// Make sure the exception isn't caused by calling the function twice.
ctx2.drawImage(canvas, 0, 0);
// Calling again inside a layer should throw.
ctx.beginLayer();
assert_throws_dom("InvalidStateError",
() => ctx2.drawImage(canvas, 0, 0));

});
</script>

Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<!DOCTYPE html>
<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
<title>Canvas test: 2d.layer.malformed-operations.getImageData</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.malformed-operations.getImageData</h1>
<p class="desc">Check that exceptions are thrown for operations that are malformed while layers are open.</p>


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

<ul id="d"></ul>
<script>
var t = async_test("Check that exceptions are thrown for operations that are malformed while layers are open.");
_addTest(function(canvas, ctx) {

// Shouldn't throw on its own.
ctx.getImageData(0, 0, 200, 200);
// Make sure the exception isn't caused by calling the function twice.
ctx.getImageData(0, 0, 200, 200);
// Calling again inside a layer should throw.
ctx.beginLayer();
assert_throws_dom("InvalidStateError",
() => ctx.getImageData(0, 0, 200, 200));

});
</script>

Original file line number Diff line number Diff line change
@@ -1,34 +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>
<title>Canvas test: 2d.layer.malformed-operations.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>
<h1>2d.layer.malformed-operations.putImageData</h1>
<p class="desc">Check that exceptions are thrown for operations that are malformed while layers are open.</p>


<p class="output">Actual output:</p>
<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
<canvas id="c" class="output" width="200" height="200"><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.");
var t = async_test("Check that exceptions are thrown for operations that are malformed while layers are open.");
_addTest(function(canvas, ctx) {

const canvas2 = new OffscreenCanvas(100, 50);
const canvas2 = new OffscreenCanvas(200, 200);
const ctx2 = canvas2.getContext('2d')
const data = ctx2.getImageData(0, 0, 1, 1);
// `putImageData` shouldn't throw on it's own.
// Shouldn't throw on its 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));
assert_throws_dom("InvalidStateError",
() => ctx.putImageData(data, 0, 0));

});
</script>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<!DOCTYPE html>
<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
<title>Canvas test: 2d.layer.malformed-operations.toDataURL</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.malformed-operations.toDataURL</h1>
<p class="desc">Check that exceptions are thrown for operations that are malformed while layers are open.</p>


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

<ul id="d"></ul>
<script>
var t = async_test("Check that exceptions are thrown for operations that are malformed while layers are open.");
_addTest(function(canvas, ctx) {

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

});
</script>

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Loading

0 comments on commit 75a3cea

Please sign in to comment.