Bug 709490 - Part 4: Mochitests for offscreencanvas. r=baku, r=jgilbert

Thanks Jon Morton [:jmorton] (jonanin@gmail.com) for polishing patches.
This commit is contained in:
Morris Tseng 2015-10-12 11:21:03 +08:00
parent bff0b9a1af
commit 55e63cb455
11 changed files with 742 additions and 0 deletions

View File

@ -27,6 +27,9 @@ support-files =
imagebitmap_on_worker.js
imagebitmap_structuredclone.js
imagebitmap_structuredclone_iframe.html
offscreencanvas.js
offscreencanvas_neuter.js
offscreencanvas_serviceworker_inner.html
[test_2d.clearRect.image.offscreen.html]
[test_2d.clip.winding.html]
@ -261,3 +264,18 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # bug 1040965
[test_createPattern_broken.html]
[test_setlinedash.html]
[test_filter.html]
[test_offscreencanvas_basic_webgl.html]
tags = offscreencanvas
[test_offscreencanvas_sharedworker.html]
tags = offscreencanvas
[test_offscreencanvas_serviceworker.html]
tags = offscreencanvas
skip-if = buildapp == 'b2g'
[test_offscreencanvas_neuter.html]
tags = offscreencanvas
[test_offscreencanvas_many.html]
tags = offscreencanvas
[test_offscreencanvas_sizechange.html]
tags = offscreencanvas
[test_offscreencanvas_subworker.html]
tags = offscreencanvas

View File

