summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas')
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas-worker-font-load-crash.html19
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.constructor.html51
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.constructor.worker.js45
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.getcontext.html80
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.getcontext.worker.js77
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.resize.html240
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfer.lowlatency.nocrash.html12
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfer.to.imagebitmap.html112
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfer.to.imagebitmap.nocrash.html16
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfer.to.imagebitmap.w.html201
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfercontrol.to.offscreen.html34
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfercontrol.to.offscreen.w.html76
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transferrable.html83
-rw-r--r--testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transferrable.w.html142
14 files changed, 1188 insertions, 0 deletions
diff --git a/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas-worker-font-load-crash.html b/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas-worker-font-load-crash.html
new file mode 100644
index 0000000000..1baf7847de
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas-worker-font-load-crash.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<html class="test-wait reftest-wait">
+<script>
+ let url = URL.createObjectURL(new Blob([`
+ let font = new FontFace('Ahem', 'url(/fonts/Ahem.ttf)');
+ self.fonts.add(font);
+ let canvas = new OffscreenCanvas(100, 100);
+ let ctx = canvas.getContext('2d');
+ ctx.font = "10px Ahem";
+ ctx.fillText('Hello', 0, 10);
+ postMessage('done');
+ `], { type: "application/javascript" }));
+ var worker = new Worker(url);
+ worker.onmessage = function() {
+ worker.terminate();
+ URL.revokeObjectURL(url);
+ document.documentElement.className = "";
+ };
+</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.constructor.html b/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.constructor.html
new file mode 100644
index 0000000000..a2ad1dcc7e
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.constructor.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/html/canvas/resources/canvas-tests.js"></script>
+<link rel="help" href="https://html.spec.whatwg.org/#dom-offscreencanvas">
+<script>
+
+test(function() {
+ assert_throws_js(
+ TypeError,
+ () => OffscreenCanvas(100, 50),
+ "Calling OffscreenCanvas constructor without 'new' must throw"
+ );
+}, "OffscreenCanvas constructor called as normal function");
+
+test(function() {
+ var offscreenCanvas = new OffscreenCanvas(100, 50);
+ assert_equals(offscreenCanvas.width, 100);
+ assert_equals(offscreenCanvas.height, 50);
+
+ offscreenCanvas.width = 50;
+ offscreenCanvas.height = 100;
+ assert_equals(offscreenCanvas.width, 50);
+ assert_equals(offscreenCanvas.height, 100);
+}, "Test that calling OffscreenCanvas's constructor generates correct width and height.");
+
+test(function() {
+ var offscreenCanvas1 = new OffscreenCanvas(1, 1);
+
+ offscreenCanvas1.width = null;
+ offscreenCanvas1.height = null;
+ assert_equals(offscreenCanvas1.width, 0);
+ assert_equals(offscreenCanvas1.height, 0);
+
+ assert_throws_js(TypeError, function() { new OffscreenCanvas(-1, -1); });
+
+ var offscreenCanvas2 = new OffscreenCanvas(null, null);
+ assert_equals(offscreenCanvas2.width, 0);
+ assert_equals(offscreenCanvas2.height, 0);
+
+ assert_throws_js(TypeError, function() { offscreenCanvas2.width = -1; });
+ assert_throws_js(TypeError, function() { offscreenCanvas2.height = -1; });
+
+ var obj = {Name: "John Doe", Age: 30};
+ assert_throws_js(TypeError, function() { offscreenCanvas2.width = obj; });
+ assert_throws_js(TypeError, function() { offscreenCanvas2.height = obj; });
+ assert_throws_js(TypeError, function() { new OffscreenCanvas(obj, obj); });
+}, "Test that OffscreenCanvas constructor handles invalid arguments correctly");
+
+</script>
+
diff --git a/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.constructor.worker.js b/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.constructor.worker.js
new file mode 100644
index 0000000000..72cfb728f0
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.constructor.worker.js
@@ -0,0 +1,45 @@
+// spec link: https://html.spec.whatwg.org/#dom-offscreencanvas
+
+importScripts("/resources/testharness.js");
+importScripts("/html/canvas/resources/canvas-tests.js");
+
+var t1 = async_test("Test that calling OffscreenCanvas's constructor generates correct width and height.");
+t1.step(function() {
+ var offscreenCanvas = new OffscreenCanvas(100, 50);
+ assert_equals(offscreenCanvas.width, 100);
+ assert_equals(offscreenCanvas.height, 50);
+
+ offscreenCanvas.width = 50;
+ offscreenCanvas.height = 100;
+ assert_equals(offscreenCanvas.width, 50);
+ assert_equals(offscreenCanvas.height, 100);
+ t1.done();
+});
+
+var t2 = async_test("Test that OffscreenCanvas constructor handles invalid arguments correctly in a worker");
+t2.step(function() {
+ var offscreenCanvas1 = new OffscreenCanvas(1, 1);
+
+ offscreenCanvas1.width = null;
+ offscreenCanvas1.height = null;
+ assert_equals(offscreenCanvas1.width, 0);
+ assert_equals(offscreenCanvas1.height, 0);
+
+ assert_throws_js(TypeError, function() { new OffscreenCanvas(-1, -1); });
+
+ var offscreenCanvas2 = new OffscreenCanvas(null, null);
+ assert_equals(offscreenCanvas2.width, 0);
+ assert_equals(offscreenCanvas2.height, 0);
+
+ assert_throws_js(TypeError, function() { offscreenCanvas2.width = -1; });
+ assert_throws_js(TypeError, function() { offscreenCanvas2.height = -1; });
+
+ var obj = {Name: "John Doe", Age: 30};
+ assert_throws_js(TypeError, function() { offscreenCanvas2.width = obj; });
+ assert_throws_js(TypeError, function() { offscreenCanvas2.height = obj; });
+ assert_throws_js(TypeError, function() { new OffscreenCanvas(obj, obj); });
+ t2.done();
+});
+
+done();
+
diff --git a/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.getcontext.html b/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.getcontext.html
new file mode 100644
index 0000000000..51c167ddca
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.getcontext.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/html/canvas/resources/canvas-tests.js"></script>
+<link rel="help" href="https://html.spec.whatwg.org/#dom-offscreencanvas-getcontext">
+<script>
+
+test(function() {
+ var offscreenCanvas = new OffscreenCanvas(1, 1);
+ assert_throws_js(TypeError, function() { offscreenCanvas.getContext('3d'); });
+}, "Test that getContext with un-supported string throws a TypeError.");
+
+test(function() {
+ var offscreenCanvas1 = new OffscreenCanvas(1, 1);
+ var ctx1 = offscreenCanvas1.getContext('2d');
+ assert_true(ctx1 instanceof OffscreenCanvasRenderingContext2D);
+
+ var offscreenCanvas2 = new OffscreenCanvas(1, 1);
+ var ctx2 = offscreenCanvas2.getContext('webgl');
+ assert_true(ctx2 instanceof WebGLRenderingContext);
+
+ var offscreenCanvas3 = new OffscreenCanvas(1, 1);
+ var ctx3 = offscreenCanvas3.getContext('webgl2');
+ assert_true(ctx3 instanceof WebGL2RenderingContext);
+}, "Test that getContext with supported string returns correct results");
+
+test(function() {
+ var offscreenCanvas1 = new OffscreenCanvas(1, 1);
+ var ctx1 = offscreenCanvas1.getContext('2d');
+ var ctx2 = offscreenCanvas1.getContext('webgl');
+ assert_equals(ctx2, null);
+
+ var offscreenCanvas2 = new OffscreenCanvas(1, 1);
+ var ctx3 = offscreenCanvas2.getContext('webgl');
+ var ctx4 = offscreenCanvas2.getContext('2d');
+ assert_equals(ctx4, null);
+}, "Test that getContext twice with different context type returns null the second time");
+
+test(function() {
+ var offscreenCanvas = new OffscreenCanvas(1, 2);
+ var ctx = offscreenCanvas.getContext('2d');
+ var dstCanvas = ctx.canvas;
+ assert_equals(dstCanvas.width, 1);
+ assert_equals(dstCanvas.height, 2);
+}, "Test that 2dcontext.canvas should return the original OffscreenCanvas");
+
+test(function() {
+ var offscreenCanvas = new OffscreenCanvas(1, 2);
+ var ctx = offscreenCanvas.getContext('webgl');
+ var dstCanvas = ctx.canvas;
+ assert_equals(dstCanvas.width, 1);
+ assert_equals(dstCanvas.height, 2);
+}, "Test that webglcontext.canvas should return the original OffscreenCanvas");
+
+test(function() {
+ var offscreenCanvas = new OffscreenCanvas(10, 10);
+ var ctx = offscreenCanvas.getContext('2d', {alpha: false});
+ ctx.fillStyle = 'rgba(0, 255, 0, 0.5)';
+ ctx.fillRect(0, 0, 10, 10);
+ _assertPixelApprox(offscreenCanvas, 5,5, 0,127,0,255, 2);
+}, "Test that OffscreenCanvasRenderingContext2D with alpha disabled makes the OffscreenCanvas opaque");
+
+test(function() {
+ var offscreenCanvas = new OffscreenCanvas(10, 10);
+ var ctx = offscreenCanvas.getContext('2d', {alpha: true});
+ ctx.fillStyle = 'rgba(0, 255, 0, 0.5)';
+ ctx.fillRect(0, 0, 10, 10);
+ _assertPixelApprox(offscreenCanvas, 5,5, 0,255,0,127, 2);
+}, "Test that OffscreenCanvasRenderingContext2D with alpha enabled preserves the alpha");
+
+test(function() {
+ var offscreenCanvas = new OffscreenCanvas(10, 10);
+ var ctx = offscreenCanvas.getContext('2d');
+ ctx.fillStyle = 'rgba(0, 255, 0, 0.5)';
+ ctx.fillRect(0, 0, 10, 10);
+ _assertPixelApprox(offscreenCanvas, 5,5, 0,255,0,127, 2);
+}, "Test that 'alpha' context creation attribute is true by default");
+
+</script>
+
diff --git a/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.getcontext.worker.js b/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.getcontext.worker.js
new file mode 100644
index 0000000000..c413791f61
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.getcontext.worker.js
@@ -0,0 +1,77 @@
+// spec link: https://html.spec.whatwg.org/#dom-offscreencanvas-getcontext
+
+importScripts("/resources/testharness.js");
+importScripts("/html/canvas/resources/canvas-tests.js");
+
+test(function() {
+ var offscreenCanvas = new OffscreenCanvas(1, 1);
+ assert_throws_js(TypeError, function() { offscreenCanvas.getContext('3d'); });
+}, "Test that getContext with un-supported string throws a TypeError.");
+
+test(function() {
+ var offscreenCanvas1 = new OffscreenCanvas(1, 1);
+ var ctx1 = offscreenCanvas1.getContext('2d');
+ assert_true(ctx1 instanceof OffscreenCanvasRenderingContext2D);
+
+ var offscreenCanvas2 = new OffscreenCanvas(1, 1);
+ var ctx2 = offscreenCanvas2.getContext('webgl');
+ assert_true(ctx2 instanceof WebGLRenderingContext);
+
+ var offscreenCanvas3 = new OffscreenCanvas(1, 1);
+ var ctx3 = offscreenCanvas3.getContext('webgl2');
+ assert_true(ctx3 instanceof WebGL2RenderingContext);
+}, "Test that getContext with supported string returns correct results");
+
+test(function() {
+ var offscreenCanvas1 = new OffscreenCanvas(1, 1);
+ var ctx1 = offscreenCanvas1.getContext('2d');
+ var ctx2 = offscreenCanvas1.getContext('webgl');
+ assert_equals(ctx2, null);
+
+ var offscreenCanvas2 = new OffscreenCanvas(1, 1);
+ var ctx3 = offscreenCanvas2.getContext('webgl');
+ var ctx4 = offscreenCanvas2.getContext('2d');
+ assert_equals(ctx4, null);
+}, "Test that getContext twice with different context type returns null the second time");
+
+test(function() {
+ var offscreenCanvas = new OffscreenCanvas(1, 2);
+ var ctx = offscreenCanvas.getContext('2d');
+ var dstCanvas = ctx.canvas;
+ assert_equals(dstCanvas.width, 1);
+ assert_equals(dstCanvas.height, 2);
+}, "Test that 2dcontext.canvas should return the original OffscreenCanvas");
+
+test(function() {
+ var offscreenCanvas = new OffscreenCanvas(1, 2);
+ var ctx = offscreenCanvas.getContext('webgl');
+ var dstCanvas = ctx.canvas;
+ assert_equals(dstCanvas.width, 1);
+ assert_equals(dstCanvas.height, 2);
+}, "Test that webglcontext.canvas should return the original OffscreenCanvas");
+
+test(function() {
+ var offscreenCanvas = new OffscreenCanvas(10, 10);
+ var ctx = offscreenCanvas.getContext('2d', {alpha: false});
+ ctx.fillStyle = 'rgba(0, 255, 0, 0.5)';
+ ctx.fillRect(0, 0, 10, 10);
+ _assertPixelApprox(offscreenCanvas, 5,5, 0,127,0,255, 2);
+}, "Test that OffscreenCanvasRenderingContext2D with alpha disabled makes the OffscreenCanvas opaque");
+
+test(function() {
+ var offscreenCanvas = new OffscreenCanvas(10, 10);
+ var ctx = offscreenCanvas.getContext('2d', {alpha: true});
+ ctx.fillStyle = 'rgba(0, 255, 0, 0.5)';
+ ctx.fillRect(0, 0, 10, 10);
+ _assertPixelApprox(offscreenCanvas, 5,5, 0,255,0,127, 2);
+}, "Test that OffscreenCanvasRenderingContext2D with alpha enabled preserves the alpha");
+
+test(function() {
+ var offscreenCanvas = new OffscreenCanvas(10, 10);
+ var ctx = offscreenCanvas.getContext('2d');
+ ctx.fillStyle = 'rgba(0, 255, 0, 0.5)';
+ ctx.fillRect(0, 0, 10, 10);
+ _assertPixelApprox(offscreenCanvas, 5,5, 0,255,0,127, 2);
+}, "Test that 'alpha' context creation attribute is true by default");
+
+done();
diff --git a/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.resize.html b/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.resize.html
new file mode 100644
index 0000000000..3ff0eea153
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.resize.html
@@ -0,0 +1,240 @@
+<!DOCTYPE html>
+<title>Test resizing an OffscreenCanvas with a 2d context</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/html/canvas/resources/canvas-tests.js"></script>
+<body></body>
+<script>
+test(function() {
+ var canvas = new OffscreenCanvas(10, 20);
+ canvas.width = 30;
+ canvas.height = 40;
+ assert_equals(canvas.width, 30);
+ assert_equals(canvas.height, 40);
+}, "Verify that writing to the width and height attributes of an OffscreenCanvas works when there is no context attached.");
+
+test(function() {
+ var canvas = new OffscreenCanvas(10, 20);
+ canvas.getContext('2d');
+ canvas.width = 30;
+ canvas.height = 40;
+ assert_equals(canvas.width, 30);
+ assert_equals(canvas.height, 40);
+ var image = canvas.transferToImageBitmap();
+ assert_equals(image.width, 30);
+ assert_equals(image.height, 40);
+}, "Verify that writing to the width and height attributes of an OffscreenCanvas works when there is a 2d context attached.");
+
+test(function() {
+ var canvas = new OffscreenCanvas(10, 20);
+ canvas.getContext('webgl');
+ canvas.width = 30;
+ canvas.height = 40;
+ assert_equals(canvas.width, 30);
+ assert_equals(canvas.height, 40);
+ var image = canvas.transferToImageBitmap();
+ assert_equals(image.width, 30);
+ assert_equals(image.height, 40);
+}, "Verify that writing to the width and height attributes of an OffscreenCanvas works when there is a webgl context attached.");
+
+test(function() {
+ var placeholder = document.createElement('canvas');
+ placeholder.width = 2;
+ placeholder.height = 2;
+ var offscreen = placeholder.transferControlToOffscreen();
+ assert_throws_dom("InvalidStateError", () => { placeholder.width = 1; });
+ assert_throws_dom("InvalidStateError", () => { placeholder.height = 1; });
+}, "Verify that writing to the width or height attribute of a placeholder canvas throws an exception");
+
+test(function() {
+ var placeholder = document.createElement('canvas');
+ placeholder.width = 1;
+ placeholder.height = 1;
+ var offscreen = placeholder.transferControlToOffscreen();
+ assert_throws_dom("InvalidStateError", () => { placeholder.width = 1; });
+ assert_throws_dom("InvalidStateError", () => { placeholder.height = 1; });
+}, "Verify that writing to the width or height attribute of a placeholder canvas throws an exception even when not changing the value of the attribute.");
+
+test(function() {
+ var canvas = new OffscreenCanvas(10, 20);
+ var ctx = canvas.getContext('2d');
+ ctx.lineWidth = 5;
+ canvas.width = 30;
+ assert_equals(ctx.lineWidth, 1);
+ ctx.lineWidth = 5;
+ canvas.height = 40;
+ assert_equals(ctx.lineWidth, 1);
+}, "Verify that resizing a 2d context resets its state.");
+
+test(function() {
+ var canvas = new OffscreenCanvas(10, 20);
+ var ctx = canvas.getContext('2d');
+ ctx.lineWidth = 5;
+ canvas.width = canvas.width;
+ assert_equals(ctx.lineWidth, 1);
+ ctx.lineWidth = 5;
+ canvas.height = canvas.height;
+ assert_equals(ctx.lineWidth, 1);
+}, "Verify that setting the size of a 2d context to the same size it already had resets its state.");
+
+async_test(function(t) {
+ var placeholder = document.createElement('canvas');
+ document.body.appendChild(placeholder); // So that we can check computed style/
+ placeholder.width = 10;
+ placeholder.height = 20;
+ var offscreen = placeholder.transferControlToOffscreen();
+ var ctx = offscreen.getContext('2d');
+ t.step(function() {
+ // Verify that setting the size of an OffscreenCanvas that has a placeholder works.
+ offscreen.width = 30;
+ offscreen.height = 40;
+ assert_equals(offscreen.width, 30);
+ assert_equals(offscreen.height, 40);
+ var image = offscreen.transferToImageBitmap();
+ assert_equals(image.width, 30);
+ assert_equals(image.height, 40);
+ });
+ t.step(function() {
+ // Verify that setting the size of an OffscreenCanvas does not directly update the size of its placeholder canvas.
+ assert_equals(placeholder.width, 10);
+ assert_equals(placeholder.height, 20);
+ });
+ var asyncStepsCompleted = 0;
+ createImageBitmap(placeholder).then(image => {
+ t.step(function() {
+ // Verify that the placeholder was not updated synchronously.
+ assert_equals(image.width, 10);
+ assert_equals(image.height, 20);
+ });
+ asyncStepsCompleted = asyncStepsCompleted + 1;
+ if (asyncStepsCompleted == 2) {
+ t.done();
+ }
+ });
+
+ function testImage() {
+ if (placeholder.width != 30) {
+ requestAnimationFrame(testImage);
+ } else {
+ t.step(function() {
+ assert_equals(placeholder.width, 30);
+ assert_equals(placeholder.height, 40);
+ var computedStyle = window.getComputedStyle(placeholder);
+ assert_equals(computedStyle.getPropertyValue('width'), "30px");
+ assert_equals(computedStyle.getPropertyValue('height'), "40px");
+ });
+ createImageBitmap(placeholder).then(image => {
+ t.step(function() {
+ // Verify that an image grabbed from the placeholder has the correct dimensions
+ assert_equals(image.width, 30);
+ assert_equals(image.height, 40);
+ });
+ asyncStepsCompleted = asyncStepsCompleted + 1;
+ if (asyncStepsCompleted == 2) {
+ t.done();
+ }
+ });
+ }
+ }
+
+ requestAnimationFrame(testImage);
+}, "Verify that resizing an OffscreenCanvas with a 2d context propagates the new size to its placeholder canvas asynchronously.");
+
+async_test(function(t) {
+ var placeholder = document.createElement('canvas');
+ document.body.appendChild(placeholder); // So that we can check computed style/
+ placeholder.width = 10;
+ placeholder.height = 20;
+ var offscreen = placeholder.transferControlToOffscreen();
+ var ctx = offscreen.getContext('webgl');
+ t.step(function() {
+ // Verify that setting the size of an OffscreenCanvas that has a placeholder works.
+ offscreen.width = 30;
+ offscreen.height = 40;
+ assert_equals(offscreen.width, 30);
+ assert_equals(offscreen.height, 40);
+ var image = offscreen.transferToImageBitmap();
+ assert_equals(image.width, 30);
+ assert_equals(image.height, 40);
+ });
+ t.step(function() {
+ // Verify that setting the size of an OffscreenCanvas does not directly update the size of its placeholder canvas.
+ assert_equals(placeholder.width, 10);
+ assert_equals(placeholder.height, 20);
+ });
+ var asyncStepsCompleted = 0;
+ createImageBitmap(placeholder).then(image => {
+ t.step(function() {
+ // Verify that the placeholder was not updated synchronously.
+ assert_equals(image.width, 10);
+ assert_equals(image.height, 20);
+ });
+ asyncStepsCompleted = asyncStepsCompleted + 1;
+ if (asyncStepsCompleted == 2) {
+ t.done();
+ }
+ });
+
+ function testImage() {
+ if (placeholder.width != 30) {
+ requestAnimationFrame(testImage);
+ } else {
+ t.step(function() {
+ assert_equals(placeholder.width, 30);
+ assert_equals(placeholder.height, 40);
+ var computedStyle = window.getComputedStyle(placeholder);
+ assert_equals(computedStyle.getPropertyValue('width'), "30px");
+ assert_equals(computedStyle.getPropertyValue('height'), "40px");
+ });
+ createImageBitmap(placeholder).then(image => {
+ t.step(function() {
+ // Verify that an image grabbed from the placeholder has the correct dimensions
+ assert_equals(image.width, 30);
+ assert_equals(image.height, 40);
+ });
+ asyncStepsCompleted = asyncStepsCompleted + 1;
+ if (asyncStepsCompleted == 2) {
+ t.done();
+ }
+ });
+ }
+ }
+ requestAnimationFrame(testImage);
+}, "Verify that resizing an OffscreenCanvas with a webgl context propagates the new size to its placeholder canvas asynchronously.");
+
+async_test(function(t){
+ var placeholder = document.createElement('canvas');
+ placeholder.width = 1;
+ placeholder.height = 1;
+ var offscreen = placeholder.transferControlToOffscreen();
+ var ctx = offscreen.getContext('2d');
+ offscreen.width = offscreen.height = 10;
+ ctx.fillStyle = '#0f0';
+ ctx.fillRect(0, 0, 10, 10);
+
+ var testCanvas = document.createElement('canvas');
+ testCanvas.width = testCanvas.height = 20;
+ var testCtx = testCanvas.getContext('2d');
+
+ function testImage() {
+ if (placeholder.width != 10) {
+ requestAnimationFrame(testImage);
+ } else {
+ testCtx.drawImage(placeholder, 0, 0);
+ var pixel1 = testCtx.getImageData(9, 9, 1, 1).data;
+ var pixel2 = testCtx.getImageData(9, 10, 1, 1).data;
+ var pixel3 = testCtx.getImageData(10, 9, 1, 1).data;
+ t.step(function() {
+ assert_equals(placeholder.width, 10);
+ assert_equals(placeholder.height, 10);
+ assert_array_equals(pixel1, [0, 255, 0, 255]);
+ assert_array_equals(pixel2, [0, 0, 0, 0]);
+ assert_array_equals(pixel3, [0, 0, 0, 0]);
+ });
+ t.done();
+ }
+ }
+
+ requestAnimationFrame(testImage);
+}, "Verify that drawImage uses the size of the frame as the intinsic size of a placeholder canvas.");
+</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfer.lowlatency.nocrash.html b/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfer.lowlatency.nocrash.html
new file mode 100644
index 0000000000..1960841564
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfer.lowlatency.nocrash.html
@@ -0,0 +1,12 @@
+<title>Transfer Low-Latency Canvas</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/html/canvas/resources/canvas-tests.js"></script>
+<body></body>
+
+<script>
+test(function(t) {
+ var ctx = document.createElement("canvas").getContext('2d', {desynchronized:true});
+ assert_throws_dom("InvalidStateError", () => { ctx.canvas.transferControlToOffscreen(); });
+}, "Tests that transferring a low latency canvas does not cause a crash. See crbug.com/1255153");
+</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfer.to.imagebitmap.html b/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfer.to.imagebitmap.html
new file mode 100644
index 0000000000..6e1adf9591
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfer.to.imagebitmap.html
@@ -0,0 +1,112 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/html/canvas/resources/canvas-tests.js"></script>
+<link rel="help" href="https://html.spec.whatwg.org/#dom-offscreencanvas-transfertoimagebitmap">
+
+<script id="myWorker" type="text/worker">
+
+self.onmessage = function(e) {
+};
+
+</script>
+
+<script>
+function makeWorker(script)
+{
+ var blob = new Blob([script]);
+ return new Worker(URL.createObjectURL(blob));
+}
+
+test(function() {
+ function testSize(contextType) {
+ var offscreenCanvas = new OffscreenCanvas(100, 50);
+ var ctx = offscreenCanvas.getContext(contextType);
+ var image = offscreenCanvas.transferToImageBitmap();
+ assert_equals(image.width, 100);
+ assert_equals(image.height, 50);
+ }
+
+ testSize('2d');
+ testSize('webgl');
+}, "Test that transferToImageBitmap returns an ImageBitmap with correct width and height");
+
+test(function() {
+ function testImageBitmapClr(shouldCallTwice, alphaVal) {
+ var offscreenCanvas = new OffscreenCanvas(100, 50);
+ var ctx = offscreenCanvas.getContext('2d', {alpha: alphaVal});
+ ctx.fillStyle = "#0f0";
+ ctx.fillRect(0, 0, 100, 50);
+ var image = offscreenCanvas.transferToImageBitmap();
+
+ if (shouldCallTwice)
+ image = offscreenCanvas.transferToImageBitmap();
+
+ var drawCanvas = document.createElement('canvas');
+ drawCanvas.width = 100;
+ drawCanvas.height = 50;
+ var dCtx = drawCanvas.getContext('2d');
+ dCtx.drawImage(image, 0, 0);
+
+ if (shouldCallTwice) {
+ if (alphaVal)
+ _assertPixel(drawCanvas, 50,25, 0,0,0,0);
+ else
+ _assertPixel(drawCanvas, 50,25, 0,0,0,255);
+ } else {
+ _assertPixel(drawCanvas, 50,25, 0,255,0,255);
+ }
+ }
+
+ testImageBitmapClr(false, true);
+ testImageBitmapClr(true, true);
+ testImageBitmapClr(true, false);
+}, "Test that transferToImageBitmap returns an ImageBitmap with correct color");
+
+test(function() {
+ var offscreenCanvas = new OffscreenCanvas(100, 50);
+ var ctx = offscreenCanvas.getContext('2d');
+ ctx.lineWidth = 10;
+ var image = offscreenCanvas.transferToImageBitmap();
+ assert_equals(ctx.lineWidth, 10);
+}, "Test that transferToImageBitmap won't change context's property");
+
+test(function() {
+ var offscreenCanvas = new OffscreenCanvas(100, 50);
+ var ctx = offscreenCanvas.getContext('2d');
+ ctx.rect(0, 0, 25, 50);
+ ctx.clip();
+ ctx.translate(20, 20);
+
+ ctx.fillStyle = '#0f0';
+ var image1 = offscreenCanvas.transferToImageBitmap();
+ // trasnform should be preserved
+ ctx.fillRect(0, 0, 10, 10);
+ var image2 = offscreenCanvas.transferToImageBitmap();
+
+ var drawCanvas = document.createElement('canvas');
+ drawCanvas.width = 100;
+ drawCanvas.height = 50;
+ var dCtx = drawCanvas.getContext('2d');
+ dCtx.drawImage(image2, 0, 0);
+ // Verify that transform was carried over.
+ _assertPixel(drawCanvas, 23,25, 0,255,0,255);
+ // Verify that clip was carried over.
+ _assertPixel(drawCanvas, 27,25, 0,0,0,0);
+}, "Test that transferToImageBitmap preserves transform");
+
+async_test(function(t) {
+ var worker = makeWorker(document.getElementById("myWorker").textContent);
+ var offscreenCanvas = new OffscreenCanvas(10, 10);
+ worker.postMessage(offscreenCanvas, [offscreenCanvas]);
+ assert_throws_dom("InvalidStateError", function() { offscreenCanvas.transferToImageBitmap(); });
+ t.done();
+}, "Test that call transferToImageBitmap on a detached OffscreenCanvas throws an exception");
+
+test(function() {
+ var offscreenCanvas = new OffscreenCanvas(10, 10);
+ assert_throws_dom("InvalidStateError", function() { offscreenCanvas.transferToImageBitmap(); });
+}, "Test that transferToImageBitmap without a context throws an exception");
+
+</script>
+
diff --git a/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfer.to.imagebitmap.nocrash.html b/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfer.to.imagebitmap.nocrash.html
new file mode 100644
index 0000000000..09a388ed35
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfer.to.imagebitmap.nocrash.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<body>
+ <p>Tests that an ImageBitmap in Offscreen without content does not crash.</p>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+async_test(function(t) {
+ var v1 = document.createElement("canvas");
+ var v2 = v1.transferControlToOffscreen();
+ var v3 = v2.getContext("bitmaprenderer");
+ v2.width = 67;
+ t.done();
+});
+</script>
diff --git a/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfer.to.imagebitmap.w.html b/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfer.to.imagebitmap.w.html
new file mode 100644
index 0000000000..b51ce0efa2
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfer.to.imagebitmap.w.html
@@ -0,0 +1,201 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/html/canvas/resources/canvas-tests.js"></script>
+<link rel="help" href="https://html.spec.whatwg.org/#dom-offscreencanvas-transfertoimagebitmap">
+
+<script id="myWorker" type="text/worker">
+
+function testSize(contextType)
+{
+ var offscreenCanvas = new OffscreenCanvas(100, 50);
+ var ctx = offscreenCanvas.getContext(contextType);
+ var image = offscreenCanvas.transferToImageBitmap();
+ if (image.width == 100 && image.height == 50)
+ return true;
+ return false;
+}
+
+function testImageBitmapClr(shouldCallTwice, alphaVal) {
+ var offscreenCanvas = new OffscreenCanvas(100, 50);
+ var ctx = offscreenCanvas.getContext('2d', {alpha: alphaVal});
+ ctx.fillStyle = "#0f0";
+ ctx.fillRect(0, 0, 100, 50);
+ var image = offscreenCanvas.transferToImageBitmap();
+
+ if (shouldCallTwice)
+ image = offscreenCanvas.transferToImageBitmap();
+ return image;
+}
+
+function isInvalidStateError(funcStr, offscreenCanvas)
+{
+ try {
+ eval(funcStr);
+ } catch (e) {
+ if (e instanceof DOMException && e.name == "InvalidStateError")
+ return true;
+ return false;
+ }
+}
+
+function testImageBitmapSize()
+{
+ return testSize('2d') && testSize('webgl');
+}
+
+function testLineWidthNotAltered()
+{
+ var offscreenCanvas = new OffscreenCanvas(100, 50);
+ var ctx = offscreenCanvas.getContext('2d');
+ ctx.lineWidth = 10;
+ var image = offscreenCanvas.transferToImageBitmap();
+ return ctx.lineWidth == 10;
+}
+
+function testTransformPreserved()
+{
+ var offscreenCanvas = new OffscreenCanvas(100, 50);
+ var ctx = offscreenCanvas.getContext('2d');
+ ctx.rect(0, 0, 25, 50);
+ ctx.clip();
+ ctx.translate(20, 20);
+
+ ctx.fillStyle = '#0f0';
+ var image1 = offscreenCanvas.transferToImageBitmap();
+ // trasnform should be preserved
+ ctx.fillRect(0, 0, 10, 10);
+ var image2 = offscreenCanvas.transferToImageBitmap();
+ return image2;
+}
+
+function testException()
+{
+ var offscreenCanvas = new OffscreenCanvas(10, 10);
+ return isInvalidStateError("offscreenCanvas.transferToImageBitmap()", offscreenCanvas);
+}
+
+self.onmessage = function(e) {
+ switch (e.data) {
+ case 'test1':
+ self.postMessage(testImageBitmapSize());
+ break;
+ case 'test2':
+ self.postMessage(testImageBitmapClr(false, true));
+ break;
+ case 'test3':
+ self.postMessage(testImageBitmapClr(true, true));
+ break;
+ case 'test4':
+ self.postMessage(testImageBitmapClr(true, false));
+ break;
+ case 'test5':
+ self.postMessage(testLineWidthNotAltered());
+ break;
+ case 'test6':
+ self.postMessage(testTransformPreserved());
+ break;
+ case 'test7':
+ var offscreenCanvas = new OffscreenCanvas(10, 10);
+ self.postMessage({offscreenCanvas: offscreenCanvas}, [offscreenCanvas]);
+ self.postMessage(isInvalidStateError("offscreenCanvas.transferToImageBitmap()", offscreenCanvas));
+ break;
+ case 'test8':
+ self.postMessage(testException());
+ break;
+ }
+};
+
+</script>
+
+<script>
+function makeWorker(test) {
+ var blob = new Blob([document.getElementById("myWorker").textContent]);
+ var worker = new Worker(URL.createObjectURL(blob));
+ worker.onerror = test.unreached_func("error");
+ return worker;
+}
+
+function drawImageBitmap(image, x, y)
+{
+ var drawCanvas = document.createElement('canvas');
+ drawCanvas.width = 100;
+ drawCanvas.height = 50;
+ var dCtx = drawCanvas.getContext('2d');
+ dCtx.drawImage(image, 0, 0);
+ return dCtx.getImageData(x, y, 1, 1).data;
+}
+
+async_test(function(t) {
+ var worker = makeWorker(t);
+ worker.addEventListener('message', t.step_func_done(function(msg) {
+ assert_true(msg.data);
+ }));
+ worker.postMessage('test1');
+}, "Test that transferToImageBitmap returns an ImageBitmap with correct width and height in a worker");
+
+async_test(function(t) {
+ var worker = makeWorker(t);
+ worker.addEventListener('message', t.step_func_done(function(msg) {
+ var clr = drawImageBitmap(msg.data, 50, 25);
+ assert_array_equals(clr, [0, 255, 0, 255]);
+ }));
+ worker.postMessage('test2');
+}, "Test that transferToImageBitmap returns an ImageBitmap with correct color in a worker");
+
+async_test(function(t) {
+ var worker = makeWorker(t);
+ worker.addEventListener('message', t.step_func_done(function(msg) {
+ var clr = drawImageBitmap(msg.data, 50, 25);
+ assert_array_equals(clr, [0, 0, 0, 0]);
+ }));
+ worker.postMessage('test3');
+}, "Test that call transferToImageBitmap twice returns an ImageBitmap with correct color in a worker");
+
+async_test(function(t) {
+ var worker = makeWorker(t);
+ worker.addEventListener('message', t.step_func_done(function(msg) {
+ var clr = drawImageBitmap(msg.data, 50, 25);
+ assert_array_equals(clr, [0, 0, 0, 255]);
+ }));
+ worker.postMessage('test4');
+}, "Test that call transferToImageBitmap twice on a alpha-disabled context returns an ImageBitmap with correct color in a worker");
+
+async_test(function(t) {
+ var worker = makeWorker(t);
+ worker.addEventListener('message', t.step_func_done(function(msg) {
+ assert_true(msg.data);
+ }));
+ worker.postMessage('test5');
+}, "Test that transferToImageBitmap won't change context's property in a worker");
+
+async_test(function(t) {
+ var worker = makeWorker(t);
+ worker.addEventListener('message', t.step_func_done(function(msg) {
+ var clr1 = drawImageBitmap(msg.data, 23, 25);
+ assert_array_equals(clr1, [0, 255, 0, 255]);
+ var clr2 = drawImageBitmap(msg.data, 27, 25);
+ assert_array_equals(clr2, [0, 0, 0, 0]);
+ }));
+ worker.postMessage('test6');
+}, "Test that call transferToImageBitmap preserves transform in a worker");
+
+async_test(function(t) {
+ var worker = makeWorker(t);
+ worker.addEventListener('message', t.step_func_done(function(msg) {
+ if (msg.data == true || msg.data == false)
+ assert_true(msg.data);
+ }));
+ worker.postMessage('test7');
+}, "Test that call transferToImageBitmap on a detached OffscreenCanvas throws an exception in a worker");
+
+async_test(function(t) {
+ var worker = makeWorker(t);
+ worker.addEventListener('message', t.step_func_done(function(msg) {
+ assert_true(msg.data);
+ }));
+ worker.postMessage('test8');
+}, "Test that call transferToImageBitmap without a context throws an exception in a worker");
+
+</script>
+
diff --git a/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfercontrol.to.offscreen.html b/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfercontrol.to.offscreen.html
new file mode 100644
index 0000000000..fea375b2ad
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfercontrol.to.offscreen.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/html/canvas/resources/canvas-tests.js"></script>
+<link rel="help" href="https://html.spec.whatwg.org/#dom-canvas-transfercontroltooffscreen">
+<script>
+
+test(function() {
+ var placeholder = document.createElement('canvas');
+ placeholder.width = 100;
+ placeholder.height = 50;
+ var offscreenCanvas = placeholder.transferControlToOffscreen();
+ assert_equals(offscreenCanvas.width, 100);
+ assert_equals(offscreenCanvas.height, 50);
+}, "Test that an OffscreenCanvas generated by transferControlToOffscreen gets correct width and height");
+
+test(function() {
+ var placeholder = document.createElement('canvas');
+ placeholder.width = 100;
+ placeholder.height = 50;
+ var offscreenCanvas = placeholder.transferControlToOffscreen();
+ assert_throws_dom("InvalidStateError", function() { placeholder.getContext('2d'); });
+}, "Test that calling getContext on a placeholder canvas that has already transferred its control throws an exception");
+
+test(function() {
+ var placeholder = document.createElement('canvas');
+ placeholder.width = 100;
+ placeholder.height = 50;
+ var offscreenCanvas = placeholder.transferControlToOffscreen();
+ assert_throws_dom("InvalidStateError", function() { placeholder.transferControlToOffscreen(); });
+}, "Test that calling transferControlToOffscreen twice throws an exception");
+
+</script>
+
diff --git a/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfercontrol.to.offscreen.w.html b/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfercontrol.to.offscreen.w.html
new file mode 100644
index 0000000000..1347e7b50b
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfercontrol.to.offscreen.w.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/html/canvas/resources/canvas-tests.js"></script>
+<link rel="help" href="https://html.spec.whatwg.org/#dom-canvas-transfercontroltooffscreen">
+
+<script id="myWorker" type="text/worker">
+
+function testSize(offscreenCanvas)
+{
+ if (offscreenCanvas.width == 100 && offscreenCanvas.height == 50)
+ return true;
+ return false;
+}
+
+self.onmessage = function(e) {
+ switch (e.data.msg) {
+ case 'test1':
+ self.postMessage(testSize(e.data.data));
+ break;
+ case 'test2':
+ self.postMessage("");
+ break;
+ case 'test3':
+ self.postMessage("");
+ break;
+ }
+};
+
+</script>
+
+<script>
+function makeWorker(script)
+{
+ var blob = new Blob([script]);
+ return new Worker(URL.createObjectURL(blob));
+}
+
+async_test(function(t) {
+ var placeholder = document.createElement('canvas');
+ placeholder.width = 100;
+ placeholder.height = 50;
+ var offscreenCanvas = placeholder.transferControlToOffscreen();
+ var worker = makeWorker(document.getElementById("myWorker").textContent);
+ worker.addEventListener('message', t.step_func_done(function(msg) {
+ assert_true(msg.data);
+ }));
+ worker.postMessage({msg: 'test1', data: offscreenCanvas}, [offscreenCanvas]);
+}, "Test that an OffscreenCanvas generated by transferControlToOffscreen gets correct width and height when it is transferred to a worker");
+
+async_test(function(t) {
+ var placeholder = document.createElement('canvas');
+ placeholder.width = 100;
+ placeholder.height = 50;
+ var offscreenCanvas = placeholder.transferControlToOffscreen();
+ var worker = makeWorker(document.getElementById("myWorker").textContent);
+ worker.addEventListener('message', t.step_func_done(function(msg) {
+ assert_throws_dom("InvalidStateError", function() { placeholder.getContext('2d'); });
+ }));
+ worker.postMessage({msg: 'test2', data: offscreenCanvas}, [offscreenCanvas]);
+}, "Test that calling getContext on a placeholder canvas that is transferred its control to an OffscreenCanvas throws an exception, when the OffscreenCanvas is transferred to a worker");
+
+async_test(function(t) {
+ var placeholder = document.createElement('canvas');
+ placeholder.width = 100;
+ placeholder.height = 50;
+ var offscreenCanvas = placeholder.transferControlToOffscreen();
+ var worker = makeWorker(document.getElementById("myWorker").textContent);
+ worker.addEventListener('message', t.step_func_done(function(msg) {
+ assert_throws_dom("InvalidStateError", function() { placeholder.transferControlToOffscreen(); });
+ }));
+ worker.postMessage({msg: 'test3', data: offscreenCanvas}, [offscreenCanvas]);
+}, "Test that calling transferControlToOffscreen twice throws an exception, when its associated OffscreenCanvas is transferred to a worker");
+
+</script>
+
diff --git a/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transferrable.html b/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transferrable.html
new file mode 100644
index 0000000000..76796034e9
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transferrable.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/html/canvas/resources/canvas-tests.js"></script>
+<link rel="help" href="https://html.spec.whatwg.org/#offscreencanvas">
+
+<script id="myWorker" type="text/worker">
+
+function test1(offscreenCanvas)
+{
+ return offscreenCanvas.width == 10 && offscreenCanvas.height == 10;
+}
+
+self.onmessage = function(e) {
+ switch(e.data.msg) {
+ case 'test1':
+ self.postMessage(test1(e.data.data));
+ break;
+ }
+};
+
+</script>
+
+<script>
+function makeWorker(script)
+{
+ var blob = new Blob([script]);
+ return new Worker(URL.createObjectURL(blob));
+}
+
+async_test(function(t) {
+ var worker = makeWorker(document.getElementById("myWorker").textContent);
+ var offscreenCanvas = new OffscreenCanvas(10, 10);
+ worker.postMessage({msg: 'test1', data: offscreenCanvas}, [offscreenCanvas]);
+ worker.addEventListener('message', t.step_func_done(function(msg) {
+ assert_true(msg.data);
+ }));
+ assert_equals(offscreenCanvas.width, 0);
+ assert_equals(offscreenCanvas.height, 0);
+}, "Test that offscreenCanvas's size is correct after being transferred to a worker.");
+
+
+test(function() {
+ function testException(contextType) {
+ var worker = makeWorker(document.getElementById("myWorker").textContent);
+ var offscreenCanvas = new OffscreenCanvas(10, 10);
+ var ctx = offscreenCanvas.getContext(contextType);
+ assert_throws_dom("InvalidStateError", function() {
+ worker.postMessage({offscreenCanvas}, [offscreenCanvas]);
+ });
+ }
+ testException('2d');
+}, "Test that transfer an OffscreenCanvas that already have a 2d context throws exception.");
+
+test(function() {
+ var worker = makeWorker(document.getElementById("myWorker").textContent);
+ var offscreenCanvas = new OffscreenCanvas(10, 10);
+ worker.postMessage({offscreenCanvas}, [offscreenCanvas]);
+ assert_throws_dom("DataCloneError", function() {
+ worker.postMessage({offscreenCanvas}, [offscreenCanvas]);
+ });
+}, "Test that transfer an OffscreenCanvas twice throws exception.");
+
+test(function() {
+ var worker = makeWorker(document.getElementById("myWorker").textContent);
+ var offscreenCanvas = new OffscreenCanvas(10, 10);
+ worker.postMessage({offscreenCanvas}, [offscreenCanvas]);
+ assert_throws_dom("InvalidStateError", function() {
+ offscreenCanvas.getContext('2d');
+ });
+}, "Test that calling getContext('2d') on a detached OffscreenCanvas throws exception.");
+
+test(function() {
+ var worker = makeWorker(document.getElementById("myWorker").textContent);
+ var offscreenCanvas = new OffscreenCanvas(10, 10);
+ worker.postMessage({offscreenCanvas}, [offscreenCanvas]);
+ assert_throws_dom("InvalidStateError", function() {
+ offscreenCanvas.getContext('webgl');
+ });
+}, "Test that calling getContext('webgl') on a detached OffscreenCanvas throws exception.");
+
+</script>
+
diff --git a/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transferrable.w.html b/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transferrable.w.html
new file mode 100644
index 0000000000..38f981e8f0
--- /dev/null
+++ b/testing/web-platform/tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transferrable.w.html
@@ -0,0 +1,142 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/html/canvas/resources/canvas-tests.js"></script>
+<link rel="help" href="https://html.spec.whatwg.org/#offscreencanvas">
+
+<script id="myWorker" type="text/worker">
+
+function isInvalidStateError(funcStr, offscreenCanvas)
+{
+ try {
+ eval(funcStr);
+ } catch (e) {
+ if (e instanceof DOMException && e.name == "InvalidStateError")
+ return true;
+ return false;
+ }
+}
+
+function testExceptionWith2DContext()
+{
+ var offscreenCanvas = new OffscreenCanvas(10, 10);
+ var ctx = offscreenCanvas.getContext('2d');
+ return isInvalidStateError("self.postMessage(offscreenCanvas, [offscreenCanvas])", offscreenCanvas);
+}
+
+function testExceptionWithWebGLContext()
+{
+ var offscreenCanvas = new OffscreenCanvas(10, 10);
+ var ctx = offscreenCanvas.getContext('webgl');
+ return isInvalidStateError("self.postMessage(offscreenCanvas, [offscreenCanvas])", offscreenCanvas);
+}
+
+function testExceptionWithDetachedOffscreenCanvas1()
+{
+ var offscreenCanvas = new OffscreenCanvas(10, 10);
+ self.postMessage(offscreenCanvas, [offscreenCanvas]);
+ return isInvalidStateError("self.postMessage(offscreenCanvas, [offscreenCanvas])", offscreenCanvas);
+}
+
+function testExceptionWithDetachedOffscreenCanvas2()
+{
+ var offscreenCanvas = new OffscreenCanvas(10, 10);
+ self.postMessage(offscreenCanvas, [offscreenCanvas]);
+ return isInvalidStateError("offscreenCanvas.getContext('2d')", offscreenCanvas);
+}
+
+function testExceptionWithDetachedOffscreenCanvas3()
+{
+ var offscreenCanvas = new OffscreenCanvas(10, 10);
+ self.postMessage(offscreenCanvas, [offscreenCanvas]);
+ return isInvalidStateError("offscreenCanvas.getContext('webgl')", offscreenCanvas);
+}
+
+self.onmessage = function(e) {
+ switch(e.data) {
+ case 'test1':
+ var offscreenCanvas = new OffscreenCanvas(10, 10);
+ self.postMessage(offscreenCanvas, [offscreenCanvas]);
+ break;
+ case 'test2':
+ self.postMessage(testExceptionWith2DContext());
+ break;
+ case 'test3':
+ self.postMessage(testExceptionWithWebGLContext());
+ break;
+ case 'test4':
+ self.postMessage(testExceptionWithDetachedOffscreenCanvas1());
+ break;
+ case 'test5':
+ self.postMessage(testExceptionWithDetachedOffscreenCanvas2());
+ break;
+ case 'test6':
+ self.postMessage(testExceptionWithDetachedOffscreenCanvas3());
+ break;
+ }
+};
+
+</script>
+
+<script>
+function makeWorker(test) {
+ var blob = new Blob([document.getElementById("myWorker").textContent]);
+ var worker = new Worker(URL.createObjectURL(blob));
+ worker.onerror = test.unreached_func("error");
+ return worker;
+}
+
+async_test(function(t) {
+ var worker = makeWorker(t);
+ worker.addEventListener('message', t.step_func_done(function(msg) {
+ assert_equals(msg.data.width, 10);
+ assert_equals(msg.data.height, 10);
+ }));
+ worker.postMessage('test1');
+}, "Test that OffscreenCanvas's size is correct after being transferred from a worker.");
+
+async_test(function(t) {
+ var worker = makeWorker(t);
+ worker.addEventListener('message', t.step_func_done(function(msg) {
+ assert_true(msg.data);
+ }));
+ worker.postMessage('test2');
+}, "Test that transfer an OffscreenCanvas that has a 2d context throws exception in a worker.");
+
+async_test(function(t) {
+ var worker = makeWorker(t);
+ worker.addEventListener('message', t.step_func_done(function(msg) {
+ assert_true(msg.data);
+ }));
+ worker.postMessage('test3');
+}, "Test that transfer an OffscreenCanvas that has a webgl context throws exception in a worker.");
+
+async_test(function(t) {
+ var worker = makeWorker(t);
+ worker.addEventListener('message', t.step_func_done(function(msg) {
+ if (msg.data == true || msg.data == false)
+ assert_true(msg.data);
+ }));
+ worker.postMessage('test4');
+}, "Test that transfer an OffscreenCanvas twice throws exception in a worker.");
+
+async_test(function(t) {
+ var worker = makeWorker(t);
+ worker.addEventListener('message', t.step_func_done(function(msg) {
+ if (msg.data == true || msg.data == false)
+ assert_true(msg.data);
+ }));
+ worker.postMessage('test5');
+}, "Test that calling getContext('2d') on a detached OffscreenCanvas throws exception in a worker.");
+
+async_test(function(t) {
+ var worker = makeWorker(t);
+ worker.addEventListener('message', t.step_func_done(function(msg) {
+ if (msg.data == true || msg.data == false)
+ assert_true(msg.data);
+ }));
+ worker.postMessage('test6');
+}, "Test that calling getContext('webgl') on a detached OffscreenCanvas throws exception in a worker.");
+
+</script>
+