<!DOCTYPE html>
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<script>
const canvasSize = 10;
assertImageEmpty = async function (dataUrl) {
const readbackCanvas = document.createElement("canvas");
const readbackCtx = readbackCanvas.getContext('2d');
const img = new Image();
img.src = dataUrl;
await img.decode();
readbackCtx.drawImage(img, 0, 0);
imageData = readbackCtx.getImageData(0, 0, canvasSize, canvasSize);
assert_array_equals(imageData.data,
new Array(canvasSize * canvasSize * 4).fill(0),
"Expected image to be empty.");
};
promise_test(async t => {
const image = new Image();
// Notice that we don't set the image.crossOrigin property.
image.src = "http://localhost:8000/security/resources/abe-allow-star.php";
await image.decode();
const canvas = document.createElement('canvas');
canvas.width = canvas.height = canvasSize;
const offscreen = canvas.transferControlToOffscreen();
const ctx = offscreen.getContext('2d');
ctx.drawImage(image, 0, 0);
// Tests that the placerholder canvas is empty until the offscreen frame
// propagates and unreadable afterward.
readbackCanvas = async (reject) => {
(async () => {
// Should either throw if the frame propagated, or be an empty image.
const dataUrl = canvas.toDataURL();
await assertImageEmpty(dataUrl);
})()
// Try again, until the frame propagates and `toDataURL` throws.
.then(() => requestAnimationFrame(() => readbackCanvas(reject)))
.catch(reject);
};
// Succeeds when `toDataURL` throws. The test will fail with a timeout if it
// never happens.
await promise_rejects_dom(t, 'SecurityError',
// Create a promise whose `reject` handler will be called asynchronously,
// now or in any future animation frames.
new Promise((_, reject) => readbackCanvas(reject)));
}, "Verify that the placeholder <canvas> associated with an OffscreenCanvas tainted with cross-origin content cannot be read once commit has propagated.");
</script>