@ -0,0 +1,274 @@
/* WebWorker for test_offscreencanvas_*.html */
var port = null;
function ok(expect, msg) {
if (port) {
port.postMessage({type: "test", result: !!expect, name: msg});
} else {
postMessage({type: "test", result: !!expect, name: msg});
}
}
function finish() {
if (port) {
port.postMessage({type: "finish"});
} else {
postMessage({type: "finish"});
}
}
//--------------------------------------------------------------------
// WebGL Drawing Functions
//--------------------------------------------------------------------
function createDrawFunc(canvas) {
var gl;
try {
gl = canvas.getContext("experimental-webgl");
} catch (e) {}
if (!gl) {
ok(false, "WebGL is unavailable");
return null;
}
var vertSrc = "attribute vec2 position; \
void main(void) { \
gl_Position = vec4(position, 0.0, 1.0); \
}";
var fragSrc = "precision mediump float; \
void main(void) { \
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0); \
}";
// Returns a valid shader, or null on errors.
var createShader = function(src, t) {
var shader = gl.createShader(t);
gl.shaderSource(shader, src);
gl.compileShader(shader);
return shader;
};
var createProgram = function(vsSrc, fsSrc) {
var vs = createShader(vsSrc, gl.VERTEX_SHADER);
var fs = createShader(fsSrc, gl.FRAGMENT_SHADER);
var prog = gl.createProgram();
gl.attachShader(prog, vs);
gl.attachShader(prog, fs);
gl.linkProgram(prog);
if (!gl.getProgramParameter(prog, gl.LINK_STATUS)) {
var str = "Shader program linking failed:";
str += "\nShader program info log:\n" + gl.getProgramInfoLog(prog);
str += "\n\nVert shader log:\n" + gl.getShaderInfoLog(vs);
str += "\n\nFrag shader log:\n" + gl.getShaderInfoLog(fs);
console.log(str);
ok(false, "Shader program linking failed");
return null;
}
return prog;
};
gl.disable(gl.DEPTH_TEST);
var program = createProgram(vertSrc, fragSrc);
ok(program, "Creating shader program");
program.positionAttr = gl.getAttribLocation(program, "position");
ok(program.positionAttr >= 0, "position attribute should be valid");
var vertCoordArr = new Float32Array([
-1, -1,
1, -1,
-1, 1,
1, 1,
]);
var vertCoordBuff = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertCoordBuff);
gl.bufferData(gl.ARRAY_BUFFER, vertCoordArr, gl.STATIC_DRAW);
var checkGLError = function(prefix, refValue) {
if (!refValue) {
refValue = 0;
}
var error = gl.getError();
ok(error == refValue,
prefix + 'gl.getError should be 0x' + refValue.toString(16) +
', was 0x' + error.toString(16) + '.');
};
var testPixel = function(x, y, refData, infoString) {
var pixel = new Uint8Array(4);
gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
var pixelMatches = pixel[0] == refData[0] &&
pixel[1] == refData[1] &&
pixel[2] == refData[2] &&
pixel[3] == refData[3];
ok(pixelMatches, infoString);
};
var preDraw = function(prefix) {
gl.clearColor(1.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
testPixel(0, 0, [255, 0, 0, 255], prefix + 'Should be red before drawing.');
};
var postDraw = function(prefix) {
testPixel(0, 0, [0, 255, 0, 255], prefix + 'Should be green after drawing.');
};
gl.useProgram(program);
gl.enableVertexAttribArray(program.position);
gl.vertexAttribPointer(program.position, 2, gl.FLOAT, false, 0, 0);
// Start drawing
checkGLError('after setup');
return function(prefix) {
if (prefix) {
prefix = "[" + prefix + "] ";
} else {
prefix = "";
}
gl.viewport(0, 0, canvas.width, canvas.height);
preDraw(prefix);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
postDraw(prefix);
checkGLError(prefix);
};
}
/* entry point */
function entryFunction(testStr, subtests, offscreenCanvas) {
var test = testStr;
var canvas = offscreenCanvas;
if (test != "subworker") {
ok(canvas, "Canvas successfully transfered to worker");
ok(canvas.getContext, "Canvas has getContext");
ok(canvas.width == 64, "OffscreenCanvas width should be 64");
ok(canvas.height == 64, "OffscreenCanvas height should be 64");
}
var draw;
//------------------------------------------------------------------------
// Basic WebGL test
//------------------------------------------------------------------------
if (test == "webgl") {
draw = createDrawFunc(canvas);
if (!draw) {
finish();
return;
}
var count = 0;
var iid = setInterval(function() {
if (count++ > 20) {
clearInterval(iid);
ok(true, "Worker is done");
finish();
return;
}
draw("loop " +count);
}, 0);
}
//------------------------------------------------------------------------
// Canvas Size Change from Worker
//------------------------------------------------------------------------
else if (test == "webgl_changesize") {
draw = createDrawFunc(canvas);
if (!draw) {
finish();
return;
}
draw("64x64");
setTimeout(function() {
canvas.width = 128;
canvas.height = 128;
draw("Increased to 128x128");
setTimeout(function() {
canvas.width = 32;
canvas.width = 32;
draw("Decreased to 32x32");
setTimeout(function() {
canvas.width = 64;
canvas.height = 64;
draw("Increased to 64x64");
ok(true, "Worker is done");
finish();
}, 0);
}, 0);
}, 0);
}
//------------------------------------------------------------------------
// Using OffscreenCanvas from sub workers
//------------------------------------------------------------------------
else if (test == "subworker") {
/* subworker tests take a list of tests to run on children */
var stillRunning = 0;
subtests.forEach(function (subtest) {
++stillRunning;
var subworker = new Worker('offscreencanvas.js');
subworker.onmessage = function(evt) {
/* report finish to parent when all children are finished */
if (evt.data.type == "finish") {
subworker.terminate();
if (--stillRunning == 0) {
ok(true, "Worker is done");
finish();
}
return;
}
/* relay all other messages to parent */
postMessage(evt.data);
};
var findTransferables = function(t) {
if (t.test == "subworker") {
var result = [];
t.subtests.forEach(function(test) {
result = result.concat(findTransferables(test));
});
return result;
} else {
return [t.canvas];
}
};
subworker.postMessage(subtest, findTransferables(subtest));
});
}
};
onmessage = function(evt) {
port = evt.ports[0];
entryFunction(evt.data.test, evt.data.subtests, evt.data.canvas);
};
onconnect = function(evt) {
port = evt.ports[0];
port.addEventListener('message', function(evt) {
entryFunction(evt.data.test, evt.data.subtests, evt.data.canvas);
});
port.start();
};

View File

@ -0,0 +1 @@
/* empty worker for test_offscreencanvas_disable.html */

View File

