summaryrefslogtreecommitdiffstats
path: root/dom/canvas/test/reftest
diff options
context:
space:
mode:
Diffstat (limited to 'dom/canvas/test/reftest')
-rw-r--r--dom/canvas/test/reftest/1177726-text-stroke-bounds-ref.html24
-rw-r--r--dom/canvas/test/reftest/1177726-text-stroke-bounds.html28
-rw-r--r--dom/canvas/test/reftest/1678909-1-ref.html15
-rw-r--r--dom/canvas/test/reftest/1678909-1.html14
-rw-r--r--dom/canvas/test/reftest/1719886-1-ref.html28
-rw-r--r--dom/canvas/test/reftest/1719886-1.html32
-rw-r--r--dom/canvas/test/reftest/1758968-1-ref.html13
-rw-r--r--dom/canvas/test/reftest/1758968-1.html16
-rw-r--r--dom/canvas/test/reftest/1768521-1-ref.html22
-rw-r--r--dom/canvas/test/reftest/1768521-1.html23
-rw-r--r--dom/canvas/test/reftest/black.html9
-rw-r--r--dom/canvas/test/reftest/capturestream.html35
-rw-r--r--dom/canvas/test/reftest/clip-multiple-move-1-ref.html22
-rw-r--r--dom/canvas/test/reftest/clip-multiple-move-1.html27
-rw-r--r--dom/canvas/test/reftest/clip-multiple-move-2-ref.html13
-rw-r--r--dom/canvas/test/reftest/clip-multiple-move-2.html32
-rw-r--r--dom/canvas/test/reftest/clip-multiple-paths-badref.html22
-rw-r--r--dom/canvas/test/reftest/clip-multiple-paths.html27
-rw-r--r--dom/canvas/test/reftest/clipped-dash-stroke-rect-ref.html19
-rw-r--r--dom/canvas/test/reftest/clipped-dash-stroke-rect.html19
-rw-r--r--dom/canvas/test/reftest/color_quads.html327
-rw-r--r--dom/canvas/test/reftest/color_quads.list17
-rw-r--r--dom/canvas/test/reftest/color_quads.pngbin0 -> 5893 bytes
-rw-r--r--dom/canvas/test/reftest/color_quads_401.pngbin0 -> 5823 bytes
-rw-r--r--dom/canvas/test/reftest/colors-no-alpha.pngbin0 -> 439 bytes
-rw-r--r--dom/canvas/test/reftest/colors-non-premult.pngbin0 -> 444 bytes
-rw-r--r--dom/canvas/test/reftest/colors-premult.pngbin0 -> 441 bytes
-rw-r--r--dom/canvas/test/reftest/draw-large-image-ref.html4
-rw-r--r--dom/canvas/test/reftest/draw-large-image.html15
-rw-r--r--dom/canvas/test/reftest/drawCustomFocusRing-ref.html18
-rw-r--r--dom/canvas/test/reftest/drawFocusIfNeeded-ref.html18
-rw-r--r--dom/canvas/test/reftest/drawFocusIfNeeded.html28
-rw-r--r--dom/canvas/test/reftest/filters/default-color.html16
-rw-r--r--dom/canvas/test/reftest/filters/drop-shadow-transformed.html17
-rw-r--r--dom/canvas/test/reftest/filters/drop-shadow.html16
-rw-r--r--dom/canvas/test/reftest/filters/fillText-with-filter-grayscale-1-ref.html12
-rw-r--r--dom/canvas/test/reftest/filters/fillText-with-filter-grayscale-1.html13
-rw-r--r--dom/canvas/test/reftest/filters/fillText-with-filter-grayscale-2-ref.html13
-rw-r--r--dom/canvas/test/reftest/filters/fillText-with-filter-grayscale-2.html14
-rw-r--r--dom/canvas/test/reftest/filters/fillText-with-filter-opacity-1-ref.html13
-rw-r--r--dom/canvas/test/reftest/filters/fillText-with-filter-opacity-1.html13
-rw-r--r--dom/canvas/test/reftest/filters/fillText-with-filter-opacity-2-ref.html13
-rw-r--r--dom/canvas/test/reftest/filters/fillText-with-filter-opacity-2.html14
-rw-r--r--dom/canvas/test/reftest/filters/fillText-with-shadow-1.html14
-rw-r--r--dom/canvas/test/reftest/filters/fillText-with-shadow-2.html15
-rw-r--r--dom/canvas/test/reftest/filters/fillText-without-shadow-1-ref.html12
-rw-r--r--dom/canvas/test/reftest/filters/fillText-without-shadow-2-ref.html13
-rw-r--r--dom/canvas/test/reftest/filters/global-alpha-ref.html18
-rw-r--r--dom/canvas/test/reftest/filters/global-alpha.html17
-rw-r--r--dom/canvas/test/reftest/filters/global-composite-operation-ref.html26
-rw-r--r--dom/canvas/test/reftest/filters/global-composite-operation.html21
-rw-r--r--dom/canvas/test/reftest/filters/liveness-document-open.html35
-rw-r--r--dom/canvas/test/reftest/filters/liveness-document-removeChild.html34
-rw-r--r--dom/canvas/test/reftest/filters/liveness.html18
-rw-r--r--dom/canvas/test/reftest/filters/multiple-drop-shadows.html16
-rw-r--r--dom/canvas/test/reftest/filters/ref.html17
-rw-r--r--dom/canvas/test/reftest/filters/reftest.list32
-rw-r--r--dom/canvas/test/reftest/filters/shadow-ref.html19
-rw-r--r--dom/canvas/test/reftest/filters/shadow.html18
-rw-r--r--dom/canvas/test/reftest/filters/strokeText-with-filter-grayscale-1-ref.html12
-rw-r--r--dom/canvas/test/reftest/filters/strokeText-with-filter-grayscale-1.html13
-rw-r--r--dom/canvas/test/reftest/filters/strokeText-with-filter-grayscale-2-ref.html13
-rw-r--r--dom/canvas/test/reftest/filters/strokeText-with-filter-grayscale-2.html14
-rw-r--r--dom/canvas/test/reftest/filters/strokeText-with-shadow-1.html14
-rw-r--r--dom/canvas/test/reftest/filters/strokeText-with-shadow-2.html15
-rw-r--r--dom/canvas/test/reftest/filters/strokeText-without-shadow-1-ref.html12
-rw-r--r--dom/canvas/test/reftest/filters/strokeText-without-shadow-2-ref.html13
-rw-r--r--dom/canvas/test/reftest/filters/subregion-fill-paint.html27
-rw-r--r--dom/canvas/test/reftest/filters/subregion-ref.html15
-rw-r--r--dom/canvas/test/reftest/filters/subregion-stroke-paint.html27
-rw-r--r--dom/canvas/test/reftest/filters/svg-bbox-ref.html15
-rw-r--r--dom/canvas/test/reftest/filters/svg-bbox.html27
-rw-r--r--dom/canvas/test/reftest/filters/svg-inline.html30
-rw-r--r--dom/canvas/test/reftest/filters/svg-liveness.html64
-rw-r--r--dom/canvas/test/reftest/filters/svg-off-screen.html33
-rw-r--r--dom/canvas/test/reftest/filters/units-em.html21
-rw-r--r--dom/canvas/test/reftest/filters/units-ex.html17
-rw-r--r--dom/canvas/test/reftest/filters/units-off-screen.html21
-rw-r--r--dom/canvas/test/reftest/filters/units-pt.html16
-rw-r--r--dom/canvas/test/reftest/filters/units.html16
-rw-r--r--dom/canvas/test/reftest/green.pngbin0 -> 1358 bytes
-rw-r--r--dom/canvas/test/reftest/red_ref.pngbin0 -> 993 bytes
-rw-r--r--dom/canvas/test/reftest/red_tall.pngbin0 -> 268626 bytes
-rw-r--r--dom/canvas/test/reftest/reftest.list255
-rw-r--r--dom/canvas/test/reftest/stroketext-shadow-ref.html19
-rw-r--r--dom/canvas/test/reftest/stroketext-shadow.html20
-rw-r--r--dom/canvas/test/reftest/visible-occluded-ref.html127
-rw-r--r--dom/canvas/test/reftest/visible-occluded.html124
-rw-r--r--dom/canvas/test/reftest/webgl-capturestream-test.html50
-rw-r--r--dom/canvas/test/reftest/webgl-clear-test.html40
-rw-r--r--dom/canvas/test/reftest/webgl-color-offscreen-test.html124
-rw-r--r--dom/canvas/test/reftest/webgl-color-test.html123
-rw-r--r--dom/canvas/test/reftest/webgl-disable-test.html60
-rw-r--r--dom/canvas/test/reftest/webgl-hanging-fb-test.html58
-rw-r--r--dom/canvas/test/reftest/webgl-hanging-scissor-test.html57
-rw-r--r--dom/canvas/test/reftest/webgl-resize-test.html53
-rw-r--r--dom/canvas/test/reftest/webgl-utils.js82
-rw-r--r--dom/canvas/test/reftest/white.pngbin0 -> 1401 bytes
-rw-r--r--dom/canvas/test/reftest/wrapper.html27
99 files changed, 3000 insertions, 0 deletions
diff --git a/dom/canvas/test/reftest/1177726-text-stroke-bounds-ref.html b/dom/canvas/test/reftest/1177726-text-stroke-bounds-ref.html
new file mode 100644
index 0000000000..46d37d8ed8
--- /dev/null
+++ b/dom/canvas/test/reftest/1177726-text-stroke-bounds-ref.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Testcase for bug 1177726</title>
+</head>
+<body>
+
+<canvas id="c" width="400" height="200">
+<p>No canvas.</p>
+</canvas>
+
+<script>
+var canvas = document.getElementsByTagName("canvas")[0];
+var ctx = canvas.getContext('2d');
+
+ctx.font = "120px 'Helvetica'";
+ctx.lineWidth = 15;
+ctx.lineJoin = "round";
+
+ctx.strokeText("Ehsan", 20, 110);
+</script>
+</body>
+</html>
diff --git a/dom/canvas/test/reftest/1177726-text-stroke-bounds.html b/dom/canvas/test/reftest/1177726-text-stroke-bounds.html
new file mode 100644
index 0000000000..1f459ce0b6
--- /dev/null
+++ b/dom/canvas/test/reftest/1177726-text-stroke-bounds.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Testcase for bug 1177726</title>
+</head>
+<body>
+
+<canvas id="c" width="400" height="200">
+<p>No canvas.</p>
+</canvas>
+
+<script>
+var canvas = document.getElementsByTagName("canvas")[0];
+var ctx = canvas.getContext('2d');
+
+ctx.shadowColor = 'white';
+ctx.shadowOffsetX = 5;
+ctx.shadowOffsetY = 5;
+ctx.shadowBlur = 0;
+ctx.font = "120px 'Helvetica'";
+ctx.lineWidth = 15;
+ctx.lineJoin = "round";
+
+ctx.strokeText("Ehsan", 20, 110);
+</script>
+</body>
+</html>
diff --git a/dom/canvas/test/reftest/1678909-1-ref.html b/dom/canvas/test/reftest/1678909-1-ref.html
new file mode 100644
index 0000000000..c97f31752d
--- /dev/null
+++ b/dom/canvas/test/reftest/1678909-1-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<head><meta charset="utf-8"></head>
+<body>
+ <canvas id="canvas" width="200" height="200"></canvas>
+ <script>
+ let canvas = document.getElementById('canvas');
+ let ctx = canvas.getContext('2d');
+ for (let i=0; i<100; i+=50) {
+ let arr = new Uint8ClampedArray(Array(40000).fill(200));
+ createImageBitmap(new ImageData(arr, 100)).then(img => {
+ ctx.drawImage(img, i, i);
+ });
+ }
+ </script>
+</body>
diff --git a/dom/canvas/test/reftest/1678909-1.html b/dom/canvas/test/reftest/1678909-1.html
new file mode 100644
index 0000000000..74bc21f53e
--- /dev/null
+++ b/dom/canvas/test/reftest/1678909-1.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<head><meta charset="utf-8"></head>
+<body>
+ <canvas id="canvas" width="200" height="200"></canvas>
+ <script>
+ let canvas = document.getElementById('canvas');
+ let ctx = canvas.getContext('2d');
+ let arr = new Uint8ClampedArray(Array(40000).fill(200));
+ createImageBitmap(new ImageData(arr, 100)).then(img => {
+ for (let i=0; i<100; i+=50)
+ ctx.drawImage(img, i, i);
+ });
+ </script>
+</body>
diff --git a/dom/canvas/test/reftest/1719886-1-ref.html b/dom/canvas/test/reftest/1719886-1-ref.html
new file mode 100644
index 0000000000..da35d86677
--- /dev/null
+++ b/dom/canvas/test/reftest/1719886-1-ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<body>
+Pattern Canvas<br>
+<canvas id="patternCanvas" style="border: 1px solid black" width="10" height="10"></canvas><br>
+Main Canvas (red square should be in top-left corner)<br>
+<canvas id="canvas" style="border: 1px solid black" width="100" height="100"></canvas>
+<script>
+
+// Draw a 10x10 red rectangle that will be used for the pattern.
+const patternCanvas = document.getElementById("patternCanvas");
+const patternCtx = patternCanvas.getContext("2d");
+patternCtx.fillStyle = "red";
+patternCtx.fillRect(0, 0, patternCanvas.width, patternCanvas.height);
+
+const canvas = document.getElementById("canvas");
+const ctx = canvas.getContext("2d");
+
+const pattern = ctx.createPattern(patternCanvas, "no-repeat");
+
+ctx.fillStyle = pattern;
+// Fill the entire canvas with the pattern.
+ctx.fillRect(0, 0, 100, 100);
+
+</script>
+
+</body>
+</html>
diff --git a/dom/canvas/test/reftest/1719886-1.html b/dom/canvas/test/reftest/1719886-1.html
new file mode 100644
index 0000000000..7a0c0f7ea4
--- /dev/null
+++ b/dom/canvas/test/reftest/1719886-1.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+<body>
+Pattern Canvas<br>
+<canvas id="patternCanvas" style="border: 1px solid black" width="10" height="10"></canvas><br>
+Main Canvas (red square should be in top-left corner)<br>
+<canvas id="canvas" style="border: 1px solid black" width="100" height="100"></canvas>
+<script>
+
+// Draw a 10x10 red rectangle that will be used for the pattern.
+const patternCanvas = document.getElementById("patternCanvas");
+const patternCtx = patternCanvas.getContext("2d");
+patternCtx.fillStyle = "red";
+patternCtx.fillRect(0, 0, patternCanvas.width, patternCanvas.height);
+
+const canvas = document.getElementById("canvas");
+const ctx = canvas.getContext("2d");
+const height = 100;
+ctx.translate(0, height);
+
+const pattern = ctx.createPattern(patternCanvas, "no-repeat");
+// Reverse translation applied to the canvas.
+pattern.setTransform((new DOMMatrix()).translate(0, -height));
+
+ctx.fillStyle = pattern;
+// Fill the entire canvas with the pattern.
+ctx.fillRect(0, -height, 100, 100);
+
+</script>
+
+</body>
+</html> \ No newline at end of file
diff --git a/dom/canvas/test/reftest/1758968-1-ref.html b/dom/canvas/test/reftest/1758968-1-ref.html
new file mode 100644
index 0000000000..a97e27d5fe
--- /dev/null
+++ b/dom/canvas/test/reftest/1758968-1-ref.html
@@ -0,0 +1,13 @@
+<div style="width: 100px; height: 100px;"><canvas id="canvas" width="100" height="50"></canvas></div>
+<script>
+ var can = document.getElementById('canvas');
+ var ctx = can.getContext('2d');
+
+ ctx.shadowOffsetX = 24;
+ ctx.shadowOffsetY = 24;
+ ctx.shadowColor = 'blue';
+ ctx.shadowBlur = 20;
+
+ ctx.fillStyle = 'black';
+ ctx.fillRect(0,0,40,40);
+</script>
diff --git a/dom/canvas/test/reftest/1758968-1.html b/dom/canvas/test/reftest/1758968-1.html
new file mode 100644
index 0000000000..0a78686594
--- /dev/null
+++ b/dom/canvas/test/reftest/1758968-1.html
@@ -0,0 +1,16 @@
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+ var can = document.getElementById('canvas');
+ var ctx = can.getContext('2d');
+
+ ctx.shadowOffsetX = 24;
+ ctx.shadowOffsetY = 24;
+ ctx.shadowColor = 'blue';
+ ctx.shadowBlur = 20;
+
+ ctx.rect(0,0,100,50);
+ ctx.clip();
+
+ ctx.fillStyle = 'black';
+ ctx.fillRect(0,0,40,40);
+</script>
diff --git a/dom/canvas/test/reftest/1768521-1-ref.html b/dom/canvas/test/reftest/1768521-1-ref.html
new file mode 100644
index 0000000000..d3c86ea35b
--- /dev/null
+++ b/dom/canvas/test/reftest/1768521-1-ref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<body>
+<canvas id="patternCanvas" width="8" height="32"></canvas>
+<br>
+<canvas id="canvas" width="32" height="32"></canvas>
+<script>
+
+const patternCanvas = document.getElementById("patternCanvas");
+const patternCtx = patternCanvas.getContext("2d");
+patternCtx.fillStyle = "green";
+patternCtx.fillRect(0, 0, patternCanvas.width, patternCanvas.height);
+
+const canvas = document.getElementById("canvas");
+const ctx = canvas.getContext("2d");
+ctx.fillStyle = "green";
+ctx.fillRect(16, 16, 16, 16);
+</script>
+
+</body>
+</html>
+
diff --git a/dom/canvas/test/reftest/1768521-1.html b/dom/canvas/test/reftest/1768521-1.html
new file mode 100644
index 0000000000..e9e681f2e6
--- /dev/null
+++ b/dom/canvas/test/reftest/1768521-1.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<body>
+<canvas id="patternCanvas" width="8" height="32"></canvas>
+<br>
+<canvas id="canvas" width="32" height="32"></canvas>
+<script>
+
+const patternCanvas = document.getElementById("patternCanvas");
+const patternCtx = patternCanvas.getContext("2d");
+patternCtx.fillStyle = "green";
+patternCtx.fillRect(0, 0, patternCanvas.width, patternCanvas.height);
+
+const canvas = document.getElementById("canvas");
+const ctx = canvas.getContext("2d");
+const pattern = ctx.createPattern(patternCanvas, "repeat-x");
+ctx.fillStyle = pattern;
+ctx.fillRect(16, 16, 16, 16);
+</script>
+
+</body>
+</html>
+
diff --git a/dom/canvas/test/reftest/black.html b/dom/canvas/test/reftest/black.html
new file mode 100644
index 0000000000..d2c721b1d5
--- /dev/null
+++ b/dom/canvas/test/reftest/black.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+</head>
+<body>
+ <div style="width: 256px; height: 256px; background-color: black"></div>
+</body>
+</html>
diff --git a/dom/canvas/test/reftest/capturestream.html b/dom/canvas/test/reftest/capturestream.html
new file mode 100644
index 0000000000..b07ab394bc
--- /dev/null
+++ b/dom/canvas/test/reftest/capturestream.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<meta charset='UTF-8'>
+<!--
+Clear the canvas to green and capture it to a stream to test that we can get
+the stream to screen in a local video element.
+-->
+<html class="reftest-wait">
+
+<head>
+ <script type='text/javascript'>
+function finished() {
+ document.documentElement.removeAttribute("class");
+}
+
+function runTest() {
+ var canvas = document.getElementById('canvas');
+ var context = canvas.getContext('2d');
+ context.fillStyle = "rgba(0, 255, 0, 1)";
+ context.fillRect(0, 0, canvas.width, canvas.height);
+
+ var video = document.getElementById('video');
+ video.srcObject = canvas.captureStream(0);
+ video.play();
+ video.onloadeddata = finished;
+ video.onerror = finished;
+}
+ </script>
+</head>
+
+<body onload='runTest();'>
+ <video id='video' width='256' height='256'></video>
+ <canvas id='canvas' width='256' height='256' style="display:none"></canvas>
+</body>
+
+</html>
diff --git a/dom/canvas/test/reftest/clip-multiple-move-1-ref.html b/dom/canvas/test/reftest/clip-multiple-move-1-ref.html
new file mode 100644
index 0000000000..4e85b76565
--- /dev/null
+++ b/dom/canvas/test/reftest/clip-multiple-move-1-ref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+
+var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+
+ctx.fillStyle = '#0f0';
+ctx.fillRect(0, 0, 100, 100);
+
+ctx.beginPath();
+ctx.rect(30, 30, 40, 40);
+ctx.clip();
+
+ctx.fillStyle = '#f00';
+
+ctx.fillRect(0, 0, 100, 100);
+
+</script>
+</body></html>
diff --git a/dom/canvas/test/reftest/clip-multiple-move-1.html b/dom/canvas/test/reftest/clip-multiple-move-1.html
new file mode 100644
index 0000000000..3dbd0391d6
--- /dev/null
+++ b/dom/canvas/test/reftest/clip-multiple-move-1.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+<canvas id="canvas" width="100" height="100"></canvas>
+
+<script>
+
+var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+
+ctx.fillStyle = '#0f0';
+ctx.fillRect(0, 0, 100, 100);
+
+ctx.beginPath();
+ctx.moveTo(100, 30);
+ctx.moveTo(30, 30);
+ctx.lineTo(30, 70);
+ctx.lineTo(70, 70);
+ctx.lineTo(70, 30);
+ctx.closePath();
+ctx.clip();
+
+ctx.fillStyle = '#f00';
+ctx.fillRect(0, 0, 100, 100);
+
+</script>
+</body></html>
diff --git a/dom/canvas/test/reftest/clip-multiple-move-2-ref.html b/dom/canvas/test/reftest/clip-multiple-move-2-ref.html
new file mode 100644
index 0000000000..8b3d37a362
--- /dev/null
+++ b/dom/canvas/test/reftest/clip-multiple-move-2-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<canvas id="canvas" width="150" height="150"></canvas>
+<script>
+
+var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+ctx.fillStyle = '#0f0';
+ctx.fillRect(0, 0, 150, 150);
+
+</script>
+</body></html>
diff --git a/dom/canvas/test/reftest/clip-multiple-move-2.html b/dom/canvas/test/reftest/clip-multiple-move-2.html
new file mode 100644
index 0000000000..55e272f357
--- /dev/null
+++ b/dom/canvas/test/reftest/clip-multiple-move-2.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+<head>
+<canvas id="canvas" width="150" height="150"></canvas>
+
+<script>
+
+var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+
+ctx.fillStyle = '#f00';
+ctx.fillRect(0, 0, 150, 150);
+
+ctx.beginPath();
+ctx.moveTo(0, 0);
+ctx.moveTo(0, -1);
+ctx.lineTo(0, 150);
+ctx.lineTo(150, 150);
+
+// The coordinate '149.99999' makes skia use GrConvexPolyEffect to handle the points.
+// The result should be same as '150'. So this test checks if the GrConvexPolyEffect
+// works well.
+ctx.lineTo(149.99999, -1);
+
+ctx.closePath();
+ctx.clip();
+
+ctx.fillStyle = '#0f0';
+ctx.fillRect(0, 0, 150, 150);
+
+</script>
+</body></html>
diff --git a/dom/canvas/test/reftest/clip-multiple-paths-badref.html b/dom/canvas/test/reftest/clip-multiple-paths-badref.html
new file mode 100644
index 0000000000..42a987a19e
--- /dev/null
+++ b/dom/canvas/test/reftest/clip-multiple-paths-badref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+
+var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+
+ctx.fillStyle = '#0f0';
+ctx.fillRect(0, 0, 100, 100);
+
+ctx.beginPath();
+ctx.arc(50, 50, 25, 0, 2 * Math.PI);
+ctx.clip();
+
+ctx.fillStyle = '#f00';
+
+ctx.fillRect(0, 0, 100, 100);
+
+</script>
+</body></html>
diff --git a/dom/canvas/test/reftest/clip-multiple-paths.html b/dom/canvas/test/reftest/clip-multiple-paths.html
new file mode 100644
index 0000000000..0e1e0d4994
--- /dev/null
+++ b/dom/canvas/test/reftest/clip-multiple-paths.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+<canvas id="canvas" width="100" height="100"></canvas>
+
+<script>
+
+var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+
+ctx.fillStyle = '#0f0';
+ctx.fillRect(0, 0, 100, 100);
+
+ctx.beginPath();
+ctx.rect(30, 30, 40, 40);
+ctx.clip();
+
+ctx.beginPath();
+ctx.arc(50, 50, 25, 0, 2 * Math.PI);
+ctx.clip();
+
+ctx.fillStyle = '#f00';
+
+ctx.fillRect(0, 0, 100, 100);
+
+</script>
+</body></html>
diff --git a/dom/canvas/test/reftest/clipped-dash-stroke-rect-ref.html b/dom/canvas/test/reftest/clipped-dash-stroke-rect-ref.html
new file mode 100644
index 0000000000..117bf4fbca
--- /dev/null
+++ b/dom/canvas/test/reftest/clipped-dash-stroke-rect-ref.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<html>
+<body>
+<script>
+canvas = document.createElement('canvas');
+document.body.appendChild(canvas);
+ctx = canvas.getContext('2d');
+
+canvas.width = 1000;
+canvas.height = 1000;
+ctx.translate(420.31465167323177, 40.531991340689785);
+
+
+ctx.strokeStyle = 'red';
+ctx.lineWidth = 3;
+ctx.setLineDash([24, 12]);
+ctx.strokeRect(15, -441, 60, 420);
+
+</script>
diff --git a/dom/canvas/test/reftest/clipped-dash-stroke-rect.html b/dom/canvas/test/reftest/clipped-dash-stroke-rect.html
new file mode 100644
index 0000000000..0e44254ec3
--- /dev/null
+++ b/dom/canvas/test/reftest/clipped-dash-stroke-rect.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<html>
+<body>
+<script>
+canvas = document.createElement('canvas');
+document.body.appendChild(canvas);
+ctx = canvas.getContext('2d');
+
+canvas.width = 1000;
+canvas.height = 1000;
+ctx.translate(420.31465167323177, 40.531991340689785);
+ctx.scale(3, 3);
+
+ctx.strokeStyle = 'red';
+ctx.lineWidth = 1;
+ctx.setLineDash([8, 4]);
+ctx.strokeRect(5, -147, 20, 140);
+
+</script>
diff --git a/dom/canvas/test/reftest/color_quads.html b/dom/canvas/test/reftest/color_quads.html
new file mode 100644
index 0000000000..944d1f1370
--- /dev/null
+++ b/dom/canvas/test/reftest/color_quads.html
@@ -0,0 +1,327 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+ <!--
+# color_quads.html
+
+* The default is a 400x400 2d canvas, with 0, 16, 235, and 255 "gray" outer
+ quads, and 50%-red, -green, -blue, and -gray inner quads.
+
+* We default to showing the settings pane when loaded without a query string.
+ This way, someone naively opens this in a browser, they can immediately see
+ all available options.
+
+* The "Publish" button updates the url, and so causes the settings pane to
+ hide.
+
+* Clicking on the canvas toggles the settings pane for further editing.
+ -->
+ <head>
+ <meta charset="utf-8">
+ <title>color_quads.html (2022-07-15)</title>
+ </head>
+ <body>
+ <div id="e_settings">
+ Image override: <input id="e_img" type="text">
+
+ <br>
+ <br>Canvas Width: <input id="e_width" type="text" value="400">
+ <br>Canvas Height: <input id="e_height" type="text" value="400">
+ <br>Canvas Colorspace: <input id="e_cspace" type="text">
+ <br>Canvas Context Type: <select id="e_context">
+ <option value="2d" selected="selected">Canvas2D</option>
+ <option value="webgl">WebGL</option>
+ </select>
+ <br>Canvas Context Options: <input id="e_options" type="text" value="{}">
+
+ <br>
+ <br>OuterTopLeft: <input id="e_color_o1" type="text" value="rgb(0,0,0)">
+ <br>OuterTopRight: <input id="e_color_o2" type="text" value="rgb(16,16,16)">
+ <br>OuterBottomLeft: <input id="e_color_o3" type="text" value="rgb(235,235,235)">
+ <br>OuterBottomRight: <input id="e_color_o4" type="text" value="rgb(255,255,255)">
+ <br>
+ <br>InnerTopLeft: <input id="e_color_i1" type="text" value="rgb(127,0,0)">
+ <br>InnerTopRight: <input id="e_color_i2" type="text" value="rgb(0,127,0)">
+ <br>InnerBottomLeft: <input id="e_color_i3" type="text" value="rgb(0,0,127)">
+ <br>InnerBottomRight: <input id="e_color_i4" type="text" value="rgb(127,127,127)">
+ <br><input id="e_publish" type="button" value="Publish">
+ <hr>
+ </div>
+ <div id="e_canvas_holder">
+ <canvas></canvas>
+ </div>
+ <script>
+"use strict";
+
+// document.body.style.backgroundColor = '#fdf';
+
+// -
+
+// Click the canvas to toggle the settings pane.
+e_canvas_holder.addEventListener("click", () => {
+ // Toggle display:none to hide/unhide.
+ e_settings.style.display = e_settings.style.display ? "" : "none";
+});
+
+// Hide settings initially if there's a query string in the url.
+if (window.location.search.startsWith("?")) {
+ e_settings.style.display = "none";
+}
+
+// -
+
+function map(obj, fn) {
+ fn = fn || (x => x);
+ const ret = {};
+ for (const [k,v] of Object.entries(obj)) {
+ ret[k] = fn(v, k);
+ }
+ return ret;
+}
+
+function map_keys_required(obj, keys, fn) {
+ fn = fn || (x => x);
+
+ const ret = {};
+ for (const k of keys) {
+ const v = obj[k];
+ if (v === undefined) throw {k, obj};
+ ret[k] = fn(v, k);
+ }
+ return ret;
+}
+
+function set_device_pixel_size(e, device_size) {
+ const DPR = window.devicePixelRatio;
+ map_keys_required(device_size, ['width', 'height'], (device, k) => {
+ const css = device / DPR;
+ e.style[k] = css + 'px';
+ });
+}
+
+function pad_top_left_to_device_pixels(e) {
+ const DPR = window.devicePixelRatio;
+
+ e.style.padding = '';
+ let css_rect = e.getBoundingClientRect();
+ css_rect = map_keys_required(css_rect, ['left', 'top']);
+
+ const orig_device_rect = {};
+ const snapped_padding = map(css_rect, (css, k) => {
+ const device = orig_device_rect[k] = css * DPR;
+ const device_snapped = Math.round(device);
+ let device_padding = device_snapped - device;
+ // Negative padding is treated as 0.
+ // We want to pad:
+ // * 3.9 -> 4.0
+ // * 3.1 -> 4.0
+ // * 3.00000001 -> 3.0
+ if (device_padding < 0.01) {
+ device_padding += 1;
+ }
+ const css_padding = device_padding / DPR;
+ // console.log({css, k, device, device_snapped, device_padding, css_padding});
+ return css_padding;
+ });
+
+ e.style.paddingLeft = snapped_padding.left + 'px';
+ e.style.paddingTop = snapped_padding.top + 'px';
+ console.log(`[info] At dpr=${DPR}, padding`, css_rect, '(', orig_device_rect, 'device) by', snapped_padding);
+}
+
+// -
+
+const SETTING_NODES = {};
+e_settings.childNodes.forEach(n => {
+ if (!n.id) return;
+ SETTING_NODES[n.id] = n;
+ n._default = n.value;
+});
+
+const URL_PARAMS = new URLSearchParams(window.location.search);
+URL_PARAMS.forEach((v,k) => {
+ const n = SETTING_NODES[k];
+ if (!n) {
+ if (k && !k.startsWith('__')) {
+ console.warn(`Unrecognized setting: ${k} = ${v}`);
+ }
+ return;
+ }
+ n.value = v;
+});
+
+// -
+
+function UNITTEST_STR_EQ(was, expected) {
+ function to_result(src) {
+ let result = src;
+ if (typeof(result) == 'string') {
+ result = eval(result);
+ }
+ let result_str = result.toString();
+ if (result instanceof Array) {
+ result_str = '[' + result_str + ']';
+ }
+ return {src, result, result_str};
+ }
+ was = to_result(was);
+ expected = to_result(expected);
+
+ if (false) {
+ if (was.result_str != expected.result_str) {
+ throw {was, expected};
+ }
+ console.log(`[unittest] OK `, was.src, ` -> ${was.result_str} (`, expected.src, `)`);
+ }
+ console.assert(was.result_str == expected.result_str,
+ was.src, ` -> ${was.result_str} (`, expected.src, `)`);
+}
+
+// -
+
+/// Non-Premult-Alpha, e.g. [1.0, 1.0, 1.0, 0.5]
+function parse_css_color_npa(str) {
+ const m = /(rgba?)\((.*)\)/.exec(str);
+ if (!m) throw str;
+
+ let vals = m[2];
+ vals = vals.split(',').map(s => parseFloat(s));
+ if (vals.length == 3) {
+ vals.push(1.0);
+ }
+ for (let i = 0; i < 3; i++) {
+ vals[i] /= 255;
+ }
+ return vals;
+}
+UNITTEST_STR_EQ(`parse_css_color_npa('rgb(255,255,255)');`, [1,1,1,1]);
+UNITTEST_STR_EQ(`parse_css_color_npa('rgba(255,255,255)');`, [1,1,1,1]);
+UNITTEST_STR_EQ(`parse_css_color_npa('rgb(20,40,60)');`, '[20/255, 40/255, 60/255, 1]');
+UNITTEST_STR_EQ(`parse_css_color_npa('rgb(20,40,60,0.5)');`, '[20/255, 40/255, 60/255, 0.5]');
+UNITTEST_STR_EQ(`parse_css_color_npa('rgb(20,40,60,0)');`, '[20/255, 40/255, 60/255, 0]');
+
+// -
+
+let e_canvas;
+
+async function draw() {
+ while (e_canvas_holder.firstChild) {
+ e_canvas_holder.removeChild(e_canvas_holder.firstChild);
+ }
+
+ if (e_img.value) {
+ const img = document.createElement("img");
+ img.src = e_img.value;
+ console.log('img.src =', img.src);
+ await img.decode();
+ e_canvas_holder.appendChild(img);
+ set_device_pixel_size(img, {width: img.naturalWidth, height: img.naturalHeight});
+ pad_top_left_to_device_pixels(img);
+ return;
+ }
+
+ e_canvas = document.createElement("canvas");
+
+ let options = eval(`Object.assign(${e_options.value})`);
+ options.colorSpace = e_cspace.value || undefined;
+
+ const context = e_canvas.getContext(e_context.value, options);
+ if (context.drawingBufferColorSpace && options.colorSpace) {
+ context.drawingBufferColorSpace = options.colorSpace;
+ }
+ if (context.getContextAttributes) {
+ options = context.getContextAttributes();
+ }
+ console.log({options});
+
+ // -
+
+ const W = parseInt(e_width.value);
+ const H = parseInt(e_height.value);
+ context.canvas.width = W;
+ context.canvas.height = H;
+ e_canvas_holder.appendChild(e_canvas);
+
+ // If we don't snap to the device pixel grid, borders between color blocks
+ // will be filtered, and this causes a lot of fuzzy() annotations.
+ set_device_pixel_size(e_canvas, e_canvas);
+ pad_top_left_to_device_pixels(e_canvas);
+
+ // -
+
+ let fillFromElem;
+ if (context.fillRect) {
+ const c2d = context;
+ fillFromElem = (e, left, top, w, h) => {
+ if (!e.value) return;
+ c2d.fillStyle = e.value;
+ c2d.fillRect(left, top, w, h);
+ };
+
+ } else if (context.drawArrays) {
+ const gl = context;
+ gl.enable(gl.SCISSOR_TEST);
+ gl.disable(gl.DEPTH_TEST);
+ fillFromElem = (e, left, top, w, h) => {
+ if (!e.value) return;
+ const rgba = parse_css_color_npa(e.value.trim());
+ if (false && options.premultipliedAlpha) {
+ for (let i = 0; i < 3; i++) {
+ rgba[i] *= rgba[3];
+ }
+ }
+
+ const bottom = top+h; // in y-down c2d coords
+ gl.scissor(left, gl.drawingBufferHeight - bottom, w, h);
+ gl.clearColor(...rgba);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ };
+ }
+
+ // -
+
+ const LEFT_HALF = W/2 | 0; // Round
+ const TOP_HALF = H/2 | 0;
+
+ fillFromElem(e_color_o1, 0 , 0 , LEFT_HALF, TOP_HALF);
+ fillFromElem(e_color_o2, LEFT_HALF, 0 , W-LEFT_HALF, TOP_HALF);
+ fillFromElem(e_color_o3, 0 , TOP_HALF, LEFT_HALF, H-TOP_HALF);
+ fillFromElem(e_color_o4, LEFT_HALF, TOP_HALF, W-LEFT_HALF, H-TOP_HALF);
+
+ // -
+
+ const INNER_SCALE = 1/4;
+ const W_INNER = W*INNER_SCALE | 0;
+ const H_INNER = H*INNER_SCALE | 0;
+
+ fillFromElem(e_color_i1, LEFT_HALF-W_INNER, TOP_HALF-H_INNER, W_INNER, H_INNER);
+ fillFromElem(e_color_i2, LEFT_HALF , TOP_HALF-H_INNER, W_INNER, H_INNER);
+ fillFromElem(e_color_i3, LEFT_HALF-W_INNER, TOP_HALF , W_INNER, H_INNER);
+ fillFromElem(e_color_i4, LEFT_HALF , TOP_HALF , W_INNER, H_INNER);
+}
+
+(async () => {
+ await draw();
+ document.documentElement.removeAttribute("class");
+})();
+
+// -
+
+Object.values(SETTING_NODES).forEach(x => {
+ x.addEventListener("change", draw);
+});
+
+e_publish.addEventListener("click", () => {
+ let settings = [];
+ for (const n of Object.values(SETTING_NODES)) {
+ if (n.value == n._default) continue;
+ settings.push(`${n.id}=${n.value}`);
+ }
+ settings = settings.join("&");
+ if (!settings) {
+ settings = "="; // Empty key-value pair is "publish with default settings"
+ }
+ window.location.search = "?" + settings;
+});
+ </script>
+ </body>
+</html>
diff --git a/dom/canvas/test/reftest/color_quads.list b/dom/canvas/test/reftest/color_quads.list
new file mode 100644
index 0000000000..ea96838275
--- /dev/null
+++ b/dom/canvas/test/reftest/color_quads.list
@@ -0,0 +1,17 @@
+defaults pref(webgl.force-enabled,true)
+
+== color_quads.html?= color_quads.html?e_img=color_quads.png
+== color_quads.html?e_context=webgl color_quads.html?=
+
+# Test odd width and height
+== color_quads.html?e_width=401&e_height=401 color_quads.html?e_img=color_quads_401.png
+== color_quads.html?e_context=webgl&e_width=401&e_height=401 color_quads.html?e_width=401&e_height=401
+
+# Test various alpha values for webgl.
+== color_quads.html?desc=premult-alpha_&e_context=webgl&e_color_o1=rgb(0,0,0,0.95)&e_color_o2=rgb(16,16,16,0.95)&e_color_o3=rgb(235,235,235,0.95)&e_color_o4=rgb(255,255,255,0.95)&e_color_i4=rgb(0,0,0,0) color_quads.html?e_color_o1=rgb(13,13,13)&e_color_o2=rgb(29,29,29)&e_color_o3=rgb(248,248,248)&e_color_i4=rgb(255,255,255)
+
+== color_quads.html?desc=no-alpha______&e_context=webgl&e_options={alpha:false}&e_color_o1=rgb(0,0,0,0.95)&e_color_o2=rgb(16,16,16,0.95)&e_color_o3=rgb(235,235,235,0.95)&e_color_o4=rgb(255,255,255,0.95)&e_color_i4=rgb(0,0,0,0) color_quads.html?e_color_i4=rgb(0,0,0)
+
+skip-if(swgl) skip-if(gtkWidget&&useDrawSnapshot) fuzzy-if(Android&&!swgl,255-255,120000-120000) == color_quads.html?desc=straight-alpha&e_context=webgl&e_options={premultipliedAlpha:false}&e_color_o1=rgb(0,0,0,0.95)&e_color_o2=rgb(16,16,16,0.95)&e_color_o3=rgb(235,235,235,0.95)&e_color_o4=rgb(255,255,255,0.95)&e_color_i4=rgb(0,0,0,0) color_quads.html?e_color_o1=rgb(13,13,13)&e_color_o2=rgb(28,28,28)&e_color_o3=rgb(236,236,236)&e_color_i4=rgb(255,255,255)
+skip-if(!swgl) == color_quads.html?desc=straight-alpha&e_context=webgl&e_options={premultipliedAlpha:false}&e_color_o1=rgb(0,0,0,0.95)&e_color_o2=rgb(16,16,16,0.95)&e_color_o3=rgb(235,235,235,0.95)&e_color_o4=rgb(255,255,255,0.95)&e_color_i4=rgb(0,0,0,0) color_quads.html?e_color_o1=rgb(14,14,14)&e_color_o2=rgb(30,30,30)&e_color_o3=rgb(237,237,237)&e_color_i1=rgb(128,1,1)&e_color_i2=rgb(1,128,1)&e_color_i3=rgb(1,1,128)&e_color_i4=rgb(255,255,255)
+skip-if(!(gtkWidget&&useDrawSnapshot)) == color_quads.html?desc=straight-alpha&e_context=webgl&e_options={premultipliedAlpha:false}&e_color_o1=rgb(0,0,0,0.95)&e_color_o2=rgb(16,16,16,0.95)&e_color_o3=rgb(235,235,235,0.95)&e_color_o4=rgb(255,255,255,0.95)&e_color_i4=rgb(0,0,0,0) color_quads.html?e_color_o1=rgb(13,13,13)&e_color_o2=rgb(29,29,29)&e_color_o3=rgb(237,237,237)&e_color_i4=rgb(255,255,255)
diff --git a/dom/canvas/test/reftest/color_quads.png b/dom/canvas/test/reftest/color_quads.png
new file mode 100644
index 0000000000..de92b33494
--- /dev/null
+++ b/dom/canvas/test/reftest/color_quads.png
Binary files differ
diff --git a/dom/canvas/test/reftest/color_quads_401.png b/dom/canvas/test/reftest/color_quads_401.png
new file mode 100644
index 0000000000..a596ea8301
--- /dev/null
+++ b/dom/canvas/test/reftest/color_quads_401.png
Binary files differ
diff --git a/dom/canvas/test/reftest/colors-no-alpha.png b/dom/canvas/test/reftest/colors-no-alpha.png
new file mode 100644
index 0000000000..5c6f48a40a
--- /dev/null
+++ b/dom/canvas/test/reftest/colors-no-alpha.png
Binary files differ
diff --git a/dom/canvas/test/reftest/colors-non-premult.png b/dom/canvas/test/reftest/colors-non-premult.png
new file mode 100644
index 0000000000..727fe15a8c
--- /dev/null
+++ b/dom/canvas/test/reftest/colors-non-premult.png
Binary files differ
diff --git a/dom/canvas/test/reftest/colors-premult.png b/dom/canvas/test/reftest/colors-premult.png
new file mode 100644
index 0000000000..98d5e0feca
--- /dev/null
+++ b/dom/canvas/test/reftest/colors-premult.png
Binary files differ
diff --git a/dom/canvas/test/reftest/draw-large-image-ref.html b/dom/canvas/test/reftest/draw-large-image-ref.html
new file mode 100644
index 0000000000..a86079e129
--- /dev/null
+++ b/dom/canvas/test/reftest/draw-large-image-ref.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html><meta charset=utf-8>
+<body>
+<img style="width: 200px;" src="red_ref.png">
+</body>
diff --git a/dom/canvas/test/reftest/draw-large-image.html b/dom/canvas/test/reftest/draw-large-image.html
new file mode 100644
index 0000000000..ba758d01e8
--- /dev/null
+++ b/dom/canvas/test/reftest/draw-large-image.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html><meta charset=utf-8>
+<body class="reftest-wait">
+<canvas style="width: 200px;" id="canvas"></canvas>
+<script>
+const ctx1 = document.getElementById("canvas").getContext("2d");
+const img1 = new Image();
+img1.onload = () => {
+ ctx1.canvas.width = img1.width;
+ ctx1.canvas.height = 200;
+ ctx1.drawImage(img1, 0, 0);
+ document.body.classList.remove("reftest-wait");
+};
+img1.src = "red_tall.png";
+</script>
+</body>
diff --git a/dom/canvas/test/reftest/drawCustomFocusRing-ref.html b/dom/canvas/test/reftest/drawCustomFocusRing-ref.html
new file mode 100644
index 0000000000..e1499ff1ed
--- /dev/null
+++ b/dom/canvas/test/reftest/drawCustomFocusRing-ref.html
@@ -0,0 +1,18 @@
+<!--docytpe html-->
+<html><head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<meta charset="UTF-8">
+<script>
+window.onload=function(){
+var c=document.getElementById("myCanvas").getContext("2d");
+c.beginPath();
+c.strokeRect(10, 10, 200, 200);
+}
+</script>
+</head>
+<body>
+<canvas id="myCanvas" height="500" width="500" style="border:1px solid black">
+
+</canvas>
+
+</body></html>
diff --git a/dom/canvas/test/reftest/drawFocusIfNeeded-ref.html b/dom/canvas/test/reftest/drawFocusIfNeeded-ref.html
new file mode 100644
index 0000000000..f22f6e72cd
--- /dev/null
+++ b/dom/canvas/test/reftest/drawFocusIfNeeded-ref.html
@@ -0,0 +1,18 @@
+<!--docytpe html-->
+<html><head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<meta charset="UTF-8">
+<script>
+window.onload=function(){
+var c=document.getElementById("myCanvas").getContext("2d");
+c.beginPath();
+c.setLineDash([1,1]);
+c.strokeRect(10, 10, 200, 200);
+}
+</script>
+</head>
+<body>
+<canvas id="myCanvas" height="500" width="500" style="border:1px solid black">
+</canvas>
+
+</body></html>
diff --git a/dom/canvas/test/reftest/drawFocusIfNeeded.html b/dom/canvas/test/reftest/drawFocusIfNeeded.html
new file mode 100644
index 0000000000..048723fd48
--- /dev/null
+++ b/dom/canvas/test/reftest/drawFocusIfNeeded.html
@@ -0,0 +1,28 @@
+<!--docytpe html-->
+<html><head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<meta charset="UTF-8">
+<script>
+window.onload=function(){
+var c=document.getElementById("myCanvas").getContext("2d");
+var in1=document.getElementById("in1");
+var in2=document.getElementById("in2");
+in1.onfocus=function(){
+c.beginPath();
+c.rect(10, 10, 200, 200);
+c.drawFocusIfNeeded(in1);
+c.beginPath();
+c.rect(10, 220, 200, 200);
+c.drawFocusIfNeeded(in2);
+}
+in1.focus();
+}
+</script>
+</head>
+<body>
+<canvas id="myCanvas" height="500" width="500" style="border:1px solid black">
+ <input id="in1" type="range" min="1" max="12">
+ <input id="in2" type="range" min="1" max="12">
+</canvas>
+
+</body></html>
diff --git a/dom/canvas/test/reftest/filters/default-color.html b/dom/canvas/test/reftest/filters/default-color.html
new file mode 100644
index 0000000000..82fb5eda38
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/default-color.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<body>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+
+var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+
+ctx.filter = 'drop-shadow(0 10px)';
+ctx.fillStyle = '#0f0';
+ctx.fillRect(25, 25, 50, 40);
+
+</script>
+</body>
+</html>
diff --git a/dom/canvas/test/reftest/filters/drop-shadow-transformed.html b/dom/canvas/test/reftest/filters/drop-shadow-transformed.html
new file mode 100644
index 0000000000..0cf33deea8
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/drop-shadow-transformed.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<body>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+
+var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+
+ctx.fillStyle = '#0f0';
+ctx.scale(-1, -1);
+ctx.filter = 'drop-shadow(0 10px black)';
+ctx.fillRect(-75, -65, 50, 40);
+
+</script>
+</body>
+</html>
diff --git a/dom/canvas/test/reftest/filters/drop-shadow.html b/dom/canvas/test/reftest/filters/drop-shadow.html
new file mode 100644
index 0000000000..6977b7d5e0
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/drop-shadow.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<body>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+
+var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+
+ctx.filter = 'drop-shadow(0 10px black)';
+ctx.fillStyle = '#0f0';
+ctx.fillRect(25, 25, 50, 40);
+
+</script>
+</body>
+</html>
diff --git a/dom/canvas/test/reftest/filters/fillText-with-filter-grayscale-1-ref.html b/dom/canvas/test/reftest/filters/fillText-with-filter-grayscale-1-ref.html
new file mode 100644
index 0000000000..897d0565f1
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/fillText-with-filter-grayscale-1-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+var canvas = document.getElementById("canvas");
+var ctx = canvas.getContext("2d");
+ctx.fillStyle = "rgb(85,85,85)";
+ctx.font = "20px serif";
+ctx.fillText("Hello world", 0, 50);
+</script>
+</body></html>
diff --git a/dom/canvas/test/reftest/filters/fillText-with-filter-grayscale-1.html b/dom/canvas/test/reftest/filters/fillText-with-filter-grayscale-1.html
new file mode 100644
index 0000000000..28c3d7d028
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/fillText-with-filter-grayscale-1.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+var canvas = document.getElementById("canvas");
+var ctx = canvas.getContext("2d");
+ctx.fillStyle = "rgb(85,85,85)";
+ctx.filter = "grayscale(100%)";
+ctx.font = "20px serif";
+ctx.fillText("Hello world", 0, 50);
+</script>
+</body></html>
diff --git a/dom/canvas/test/reftest/filters/fillText-with-filter-grayscale-2-ref.html b/dom/canvas/test/reftest/filters/fillText-with-filter-grayscale-2-ref.html
new file mode 100644
index 0000000000..9e416dbe94
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/fillText-with-filter-grayscale-2-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+var canvas = document.getElementById("canvas");
+var ctx = canvas.getContext("2d");
+ctx.globalAlpha = 0.5;
+ctx.fillStyle = "rgb(85,85,85)";
+ctx.font = "20px serif";
+ctx.fillText("Hello world", 0, 50);
+</script>
+</body></html>
diff --git a/dom/canvas/test/reftest/filters/fillText-with-filter-grayscale-2.html b/dom/canvas/test/reftest/filters/fillText-with-filter-grayscale-2.html
new file mode 100644
index 0000000000..3abc4ae82a
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/fillText-with-filter-grayscale-2.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+var canvas = document.getElementById("canvas");
+var ctx = canvas.getContext("2d");
+ctx.globalAlpha = 0.5;
+ctx.fillStyle = "rgb(85,85,85)";
+ctx.filter = "grayscale(100%)";
+ctx.font = "20px serif";
+ctx.fillText("Hello world", 0, 50);
+</script>
+</body></html>
diff --git a/dom/canvas/test/reftest/filters/fillText-with-filter-opacity-1-ref.html b/dom/canvas/test/reftest/filters/fillText-with-filter-opacity-1-ref.html
new file mode 100644
index 0000000000..f471335c86
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/fillText-with-filter-opacity-1-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+var canvas = document.getElementById("canvas");
+var ctx = canvas.getContext("2d");
+ctx.globalAlpha = 0.5;
+ctx.fillStyle = "rgb(0,128,0)";
+ctx.font = "20px serif";
+ctx.fillText("Hello world", 0, 50);
+</script>
+</body></html>
diff --git a/dom/canvas/test/reftest/filters/fillText-with-filter-opacity-1.html b/dom/canvas/test/reftest/filters/fillText-with-filter-opacity-1.html
new file mode 100644
index 0000000000..898a3d9261
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/fillText-with-filter-opacity-1.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+var canvas = document.getElementById("canvas");
+var ctx = canvas.getContext("2d");
+ctx.fillStyle = "rgb(0,128,0)";
+ctx.filter = "opacity(0.5)";
+ctx.font = "20px serif";
+ctx.fillText("Hello world", 0, 50);
+</script>
+</body></html>
diff --git a/dom/canvas/test/reftest/filters/fillText-with-filter-opacity-2-ref.html b/dom/canvas/test/reftest/filters/fillText-with-filter-opacity-2-ref.html
new file mode 100644
index 0000000000..64762a3a67
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/fillText-with-filter-opacity-2-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+var canvas = document.getElementById("canvas");
+var ctx = canvas.getContext("2d");
+ctx.globalAlpha = 0.25;
+ctx.fillStyle = "rgb(0,255,0)";
+ctx.font = "20px serif";
+ctx.fillText("Hello world", 0, 50);
+</script>
+</body></html>
diff --git a/dom/canvas/test/reftest/filters/fillText-with-filter-opacity-2.html b/dom/canvas/test/reftest/filters/fillText-with-filter-opacity-2.html
new file mode 100644
index 0000000000..41c9c5c642
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/fillText-with-filter-opacity-2.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+var canvas = document.getElementById("canvas");
+var ctx = canvas.getContext("2d");
+ctx.globalAlpha = 0.5;
+ctx.fillStyle = "rgb(0,255,0)";
+ctx.filter = "opacity(0.5)";
+ctx.font = "20px serif";
+ctx.fillText("Hello world", 0, 50);
+</script>
+</body></html>
diff --git a/dom/canvas/test/reftest/filters/fillText-with-shadow-1.html b/dom/canvas/test/reftest/filters/fillText-with-shadow-1.html
new file mode 100644
index 0000000000..a84b2fe92d
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/fillText-with-shadow-1.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+var canvas = document.getElementById("canvas");
+var ctx = canvas.getContext("2d");
+ctx.shadowColor = "black";
+ctx.shadowBlur = 2;
+ctx.fillStyle = "green";
+ctx.font = "20px serif";
+ctx.fillText("Hello world", 0, 50);
+</script>
+</body></html>
diff --git a/dom/canvas/test/reftest/filters/fillText-with-shadow-2.html b/dom/canvas/test/reftest/filters/fillText-with-shadow-2.html
new file mode 100644
index 0000000000..17975bf37c
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/fillText-with-shadow-2.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+var canvas = document.getElementById("canvas");
+var ctx = canvas.getContext("2d");
+ctx.globalAlpha = 0.5;
+ctx.shadowColor = "black";
+ctx.shadowBlur = 2;
+ctx.fillStyle = "green";
+ctx.font = "20px serif";
+ctx.fillText("Hello world", 0, 50);
+</script>
+</body></html>
diff --git a/dom/canvas/test/reftest/filters/fillText-without-shadow-1-ref.html b/dom/canvas/test/reftest/filters/fillText-without-shadow-1-ref.html
new file mode 100644
index 0000000000..5d332e3f09
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/fillText-without-shadow-1-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+var canvas = document.getElementById("canvas");
+var ctx = canvas.getContext("2d");
+ctx.fillStyle = "green";
+ctx.font = "20px serif";
+ctx.fillText("Hello world", 0, 50);
+</script>
+</body></html>
diff --git a/dom/canvas/test/reftest/filters/fillText-without-shadow-2-ref.html b/dom/canvas/test/reftest/filters/fillText-without-shadow-2-ref.html
new file mode 100644
index 0000000000..9469175832
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/fillText-without-shadow-2-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+var canvas = document.getElementById("canvas");
+var ctx = canvas.getContext("2d");
+ctx.globalAlpha = 0.5;
+ctx.fillStyle = "green";
+ctx.font = "20px serif";
+ctx.fillText("Hello world", 0, 50);
+</script>
+</body></html>
diff --git a/dom/canvas/test/reftest/filters/global-alpha-ref.html b/dom/canvas/test/reftest/filters/global-alpha-ref.html
new file mode 100644
index 0000000000..2577581401
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/global-alpha-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<body>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+
+var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+
+ctx.globalAlpha = 0.5;
+ctx.fillStyle = '#000';
+ctx.fillRect(25, 35, 50, 40);
+ctx.fillStyle = '#0f0';
+ctx.fillRect(25, 25, 50, 40);
+
+</script>
+</body>
+</html>
diff --git a/dom/canvas/test/reftest/filters/global-alpha.html b/dom/canvas/test/reftest/filters/global-alpha.html
new file mode 100644
index 0000000000..8b6eb97520
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/global-alpha.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<body>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+
+var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+
+ctx.filter = 'drop-shadow(0 10px #000)';
+ctx.globalAlpha = 0.5;
+ctx.fillStyle = '#0f0';
+ctx.fillRect(25, 25, 50, 40);
+
+</script>
+</body>
+</html>
diff --git a/dom/canvas/test/reftest/filters/global-composite-operation-ref.html b/dom/canvas/test/reftest/filters/global-composite-operation-ref.html
new file mode 100644
index 0000000000..cad9089354
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/global-composite-operation-ref.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<body>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+
+var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+
+ctx.fillStyle = '#000';
+ctx.arc(50, 50, 25, 0, Math.PI * 2, true);
+ctx.fill();
+
+var tmp_canvas = canvas.cloneNode();
+var tmp_ctx = tmp_canvas.getContext('2d');
+tmp_ctx.fillStyle = '#0f0';
+tmp_ctx.fillRect(25, 25, 50, 50);
+tmp_ctx.fillStyle = '#000';
+tmp_ctx.fillRect(25, 65, 50, 10);
+
+ctx.globalCompositeOperation = 'source-in';
+ctx.drawImage(tmp_canvas, 0, 0);
+
+</script>
+</body>
+</html>
diff --git a/dom/canvas/test/reftest/filters/global-composite-operation.html b/dom/canvas/test/reftest/filters/global-composite-operation.html
new file mode 100644
index 0000000000..61a6f206a3
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/global-composite-operation.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<body>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+
+var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+
+ctx.fillStyle = '#000';
+ctx.arc(50, 50, 25, 0, Math.PI * 2, true);
+ctx.fill();
+
+ctx.filter = 'drop-shadow(0 10px black)';
+ctx.globalCompositeOperation = 'source-in';
+ctx.fillStyle = '#0f0';
+ctx.fillRect(25, 25, 50, 40);
+
+</script>
+</body>
+</html>
diff --git a/dom/canvas/test/reftest/filters/liveness-document-open.html b/dom/canvas/test/reftest/filters/liveness-document-open.html
new file mode 100644
index 0000000000..de31875e53
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/liveness-document-open.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html lang="en">
+<title>canvas filters: remove referenced filter element through document.open()</title>
+<body onload="loaded()">
+<canvas id="canvas" width="10" height="10"></canvas>
+<svg height="0">
+ <filter id="filter">
+ <feFlood flood-color="red"/>
+ </filter>
+</svg>
+<script>
+function loaded() {
+ var ctx = document.getElementById('canvas').getContext('2d');
+ ctx.filter = 'url(#filter)';
+ ctx.fillRect(0, 0, 10, 10); // do a draw first to work around bug 1287316
+ document.open();
+ // The document.open() call removed #filter from the document. So the filter
+ // reference should now be invalid, and the rect should be drawn without a
+ // filter applied, resulting in black.
+ ctx.fillRect(0, 0, 10, 10);
+ try {
+ var data = ctx.getImageData(0, 0, 1, 1).data;
+ if (data[0] == 0 && data[1] == 0 && data[2] == 0 && data[3] == 255) {
+ // Successfully painted black.
+ document.write('PASS');
+ } else {
+ // Painted something else, like red.
+ document.write('FAIL');
+ }
+ } catch (e) {
+ document.write('getImageData failed');
+ }
+ document.close();
+}
+</script>
diff --git a/dom/canvas/test/reftest/filters/liveness-document-removeChild.html b/dom/canvas/test/reftest/filters/liveness-document-removeChild.html
new file mode 100644
index 0000000000..acce9b8694
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/liveness-document-removeChild.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html lang="en">
+<title>canvas filters: remove referenced filter element through document.removeChild()</title>
+<body onload="loaded()">
+<canvas id="canvas" width="10" height="10"></canvas>
+<svg height="0">
+ <filter id="filter">
+ <feFlood flood-color="red"/>
+ </filter>
+</svg>
+<script>
+function loaded() {
+ var ctx = document.getElementById('canvas').getContext('2d');
+ ctx.filter = 'url(#filter)';
+ ctx.fillRect(0, 0, 10, 10); // do a draw first to work around bug 1287316
+ document.removeChild(document.documentElement);
+ // The document.removeChild() call removed #filter from the document. So the
+ // filter reference should now be invalid, and the rect should be drawn
+ // without a filter applied, resulting in black.
+ ctx.fillRect(0, 0, 10, 10);
+ try {
+ var data = ctx.getImageData(0, 0, 1, 1).data;
+ if (data[0] == 0 && data[1] == 0 && data[2] == 0 && data[3] == 255) {
+ // Successfully painted black.
+ document.write('PASS');
+ } else {
+ // Painted something else, like red.
+ document.write('FAIL');
+ }
+ } catch (e) {
+ document.write('getImageData failed');
+ }
+}
+</script>
diff --git a/dom/canvas/test/reftest/filters/liveness.html b/dom/canvas/test/reftest/filters/liveness.html
new file mode 100644
index 0000000000..1f3b75d78e
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/liveness.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<body>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+
+var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+
+ctx.font = '20px sans-serif';
+ctx.filter = 'drop-shadow(0 .5em black)';
+ctx.font = '10px sans-serif';
+ctx.fillStyle = '#0f0';
+ctx.fillRect(25, 25, 50, 40);
+
+</script>
+</body>
+</html>
diff --git a/dom/canvas/test/reftest/filters/multiple-drop-shadows.html b/dom/canvas/test/reftest/filters/multiple-drop-shadows.html
new file mode 100644
index 0000000000..f8d9261c65
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/multiple-drop-shadows.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<body>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+
+var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+
+ctx.fillStyle = '#0f0';
+ctx.filter = 'drop-shadow(0 10px black) drop-shadow(10px 0 #ccc)';
+ctx.fillRect(20, 25, 50, 40);
+
+</script>
+</body>
+</html>
diff --git a/dom/canvas/test/reftest/filters/ref.html b/dom/canvas/test/reftest/filters/ref.html
new file mode 100644
index 0000000000..bb634fe66d
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/ref.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<body>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+
+var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+
+ctx.fillStyle = '#0f0';
+ctx.fillRect(25, 25, 50, 40);
+ctx.fillStyle = '#000';
+ctx.fillRect(25, 65, 50, 10);
+
+</script>
+</body>
+</html>
diff --git a/dom/canvas/test/reftest/filters/reftest.list b/dom/canvas/test/reftest/filters/reftest.list
new file mode 100644
index 0000000000..c9990f5cc1
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/reftest.list
@@ -0,0 +1,32 @@
+defaults pref(canvas.filters.enabled,true)
+
+== default-color.html ref.html
+== drop-shadow.html ref.html
+== drop-shadow-transformed.html ref.html
+fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)||azureSkia,0-1,0-1500) == global-alpha.html global-alpha-ref.html
+== global-composite-operation.html global-composite-operation-ref.html
+== liveness.html ref.html
+== liveness-document-open.html data:text/html,PASS
+== liveness-document-removeChild.html data:text/html,PASS
+== multiple-drop-shadows.html shadow-ref.html
+== shadow.html shadow-ref.html
+== subregion-fill-paint.html subregion-ref.html
+== subregion-stroke-paint.html subregion-ref.html
+== svg-bbox.html svg-bbox-ref.html
+== svg-inline.html ref.html
+== svg-liveness.html ref.html
+== svg-off-screen.html ref.html
+== units.html ref.html
+== units-em.html ref.html
+== units-ex.html ref.html
+== units-off-screen.html ref.html
+fuzzy(0-2,0-700) == fillText-with-filter-opacity-1.html fillText-with-filter-opacity-1-ref.html
+fuzzy(0-1,0-302) == fillText-with-filter-opacity-2.html fillText-with-filter-opacity-2-ref.html
+fuzzy(0-1,0-600) fuzzy-if(d2d&&!swgl,0-36,0-15) == strokeText-with-filter-grayscale-1.html strokeText-with-filter-grayscale-1-ref.html
+fuzzy(0-1,0-600) == strokeText-with-filter-grayscale-2.html strokeText-with-filter-grayscale-2-ref.html
+!= fillText-with-shadow-1.html fillText-without-shadow-1-ref.html
+!= fillText-with-shadow-2.html fillText-without-shadow-2-ref.html
+fuzzy(0-1,0-400) == fillText-with-filter-grayscale-1.html fillText-with-filter-grayscale-1-ref.html
+fuzzy(0-1,0-400) == fillText-with-filter-grayscale-2.html fillText-with-filter-grayscale-2-ref.html
+!= strokeText-with-shadow-1.html strokeText-without-shadow-1-ref.html
+!= strokeText-with-shadow-2.html strokeText-without-shadow-2-ref.html
diff --git a/dom/canvas/test/reftest/filters/shadow-ref.html b/dom/canvas/test/reftest/filters/shadow-ref.html
new file mode 100644
index 0000000000..736c5f94dd
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/shadow-ref.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<body>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+
+var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+
+ctx.fillStyle = '#0f0';
+ctx.shadowOffsetX = 10;
+ctx.shadowColor = '#ccc';
+ctx.fillRect(20, 25, 50, 40);
+ctx.fillStyle = '#000';
+ctx.fillRect(20, 65, 50, 10);
+
+</script>
+</body>
+</html>
diff --git a/dom/canvas/test/reftest/filters/shadow.html b/dom/canvas/test/reftest/filters/shadow.html
new file mode 100644
index 0000000000..61de33bdc2
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/shadow.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<body>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+
+var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+
+ctx.fillStyle = '#0f0';
+ctx.filter = 'drop-shadow(0 10px black)';
+ctx.shadowOffsetX = 10;
+ctx.shadowColor = '#ccc';
+ctx.fillRect(20, 25, 50, 40);
+
+</script>
+</body>
+</html>
diff --git a/dom/canvas/test/reftest/filters/strokeText-with-filter-grayscale-1-ref.html b/dom/canvas/test/reftest/filters/strokeText-with-filter-grayscale-1-ref.html
new file mode 100644
index 0000000000..e576da6294
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/strokeText-with-filter-grayscale-1-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+var canvas = document.getElementById("canvas");
+var ctx = canvas.getContext("2d");
+ctx.strokeStyle = "rgb(85,85,85)";
+ctx.font = "20px serif";
+ctx.strokeText("Hello world", 0, 50);
+</script>
+</body></html>
diff --git a/dom/canvas/test/reftest/filters/strokeText-with-filter-grayscale-1.html b/dom/canvas/test/reftest/filters/strokeText-with-filter-grayscale-1.html
new file mode 100644
index 0000000000..76ef3271e6
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/strokeText-with-filter-grayscale-1.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+var canvas = document.getElementById("canvas");
+var ctx = canvas.getContext("2d");
+ctx.strokeStyle = "rgb(85,85,85)";
+ctx.filter = "grayscale(100%)";
+ctx.font = "20px serif";
+ctx.strokeText("Hello world", 0, 50);
+</script>
+</body></html>
diff --git a/dom/canvas/test/reftest/filters/strokeText-with-filter-grayscale-2-ref.html b/dom/canvas/test/reftest/filters/strokeText-with-filter-grayscale-2-ref.html
new file mode 100644
index 0000000000..e020ab205c
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/strokeText-with-filter-grayscale-2-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+var canvas = document.getElementById("canvas");
+var ctx = canvas.getContext("2d");
+ctx.globalAlpha = 0.5;
+ctx.strokeStyle = "rgb(85,85,85)";
+ctx.font = "20px serif";
+ctx.strokeText("Hello world", 0, 50);
+</script>
+</body></html>
diff --git a/dom/canvas/test/reftest/filters/strokeText-with-filter-grayscale-2.html b/dom/canvas/test/reftest/filters/strokeText-with-filter-grayscale-2.html
new file mode 100644
index 0000000000..60e3374980
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/strokeText-with-filter-grayscale-2.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+var canvas = document.getElementById("canvas");
+var ctx = canvas.getContext("2d");
+ctx.globalAlpha = 0.5;
+ctx.strokeStyle = "rgb(85,85,85)";
+ctx.filter = "grayscale(100%)";
+ctx.font = "20px serif";
+ctx.strokeText("Hello world", 0, 50);
+</script>
+</body></html>
diff --git a/dom/canvas/test/reftest/filters/strokeText-with-shadow-1.html b/dom/canvas/test/reftest/filters/strokeText-with-shadow-1.html
new file mode 100644
index 0000000000..6c7ecf137a
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/strokeText-with-shadow-1.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+var canvas = document.getElementById("canvas");
+var ctx = canvas.getContext("2d");
+ctx.shadowColor = "black";
+ctx.shadowBlur = 2;
+ctx.strokeStyle = "green";
+ctx.font = "20px serif";
+ctx.strokeText("Hello world", 0, 50);
+</script>
+</body></html>
diff --git a/dom/canvas/test/reftest/filters/strokeText-with-shadow-2.html b/dom/canvas/test/reftest/filters/strokeText-with-shadow-2.html
new file mode 100644
index 0000000000..3b8b8be478
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/strokeText-with-shadow-2.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+var canvas = document.getElementById("canvas");
+var ctx = canvas.getContext("2d");
+ctx.globalAlpha = 0.5;
+ctx.shadowColor = "black";
+ctx.shadowBlur = 2;
+ctx.strokeStyle = "green";
+ctx.font = "20px serif";
+ctx.strokeText("Hello world", 0, 50);
+</script>
+</body></html>
diff --git a/dom/canvas/test/reftest/filters/strokeText-without-shadow-1-ref.html b/dom/canvas/test/reftest/filters/strokeText-without-shadow-1-ref.html
new file mode 100644
index 0000000000..120cce9eb9
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/strokeText-without-shadow-1-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+var canvas = document.getElementById("canvas");
+var ctx = canvas.getContext("2d");
+ctx.strokeStyle = "green";
+ctx.font = "20px serif";
+ctx.strokeText("Hello world", 0, 50);
+</script>
+</body></html>
diff --git a/dom/canvas/test/reftest/filters/strokeText-without-shadow-2-ref.html b/dom/canvas/test/reftest/filters/strokeText-without-shadow-2-ref.html
new file mode 100644
index 0000000000..0892587a5e
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/strokeText-without-shadow-2-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+var canvas = document.getElementById("canvas");
+var ctx = canvas.getContext("2d");
+ctx.globalAlpha = 0.5;
+ctx.strokeStyle = "green";
+ctx.font = "20px serif";
+ctx.strokeText("Hello world", 0, 50);
+</script>
+</body></html>
diff --git a/dom/canvas/test/reftest/filters/subregion-fill-paint.html b/dom/canvas/test/reftest/filters/subregion-fill-paint.html
new file mode 100644
index 0000000000..854190359f
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/subregion-fill-paint.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<body>
+<svg style="display: block; width: 0; height: 0">
+ <defs>
+ <filter id="merge" primitiveUnits="objectBoundingBox">
+ <feMerge x="25%" y="25%" width="50%" height="50%">
+ <feMergeNode in="SourceGraphic"/>
+ <feMergeNode in="FillPaint"/>
+ </feMerge>
+ </filter>
+ </defs>
+</svg>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+
+var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+
+ctx.filter = 'url(#merge)';
+ctx.fillStyle = '#0f0';
+ctx.arc(50, 50, 25, 0, Math.PI * 2, true);
+ctx.fill();
+
+</script>
+</body>
+</html>
diff --git a/dom/canvas/test/reftest/filters/subregion-ref.html b/dom/canvas/test/reftest/filters/subregion-ref.html
new file mode 100644
index 0000000000..97b231b946
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/subregion-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<body>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+
+var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+
+ctx.fillStyle = '#0f0';
+ctx.fillRect(25, 25, 50, 50);
+
+</script>
+</body>
+</html>
diff --git a/dom/canvas/test/reftest/filters/subregion-stroke-paint.html b/dom/canvas/test/reftest/filters/subregion-stroke-paint.html
new file mode 100644
index 0000000000..24ed92a9be
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/subregion-stroke-paint.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<body>
+<svg style="display: block; width: 0; height: 0">
+ <defs>
+ <filter id="merge" primitiveUnits="objectBoundingBox">
+ <feMerge x="25%" y="25%" width="50%" height="50%">
+ <feMergeNode in="SourceGraphic"/>
+ <feMergeNode in="StrokePaint"/>
+ </feMerge>
+ </filter>
+ </defs>
+</svg>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+
+var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+
+ctx.filter = 'url(#merge)';
+ctx.strokeStyle = '#0f0';
+ctx.arc(50, 50, 25, 0, Math.PI * 2, true);
+ctx.fill();
+
+</script>
+</body>
+</html>
diff --git a/dom/canvas/test/reftest/filters/svg-bbox-ref.html b/dom/canvas/test/reftest/filters/svg-bbox-ref.html
new file mode 100644
index 0000000000..323cea948a
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/svg-bbox-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<body>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+
+var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+
+ctx.fillStyle = '#0f0';
+ctx.fillRect(0, 0, 100, 100);
+
+</script>
+</body>
+</html>
diff --git a/dom/canvas/test/reftest/filters/svg-bbox.html b/dom/canvas/test/reftest/filters/svg-bbox.html
new file mode 100644
index 0000000000..f25e26355d
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/svg-bbox.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<body>
+<svg style="display: block; width: 0; height: 0">
+ <defs>
+ <filter id="color-matrix">
+ <feColorMatrix type="matrix" in="SourceGraphic"
+ values="0 0 0 0 0
+ 0 0 0 0 255
+ 0 0 0 0 0
+ 0 0 0 0 255"/>
+ </filter>
+ </defs>
+</svg>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+
+var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+
+ctx.filter = 'url(#color-matrix)';
+ctx.fillStyle = '#fff';
+ctx.fillRect(25, 25, 50, 50);
+
+</script>
+</body>
+</html>
diff --git a/dom/canvas/test/reftest/filters/svg-inline.html b/dom/canvas/test/reftest/filters/svg-inline.html
new file mode 100644
index 0000000000..f9be99800a
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/svg-inline.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<body>
+<svg style="display: block; width: 0; height: 0">
+ <defs>
+ <filter id="drop-shadow">
+ <feGaussianBlur in="SourceAlpha" stdDeviation="0"/>
+ <feOffset dx="0" dy="10" result="offsetblur"/>
+ <feFlood flood-color="rgba(0,0,0,1)"/>
+ <feComposite in2="offsetblur" operator="in"/>
+ <feMerge>
+ <feMergeNode/>
+ <feMergeNode in="SourceGraphic"/>
+ </feMerge>
+ </filter>
+ </defs>
+</svg>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+
+var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+
+ctx.filter = 'url(#drop-shadow)';
+ctx.fillStyle = '#0f0';
+ctx.fillRect(25, 25, 50, 40);
+
+</script>
+</body>
+</html>
diff --git a/dom/canvas/test/reftest/filters/svg-liveness.html b/dom/canvas/test/reftest/filters/svg-liveness.html
new file mode 100644
index 0000000000..732fe7562f
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/svg-liveness.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script>
+
+var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
+svg.setAttribute('style', 'display: block; width: 0; height: 0');
+
+var defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs');
+
+var dropShadowFilter = document.createElementNS('http://www.w3.org/2000/svg', 'filter');
+dropShadowFilter.setAttribute('id', 'drop-shadow');
+
+var gaussianFilter = document.createElementNS('http://www.w3.org/2000/svg', 'feGaussianBlur');
+gaussianFilter.setAttribute('in', 'SourceAlpha');
+gaussianFilter.setAttribute('stdDeviation', '0');
+dropShadowFilter.appendChild(gaussianFilter);
+
+var offset = document.createElementNS('http://www.w3.org/2000/svg', 'feOffset');
+offset.setAttribute('dx', '0');
+offset.setAttribute('dy', '0');
+offset.setAttribute('result', 'offsetblur');
+dropShadowFilter.appendChild(offset);
+
+var flood = document.createElementNS('http://www.w3.org/2000/svg', 'feFlood');
+flood.setAttribute('flood-color', 'rgba(0,0,0,1)');
+dropShadowFilter.appendChild(flood);
+
+var composite = document.createElementNS('http://www.w3.org/2000/svg', 'feComposite');
+composite.setAttribute('in2', 'offsetblur');
+composite.setAttribute('operator', 'in');
+dropShadowFilter.appendChild(composite);
+
+var merge = document.createElementNS('http://www.w3.org/2000/svg', 'feMerge');
+var mergeNode = document.createElementNS('http://www.w3.org/2000/svg', 'feMergeNode');
+merge.appendChild(mergeNode);
+
+var mergeNode = document.createElementNS('http://www.w3.org/2000/svg', 'feMergeNode');
+mergeNode.setAttribute('in', 'SourceGraphic');
+merge.appendChild(mergeNode);
+dropShadowFilter.appendChild(merge);
+
+defs.appendChild(dropShadowFilter);
+svg.appendChild(defs);
+
+document.body.appendChild(svg);
+
+</script>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+
+var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+
+ctx.filter = 'url(#drop-shadow)';
+
+offset.setAttribute('dy', '10');
+
+ctx.fillStyle = '#0f0';
+ctx.fillRect(25, 25, 50, 40);
+
+</script>
+</body>
+</html>
diff --git a/dom/canvas/test/reftest/filters/svg-off-screen.html b/dom/canvas/test/reftest/filters/svg-off-screen.html
new file mode 100644
index 0000000000..1aa22cd990
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/svg-off-screen.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<body>
+<svg style="display: block; width: 0; height: 0">
+ <defs>
+ <filter id="drop-shadow">
+ <feGaussianBlur in="SourceAlpha" stdDeviation="0"/>
+ <feOffset dx="0" dy="10" result="offsetblur"/>
+ <feFlood flood-color="rgba(0,0,0,1)"/>
+ <feComposite in2="offsetblur" operator="in"/>
+ <feMerge>
+ <feMergeNode/>
+ <feMergeNode in="SourceGraphic"/>
+ </feMerge>
+ </filter>
+ </defs>
+</svg>
+<script>
+
+var canvas = document.createElement('canvas');
+canvas.width = 100;
+canvas.height = 100;
+var ctx = canvas.getContext('2d');
+
+ctx.filter = 'url(#drop-shadow)';
+ctx.fillStyle = '#0f0';
+ctx.fillRect(25, 25, 50, 40);
+
+document.body.appendChild(canvas);
+
+</script>
+</body>
+</html>
diff --git a/dom/canvas/test/reftest/filters/units-em.html b/dom/canvas/test/reftest/filters/units-em.html
new file mode 100644
index 0000000000..44f76dc4b4
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/units-em.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<body>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+
+var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+
+ctx.font = '20px sans-serif';
+ctx.filter = 'drop-shadow(0 .5em black)';
+ctx.fillStyle = '#0f0';
+ctx.fillRect(25, 25, 50, 40);
+
+canvas.style.fontSize = '5px';
+ctx.font = '4em sans-serif';
+ctx.filter = 'drop-shadow(0 .5em black)';
+
+</script>
+</body>
+</html>
diff --git a/dom/canvas/test/reftest/filters/units-ex.html b/dom/canvas/test/reftest/filters/units-ex.html
new file mode 100644
index 0000000000..3bf4fadd74
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/units-ex.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<body>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+
+var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+
+ctx.font = '10px sans-serif';
+ctx.filter = 'drop-shadow(0 2ex black)';
+ctx.fillStyle = '#0f0';
+ctx.fillRect(25, 25, 50, 40);
+
+</script>
+</body>
+</html>
diff --git a/dom/canvas/test/reftest/filters/units-off-screen.html b/dom/canvas/test/reftest/filters/units-off-screen.html
new file mode 100644
index 0000000000..879e575c10
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/units-off-screen.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script>
+
+var canvas = document.createElement('canvas');
+canvas.width = 500;
+canvas.height = 500;
+canvas.style.width = '100px';
+canvas.style.height = '100px';
+var ctx = canvas.getContext('2d');
+
+ctx.filter = 'drop-shadow(0 50px black)';
+ctx.fillStyle = '#0f0';
+ctx.fillRect(125, 125, 250, 200);
+
+document.body.appendChild(canvas);
+
+</script>
+</body>
+</html>
diff --git a/dom/canvas/test/reftest/filters/units-pt.html b/dom/canvas/test/reftest/filters/units-pt.html
new file mode 100644
index 0000000000..74fecb3d81
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/units-pt.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<body>
+<canvas id="canvas" width="100" height="100"></canvas>
+<script>
+
+var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+
+ctx.filter = 'drop-shadow(0 10mm black)';
+ctx.fillStyle = '#0f0';
+ctx.fillRect(25, 25, 50, 40);
+
+</script>
+</body>
+</html>
diff --git a/dom/canvas/test/reftest/filters/units.html b/dom/canvas/test/reftest/filters/units.html
new file mode 100644
index 0000000000..d12abdeb13
--- /dev/null
+++ b/dom/canvas/test/reftest/filters/units.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<body>
+<canvas id="canvas" width="500" height="500" style="width: 100px; height: 100px"></canvas>
+<script>
+
+var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+
+ctx.filter = 'drop-shadow(0 50px black)';
+ctx.fillStyle = '#0f0';
+ctx.fillRect(125, 125, 250, 200);
+
+</script>
+</body>
+</html>
diff --git a/dom/canvas/test/reftest/green.png b/dom/canvas/test/reftest/green.png
new file mode 100644
index 0000000000..348330a558
--- /dev/null
+++ b/dom/canvas/test/reftest/green.png
Binary files differ
diff --git a/dom/canvas/test/reftest/red_ref.png b/dom/canvas/test/reftest/red_ref.png
new file mode 100644
index 0000000000..487085a148
--- /dev/null
+++ b/dom/canvas/test/reftest/red_ref.png
Binary files differ
diff --git a/dom/canvas/test/reftest/red_tall.png b/dom/canvas/test/reftest/red_tall.png
new file mode 100644
index 0000000000..fdf5f4978b
--- /dev/null
+++ b/dom/canvas/test/reftest/red_tall.png
Binary files differ
diff --git a/dom/canvas/test/reftest/reftest.list b/dom/canvas/test/reftest/reftest.list
new file mode 100644
index 0000000000..fca1c1c490
--- /dev/null
+++ b/dom/canvas/test/reftest/reftest.list
@@ -0,0 +1,255 @@
+# Canvas Filter Reftests
+include filters/reftest.list
+include color_quads.list
+
+# WebGL Reftests!
+defaults pref(webgl.force-enabled,true) skip-if(Android)
+
+# Check that disabling works:
+ == webgl-disable-test.html?nogl wrapper.html?green.png
+pref(webgl.disabled,true) == webgl-disable-test.html wrapper.html?green.png
+
+# Basic WebGL tests:
+# Do we get pixels to the screen at all?
+# Neither of these should ever break.
+skip-if(Android) == webgl-clear-test.html wrapper.html?green.png
+skip-if(Android) == webgl-clear-test.html?readback wrapper.html?green.png
+
+# Make sure that our choice of attribs doesn't break rendering.
+skip-if(Android) == webgl-clear-test.html?depth wrapper.html?green.png
+skip-if(Android) == webgl-clear-test.html?stencil wrapper.html?green.png
+skip-if(Android) == webgl-clear-test.html?depth&stencil wrapper.html?green.png
+
+# Check that resize works:
+skip-if(Android) == webgl-resize-test.html wrapper.html?green.png
+
+# Check that captureStream() displays in a local video element
+skip-if(Android) == webgl-capturestream-test.html?preserve wrapper.html?green.png
+
+# Some of the failure conditions are a little weird. I'm (jgilbert) setting these based on
+# failures encountered when running on Try, and then targetting the Try config by
+# differences in the `sandbox` contents. That is, I'm labeling based on symptoms rather
+# than cause.
+# WinXP R: winWidget && layersGPUAccelerated && !d3d11
+# Win7+ R: winWidget && layersGPUAccelerated && d3d11
+# Win7+ Ru: winWidget && !layersGPUAccelerated && d3d11
+# (Note that we have to remove spaces when used below)
+
+# IMPORTANT: Expected outcomes are evaluated left-to-right, and they replace eachother.
+# That means that if an unconditional status (`fuzzy()`) is to the right of another status
+# (such as fails-if), it will overwrite the old status.
+#
+# As such, all unconditional statuses should be to the left of conditional statuses.
+# (See /layout/tools/reftest/reftest.js:945)
+
+# Does we draw the correct colors in the correct places?
+# Combinations: PowerSet([readback, aa, preserve, premult, alpha]) x [frame=1,frame=6]
+# This is 2^6 = 64 combinations.
+skip-if(Android) == webgl-color-test.html?frame=1&__&________&_______&_____ wrapper.html?colors-no-alpha.png
+skip-if(Android) == webgl-color-test.html?frame=1&aa&________&_______&_____ wrapper.html?colors-no-alpha.png
+skip-if(Android) == webgl-color-test.html?frame=1&__&preserve&_______&_____ wrapper.html?colors-no-alpha.png
+skip-if(Android) == webgl-color-test.html?frame=1&aa&preserve&_______&_____ wrapper.html?colors-no-alpha.png
+skip-if(Android) == webgl-color-test.html?frame=1&__&________&premult&_____ wrapper.html?colors-no-alpha.png
+skip-if(Android) == webgl-color-test.html?frame=1&aa&________&premult&_____ wrapper.html?colors-no-alpha.png
+skip-if(Android) == webgl-color-test.html?frame=1&__&preserve&premult&_____ wrapper.html?colors-no-alpha.png
+skip-if(Android) == webgl-color-test.html?frame=1&aa&preserve&premult&_____ wrapper.html?colors-no-alpha.png
+fuzzy(0-1,0-30000) skip-if(Android) == webgl-color-test.html?frame=1&__&________&_______&alpha wrapper.html?colors-non-premult.png
+fuzzy(0-1,0-30000) skip-if(Android) == webgl-color-test.html?frame=1&aa&________&_______&alpha wrapper.html?colors-non-premult.png
+fuzzy(0-1,0-30000) skip-if(Android) == webgl-color-test.html?frame=1&__&preserve&_______&alpha wrapper.html?colors-non-premult.png
+fuzzy(0-1,0-30000) skip-if(Android) == webgl-color-test.html?frame=1&aa&preserve&_______&alpha wrapper.html?colors-non-premult.png
+skip-if(Android) == webgl-color-test.html?frame=1&__&________&premult&alpha wrapper.html?colors-premult.png
+skip-if(Android) == webgl-color-test.html?frame=1&aa&________&premult&alpha wrapper.html?colors-premult.png
+skip-if(Android) == webgl-color-test.html?frame=1&__&preserve&premult&alpha wrapper.html?colors-premult.png
+skip-if(Android) == webgl-color-test.html?frame=1&aa&preserve&premult&alpha wrapper.html?colors-premult.png
+
+skip-if(Android) == webgl-color-test.html?frame=6&__&________&_______&_____ wrapper.html?colors-no-alpha.png
+skip-if(Android) == webgl-color-test.html?frame=6&aa&________&_______&_____ wrapper.html?colors-no-alpha.png
+skip-if(Android) == webgl-color-test.html?frame=6&__&preserve&_______&_____ wrapper.html?colors-no-alpha.png
+skip-if(Android) == webgl-color-test.html?frame=6&aa&preserve&_______&_____ wrapper.html?colors-no-alpha.png
+skip-if(Android) == webgl-color-test.html?frame=6&__&________&premult&_____ wrapper.html?colors-no-alpha.png
+skip-if(Android) == webgl-color-test.html?frame=6&aa&________&premult&_____ wrapper.html?colors-no-alpha.png
+skip-if(Android) == webgl-color-test.html?frame=6&__&preserve&premult&_____ wrapper.html?colors-no-alpha.png
+skip-if(Android) == webgl-color-test.html?frame=6&aa&preserve&premult&_____ wrapper.html?colors-no-alpha.png
+fuzzy(0-1,0-30000) skip-if(Android) == webgl-color-test.html?frame=6&__&________&_______&alpha wrapper.html?colors-non-premult.png
+fuzzy(0-1,0-30000) skip-if(Android) == webgl-color-test.html?frame=6&aa&________&_______&alpha wrapper.html?colors-non-premult.png
+fuzzy(0-1,0-30000) skip-if(Android) == webgl-color-test.html?frame=6&__&preserve&_______&alpha wrapper.html?colors-non-premult.png
+fuzzy(0-1,0-30000) skip-if(Android) == webgl-color-test.html?frame=6&aa&preserve&_______&alpha wrapper.html?colors-non-premult.png
+skip-if(Android) == webgl-color-test.html?frame=6&__&________&premult&alpha wrapper.html?colors-premult.png
+skip-if(Android) == webgl-color-test.html?frame=6&aa&________&premult&alpha wrapper.html?colors-premult.png
+skip-if(Android) == webgl-color-test.html?frame=6&__&preserve&premult&alpha wrapper.html?colors-premult.png
+skip-if(Android) == webgl-color-test.html?frame=6&aa&preserve&premult&alpha wrapper.html?colors-premult.png
+
+== webgl-color-test.html?frame=1&readback&__&________&_______&_____ wrapper.html?colors-no-alpha.png
+== webgl-color-test.html?frame=1&readback&aa&________&_______&_____ wrapper.html?colors-no-alpha.png
+== webgl-color-test.html?frame=1&readback&__&preserve&_______&_____ wrapper.html?colors-no-alpha.png
+== webgl-color-test.html?frame=1&readback&aa&preserve&_______&_____ wrapper.html?colors-no-alpha.png
+== webgl-color-test.html?frame=1&readback&__&________&premult&_____ wrapper.html?colors-no-alpha.png
+== webgl-color-test.html?frame=1&readback&aa&________&premult&_____ wrapper.html?colors-no-alpha.png
+== webgl-color-test.html?frame=1&readback&__&preserve&premult&_____ wrapper.html?colors-no-alpha.png
+== webgl-color-test.html?frame=1&readback&aa&preserve&premult&_____ wrapper.html?colors-no-alpha.png
+fuzzy(0-1,0-30000) == webgl-color-test.html?frame=1&readback&__&________&_______&alpha wrapper.html?colors-non-premult.png
+fuzzy(0-1,0-30000) == webgl-color-test.html?frame=1&readback&aa&________&_______&alpha wrapper.html?colors-non-premult.png
+fuzzy(0-1,0-30000) == webgl-color-test.html?frame=1&readback&__&preserve&_______&alpha wrapper.html?colors-non-premult.png
+fuzzy(0-1,0-30000) == webgl-color-test.html?frame=1&readback&aa&preserve&_______&alpha wrapper.html?colors-non-premult.png
+== webgl-color-test.html?frame=1&readback&__&________&premult&alpha wrapper.html?colors-premult.png
+== webgl-color-test.html?frame=1&readback&aa&________&premult&alpha wrapper.html?colors-premult.png
+== webgl-color-test.html?frame=1&readback&__&preserve&premult&alpha wrapper.html?colors-premult.png
+== webgl-color-test.html?frame=1&readback&aa&preserve&premult&alpha wrapper.html?colors-premult.png
+
+== webgl-color-test.html?frame=6&readback&__&________&_______&_____ wrapper.html?colors-no-alpha.png
+== webgl-color-test.html?frame=6&readback&aa&________&_______&_____ wrapper.html?colors-no-alpha.png
+== webgl-color-test.html?frame=6&readback&__&preserve&_______&_____ wrapper.html?colors-no-alpha.png
+== webgl-color-test.html?frame=6&readback&aa&preserve&_______&_____ wrapper.html?colors-no-alpha.png
+== webgl-color-test.html?frame=6&readback&__&________&premult&_____ wrapper.html?colors-no-alpha.png
+== webgl-color-test.html?frame=6&readback&aa&________&premult&_____ wrapper.html?colors-no-alpha.png
+== webgl-color-test.html?frame=6&readback&__&preserve&premult&_____ wrapper.html?colors-no-alpha.png
+== webgl-color-test.html?frame=6&readback&aa&preserve&premult&_____ wrapper.html?colors-no-alpha.png
+fuzzy(0-1,0-30000) == webgl-color-test.html?frame=6&readback&__&________&_______&alpha wrapper.html?colors-non-premult.png
+fuzzy(0-1,0-30000) == webgl-color-test.html?frame=6&readback&aa&________&_______&alpha wrapper.html?colors-non-premult.png
+fuzzy(0-1,0-30000) == webgl-color-test.html?frame=6&readback&__&preserve&_______&alpha wrapper.html?colors-non-premult.png
+fuzzy(0-1,0-30000) == webgl-color-test.html?frame=6&readback&aa&preserve&_______&alpha wrapper.html?colors-non-premult.png
+== webgl-color-test.html?frame=6&readback&__&________&premult&alpha wrapper.html?colors-premult.png
+== webgl-color-test.html?frame=6&readback&aa&________&premult&alpha wrapper.html?colors-premult.png
+== webgl-color-test.html?frame=6&readback&__&preserve&premult&alpha wrapper.html?colors-premult.png
+== webgl-color-test.html?frame=6&readback&aa&preserve&premult&alpha wrapper.html?colors-premult.png
+
+# OffscreenCanvas variant of the above.
+skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&__&________&_______&_____ wrapper.html?colors-no-alpha.png
+skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&aa&________&_______&_____ wrapper.html?colors-no-alpha.png
+skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&__&preserve&_______&_____ wrapper.html?colors-no-alpha.png
+skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&aa&preserve&_______&_____ wrapper.html?colors-no-alpha.png
+skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&__&________&premult&_____ wrapper.html?colors-no-alpha.png
+skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&aa&________&premult&_____ wrapper.html?colors-no-alpha.png
+skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&__&preserve&premult&_____ wrapper.html?colors-no-alpha.png
+skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&aa&preserve&premult&_____ wrapper.html?colors-no-alpha.png
+fuzzy(0-1,0-30000) skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&__&________&_______&alpha wrapper.html?colors-non-premult.png
+fuzzy(0-1,0-30000) skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&aa&________&_______&alpha wrapper.html?colors-non-premult.png
+fuzzy(0-1,0-30000) skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&__&preserve&_______&alpha wrapper.html?colors-non-premult.png
+fuzzy(0-1,0-30000) skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&aa&preserve&_______&alpha wrapper.html?colors-non-premult.png
+skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&__&________&premult&alpha wrapper.html?colors-premult.png
+skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&aa&________&premult&alpha wrapper.html?colors-premult.png
+skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&__&preserve&premult&alpha wrapper.html?colors-premult.png
+skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&aa&preserve&premult&alpha wrapper.html?colors-premult.png
+
+skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&__&________&_______&_____ wrapper.html?colors-no-alpha.png
+skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&aa&________&_______&_____ wrapper.html?colors-no-alpha.png
+skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&__&preserve&_______&_____ wrapper.html?colors-no-alpha.png
+skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&aa&preserve&_______&_____ wrapper.html?colors-no-alpha.png
+skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&__&________&premult&_____ wrapper.html?colors-no-alpha.png
+skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&aa&________&premult&_____ wrapper.html?colors-no-alpha.png
+skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&__&preserve&premult&_____ wrapper.html?colors-no-alpha.png
+skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&aa&preserve&premult&_____ wrapper.html?colors-no-alpha.png
+fuzzy(0-1,0-30000) skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&__&________&_______&alpha wrapper.html?colors-non-premult.png
+fuzzy(0-1,0-30000) skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&aa&________&_______&alpha wrapper.html?colors-non-premult.png
+fuzzy(0-1,0-30000) skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&__&preserve&_______&alpha wrapper.html?colors-non-premult.png
+fuzzy(0-1,0-30000) skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&aa&preserve&_______&alpha wrapper.html?colors-non-premult.png
+skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&__&________&premult&alpha wrapper.html?colors-premult.png
+skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&aa&________&premult&alpha wrapper.html?colors-premult.png
+skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&__&preserve&premult&alpha wrapper.html?colors-premult.png
+skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&aa&preserve&premult&alpha wrapper.html?colors-premult.png
+
+pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&readback&__&________&_______&_____ wrapper.html?colors-no-alpha.png
+pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&readback&aa&________&_______&_____ wrapper.html?colors-no-alpha.png
+pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&readback&__&preserve&_______&_____ wrapper.html?colors-no-alpha.png
+pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&readback&aa&preserve&_______&_____ wrapper.html?colors-no-alpha.png
+pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&readback&__&________&premult&_____ wrapper.html?colors-no-alpha.png
+pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&readback&aa&________&premult&_____ wrapper.html?colors-no-alpha.png
+pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&readback&__&preserve&premult&_____ wrapper.html?colors-no-alpha.png
+pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&readback&aa&preserve&premult&_____ wrapper.html?colors-no-alpha.png
+fuzzy(0-1,0-30000) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&readback&__&________&_______&alpha wrapper.html?colors-non-premult.png
+fuzzy(0-1,0-30000) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&readback&aa&________&_______&alpha wrapper.html?colors-non-premult.png
+fuzzy(0-1,0-30000) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&readback&__&preserve&_______&alpha wrapper.html?colors-non-premult.png
+fuzzy(0-1,0-30000) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&readback&aa&preserve&_______&alpha wrapper.html?colors-non-premult.png
+pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&readback&__&________&premult&alpha wrapper.html?colors-premult.png
+pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&readback&aa&________&premult&alpha wrapper.html?colors-premult.png
+pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&readback&__&preserve&premult&alpha wrapper.html?colors-premult.png
+pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&readback&aa&preserve&premult&alpha wrapper.html?colors-premult.png
+
+pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&readback&__&________&_______&_____ wrapper.html?colors-no-alpha.png
+pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&readback&aa&________&_______&_____ wrapper.html?colors-no-alpha.png
+pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&readback&__&preserve&_______&_____ wrapper.html?colors-no-alpha.png
+pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&readback&aa&preserve&_______&_____ wrapper.html?colors-no-alpha.png
+pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&readback&__&________&premult&_____ wrapper.html?colors-no-alpha.png
+pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&readback&aa&________&premult&_____ wrapper.html?colors-no-alpha.png
+pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&readback&__&preserve&premult&_____ wrapper.html?colors-no-alpha.png
+pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&readback&aa&preserve&premult&_____ wrapper.html?colors-no-alpha.png
+fuzzy(0-1,0-30000) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&readback&__&________&_______&alpha wrapper.html?colors-non-premult.png
+fuzzy(0-1,0-30000) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&readback&aa&________&_______&alpha wrapper.html?colors-non-premult.png
+fuzzy(0-1,0-30000) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&readback&__&preserve&_______&alpha wrapper.html?colors-non-premult.png
+fuzzy(0-1,0-30000) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&readback&aa&preserve&_______&alpha wrapper.html?colors-non-premult.png
+pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&readback&__&________&premult&alpha wrapper.html?colors-premult.png
+pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&readback&aa&________&premult&alpha wrapper.html?colors-premult.png
+pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&readback&__&preserve&premult&alpha wrapper.html?colors-premult.png
+pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&readback&aa&preserve&premult&alpha wrapper.html?colors-premult.png
+
+
+# Check for hanging bindings/state settings:
+skip-if(Android) == webgl-hanging-fb-test.html?__&________ wrapper.html?green.png
+skip-if(Android) == webgl-hanging-fb-test.html?aa&________ wrapper.html?green.png
+skip-if(Android) == webgl-hanging-fb-test.html?__&preserve wrapper.html?green.png
+skip-if(Android) == webgl-hanging-fb-test.html?aa&preserve wrapper.html?green.png
+== webgl-hanging-fb-test.html?readback&__&________ wrapper.html?green.png
+== webgl-hanging-fb-test.html?readback&aa&________ wrapper.html?green.png
+== webgl-hanging-fb-test.html?readback&__&preserve wrapper.html?green.png
+== webgl-hanging-fb-test.html?readback&aa&preserve wrapper.html?green.png
+
+skip-if(Android) == webgl-hanging-scissor-test.html?__ wrapper.html?green.png
+skip-if(Android) == webgl-hanging-scissor-test.html?aa wrapper.html?green.png
+== webgl-hanging-scissor-test.html?readback&__ wrapper.html?green.png
+== webgl-hanging-scissor-test.html?readback&aa wrapper.html?green.png
+
+
+# Check that our experimental prefs still work:
+
+# 16bpp for Android: [16bpp] * PowerSet([readback, premult, alpha])
+# RGB565 dithers 127 to [123,132]. (Max error: 5)
+# RGBA4444 dithers 128 to [119,136], and 191 to [192]. (Max error: 9)
+# Bug 1285531 - tests disabled for memory corruption
+fuzzy(0-5,0-30000) skip pref(webgl.prefer-16bpp,true) == webgl-color-test.html?16bpp&________&_______&_____ wrapper.html?colors-no-alpha.png
+fuzzy(0-5,0-30000) skip pref(webgl.prefer-16bpp,true) == webgl-color-test.html?16bpp&readback&_______&_____ wrapper.html?colors-no-alpha.png
+fuzzy(0-5,0-30000) skip pref(webgl.prefer-16bpp,true) == webgl-color-test.html?16bpp&________&premult&_____ wrapper.html?colors-no-alpha.png
+fuzzy(0-5,0-30000) skip pref(webgl.prefer-16bpp,true) == webgl-color-test.html?16bpp&readback&premult&_____ wrapper.html?colors-no-alpha.png
+fuzzy(0-9,0-40000) skip pref(webgl.prefer-16bpp,true) == webgl-color-test.html?16bpp&________&_______&alpha wrapper.html?colors-non-premult.png
+fuzzy(0-9,0-40000) skip pref(webgl.prefer-16bpp,true) == webgl-color-test.html?16bpp&readback&_______&alpha wrapper.html?colors-non-premult.png
+fuzzy(0-9,0-40000) skip pref(webgl.prefer-16bpp,true) == webgl-color-test.html?16bpp&________&premult&alpha wrapper.html?colors-premult.png
+fuzzy(0-9,0-40000) skip pref(webgl.prefer-16bpp,true) == webgl-color-test.html?16bpp&readback&premult&alpha wrapper.html?colors-premult.png
+
+# Force native GL (Windows):
+skip pref(webgl.disable-angle,true) == webgl-color-test.html?native-gl wrapper.html?colors-no-alpha.png
+
+
+# ----------------------------------------------------------------------
+# Non-WebGL Reftests!
+
+
+# Do we correctly handle multiple clip paths?
+!= clip-multiple-paths.html clip-multiple-paths-badref.html
+
+# Bug 1255062
+== clip-multiple-move-1.html clip-multiple-move-1-ref.html
+fuzzy(0-1,0-150) == clip-multiple-move-2.html clip-multiple-move-2-ref.html
+
+# Bug 815648
+== stroketext-shadow.html stroketext-shadow-ref.html
+
+# focus rings
+pref(canvas.focusring.enabled,true) fuzzy(0-1,0-2) skip-if(cocoaWidget||winWidget||gtkWidget) needs-focus == drawFocusIfNeeded.html drawFocusIfNeeded-ref.html
+
+# Check that captureStream() displays in a local video element
+== capturestream.html wrapper.html?green.png
+
+fuzzy-if(azureSkia,0-16,0-20) fuzzy-if(Android,0-3,0-40) fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-1,0-1) == 1177726-text-stroke-bounds.html 1177726-text-stroke-bounds-ref.html
+
+# Bug 1366027
+== clipped-dash-stroke-rect.html clipped-dash-stroke-rect-ref.html
+
+# Bug 1377303
+skip-if(Android) == visible-occluded.html visible-occluded-ref.html
+
+== 1678909-1.html 1678909-1-ref.html
+== 1719886-1.html 1719886-1-ref.html
+
+skip-if(isDebugBuild) == draw-large-image.html draw-large-image-ref.html
+
+== 1758968-1.html 1758968-1-ref.html
+== 1768521-1.html 1768521-1-ref.html
diff --git a/dom/canvas/test/reftest/stroketext-shadow-ref.html b/dom/canvas/test/reftest/stroketext-shadow-ref.html
new file mode 100644
index 0000000000..1a77caaaa5
--- /dev/null
+++ b/dom/canvas/test/reftest/stroketext-shadow-ref.html
@@ -0,0 +1,19 @@
+<!--docytpe html-->
+<html><head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<meta charset="UTF-8">
+<script>
+window.onload=function(){
+c=document.getElementById("myCanvas").getContext("2d");
+c.canvas.width=c.canvas.width;
+c.font="35px sans-serif";
+c.shadowColor="darkblue";
+c.shadowBlur=2;
+c.strokeText('ABCDEF',20,100);
+}
+</script>
+</head>
+<body>
+<canvas id="myCanvas" height="500" width="500" style="border:1px solid black"></canvas>
+
+</body></html>
diff --git a/dom/canvas/test/reftest/stroketext-shadow.html b/dom/canvas/test/reftest/stroketext-shadow.html
new file mode 100644
index 0000000000..acfa8d8929
--- /dev/null
+++ b/dom/canvas/test/reftest/stroketext-shadow.html
@@ -0,0 +1,20 @@
+<!--docytpe html-->
+<html><head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<meta charset="UTF-8">
+<script>
+window.onload=function(){
+c=document.getElementById("myCanvas").getContext("2d");
+c.canvas.width=c.canvas.width;
+c.font="35px sans-serif";
+c.shadowColor="darkblue";
+c.shadowBlur=2;
+c.moveTo(20,20);
+c.strokeText('ABCDEF',20,100);
+}
+</script>
+</head>
+<body>
+<canvas id="myCanvas" height="500" width="500" style="border:1px solid black"></canvas>
+
+</body></html>
diff --git a/dom/canvas/test/reftest/visible-occluded-ref.html b/dom/canvas/test/reftest/visible-occluded-ref.html
new file mode 100644
index 0000000000..d5a5853165
--- /dev/null
+++ b/dom/canvas/test/reftest/visible-occluded-ref.html
@@ -0,0 +1,127 @@
+<!DOCTYPE html>
+<meta charset='UTF-8'>
+<!--
+Color Test
+
+Clear the four quadrants of the canvas as follows:
++------+------+
+| blue |black |
+| | |
++------+------+
+| red |green |
+| | |
++------+------+
+
+Clear with a given alpha value. What effect this has depends on the
+context-creation args passed to this page.
+-->
+<html class='reftest-wait'>
+
+<head>
+ <script type='text/javascript' src='webgl-utils.js'></script>
+ <script type='text/javascript'>
+'use strict';
+
+var COLOR_VALUE = 127.0 / 255.0;
+var ALPHA_VALUE = 127.0 / 255.0;
+
+function renderFrame(gl) {
+ gl.enable(gl.SCISSOR_TEST);
+
+ gl.scissor(0, 0, 100, 100);
+ gl.clearColor(COLOR_VALUE, 0.0, 0.0, ALPHA_VALUE);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ gl.scissor(100, 0, 100, 100);
+ gl.clearColor(0.0, COLOR_VALUE, 0.0, ALPHA_VALUE);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ gl.scissor(0, 100, 100, 100);
+ gl.clearColor(0.0, 0.0, COLOR_VALUE, ALPHA_VALUE);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ gl.scissor(100, 100, 100, 100);
+ gl.clearColor(0.0, 0.0, 0.0, ALPHA_VALUE);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ gl.scissor(0, 75, 50, 50);
+ gl.clearColor(0.0, 0.0, 1.0, 1.0);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Boilerplate
+
+var TIMEOUT_MS = 30 * 1000;
+
+function setStatus(text) {
+ var elem = document.getElementById('status');
+ elem.innerHTML = text;
+}
+
+var gIsComplete = false;
+
+function markComplete(statusText) {
+ if (!statusText)
+ statusText = '';
+
+ if (gIsComplete)
+ return;
+ gIsComplete = true;
+
+ setStatus(statusText);
+ document.documentElement.removeAttribute('class');
+}
+
+function markError(text) {
+ markComplete('Error: ' + text);
+}
+
+function markTimedOut() {
+ markError('Timed out waiting on test completion.');
+}
+
+function runFrame(gl, frameCount, maxFrameCount) {
+ renderFrame(gl);
+ frameCount++;
+
+ if (frameCount >= maxFrameCount) {
+ console.log('Rendered ' + frameCount + ' frames.');
+ markComplete();
+ return;
+ }
+
+ requestAnimationFrame(function(){
+ runFrame(gl, frameCount, maxFrameCount);
+ });
+}
+
+function runTest() {
+ var canvas = document.getElementById('canvas');
+
+ var gl = initGL(canvas);
+ if (!gl) {
+ markError('WebGL context creation failed.');
+ return;
+ }
+
+ var maxFrameCount = arg('frame', 1);
+ if (maxFrameCount < 1) {
+ markError('Invalid `frame` arg: ' + maxFrameCount);
+ return;
+ }
+
+ setStatus('Waiting...');
+
+ runFrame(gl, 0, maxFrameCount);
+ setTimeout(markTimedOut, TIMEOUT_MS);
+}
+ </script>
+</head>
+
+<body onload='runTest();'>
+<canvas style="position:fixed; left: 0px; top: 0px;" id='canvas' width='200' height='200'></canvas>
+<div id='status'></div>
+</body>
+
+</html>
diff --git a/dom/canvas/test/reftest/visible-occluded.html b/dom/canvas/test/reftest/visible-occluded.html
new file mode 100644
index 0000000000..6beae5f132
--- /dev/null
+++ b/dom/canvas/test/reftest/visible-occluded.html
@@ -0,0 +1,124 @@
+<!DOCTYPE html>
+<meta charset='UTF-8'>
+<!--
+Color Test
+
+Clear the four quadrants of the canvas as follows:
++------+------+
+| blue |black |
+| | |
++------+------+
+| red |green |
+| | |
++------+------+
+
+Clear with a given alpha value. What effect this has depends on the
+context-creation args passed to this page.
+-->
+<html class='reftest-wait'>
+
+<head>
+ <script type='text/javascript' src='webgl-utils.js'></script>
+ <script type='text/javascript'>
+'use strict';
+
+var COLOR_VALUE = 127.0 / 255.0;
+var ALPHA_VALUE = 127.0 / 255.0;
+
+function renderFrame(gl) {
+ gl.enable(gl.SCISSOR_TEST);
+
+ gl.scissor(0, 0, 100, 100);
+ gl.clearColor(COLOR_VALUE, 0.0, 0.0, ALPHA_VALUE);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ gl.scissor(100, 0, 100, 100);
+ gl.clearColor(0.0, COLOR_VALUE, 0.0, ALPHA_VALUE);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ gl.scissor(0, 100, 100, 100);
+ gl.clearColor(0.0, 0.0, COLOR_VALUE, ALPHA_VALUE);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ gl.scissor(100, 100, 100, 100);
+ gl.clearColor(0.0, 0.0, 0.0, ALPHA_VALUE);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Boilerplate
+
+var TIMEOUT_MS = 30 * 1000;
+
+function setStatus(text) {
+ var elem = document.getElementById('status');
+ elem.innerHTML = text;
+}
+
+var gIsComplete = false;
+
+function markComplete(statusText) {
+ if (!statusText)
+ statusText = '';
+
+ if (gIsComplete)
+ return;
+ gIsComplete = true;
+
+ setStatus(statusText);
+ document.documentElement.removeAttribute('class');
+}
+
+function markError(text) {
+ markComplete('Error: ' + text);
+}
+
+function markTimedOut() {
+ markError('Timed out waiting on test completion.');
+}
+
+function runFrame(gl, frameCount, maxFrameCount) {
+ renderFrame(gl);
+ frameCount++;
+
+ if (frameCount >= maxFrameCount) {
+ console.log('Rendered ' + frameCount + ' frames.');
+ markComplete();
+ return;
+ }
+
+ requestAnimationFrame(function(){
+ runFrame(gl, frameCount, maxFrameCount);
+ });
+}
+
+function runTest() {
+ var canvas = document.getElementById('canvas');
+
+ var gl = initGL(canvas);
+ if (!gl) {
+ markError('WebGL context creation failed.');
+ return;
+ }
+
+ var maxFrameCount = arg('frame', 1);
+ if (maxFrameCount < 1) {
+ markError('Invalid `frame` arg: ' + maxFrameCount);
+ return;
+ }
+
+ setStatus('Waiting...');
+
+ runFrame(gl, 0, maxFrameCount);
+ setTimeout(markTimedOut, TIMEOUT_MS);
+}
+ </script>
+</head>
+
+<body onload='runTest();'>
+<canvas style="position:fixed; left: 0px; top: 0px;" id='canvas' width='200' height='200'></canvas>
+<div style="display:block; background-color: blue; position: fixed; top: 75px; left: 0px; width: 50px; height: 50px;"></div>
+<div id='status'></div>
+</body>
+
+</html>
diff --git a/dom/canvas/test/reftest/webgl-capturestream-test.html b/dom/canvas/test/reftest/webgl-capturestream-test.html
new file mode 100644
index 0000000000..efd343702e
--- /dev/null
+++ b/dom/canvas/test/reftest/webgl-capturestream-test.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<meta charset='UTF-8'>
+<!--
+Clear the canvas to green and capture it to a stream to test that we can get
+the stream to screen in a local video element.
+-->
+<html class="reftest-wait">
+
+<head>
+ <script type='text/javascript' src='webgl-utils.js'></script>
+ <script type='text/javascript'>
+'use strict';
+
+function setStatus(text) {
+ var elem = document.getElementById('status');
+ elem.innerHTML = text;
+}
+
+function finished() {
+ document.documentElement.removeAttribute("class");
+}
+
+function runTest() {
+ var canvas = document.getElementById('canvas');
+
+ var gl = initGL(canvas);
+ if (!gl) {
+ setStatus('WebGL context creation failed.');
+ return;
+ }
+
+ gl.clearColor(0.0, 1.0, 0.0, 1.0);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ var video = document.getElementById('video');
+ video.srcObject = canvas.captureStream(0);
+ video.play();
+ video.onloadeddata = finished;
+ video.onerror = finished;
+}
+ </script>
+</head>
+
+<body onload='runTest();'>
+ <video id='video' width='256' height='256'></video>
+ <canvas id='canvas' width='256' height='256' style="display:none"></canvas>
+ <div id='status'></div>
+</body>
+
+</html>
diff --git a/dom/canvas/test/reftest/webgl-clear-test.html b/dom/canvas/test/reftest/webgl-clear-test.html
new file mode 100644
index 0000000000..9be310c8ac
--- /dev/null
+++ b/dom/canvas/test/reftest/webgl-clear-test.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<meta charset='UTF-8'>
+<!--
+Clear the canvas to green to test that we get pixels to the screen.
+
+If this fails, something is seriously wrong.
+-->
+<html>
+
+<head>
+ <script type='text/javascript' src='webgl-utils.js'></script>
+ <script type='text/javascript'>
+'use strict';
+
+function setStatus(text) {
+ var elem = document.getElementById('status');
+ elem.innerHTML = text;
+}
+
+function runTest() {
+ var canvas = document.getElementById('canvas');
+
+ var gl = initGL(canvas);
+ if (!gl) {
+ setStatus('WebGL context creation failed.');
+ return;
+ }
+
+ gl.clearColor(0.0, 1.0, 0.0, 1.0);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+}
+ </script>
+</head>
+
+<body onload='runTest();'>
+ <canvas id='canvas' width='256' height='256'></canvas>
+ <div id='status'></div>
+</body>
+
+</html>
diff --git a/dom/canvas/test/reftest/webgl-color-offscreen-test.html b/dom/canvas/test/reftest/webgl-color-offscreen-test.html
new file mode 100644
index 0000000000..517a34e6f5
--- /dev/null
+++ b/dom/canvas/test/reftest/webgl-color-offscreen-test.html
@@ -0,0 +1,124 @@
+<!DOCTYPE html>
+<meta charset='UTF-8'>
+<!--
+Color Test
+
+Clear the four quadrants of the canvas as follows:
++------+------+
+| blue |black |
+| | |
++------+------+
+| red |green |
+| | |
++------+------+
+
+Clear with a given alpha value. What effect this has depends on the
+context-creation args passed to this page.
+-->
+<html class='reftest-wait'>
+
+<head>
+ <script type='text/javascript' src='webgl-utils.js'></script>
+ <script type='text/javascript'>
+'use strict';
+
+var COLOR_VALUE = 127.0 / 255.0;
+var ALPHA_VALUE = 127.0 / 255.0;
+
+function renderFrame(gl) {
+ gl.enable(gl.SCISSOR_TEST);
+
+ gl.scissor(0, 0, 100, 100);
+ gl.clearColor(COLOR_VALUE, 0.0, 0.0, ALPHA_VALUE);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ gl.scissor(100, 0, 100, 100);
+ gl.clearColor(0.0, COLOR_VALUE, 0.0, ALPHA_VALUE);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ gl.scissor(0, 100, 100, 100);
+ gl.clearColor(0.0, 0.0, COLOR_VALUE, ALPHA_VALUE);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ gl.scissor(100, 100, 100, 100);
+ gl.clearColor(0.0, 0.0, 0.0, ALPHA_VALUE);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Boilerplate
+
+var TIMEOUT_MS = 30 * 1000;
+
+function setStatus(text) {
+ var elem = document.getElementById('status');
+ elem.innerHTML = text;
+}
+
+var gIsComplete = false;
+
+function markComplete(statusText) {
+ if (!statusText)
+ statusText = '';
+
+ if (gIsComplete)
+ return;
+ gIsComplete = true;
+
+ setStatus(statusText);
+ document.documentElement.removeAttribute('class');
+}
+
+function markError(text) {
+ markComplete('Error: ' + text);
+}
+
+function markTimedOut() {
+ markError('Timed out waiting on test completion.');
+}
+
+function runFrame(gl, frameCount, maxFrameCount) {
+ renderFrame(gl);
+ frameCount++;
+
+ if (frameCount >= maxFrameCount) {
+ console.log('Rendered ' + frameCount + ' frames.');
+ markComplete();
+ return;
+ }
+
+ requestAnimationFrame(function(){
+ runFrame(gl, frameCount, maxFrameCount);
+ });
+}
+
+function runTest() {
+ var canvas = document.getElementById('canvas');
+ var offscreenCanvas = canvas.transferControlToOffscreen();
+
+ var gl = initGL(offscreenCanvas);
+ if (!gl) {
+ markError('WebGL context creation failed.');
+ return;
+ }
+
+ var maxFrameCount = arg('frame', 1);
+ if (maxFrameCount < 1) {
+ markError('Invalid `frame` arg: ' + maxFrameCount);
+ return;
+ }
+
+ setStatus('Waiting...');
+
+ runFrame(gl, 0, maxFrameCount);
+ setTimeout(markTimedOut, TIMEOUT_MS);
+}
+ </script>
+</head>
+
+<body onload='runTest();'>
+ <canvas id='canvas' width='200' height='200'></canvas>
+ <div id='status'></div>
+</body>
+
+</html>
diff --git a/dom/canvas/test/reftest/webgl-color-test.html b/dom/canvas/test/reftest/webgl-color-test.html
new file mode 100644
index 0000000000..acbddd806a
--- /dev/null
+++ b/dom/canvas/test/reftest/webgl-color-test.html
@@ -0,0 +1,123 @@
+<!DOCTYPE html>
+<meta charset='UTF-8'>
+<!--
+Color Test
+
+Clear the four quadrants of the canvas as follows:
++------+------+
+| blue |black |
+| | |
++------+------+
+| red |green |
+| | |
++------+------+
+
+Clear with a given alpha value. What effect this has depends on the
+context-creation args passed to this page.
+-->
+<html class='reftest-wait'>
+
+<head>
+ <script type='text/javascript' src='webgl-utils.js'></script>
+ <script type='text/javascript'>
+'use strict';
+
+var COLOR_VALUE = 127.0 / 255.0;
+var ALPHA_VALUE = 127.0 / 255.0;
+
+function renderFrame(gl) {
+ gl.enable(gl.SCISSOR_TEST);
+
+ gl.scissor(0, 0, 100, 100);
+ gl.clearColor(COLOR_VALUE, 0.0, 0.0, ALPHA_VALUE);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ gl.scissor(100, 0, 100, 100);
+ gl.clearColor(0.0, COLOR_VALUE, 0.0, ALPHA_VALUE);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ gl.scissor(0, 100, 100, 100);
+ gl.clearColor(0.0, 0.0, COLOR_VALUE, ALPHA_VALUE);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ gl.scissor(100, 100, 100, 100);
+ gl.clearColor(0.0, 0.0, 0.0, ALPHA_VALUE);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Boilerplate
+
+var TIMEOUT_MS = 30 * 1000;
+
+function setStatus(text) {
+ var elem = document.getElementById('status');
+ elem.innerHTML = text;
+}
+
+var gIsComplete = false;
+
+function markComplete(statusText) {
+ if (!statusText)
+ statusText = '';
+
+ if (gIsComplete)
+ return;
+ gIsComplete = true;
+
+ setStatus(statusText);
+ document.documentElement.removeAttribute('class');
+}
+
+function markError(text) {
+ markComplete('Error: ' + text);
+}
+
+function markTimedOut() {
+ markError('Timed out waiting on test completion.');
+}
+
+function runFrame(gl, frameCount, maxFrameCount) {
+ renderFrame(gl);
+ frameCount++;
+
+ if (frameCount >= maxFrameCount) {
+ console.log('Rendered ' + frameCount + ' frames.');
+ markComplete();
+ return;
+ }
+
+ requestAnimationFrame(function(){
+ runFrame(gl, frameCount, maxFrameCount);
+ });
+}
+
+function runTest() {
+ var canvas = document.getElementById('canvas');
+
+ var gl = initGL(canvas);
+ if (!gl) {
+ markError('WebGL context creation failed.');
+ return;
+ }
+
+ var maxFrameCount = arg('frame', 1);
+ if (maxFrameCount < 1) {
+ markError('Invalid `frame` arg: ' + maxFrameCount);
+ return;
+ }
+
+ setStatus('Waiting...');
+
+ runFrame(gl, 0, maxFrameCount);
+ setTimeout(markTimedOut, TIMEOUT_MS);
+}
+ </script>
+</head>
+
+<body onload='runTest();'>
+ <canvas id='canvas' width='200' height='200'></canvas>
+ <div id='status'></div>
+</body>
+
+</html>
diff --git a/dom/canvas/test/reftest/webgl-disable-test.html b/dom/canvas/test/reftest/webgl-disable-test.html
new file mode 100644
index 0000000000..30581ec255
--- /dev/null
+++ b/dom/canvas/test/reftest/webgl-disable-test.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="UTF-8">
+
+<script type="text/javascript" src="webgl-utils.js"></script>
+<script type="text/javascript">
+/* Disable Test
+ *
+ * If we succeed in getting a WebGL context, we will fill
+ * the canvas with red. If we fail to acquire a WebGL context,
+ * we will use Canvas2D to instead fill it with green.
+ *
+ * Note that this test differs from the others in that
+ * it will draw differently if it receives a WebGL context.
+ * Other tests are designed to fallback silently to Canvas2D.
+ *
+ * We use this test to assure that when we disable WebGL,
+ * WebGL does not function. This is trivially true for systems
+ * that don't support WebGL. This test is not viable for testing
+ * that WebGL works, as blocklisted systems will always draw green.
+ */
+
+"use strict";
+
+function renderGL(gl) {
+ gl.clearColor(1.0, 0.0, 0.0, 1.0);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ gl.finish();
+}
+
+function renderBackup(canvas) {
+ var context = canvas.getContext("2d");
+ context.fillStyle = "rgba(0, 255, 0, 1.0)";
+ context.fillRect(0, 0, 256, 256);
+}
+
+function runTest() {
+ var canvas = document.getElementById("canvas");
+ var gl = initGL(canvas);
+
+ if (gl)
+ renderGL(gl);
+ else
+ renderBackup(canvas);
+
+ waitForComposite(testComplete);
+}
+
+function testComplete() {
+ document.documentElement.removeAttribute("class");
+}
+</script>
+</head>
+
+<body onload="rAF(runTest);">
+ <canvas id="canvas" width="256" height="256"></canvas>
+</body>
+
+</html>
diff --git a/dom/canvas/test/reftest/webgl-hanging-fb-test.html b/dom/canvas/test/reftest/webgl-hanging-fb-test.html
new file mode 100644
index 0000000000..3f950d8295
--- /dev/null
+++ b/dom/canvas/test/reftest/webgl-hanging-fb-test.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="UTF-8">
+
+<script type="text/javascript" src="webgl-utils.js"></script>
+<script type="text/javascript">
+/* Hanging Framebuffer Test
+ *
+ * Clear the canvas to green, but create and bind a new framebuffer
+ * before returning. This will fail if we blindly read from the bound
+ * framebuffer, instead of binding to the screen and reading from that.
+ *
+ * How failure looks isn't well defined, since this is an empty framebuffer,
+ * thus is incomplete, and should cause errors if it's read from.
+ */
+
+"use strict";
+
+function renderGL(gl) {
+ gl.clearColor(0.0, 1.0, 0.0, 1.0);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ var fb = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+
+ gl.finish();
+}
+
+function renderFailure(canvas) {
+ // This will also trigger RAF for us.
+ var context = canvas.getContext("2d");
+ context.fillText('WebGL failed.', 64, 64);
+}
+
+function runTest() {
+ var canvas = document.getElementById("canvas");
+ var gl = initGL(canvas);
+
+ if (gl)
+ renderGL(gl);
+ else
+ renderFailure(canvas);
+
+ waitForComposite(testComplete);
+}
+
+function testComplete() {
+ document.documentElement.removeAttribute("class");
+}
+</script>
+</head>
+
+<body onload="rAF(runTest);">
+ <canvas id="canvas" width="256" height="256"></canvas>
+</body>
+
+</html>
diff --git a/dom/canvas/test/reftest/webgl-hanging-scissor-test.html b/dom/canvas/test/reftest/webgl-hanging-scissor-test.html
new file mode 100644
index 0000000000..fb035153f1
--- /dev/null
+++ b/dom/canvas/test/reftest/webgl-hanging-scissor-test.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="UTF-8">
+
+<script type="text/javascript" src="webgl-utils.js"></script>
+<script type="text/javascript">
+/* Hanging Scissor Test
+ *
+ * Clear the canvas to green, but create and enable and set scissor values
+ * before returning. This can fail if we blindly blit or read from the screen
+ * without disabling scissor-test.
+ *
+ * Failure should look like only the top-left quadrant is rendered.
+ */
+
+"use strict";
+
+function renderGL(gl) {
+ gl.clearColor(0.0, 1.0, 0.0, 1.0);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ gl.enable(gl.SCISSOR_TEST);
+ gl.scissor(0, 128, 128, 128);
+
+ gl.finish();
+}
+
+function renderFailure(canvas) {
+ // This will also trigger RAF for us.
+ var context = canvas.getContext("2d");
+ context.fillText('WebGL failed.', 64, 64);
+}
+
+function runTest() {
+ var canvas = document.getElementById("canvas");
+ var gl = initGL(canvas);
+
+ if (gl)
+ renderGL(gl);
+ else
+ renderFailure(canvas);
+
+ waitForComposite(testComplete);
+}
+
+function testComplete() {
+ document.documentElement.removeAttribute("class");
+}
+</script>
+</head>
+
+<body onload="rAF(runTest);">
+ <canvas id="canvas" width="256" height="256"></canvas>
+</body>
+
+</html>
diff --git a/dom/canvas/test/reftest/webgl-resize-test.html b/dom/canvas/test/reftest/webgl-resize-test.html
new file mode 100644
index 0000000000..0917e997de
--- /dev/null
+++ b/dom/canvas/test/reftest/webgl-resize-test.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html class='reftest-wait'>
+ <head>
+ <meta charset='UTF-8'>
+ <script type='text/javascript' src='webgl-utils.js'></script>
+ </head>
+
+ <body>
+ <canvas id='e_canvas'></canvas>
+ <br>
+ <div id='e_log'></div>
+ <script>
+/* Resize Test
+ *
+ * Create canvas of wrong size.
+ * Clear the canvas to red.
+ * Resize to correct size.
+ * Clear to green.
+ */
+
+'use strict';
+
+async function awaitComposite() {
+ await new Promise((res, rej) => {
+ waitForComposite(res);
+ });
+}
+
+function testComplete() {
+ document.documentElement.removeAttribute('class');
+}
+
+(async function() {
+ const gl = initGL(e_canvas);
+ if (!gl) {
+ e_log.textContent = 'WebGL failed.';
+ } else {
+ gl.clearColor(1.0, 0.0, 0.0, 1.0); // red
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ await awaitComposite();
+
+ gl.canvas.width = 256;
+ gl.canvas.height = 256;
+ gl.clearColor(0.0, 1.0, 0.0, 1.0); // green
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ }
+
+ await awaitComposite();
+ testComplete();
+})();
+ </script>
+ </body>
+</html>
diff --git a/dom/canvas/test/reftest/webgl-utils.js b/dom/canvas/test/reftest/webgl-utils.js
new file mode 100644
index 0000000000..798e7fee0f
--- /dev/null
+++ b/dom/canvas/test/reftest/webgl-utils.js
@@ -0,0 +1,82 @@
+"use strict";
+
+function parseArgs() {
+ var query = window.location.search.substring(1);
+
+ var split = query.split("&");
+
+ var args = {}
+ for (var i = 0; i < split.length; i++) {
+ var pair = split[i].split("=");
+
+ var key = pair[0];
+ var value = true;
+ if (pair.length >= 2) {
+ eval("value = " + decodeURIComponent(pair[1]) + ";");
+ }
+
+ args[key] = value;
+ }
+
+ return args;
+}
+
+var gArgs = null;
+function arg(key, defaultVal) {
+ if (gArgs === null) {
+ gArgs = parseArgs();
+ }
+
+ if (!(key in gArgs))
+ return defaultVal;
+
+ return gArgs[key];
+}
+
+function initGL(canvas) {
+ if (arg("nogl"))
+ return null;
+
+ var gl = null;
+
+ var withAA = arg("aa", false);
+ var withAlpha = arg("alpha", false);
+ var withDepth = arg("depth", false);
+ var withPremult = arg("premult", false);
+ var withPreserve = arg("preserve", false);
+ var withStencil = arg("stencil", false);
+
+ try {
+ var argDict = {
+ alpha: withAlpha,
+ depth: withDepth,
+ stencil: withStencil,
+ antialias: withAA,
+ premultipliedAlpha: withPremult,
+ preserveDrawingBuffer: withPreserve,
+ };
+ gl = canvas.getContext("webgl", argDict);
+ } catch(e) {}
+
+ return gl;
+}
+
+function rAF(func) {
+ var raf = window.requestAnimationFrame;
+ raf(func);
+}
+
+var MAX_WAIT_FOR_COMPOSITE_DELAY_MS = 500;
+
+function waitForComposite(func) {
+ var isDone = false;
+ var doneFunc = function () {
+ if (isDone)
+ return;
+ isDone = true;
+ func();
+ };
+
+ rAF(doneFunc);
+ setTimeout(doneFunc, MAX_WAIT_FOR_COMPOSITE_DELAY_MS);
+}
diff --git a/dom/canvas/test/reftest/white.png b/dom/canvas/test/reftest/white.png
new file mode 100644
index 0000000000..23b21c59cb
--- /dev/null
+++ b/dom/canvas/test/reftest/white.png
Binary files differ
diff --git a/dom/canvas/test/reftest/wrapper.html b/dom/canvas/test/reftest/wrapper.html
new file mode 100644
index 0000000000..1b59b226c3
--- /dev/null
+++ b/dom/canvas/test/reftest/wrapper.html
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML>
+<html class="reftest-wait">
+<head>
+<title>Image reftest wrapper</title>
+<style type="text/css">
+ #image1 { background-color: rgb(10, 100, 250); }
+</style>
+<script>
+ // The image is loaded async after the page loads
+ // wait for it to finish loading
+ function onImageLoad() {
+ document.documentElement.removeAttribute("class");
+ };
+</script>
+</head>
+<body>
+<img id="image1">
+<script>
+ // Use as "wrapper.html?image.png"
+ var imgURL = document.location.search.substr(1);
+ document.images[0].onload = onImageLoad;
+ document.images[0].onerror = onImageLoad;
+ document.images[0].src = imgURL;
+</script>
+</body>
+</html>
+