@ -0,0 +1,32 @@
<!DOCTYPE HTML>
<html>
<head>
<title>WebGL in OffscreenCanvas</title>
</head>
<body>
<canvas id="c" width="64" height="64"></canvas>
<script>
function ok(expect, msg) {
parent.postMessage({type: "test", result: !!expect, name: msg}, "*");
}
var htmlCanvas = document.getElementById("c");
ok(htmlCanvas, "Should have HTML canvas element");
var messageChannel = new MessageChannel();
messageChannel.port1.onmessage = function(evt) {
parent.postMessage(evt.data, "*");
}
ok(htmlCanvas.transferControlToOffscreen, "HTMLCanvasElement has transferControlToOffscreen function");
var offscreenCanvas = htmlCanvas.transferControlToOffscreen();
ok(offscreenCanvas, "Expected transferControlToOffscreen to succeed");
navigator.serviceWorker.ready.then(function() {
navigator.serviceWorker.controller.postMessage({test: 'webgl', canvas: offscreenCanvas}, [offscreenCanvas, messageChannel.port2]);
});
</script>
</body>
</html>

View File

@ -0,0 +1,48 @@
<!DOCTYPE HTML>
<html>
<head>
<title>WebGL in OffscreenCanvas</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
</head>
<body>
<canvas id="c" width="64" height="64"></canvas>
<script>
SimpleTest.waitForExplicitFinish();
function runTest() {
var htmlCanvas = document.getElementById("c");
var worker = new Worker("offscreencanvas.js");
ok(htmlCanvas, "Should have HTML canvas element");
ok(worker, "Web worker successfully created");
worker.onmessage = function(evt) {
var msg = evt.data || {};
if (msg.type == "test") {
ok(msg.result, msg.name);
}
if (msg.type == "finish") {
worker.terminate();
SimpleTest.finish();
}
}
ok(htmlCanvas.transferControlToOffscreen, "HTMLCanvasElement has transferControlToOffscreen function");
var offscreenCanvas = htmlCanvas.transferControlToOffscreen();
ok(offscreenCanvas, "Expected transferControlToOffscreen to succeed");
worker.postMessage({test: 'webgl', canvas: offscreenCanvas}, [offscreenCanvas]);
}
SpecialPowers.pushPrefEnv({'set': [
['gfx.offscreencanvas.enabled', true],
['webgl.force-enabled', true],
]}, runTest);
</script>
</body>
</html>

View File

@ -0,0 +1,67 @@
<!DOCTYPE HTML>
<html>
<head>
<title>WebGL in OffscreenCanvas</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
</head>
<body>
<!--
This test needs several workers run offscreen canvas simultaneously.
So we choose 8 workers, 4 of them run basic webgl drawing test and
others run size changing test.
-->
<script>
SimpleTest.waitForExplicitFinish();
function createCanvas() {
var htmlCanvas = document.createElement('canvas');
htmlCanvas.width = 64;
htmlCanvas.height = 64;
document.body.appendChild(htmlCanvas);
return htmlCanvas;
}
function runTest() {
var stillRunning = 0;
var startWorker = function(canvas, test) {
stillRunning++;
var worker = new Worker("offscreencanvas.js");
worker.onmessage = function(evt) {
var msg = evt.data || {};
if (msg.type == "test") {
ok(msg.result, msg.name);
}
if (msg.type == "finish") {
worker.terminate();
if (--stillRunning == 0)
SimpleTest.finish();
}
}
var offscreenCanvas = canvas.transferControlToOffscreen();
worker.postMessage({test: test, canvas: offscreenCanvas}, [offscreenCanvas]);
}
/* create 4 workers that do the regular drawing test and 4 workers
that do the size change test */
for (var i = 0; i < 4; i++) {
startWorker(createCanvas(), 'webgl');
}
for (var i = 0; i < 4; i++) {
startWorker(createCanvas(), 'webgl_changesize');
}
}
SpecialPowers.pushPrefEnv({'set': [
['gfx.offscreencanvas.enabled', true],
['webgl.force-enabled', true]
]}, runTest);
</script>
</body>
</html>

View File

@ -0,0 +1,78 @@
<!DOCTYPE HTML>
<html>
<head>
<title>OffscreenCanvas: Test neutering</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
</head>
<body>
<canvas id="c" width="64" height="64"></canvas>
<script>
SimpleTest.waitForExplicitFinish();
function runTest() {
var htmlCanvas = document.getElementById("c");
var worker = new Worker("offscreencanvas_neuter.js");
ok(htmlCanvas, "Should have HTML canvas element");
ok(worker, "Web worker successfully created");
ok(htmlCanvas.transferControlToOffscreen, "HTMLCanvasElement has transferControlToOffscreen function");
var offscreenCanvas = htmlCanvas.transferControlToOffscreen();
ok(offscreenCanvas, "Expected transferControlToOffscreen to succeed");
/* check html canvas is neuterd */
is(htmlCanvas.width, 64, "HTML canvas has correct width");
SimpleTest.doesThrow(
function() { htmlCanvas.width = 128; },
"Can't change html canvas' width after transferControlToOffscreen");
SimpleTest.doesThrow(
function() { htmlCanvas.height = 128; },
"Can't change html canvas' height after transferControlToOffscreen");
ok(!htmlCanvas.getContext("2d"), "Can't getContext after transferControlToOffscreen");
ok(!htmlCanvas.getContext("webgl"), "Can't getContext after transferControlToOffscreen");
ok(!htmlCanvas.getContext("webgl2"), "Can't getContext after transferControlToOffscreen");
worker.postMessage(offscreenCanvas, [offscreenCanvas]);
/* check parent offscreencanvas is neutered after being transfered */
SimpleTest.doesThrow(
function() { offscreenCanvas.width = 128; },
"Can't change transfered worker canvas width");
SimpleTest.doesThrow(
function() { offscreenCanvas.height = 128; },
"Can't change transfered worker canvas height");
SimpleTest.doesThrow(
function() { offscreenCanvas.getContext("2d") },
"Can't getContext on transfered worker canvas");
SimpleTest.doesThrow(
function() { offscreenCanvas.getContext("webgl") },
"Can't getContext on transfered worker canvas");
SimpleTest.doesThrow(
function() { offscreenCanvas.getContext("webgl2") },
"Can't getContext on transfered worker canvas");
// Transfer a neutered offscreencanvas should be ok.
worker.postMessage(offscreenCanvas, [offscreenCanvas]);
worker.terminate();
SimpleTest.finish();
}
SpecialPowers.pushPrefEnv({'set': [
['gfx.offscreencanvas.enabled', true],
['webgl.force-enabled', true],
]}, runTest);
</script>
</body>
</html>

View File

@ -0,0 +1,46 @@
<!DOCTYPE HTML>
<html>
<head>
<title>WebGL in OffscreenCanvas</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
</head>
<body>
<script>
SimpleTest.waitForExplicitFinish();
function runTest() {
window.onmessage = function(evt) {
var msg = evt.data || {};
if (msg.type == "test") {
ok(msg.result, msg.name);
}
if (msg.type == "finish") {
SimpleTest.finish();
}
}
navigator.serviceWorker.register('offscreencanvas.js', { scope: "."})
// Wait until the service worker is active.
.then(navigator.serviceWorker.ready)
// ...and then show the interface for the commands once it's ready.
.then(function() {
iframe = document.createElement("iframe");
iframe.setAttribute('src', "offscreencanvas_serviceworker_inner.html");
document.body.appendChild(iframe);
})
}
SpecialPowers.pushPrefEnv({'set': [
['gfx.offscreencanvas.enabled', true],
['webgl.force-enabled', true],
["dom.serviceWorkers.exemptFromPerDomainMax", true],
["dom.serviceWorkers.interception.enabled", true],
["dom.serviceWorkers.enabled", true],
["dom.serviceWorkers.testing.enabled", true]
]}, runTest);
</script>
</body>
</html>

View File

@ -0,0 +1,47 @@
<!DOCTYPE HTML>
<html>
<head>
<title>WebGL in OffscreenCanvas</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
</head>
<body>
<canvas id="c" width="64" height="64"></canvas>
<script>
SimpleTest.waitForExplicitFinish();
function runTest() {
var htmlCanvas = document.getElementById("c");
var worker = new SharedWorker("offscreencanvas.js");
ok(htmlCanvas, "Should have HTML canvas element");
ok(worker, "Web worker successfully created");
ok(htmlCanvas.transferControlToOffscreen, "HTMLCanvasElement has transferControlToOffscreen function");
var offscreenCanvas = htmlCanvas.transferControlToOffscreen();
ok(offscreenCanvas, "Expected transferControlToOffscreen to succeed");
worker.port.start();
// We don't support transferring OffscreenCanvas via shared worker.
SimpleTest.doesThrow(
function() {
worker.port.postMessage({test: 'webgl', canvas: offscreenCanvas}, [offscreenCanvas]);
},
"OffscreenCanvas cannot transfer to shared worker"
);
SimpleTest.finish();
}
SpecialPowers.pushPrefEnv({'set': [
['gfx.offscreencanvas.enabled', true],
['webgl.force-enabled', true],
]}, runTest);
</script>
</body>
</html>

View File

@ -0,0 +1,41 @@
<!DOCTYPE HTML>
<html>
<head>
<title>WebGL in OffscreenCanvas</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
</head>
<body>
<canvas id="c" width="64" height="64"></canvas>
<script>
SimpleTest.waitForExplicitFinish();
function runTest() {
var htmlCanvas = document.getElementById("c");
var worker = new Worker("offscreencanvas.js");
worker.onmessage = function(evt) {
var msg = evt.data || {};
if (msg.type == "test") {
ok(msg.result, msg.name);
}
if (msg.type == "finish") {
worker.terminate();
SimpleTest.finish();
}
}
var offscreenCanvas = htmlCanvas.transferControlToOffscreen();
worker.postMessage({test: 'webgl_changesize', canvas: offscreenCanvas}, [offscreenCanvas]);
}
SpecialPowers.pushPrefEnv({'set': [
['gfx.offscreencanvas.enabled', true],
['webgl.force-enabled', true],
]}, runTest);
</script>
</body>
</html>

View File

@ -0,0 +1,90 @@
<!DOCTYPE HTML>
<html>
<head>
<title>OffscreenCanvas: Test subworkers</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
</head>
<body>
<!--
We want to test offscreen canvas works well when it running on worker
and nested worker simultaneously. So we create 10 canvas and dispatch
it to different workers and sub-workers.
-->
<script>
SimpleTest.waitForExplicitFinish();
function createCanvas() {
var htmlCanvas = document.createElement('canvas');
htmlCanvas.width = 64;
htmlCanvas.height = 64;
document.body.appendChild(htmlCanvas);
return htmlCanvas.transferControlToOffscreen();
}
function runTest() {
var worker = new Worker("offscreencanvas.js");
worker.onmessage = function(evt) {
var msg = evt.data || {};
if (msg.type == "test") {
ok(msg.result, msg.name);
}
if (msg.type == "finish") {
worker.terminate();
SimpleTest.finish();
}
}
var findTransferables = function(t) {
if (t.test == "subworker") {
var result = [];
t.subtests.forEach(function(test) {
result = result.concat(findTransferables(test));
});
return result;
} else {
return [t.canvas];
}
};
var testData =
{test: 'subworker', subtests: [
{test: 'webgl', canvas: createCanvas()},
{test: 'subworker', subtests: [
{test: 'webgl', canvas: createCanvas()},
{test: 'webgl_changesize', canvas: createCanvas()},
{test: 'webgl', canvas: createCanvas()}
]},
{test: 'subworker', subtests: [
{test: 'webgl', canvas: createCanvas()},
{test: 'webgl_changesize', canvas: createCanvas()},
{test: 'subworker', subtests: [
{test: 'webgl_changesize', canvas: createCanvas()},
{test: 'webgl', canvas: createCanvas()}
]},
{test: 'subworker', subtests: [
{test: 'webgl_changesize', canvas: createCanvas()},
{test: 'subworker', subtests: [
{test: 'subworker', subtests: [
{test: 'webgl_changesize', canvas: createCanvas()}
]}
]}
]},
]}
]};
worker.postMessage(testData, findTransferables(testData));
}
SpecialPowers.pushPrefEnv({'set': [
['gfx.offscreencanvas.enabled', true],
['webgl.force-enabled', true],
]}, runTest);
</script>
</body>
</html>