[npotb] Import WebGL test suite into tree
authorVladimir Vukicevic <vladimir@pobox.com>
Fri, 04 Jun 2010 12:03:40 -0700
changeset 43100 c277da9b14f27a62251df69b2ae915431b9f280b
parent 43099 69f7a0a6e333d2bbe89748c6ca58f6b51d3f8259
child 43101 e7fac7e69d57737eab699092f81d0779aa7ecb21
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone1.9.3a5pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
[npotb] Import WebGL test suite into tree
content/canvas/test/webgl/README.mozilla
content/canvas/test/webgl/conformance/00_readme.txt
content/canvas/test/webgl/conformance/00_test_list.txt
content/canvas/test/webgl/conformance/array-unit-tests.html
content/canvas/test/webgl/conformance/buffer-bind-test.html
content/canvas/test/webgl/conformance/bug-31889.html
content/canvas/test/webgl/conformance/bug-32364.html
content/canvas/test/webgl/conformance/bug-32456.html
content/canvas/test/webgl/conformance/bug-32619.html
content/canvas/test/webgl/conformance/bug-32692.html
content/canvas/test/webgl/conformance/bug-32888.html
content/canvas/test/webgl/conformance/canvas-test.html
content/canvas/test/webgl/conformance/constants.html
content/canvas/test/webgl/conformance/context-type-test.html
content/canvas/test/webgl/conformance/draw-arrays-out-of-bounds.html
content/canvas/test/webgl/conformance/draw-elements-out-of-bounds.html
content/canvas/test/webgl/conformance/error-reporting.html
content/canvas/test/webgl/conformance/framebuffer-test.html
content/canvas/test/webgl/conformance/get-active-test.html
content/canvas/test/webgl/conformance/gl-bindattribLocation-test.html
content/canvas/test/webgl/conformance/gl-drawelements.html
content/canvas/test/webgl/conformance/gl-enable-enum-test.html
content/canvas/test/webgl/conformance/gl-enable-vertex-attrib.html
content/canvas/test/webgl/conformance/gl-enum-tests.html
content/canvas/test/webgl/conformance/gl-get-calls.html
content/canvas/test/webgl/conformance/gl-getstring.html
content/canvas/test/webgl/conformance/gl-object-get-calls.html
content/canvas/test/webgl/conformance/gl-pixelstorei.html
content/canvas/test/webgl/conformance/gl-scissor-test.html
content/canvas/test/webgl/conformance/gl-shader-test.html
content/canvas/test/webgl/conformance/gl-uniform-arrays.html
content/canvas/test/webgl/conformance/gl-uniform-bool.html
content/canvas/test/webgl/conformance/gl-uniformmatrix4fv.html
content/canvas/test/webgl/conformance/gl-unknown-uniform.html
content/canvas/test/webgl/conformance/gl-vertexattrib.html
content/canvas/test/webgl/conformance/gl-vertexattribpointer.html
content/canvas/test/webgl/conformance/glsl-2types-of-textures-on-same-unit.html
content/canvas/test/webgl/conformance/glsl-conformance.html
content/canvas/test/webgl/conformance/incorrect-context-object-behaviour.html
content/canvas/test/webgl/conformance/index-validation-copies-indices.html
content/canvas/test/webgl/conformance/index-validation.html
content/canvas/test/webgl/conformance/methods.html
content/canvas/test/webgl/conformance/null-object-behaviour.html
content/canvas/test/webgl/conformance/origin-clean-conformance.html
content/canvas/test/webgl/conformance/program-test.html
content/canvas/test/webgl/conformance/readpixels-test.html
content/canvas/test/webgl/conformance/resource-sharing-test.html
content/canvas/test/webgl/conformance/resources/array-unit-tests.js
content/canvas/test/webgl/conformance/resources/boolUniformShader.vert
content/canvas/test/webgl/conformance/resources/bug-32888-texture.png
content/canvas/test/webgl/conformance/resources/error-reporting.js
content/canvas/test/webgl/conformance/resources/floatUniformShader.vert
content/canvas/test/webgl/conformance/resources/fragmentShader.frag
content/canvas/test/webgl/conformance/resources/get-active-test.js
content/canvas/test/webgl/conformance/resources/gl-object-get-calls.js
content/canvas/test/webgl/conformance/resources/incorrect-context-object-behaviour.js
content/canvas/test/webgl/conformance/resources/index-validation.js
content/canvas/test/webgl/conformance/resources/intUniformShader.vert
content/canvas/test/webgl/conformance/resources/matUniformShader.vert
content/canvas/test/webgl/conformance/resources/noopUniformShader.frag
content/canvas/test/webgl/conformance/resources/null-object-behaviour.js
content/canvas/test/webgl/conformance/resources/structUniformShader.vert
content/canvas/test/webgl/conformance/resources/testrunner.js
content/canvas/test/webgl/conformance/resources/uniform-location.js
content/canvas/test/webgl/conformance/resources/utils3d.js
content/canvas/test/webgl/conformance/resources/vertexShader.vert
content/canvas/test/webgl/conformance/resources/webgl-test-utils.js
content/canvas/test/webgl/conformance/resources/webgl-test.js
content/canvas/test/webgl/conformance/texparameter-test.html
content/canvas/test/webgl/conformance/texture-active-bind-2.html
content/canvas/test/webgl/conformance/texture-active-bind.html
content/canvas/test/webgl/conformance/texture-complete.html
content/canvas/test/webgl/conformance/texture-formats-test.html
content/canvas/test/webgl/conformance/texture-npot.html
content/canvas/test/webgl/conformance/triangle.html
content/canvas/test/webgl/conformance/uniform-location.html
content/canvas/test/webgl/conformance/uniform-samplers-test.html
content/canvas/test/webgl/conformance/uninitialized-test.html
content/canvas/test/webgl/extra/50x50pixel-black-with-red-triangle.png
content/canvas/test/webgl/extra/canvas-compositing-test.html
content/canvas/test/webgl/extra/canvas-compositing-test.png
content/canvas/test/webgl/extra/fbo-lost-context.html
content/canvas/test/webgl/extra/out-of-memory.html
content/canvas/test/webgl/extra/out-of-resources.html
content/canvas/test/webgl/misc/program-test-1.html
content/canvas/test/webgl/resources/desktop-gl-constants.js
content/canvas/test/webgl/resources/js-test-post.js
content/canvas/test/webgl/resources/js-test-pre.js
content/canvas/test/webgl/resources/js-test-style.css
content/canvas/test/webgl/resources/webgl-test-harness.js
content/canvas/test/webgl/test_list.txt
content/canvas/test/webgl/webgl-conformance-tests.html
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/README.mozilla
@@ -0,0 +1,16 @@
+This is a local copy of the WebGL conformance suite.
+
+  SVN revision: 11588
+
+The canonical location for this testsuite is:
+
+  https://cvs.khronos.org/svn/repos/registry/trunk/public/webgl/sdk/tests/
+
+All files and directories in this directory, with the exception of "README.mozilla"
+(this file), the "mozilla" directory, and the "patches" directory come from
+upstream and should not be modified without corresponding upstream fixes and/or a
+patch file in the "patches" directory.
+
+The "mozilla" directory contains integration of this test suite into Mozilla's
+testing system.
+
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/00_readme.txt
@@ -0,0 +1,13 @@
+This file "00_test_list.txt" lists which files the test harness should run.
+
+If you add new tests you can update it with
+
+on windows
+
+   dir /b *.html >00_test_list.txt
+
+on OSX / Linux
+
+   ls -1 *.html >00_test_list.txt
+
+
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/00_test_list.txt
@@ -0,0 +1,53 @@
+array-unit-tests.html
+buffer-bind-test.html
+bug-31889.html
+bug-32364.html
+bug-32456.html
+bug-32692.html
+bug-32888.html
+canvas-test.html
+constants.html
+context-type-test.html
+draw-arrays-out-of-bounds.html
+draw-elements-out-of-bounds.html
+error-reporting.html
+framebuffer-test.html
+get-active-test.html
+gl-bindattribLocation-test.html
+gl-drawelements.html
+gl-enable-enum-test.html
+gl-enable-vertex-attrib.html
+gl-enum-tests.html
+gl-get-calls.html
+gl-object-get-calls.html
+gl-pixelstorei.html
+gl-scissor-test.html
+gl-shader-test.html
+gl-uniform-arrays.html
+gl-uniform-bool.html
+gl-uniformmatrix4fv.html
+gl-unknown-uniform.html
+gl-vertexattrib.html
+gl-vertexattribpointer.html
+gl-getstring.html
+glsl-2types-of-textures-on-same-unit.html
+glsl-conformance.html
+incorrect-context-object-behaviour.html
+index-validation-copies-indices.html
+index-validation.html
+methods.html
+null-object-behaviour.html
+origin-clean-conformance.html
+program-test.html
+readpixels-test.html
+resource-sharing-test.html
+texture-active-bind.html
+texture-active-bind-2.html
+texparameter-test.html
+texture-complete.html
+texture-formats-test.html
+texture-npot.html
+triangle.html
+uniform-location.html
+uniform-samplers-test.html
+
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/array-unit-tests.html
@@ -0,0 +1,43 @@
+<!--
+Copyright (c) 2009 The Chromium Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<html>
+<head>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+
+<script type="text/javascript" src="resources/array-unit-tests.js"></script>
+<script src="../resources/js-test-post.js"></script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/buffer-bind-test.html
@@ -0,0 +1,68 @@
+<!--
+Copyright (c) 2009 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+ -->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+  "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+  <head>
+    <title>WebGL BindBuffer conformance test.</title>
+    <link rel="stylesheet" href="../resources/js-test-style.css"/>
+    <script src="../resources/js-test-pre.js"></script>
+    <script src="resources/webgl-test.js"> </script>
+    <script src="../../debug/webgl-debug.js"> </script>
+</head>
+<body>
+<canvas id="example" width="40" height="40" style="width: 40px; height: 40px;"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+<script>
+description("Checks a buffer can only be bound to 1 target.");
+
+debug("");
+debug("Canvas.getContext");
+
+var gl = create3DContext(document.getElementById("canvas"));
+if (!gl) {
+  testFailed("context does not exist");
+} else {
+  testPassed("context exists");
+
+  debug("");
+
+  var buf = gl.createBuffer();
+  gl.bindBuffer(gl.ARRAY_BUFFER, buf);
+  assertMsg(gl.getError() == gl.NO_ERROR,
+            "should be able to bind buffer.");
+  gl.bindBuffer(gl.ARRAY_BUFFER, null);
+  assertMsg(gl.getError() == gl.NO_ERROR,
+            "should be able to unbind buffer.");
+  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buf);
+  assertMsg(gl.getError() == gl.INVALID_OPERATION,
+            "should get INVALID_OPERATION if attempting to bind buffer to different target");
+
+  var buf = gl.createBuffer();
+  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buf);
+  assertMsg(gl.getError() == gl.NO_ERROR,
+            "should be able to bind buffer.");
+  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
+  assertMsg(gl.getError() == gl.NO_ERROR,
+            "should be able to unbind buffer.");
+  gl.bindBuffer(gl.ARRAY_BUFFER, buf);
+  assertMsg(gl.getError() == gl.INVALID_OPERATION,
+            "should get INVALID_OPERATION if attempting to bind buffer to different target");
+}
+
+debug("");
+successfullyParsed = true;
+</script>
+</body>
+<script src="../resources/js-test-post.js"></script>
+
+<script>
+</script>
+
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/bug-31889.html
@@ -0,0 +1,57 @@
+<!--
+Copyright (c) 2009 The Chromium Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<html>
+<head>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/webgl-test.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+
+<script>
+
+description('Regression test for <a href="https://bugs.webkit.org/show_bug.cgi?id=31889">https://bugs.webkit.org/show_bug.cgi?id=31889</a> : <code>[v8] WebCore::WebGLArrayBufferInternal::byteLengthAttrGetter NULL pointer</code>');
+
+<!-- The following used to cause a crash in Chrome -->
+new WebGLArrayBuffer().byteLength;
+
+testPassed("new WebGLArrayBuffer().byteLength did not crash");
+successfullyParsed = true;
+
+</script>
+<script src="../resources/js-test-post.js"></script>
+
+<script>
+</script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/bug-32364.html
@@ -0,0 +1,64 @@
+<!--
+Copyright (c) 2009 The Chromium Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<html>
+<head>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/webgl-test.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+
+<script>
+
+description('Regression test for <a href="https://bugs.webkit.org/show_bug.cgi?id=32364">https://bugs.webkit.org/show_bug.cgi?id=32364</a> : <code>[Chromium] SporeViewer demo doesn\'t work in Chromium</code>');
+
+var gl = create3DContext();
+var floatProgram = loadProgram(gl, "resources/floatUniformShader.vert", "resources/noopUniformShader.frag");
+shouldBeUndefined("gl.useProgram(floatProgram)");
+var fval4Loc = gl.getUniformLocation(floatProgram, "fval4");
+shouldBe("gl.getError()", "gl.NO_ERROR");
+shouldBeUndefined("gl.uniform4fv(fval4Loc, new WebGLFloatArray([0.1, 0.2, 0.4, 1.0]));");
+
+var tmpcanvas = document.createElement("canvas");
+tmpcanvas.width = 2;
+tmpcanvas.height = 2;
+var texture = gl.createTexture();
+shouldBeUndefined("gl.bindTexture(gl.TEXTURE_2D, texture)");
+shouldBeUndefined("gl.texImage2D(gl.TEXTURE_2D, 0, tmpcanvas)");
+
+successfullyParsed = true;
+
+</script>
+<script src="../resources/js-test-post.js"></script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/bug-32456.html
@@ -0,0 +1,103 @@
+<!--
+Copyright (c) 2009 The Chromium Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<html>
+<head>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/webgl-test.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+
+<script>
+
+description('Regression test for <a href="https://bugs.webkit.org/show_bug.cgi?id=32456">https://bugs.webkit.org/show_bug.cgi?id=32456</a> : <code>Errors in WebGL[T]Array set() and get() methods</code>');
+
+debug("Testing WebGLFloatArray get / set");
+var array = new WebGLFloatArray([1.5]);
+shouldBe("array.get(0)", "1.5");
+shouldBe("array[0]", "1.5");
+shouldBeUndefined("array.set(0, 2.5)");
+shouldBe("array.get(0)", "2.5");
+shouldBe("array[0]", "2.5");
+
+debug("Testing WebGLByteArray get / set");
+array = new WebGLByteArray(1);
+shouldBeUndefined("array.set(0, 127)");
+shouldBe("array.get(0)", "127");
+shouldBe("array[0]", "127");
+shouldBeUndefined("array.set(0, -128)");
+shouldBe("array.get(0)", "-128");
+shouldBe("array[0]", "-128");
+
+debug("Testing WebGLUnsignedByteArray get / set");
+array = new WebGLUnsignedByteArray(1);
+shouldBeUndefined("array.set(0, 255)");
+shouldBe("array.get(0)", "255");
+shouldBe("array[0]", "255");
+
+debug("Testing WebGLShortArray get / set");
+array = new WebGLShortArray(1);
+shouldBeUndefined("array.set(0, 32767)");
+shouldBe("array.get(0)", "32767");
+shouldBe("array[0]", "32767");
+shouldBeUndefined("array.set(0, -32768)");
+shouldBe("array.get(0)", "-32768");
+shouldBe("array[0]", "-32768");
+
+debug("Testing WebGLUnsignedShortArray get / set");
+array = new WebGLUnsignedShortArray(1);
+shouldBeUndefined("array.set(0, 65535)");
+shouldBe("array.get(0)", "65535");
+shouldBe("array[0]", "65535");
+
+debug("Testing WebGLIntArray get / set");
+array = new WebGLIntArray(1);
+shouldBeUndefined("array.set(0, -2147483648)");
+shouldBe("array.get(0)", "-2147483648");
+shouldBe("array[0]", "-2147483648");
+shouldBeUndefined("array.set(0, 2147483647)");
+shouldBe("array.get(0)", "2147483647");
+shouldBe("array[0]", "2147483647");
+
+debug("Testing WebGLUnsignedIntArray get / set");
+array = new WebGLUnsignedIntArray(1);
+shouldBeUndefined("array.set(0, 4294967295)");
+shouldBe("array.get(0)", "4294967295");
+shouldBe("array[0]", "4294967295");
+
+successfullyParsed = true;
+
+</script>
+<script src="../resources/js-test-post.js"></script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/bug-32619.html
@@ -0,0 +1,88 @@
+<!doctype html>
+<html>
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+	<title>WebKit Bug #32619 regression test</title>
+	<link rel="stylesheet" href="../resources/js-test-style.css"/>
+	<script src="../resources/js-test-pre.js"></script>
+	<script src="resources/webgl-test.js"></script>
+	<script src="resources/testrunner.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<canvas id="canvas" width="2" height="2"> </canvas>
+<script><!--
+description("WebKit Bug #32619 regression test.");
+
+var canvas = document.getElementById("canvas");
+var gl = create3DContext(canvas);
+if (!gl)
+  testFailed("Context created.");
+else
+  testPassed("Context created.");
+
+
+/* object containing all tests in this testsuite */
+var bug32619_tests = {
+	setup: function () {
+		bug32619_tests.tex = gl.createTexture();
+		gl.bindTexture(gl.TEXTURE_2D, bug32619_tests.tex);
+		gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 64, 64, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+	},
+	teardown: function () {
+		gl.deleteTexture(bug32619_tests.tex);
+	},
+
+	"Passing a buffer not large enough to texImage2D should generate an INVALID_OPERATION" : function () {
+		this.setup = function () {
+			var tooSmall = new WebGLUnsignedByteArray(64);
+			gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 64, 64, 0, gl.RGBA, gl.UNSIGNED_BYTE, tooSmall);
+		};
+		this.expects = gl.INVALID_OPERATION;
+	},
+	"Passing texImage2D parameter data of Number type should throw a TypeError" : function () {
+		this.setup = function () {
+			gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 64, 64, 0, gl.RGBA, gl.UNSIGNED_BYTE, 42);
+		};
+		this.expects = "TypeError";
+	},
+	"Passing texImage2D parameter data of String type should throw a TypeError" : function () {
+		this.setup = function () {
+			gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 64, 64, 0, gl.RGBA, gl.UNSIGNED_BYTE, "not a buffer");
+		};
+		this.expects = "TypeError";
+	},
+	"Passing a buffer not large enough to texSubImage2D should generate an INVALID_OPERATION" : function () {
+		this.setup = function () {
+			var tooSmall = new WebGLUnsignedByteArray(64);
+			gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 64, 64, gl.RGBA, gl.UNSIGNED_BYTE, tooSmall);
+		};
+		this.expects = gl.INVALID_OPERATION;
+	},
+	"Passing texSubImage2D parameter data of Number type should throw a TypeError" : function () {
+		this.setup = function () {
+			gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 64, 64, gl.RGBA, gl.UNSIGNED_BYTE, 42);
+		};
+		this.expects = "TypeError";
+	},
+	"Passing texSubImage2D parameter data of String type should throw a TypeError" : function () {
+		this.setup = function () {
+			gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 64, 64, gl.RGBA, gl.UNSIGNED_BYTE, "not a buffer");
+		};
+		this.expects = "TypeError";
+	},
+}
+
+runTestsuite(bug32619_tests);
+
+debug("");
+successfullyParsed = true;
+--></script>
+<script src="../resources/js-test-post.js"></script>
+<script>
+</script>
+
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/bug-32692.html
@@ -0,0 +1,69 @@
+<!--
+Copyright (c) 2009 The Chromium Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<html>
+<head>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/webgl-test.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+
+<script>
+description('Regression test for <a href="https://bugs.webkit.org/show_bug.cgi?id=32692">https://bugs.webkit.org/show_bug.cgi?id=32692</a> : <code>Index validation for drawElements examines too many indices</code>');
+
+var context = create3DContext();
+var program = loadStandardProgram(context);
+
+context.useProgram(program);
+var vertexObject = context.createBuffer();
+context.enableVertexAttribArray(0);
+context.bindBuffer(context.ARRAY_BUFFER, vertexObject);
+// 4 vertices -> 2 triangles
+context.bufferData(context.ARRAY_BUFFER, new WebGLFloatArray([ 0,0,0, 0,1,0, 1,0,0, 1,1,0 ]), context.STATIC_DRAW);
+context.vertexAttribPointer(0, 3, context.FLOAT, false, 0, 0);
+
+var indexObject = context.createBuffer();
+
+debug("Test out of range indices")
+context.bindBuffer(context.ELEMENT_ARRAY_BUFFER, indexObject);
+context.bufferData(context.ELEMENT_ARRAY_BUFFER, new WebGLUnsignedShortArray([ 10000, 0, 1, 2, 3, 10000 ]), context.STATIC_DRAW);
+shouldGenerateGLError(context, context.NO_ERROR, "context.drawElements(context.TRIANGLE_STRIP, 4, context.UNSIGNED_SHORT, 2)");
+shouldGenerateGLError(context, context.INVALID_OPERATION, "context.drawElements(context.TRIANGLE_STRIP, 4, context.UNSIGNED_SHORT, 0)");
+shouldGenerateGLError(context, context.INVALID_OPERATION, "context.drawElements(context.TRIANGLE_STRIP, 4, context.UNSIGNED_SHORT, 4)");
+
+debug("")
+successfullyParsed = true;
+</script>
+
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/bug-32888.html
@@ -0,0 +1,190 @@
+<!--
+Copyright (c) 2009 The Chromium Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<html>
+<head>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/webgl-test.js"></script>
+<script src="resources/utils3d.js"> </script>
+<script id="vshader" type="x-shader/x-vertex">
+attribute vec3 g_Position;
+attribute vec2 g_TexCoord0;
+
+varying vec2 texCoord;
+
+void main()
+{
+    gl_Position = vec4(g_Position.x, g_Position.y, g_Position.z, 1.0);
+    texCoord = g_TexCoord0;
+}
+</script>
+
+<script id="fshader" type="x-shader/x-fragment">
+uniform sampler2D tex;
+varying vec2 texCoord;
+
+void main()
+{
+    gl_FragColor = texture2D(tex, texCoord);
+}
+</script>
+
+<script>
+var gl = null;
+var textureLoc = null;
+var successfullyParsed = false;
+
+function init()
+{
+    if (window.layoutTestController) {
+        layoutTestController.overridePreference("WebKitWebGLEnabled", "1");
+        layoutTestController.dumpAsText();
+        layoutTestController.waitUntilDone();
+    }
+
+    description('Regression test for <a href="https://bugs.webkit.org/show_bug.cgi?id=32888">https://bugs.webkit.org/show_bug.cgi?id=32888</a> : <code>Garbage in transparent regions of images uploaded as textures</code>');
+
+    gl = initWebGL("example", "vshader", "fshader", [ "g_Position", "g_TexCoord0" ], [ 0, 0, 0, 1 ], 1);
+    gl.viewport(0, 0, 32, 32);
+
+    textureLoc = gl.getUniformLocation(gl.program, "tex");
+
+    var vertices = new WebGLFloatArray([
+         1.0,  1.0, 0.0,
+        -1.0,  1.0, 0.0,
+        -1.0, -1.0, 0.0,
+         1.0,  1.0, 0.0,
+        -1.0, -1.0, 0.0,
+         1.0, -1.0, 0.0]);
+    // The input texture has 8 characters; take the leftmost one
+    var coeff = 1.0 / 8.0;
+    var texCoords = new WebGLFloatArray([
+        coeff, 1.0,
+        0.0, 1.0,
+        0.0, 0.0,
+        coeff, 1.0,
+        0.0, 0.0,
+        coeff, 0.0]);
+    var texCoordOffset = vertices.byteLength;
+
+    var vbo = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
+    gl.bufferData(gl.ARRAY_BUFFER,
+                  texCoordOffset + texCoords.byteLength,
+                  gl.STATIC_DRAW);
+    gl.bufferSubData(gl.ARRAY_BUFFER, 0, vertices);
+    gl.bufferSubData(gl.ARRAY_BUFFER, texCoordOffset, texCoords);
+
+    gl.enableVertexAttribArray(0);
+    gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
+    gl.enableVertexAttribArray(1);
+    gl.vertexAttribPointer(1, 2, gl.FLOAT, gl.FALSE, 0, texCoordOffset);
+
+    texture = loadTexture("resources/bug-32888-texture.png");
+}
+
+function loadTexture(src) {
+    var texture = gl.createTexture();
+    gl.bindTexture(gl.TEXTURE_2D, texture);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+    var image = new Image();
+    image.onload = function() {
+        gl.bindTexture(gl.TEXTURE_2D, texture);
+        gl.texImage2D(gl.TEXTURE_2D, 0, image, true);
+        runTest();
+    };
+    image.src = src;
+    return texture;
+}
+
+// These two declarations need to be global for "shouldBe" to see them
+var buf = null;
+var idx = 0;
+
+function runTest()
+{
+    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+    // Bind the texture to texture unit 0
+    gl.bindTexture(gl.TEXTURE_2D, texture);
+    // Point the uniform sampler to texture unit 0
+    gl.uniform1i(textureLoc, 0);
+    // Draw the triangles
+    gl.drawArrays(gl.TRIANGLES, 0, 6);
+
+    // Read back the rendering results
+    var width = 32;
+    var height = 32;
+    buf = gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE);
+    // Spot check a couple of 2x2 regions in the upper and lower left
+    // corners; they should be the background color rather than
+    // garbage
+    var queryWidth = 2;
+    var queryHeight = 2;
+    debug("Checking lower left corner");
+    var xoff = 1;
+    var yoff = height - 3;
+    for (var y = 0; y < queryHeight; y++) {
+        for (var x = 0; x < queryWidth; x++) {
+            idx = ((yoff + y) * width * 4 +
+                   (xoff + x) * 4);
+            shouldBe("buf[idx] == 0 && buf[idx + 1] == 0 && buf[idx + 2] == 0", "true");
+        }
+    }
+    debug("Checking upper left corner");
+    yoff = 1;
+    for (var y = 0; y < queryHeight; y++) {
+        for (var x = 0; x < queryWidth; x++) {
+            idx = ((yoff + y) * width * 4 +
+                   (xoff + x) * 4);
+            shouldBe("buf[idx] == 0 && buf[idx + 1] == 0 && buf[idx + 2] == 0", "true");
+        }
+    }
+
+    successfullyParsed = true;
+    var epilogue = document.createElement("script");
+    epilogue.onload = finish;
+    epilogue.src = "../resources/js-test-post.js";
+    document.body.appendChild(epilogue);
+}
+
+function finish() {
+    if (window.layoutTestController) {
+        layoutTestController.notifyDone();
+    }
+}
+</script>
+</head>
+<body onload="init()">
+<canvas id="example" width="32px" height="32px"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/canvas-test.html
@@ -0,0 +1,190 @@
+<!--
+Copyright (c) 2009 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+ -->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+  "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>WebGL Canvas Conformance Tests</title>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/desktop-gl-constants.js" type="text/javascript"></script>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/webgl-test.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<canvas id="canvas" style="width: 50px; height: 50px;"> </canvas>
+<canvas id="canvas2d" width="40" height="40"> </canvas>
+<script>
+description("This test ensures WebGL implementations interact correctly with the canvas tag.");
+
+debug("");
+debug("Canvas.getContext");
+
+var canvas = document.getElementById("canvas");
+var canvas2d = document.getElementById("canvas2d");
+var ctx2d = canvas2d.getContext("2d");
+var gl = create3DContext(canvas);
+if (!gl) {
+  testFailed("context does not exist");
+} else {
+  testPassed("context exists");
+
+  debug("");
+  debug("Checking canvas and WebGL interaction");
+
+  // Check that a canvas with no width or height is 300x300 pixels
+  shouldBe('canvas.width', '300');
+  shouldBe('canvas.height', '150');
+
+  // Check get a 4 value gl parameter as a csv string.
+  function getValue4v(name) {
+    var v = gl.getParameter(name);
+    var result = '' +
+        v[0] + ',' +
+        v[1] + ',' +
+        v[2] + ',' +
+        v[3];
+    return result;
+  }
+
+  function getViewport() {
+  return getValue4v(gl.VIEWPORT);
+  }
+
+  function getClearColor() {
+  return getValue4v(gl.COLOR_CLEAR_VALUE);
+  }
+
+  function isAboutEqual(a, b) {
+    return Math.abs(a - b) < 0.01;
+  }
+
+  function isAboutEqualInt(a, b) {
+    return Math.abs(a - b) < 3;
+  }
+
+  function checkCanvasContentIs(r3d,g3d,b3d,a3d) {
+    var r2d;
+    var g2d;
+    var b2d;
+    var a2d;
+
+    function checkPixel(x, y, r3d,g3d,b3d,a3d) {
+      var offset = (y * 40 + x) * 4;
+      r2d = imgData.data[offset];
+      g2d = imgData.data[offset + 1];
+      b2d = imgData.data[offset + 2];
+      a2d = imgData.data[offset + 3];
+      //debug('' + x + ', ' + y + "(" + offset + ") = " + r2d + ", " + g2d + ", " + b2d + ", " + a2d);
+      return isAboutEqualInt(r2d, r3d) &&
+             isAboutEqualInt(g2d, g3d) &&
+             isAboutEqualInt(b2d, b3d) &&
+             isAboutEqualInt(a2d, a3d);
+    }
+
+    function checkPixels(r3d,g3d,b3d,a3d) {
+      return checkPixel(0, 0, r3d, g3d, b3d, a3d) &&
+             checkPixel(0, 39, r3d, g3d, b3d, a3d) &&
+             checkPixel(39, 0, r3d, g3d, b3d, a3d) &&
+             checkPixel(39, 39, r3d, g3d, b3d, a3d) &&
+             checkPixel(0, 0, r3d, g3d, b3d, a3d);
+    };
+
+    // Set to just take the color from the 3d canvas
+    ctx2d.globalCompositeOperation = 'copy';
+
+    // fill 2d canvas with orange
+    ctx2d.fillStyle = "rgb(255,192,128)";
+    ctx2d.fillRect (0, 0, 40, 40);
+
+    // get the image data
+    var imgData = ctx2d.getImageData(0, 0, 40, 40);
+
+    // check it got cleared.
+    if (!checkPixels(255, 192, 128, 255)) {
+      testFailed("unable to fill 2d context.");
+      return;
+    }
+
+    // draw 3d canvas on top.
+    ctx2d.drawImage(canvas, 0,0, 40, 40);
+
+    // get the image data
+    var imgData = ctx2d.getImageData(0, 0, 40, 40);
+
+    // Check it's the expected color.
+    if (!checkPixels(r3d, g3d, b3d, a3d)) {
+     testFailed("pixels are " + r2d + "," + g2d + "," + b2d + "," + a2d +
+                " expected " + r3d + "," + g3d + "," + b3d + "," + a3d);
+    } else {
+      testPassed("pixels are " + r3d + "," + g3d + "," + b3d + "," + a3d);
+    }
+  }
+
+  checkCanvasContentIs(0, 0, 0, 0);
+  shouldBe('getViewport()', '"0,0,300,150"');
+
+  // Change the display size of the canvas and check
+  // the viewport size does not change.
+  debug("");
+  debug("change display size of canvas and see that viewport does not change");
+  canvas.style.width = "100px";
+  canvas.style.height = "25px";
+  var intervalId;
+  intervalId = window.setInterval(function() {
+    if (canvas.clientWidth == 100 &&
+        canvas.clientHeight == 25) {
+      window.clearInterval(intervalId);
+      shouldBe('getViewport()', '"0,0,300,150"');
+      shouldBe('canvas.width', '300');
+      shouldBe('canvas.height', '150');
+
+      // Change the actual size of the canvas
+      // Check that the viewport does not change.
+      // Check that the clear color does not change.
+      // Check that the color mask does not change.
+      debug("");
+      debug("change the actual size of the canvas and see that the viewport does not change");
+      gl.clearColor(0.25, 0.5, 0.75, 1);
+      gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+      checkCanvasContentIs(64, 128, 192, 255);
+      gl.colorMask(0,0,0,0);
+      canvas.width = 400;
+      canvas.height = 10;
+
+      var v = gl.getParameter(gl.COLOR_CLEAR_VALUE);
+      assertMsg(isAboutEqual(v[0], 0.25) &&
+                isAboutEqual(v[1], 0.5) &&
+                isAboutEqual(v[2], 0.75) &&
+                isAboutEqual(v[3], 1),
+                "gl.clearColor should not change after canvas resize");
+      v = gl.getParameter(gl.COLOR_WRITEMASK);
+      assertMsg(isAboutEqual(v[0], 0) &&
+                isAboutEqual(v[1], 0) &&
+                isAboutEqual(v[2], 0) &&
+                isAboutEqual(v[3], 0),
+                "gl.colorMask should not change after canvas resize");
+      shouldBe('getViewport()', '"0,0,300,150"');
+      checkCanvasContentIs(0, 0, 0, 0);
+
+      debug("");
+      successfullyParsed = true;
+      shouldBeTrue("successfullyParsed");
+      debug('<br /><span class="pass">TEST COMPLETE</span>');
+      notifyFinishedToHarness();
+    }
+   }, 1000/30);
+}
+
+
+</script>
+<script>
+</script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/constants.html
@@ -0,0 +1,488 @@
+<html>
+<head>
+<!--
+Copyright (c) 2009 Ilmari Heikkinen. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>WebGL Constants Test</title>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/desktop-gl-constants.js" type="text/javascript"></script>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/webgl-test.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<canvas id="canvas" style="width: 50px; height: 50px;"> </canvas>
+<script>
+description("This test ensures that the WebGL context has all the constants in the specification.");
+
+var constants = {
+    /* ClearBufferMask */
+DEPTH_BUFFER_BIT               : 0x00000100,
+STENCIL_BUFFER_BIT             : 0x00000400,
+COLOR_BUFFER_BIT               : 0x00004000,
+    
+    /* BeginMode */
+POINTS                         : 0x0000,
+LINES                          : 0x0001,
+LINE_LOOP                      : 0x0002,
+LINE_STRIP                     : 0x0003,
+TRIANGLES                      : 0x0004,
+TRIANGLE_STRIP                 : 0x0005,
+TRIANGLE_FAN                   : 0x0006,
+    
+    /* AlphaFunction (not supported in ES20) */
+    /*      NEVER */
+    /*      LESS */
+    /*      EQUAL */
+    /*      LEQUAL */
+    /*      GREATER */
+    /*      NOTEQUAL */
+    /*      GEQUAL */
+    /*      ALWAYS */
+    
+    /* BlendingFactorDest */
+ZERO                           : 0,
+ONE                            : 1,
+SRC_COLOR                      : 0x0300,
+ONE_MINUS_SRC_COLOR            : 0x0301,
+SRC_ALPHA                      : 0x0302,
+ONE_MINUS_SRC_ALPHA            : 0x0303,
+DST_ALPHA                      : 0x0304,
+ONE_MINUS_DST_ALPHA            : 0x0305,
+    
+    /* BlendingFactorSrc */
+    /*      ZERO */
+    /*      ONE */
+DST_COLOR                      : 0x0306,
+ONE_MINUS_DST_COLOR            : 0x0307,
+SRC_ALPHA_SATURATE             : 0x0308,
+    /*      SRC_ALPHA */
+    /*      ONE_MINUS_SRC_ALPHA */
+    /*      DST_ALPHA */
+    /*      ONE_MINUS_DST_ALPHA */
+    
+    /* BlendEquationSeparate */
+FUNC_ADD                       : 0x8006,
+BLEND_EQUATION                 : 0x8009,
+BLEND_EQUATION_RGB             : 0x8009,   /* same as BLEND_EQUATION */
+BLEND_EQUATION_ALPHA           : 0x883D,
+    
+    /* BlendSubtract */
+FUNC_SUBTRACT                  : 0x800A,
+FUNC_REVERSE_SUBTRACT          : 0x800B,
+    
+    /* Separate Blend Functions */
+BLEND_DST_RGB                  : 0x80C8,
+BLEND_SRC_RGB                  : 0x80C9,
+BLEND_DST_ALPHA                : 0x80CA,
+BLEND_SRC_ALPHA                : 0x80CB,
+CONSTANT_COLOR                 : 0x8001,
+ONE_MINUS_CONSTANT_COLOR       : 0x8002,
+CONSTANT_ALPHA                 : 0x8003,
+ONE_MINUS_CONSTANT_ALPHA       : 0x8004,
+BLEND_COLOR                    : 0x8005,
+    
+    /* Buffer Objects */
+ARRAY_BUFFER                   : 0x8892,
+ELEMENT_ARRAY_BUFFER           : 0x8893,
+ARRAY_BUFFER_BINDING           : 0x8894,
+ELEMENT_ARRAY_BUFFER_BINDING   : 0x8895,
+    
+STREAM_DRAW                    : 0x88E0,
+STATIC_DRAW                    : 0x88E4,
+DYNAMIC_DRAW                   : 0x88E8,
+    
+BUFFER_SIZE                    : 0x8764,
+BUFFER_USAGE                   : 0x8765,
+    
+CURRENT_VERTEX_ATTRIB          : 0x8626,
+    
+    /* CullFaceMode */
+FRONT                          : 0x0404,
+BACK                           : 0x0405,
+FRONT_AND_BACK                 : 0x0408,
+    
+    /* DepthFunction */
+    /*      NEVER */
+    /*      LESS */
+    /*      EQUAL */
+    /*      LEQUAL */
+    /*      GREATER */
+    /*      NOTEQUAL */
+    /*      GEQUAL */
+    /*      ALWAYS */
+    
+    /* EnableCap */
+    /* TEXTURE_2D */
+CULL_FACE                      : 0x0B44,
+BLEND                          : 0x0BE2,
+DITHER                         : 0x0BD0,
+STENCIL_TEST                   : 0x0B90,
+DEPTH_TEST                     : 0x0B71,
+SCISSOR_TEST                   : 0x0C11,
+POLYGON_OFFSET_FILL            : 0x8037,
+SAMPLE_ALPHA_TO_COVERAGE       : 0x809E,
+SAMPLE_COVERAGE                : 0x80A0,
+    
+    /* ErrorCode */
+NO_ERROR                       : 0,
+INVALID_ENUM                   : 0x0500,
+INVALID_VALUE                  : 0x0501,
+INVALID_OPERATION              : 0x0502,
+OUT_OF_MEMORY                  : 0x0505,
+    
+    /* FrontFaceDirection */
+CW                             : 0x0900,
+CCW                            : 0x0901,
+    
+    /* GetPName */
+LINE_WIDTH                     : 0x0B21,
+ALIASED_POINT_SIZE_RANGE       : 0x846D,
+ALIASED_LINE_WIDTH_RANGE       : 0x846E,
+CULL_FACE_MODE                 : 0x0B45,
+FRONT_FACE                     : 0x0B46,
+DEPTH_RANGE                    : 0x0B70,
+DEPTH_WRITEMASK                : 0x0B72,
+DEPTH_CLEAR_VALUE              : 0x0B73,
+DEPTH_FUNC                     : 0x0B74,
+STENCIL_CLEAR_VALUE            : 0x0B91,
+STENCIL_FUNC                   : 0x0B92,
+STENCIL_FAIL                   : 0x0B94,
+STENCIL_PASS_DEPTH_FAIL        : 0x0B95,
+STENCIL_PASS_DEPTH_PASS        : 0x0B96,
+STENCIL_REF                    : 0x0B97,
+STENCIL_VALUE_MASK             : 0x0B93,
+STENCIL_WRITEMASK              : 0x0B98,
+STENCIL_BACK_FUNC              : 0x8800,
+STENCIL_BACK_FAIL              : 0x8801,
+STENCIL_BACK_PASS_DEPTH_FAIL   : 0x8802,
+STENCIL_BACK_PASS_DEPTH_PASS   : 0x8803,
+STENCIL_BACK_REF               : 0x8CA3,
+STENCIL_BACK_VALUE_MASK        : 0x8CA4,
+STENCIL_BACK_WRITEMASK         : 0x8CA5,
+VIEWPORT                       : 0x0BA2,
+SCISSOR_BOX                    : 0x0C10,
+    /*      SCISSOR_TEST */
+COLOR_CLEAR_VALUE              : 0x0C22,
+COLOR_WRITEMASK                : 0x0C23,
+UNPACK_ALIGNMENT               : 0x0CF5,
+PACK_ALIGNMENT                 : 0x0D05,
+MAX_TEXTURE_SIZE               : 0x0D33,
+MAX_VIEWPORT_DIMS              : 0x0D3A,
+SUBPIXEL_BITS                  : 0x0D50,
+RED_BITS                       : 0x0D52,
+GREEN_BITS                     : 0x0D53,
+BLUE_BITS                      : 0x0D54,
+ALPHA_BITS                     : 0x0D55,
+DEPTH_BITS                     : 0x0D56,
+STENCIL_BITS                   : 0x0D57,
+POLYGON_OFFSET_UNITS           : 0x2A00,
+    /*      POLYGON_OFFSET_FILL */
+POLYGON_OFFSET_FACTOR          : 0x8038,
+TEXTURE_BINDING_2D             : 0x8069,
+SAMPLE_BUFFERS                 : 0x80A8,
+SAMPLES                        : 0x80A9,
+SAMPLE_COVERAGE_VALUE          : 0x80AA,
+SAMPLE_COVERAGE_INVERT         : 0x80AB,
+    
+    /* GetTextureParameter */
+    /*      TEXTURE_MAG_FILTER */
+    /*      TEXTURE_MIN_FILTER */
+    /*      TEXTURE_WRAP_S */
+    /*      TEXTURE_WRAP_T */
+    
+NUM_COMPRESSED_TEXTURE_FORMATS : 0x86A2,
+COMPRESSED_TEXTURE_FORMATS     : 0x86A3,
+    
+    /* HintMode */
+DONT_CARE                      : 0x1100,
+FASTEST                        : 0x1101,
+NICEST                         : 0x1102,
+    
+    /* HintTarget */
+GENERATE_MIPMAP_HINT            : 0x8192,
+    
+    /* DataType */
+BYTE                           : 0x1400,
+UNSIGNED_BYTE                  : 0x1401,
+SHORT                          : 0x1402,
+UNSIGNED_SHORT                 : 0x1403,
+INT                            : 0x1404,
+UNSIGNED_INT                   : 0x1405,
+FLOAT                          : 0x1406,
+    
+    /* PixelFormat */
+DEPTH_COMPONENT                : 0x1902,
+ALPHA                          : 0x1906,
+RGB                            : 0x1907,
+RGBA                           : 0x1908,
+LUMINANCE                      : 0x1909,
+LUMINANCE_ALPHA                : 0x190A,
+    
+    /* PixelType */
+    /*      UNSIGNED_BYTE */
+UNSIGNED_SHORT_4_4_4_4         : 0x8033,
+UNSIGNED_SHORT_5_5_5_1         : 0x8034,
+UNSIGNED_SHORT_5_6_5           : 0x8363,
+    
+    /* Shaders */
+FRAGMENT_SHADER                  : 0x8B30,
+VERTEX_SHADER                    : 0x8B31,
+MAX_VERTEX_ATTRIBS               : 0x8869,
+MAX_VERTEX_UNIFORM_VECTORS       : 0x8DFB,
+MAX_VARYING_VECTORS              : 0x8DFC,
+MAX_COMBINED_TEXTURE_IMAGE_UNITS : 0x8B4D,
+MAX_VERTEX_TEXTURE_IMAGE_UNITS   : 0x8B4C,
+MAX_TEXTURE_IMAGE_UNITS          : 0x8872,
+MAX_FRAGMENT_UNIFORM_VECTORS     : 0x8DFD,
+SHADER_TYPE                      : 0x8B4F,
+DELETE_STATUS                    : 0x8B80,
+LINK_STATUS                      : 0x8B82,
+VALIDATE_STATUS                  : 0x8B83,
+ATTACHED_SHADERS                 : 0x8B85,
+ACTIVE_UNIFORMS                  : 0x8B86,
+ACTIVE_UNIFORM_MAX_LENGTH        : 0x8B87,
+ACTIVE_ATTRIBUTES                : 0x8B89,
+ACTIVE_ATTRIBUTE_MAX_LENGTH      : 0x8B8A,
+SHADING_LANGUAGE_VERSION         : 0x8B8C,
+CURRENT_PROGRAM                  : 0x8B8D,
+    
+    /* StencilFunction */
+NEVER                          : 0x0200,
+LESS                           : 0x0201,
+EQUAL                          : 0x0202,
+LEQUAL                         : 0x0203,
+GREATER                        : 0x0204,
+NOTEQUAL                       : 0x0205,
+GEQUAL                         : 0x0206,
+ALWAYS                         : 0x0207,
+    
+    /* StencilOp */
+    /*      ZERO */
+KEEP                           : 0x1E00,
+REPLACE                        : 0x1E01,
+INCR                           : 0x1E02,
+DECR                           : 0x1E03,
+INVERT                         : 0x150A,
+INCR_WRAP                      : 0x8507,
+DECR_WRAP                      : 0x8508,
+    
+    /* StringName */
+VENDOR                         : 0x1F00,
+RENDERER                       : 0x1F01,
+VERSION                        : 0x1F02,
+EXTENSIONS                     : 0x1F03,
+    
+    /* TextureMagFilter */
+NEAREST                        : 0x2600,
+LINEAR                         : 0x2601,
+    
+    /* TextureMinFilter */
+    /*      NEAREST */
+    /*      LINEAR */
+NEAREST_MIPMAP_NEAREST         : 0x2700,
+LINEAR_MIPMAP_NEAREST          : 0x2701,
+NEAREST_MIPMAP_LINEAR          : 0x2702,
+LINEAR_MIPMAP_LINEAR           : 0x2703,
+    
+    /* TextureParameterName */
+TEXTURE_MAG_FILTER             : 0x2800,
+TEXTURE_MIN_FILTER             : 0x2801,
+TEXTURE_WRAP_S                 : 0x2802,
+TEXTURE_WRAP_T                 : 0x2803,
+    
+    /* TextureTarget */
+TEXTURE_2D                     : 0x0DE1,
+TEXTURE                        : 0x1702,
+    
+TEXTURE_CUBE_MAP               : 0x8513,
+TEXTURE_BINDING_CUBE_MAP       : 0x8514,
+TEXTURE_CUBE_MAP_POSITIVE_X    : 0x8515,
+TEXTURE_CUBE_MAP_NEGATIVE_X    : 0x8516,
+TEXTURE_CUBE_MAP_POSITIVE_Y    : 0x8517,
+TEXTURE_CUBE_MAP_NEGATIVE_Y    : 0x8518,
+TEXTURE_CUBE_MAP_POSITIVE_Z    : 0x8519,
+TEXTURE_CUBE_MAP_NEGATIVE_Z    : 0x851A,
+MAX_CUBE_MAP_TEXTURE_SIZE      : 0x851C,
+    
+    /* TextureUnit */
+TEXTURE0                       : 0x84C0,
+TEXTURE1                       : 0x84C1,
+TEXTURE2                       : 0x84C2,
+TEXTURE3                       : 0x84C3,
+TEXTURE4                       : 0x84C4,
+TEXTURE5                       : 0x84C5,
+TEXTURE6                       : 0x84C6,
+TEXTURE7                       : 0x84C7,
+TEXTURE8                       : 0x84C8,
+TEXTURE9                       : 0x84C9,
+TEXTURE10                      : 0x84CA,
+TEXTURE11                      : 0x84CB,
+TEXTURE12                      : 0x84CC,
+TEXTURE13                      : 0x84CD,
+TEXTURE14                      : 0x84CE,
+TEXTURE15                      : 0x84CF,
+TEXTURE16                      : 0x84D0,
+TEXTURE17                      : 0x84D1,
+TEXTURE18                      : 0x84D2,
+TEXTURE19                      : 0x84D3,
+TEXTURE20                      : 0x84D4,
+TEXTURE21                      : 0x84D5,
+TEXTURE22                      : 0x84D6,
+TEXTURE23                      : 0x84D7,
+TEXTURE24                      : 0x84D8,
+TEXTURE25                      : 0x84D9,
+TEXTURE26                      : 0x84DA,
+TEXTURE27                      : 0x84DB,
+TEXTURE28                      : 0x84DC,
+TEXTURE29                      : 0x84DD,
+TEXTURE30                      : 0x84DE,
+TEXTURE31                      : 0x84DF,
+ACTIVE_TEXTURE                 : 0x84E0,
+    
+    /* TextureWrapMode */
+REPEAT                         : 0x2901,
+CLAMP_TO_EDGE                  : 0x812F,
+MIRRORED_REPEAT                : 0x8370,
+    
+    /* Uniform Types */
+FLOAT_VEC2                     : 0x8B50,
+FLOAT_VEC3                     : 0x8B51,
+FLOAT_VEC4                     : 0x8B52,
+INT_VEC2                       : 0x8B53,
+INT_VEC3                       : 0x8B54,
+INT_VEC4                       : 0x8B55,
+BOOL                           : 0x8B56,
+BOOL_VEC2                      : 0x8B57,
+BOOL_VEC3                      : 0x8B58,
+BOOL_VEC4                      : 0x8B59,
+FLOAT_MAT2                     : 0x8B5A,
+FLOAT_MAT3                     : 0x8B5B,
+FLOAT_MAT4                     : 0x8B5C,
+SAMPLER_2D                     : 0x8B5E,
+SAMPLER_CUBE                   : 0x8B60,
+    
+    /* Vertex Arrays */
+VERTEX_ATTRIB_ARRAY_ENABLED        : 0x8622,
+VERTEX_ATTRIB_ARRAY_SIZE           : 0x8623,
+VERTEX_ATTRIB_ARRAY_STRIDE         : 0x8624,
+VERTEX_ATTRIB_ARRAY_TYPE           : 0x8625,
+VERTEX_ATTRIB_ARRAY_NORMALIZED     : 0x886A,
+VERTEX_ATTRIB_ARRAY_POINTER        : 0x8645,
+VERTEX_ATTRIB_ARRAY_BUFFER_BINDING : 0x889F,
+    
+    /* Read Format */
+IMPLEMENTATION_COLOR_READ_TYPE   : 0x8B9A,
+IMPLEMENTATION_COLOR_READ_FORMAT : 0x8B9B,
+    
+    /* Shader Source */
+COMPILE_STATUS                 : 0x8B81,
+INFO_LOG_LENGTH                : 0x8B84,
+SHADER_SOURCE_LENGTH           : 0x8B88,
+SHADER_COMPILER                : 0x8DFA,
+    
+    /* Shader Precision-Specified Types */
+LOW_FLOAT                      : 0x8DF0,
+MEDIUM_FLOAT                   : 0x8DF1,
+HIGH_FLOAT                     : 0x8DF2,
+LOW_INT                        : 0x8DF3,
+MEDIUM_INT                     : 0x8DF4,
+HIGH_INT                       : 0x8DF5,
+    
+    /* Framebuffer Object. */
+FRAMEBUFFER                    : 0x8D40,
+RENDERBUFFER                   : 0x8D41,
+    
+RGBA4                          : 0x8056,
+RGB5_A1                        : 0x8057,
+RGB565                         : 0x8D62,
+DEPTH_COMPONENT16              : 0x81A5,
+STENCIL_INDEX                  : 0x1901,
+STENCIL_INDEX8                 : 0x8D48,
+    
+RENDERBUFFER_WIDTH             : 0x8D42,
+RENDERBUFFER_HEIGHT            : 0x8D43,
+RENDERBUFFER_INTERNAL_FORMAT   : 0x8D44,
+RENDERBUFFER_RED_SIZE          : 0x8D50,
+RENDERBUFFER_GREEN_SIZE        : 0x8D51,
+RENDERBUFFER_BLUE_SIZE         : 0x8D52,
+RENDERBUFFER_ALPHA_SIZE        : 0x8D53,
+RENDERBUFFER_DEPTH_SIZE        : 0x8D54,
+RENDERBUFFER_STENCIL_SIZE      : 0x8D55,
+    
+FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE           : 0x8CD0,
+FRAMEBUFFER_ATTACHMENT_OBJECT_NAME           : 0x8CD1,
+FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL         : 0x8CD2,
+FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE : 0x8CD3,
+    
+COLOR_ATTACHMENT0              : 0x8CE0,
+DEPTH_ATTACHMENT               : 0x8D00,
+STENCIL_ATTACHMENT             : 0x8D20,
+    
+NONE                           : 0,
+    
+FRAMEBUFFER_COMPLETE                      : 0x8CD5,
+FRAMEBUFFER_INCOMPLETE_ATTACHMENT         : 0x8CD6,
+FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT : 0x8CD7,
+FRAMEBUFFER_INCOMPLETE_DIMENSIONS         : 0x8CD9,
+FRAMEBUFFER_UNSUPPORTED                   : 0x8CDD,
+  
+FRAMEBUFFER_BINDING            : 0x8CA6,
+RENDERBUFFER_BINDING           : 0x8CA7,
+MAX_RENDERBUFFER_SIZE          : 0x84E8,
+    
+INVALID_FRAMEBUFFER_OPERATION  : 0x0506
+};
+
+function assertProperty(v, p) {
+  if (v[p] == null) {
+    testFailed("Property does not exist: " + p)
+    return false;
+  } else {
+    return true;
+  }
+}
+
+function assertMsg_(bool, msg) {
+  if (!bool) // show only failures to avoid spamming result list
+    assertMsg(bool, msg);
+  return bool;
+}
+
+debug("");
+debug("Canvas.getContext");
+
+var canvas = document.getElementById("canvas");
+var gl = create3DContext(canvas);
+var passed = true;
+for (var i in constants) {
+  var r = assertProperty(gl, i) && assertMsg_(gl[i] == constants[i], "Property "+i+" value test "+gl[i]+" == "+constants[i]);
+  passed = passed && r;
+}
+if (passed) {
+  testPassed("All WebGL constants found to have correct values.");
+}
+var extended = false;
+for (var i in gl) {
+  if (i.match(/^[^a-z]/) && constants[i] == null) {
+    if (!extended) {
+      extended = true;
+      debug("Also found the following extra constants:");
+    }
+    debug(i);
+  }
+}
+
+debug("");
+successfullyParsed = true;
+</script>
+<script src="../resources/js-test-post.js"></script>
+<script>
+</script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/context-type-test.html
@@ -0,0 +1,47 @@
+<!--
+Copyright (c) 2009 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+ -->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+  "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>WebGL Canvas Conformance Tests</title>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/desktop-gl-constants.js" type="text/javascript"></script>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/webgl-test.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<canvas id="canvas" style="width: 50px; height: 50px;"> </canvas>
+<canvas id="canvas2d" width="40" height="40"> </canvas>
+<script>
+description("This test ensures WebGL implementations interact correctly with the canvas tag.");
+
+debug("");
+debug("Canvas.getContext");
+
+var canvas = document.getElementById("canvas");
+var gl = create3DContext(canvas);
+if (!gl) {
+  testFailed("context does not exist");
+} else {
+  testPassed("context exists");
+
+  debug("Checking context type");
+  assertMsg(gl instanceof WebGLRenderingContext,
+            "context type should be WebGLRenderingContext");
+}
+debug("");
+successfullyParsed = true;
+</script>
+<script src="../resources/js-test-post.js"></script>
+<script>
+</script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/draw-arrays-out-of-bounds.html
@@ -0,0 +1,77 @@
+<!--
+Copyright (C) 2009 Apple Computer, Inc.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<html>
+<head>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/webgl-test.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+
+<script>
+description("Test of drawArrays with out-of-bounds parameters");
+
+var context = create3DContext();
+var program = loadStandardProgram(context);
+
+context.useProgram(program);
+var vertexObject = context.createBuffer();
+context.bindBuffer(context.ARRAY_BUFFER, vertexObject);
+context.enableVertexAttribArray(0);
+
+debug("Test empty buffer")
+context.bufferData(context.ARRAY_BUFFER, new WebGLFloatArray([  ]), context.STATIC_DRAW);
+context.vertexAttribPointer(0, 3, context.FLOAT, false, 0, 0);
+shouldGenerateGLError(context, context.INVALID_OPERATION, "context.drawArrays(context.TRIANGLES, 0, 1)");
+shouldGenerateGLError(context, context.INVALID_OPERATION, "context.drawArrays(context.TRIANGLES, 0, 10000)");
+shouldGenerateGLError(context, context.INVALID_OPERATION, "context.drawArrays(context.TRIANGLES, 0, 10000000000000)");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.drawArrays(context.TRIANGLES, 0, -1)");
+shouldGenerateGLError(context, context.INVALID_OPERATION, "context.drawArrays(context.TRIANGLES, 1, 0)");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.drawArrays(context.TRIANGLES, -1, 0)");
+shouldGenerateGLError(context, context.INVALID_OPERATION, "context.drawArrays(context.TRIANGLES, 1, -1)");
+shouldGenerateGLError(context, context.INVALID_OPERATION, "context.drawArrays(context.TRIANGLES, -1, 1)");
+
+debug("")
+debug("Test buffer with 3 float vectors")
+context.bufferData(context.ARRAY_BUFFER, new WebGLFloatArray([ 0,0.5,0, -0.5,-0.5,0, 0.5,-0.5,0 ]), context.STATIC_DRAW);
+context.vertexAttribPointer(0, 3, context.FLOAT, false, 0, 0);
+shouldGenerateGLError(context, context.NO_ERROR, "context.drawArrays(context.TRIANGLES, 0, 3)");
+shouldGenerateGLError(context, context.INVALID_OPERATION, "context.drawArrays(context.TRIANGLES, 3, 2)");
+shouldGenerateGLError(context, context.INVALID_OPERATION, "context.drawArrays(context.TRIANGLES, 0, 10000)");
+shouldGenerateGLError(context, context.INVALID_OPERATION, "context.drawArrays(context.TRIANGLES, 0, 10000000000000)");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.drawArrays(context.TRIANGLES, 0, -1)");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.drawArrays(context.TRIANGLES, -1, 0)");
+shouldGenerateGLError(context, context.INVALID_OPERATION, "context.drawArrays(context.TRIANGLES, 1, -1)");
+shouldGenerateGLError(context, context.INVALID_OPERATION, "context.drawArrays(context.TRIANGLES, -1, 1)");
+
+debug("")
+successfullyParsed = true;
+</script>
+
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/draw-elements-out-of-bounds.html
@@ -0,0 +1,79 @@
+<!--
+Copyright (C) 2009 Apple Computer, Inc.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<html>
+<head>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/webgl-test.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+
+<script>
+description("Test of drawElements with out-of-bounds parameters");
+
+var context = create3DContext();
+var program = loadStandardProgram(context);
+
+context.useProgram(program);
+var vertexObject = context.createBuffer();
+context.enableVertexAttribArray(0);
+context.bindBuffer(context.ARRAY_BUFFER, vertexObject);
+context.bufferData(context.ARRAY_BUFFER, new WebGLFloatArray([ 0,0.5,0, -0.5,-0.5,0, 0.5,-0.5,0 ]), context.STATIC_DRAW);
+context.vertexAttribPointer(0, 3, context.FLOAT, false, 0, 0);
+
+var indexObject = context.createBuffer();
+
+debug("Test empty index buffer")
+context.bindBuffer(context.ELEMENT_ARRAY_BUFFER, indexObject);
+context.bufferData(context.ELEMENT_ARRAY_BUFFER, new WebGLUnsignedByteArray([  ]), context.STATIC_DRAW);
+shouldGenerateGLError(context, context.INVALID_OPERATION, "context.drawElements(context.TRIANGLES, 3, context.UNSIGNED_BYTE, 0)");
+shouldGenerateGLError(context, context.INVALID_OPERATION, "context.drawElements(context.TRIANGLES, 10000, context.UNSIGNED_BYTE, 0)");
+shouldGenerateGLError(context, context.INVALID_OPERATION, "context.drawElements(context.TRIANGLES, 10000000000000, context.UNSIGNED_BYTE, 0)");
+shouldGenerateGLError(context, context.INVALID_OPERATION, "context.drawElements(context.TRIANGLES, 1, context.UNSIGNED_BYTE, 0)");
+shouldGenerateGLError(context, context.INVALID_OPERATION, "context.drawElements(context.TRIANGLES, 0, context.UNSIGNED_BYTE, -1)");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.drawElements(context.TRIANGLES, -1, context.UNSIGNED_BYTE, 1)");
+shouldGenerateGLError(context, context.INVALID_OPERATION, "context.drawElements(context.TRIANGLES, 1, context.UNSIGNED_BYTE, -1)");
+
+debug("")
+debug("Test buffer with 3 byte indexes")
+context.bindBuffer(context.ELEMENT_ARRAY_BUFFER, indexObject);
+context.bufferData(context.ELEMENT_ARRAY_BUFFER, new WebGLUnsignedByteArray([ 0, 1, 2 ]), context.STATIC_DRAW);
+shouldGenerateGLError(context, context.NO_ERROR, "context.drawElements(context.TRIANGLES, 3, context.UNSIGNED_BYTE, 0)");
+shouldGenerateGLError(context, context.INVALID_OPERATION, "context.drawElements(context.TRIANGLES, 3, context.UNSIGNED_BYTE, 2)");
+shouldGenerateGLError(context, context.INVALID_OPERATION, "context.drawElements(context.TRIANGLES, 10000, context.UNSIGNED_BYTE, 0)");
+shouldGenerateGLError(context, context.INVALID_OPERATION, "context.drawElements(context.TRIANGLES, 10000000000000, context.UNSIGNED_BYTE, 0)");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.drawElements(context.TRIANGLES, 0, context.UNSIGNED_BYTE, -1)");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.drawElements(context.TRIANGLES, -1, context.UNSIGNED_BYTE, 1)");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.drawElements(context.TRIANGLES, 1, context.UNSIGNED_BYTE, -1)");
+
+debug("")
+successfullyParsed = true;
+</script>
+
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/error-reporting.html
@@ -0,0 +1,44 @@
+<!--
+Copyright (c) 2009 The Chromium Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<html>
+<head>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/webgl-test.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+
+<script src="resources/error-reporting.js"></script>
+
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/framebuffer-test.html
@@ -0,0 +1,133 @@
+<!--
+Copyright (c) 2009 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+ -->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+  "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>WebGL Framebuffer Test</title>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/desktop-gl-constants.js" type="text/javascript"></script>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/webgl-test.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<canvas id="canvas" width="2" height="2"> </canvas>
+<script>
+description("This tests framebuffer/renderbuffer-related functions");
+
+debug("");
+debug("Canvas.getContext");
+
+var canvas = document.getElementById("canvas");
+var gl = create3DContext(canvas);
+if (!gl) {
+  testFailed("context does not exist");
+} else {
+  testPassed("context exists");
+
+  debug("");
+  debug("Checking framebuffer/renderbuffer stuff.");
+
+  var value = gl.getFramebufferAttachmentParameter(
+     gl.FRAMEBUFFER,
+     gl.COLOR_ATTACHMENT0,
+     gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE);
+  assertMsg(gl.getError() == gl.INVALID_OPERATION,
+     "calling getFramebufferAttachmentParameter on the default framebuffer should generate INVALID_OPERATION.");
+
+  var tex = gl.createTexture();
+  gl.bindTexture(gl.TEXTURE_2D, tex);
+  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+  gl.texImage2D(gl.TEXTURE_2D,
+                0,                 // level
+                gl.RGBA,           // internalFormat
+                canvas.width,      // width
+                canvas.height,     // height
+                0,                 // border
+                gl.RGBA,           // format
+                gl.UNSIGNED_BYTE,  // type
+                null);             // data
+  gl.framebufferTexture2D(
+      gl.FRAMEBUFFER,
+      gl.COLOR_ATTACHMENT0,
+      gl.TEXTURE_2D,
+      tex,
+      0);
+  assertMsg(gl.getError() == gl.INVALID_OPERATION,
+            "trying to attach a texture to default framebuffer should generate INVALID_OPERATION.");
+
+  gl.framebufferRenderbuffer(
+      gl.FRAMEBUFFER,
+      gl.COLOR_ATTACHMENT0,
+      gl.RENDERBUFFER,
+      null);
+  assertMsg(gl.getError() == gl.INVALID_OPERATION,
+            "trying to detach default renderbuffer from default framebuffer should generate INVALID_OPERATION.");
+
+  var rb = gl.createRenderbuffer();
+  gl.bindRenderbuffer(gl.RENDERBUFFER, rb);
+  gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, canvas.width, canvas.height);
+  assertMsg(gl.getError() == gl.NO_ERROR,
+            "allocating renderbuffer storage of a newly created renderbuffer should succeed.");
+
+  gl.framebufferRenderbuffer(
+      gl.FRAMEBUFFER,
+      gl.COLOR_ATTACHMENT0,
+      gl.RENDERBUFFER,
+      rb);
+  assertMsg(gl.getError() == gl.INVALID_OPERATION,
+            "trying to attach a renderbuffer to the default framebuffer should generate INVALID_OPERATION.");
+
+  var fbtex = gl.createTexture();
+  gl.bindTexture(gl.TEXTURE_2D, fbtex);
+  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, canvas.width, canvas.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+  var fb = gl.createFramebuffer();
+
+  gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+  assertMsg(gl.getError() == gl.NO_ERROR,
+            "binding a newly created framebuffer should succeed.");
+
+  gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, fbtex, 0);
+  assertMsg(gl.getError() == gl.NO_ERROR,
+            "attaching a texture to a framebuffer should succeed.");
+
+  gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, null, 0);
+  assertMsg(gl.getError() == gl.NO_ERROR,
+            "detaching a texture from a framebuffer should succeed.");
+
+  gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, fbtex, 1);
+  assertMsg(gl.getError() == gl.INVALID_VALUE,
+            "calling framebufferTexture2D with non-zero mipmap level should generate INVALID_VALUE.");
+
+  gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb);
+  assertMsg(gl.getError() == gl.NO_ERROR,
+            "attaching a renderbuffer to a framebuffer should succeed.");
+
+  gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, null);
+  assertMsg(gl.getError() == gl.NO_ERROR,
+            "detaching a renderbuffer from a framebuffer should succeed.");
+
+  gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+  assertMsg(gl.getError() == gl.NO_ERROR,
+            "binding default (null) framebuffer should succeed.");
+}
+
+debug("");
+successfullyParsed = true;
+
+</script>
+<script src="../resources/js-test-post.js"></script>
+<script>
+</script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/get-active-test.html
@@ -0,0 +1,40 @@
+<!--
+Copyright (C) 2009 Apple Computer, Inc.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+
+<html>
+<head>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/webgl-test.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+
+<script src="resources/get-active-test.js"></script>
+
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/gl-bindattribLocation-test.html
@@ -0,0 +1,210 @@
+<!--
+Copyright (c) 2009 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+ -->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+  "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>WebGL BindAttribLocation Conformance Tests</title>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/desktop-gl-constants.js" type="text/javascript"></script>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/webgl-test.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<canvas style="border: 1px solid black;" id="canvas" width="50" height="50">
+</canvas><script id="vshader" type="text/something-not-javascript">
+attribute vec4 vPosition;
+attribute vec4 vColor;
+varying vec4 color;
+void main()
+{
+    gl_Position = vPosition;
+    color = vColor;
+}
+</script>
+<script id="fshader" type="text/something-not-javascript">
+precision mediump float;
+varying vec4 color;
+void main()
+{
+    gl_FragColor = color;
+}
+</script>
+<script>
+description("This test ensures WebGL implementations don't allow names that start with 'gl_' when calling bindAttribLocation.");
+
+debug("");
+debug("Canvas.getContext");
+
+var gl = create3DContext(document.getElementById("canvas"));
+if (!gl) {
+  testFailed("context does not exist");
+} else {
+  testPassed("context exists");
+
+  function fail(x,y, buf, shouldBe)
+  {
+      var i = (y*50+x) * 4;
+      var reason = "pixel at ("+x+","+y+") is ("+buf[i]+","+buf[i+1]+","+buf[i+2]+","+buf[i+3]+"), should be "+shouldBe;
+      testFailed(reason);
+  }
+
+  function pass()
+  {
+      testPassed("drawing is correct");
+  }
+
+  function loadShader(shaderType, shaderId) {
+    // Get the shader source.
+    var shaderSource = document.getElementById(shaderId).text;
+
+    // Create the shader object
+    var shader = gl.createShader(shaderType);
+    if (shader == null) {
+        debug("*** Error: unable to create shader '"+shaderId+"'");
+        return null;
+    }
+
+    // Load the shader source
+    gl.shaderSource(shader, shaderSource);
+
+    // Compile the shader
+    gl.compileShader(shader);
+
+    // Check the compile status
+    var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
+    if (!compiled) {
+        // Something went wrong during compilation; get the error
+        var error = gl.getShaderInfoLog(shader);
+        log("*** Error compiling shader '"+shader+"':"+error);
+        gl.deleteShader(shader);
+        return null;
+    }
+    return shader;
+  }
+
+  debug("");
+  debug("Checking gl.bindAttribLocation.");
+
+  var program = gl.createProgram();
+  gl.bindAttribLocation(program, 0, "gl_foo");
+  assertMsg(gl.getError() == gl.INVALID_OPERATION,
+            "bindAttribLocation should return INVALID_OPERATION if name starts with 'gl_'");
+  gl.bindAttribLocation(program, 0, "gl_TexCoord0");
+  assertMsg(gl.getError() == gl.INVALID_OPERATION,
+            "bindAttribLocation should return INVALID_OPERATION if name starts with 'gl_'");
+
+  var vs = loadShader(gl.VERTEX_SHADER, "vshader");
+  var fs = loadShader(gl.FRAGMENT_SHADER, "fshader");
+  gl.attachShader(program, vs);
+  gl.attachShader(program, fs);
+
+  var positions = gl.createBuffer();
+  gl.bindBuffer(gl.ARRAY_BUFFER, positions);
+  gl.bufferData(gl.ARRAY_BUFFER, new WebGLFloatArray([ 0,0.5,0, -0.5,-0.5,0, 0.5,-0.5,0 ]), gl.STATIC_DRAW);
+
+  var colors = gl.createBuffer();
+  gl.bindBuffer(gl.ARRAY_BUFFER, colors);
+  gl.bufferData(gl.ARRAY_BUFFER, new WebGLFloatArray([
+     0,1,0,1,
+     0,1,0,1,
+     0,1,0,1]), gl.STATIC_DRAW);
+
+  function setBindLocations(colorLocation, positionLocation) {
+    gl.bindAttribLocation(program, positionLocation, "vPosition");
+    gl.bindAttribLocation(program, colorLocation, "vColor");
+    gl.linkProgram(program);
+    gl.useProgram(program);
+    var linked = (gl.getProgramParameter(program, gl.LINK_STATUS) != 0);
+    assertMsg(linked, "program linked successfully");
+
+    debug("vPosition:" + gl.getAttribLocation(program, "vPosition"))
+    debug("vColor   :" + gl.getAttribLocation(program, "vColor"))
+    assertMsg(gl.getAttribLocation(program, "vPosition") == positionLocation,
+              "location of vPositon should be " + positionLocation);
+    assertMsg(gl.getAttribLocation(program, "vColor") == colorLocation,
+              "location of vColor should be " + colorLocation);
+
+    var ploc = gl.getAttribLocation(program, "vPosition");
+    var cloc = gl.getAttribLocation(program, "vColor");
+    gl.bindBuffer(gl.ARRAY_BUFFER, positions);
+    gl.enableVertexAttribArray(positionLocation);
+    gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 0, 0);
+    gl.bindBuffer(gl.ARRAY_BUFFER, colors);
+    gl.enableVertexAttribArray(colorLocation);
+    gl.vertexAttribPointer(colorLocation, 4, gl.FLOAT, false, 0, 0);
+  }
+
+  function checkDraw(colorLocation, positionLocation, r, g, b, a) {
+    gl.clearColor(0, 0, 0, 1);
+    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+    gl.drawArrays(gl.TRIANGLES, 0, 3);
+
+    var buf = gl.readPixels(0, 0, 50, 50, gl.RGBA, gl.UNSIGNED_BYTE);
+
+    function checkPixel(x, y, r, g, b, a) {
+      var offset = (y * 50 + x) * 4;
+      if (buf[offset + 0] != r ||
+          buf[offset + 1] != g ||
+          buf[offset + 2] != b ||
+          buf[offset + 3] != a) {
+          fail(x, y, buf, "(" + r + "," + g + "," + b + "," + a + ")");
+          return false;
+      }
+      return true;
+    }
+
+    // Test several locations
+    // First line should be all black
+    var success = true;
+    for (var i = 0; i < 50; ++i) {
+      success = success && checkPixel(i, 0, 0, 0, 0, 255);
+    }
+
+    // Line 15 should be red for at least 10 rgba pixels starting 20 pixels in
+    var offset = (15 * 50 + 20) * 4;
+    for (var i = 0; i < 10; ++i) {
+      success = success && checkPixel(20 + i, 15, r, g, b, a);
+    }
+
+    // Last line should be all black
+    for (var i = 0; i < 50; ++i) {
+      success = success && checkPixel(i, 49, 0, 0, 0, 255);
+    }
+
+    if (success) {
+      pass();
+    }
+
+    gl.disableVertexAttribArray(positionLocation);
+    gl.disableVertexAttribArray(colorLocation);
+  }
+
+  setBindLocations(2, 3);
+  checkDraw(2, 3, 0, 255, 0, 255);
+  setBindLocations(0, 3);
+
+  gl.disableVertexAttribArray(0);
+  gl.vertexAttrib4f(0, 1, 0, 0, 1);
+  checkDraw(0, 3, 255, 0, 0, 255);
+
+  shouldBe("gl.getError()", "gl.NO_ERROR");
+}
+
+debug("");
+successfullyParsed = true;
+
+</script>
+<script src="../resources/js-test-post.js"></script>
+
+<script>
+</script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/gl-drawelements.html
@@ -0,0 +1,101 @@
+<!--
+Copyright (c) 2009 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+  "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+  <head>
+    <title>WebGL drawElements Test</title>
+    <link rel="stylesheet" href="../resources/js-test-style.css"/>
+    <script src="../resources/js-test-pre.js"></script>
+    <script src="resources/webgl-test.js"> </script>
+    <script src="../resources/desktop-gl-constants.js" type="text/javascript"></script>
+</head>
+<body>
+<canvas id="example" width="50" height="50"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+    <script id="vshader" type="x-shader/x-vertex">
+        attribute vec4 vPosition;
+        void main()
+        {
+            gl_Position = vPosition;
+        }
+    </script>
+
+    <script id="fshader" type="x-shader/x-fragment">
+        void main()
+        {
+            gl_FragColor = vec4(1.0,0.0,0.0,1.0);
+        }
+    </script>
+
+    <script>
+        function init()
+        {
+            if (window.layoutTestController) {
+                layoutTestController.overridePreference("WebKitWebGLEnabled", "1");
+                layoutTestController.dumpAsText();
+            }
+
+            function checkDrawElements(mode, count, type, expect, msg) {
+              gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+              gl.drawElements(mode, count, type, 0);
+              assertMsg(gl.getError() == expect, msg);
+            }
+
+            gl = initWebGL("example", "vshader", "fshader", [ "vPosition"], [ 0, 0, 0, 1 ], 1);
+
+            var vertexObject = gl.createBuffer();
+            gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
+            gl.bufferData(gl.ARRAY_BUFFER, new WebGLFloatArray([ 0,0.5,0, -0.5,-0.5,0, 0.5,-0.5,0 ]), gl.STATIC_DRAW);
+            gl.enableVertexAttribArray(0);
+            gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
+
+            var vertexObject = gl.createBuffer();
+            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, vertexObject);
+            gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new WebGLUnsignedShortArray([ 0, 1, 2]), gl.STATIC_DRAW);
+
+            checkDrawElements(gl.TRIANGLES, 3, gl.UNSIGNED_SHORT,
+                              gl.NO_ERROR, "can call gl.DrawElements with UNSIGNED_SHORT");
+
+            var vertexObject = gl.createBuffer();
+            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, vertexObject);
+            gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new WebGLUnsignedByteArray([ 0, 1, 2, 0]), gl.STATIC_DRAW);
+
+            checkDrawElements(
+                gl.TRIANGLES, 3, gl.UNSIGNED_BYTE,
+                gl.NO_ERROR, "can call gl.DrawElements with UNSIGNED_BYTE");
+            checkDrawElements(
+                desktopGL['QUAD_STRIP'], 4, gl.UNSIGNED_BYTE,
+                gl.INVALID_ENUM, "gl.DrawElements with QUAD_STRIP should return INVALID_ENUM");
+            checkDrawElements(
+                desktopGL['QUADS'], 4, gl.UNSIGNED_BYTE,
+                gl.INVALID_ENUM, "gl.DrawElements with QUADS should return INVALID_ENUM");
+            checkDrawElements(
+                desktopGL['POLYGON'], 4, gl.UNSIGNED_BYTE,
+                gl.INVALID_ENUM, "gl.DrawElements with POLYGON should return INVALID_ENUM");
+
+            var vertexObject = gl.createBuffer();
+            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, vertexObject);
+            gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new WebGLUnsignedIntArray([ 0, 1, 2]), gl.STATIC_DRAW);
+
+            checkDrawElements(
+                gl.TRIANGLES, 3, gl.UNSIGNED_INT,
+                gl.INVALID_ENUM, "gl.DrawElements should return INVALID_ENUM with UNSIGNED_INT");
+
+       }
+
+       init();
+       successfullyParsed = true;
+    </script>
+</body>
+<script src="../resources/js-test-post.js"></script>
+
+<script>
+</script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/gl-enable-enum-test.html
@@ -0,0 +1,137 @@
+<!--
+Copyright (c) 2009 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+ -->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+  "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>WebGL gl.ENABLE enums Conformance Tests</title>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/desktop-gl-constants.js" type="text/javascript"></script>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/webgl-test.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<canvas id="canvas" width="2" height="2"> </canvas>
+<script>
+description("This test ensures WebGL implementations allow OpenGL ES 2.0 features to be turned on but not non OpenGL ES 2.0 features.");
+
+debug("");
+debug("Canvas.getContext");
+
+var gl = create3DContext(document.getElementById("canvas"));
+if (!gl) {
+  testFailed("context does not exist");
+} else {
+  testPassed("context exists");
+
+  debug("");
+  debug("Checking gl.ENABLE enums.");
+
+  var invalidEnums = [
+    'ALPHA_TEST',
+    'AUTO_NORMAL',
+    'CLIP_PLANE0',
+    'CLIP_PLANE1',
+    'COLOR_LOGIC_OP',
+    'COLOR_MATERIAL',
+    'COLOR_SUM',
+    'COLOR_TABLE',
+ //   'CONVOLUTION_1D',
+ //   'CONVOLUTION_2D',
+    'FOG',
+    'HISTOGRAM',
+    'INDEX_LOGIC_OP',
+    'LIGHT0',
+    'LIGHT1',
+    'LIGHTING',
+    'LINE_SMOOTH',
+    'LINE_STIPPLE',
+    'MAP1_COLOR_4',
+    'MAP1_INDEX',
+    'MAP1_NORMAL',
+    'MAP1_TEXTURE_COORD_1',
+    'MAP1_TEXTURE_COORD_2',
+    'MAP1_TEXTURE_COORD_3',
+    'MAP1_TEXTURE_COORD_4',
+    'MAP1_VERTEX_3',
+    'MAP1_VERTEX_4',
+    'MAP2_COLOR_4',
+    'MAP2_INDEX',
+    'MAP2_NORMAL',
+    'MAP2_TEXTURE_COORD_1',
+    'MAP2_TEXTURE_COORD_2',
+    'MAP2_TEXTURE_COORD_3',
+    'MAP2_TEXTURE_COORD_4',
+    'MAP2_VERTEX_3',
+    'MAP2_VERTEX_4',
+    'MINMAX',
+    'MULTISAMPLE',
+    'NORMALIZE',
+    'POINT_SMOOTH',
+    'POINT_SPRITE',
+    'POLYGON_OFFSET_LINE',
+    'POLYGON_OFFSET_POINT',
+    'POLYGON_SMOOTH',
+    'POLYGON_STIPPLE',
+    'POST_COLOR_MATRIX_COLOR_TABLE',
+    'POST_CONVOLUTION_COLOR_TABLE',
+    'RESCALE_NORMAL',
+    'SAMPLE_ALPHA_TO_ONE',
+ //   'SEPARABLE_2D',
+    'TEXTURE_1D',
+    'TEXTURE_2D',
+    'TEXTURE_3D',
+    'TEXTURE_CUBE_MAP',
+    'TEXTURE_GEN_Q',
+    'TEXTURE_GEN_R',
+    'TEXTURE_GEN_S',
+    'TEXTURE_GEN_T',
+    'VERTEX_PROGRAM_POINT_SIZE',
+    'VERTEX_PROGRAM_TWO_SIDE'
+  ];
+
+  for (var ii = 0; ii < invalidEnums.length; ++ii) {
+    var name = invalidEnums[ii];
+    gl.enable(desktopGL[name]);
+    assertMsg(gl.getError() == gl.INVALID_ENUM,
+              "gl.enable must set INVALID_ENUM when passed GL_" + name );
+  }
+
+  var validEnums = [
+    'BLEND',
+    'CULL_FACE',
+    'DEPTH_TEST',
+    'DITHER ',
+    'POLYGON_OFFSET_FILL',
+    'SAMPLE_ALPHA_TO_COVERAGE',
+    'SAMPLE_COVERAGE',
+    'SCISSOR_TEST',
+    'STENCIL_TEST'
+  ];
+
+  for (var ii = 0; ii < validEnums.length; ++ii) {
+    var name = validEnums[ii];
+    gl.enable(gl[name]);
+    assertMsg(gl.getError() == gl.NO_ERROR,
+              "gl.enable must succeed when passed gl." + name );
+  }
+
+}
+
+debug("");
+successfullyParsed = true;
+
+</script>
+<script src="../resources/js-test-post.js"></script>
+
+<script>
+</script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/gl-enable-vertex-attrib.html
@@ -0,0 +1,60 @@
+<!--
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+-->
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>WebGL Enable Vertex Attrib Test</title>
+    <link rel="stylesheet" href="../resources/js-test-style.css"/>
+    <script src="../resources/js-test-pre.js"></script>
+    <script src="resources/webgl-test.js"> </script>
+</head>
+<body>
+<canvas id="example" width="50" height="50">
+</canvas>
+<div id="description"></div>
+<div id="console"></div>
+<script id="vshader" type="x-shader/x-vertex">
+    attribute vec4 vPosition;
+    void main()
+    {
+        gl_Position = vPosition;
+    }
+</script>
+
+<script id="fshader" type="x-shader/x-fragment">
+    void main()
+    {
+        gl_FragColor = vec4(1.0,0.0,0.0,1.0);
+    }
+</script>
+
+<script>
+gl = initWebGL("example", "vshader", "fshader", [ "vPosition"], [ 0, 0, 0, 1 ], 1);
+gl.viewport(0, 0, 50, 50);
+
+var vertexObject = gl.createBuffer();
+gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
+gl.bufferData(gl.ARRAY_BUFFER, new WebGLFloatArray([ 0,0.5,0, -0.5,-0.5,0, 0.5,-0.5,0 ]), gl.STATIC_DRAW);
+gl.enableVertexAttribArray(0);
+gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
+
+gl.enableVertexAttribArray(3);
+shouldBe("gl.getError()", "gl.NO_ERROR");
+
+gl.drawArrays(gl.TRIANGLES, 0, 3);
+shouldBe("gl.getError()", "gl.INVALID_OPERATION");
+
+successfullyParsed = true;
+</script>
+</body>
+<script src="../resources/js-test-post.js"></script>
+
+<script>
+</script>
+
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/gl-enum-tests.html
@@ -0,0 +1,77 @@
+<!--
+Copyright (c) 2009 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+ -->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+  "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>WebGL gl enums Conformance Tests</title>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/desktop-gl-constants.js" type="text/javascript"></script>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/webgl-test.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<canvas id="canvas" width="2" height="2"> </canvas>
+<script>
+description("This test ensures WebGL various functions fail when passed non OpenGL ES 2.0 enums.");
+
+debug("");
+debug("Canvas.getContext");
+
+var gl = create3DContext(document.getElementById("canvas"));
+if (!gl) {
+  testFailed("context does not exist");
+} else {
+  testPassed("context exists");
+
+  debug("");
+  debug("Checking gl enums.");
+
+  var tex = gl.createTexture();
+  var tests = [
+    "gl.bindTexture(desktopGL['TEXTURE_3D'], tex)",
+    "gl.blendEquation(desktopGL['MIN'])",
+    "gl.blendEquation(desktopGL['MAX'])",
+    "gl.blendEquationSeparate(desktopGL['MIN'], gl.FUNC_ADD)",
+    "gl.blendEquationSeparate(desktopGL['MAX'], gl.FUNC_ADD)",
+    "gl.blendEquationSeparate(gl.FUNC_ADD, desktopGL['MIN'])",
+    "gl.blendEquationSeparate(gl.FUNC_ADD, desktopGL['MAX'])",
+    "gl.bufferData(gl.ARRAY_BUFFER, 3, desktopGL['STATIC_READ'])",
+    "gl.disable(desktopGL['CLIP_PLANE0'])",
+    "gl.disable(desktopGL['POINT_SPRITE'])",
+    "gl.getBufferParameter(gl.ARRAY_BUFFER, desktopGL['PIXEL_PACK_BUFFER'])",
+    "gl.getTexParameter(gl.TEXTURE_2D, desktopGL['GENERATE_MIPMAP'])",
+    "gl.getTexParameter(gl.TEXTURE_2D, desktopGL['GENERATE_MIPMAP'])",
+    "gl.hint(desktopGL['PERSPECTIVE_CORRECTION_HINT'], gl.FASTEST)",
+    "gl.isEnabled(desktopGL['CLIP_PLANE0'])",
+    "gl.isEnabled(desktopGL['POINT_SPRITE'])",
+    "gl.pixelStorei(desktopGL['PACK_SWAP_BYTES'], 1)",
+    "gl.readPixels(0, 0, 1, 1, gl.ALPHA, gl.SHORT)",
+    "gl.texParameteri(desktopGL['TEXTURE_3D'], gl.TEXTURE_MAG_FILTER, gl.NEAREST)",
+    "gl.texParameteri(gl.TEXTURE_2D, desktopGL['GENERATE_MIPMAP'], 1)"
+   ];
+   for (var ii = 0; ii < tests.length; ++ii) {
+     eval(tests[ii]);
+     assertMsg(gl.getError() != gl.NO_ERROR,
+               tests[ii] + " should fail.");
+   }
+}
+
+debug("");
+successfullyParsed = true;
+
+</script>
+<script src="../resources/js-test-post.js"></script>
+
+<script>
+</script>
+
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/gl-get-calls.html
@@ -0,0 +1,138 @@
+<!--
+Copyright (C) 2009 Apple Computer, Inc.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>WebGL gl calls Conformance Tests</title>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/webgl-test.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<canvas id="canvas" width="2" height="2"> </canvas>
+
+<script>
+
+description("This test ensures basic functionality of the underlying graphics library");
+
+debug("");
+debug("Canvas.getContext");
+
+var context = create3DContext(document.getElementById("canvas"));
+if (!context)
+    testFailed("context does not exist");
+else {
+    testPassed("context exists");
+
+    debug("");
+    debug("Context contains getError");
+    if ("getError" in context)
+      testPassed("context contains getError");
+    else
+      testFailed("context does not contains getError");
+
+    debug("");
+    debug("Check default values");
+    shouldBe('context.getParameter(context.ACTIVE_TEXTURE)', 'context.TEXTURE0');
+    shouldBe('(context.getParameter(context.ALIASED_LINE_WIDTH_RANGE)[0] == 1) || (context.getParameter(context.ALIASED_LINE_WIDTH_RANGE)[1] == 1)', 'true');
+    shouldBe('(context.getParameter(context.ALIASED_POINT_SIZE_RANGE)[0] == 1) || (context.getParameter(context.ALIASED_POINT_SIZE_RANGE)[1] == 1)', 'true');
+    shouldBe('context.getParameter(context.ARRAY_BUFFER_BINDING)', 'null');
+    shouldBe('context.getParameter(context.BLEND)', 'false');
+    shouldBe('context.getParameter(context.BLEND_COLOR)', '[0, 0, 0, 0]');
+    shouldBe('context.getParameter(context.BLEND_DST_ALPHA)', '0');
+    shouldBe('context.getParameter(context.BLEND_DST_RGB)', '0');
+    shouldBe('context.getParameter(context.BLEND_EQUATION_ALPHA)', 'context.FUNC_ADD');
+    shouldBe('context.getParameter(context.BLEND_EQUATION_RGB)', 'context.FUNC_ADD');
+    shouldBe('context.getParameter(context.BLEND_SRC_ALPHA)', '1');
+    shouldBe('context.getParameter(context.BLEND_SRC_RGB)', '1');
+    shouldBe('context.getParameter(context.COLOR_CLEAR_VALUE)', '[0, 0, 0, 0]');
+    shouldBe('context.getParameter(context.COLOR_WRITEMASK)', '[1, 1, 1, 1]');
+    shouldBe('context.getParameter(context.CULL_FACE)', 'false');
+    shouldBe('context.getParameter(context.CULL_FACE_MODE)', 'context.BACK');
+    shouldBe('context.getParameter(context.CURRENT_PROGRAM)', 'null');
+    shouldBe('context.getParameter(context.DEPTH_FUNC)', 'context.LESS');
+    shouldBe('context.getParameter(context.DEPTH_RANGE)', '[0, 1]');
+    shouldBe('context.getParameter(context.DEPTH_TEST)', 'false');
+    shouldBe('context.getParameter(context.DEPTH_WRITEMASK)', 'true');
+    shouldBe('context.getParameter(context.DITHER)', 'true');
+    shouldBe('context.getParameter(context.ELEMENT_ARRAY_BUFFER_BINDING)', 'null');
+    shouldBe('context.getParameter(context.FRONT_FACE)', 'context.CCW');
+    shouldBe('context.getParameter(context.GENERATE_MIPMAP_HINT)', 'context.DONT_CARE');
+    shouldBe('context.getParameter(context.LINE_WIDTH)', '1');
+    shouldBe('context.getParameter(context.POLYGON_OFFSET_FACTOR)', '0');
+    shouldBe('context.getParameter(context.POLYGON_OFFSET_FILL)', 'false');
+    shouldBe('context.getParameter(context.POLYGON_OFFSET_UNITS)', '0');
+    shouldBe('context.getParameter(context.RENDERBUFFER_BINDING)', 'null');
+    shouldBe('context.getParameter(context.SAMPLE_COVERAGE_INVERT)', 'false');
+    shouldBe('context.getParameter(context.SAMPLE_COVERAGE_VALUE)', '1');
+    shouldBe('context.getParameter(context.SCISSOR_BOX)[0]', '0');
+    shouldBe('context.getParameter(context.SCISSOR_BOX)[1]', '0');
+    shouldBe('context.getParameter(context.SCISSOR_TEST)', 'false');
+    shouldBe('context.getParameter(context.STENCIL_BACK_FAIL)', 'context.KEEP');
+    shouldBe('context.getParameter(context.STENCIL_BACK_FUNC)', 'context.ALWAYS');
+    shouldBe('context.getParameter(context.STENCIL_BACK_PASS_DEPTH_FAIL)', 'context.KEEP');
+    shouldBe('context.getParameter(context.STENCIL_BACK_PASS_DEPTH_PASS)', 'context.KEEP');
+    shouldBe('context.getParameter(context.STENCIL_BACK_REF)', '0');
+    shouldBe('context.getParameter(context.STENCIL_BACK_VALUE_MASK)', '0xFFFFFFFF');
+    shouldBe('context.getParameter(context.STENCIL_BACK_WRITEMASK)', '0xFFFFFFFF');
+    shouldBe('context.getParameter(context.STENCIL_BITS)', '0');
+    shouldBe('context.getParameter(context.STENCIL_CLEAR_VALUE)', '0');
+    shouldBe('context.getParameter(context.STENCIL_FAIL)', 'context.KEEP');
+    shouldBe('context.getParameter(context.STENCIL_FUNC)', 'context.ALWAYS');
+    shouldBe('context.getParameter(context.STENCIL_PASS_DEPTH_FAIL)', 'context.KEEP');
+    shouldBe('context.getParameter(context.STENCIL_PASS_DEPTH_PASS)', 'context.KEEP');
+    shouldBe('context.getParameter(context.STENCIL_REF)', '0');
+    shouldBe('context.getParameter(context.STENCIL_TEST)', 'false');
+    shouldBe('context.getParameter(context.STENCIL_VALUE_MASK)', '0xFFFFFFFF');
+    shouldBe('context.getParameter(context.STENCIL_WRITEMASK)', '0xFFFFFFFF');
+    shouldBe('context.getParameter(context.TEXTURE_BINDING_2D)', 'null');
+    shouldBe('context.getParameter(context.TEXTURE_BINDING_CUBE_MAP)', 'null');
+    shouldBe('context.getParameter(context.VIEWPORT)', '[0, 0, 2, 2]');
+    shouldBeTrue('context.getParameter(context.MAX_FRAGMENT_UNIFORM_VECTORS) >= 16');
+    shouldBeTrue('context.getParameter(context.MAX_VERTEX_UNIFORM_VECTORS) >= 128');
+    shouldBeTrue('context.getParameter(context.MAX_VARYING_VECTORS) >= 8');
+    shouldBe('context.getParameter(context.NUM_COMPRESSED_TEXTURE_FORMATS)', '0');
+    shouldBe('context.getParameter(context.NUM_SHADER_BINARY_FORMATS)', '0');
+    shouldBe('context.getParameter(context.SHADER_COMPILER)', 'true');
+    shouldBe('context.getParameter(context.IMPLEMENTATION_COLOR_READ_FORMAT)', 'context.RGBA');
+    shouldBe('context.getParameter(context.IMPLEMENTATION_COLOR_READ_TYPE)', 'context.UNSIGNED_BYTE');
+    shouldBe('context.getParameter(context.COMPRESSED_TEXTURE_FORMATS)', '[]');
+    shouldBe('context.getParameter(context.SHADER_BINARY_FORMATS)', '[]');
+}
+
+debug("");
+successfullyParsed = true;
+
+</script>
+<script src="../resources/js-test-post.js"></script>
+
+<script>
+</script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/gl-getstring.html
@@ -0,0 +1,59 @@
+<!--
+Copyright (c) 2009 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+ -->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+  "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>WebGL gl.getString Conformance Tests</title>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/desktop-gl-constants.js" type="text/javascript"></script>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/webgl-test.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<canvas id="canvas" width="2" height="2"> </canvas>
+<script>
+description("This test checks getString returns strings in the correct format");
+
+debug("");
+debug("Canvas.getContext");
+
+var gl = create3DContext(document.getElementById("canvas"));
+if (!gl) {
+  testFailed("context does not exist");
+} else {
+  testPassed("context exists");
+
+  debug("");
+  checkPrefix("OpenGL ES 2.0", "VERSION");
+  checkPrefix("OpenGL ES GLSL ES 1.0", "SHADING_LANGUAGE_VERSION");
+  shouldBe("gl.getString(gl.EXTENSIONS)", "''");
+}
+
+function checkPrefix(expected, enum) {
+  var s = gl.getString(gl[enum]);
+  if (s.length >= expected.length &&
+      s.substring(0, expected.length) == expected) {
+    testPassed("getString(gl." + enum + ") correctly started with " + expected);
+  } else {
+    testFailed("getString(gl." + enum + ") did not start with " + expected);
+  }
+}
+
+debug("");
+successfullyParsed = true;
+
+</script>
+<script src="../resources/js-test-post.js"></script>
+
+<script>
+</script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/gl-object-get-calls.html
@@ -0,0 +1,40 @@
+<!--
+Copyright (C) 2009 Apple Computer, Inc.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+
+<html>
+<head>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/webgl-test.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+
+<script src="resources/gl-object-get-calls.js"></script>
+
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/gl-pixelstorei.html
@@ -0,0 +1,134 @@
+<!--
+Copyright (c) 2009 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+  "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+  <head>
+    <title>WebGL pixelStorei Test</title>
+    <link rel="stylesheet" href="../resources/js-test-style.css"/>
+    <script src="../resources/js-test-pre.js"></script>
+    <script src="resources/webgl-test.js"> </script>
+    <script src="../resources/desktop-gl-constants.js" type="text/javascript"></script>
+</head>
+<body>
+<canvas id="example" width="50" height="50"></canvas>
+<canvas id="2d00" width="50" height="50"></canvas>
+<canvas id="2d01" width="50" height="50"></canvas>
+<canvas id="2d02" width="50" height="50"></canvas>
+<canvas id="2d03" width="50" height="50"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+    <script id="vshader" type="x-shader/x-vertex">
+        attribute vec4 vPosition;
+        void main()
+        {
+            gl_Position = vPosition;
+        }
+    </script>
+
+    <script id="fshader" type="x-shader/x-fragment">
+        void main()
+        {
+            gl_FragColor = vec4(1.0,0.0,0.0,1.0);
+        }
+    </script>
+
+    <script>
+        function fail(x,y, name, buf, shouldBe)
+        {
+            var i = (y*50+x) * 4;
+            var reason = "pixel in "+name+" at ("+x+","+y+") is ("+buf[i]+","+buf[i+1]+","+buf[i+2]+","+buf[i+3]+"), should be "+shouldBe;
+            testFailed(reason);
+        }
+
+        function pass(name)
+        {
+            testPassed("drawing is correct in " + name);
+        }
+
+        function init()
+        {
+            if (window.layoutTestController) {
+                layoutTestController.overridePreference("WebKitWebGLEnabled", "1");
+                layoutTestController.dumpAsText();
+            }
+
+            debug("There should be 5 red triangles on 5 black squares above");
+            debug("");
+
+            debug("This test checks that drawImage and readPixels are not effected by gl.Pixelstorei(gl.PACK_ALIGNMENT) and visa versa");
+            debug("");
+
+            var canvas3d = document.getElementById("example");
+            gl = initWebGL("example", "vshader", "fshader", [ "vPosition"], [ 0, 0, 0, 1 ], 1);
+
+            var vertexObject = gl.createBuffer();
+            gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
+            gl.bufferData(gl.ARRAY_BUFFER, new WebGLFloatArray([ 0,0.5,0, -0.5,-0.5,0, 0.5,-0.5,0 ]), gl.STATIC_DRAW);
+            gl.enableVertexAttribArray(0);
+            gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
+
+            gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+            gl.drawArrays(gl.TRIANGLES, 0, 3);
+
+
+            function checkData(buf, name) {
+              // Test several locations
+              // First line should be all black
+              for (var i = 0; i < 50; ++i)
+                  if (buf[i*4] != 0 || buf[i*4+1] != 0 || buf[i*4+2] != 0 || buf[i*4+3] != 255) {
+                      fail(i, 0, name, buf, "(0,0,0,255)");
+                      return;
+                  }
+
+              // Line 15 should be red for at least 10 red pixels starting 20 pixels in
+              var offset = (15*50+20) * 4;
+              for (var i = 0; i < 10; ++i)
+                  if (buf[offset+i*4] != 255 || buf[offset+i*4+1] != 0 || buf[offset+i*4+2] != 0 || buf[offset+i*4+3] != 255) {
+                      fail(20 + i, 15, name, buf, "(255,0,0,255)");
+                      return;
+                  }
+              // Last line should be all black
+              offset = (49*50) * 4;
+              for (var i = 0; i < 50; ++i)
+                  if (buf[offset+i*4] != 0 || buf[offset+i*4+1] != 0 || buf[offset+i*4+2] != 0 || buf[offset+i*4+3] != 255) {
+                      fail(i, 49, name, buf, "(0,0,0,255)");
+                      return;
+                  }
+
+              pass(name);
+            }
+
+            function checkColors() {
+              var buf = gl.readPixels(0, 0, 50, 50, gl.RGBA, gl.UNSIGNED_BYTE);
+              checkData(buf, "3d context");
+              var imgData = ctx2d.getImageData(0, 0, 50, 50);
+              checkData(imgData.data, "2d context");
+            }
+
+            var table = [1, 2, 4, 8];
+            for (var ii = 0; ii < table.length; ++ii) {
+              gl.pixelStorei(gl.PACK_ALIGNMENT, table[ii]);
+              ctx2d = document.getElementById("2d0" + ii).getContext("2d");
+              ctx2d.globalCompositeOperation = 'copy';
+              ctx2d.drawImage(canvas3d, 0, 0);
+              checkColors();
+              assertMsg(gl.getParameter(gl.PACK_ALIGNMENT) == table[ii],
+                        "PACK_ALIGNMENT is " + table[ii]);
+            }
+       }
+
+       init();
+       successfullyParsed = true;
+    </script>
+</body>
+<script src="../resources/js-test-post.js"></script>
+
+<script>
+</script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/gl-scissor-test.html
@@ -0,0 +1,71 @@
+<!--
+Copyright (c) 2009 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+ -->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+  "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>WebGL Scissor Test</title>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/desktop-gl-constants.js" type="text/javascript"></script>
+<script src="../../debug/webgl-debug.js"></script>
+<script src="../resources/js-test-pre.js"></script>
+<script src="../fast/resources/webgl-test.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<canvas id="canvas" width="2" height="2" style="width: 40px; height: 40px;"> </canvas>
+<script>
+description("Check if glScissor setting works.");
+
+debug("");
+debug("Canvas.getContext");
+
+var gl = create3DContext(document.getElementById("canvas"));
+if (!gl) {
+  testFailed("context does not exist");
+} else {
+  testPassed("context exists");
+
+  debug("");
+
+  // clear a portion of our FBO
+  gl.enable(gl.SCISSOR_TEST);
+  gl.scissor(0, 0, 1, 1);
+  gl.clearColor(0,1,0,1);
+  gl.clear(gl.COLOR_BUFFER_BIT);
+
+  var b = gl.readPixels(0, 0, 2, 2, gl.RGBA, gl.UNSIGNED_BYTE);
+  checkPixel(b, 0, 0, [0, 1, 0, 1]);
+  checkPixel(b, 1, 0, [0, 0, 0, 0]);
+  checkPixel(b, 0, 1, [0, 0, 0, 0]);
+  checkPixel(b, 1, 1, [0, 0, 0, 0]);
+
+  function checkPixel(b, x, y, color) {
+    var offset = (y * 2 + x) * 4;
+    var match = true;
+    for (var c = 0; c < 4; ++c) {
+      if (b[offset + c] != color[c] * 255) {
+        match = false;
+        break;
+      }
+    }
+    assertMsg(match, "pixel at " + x + ", " + y + " is expected value");
+  }
+}
+
+debug("");
+successfullyParsed = true;
+
+</script>
+<script src="../resources/js-test-post.js"></script>
+
+<script>
+</script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/gl-shader-test.html
@@ -0,0 +1,52 @@
+<!--
+Copyright (c) 2009 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+  "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>WebGL ShaderL Conformance Tests</title>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/desktop-gl-constants.js" type="text/javascript"></script>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/webgl-test.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<canvas id="canvas" width="2" height="2"> </canvas>
+<script>
+description("This test checks a few things about WebGL Shaders.");
+
+debug("");
+debug("Canvas.getContext");
+
+var gl = create3DContext(document.getElementById("canvas"));
+if (!gl) {
+  testFailed("context does not exist");
+} else {
+  testPassed("context exists");
+
+  debug("");
+  debug("Checking shaders.");
+
+  // Create the shader object
+  var shader = gl.createShader(desktopGL['GEOMETRY_SHADER_ARB']);
+  assertMsg(shader == null,
+            "should not be able to create GEOMETRY shader");
+}
+
+debug("");
+successfullyParsed = true;
+
+</script>
+<script src="../resources/js-test-post.js"></script>
+
+<script>
+</script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/gl-uniform-arrays.html
@@ -0,0 +1,265 @@
+<!--
+Copyright (c) 2009 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+ -->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+  "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>WebGL uniform array Conformance Tests</title>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/desktop-gl-constants.js" type="text/javascript"></script>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/webgl-test.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<canvas id="example" width="2" height="2"> </canvas>
+<script id="vshader" type="x-shader/x-vertex">
+    attribute vec4 vPosition;
+    void main()
+    {
+        gl_Position = vPosition;
+    }
+</script>
+
+<script id="fshader" type="x-shader/x-fragment">
+    uniform $type color[3];
+    void main()
+    {
+        gl_FragColor = vec4(color[0]$elem, color[1]$elem, color[2]$elem, 1);
+    }
+</script>
+<script>
+function loadShader(ctx, shaderType, shaderSource) {
+  // Create the shader object
+  var shader = ctx.createShader(shaderType);
+  if (shader == null) {
+    debug("*** Error: unable to create shader '"+shader+"'");
+    return null;
+  }
+
+  // Load the shader source
+  ctx.shaderSource(shader, shaderSource);
+
+  // Compile the shader
+  ctx.compileShader(shader);
+
+  // Check the compile status
+  var compiled = ctx.getShaderParameter(shader, ctx.COMPILE_STATUS);
+  if (!compiled) {
+    // Something went wrong during compilation; get the error
+    var error = ctx.getShaderInfoLog(shader);
+    debug("*** Error compiling shader '"+shader+"':"+error);
+    ctx.deleteShader(shader);
+    return null;
+  }
+
+  return shader;
+}
+
+function loadProgram(ctx, vertexShaderSrc, fragmentShaderSrc) {
+  var program = ctx.createProgram();
+  var vShader = loadShader(ctx, ctx.VERTEX_SHADER, vertexShaderSrc)
+  var fShader = loadShader(ctx, ctx.FRAGMENT_SHADER, fragmentShaderSrc);
+  ctx.attachShader(program, vShader);
+  ctx.attachShader(program, fShader);
+  ctx.linkProgram(program);
+  var linked = ctx.getProgramParameter(program, ctx.LINK_STATUS);
+  if (!linked) {
+    // something went wrong with the link
+    var error = ctx.getProgramInfoLog (ctx.program);
+    debug("Error in program linking:" + error);
+    ctx.deleteProgram(ctx.program);
+    program = null;
+  }
+//  ctx.deleteShader(fShader);
+//  ctx.deleteShader(vShader);
+  return program;
+}
+
+description("This test ensures WebGL implementations handle uniform arrays correctly.");
+
+debug("");
+
+var gl = create3DContext(document.getElementById("example"));
+
+var vSrc = document.getElementById("vshader").text;
+var fTemplate = document.getElementById("fshader").text;
+
+var typeInfos = [
+  { type: 'float',
+    jsTypeOf: 'number',
+    setter: 'uniform1fv',
+    elem: '',
+    numSrcValues: 3,
+    badSet: function(loc) {
+      gl.uniform2fv(loc, [1, 2]);
+    },
+    srcValueAsString: function(index, srcValues) {
+      return srcValues[index].toString();
+    },
+    returnValueAsString: function(value) {
+      return value === null ? 'null' : value.toString();
+    },
+    checkType: function(value) {
+      return typeof values === 'number';
+    },
+    checkValue: function(typeInfo, index, value) {
+      return typeInfo.srcValues[index] == value;
+    },
+    srcValues: [16, 15, 14]
+  },
+  { type: 'vec2',
+    jsTypeOf: 'WebGLFloatArray',
+    setter: 'uniform2fv',
+    elem: '[1]',
+    numSrcValues: 3,
+    badSet: function(loc) {
+      gl.uniform1fv(loc, [2]);
+    },
+    srcValueAsString: function(index, srcValues) {
+      return "[" + srcValues[index * 2 + 0].toString() + ", " +
+                   srcValues[index * 2 + 1].toString() + "]";
+    },
+    returnValueAsString: function(value) {
+      return value === null ? 'null' : ("[" + value[0] + ", " + value[1] + "]");
+    },
+    checkType: function(value) {
+      return typeof values.length === 'number' &&
+             values.length == 2;
+    },
+    checkValue: function(typeInfo, index, value) {
+      return value !== null &&
+             typeInfo.srcValues[index * 2 + 0] == value[0] &&
+             typeInfo.srcValues[index * 2 + 1] == value[1];
+    },
+    srcValues: [16, 15, 14, 13, 12, 11],
+  },
+  { type: 'vec3',
+    jsTypeOf: 'WebGLFloatArray',
+    setter: 'uniform3fv',
+    elem: '[2]',
+    numSrcValues: 3,
+    badSet: function(loc) {
+      gl.uniform1fv(loc, [2]);
+    },
+    srcValueAsString: function(index, srcValues) {
+      return "[" + srcValues[index * 3 + 0].toString() + ", " +
+                   srcValues[index * 3 + 1].toString() + ", " +
+                   srcValues[index * 3 + 2].toString() + "]";
+    },
+    returnValueAsString: function(value) {
+      return value === null ? 'null' :
+          ("[" + value[0] + ", " + value[1] + ", " + value[2] + "]");
+    },
+    checkType: function(value) {
+      return typeof values.length === 'number' &&
+             values.length == 3;
+    },
+    checkValue: function(typeInfo, index, value) {
+      return value !== null &&
+             typeInfo.srcValues[index * 3 + 0] == value[0] &&
+             typeInfo.srcValues[index * 3 + 1] == value[1] &&
+             typeInfo.srcValues[index * 3 + 2] == value[2];
+    },
+    srcValues: [16, 15, 14, 13, 12, 11, 10, 11, 9],
+  },
+  { type: 'vec4',
+    jsTypeOf: 'WebGLFloatArray',
+    setter: 'uniform4fv',
+    elem: '[3]',
+    numSrcValues: 3,
+    badSet: function(loc) {
+      gl.uniform1fv(loc, [2]);
+    },
+    srcValueAsString: function(index, srcValues) {
+      return "[" + srcValues[index * 4 + 0].toString() + ", " +
+                   srcValues[index * 4 + 1].toString() + ", " +
+                   srcValues[index * 4 + 2].toString() + ", " +
+                   srcValues[index * 4 + 3].toString() + "]";
+    },
+    returnValueAsString: function(value) {
+      return value === null ? 'null' :
+          ("[" + value[0] + ", " + value[1] +
+           ", " + value[2] + ", " + value[3] + "]");
+    },
+    checkType: function(value) {
+      return typeof values.length === 'number' &&
+             values.length == 4;
+    },
+    checkValue: function(typeInfo, index, value) {
+      return value !== null &&
+             typeInfo.srcValues[index * 4 + 0] == value[0] &&
+             typeInfo.srcValues[index * 4 + 1] == value[1] &&
+             typeInfo.srcValues[index * 4 + 2] == value[2] &&
+             typeInfo.srcValues[index * 4 + 3] == value[3];
+    },
+    srcValues: [16, 15, 14, 13, 12, 11, 10, 11, 9, 8, 7, 6, 5],
+  }
+];
+
+for (var tt = 0; tt < typeInfos.length; ++tt) {
+  var typeInfo = typeInfos[tt];
+  debug("");
+  debug("check " + typeInfo.type);
+  var fSrc = fTemplate.replace(/\$type/g, typeInfo.type).
+                       replace(/\$elem/g, typeInfo.elem);
+  //debug("fSrc: " + fSrc);
+  var program = loadProgram(gl, vSrc, fSrc);
+
+  var numUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
+  assertMsg(numUniforms == 1, "1 uniform found");
+  var info = gl.getActiveUniform(program, 0);
+  assertMsg(info.name == "color[0]",
+            "uniform name is 'color[0]' not 'color' as per OpenGL ES 2.0.24 section 2.10");
+  var loc = gl.getUniformLocation(program, "color");
+  var srcValues = typeInfo.srcValues;
+
+  // Try setting the value before using the program
+  gl[typeInfo.setter](loc, srcValues);
+  assertMsg(gl.getError() == gl.INVALID_OPERATION,
+            "should fail if there is no current program");
+
+  gl.useProgram(program);
+  gl[typeInfo.setter](loc, srcValues);
+  assertMsg(gl.getError() == gl.NO_ERROR,
+            "can set an array of uniforms with gl." + typeInfo.setter);
+  var values = gl.getUniform(program, loc);
+  assertMsg(gl.getError() == gl.NO_ERROR,
+            "can call gl.getUniform");
+  assertMsg(typeInfo.checkType(values),
+            "gl.getUniform returns the correct type.");
+  for (var ii = 0; ii < typeInfo.numSrcValues; ++ii) {
+    var elemLoc = gl.getUniformLocation(program, "color[" + ii + "]");
+    assertMsg(gl.getError() == gl.NO_ERROR,
+              "can get location of element " + ii +
+              " of array from gl.getUniformLocation");
+    var value = gl.getUniform(program, elemLoc);
+    assertMsg(gl.getError() == gl.NO_ERROR,
+              "can get value of element " + ii + " of array from gl.getUniform");
+    assertMsg(typeInfo.checkValue(typeInfo, ii, value),
+              "value put in (" + typeInfo.srcValueAsString(ii, srcValues) +
+              ") matches value pulled out (" +
+              typeInfo.returnValueAsString(value) + ")");
+  }
+  typeInfo.badSet(loc);
+  assertMsg(gl.getError() == gl.INVALID_OPERATION,
+            "using the wrong size of gl.Uniform fails");
+
+  gl.useProgram(null);
+}
+debug("");
+successfullyParsed = true;
+
+</script>
+<script src="../resources/js-test-post.js"></script>
+
+<script>
+</script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/gl-uniform-bool.html
@@ -0,0 +1,60 @@
+<!--
+Copyright (c) 2009 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+ -->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+  "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>WebGL uniformMatrix Conformance Tests</title>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/desktop-gl-constants.js" type="text/javascript"></script>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/webgl-test.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<canvas id="example" width="2" height="2"> </canvas>
+    <script id="vshader" type="x-shader/x-vertex">
+        attribute vec4 vPosition;
+        void main()
+        {
+            gl_Position = vPosition;
+        }
+    </script>
+
+    <script id="fshader" type="x-shader/x-fragment">
+        uniform bool color;
+        void main()
+        {
+            gl_FragColor = vec4(float(color),0.0,0.0,1.0);
+        }
+    </script>
+<script>
+description("This test ensures WebGL implementations handle bool uniforms in a OpenGL ES 2.0 spec compliant way");
+
+debug("");
+debug("NOTE: Some OpenGL drivers do not handle this correctly");
+debug("");
+debug("Checking gl.uniform1f with bool.");
+
+gl = initWebGL("example", "vshader", "fshader", [ "vPosition"], [ 0, 0, 0, 1 ], 1);
+var loc = gl.getUniformLocation(gl.program, "color");
+gl.uniform1f(loc, 1);
+assertMsg(gl.getError() == gl.NO_ERROR,
+          "should be able to set bool with gl.uniform1f");
+
+debug("");
+successfullyParsed = true;
+
+</script>
+<script src="../resources/js-test-post.js"></script>
+
+<script>
+</script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/gl-uniformmatrix4fv.html
@@ -0,0 +1,70 @@
+<!--
+Copyright (c) 2009 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+ -->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+  "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>WebGL uniformMatrix Conformance Tests</title>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/desktop-gl-constants.js" type="text/javascript"></script>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/webgl-test.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<canvas id="example" width="2" height="2"> </canvas>
+    <script id="vshader" type="x-shader/x-vertex">
+        attribute vec4 vPosition;
+        uniform mat4 world4;
+        uniform mat3 world3;
+        uniform mat2 world2;
+        void main()
+        {
+            gl_Position = vec4(vPosition.xyz, world3[0].x + world2[0].x) * world4;
+        }
+    </script>
+
+    <script id="fshader" type="x-shader/x-fragment">
+        void main()
+        {
+            gl_FragColor = vec4(1.0,0.0,0.0,1.0);
+        }
+    </script>
+<script>
+description("This test ensures WebGL implementations handle uniformMatrix in a OpenGL ES 2.0 spec compliant way");
+
+debug("");
+debug("Checking gl.uniformMatrix.");
+
+gl = initWebGL("example", "vshader", "fshader", [ "vPosition"], [ 0, 0, 0, 1 ], 1);
+for (var ii = 2; ii <= 4; ++ii) {
+  var loc = gl.getUniformLocation(gl.program, "world" + ii);
+  var mat = [];
+  for (var jj = 0; jj < ii; ++jj) {
+    for (var ll = 0; ll < ii; ++ll) {
+      mat[jj * ii + ll] = (jj == ll) ? 1 : 0;
+    }
+  }
+  name = "uniformMatrix" + ii + "fv";
+  gl[name](loc, false, mat);
+  assertMsg(gl.getError() == gl.NO_ERROR, "can call " + name + "with transpose = false");
+  gl[name](loc, true, mat);
+  assertMsg(gl.getError() == gl.INVALID_VALUE, name + " should return INVALID_VALUE with transpose = true");
+}
+
+debug("");
+successfullyParsed = true;
+
+</script>
+<script src="../resources/js-test-post.js"></script>
+
+<script>
+</script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/gl-unknown-uniform.html
@@ -0,0 +1,70 @@
+<!--
+Copyright (c) 2009 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+  "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>WebGL Unknown Uniform Conformance Test</title>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/desktop-gl-constants.js" type="text/javascript"></script>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/webgl-test.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<canvas id="canvas" width="2" height="2"> </canvas>
+<script id="vshader" type="x-shader/x-vertex">
+    attribute vec4 vPosition;
+    void main()
+    {
+        gl_Position = vPosition;
+    }
+</script>
+
+<script id="fshader" type="x-shader/x-fragment">
+    void main()
+    {
+        gl_FragColor = vec4(1.0,0.0,0.0,1.0);
+    }
+</script>
+<script>
+description("Tests that unknown uniforms don't cause errors.");
+
+debug("");
+debug("Canvas.getContext");
+
+gl = initWebGL("example", "vshader", "fshader", [ "vPosition"], [ 0, 0, 0, 1 ], 1);
+var gl = create3DContext(document.getElementById("canvas"));
+if (!gl) {
+  testFailed("context does not exist");
+} else {
+  testPassed("context exists");
+
+  debug("");
+
+  // Get the location of an unknown uniform.
+  var loc = gl.getUniformLocation(gl.program, "someUnknownUniform");
+  assertMsg(loc === null, "location of unknown uniform should be null");
+  assertMsg(gl.getError() == gl.NO_ERROR,
+            "there should be no error from getting an unknown uniform");
+  gl.uniform1f(loc, 1);
+  assertMsg(gl.getError() == gl.NO_ERROR,
+            "there should be no error from trying to set an unknown uniform");
+}
+
+debug("");
+successfullyParsed = true;
+
+</script>
+<script src="../resources/js-test-post.js"></script>
+
+<script>
+</script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/gl-vertexattrib.html
@@ -0,0 +1,53 @@
+<!--
+Copyright (c) 2009 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+ -->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+  "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>WebGL vertexAttrib Conformance Tests</title>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/desktop-gl-constants.js" type="text/javascript"></script>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/webgl-test.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<canvas id="canvas" width="2" height="2"> </canvas>
+<script>
+description("This test ensures WebGL implementations vertexAttrib can be set and read.");
+
+debug("");
+debug("Canvas.getContext");
+
+var gl = create3DContext(document.getElementById("canvas"));
+if (!gl) {
+  testFailed("context does not exist");
+} else {
+  testPassed("context exists");
+
+  debug("");
+  debug("Checking gl.vertexAttrib.");
+
+  gl.vertexAttrib4fv(0, [1, 2, 3, 4]);
+  shouldBe('gl.getVertexAttrib(0, gl.CURRENT_VERTEX_ATTRIB)[0]', '1');
+  shouldBe('gl.getVertexAttrib(0, gl.CURRENT_VERTEX_ATTRIB)[1]', '2');
+  shouldBe('gl.getVertexAttrib(0, gl.CURRENT_VERTEX_ATTRIB)[2]', '3');
+  shouldBe('gl.getVertexAttrib(0, gl.CURRENT_VERTEX_ATTRIB)[3]', '4');
+}
+
+debug("");
+successfullyParsed = true;
+
+</script>
+<script src="../resources/js-test-post.js"></script>
+
+<script>
+</script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/gl-vertexattribpointer.html
@@ -0,0 +1,51 @@
+<!--
+Copyright (c) 2009 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+ -->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+  "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>WebGL vertexAttribPointer Conformance Tests</title>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/desktop-gl-constants.js" type="text/javascript"></script>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/webgl-test.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<canvas id="canvas" width="2" height="2"> </canvas>
+<script>
+description("This test ensures WebGL implementations vertexAttribPointer can not be set if no buffer is bound.");
+
+debug("");
+debug("Canvas.getContext");
+
+var gl = create3DContext(document.getElementById("canvas"));
+if (!gl) {
+  testFailed("context does not exist");
+} else {
+  testPassed("context exists");
+
+  debug("");
+  debug("Checking gl.vertexAttribPointer.");
+
+  gl.vertexAttribPointer(0, 3, gl.FLOAT, 0, 0, 12);
+  assertMsg(gl.getError() != gl.NO_ERROR,
+            "vertexAttribPointer should fail if no buffer is bound");
+}
+
+debug("");
+successfullyParsed = true;
+
+</script>
+<script src="../resources/js-test-post.js"></script>
+
+<script>
+</script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/glsl-2types-of-textures-on-same-unit.html
@@ -0,0 +1,143 @@
+<!--
+Copyright (c) 2009 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+ -->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+  "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+  <head>
+    <title>WebGL GLSL 2 types of textures on same unit conformance test.</title>
+    <link rel="stylesheet" href="../resources/js-test-style.css"/>
+    <script src="../resources/js-test-pre.js"></script>
+    <script src="resources/webgl-test.js"> </script>
+    <script src="../../debug/webgl-debug.js"> </script>
+</head>
+<body>
+<canvas id="example" width="2" height="2" style="width: 40px; height: 40px;"></canvas>
+<canvas id="canvas2d" width="1" height="1" style="width: 40px; height: 40px;"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+<script id="vshader" type="x-shader/x-vertex">
+attribute vec4 vPosition;
+attribute vec2 texCoord0;
+varying vec2 texCoord;
+void main()
+{
+  gl_Position = vPosition;
+  texCoord = texCoord0;
+}
+</script>
+
+<script id="fshader" type="x-shader/x-fragment">
+uniform sampler2D tex2d;
+uniform samplerCube texCube;
+varying vec2 texCoord;
+void main()
+{
+  gl_FragColor =  texture2D(tex2d, texCoord) +
+                  textureCube(texCube, vec3(0,1,0));
+}
+</script>
+
+  <script>
+function init()
+{
+  if (window.layoutTestController) {
+    layoutTestController.overridePreference("WebKitWebGLEnabled", "1");
+    layoutTestController.dumpAsText();
+  }
+
+  debug("Tests that using 2 types of textures on the same texture unit");
+  debug("and referencing them both in the same program fails as per");
+  debug("OpenGL ES 2.0.24 spec section 2.10.4, Samplers subsection.");
+  debug("");
+
+  var canvas2d = document.getElementById("canvas2d");
+  var ctx2d = canvas2d.getContext("2d");
+
+  gl = initWebGL("example", "vshader", "fshader", [ "vPosition", "texCoord0"],
+                 [ 0, 0, 0, 1 ], 1);
+  gl = WebGLDebugUtils.makeDebugContext(gl);
+
+  gl.disable(gl.DEPTH_TEST);
+  gl.disable(gl.BLEND);
+
+  var vertexObject = gl.createBuffer();
+  gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
+  gl.bufferData(
+      gl.ARRAY_BUFFER,
+      new WebGLFloatArray([-1, 1,0, 1,1,0, -1,-1,0,
+                           -1,-1,0, 1,1,0,  1,-1,0]),
+      gl.STATIC_DRAW);
+  gl.enableVertexAttribArray(0);
+  gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
+
+  var vertexObject = gl.createBuffer();
+  gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
+  gl.bufferData(
+      gl.ARRAY_BUFFER,
+      new WebGLFloatArray([ 0,0, 1,0, 0,1,
+                            0,1, 1,0, 1,1]),
+      gl.STATIC_DRAW);
+  gl.enableVertexAttribArray(1);
+  gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 0, 0);
+
+  // Make texture unit 1 active.
+  gl.activeTexture(gl.TEXTURE1);
+
+  // Make a 2d texture
+  var tex2d = gl.createTexture();
+  gl.bindTexture(gl.TEXTURE_2D, tex2d);
+  ctx2d.fillStyle = "rgba(0, 0, 255, 255)";
+  ctx2d.fillRect(0, 0, 1, 1);
+  gl.texImage2D(gl.TEXTURE_2D,
+                0,             // level
+                canvas2d);     // internalFormat
+
+  // make a cube texture
+  var texCube = gl.createTexture();
+  ctx2d.fillStyle = "rgba(0, 255, 0, 64)";
+  ctx2d.fillRect(0, 0, 1, 1);
+  var targets = [
+    gl.TEXTURE_CUBE_MAP_POSITIVE_X,
+    gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
+    gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
+    gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
+    gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
+    gl.TEXTURE_CUBE_MAP_NEGATIVE_Z];
+  for (var ii = 0; ii < targets.length; ++ii) {
+    gl.texImage2D(targets[ii],
+                  0,             // level
+                  canvas2d);     // internalFormat
+  }
+
+  var tex2dLoc = gl.getUniformLocation(gl.program, "tex2d");
+  var texCubeLoc = gl.getUniformLocation(gl.program, "texCube");
+  gl.uniform1i(tex2dLoc, 1);
+  gl.uniform1i(texCubeLoc, 1);
+
+  gl.clearColor(1,0,0,1);
+  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+  for (var ii = 0; ii < 4; ++ii) {
+    var x = ii % 2;
+    var y = Math.floor(ii / 2);
+    gl.drawArrays(gl.TRIANGLES, 0, 6);
+    assertMsg(gl.getError() == gl.INVALID_OPERATION,
+              "drawing with 2 different targets on the same texture unit should generate INVALID_VALUE");
+  }
+}
+
+init();
+successfullyParsed = true;
+</script>
+</body>
+<script src="../resources/js-test-post.js"></script>
+
+<script>
+</script>
+
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/glsl-conformance.html
@@ -0,0 +1,376 @@
+<!--
+Copyright (c) 2009 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+  "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>WebGL GLSL Conformance Tests</title>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/desktop-gl-constants.js" type="text/javascript"></script>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/webgl-test.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<script id="vshader" type="text/something-not-javascript">
+attribute vec4 vPosition;
+void main()
+{
+    gl_Position = vPosition;
+}
+</script>
+<script id="fshader" type="text/something-not-javascript">
+precision mediump float;
+void main()
+{
+    gl_FragColor = vec4(1.0,0.0,0.0,1.0);
+}
+</script>
+<script id="fshaderWithPrecision" type="text/something-not-javascript">
+void main()
+{
+    gl_FragColor = mediump vec4(1.0,0.0,0.0,1.0);
+}
+</script>
+<script id="fshaderWithDefaultPrecision" type="text/something-not-javascript">
+precision mediump float;
+void main()
+{
+    gl_FragColor = vec4(1.0,0.0,0.0,1.0);
+}
+</script>
+<script id="fshaderWithOutPrecision" type="text/something-not-javascript">
+uniform vec4 color;
+void main()
+{
+    gl_FragColor = color;
+}
+</script>
+<script id="fshaderWithInvalidIdentifier" type="text/something-not-javascript">
+precision mediump float;
+uniform float gl_foo;
+void main()
+{
+    gl_FragColor = vec4(gl_foo,0.0,0.0,1.0);
+}
+</script>
+<script id="fshaderWithGLSLPreprocessorSymbol" type="text/something-not-javascript">
+#if defined(GL_ES)
+  precision mediump float;
+  void main()
+  {
+      gl_FragColor = vec4(0.0,0.0,1.0);
+  }
+#else
+  foo
+#endif
+</script>
+<script id="fshaderWithVERSION100PreprocessorSymbol" type="text/something-not-javascript">
+#if __VERSION__ == 100
+  precision mediump float;
+  void main()
+  {
+      gl_FragColor = vec4(0.0,0.0,0.0,1.0);
+  }
+#else
+  foo
+#endif
+</script>
+<script id="fshaderWithFragDepth" type="text/something-not-javascript">
+precision mediump float;
+void main()
+{
+    gl_FragColor = vec4(0.0,0.0,0.0,1.0);
+    gl_FragDepth = 1.0;
+}
+</script>
+<script id="vshaderWithClipVertex" type="text/something-not-javascript">
+attribute vec4 vPosition;
+void main()
+{
+    gl_Position = vPosition;
+    gl_ClipVertex = vPosition;
+}
+</script>
+<script id="fshaderWith__Define" type="text/something-not-javascript">
+#define __foo 1
+precision mediump float;
+void main()
+{
+    gl_FragColor = vec4(0.0,0.0,0.0,1.0);
+}
+</script>
+<script id="fshaderWithGL_Define" type="text/something-not-javascript">
+#define GL_FOO 1
+precision mediump float;
+void main()
+{
+    gl_FragColor = vec4(0.0,0.0,0.0,1.0);
+}
+</script>
+<script id="fshaderWithDefineLineContinuation" type="text/something-not-javascript">
+#define foo this \
+  is a test
+precision mediump float;
+void main()
+{
+    gl_FragColor = vec4(0.0,0.0,0.0,1.0);
+}
+</script>
+<script id="vshaderWithgl_Color" type="text/something-not-javascript">
+attribute vec4 vPosition;
+void main()
+{
+    gl_Position = gl_Color;
+}
+</script>
+<script id="vshaderWithgl_ProjectionMatrix" type="text/something-not-javascript">
+attribute vec4 vPosition;
+void main()
+{
+    gl_Position = vPosition * gl_ProjectionMatrix;
+}
+</script>
+<script id="vshaderWithAttributeArray" type="text/something-not-javascript">
+attribute vec4 vPosition[2];
+void main()
+{
+    gl_Position = vPosition[0] + vPosition[1];
+}
+</script>
+<script id="vshaderWithwebgl_" type="text/something-not-javascript">
+attribute vec4 webgl_vPosition;
+void main()
+{
+    gl_Position = webgl_vPosition;
+}
+</script>
+<script id="vshaderWith_webgl_" type="text/something-not-javascript">
+attribute vec4 _webgl_vPosition;
+void main()
+{
+    gl_Position = _webgl_vPosition;
+}
+</script>
+<canvas id="canvas" width="2" height="2"> </canvas>
+<script>
+description("This test ensures WebGL implementations allow proper GLES2 shaders compile and improper ones fail.");
+
+debug("");
+debug("Canvas.getContext");
+
+var gl = create3DContext(document.getElementById("canvas"));
+if (!gl) {
+  testFailed("context does not exist");
+} else {
+  testPassed("context exists");
+
+  debug("");
+  debug("Checking various GLSL programs.");
+
+  function log(msg) {
+    if (window.console && window.console.log) {
+      window.console.log(msg);
+    }
+  }
+
+  function loadShader(shaderType, shaderId) {
+    // Get the shader source.
+    var shaderSource = document.getElementById(shaderId).text;
+
+    // Create the shader object
+    var shader = gl.createShader(shaderType);
+    if (shader == null) {
+        debug("*** Error: unable to create shader '"+shaderId+"'");
+        return null;
+    }
+
+    // Load the shader source
+    gl.shaderSource(shader, shaderSource);
+
+    // Compile the shader
+    gl.compileShader(shader);
+
+    // Check the compile status
+    var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
+    if (!compiled) {
+        // Something went wrong during compilation; get the error
+        var error = gl.getShaderInfoLog(shader);
+        log("*** Error compiling shader '"+shader+"':"+error);
+        gl.deleteShader(shader);
+        return null;
+    }
+    return shader;
+  }
+
+  var shaderInfo = [
+    { vShaderId: 'vshader',
+      vShaderSuccess: true,
+      fShaderId: 'fshaderWithPrecision',
+      fShaderSuccess: true,
+      linkSuccess: true,
+      passMsg: 'frament shader with precision compiled and linked'
+    },
+    { vShaderId: 'vshader',
+      vShaderSuccess: true,
+      fShaderId: 'fshaderWithDefaultPrecision',
+      fShaderSuccess: true,
+      linkSuccess: true,
+      passMsg: 'fragment shader with default precision compiled and linked'
+    },
+    { vShaderId: 'vshader',
+      vShaderSuccess: true,
+      fShaderId: 'fshaderWithOutPrecision',
+      fShaderSuccess: false,
+      linkSuccess: false,
+      passMsg: 'fragment shader without precision should fail',
+    },
+    { vShaderId: 'vshader',
+      vShaderSuccess: true,
+      fShaderId: 'fshaderWithInvalidIdentifier',
+      fShaderSuccess: false,
+      linkSuccess: false,
+      passMsg: 'fragment shader with gl_ identifier should fail',
+    },
+    { vShaderId: 'vshader',
+      vShaderSuccess: true,
+      fShaderId: 'fshaderWithGLSLPreprocessorSymbol',
+      fShaderSuccess: true,
+      linkSuccess: true,
+      passMsg: 'fragment shader that uses GL_ES preprocessor symbol should succeed',
+    },
+    { vShaderId: 'vshader',
+      vShaderSuccess: true,
+      fShaderId: 'fshaderWithVERSION100PreprocessorSymbol',
+      fShaderSuccess: true,
+      linkSuccess: true,
+      passMsg: 'fragment shader that uses __VERSION__==100 should succeed',
+    },
+    { vShaderId: 'vshader',
+      vShaderSuccess: true,
+      fShaderId: 'fshaderWithFragDepth',
+      fShaderSuccess: false,
+      linkSuccess: true,
+      passMsg: 'fragment shader that uses gl_FragDepth should fail',
+    },
+    { vShaderId: 'vshaderWithClipVertex',
+      vShaderSuccess: false,
+      fShaderId: 'fshader',
+      fShaderSuccess: true,
+      linkSuccess: false,
+      passMsg: 'vertex shader that uses gl_ClipVertex should fail',
+    },
+    //{ vShaderId: 'vshader',
+    //  vShaderSuccess: true,
+    //  fShaderId: 'fshaderWith__Define',
+    //  fShaderSuccess: false,
+    //  linkSuccess: false,
+    //  passMsg: 'fragment shader that uses __ define should fail',
+    //},
+    //{ vShaderId: 'vshader',
+    //  vShaderSuccess: true,
+    //  fShaderId: 'fshaderWithGL_Define',
+    //  fShaderSuccess: false,
+    //  linkSuccess: false,
+    //  passMsg: 'fragment shader that uses GL_ define should fail',
+    //},
+    { vShaderId: 'vshader',
+      vShaderSuccess: true,
+      fShaderId: 'fshaderWithDefineLineContinuation',
+      fShaderSuccess: false,
+      linkSuccess: false,
+      passMsg: 'fragment shader that uses has line continuation macro should fail',
+    },
+    { vShaderId: 'vshaderWithgl_Color',
+      vShaderSuccess: false,
+      fShaderId: 'fshader',
+      fShaderSuccess: true,
+      linkSuccess: false,
+      passMsg: 'vertex shader that uses gl_Color should fail',
+    },
+    { vShaderId: 'vshaderWithgl_ProjectionMatrix',
+      vShaderSuccess: false,
+      fShaderId: 'fshader',
+      fShaderSuccess: true,
+      linkSuccess: false,
+      passMsg: 'vertex shader that uses gl_ProjectionMatrix should fail',
+    },
+    { vShaderId: 'vshaderWithAttributeArray',
+      vShaderSuccess: false,
+      fShaderId: 'fshader',
+      fShaderSuccess: true,
+      linkSuccess: false,
+      passMsg: 'vertex shader that uses attribute array should fail as per GLSL page 110, appendix A, section 5',
+    },
+    { vShaderId: 'vshaderWithwebgl_',
+      vShaderSuccess: false,
+      fShaderId: 'fshader',
+      fShaderSuccess: true,
+      linkSuccess: false,
+      passMsg: 'vertex shader that uses _webgl identifier should fail',
+    },
+    { vShaderId: 'vshaderWith_webgl_',
+      vShaderSuccess: false,
+      fShaderId: 'fshader',
+      fShaderSuccess: true,
+      linkSuccess: false,
+      passMsg: 'vertex shader that uses _webgl_ identifier should fail',
+    }
+  ];
+
+  for (var ii = 0; ii < shaderInfo.length; ++ii) {
+    var info = shaderInfo[ii];
+    log("vs = " + info.vShaderId + ", fs = " + info.fShaderId);
+    //debug(info.fShaderId);
+    var vShader = loadShader(gl.VERTEX_SHADER, info.vShaderId);
+    if ((vShader != null) != info.vShaderSuccess) {
+      testFailed(info.passMsg);
+      continue;
+    }
+    var fShader = loadShader(gl.FRAGMENT_SHADER, info.fShaderId);
+    //debug(fShader == null ? "fail" : "succeed");
+    if ((fShader != null) != info.fShaderSuccess) {
+      testFailed(info.passMsg);
+      continue;
+    }
+
+    if (vShader && fShader) {
+      var program = gl.createProgram();
+      gl.attachShader(program, vShader);
+      gl.attachShader(program, fShader);
+      gl.linkProgram(program);
+      var linked = (gl.getProgramParameter(program, gl.LINK_STATUS) != 0);
+      if (!linked) {
+        var error = gl.getProgramInfoLog(shader);
+        log("*** Error linking program '"+program+"':"+error);
+      }
+      if (linked != info.linkSuccess) {
+        testFailed(info.passMsg);
+        continue;
+      }
+    } else {
+      if (info.linkSuccess) {
+        testFailed(info.passMsg);
+        continue;
+      }
+    }
+    testPassed(info.passMsg);
+  }
+}
+
+debug("");
+successfullyParsed = true;
+
+</script>
+<script src="../resources/js-test-post.js"></script>
+
+<script>
+</script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/incorrect-context-object-behaviour.html
@@ -0,0 +1,39 @@
+<!--
+Copyright (C) 2009 Apple Computer, Inc.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<html>
+<head>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/webgl-test.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+
+<script src="resources/incorrect-context-object-behaviour.js"></script>
+
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/index-validation-copies-indices.html
@@ -0,0 +1,76 @@
+<!--
+Copyright (c) 2009 The Chromium Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<html>
+<head>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/webgl-test.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+
+<script>
+description('Test that client data is always copied during bufferData and bufferSubData calls, because otherwise the data the GL uses to draw may differ from that checked by the index validation code.')
+
+debug('Regression test for <a href="https://bugs.webkit.org/show_bug.cgi?id=32748">https://bugs.webkit.org/show_bug.cgi?id=32748</a> : <code>Index validation code must always copy client data</code>');
+
+var context = create3DContext();
+var program = loadStandardProgram(context);
+
+context.useProgram(program);
+var vertexObject = context.createBuffer();
+context.enableVertexAttribArray(0);
+context.bindBuffer(context.ARRAY_BUFFER, vertexObject);
+// 4 vertices -> 2 triangles
+context.bufferData(context.ARRAY_BUFFER, new WebGLFloatArray([ 0,0,0, 0,1,0, 1,0,0, 1,1,0 ]), context.STATIC_DRAW);
+context.vertexAttribPointer(0, 3, context.FLOAT, false, 0, 0);
+
+var indexObject = context.createBuffer();
+
+context.bindBuffer(context.ELEMENT_ARRAY_BUFFER, indexObject);
+var indices = new WebGLUnsignedShortArray([ 10000, 0, 1, 2, 3, 10000 ]);
+context.bufferData(context.ELEMENT_ARRAY_BUFFER, indices, context.STATIC_DRAW);
+shouldGenerateGLError(context, context.NO_ERROR, "context.drawElements(context.TRIANGLE_STRIP, 4, context.UNSIGNED_SHORT, 2)");
+shouldGenerateGLError(context, context.INVALID_OPERATION, "context.drawElements(context.TRIANGLE_STRIP, 4, context.UNSIGNED_SHORT, 0)");
+shouldGenerateGLError(context, context.INVALID_OPERATION, "context.drawElements(context.TRIANGLE_STRIP, 4, context.UNSIGNED_SHORT, 4)");
+indices[0] = 2;
+indices[5] = 1;
+shouldGenerateGLError(context, context.NO_ERROR, "context.drawElements(context.TRIANGLE_STRIP, 4, context.UNSIGNED_SHORT, 2)");
+shouldGenerateGLError(context, context.INVALID_OPERATION, "context.drawElements(context.TRIANGLE_STRIP, 4, context.UNSIGNED_SHORT, 0)");
+shouldGenerateGLError(context, context.INVALID_OPERATION, "context.drawElements(context.TRIANGLE_STRIP, 4, context.UNSIGNED_SHORT, 4)");
+
+debug("")
+successfullyParsed = true;
+</script>
+
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/index-validation.html
@@ -0,0 +1,44 @@
+<!--
+Copyright (c) 2009 The Chromium Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<html>
+<head>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/webgl-test.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+
+<script src="resources/index-validation.js"></script>
+
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/methods.html
@@ -0,0 +1,202 @@
+<html>
+<head>
+<!--
+Copyright (c) 2009 Ilmari Heikkinen. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>WebGL Methods Test</title>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/desktop-gl-constants.js" type="text/javascript"></script>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/webgl-test.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<canvas id="canvas" style="width: 50px; height: 50px;"> </canvas>
+<script>
+description("This test ensures that the WebGL context has all the methods in the specification.");
+
+var methods = [
+"canvas",
+"getContextAttributes",
+"activeTexture",
+"attachShader",
+"bindAttribLocation",
+"bindBuffer",
+"bindFramebuffer",
+"bindRenderbuffer",
+"bindTexture",
+"blendColor",
+"blendEquation",
+"blendEquationSeparate",
+"blendFunc",
+"blendFuncSeparate",
+"bufferData",
+"bufferSubData",
+"checkFramebufferStatus",
+"clear",
+"clearColor",
+"clearDepth",
+"clearStencil",
+"colorMask",
+"compileShader",
+"copyTexImage2D",
+"copyTexSubImage2D",
+"createBuffer",
+"createFramebuffer",
+"createProgram",
+"createRenderbuffer",
+"createShader",
+"createTexture",
+"cullFace",
+"deleteBuffer",
+"deleteFramebuffer",
+"deleteProgram",
+"deleteRenderbuffer",
+"deleteShader",
+"deleteTexture",
+"depthFunc",
+"depthMask",
+"depthRange",
+"detachShader",
+"disable",
+"disableVertexAttribArray",
+"drawArrays",
+"drawElements",
+"enable",
+"enableVertexAttribArray",
+"finish",
+"flush",
+"framebufferRenderbuffer",
+"framebufferTexture2D",
+"frontFace",
+"generateMipmap",
+"getActiveAttrib",
+"getActiveUniform",
+"getAttachedShaders",
+"getAttribLocation",
+"getParameter",
+"getBufferParameter",
+"getError",
+"getFramebufferAttachmentParameter",
+"getProgramParameter",
+"getProgramInfoLog",
+"getRenderbufferParameter",
+"getShaderParameter",
+"getShaderInfoLog",
+"getShaderSource",
+"getString",
+"getTexParameter",
+"getUniform",
+"getUniformLocation",
+"getVertexAttrib",
+"getVertexAttribOffset",
+"hint",
+"isBuffer",
+"isEnabled",
+"isFramebuffer",
+"isProgram",
+"isRenderbuffer",
+"isShader",
+"isTexture",
+"lineWidth",
+"linkProgram",
+"pixelStorei",
+"polygonOffset",
+"readPixels",
+"renderbufferStorage",
+"sampleCoverage",
+"scissor",
+"shaderSource",
+"stencilFunc",
+"stencilFuncSeparate",
+"stencilMask",
+"stencilMaskSeparate",
+"stencilOp",
+"stencilOpSeparate",
+"texImage2D",
+"texParameterf",
+"texParameteri",
+"texSubImage2D",
+"uniform1f",
+"uniform1fv",
+"uniform1i",
+"uniform1iv",
+"uniform2f",
+"uniform2fv",
+"uniform2i",
+"uniform2iv",
+"uniform3f",
+"uniform3fv",
+"uniform3i",
+"uniform3iv",
+"uniform4f",
+"uniform4fv",
+"uniform4i",
+"uniform4iv",
+"uniformMatrix2fv",
+"uniformMatrix3fv",
+"uniformMatrix4fv",
+"useProgram",
+"validateProgram",
+"vertexAttrib1f",
+"vertexAttrib1fv",
+"vertexAttrib2f",
+"vertexAttrib2fv",
+"vertexAttrib3f",
+"vertexAttrib3fv",
+"vertexAttrib4f",
+"vertexAttrib4fv",
+"vertexAttribPointer",
+"viewport"
+]
+
+function assertProperty(v, p) {
+  try {
+    if (v[p] == null) {
+      testFailed("Property does not exist: " + p)
+      return false;
+    } else {
+      return true;
+    }
+  } catch(e) {
+    testFailed("Trying to access the property '"+p+"' threw an error: "+e.toString());
+  }
+}
+
+debug("");
+debug("Canvas.getContext");
+
+var canvas = document.getElementById("canvas");
+var gl = create3DContext(canvas);
+var passed = true;
+for (var i=0; i<methods.length; i++) {
+  var r = assertProperty(gl, methods[i]);
+  passed = passed && r;
+}
+if (passed) {
+  testPassed("All WebGL methods found.");
+}
+var extended = false;
+for (var i in gl) {
+  if (i.match(/^[a-z]/) && methods.indexOf(i) == -1) {
+    if (!extended) {
+      extended = true;
+      debug("Also found the following extra methods:");
+    }
+    debug(i);
+  }
+}
+
+debug("");
+successfullyParsed = true;
+</script>
+<script src="../resources/js-test-post.js"></script>
+<script>
+</script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/null-object-behaviour.html
@@ -0,0 +1,39 @@
+<!--
+Copyright (C) 2009 Apple Computer, Inc.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<html>
+<head>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/webgl-test.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+
+<script src="resources/null-object-behaviour.js"></script>
+
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/origin-clean-conformance.html
@@ -0,0 +1,131 @@
+<!--
+Copyright (c) 2009 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+  "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>WebGL Origin Restrictions Conformance Tests</title>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/desktop-gl-constants.js" type="text/javascript"></script>
+<script src="../resources/js-test-pre.js"></script>
+<script src="resources/webgl-test.js"></script>
+<script>
+// This function returns the last 2 words of the domain of a URL
+// This is probably not the correct check but it will do for now.
+function getBaseDomain(str) {
+  str = str.replace("\\", "/");
+  var pos = str.indexOf("://");
+  if (pos >= 0) {
+    str = str.substr(pos + 3);
+  }
+  var parts = str.split('/');
+  var domain = parts[0].match(/\w+\.\w+$/);
+  return domain || '';
+}
+
+// Checks if function throws an exception.
+function causedException(func) {
+  var hadException = false;
+  try {
+    func();
+  } catch(e) {
+    //debug(e);
+    hadException = true;
+  }
+  //debug ("hadException: " + hadException);
+  return hadException;
+}
+
+window.onload = function() {
+  description("This test ensures WebGL implementations follow proper origin restrictions.");
+  debug("");
+  var img = document.getElementById("img");
+  assertMsg(img.width > 0 && img.height > 0, "img was loaded");
+  imgDomain = getBaseDomain(img.src);
+  pageDomain = getBaseDomain(window.location.toString());
+  assertMsg(imgDomain != pageDomain,
+            "img domain (" + imgDomain + ") and page domain (" + pageDomain + ") are not the same.");
+
+  function makeReadPixels(gl) {
+    return function() {
+      var buf = gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE);
+    };
+  }
+
+  function makeToDataURL(canvas) {
+    return function() {
+      var data = canvas.toDataURL();
+    }
+  }
+
+  debug("");
+  debug("check that copying an img from another origin clears the origin-clean flag.");
+  var canvas1 = document.getElementById("canvas1");
+  var gl1 = create3DContext(canvas1);
+  assertMsg(!causedException(makeReadPixels(gl1)),
+            "should not throw exception by readPixels for origin clean canvas.");
+  assertMsg(!causedException(makeToDataURL(canvas1)),
+            "should not throw exception by toDataURL for origin clean canvas.");
+
+  var tex = gl1.createTexture();
+  gl1.bindTexture(gl1.TEXTURE_2D, tex);
+  gl1.texImage2D(gl1.TEXTURE_2D, 0, img);
+
+  assertMsg(causedException(makeReadPixels(gl1)),
+            "should throw exception by readPixels for NON origin clean canvas.");
+  assertMsg(causedException(makeToDataURL(canvas1)),
+            "should throw exception by toDataURL for NON origin clean canvas.");
+
+  debug("");
+  debug("check that copying from 1 unclean 3d canvas to another clears the origin-clean flag on the second canvas.");
+  var canvas2 = document.getElementById("canvas2");
+  var gl2 = create3DContext(canvas2);
+
+  assertMsg(!causedException(makeReadPixels(gl2)),
+            "should not throw exception by readPixels for origin clean canvas.");
+  assertMsg(!causedException(makeToDataURL(canvas2)),
+            "should not throw exception by toDataURL for origin clean canvas.");
+
+  var tex = gl2.createTexture();
+  gl1.bindTexture(gl2.TEXTURE_2D, tex);
+  gl1.texImage2D(gl2.TEXTURE_2D, 0, canvas1);
+
+  assertMsg(causedException(makeReadPixels(gl2)),
+            "should throw exception by readPixels for NON origin clean canvas.");
+  assertMsg(causedException(makeToDataURL(canvas2)),
+            "should throw exception by toDataURL for NON origin clean canvas.");
+
+  debug("");
+  debug("check that copying from 1 unclean 3d canvas to a 2d canvas clears the origin-clean flag on the 2d canvas.");
+  var canvas3 = document.getElementById("canvas3");
+  var ctx2d = canvas3.getContext("2d");
+  assertMsg(!causedException(makeToDataURL(canvas3)),
+            "should not throw exception by toDataURL for origin clean canvas.");
+  ctx2d.drawImage(canvas2, 0, 0);
+  assertMsg(causedException(makeToDataURL(canvas3)),
+            "should throw exception by toDataURL for NON origin clean canvas.");
+
+
+  // TODO: Should check video?
+
+  debug("");
+  successfullyParsed = true;
+  shouldBeTrue("successfullyParsed");
+  debug('<br /><span class="pass">TEST COMPLETE</span>');
+  notifyFinishedToHarness();
+}
+</script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<canvas id="canvas1"></canvas>
+<canvas id="canvas2"></canvas>
+<canvas id="canvas3"></canvas>
+<img id="img" src="http://www.opengl.org/img/opengl_logo.jpg" style="display:none;"/>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/program-test.html
@@ -0,0 +1,176 @@
+<!--
+Copyright (c) 2010 Mozilla Foundation. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+  "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<title>WebGL Program Compiling/Linking Conformance Test</title>
+<link rel="stylesheet" href="../resources/js-test-style.css"/>
+<script src="../resources/desktop-gl-constants.js" type="text/javascript"></script>
+<script src="../resources/js-test-pre.js" type="text/javascript"></script>
+<script src="resources/webgl-test.js" type="text/javascript"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<canvas id="canvas" width="2" height="2"> </canvas>
+<script type="text/javascript">
+function go() {
+    description("Tests that program compiling/linking/using works correctly.");
+
+    debug("");
+    debug("Canvas.getContext");
+
+    var gl = create3DContext(document.getElementById("canvas"));
+    if (!gl) {
+        testFailed("context does not exist");
+        return;
+    }
+
+    testPassed("context exists");
+
+    gl.clearColor(0.0, 0.0, 0.0, 0.0);
+    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+    var vs = gl.createShader(gl.VERTEX_SHADER);
+    gl.shaderSource(vs, "attribute vec4 aVertex; attribute vec4 aColor; varying vec4 vColor; void main() { vColor = aColor; gl_Position = aVertex; }");
+    gl.compileShader(vs);
+
+    assertMsg(gl.getShaderParameter(vs, gl.COMPILE_STATUS) == true,
+              "good vertex shader should compiled");
+
+    var vsBad = gl.createShader(gl.VERTEX_SHADER);
+    gl.shaderSource(vsBad, "WILL NOT COMPILE;");
+    gl.compileShader(vsBad);
+
+    assertMsg(gl.getShaderParameter(vsBad, gl.COMPILE_STATUS) == false,
+              "bad vertex shader should failed to compile");
+
+    var fs = gl.createShader(gl.FRAGMENT_SHADER);
+    gl.shaderSource(fs, "#ifdef GL_ES\nprecision mediump float;\n#endif\n varying vec4 vColor; void main() { gl_FragColor = vColor; }");
+    gl.compileShader(fs);
+
+    assertMsg(gl.getShaderParameter(fs, gl.COMPILE_STATUS) == true,
+              "good fragment shader should compile");
+
+    var fs2 = gl.createShader(gl.FRAGMENT_SHADER);
+    gl.shaderSource(fs2, "#ifdef GL_ES\nprecision mediump float;\n#endif\n varying vec4 vColor; void main() { gl_FragColor = vColor * 0.5; }");
+    gl.compileShader(fs2);
+
+    assertMsg(gl.getShaderParameter(fs2, gl.COMPILE_STATUS) == true,
+              "good fragment shader #2 should compile");
+
+    var fsBad = gl.createShader(gl.FRAGMENT_SHADER);
+    gl.shaderSource(fsBad, "WILL NOT COMPILE;");
+    gl.compileShader(fsBad);
+
+    assertMsg(gl.getShaderParameter(fsBad, gl.COMPILE_STATUS) == false,
+              "bad fragment shader should fail to compile");
+
+    assertMsg(gl.getError() == gl.NO_ERROR,
+              "should be no errors at this point");
+
+    // Now create some programs.
+
+    function createAndCheckLinkStatus(shaders, expected_status, errmsg) {
+        var prog = gl.createProgram();
+        for (var i = 0; i < shaders.length; ++i)
+            gl.attachShader(prog, shaders[i]);
+        gl.bindAttribLocation(prog, 0, "aVertex");
+        gl.bindAttribLocation(prog, 1, "aColor");
+        gl.linkProgram(prog);
+        assertMsg(gl.getProgramParameter(prog, gl.LINK_STATUS) == expected_status,
+                  errmsg);
+	if (expected_status == true && gl.getProgramParameter(prog, gl.LINK_STATUS) == false)
+	    debug(gl.getProgramInfoLog(prog));
+        return prog;
+    }
+
+    var progGood1 = createAndCheckLinkStatus([vs, fs], true,
+                                             "valid program should link");
+
+    var progGood2 = createAndCheckLinkStatus([vs, fs2], true,
+                                             "valid program #2 should link");
+
+    var progBad1 = createAndCheckLinkStatus([vs], false,
+                                            "program with no fragment shader should fail to link");
+
+    var progBad2 = createAndCheckLinkStatus([fs], false,
+                                            "program with no vertex shader should fail to link");
+
+    var progBad3 = createAndCheckLinkStatus([vsBad, fs], false,
+                                            "program with bad vertex shader should fail to link");
+
+    var progBad4 = createAndCheckLinkStatus([vs, fsBad], false,
+                                            "program with bad fragment shader should fail to link");
+
+    var progBad5 = createAndCheckLinkStatus([vsBad, fsBad], false,
+                                            "program with bad shaders should fail to link");
+
+    gl.detachShader(progBad3, vs);
+    assertMsg(gl.getError() == gl.INVALID_OPERATION,
+              "detaching a shader not attached to a program should generate INVALID_OPERATION");
+
+    gl.useProgram(progBad1);
+    assertMsg(gl.getError() == gl.INVALID_OPERATION,
+              "using a program which failed to link should generate INVALID_OPERATION");
+
+    gl.useProgram(progBad5);
+    assertMsg(gl.getError() == gl.INVALID_OPERATION,
+              "using a program which failed to link should generate INVALID_OPERATION (#2)");
+
+    gl.useProgram(progGood1);
+    assertMsg(gl.getError() == gl.NO_ERROR,
+              "using a valid program shouldn't generate a GL error");
+
+    var vbuf = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, vbuf);
+    gl.bufferData(gl.ARRAY_BUFFER, new WebGLFloatArray([0.0, 0.0, 0.0, 1.0,
+							1.0, 0.0, 0.0, 1.0,
+							1.0, 1.0, 0.0, 1.0,
+							0.0, 1.0, 0.0, 1.0]), gl.STATIC_DRAW);
+    gl.vertexAttribPointer(0, 4, gl.FLOAT, false, 0, 0);
+    gl.enableVertexAttribArray(0);
+    gl.vertexAttrib3f(1, 1.0, 0.0, 0.0);
+
+    assertMsg(gl.getError() == gl.NO_ERROR,
+              "should be no errors at this point #2");
+
+    gl.useProgram(progGood1);
+    gl.drawArrays(gl.TRIANGLES, 0, 3);
+    assertMsg(gl.getError() == gl.NO_ERROR,
+              "drawing with a valid program shouldn't generate a GL error");
+
+    gl.useProgram(progBad1);
+    gl.drawArrays(gl.TRIANGLES, 0, 3);
+    assertMsg(gl.getError() != gl.NO_ERROR,
+              "drawing with an invalid program should generate some GL error XXX");
+
+    gl.useProgram(progGood2);
+    gl.attachShader(progGood2, fsBad);
+    gl.linkProgram(progGood2);
+    assertMsg(gl.getProgramParameter(progGood2, gl.LINK_STATUS) == false,
+              "linking should fail with in-use formerly good program, with new bad shader attached");
+
+    gl.useProgram(progGood1);
+    gl.drawArrays(gl.TRIANGLES, 0, 4);
+    assertMsg(gl.getError() == gl.NO_ERROR,
+              "drawing with a valid when last used program shouldn't generate a GL error");
+}
+
+debug("");
+successfullyParsed = true;
+
+go();
+</script>
+<script src="../resources/js-test-post.js"></script>
+
+<script>
+</script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/readpixels-test.html
@@ -0,0 +1,104 @@
+<!--
+Copyright (c) 2009 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+ -->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+  "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+  <head>
+    <title>WebGL ReadPixels conformance test.</title>
+    <link rel="stylesheet" href="../resources/js-test-style.css"/>
+    <script src="../resources/js-test-pre.js"></script>
+    <script src="resources/webgl-test.js"> </script>
+</head>
+<body>
+<canvas id="example" width="200" height="200"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+<script>
+description("Checks that ReadPixels works as expected.");
+
+var canvas = document.getElementById("example");
+var gl = create3DContext(canvas);
+
+if (window.layoutTestController) {
+  layoutTestController.overridePreference("WebKitWebGLEnabled", "1");
+  layoutTestController.dumpAsText();
+}
+
+var width = 2;
+var height = 2;
+
+gl.clearColor(1, 1, 1, 1);
+gl.clear(gl.COLOR_BUFFER_BIT);
+
+// Resize the canvas to 2x2. This is an attempt to get stuff in the backbuffer.
+// that shouldn't be there.
+canvas.width = width;
+canvas.height = height;
+
+gl.clearColor(0.5, 0.7, 1.0, 1);
+gl.clear(gl.COLOR_BUFFER_BIT);
+
+var innerColor = [0.5, 0.7, 1.0, 1];
+var outerColor = [0, 0, 0, 0];
+
+var tests = [
+  { msg: 'in range', checkColor: innerColor, x:  0, y:  0,
+    oneColor: innerColor, oneX: 0, oneY: 0},
+  { msg: 'off top left', checkColor: outerColor, x: -1, y: -1,
+    oneColor: innerColor, oneX: 1, oneY: 1},
+  { msg: 'off bottom right', checkColor: outerColor, x:  1, y:  1,
+    oneColor: innerColor, oneX: 0, oneY: 0},
+  { msg: 'completely off top ', checkColor: outerColor, x:  0, y: -2,
+    oneColor: outerColor, oneX: 0, oneY: 0},
+  { msg: 'completely off bottom', checkColor: outerColor, x:  0, y:  2,
+    oneColor: outerColor, oneX: 0, oneY: 0},
+  { msg: 'completely off left', checkColor: outerColor, x: -2, y:  0,
+    oneColor: outerColor, oneX: 0, oneY: 0},
+  { msg: 'completeley off right', checkColor: outerColor, x:  2, y:  0,
+    oneColor: outerColor, oneX: 0, oneY: 0}
+];
+
+for (var tt = 0; tt < tests.length; ++tt) {
+  var test = tests[tt];
+  debug("");
+  debug("checking: " + test.msg);
+  checkBuffer(test.checkColor, test.x, test.y,
+              test.oneColor, test.oneX, test.oneY);
+}
+
+assertMsg(gl.getError() == gl.NO_ERROR,
+          "there should be no GL errors");
+
+function checkBuffer(checkColor, x, y, oneColor, oneX, oneY) {
+  var buf = gl.readPixels(x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE);
+  for (var yy = 0; yy < height; ++yy) {
+    for (var xx = 0; xx < width; ++xx) {
+      var offset = (yy * width + xx) * 4;
+      var expectedColors = (oneX == xx && oneY == yy) ? oneColor : checkColor;
+      for (var cc = 0; cc < 4; ++cc) {
+        var expectedColor = expectedColors[cc] * 255;
+        var color = buf[offset + cc];
+        var diff = Math.abs(expectedColor - color);
+        assertMsg(diff < 3,
+                  "color pixel at " + xx + ", " + yy + " should be about " +
+                  expectedColor + " was " + color);
+      }
+    }
+  }
+}
+
+debug("");
+successfullyParsed = true;
+</script>
+</body>
+<script src="../resources/js-test-post.js"></script>
+
+<script>
+</script>
+
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/resource-sharing-test.html
@@ -0,0 +1,46 @@
+<!--
+Copyright (c) 2009 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+ -->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+  "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+  <head>
+    <title>WebGL Resource Sharing.</title>
+    <link rel="stylesheet" href="../resources/js-test-style.css"/>
+    <script src="../resources/js-test-pre.js"></script>
+    <script src="resources/webgl-test.js"> </script>
+    <script src="../../debug/webgl-debug.js"> </script>
+</head>
+<body>
+<canvas id="example1" width="2" height="2" style="width: 40px; height: 40px;"></canvas>
+<canvas id="example2" width="2" height="2" style="width: 40px; height: 40px;"></canvas>
+<div id="description"></div>
+<div id="console"></div>
+<script>
+debug("Tests that resources can not be shared.");
+debug("");
+
+var gl1 = create3DContext(document.getElementById("example1"));
+var gl2 = create3DContext(document.getElementById("example2"));
+assertMsg(gl1 && gl2,
+          "Got 3d context.");
+
+var vertexObject = gl1.createBuffer();
+gl2.bindBuffer(gl2.ARRAY_BUFFER, vertexObject);
+assertMsg(
+  gl2.getError() == gl2.INVALID_OPERATION,
+  "attempt to use a resource from the wrong context should fail with INVALID_OPERATION");
+
+successfullyParsed = true;
+</script>
+</body>
+<script src="../resources/js-test-post.js"></script>
+
+<script>
+</script>
+
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/resources/array-unit-tests.js
@@ -0,0 +1,461 @@
+/*
+ * Copyright (c) 2009 The Chromium Authors. All rights reserved.
+ * Copyright (C) 2009 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *    * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+description("Verifies the functionality of the new array-like objects in the WebGL spec");
+
+var currentlyRunning = '';
+var allPassed = true;
+function running(str) {
+  currentlyRunning = str;
+}
+
+function output(str) {
+  debug(str);
+}
+
+function pass() {
+  testPassed(currentlyRunning);
+}
+
+function fail(str) {
+  allPassed = false;
+  var exc;
+  if (str)
+    exc = currentlyRunning + ': ' + str;
+  else
+    exc = str;
+  testFailed(exc);
+}
+
+function assertEq(prefix, expected, val) {
+  if (expected != val) {
+    var str = prefix + ': expected ' + expected + ', got ' + val;
+    throw str;
+  }
+}
+
+function assert(prefix, expected) {
+  if (!expected) {
+    var str = prefix + ': expected value / true';
+    throw str;
+  }
+}
+
+function printSummary() {
+  if (allPassed) {
+    debug("Test passed.");
+  } else {
+    debug("TEST FAILED");
+  }
+}
+
+//
+// Tests for unsigned array variants
+//
+
+function testSetAndGet10To1(type, name) {
+  running('test ' + name + ' SetAndGet10To1');
+  try {
+    var array = new type(10);
+    for (var i = 0; i < 10; i++) {
+      array[i] = 10 - i;
+    }
+    for (var i = 0; i < 10; i++) {
+      assertEq('Element ' + i, 10 - i, array[i]);
+    }
+    pass();
+  } catch (e) {
+    fail(e);
+  }
+}
+
+function testSetAndGetMethods10To1(type, name) {
+  running('test ' + name + ' SetAndGetMethods10To1');
+  try {
+    var array = new type(10);
+    for (var i = 0; i < 10; i++) {
+      array.set(i, 10 - i);
+    }
+    for (var i = 0; i < 10; i++) {
+      assertEq('Element ' + i, 10 - i, array.get(i));
+    }
+    pass();
+  } catch (e) {
+    fail(e);
+  }
+}
+
+function testConstructWithArrayOfUnsignedValues(type, name) {
+  running('test ' + name + ' ConstructWithArrayOfUnsignedValues');
+  try {
+    var array = new type([10, 9, 8, 7, 6, 5, 4, 3, 2, 1]);
+    assertEq('Array length', 10, array.length);
+    for (var i = 0; i < 10; i++) {
+      assertEq('Element ' + i, 10 - i, array[i]);
+    }
+    pass();
+  } catch (e) {
+    fail(e);
+  }
+}
+
+function testConstructWithWebGLArrayOfUnsignedValues(type, name) {
+  running('test ' + name + ' ConstructWithWebGLArrayOfUnsignedValues');
+  try {
+    var tmp = new type([10, 9, 8, 7, 6, 5, 4, 3, 2, 1]);
+    var array = new type(tmp);
+    assertEq('Array length', 10, array.length);
+    for (var i = 0; i < 10; i++) {
+      assertEq('Element ' + i, 10 - i, array[i]);
+    }
+    pass();
+  } catch (e) {
+    fail(e);
+  }
+}
+
+//
+// Tests for signed array variants
+//
+
+function testSetAndGetPos10ToNeg10(type, name) {
+  running('test ' + name + ' SetAndGetPos10ToNeg10');
+  try {
+    var array = new type(21);
+    for (var i = 0; i < 21; i++) {
+      array[i] = 10 - i;
+    }
+    for (var i = 0; i < 21; i++) {
+      assertEq('Element ' + i, 10 - i, array[i]);
+    }
+    pass();
+  } catch (e) {
+    fail(e);
+  }
+}
+
+function testSetAndGetMethodsPos10ToNeg10(type, name) {
+  running('test ' + name + ' SetAndGetMethodsPos10ToNeg10');
+  try {
+    var array = new type(21);
+    for (var i = 0; i < 21; i++) {
+      array.set(i, 10 - i);
+    }
+    for (var i = 0; i < 21; i++) {
+      assertEq('Element ' + i, 10 - i, array.get(i));
+    }
+    pass();
+  } catch (e) {
+    fail(e);
+  }
+}
+
+function testConstructWithArrayOfSignedValues(type, name) {
+  running('test ' + name + ' ConstructWithArrayOfSignedValues');
+  try {
+    var array = new type([10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10]);
+    assertEq('Array length', 21, array.length);
+    for (var i = 0; i < 21; i++) {
+      assertEq('Element ' + i, 10 - i, array[i]);
+    }
+    pass();
+  } catch (e) {
+    fail(e);
+  }
+}
+
+function testConstructWithWebGLArrayOfSignedValues(type, name) {
+  running('test ' + name + ' ConstructWithWebGLArrayOfSignedValues');
+  try {
+    var tmp = new type([10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10]);
+    var array = new type(tmp);
+    assertEq('Array length', 21, array.length);
+    for (var i = 0; i < 21; i++) {
+      assertEq('Element ' + i, 10 - i, array[i]);
+    }
+    pass();
+  } catch (e) {
+    fail(e);
+  }
+}
+
+//
+// Test cases for both signed and unsigned types
+//
+
+function testOffsetsAndSizes(type, name, elementSizeInBytes) {
+  running('test ' + name + ' OffsetsAndSizes');
+  try {
+    var len = 10;
+    var array = new type(len);
+    assert('array.buffer', array.buffer);
+    assertEq('array.byteOffset', array.byteOffset, 0);
+    assertEq('array.length', array.length, len);
+    assertEq('array.byteLength', array.byteLength, len * elementSizeInBytes);
+    array = new type(array.buffer, elementSizeInBytes, len - 1);
+    assert('array.buffer', array.buffer);
+    assertEq('array.byteOffset', array.byteOffset, elementSizeInBytes);
+    assertEq('array.length', array.length, len - 1);
+    assertEq('array.byteLength', array.byteLength, (len - 1) * elementSizeInBytes);
+    pass();
+  } catch (e) {
+    fail(e);
+  }
+}
+
+function testSetFromWebGLArray(type, name) {
+  running('test ' + name + ' SetFromWebGLArray');
+  try {
+    var array = new type(10);
+    var array2 = new type(5);
+    for (var i = 0; i < 10; i++) {
+      assertEq('Element ' + i, 0, array[i]);
+    }
+    for (var i = 0; i < array2.length; i++) {
+      array2[i] = i;
+    }
+    array.set(array2);
+    for (var i = 0; i < array2.length; i++) {
+      assertEq('Element ' + i, i, array[i]);
+    }
+    array.set(array2, 5);
+    for (var i = 0; i < array2.length; i++) {
+      assertEq('Element ' + i, i, array[5 + i]);
+    }
+    pass();
+  } catch (e) {
+    fail(e);
+  }
+}
+
+function negativeTestSetFromWebGLArray(type, name) {
+  running('negativeTest ' + name + ' SetFromWebGLArray');
+  try {
+    var array = new type(5);
+    var array2 = new type(6);
+    for (var i = 0; i < 5; i++) {
+      assertEq('Element ' + i, 0, array[i]);
+    }
+    for (var i = 0; i < array2.length; i++) {
+      array2[i] = i;
+    }
+    try {
+      array.set(array2);
+      fail('Expected exception from array.set(array2)');
+      return;
+    } catch (e) {
+    }
+    try {
+      array2.set(array, 2);
+      fail('Expected exception from array2.set(array, 2)');
+      return;
+    } catch (e) {
+    }
+    pass();
+  } catch (e) {
+    fail(e);
+  }
+}
+
+function testSetFromArray(type, name) {
+  running('test ' + name + ' SetFromArray');
+  try {
+    var array = new type(10);
+    var array2 = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1];
+    for (var i = 0; i < 10; i++) {
+      assertEq('Element ' + i, 0, array[i]);
+    }
+    array.set(array2, 0);
+    for (var i = 0; i < array2.length; i++) {
+      assertEq('Element ' + i, 10 - i, array[i]);
+    }
+    pass();
+  } catch (e) {
+    fail(e);
+  }
+}
+
+function testSlice(type, name) {
+  running('test ' + name + ' Slice');
+  try {
+    var array = new type([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
+    var slice = array.slice(0, 5);
+    assertEq('slice.length', 5, slice.length);
+    for (var i = 0; i < 5; i++) {
+      assertEq('Element ' + i, i, slice[i]);
+    }
+    slice = array.slice(4, 6);
+    assertEq('slice.length', 6, slice.length);
+    for (var i = 0; i < 6; i++) {
+      assertEq('Element ' + i, 4 + i, slice[i]);
+    }
+    pass();
+  } catch (e) {
+    fail(e);
+  }
+}
+
+function negativeTestSlice(type, name) {
+  running('negativeTest ' + name + ' Slice');
+  try {
+    var array = new type([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
+    slice = array.slice(5, 6);
+    if (slice) {
+      fail();
+      return;
+    }
+    slice = array.slice(10, 0);
+    if (slice) {
+      fail();
+      return;
+    }
+    pass();
+  } catch (e) {
+    pass();
+  }
+}
+
+function testBoundaryConditions(type, name, lowValue, expectedLowValue, highValue, expectedHighValue) {
+  running('test ' + name + ' BoundaryConditions(' +
+          lowValue + ', ' + expectedLowValue + ', ' +
+          highValue + ', ' + expectedHighValue + ')');
+  try {
+    var array = new type(1);
+    assertEq('Array length', 1, array.length);
+    array[0] = lowValue;
+    assertEq('Element 0', expectedLowValue, array[0]);
+    array[0] = highValue;
+    assertEq('Element 0', expectedHighValue, array[0]);
+    pass();
+  } catch (e) {
+    fail(e);
+  }
+}
+
+//
+// Test driver
+//
+
+function runTests() {
+  allPassed = true;
+
+  // The "name" attribute is a concession to browsers which don't
+  // implement the "name" property on function objects
+  var testCases =
+    [ {name: "WebGLByteArray",
+       unsigned: false,
+       elementSizeInBytes: 1,
+       low: -128,
+       expectedLow: -128,
+       high: 127,
+       expectedHigh: 127},
+      {name: "WebGLFloatArray",
+       unsigned: false,
+       elementSizeInBytes: 4,
+       low: -500,
+       expectedLow: -500,
+       high: 500,
+       expectedHigh: 500},
+      {name: "WebGLIntArray",
+       unsigned: false,
+       elementSizeInBytes: 4,
+       low: -2147483648,
+       expectedLow: -2147483648,
+       high: 2147483647,
+       expectedHigh: 2147483647},
+      {name: "WebGLShortArray",
+       unsigned: false,
+       elementSizeInBytes: 2,
+       low: -32768,
+       expectedLow: -32768,
+       high: 32767,
+       expectedHigh: 32767},
+      {name: "WebGLUnsignedByteArray",
+       unsigned: true,
+       elementSizeInBytes: 1,
+       low: 0,
+       expectedLow: 0,
+       high: 255,
+       expectedHigh: 255},
+      {name: "WebGLUnsignedIntArray",
+       unsigned: true,
+       elementSizeInBytes: 4,
+       low: 0,
+       expectedLow: 0,
+       high: 4294967295,
+       expectedHigh: 4294967295},
+      {name: "WebGLUnsignedShortArray",
+       unsigned: true,
+       elementSizeInBytes: 2,
+       low: 0,
+       expectedLow: 0,
+       high: 65535,
+       expectedHigh: 65535} ];
+
+  for (var i = 0; i < testCases.length; i++) {
+    var testCase = testCases[i];
+    running(testCase.name);
+    if (!(testCase.name in window)) {
+        fail("does not exist");
+        continue;
+    }
+    var type = window[testCase.name];
+    var name = testCase.name;
+    if (testCase.unsigned) {
+      testSetAndGet10To1(type, name);
+      testSetAndGetMethods10To1(type, name);
+      testConstructWithArrayOfUnsignedValues(type, name);
+      testConstructWithWebGLArrayOfUnsignedValues(type, name);
+    } else {
+      testSetAndGetPos10ToNeg10(type, name);
+      testSetAndGetMethodsPos10ToNeg10(type, name);
+      testConstructWithArrayOfSignedValues(type, name);
+      testConstructWithWebGLArrayOfSignedValues(type, name);
+    }
+    testOffsetsAndSizes(type, name, testCase.elementSizeInBytes);
+    testSetFromWebGLArray(type, name);
+    negativeTestSetFromWebGLArray(type, name);
+    testSetFromArray(type, name);
+    testSlice(type, name);
+    negativeTestSlice(type, name);
+    testBoundaryConditions(type,
+                           name,
+                           testCase.low,
+                           testCase.expectedLow,
+                           testCase.high,
+                           testCase.expectedHigh);
+  }
+
+  printSummary();
+}
+
+runTests();
+successfullyParsed = true;
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/resources/boolUniformShader.vert
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2009 The Chromium Authors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *    * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+uniform bool bval;
+uniform bvec2 bval2;
+uniform bvec3 bval3;
+uniform bvec4 bval4;
+
+void main()
+{
+    bool allSet = bval
+            && bval2[0] && bval2[1]
+            && bval3[0] && bval3[1] && bval3[2]
+            && bval4[0] && bval4[1] && bval4[2] && bval4[3];
+    gl_Position = vec4((allSet ? 1.0 : -1.0), 0.0, 0.0, 1.0);
+}
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..e78cfe79979b85202bec19b8a454e669361ee8ca
GIT binary patch
literal 10050
zc$_6#Wn5I<*ByrLp}Rvs8iY}5Xr%K2=?0}sy1PNTh7u_W=}rNW77&mYq=p#4VQAj*
z|9&|4o=^98&tChiz1BV_URzU{5RVoQ000oaR#DIe0MJlV05c92>iJOpX%{sIyjGCa
z_bWUJ4$L$)C^~JQdFfN5*<0Hsv3{ueBMT&#mgbEiiz$x|yhw>C0jumdO-_0eOeb}D
z=cds#luY-AmD_&Jd+koH=pY&<sW=}F#~bwimLb_K@o-vSqi3)me6{na6D&uPF}wb@
zzKeg;xV5J1c46c0_*cK%(-rdW#7qGv+!s!?G5A!R_P9*whkdriaDQHM|Ah`t^eD*^
z#oXH9^u!qzXCu`gDI=wx0BCbw@x1z^Q7~=MAM$WfUtiy*Tb+sb=sSo><?QU_1nWAg
zsSSA;Bo2Y+9l9M!T<ghN!VA6Pg*Zh<ZKpfgqnM*WEU!s(?DAfJ_!>E;{~EG{@HR9w
zT(y<S(X2$YwYAk(FZi?4YXr5<M1gbyi$jUNDsz^hIj=PRIX0;MuP)^Ne5?TwHm@l`
z$j8Tr6D?PgIfM+R2fG8x%gf=C#5oorH)OSj4dy;qD-Le{-4ZMoO`bDuQhtg1B7RWf
zu}httge%j)xeq?`W;y1ftIqRN6c?kUOXu4G<fJTBPAblcBW&v;Cc^X5Tkmw59@ZR3
zT<Bi(Z~(Se`GZzRdT72RPl<dm+g33Om4IQ_L>77R>!?zwR$nYkto9p;O(tno@7@t)
z3imj<UVduUEMBUvsiDG)z7Hedl%VuB(`uh|<!dYK!U2*!aqU397=0z~YrY+&bM4sP
z&*&R3*LFHsYuj&9wc}nyhzTlzD=<p68{)>=CwzR&(6$+ZXY{^A&ZR$!9r+)=W5cPL
z6q%O!O>DtbEvwIzB>XL*Onkb)XU*d#8w37#Udtk2#V$vRB3bEtTq}e$kxBpykU3$u
z+(tNax#iEOJ|9&N^E+u>g5Sa#B86hc7z2;Ls|ob}efuVRMPFjO4(`_PcWx-)3Nv>#
zBI5ak*=uXPy+%_c)788)bXZf~;QQHTX8O?}`itr`lA3oy(dsjB-n~R|IL!_>x(995
zv%8`5acz;xqR(&Ldyx>Zimk>#M@-Z}`(mB`4?(7v;OI6DXV7qzZ8oU+!f1i|tmitC
z>a*+HqScp02<)mCAxl2PPl(-1WPi`yY%)~KN`ldOEc)$A$9<u1@YCMJ%$=qrqd04N
zTzO4RB^O@NF|yxvy({JH@$Y$S@%69uG+btqi|pd+4ubAjKFOs{w96}*g-)yCm<(F%
z@b+Qv2f1IXcd6FA{pw(%s2w?NrV{cY!~h?D=B0GVRkvFX6@QRuhl8R{74O8c<C!I^
z-(RYyKC6!Y_98tZK_C$54rFByL*K%%Ttr4JMUjM|ukCXYQ-IvQy?^|J><?L!25*yE
zPGs{rSiE1c)0)Z?!M1q1T_VAY*5<bt{8?EhSu*fk@0$Yi$7o2Vkb5&z{8tuHaq;s0
zex~Bbzm-or<IjrkXNRKkk>8poKNaAZ2h_FiEUrIH1b^Sw!<yN5mm(^@IOJjkxWg;L
zTW_GA${nmM(zJ5^%jhvu-{i?Xc-YoSWqZu!%Nd5@8`h^Q{eeDp8`T!>>+RX=uNV++
zlDQUl7m&X4-<^U{_!GX{+DvU{^4i!DU~O_@`?#&>;o+0OpN}mMWJ~7$FdDVWC3HLj
z7Qsgi38LVm#Soa10*oaHkN?K<19tH$S701P;s^mi<-=DB#nQnGOJSd@zkgdsj|#SR
zi1^qCE9kRlwyx>b0b}{yw`%<FuM8mSzQ(6{Ui@$FkPUV=HsW5ZSbSMqRCpzSgrm;T
zcRsR961V8)Df;%b{ggs1So{pW-+BH*qj`9{kuGh}wwGCnCP|m3{sf|pHpBr+sSzKj
zs5ut_3PNT*NJ{|JXkIj`Y>IITyHP%cX@LLgj9ZQ8MS~92EPx;-yKDWVla@wg^we?y
zJm+BaJqT1Nv4if1EKC$KDZpIqA-Q|LiMdZNFE6iwT=Saw-hI}0*X9mB28QuYIP*kq
zJN8@~YmJ50huYP_^g5)YVLHo1(K|Qr;P=9cOoQ1}?>`41{uD9P@02z;;H<Wvj%=*Q
zZh6s}UZ=%HEc6BNnu-#C>4<^;0E~{}`N21PQr2y|ABlY*5H8R3o>F8lPoYh#B>z!l
zcHqw=bu7gQ#v-iVq+v!*(&)#te5$cz$6T?#9-om|3aNOpl=uBpS7im;=pc25)QldI
zm~zIff2o&loHESAJvBU*yXq*Chf%eUOn@>m548j(R+4A*MBSy@--?}si;9X)F8QA%
zO?k8%CGYz-A=QrZ*92n-(@uZ~w{3`L2E_7S(-*m3rrkjU#Wv?1f*pnjUJG7i;c@N9
zap75)f&eAI{i$1d$<6(?*$7vTuR5tr;Ta07I=I;&StfPwV|@OtS7N-w7|0cp@@GKh
zq+)j(VR99P>c?VW1hDULu#7(_#M%VR|Nrzp#uR#=fMP<lLa*iFm(<;(vv(5?@G4&!
z=bpjFnPkbxU^aoBv;ANqQZ<{|4h;W$5M(hKc5q<S?l@P*kpF3=rY0c#nIMHxN^ywo
z&a{D6Z=)}V9YOurR+qGM`@8!Ty+t%l%IrU%LL0BzeV5x}H#T&f*Kc2OF<|T~PUg)o
z2cNVWHat@pu}ST13!0yvGj)Oy5M<%vwc)YYt|59Y8hZRke2{HzVm?|GA!AgXLio@1
z(s82Xv`hG%aSj$n?lXV-E7gDTS{C%uI$l{KF_epQ#I5omEc6qsj&+dm4Lv_f?LmIT
z;R*vqV2sKbiE0J9%iJ-&&?An=55whRj6D`s;g7V{^ZTe=tIrd!&tq^AEc2B*!)c^B
zzO1`jqP@z4vI+z?a<?SNgv6?Wtb=|_jeZFGM!K6ukf%`u0J@Fwlk?a7MFfY7V6|(9
z^|>)!oopmav9U2vO$m(8Rq+!OLFv$iNm&G?h`U^d;gV_CO!wWX{HE6g75dc_%Ba0d
z<`Qd{DI_e3G4DMXj23s~Y!O@^fJX90QIcFyUk&ns9fB2<I@H9MX-3v;^XzAIiW;Cm
z%;gmmz_XM7vmDl3pYYnIRBYr1o15?>K)!0=Fc^qWmbm=`Ok~3n^937{HNKAuHQndP
zi0RxUD#8Cmy=GjcyeG&Cu0D&p2uwu-?C9%Z!!1&|Z4!^ig9y&Gv9S^O==L9`Wnr?c
z5Hh|Lv}9rWGCTHpng`zo$v)9M%_9I@>uKwAh~vtzi52TU9x+9AQbLtwQfe8p6aA#F
zP6PHy_bG0?KlcYKa{`7O$F~$THPYN14e!TQ#fg;9hkJJOt9||ctLv}%h&bkOR2e#A
zB9{Vt+G@4Bs5YGMM-pCMeqp>ScQ;bwssY#m8OgNCiOSp|_F-R{X?UIAm@iyPz7Tw@
zCWTBKzuW?XK-w>{$!To5i({OU3b!&aT<xeW?!NO8t0Vee?(1&PmadwqZktg4O(!`%
zI~l2EW5a1}dwjLAc3-1hJwz67R)LN!eUfiq<CxE7OzAv>j%HmDitMJ_^d09QuBka%
z#496XKvov{U!k9?>s9XS;PBU|F@_(JLI6!4A$s~M`XAdLu12yV@ci0h6U+yzO4*7E
zRuG1p_jhFcim7S<*iwVV#*ZJsB_Eaq(vR!iAO?S2iP_NI`~tVWn|^}fxThn-{#!wS
z^GEE)U&#aVSomq9@M|9}>6_iy`p&(4Wgr8yw#u^~xBz&!A(3~`nZry2g&YJ2ZMt?Q
z(*w*OZ51fUOZ@3inRRE{$JeQ?G6Mq8CmAY9XQ{XZrBW|qEF>Du^+9D{Bfnq>U{;qz
z>b(87YwYoE%$IyrDLs|a3QYb<&Ev?@42JE#k$I#Qb%Xw;@vr+vmO$0M@h_HfF{+T$
zp-+<qScngKQ)WUwGPc|p-@%fa+xSen`Vxn6kh%kh)wZ^`I7r+V0Rf!)2EVF7@Vu}c
z{HWj*l_<8o>seDS=zevku3b%YsDp#UUA5X~tdUC0AFnVp5<saD^=kVgfyJAf9N)r&
z%ep!$q_?;C=YpeP6N<~sIjep2i06&o5v8&b4~i5qg^SJA3sBF_LVClyYB8@zN^>Cx
zg`nmi%%vYW%F6T9?LSNBtlH<>PkI!pY~gxLSH!10G;fB^bu~Y8UmtdQw2=psgd0>1
zG!Z7feD%YNuKRHb9cfOjHd?ud=DgN%9)aQ-lwzA);wJ6w9+<^vaGR`Oac%>}D->>>
zY3R^YM&Y~j(&3Ygc<r2>t+t;n1W8*|qV(oxY$wIR_Mril>cti_ck>q^(wZ23Gus`D
zEB)5XTm@n{+hG4oY-z7yhtuA_EnZ@$uv6DXOy!D?mB{xlPTh!4T91RDe@t5+j%ZR|
zg`+tOQMZXCNNdh*shjP6b1dZtRL$>d0>Esmaddkx9tV9=Po?fhI`YGKqqjVWOtd?O
zhChsmFhM>4_%$EwgEeg(bnYV?I0dQ=(Ks<W0II>*w;aVh<9YbB3_O-Mz&<CrAGmo(
zpP5Q(YinJ8RwqJmYMfjKw<j>-grclq|Et0JJD<Hpp%_#Hu>MfAlarI8=l^{+@)9oX
z5BrN3IfDP(-XN~_fWU?Wn5YQSw8z$%Pl}dfk)fW^RSyv}Zb(ln#`BowP}FghOs^6g
z-3`M)-yuHA<!1@nR}*O9p}06<rmuIA^ZgE&mwWn!?7P`+7Y^A1W0b%GUirDu@mt^G
z&?+HIsiN7I*h%9PcEBVW^T#N9ZsL8OrCGVHN?u7m)(9X}uAkb!^s%wALBuPR>C(~W
zJ1YAzDvr1h>Tm!?F)1gj&$=$|qlxe5AG9_ZChwDkRd#dLhF`OF`{@|IKQC*aglxBE
zOrNc-TPY14wDWokF?DyOHf<So9HY}|^>Kv887iwW*ksRll?HZ{S8nZ<y(0i&w9Q!F
zNZX6OGo$K1%k<IXdvYA<-z0DUm42H=m|k<ikD<*-M|~J@AyaJbJ>}4#Qc(^EZv~hy
zVkUpfRakz^Jvcmk>*5Gac2|*0nowcauj1og&N2_$#jl+=H1{I>9ZxRFxus1sw!i%N
z{qn@3A0~0~PdGd`tnYCcjKB=6)D^c;7aRTD+45CZ3e6ZpMNx4<E23ty%~7#BadB+l
zUejNT6Iz4@w4zmF(HaZjnfu|?#M}HU-j#=CARfX*=dybKBhl9=i*&LnrAbeAu6nD@
z?P0!7#Mu75*2g3pQb?LV%EGX`;raa^8h5@jrZQ*XS8JgR5Ucf<+&6}XIY>zX6bM2f
zE3nPSq|Xi|j6z9+7}^vRFc@r1w_2YYrF@cv{L2`_l(`8e&~|_#FtYVfpB?{N8PD@P
z7)n-Gt_w0ye?p(RWF|w42dNL^Sz5cl&6nzMl7IdH$*0himC>@!?8i&ZNuQWHl7>at
z6}c(5#%csiXvepXu@e&JLtb|XG7zI!>p!RW4~G1K$k(yVG&W7JuI&#eMLSM;i-bGf
zN>PBI84vRi=M%Pw09Sdr--x#Z4nXM1kY3Q=YJ#z}c+Tj5X8O|YmQ_>{Xaf}aU<FPG
z<x}!1njK4V;g?i(r*T9$s>JY;@CG68JXZT3iJ^XQ?B}PQ`;2QIV+_8Nxk5V%)`LQW
zFLUtNHmv7y2az1PqCmB;vK6BA!vDS7t?c!MdXDDdmdS?W#e)R7qdRh>V^cHvv-c=Y
zwb)xq{Ulu#%5|Qj<e{wez&PT2!IztMt%kbH3oZ&J9U;|O2K39Ep4!V^Dn1jLIbls|
zEN?Taz8z-U9Fp*4(8k&$N?vkijC*pCUr;E@@=``-x|8UDMQ0RWn3UqJwzZZo$&(=f
zLEqiYO<W&F_Mx|ML{1OM=3e1&i)jZG8yAo+=)yQ)5-ya#(d~N~^TpI+wd!XgLwXLJ
zt_vMqUJ)>Gf(-UCCcm~R<^BMn<o+8c%+3fbr&tz?Wv_xJM|V%OWoSAcWr~Iw&&_xi
za%N9H3bT#lZmC4j{CwJ#2|0c<Y9z_{4B-(iHVRns*b>HO^eu^v$|VAJ_#;>|ofEdp
z@D1AsC1VC7q6R$};#4pac;qJ>9aUpXzZ+y5zkhImfBp5;`#VMAbRZbHjx@}u7FTiG
zIP<HvQrZ@YA$2&wR?O>2`|Q2SoNP}NM=A`B)fbL1QpaS$P|{c0SZumI{cAXrcpeIU
zDI#p-bl=K)J&qun?R9V%o83MYEB`nw_FPbkj$&!Z;W6aT$I*3M+<{BUjuiBjCFV%k
znsXQq3oB_nc-*#061p3v!VV-QNs9-d$#n59wz*9Ctix^P<t?tSvHxR&1&_XTUJYl*
z1pz^5Ai0ezz7)I4wYImLUUXP$k%td|9{f6=?C3WZWAB%#O90|#zVlsb{JlX#ypnHv
zen|Y-$p1D}PLG!k%A)w1Dacz;!4&Xk;5(B`P{mGPf5*Y_nFYAtOZX4g=-FM!w>B5T
zFT2C%vvi}xfc{|bhv7f>Mi#u3HmEJ$Q8QZwXBMI(^=0uQ7Osp+5n%gNhI!Bhy~<TF
z(It;&LBEQ_oq=yjkWcQzrN~C^(Z1@w6)g_H0*863$i1ou0^&d&e{Dh|-8Q?NM{@e_
z|G4dYcAk#^McX$O=8MfF#P6F)6UgJrRxY6;8g5miVMWLq*u*J_#Em$Vl$H|ttZ?D5
z!1J(Iz2FO@KQ^bKS-<$BzA@FNWU!#k`26VK{5!dxtrKBG2hYWx@M=6xAg(J2{1x%K
zqP(924V;3X3Zxe%2QBcQ>Kh<LHJZl^f~#uqfW+#cW#+9HOSgSY7m`|tU>OB&gNP}%
zj2@(TxEGO}pU)MO76r#vE+qvV{4MpW;TX2=<y+%iz9tfP0DY)hwX?Epk0&tjSVu6K
zAWz)ZCHUTijmhg)z`WjcI{n9!z<}No86X)Ohml9xVT{p>r4@S7*V=!(zSQ67t-15{
z0+jNxC#Cz5LeBzSA~ay?>C0v7dV#OY`mHfL={d?Fqcr?acnGxpcKa2j<XHGwp!;7d
zU>SGcSuC)r!R(@Uacjv(s&0hTDD<qz5!#B8KtGbSr&s!ow5<mYGT-Q+JPSNqDO&G>
zhMd1{J@I<FKT}bZkBhaV=8rxS`etf5*U9wt76Hp?Fzvj6j{g<dH?1j=^R5Qw2ofZc
z;`K0ft)tgUM)(==PZmp@MXM|EP#%BhzDu+@6W~c!8F@k7gm1<@(56)0AGmUNfM8M$
zkx5t4|Kv1@K2W;k>z%1~)8dk~eMe-vH(1Kg-*@!=b*z+@3Ls@?;DZ!(9}u5bE-n0=
z3&5hll^|zefEXpC2PG@X(qpG!@1`0HYO7`qTvyW4zM{nd|ISijW(F-Ho>mnAK@$VN
z7G!(b-r5d!OY+_{fS}$sT+Lhr&>@sA7I*Ev&xZZ%m1^w|H~HnsL}V`TZs9a|w{<9n
zk)>7fHBJoOSQXhwTKwPg0t@5EB}0K?_||@*8Y-mk-9r0pCh%bm*k~C0pon3_xXN7I
zRn<F3D1kkxCW9<T+jcsW0(~ux5)IeRR#IdXov?_5fU#)RHDX+0QiC(&j|%&5b<vBA
zi9cQKJ=be%*o=N#+0)a-Ela03reCZ_@|i-Ai)_G6m-hAd$a*R!bN{KS;#gJ^6>Uf`
zJ|4EF%nrTt+Vx+|43@AkoOl}G+;CcOOj^C{3wBV393ro^r4EtTrS8njXqZfsr|lLL
zrQHiMR|=x|fElGmYPvpFUk^ndota%{IEuc*d^;E}2%fv5#}91l{i`@8w&hRBh1}96
zuBIVecj&oWFUsJ9<zl!$-t4;p0cJ~R$75V(Q2`%?$aDa907!-IYm9Cv%0P@+3$c^p
ze)VA()|ZzV;#!Q0;p5|bDD>jC96Yp^k9fD78U|q{#UYt@eOkMmA4#5ZfhPvgwL33M
zty8aDQ;P)#eks1gX`MdmJEI~F_B;JB;s$dau#wG*e}w-0+6z_t`H77{F?&c*qtv+)
zzL0XVq!|N<XniVO7nqWQ-#udnM{f}n23Rf>%Leb4FA5&h%>kxsU!oPFn=)T-=B+n8
zUZ~53rPg0B3E0ADvCx6Jj-*EXIWY6qcZ)~=ddyfG%am&y8yjx|*ISp&@8B*Ly}^Gf
zrJpbX5Ec7I9JC#Rct>EM6RR;<G$>;7ovQQciO+O2fRzO^U7MQZMM8{s+p~|~%p0?F
z?DD4G4khZabti#<n;dCT#Cvqq$4mu9GyAZzxhjgZ0ex{LOlrmhSAj#emov=+oy1sJ
zOGx;3forcX&mV>i0J&mmwSLWRmurnF|Bep}Tj`_%17BG-fOjGRIPmyzw_ohL;UA||
zUUfO_M?`a6%dKT#kP2e`G;y#Q24E>0g)17M=PFTX`<ZuLOvVr@2()syp}!Kw`*LHD
zNz52FPQ!n{`|PLLd69%$;zwP#yZ_dv>r8&F=0Ml||K3%{{aDYO9iSH69h-wyf?nup
zQ#cLTE!97n%-eHyS78A02BqAm2Qdeh=|-nV386w^DKZhrNPROoKvu5Mu;B0fPb;k^
zky;DcmBk^qKVCTf{EU-izJ%}=&KeyOng04ljk4~g@iP86hR+ueGX{Bl2|G!LJ|yqA
zq#6!MGppy*TRY-H{AI>5oH;?z^Z>D8vblkQ0Ang0>bp@Ok1pC+n*i$fG*`47et(4A
zYs2J9(=^ygv%Fu`VOw2}v!gR4KSGxpD*6aVO>qPTry(y#%6y9#UuIpTbYmE`Ij=PL
zKO!0$-qT|j2ql1NJ@CGR@zMQ!BwKvpTZ8_C2(P`#L3P<#Dc)^N_Ahkh%HL~hYbUfS
zfwW<krU-1NXW=!^1dEpMe>C^=fTP7MJhi<q4+IzoTnS1XDB*wH)_h?GOTj_wE&qX2
zid`i9kcolF7KSyX@vS%=ql=9(hA91@6Y}2jFptk|W79=9JA*Y$$+l${OrV>J)7;3;
z?W5JwH-JD@m`qJw|2<PQPFwf-a1XRsuJ@V1q<C=>v<iUT?>MS34`3SmK*@h=f=Pa?
z=~WmvOm2(W|6<*7aa)k>@PmfexQ9AkpEe0Umw&94s@Hd9CiL-gnt8?Ha&Ky%*ZfCJ
z2hZ?6Fku)%j}`CP)AztZe<IXF5h3(T@Yxk<p$^V8=r?&@V_2s8kbb<<&|31?j?$~5
zpJee0idjP|0g)vKzqU4*2`&YB_LwF2I<izbtf-aN+FbZ%<vHh}<#S8DPA?G*IH%}Q
zgAUS7$;s<=m4&Z3&MrGJ8iQ^w5UJ9)2a5oAP~dDBzLkwwc3G6+c_2!NO8%Xd7Y9PT
zyhMymOy;idLL|LZw)|D7A?GS@I!){E4(6>i_cC*hL4XhX>(4dVfpRsehXY$`!?kj&
zw5tw{G>uBUmTtJa1N0wnrw4B;OP_bOS0F~Z+dd~Oj+Ai9Z!w~$<JcNtU4nNT7n-+j
zt2uT%GC%nerL+(y{~<|y#!UJeZbZ82w<qo^<2_NQd<E=Cs`SnNY(VlNDvH&HGgXcY
zlB-j=nV+Z6s+(5L8T~u0g%XDdhbZj7;6Pb4l|@2`K`0ZmY1lU)sj|;AXjRCwC_s}s
zgnI#UUsQ#it67PV(;4G1G)->gmHmJd1t6!n{w3a*+z@nlx%sO%5P8^DU%6Co*6uls
z-vGfU!O<F+THR_(1>v;y-I{#vdZ^5pj>}|^A8VR3_ZQnVKBhClqhYRz(&tTy(YALL
zGF4Y(O^2dH{YTwuU8V80V<9FA3*}-joChU=?|ms<G(Ph6uo$P2vy8d^NmU`kpUR$@
zuRsxK5#b&QB9sCrg{uAoxHwxqm(zjLelA-SJu!OPN>cVVLPuYijLq=s>grS~bd4G<
z(cbqq5l*}9EE9yAQHP84=>x*{_V&Udf&@_|Z_hDQ7Oy#24U(C5<6!<xT;x2Rp*JIJ
zzJ81&2adRAX4tcvG8im1MFJsb?df&81?(I`zNgNj;tr)SPSYi977RAFSJRSS_WNW@
zp@HlANB!@%j~8V^e!_5KZNHLnGiPA_@L4t&`z7;utruHw(&A{QKvXfI&zm~_PBZIe
zP#!D!hji`X+^oq1hkavCiUb0C8A=(ai8!(ZSQk{7fX#lzbs1SbNsU4qn;A?N<-ytd
z>7vq!M1Y9DCU6mrAe)tqLuS1|ot>viS4M2beJg?D`A<{d2SSFW&1)(+GjnPnIf>#Z
z2bD#fV(J4Y^0N5;AZ0XrW%>LzgkA5gpL$rAbP@}hFxhgigUH^r%TeL+7t7Y}E6T!x
z?$CpQ(-%o1QMQ=I;0SMU{7rSIc!Hm82y5ZdYc`J>t~U-xk@D2w9)@*v2^}tCSx$(W
z(`CJJFYJKrD`#SQsr*Ud-PR;J4tgAbik?tIZ`A{@FbuFaQ{4a5T>NlM9C|&>6haA5
zIu`+V;Q3D~;MYfa_=#h+xaxnv>T$uqm58mhEFta{ob~-!7>!SL`u5#BTD<oPnCyZK
zjF82xO~HWItOjnDwA5SYPb=_|zLRdjS@DRz;Rp9OxcTlZ%*+_r%*^SaA$Kc!VUI>}
zjPH`}vb7$#+blzsA$#x4)M4f!d-s7qiI|M4M{Jm@2~^D3TGSbof@F}*k+G*>DU;aw
zW}mni3hil~5`Kc>p$hW-{Uf(|x$jXv@xQ_ao^7^{H^Htbc;q!O|NBM@CGn+yM*6kE
z35g@RI8tCEB*0G{EBWY>LhyPx_Bo+|sM8dB^TP3fU)gdL@mKJEp_iCN@FIoN<7MEc
z*?D|{G`7-9_BV2()vW1wHjh1>9S=-~;b}D+107*!!UU)M1LNIr26UMKIR6^rWYLLp
z^(?%R0WbPKuW~Y^RJ!t^&37y%(G1X62PySne@%-hJLO$WDzd{z>((AP?UQzvat8#L
z595$98yNb6SGAW619@i0KViad200>hAdTnFhG^3?l+aG^@7()i45g^@b$8PKbjg+~
z=?R}&*#Q8s9{$}0n1aLI*#P=*CnGS0)ua-AVtUIa`Zy(ZRDAC;K6b3EP|Poa0Ze?#
zV*`W5L<LsOMy$f)wr^yztOiT{HE2nJXwOWz!Uma4CSdK;XjUv-g{(7R(;ojDN;zt7
zomlV;#9COrewacmB0X<AKI7f6MJT*%^<pIbuYg5Jy}W7#vmLCIQzT8FCi6eNVw;)>
zM<dyhbL}fBzs#Mry{~nZ_T?~66ANZn#d4kJMVc@<9MWVZzKNzX=zjI!B!vRL`g~Hg
z$6`)7xoyx>F9?|4vCr|ksZg~-73Ev$6GtXdayLqjCA4hw=6lxjv(C$DiB^jTq}HqY
zp5t=&V507Wfuxu;*I7_}YzY_X<cGwe#_0R7c-@U~7`2hlKHv4S22-C`O+f_v>))l?
z-<CwD%me;pZF2p&+#Z(jh0a7nxQmrNY%$(y$QxyEYbS(z(%g-W3hGxw&`LN+qdOBR
zrKont>5GUY5jX?kZB5b<s+|N!9?RLptB8^jQa#ENl-CfkpQQG`-i~eP-OG1kq@kh7
zLjw@pSz0l1mI?gtEcb=DIPt$$$+tuztRZg@#GOl_4i?%I$;uhow-I#O-B3T%8AKrc
zd|;nL(2D8KIs_+5zgs6xyjVVM?@PuzY{31Fvdnv@yD|}`$GIzp+JG!06EI~g4@s0A
z5QG~u!@N~y`!bHqo8L*Z9-5K#Ub784fR3}^Qj&jEgbL;0&kbXsJN+}=YJJl5v^~`t
zi$xrT7wmLuFaMJll{U7pkjb91$B$PiBUM1-tO*f7k@VR=-unEe8O!2!YKNitF)=H5
zsSA{H$`aZE6bm_~yTqifgQj<EuUP!9gq;mnO5cr3^xsUmg}5{YgP57+H0F;LSase6
zoU}eg`1J%XebO*YCQm#x*MG*ykHNbct5LfdC`#^0w>PzFF7A6OW?;~3+oT#X_<+qW
zxaiUEaQCV06v~qMoIh6p5{xxtmn-7?4#?~tAuk)*nD#dROPxtOe=n@QyYF^EPs>a!
zUCyi1)Yrts#86LfUR#n;oR*F*)?o%3>^EKbvR6YxLq1Ra6E!NGG7bp<Tn5K~Q-XtC
zsGk8!^6?6joNj3@3o6&R|9r^X=yM4z2(vIdvw3&^(fd_}fVt;r%O9+yWzG5}&s8Fm
zpQP~sTmwa2!g6y$mx-v|dVQ5c=)0BHu^{X>1>t@awilR7Sf`;VXQQub<B)~0R;xBu
z4S-gX%3-80gnPGHAt&=hu<2-NmC#9XVuw#{XCeS$cW3=iUMTtXMo1F;vu!I=L{O$3
zRA?AW=m0d65Z{3yT}?xWm4DV5eX*W;xnJ1qU-JOaAJLw<)JG}i5o;k4QPG8k&CN|=
z)LV3RRl?WX-CdKT*bP<d)xxxgte(BFQL+H1bKUkaeL$7}9S^pGDa!nU0&M%K{Kch(
z1<_0t`saRYI77cPT$ToV%}$^*11oe6>}t&5;PVB!umO`oJo=B(v@s+z`<Fidnz{eZ
zg!)3C9&cJ%Ab?z{z^m<;n3%avuYJaMZ{HqbhgsIT{{uozO)d1_Ff%ig&Qs5h928uP
z>5n{Ah5!fI1n<i+dn^kYQD9ns$)%yAt6lPuI_Ywyt~w>JL+NI5QPCuO;XLa)Y<FR&
zt<%#}(|@;q+FVw%7y6j)ITc?OL9<PhEHCg?>b1FSm6eq235bcsDe<D6tMyeo>*=He
zQu{#>Dj&W^N(mzn2%F^O<l%qg-&}TMpe255K8%bM0-}14+8F#f8UMQQ!^6YLvda2A
zSy4OS^b#`QLf3~C=QizCT$H6EPgbfM|BSsk_#{DJr_ZF;OKh*Q+SaOC@qsH#l^cab
zI5vnH!jr{=87b}l^hDox`Ku6T%!4(?>Z^~L*8b&97iyW+y_?KqOnx?pAXF~u^B8=$
zZ;tNj>bjp}2QRXhw4=Lm>n&~Q3(|2V$i2{LR;$qc-t^hgB|^R~?1MVz1nOVXP*D9#
z<<zlcU;9TH7xmp(-UvrX2_1?gWl%;ZQ<r0z&9mhiv2T4pK!>d7!Xwn|!8;Y9O*TfY
z!8YHXcX{Re%bbXoEfle0<Qqc523f$Nsv@EPV&URg)y4*tQ>mN}C;?&bYS*&=OO|vM
z{SV`|H!~ibe%NEmmY~4_VqMelqmLx0V)qNa$<*DOF*0ZKbPzw~QK%w#>V(S-=2V{-
zHJKOfzKYd(B*(RslOd%193RnIyaOgdQGd#g!aL$?zy@<1M3IoO^(A1Sc<k&`Z{$w-
z6%x%!+#hXG2t=(7znwwc)vt3h+|wIx-7*#ZqWgM_eu0nU-gRNVL3D5NRz=82+OuEj
Q-xaynikb@ba+VSQ2T=c7<^TWy
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/resources/error-reporting.js
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2009 The Chromium Authors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *    * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+description("Tests generation of synthetic and real GL errors");
+
+var context = create3DContext();
+var program = loadStandardProgram(context);
+
+// Other tests in this directory like getActiveTest and
+// incorrect-context-object-behaviour already test the raising of many
+// synthetic GL errors. This test verifies the raising of certain
+// known real GL errors, and contains a few regression tests for bugs
+// discovered in the synthetic error generation and in the WebGL
+// implementation itself.
+
+shouldBe("context.getError()", "0");
+
+debug("Testing getActiveAttrib");
+// Synthetic OpenGL error
+shouldBeNull("context.getActiveAttrib(null, 2)");
+glErrorShouldBe(context, context.INVALID_OPERATION);
+// Error state should be clear by this point
+glErrorShouldBe(context, context.NO_ERROR);
+// Real OpenGL error
+shouldBeNull("context.getActiveAttrib(program, 2)");
+glErrorShouldBe(context, context.INVALID_VALUE);
+// Error state should be clear by this point
+glErrorShouldBe(context, context.NO_ERROR);
+
+debug("Testing getActiveUniform");
+// Synthetic OpenGL error
+shouldBeNull("context.getActiveUniform(null, 0)");
+glErrorShouldBe(context, context.INVALID_OPERATION);
+// Error state should be clear by this point
+glErrorShouldBe(context, context.NO_ERROR);
+// Real OpenGL error
+shouldBeNull("context.getActiveUniform(program, 50)");
+glErrorShouldBe(context, context.INVALID_VALUE);
+// Error state should be clear by this point
+glErrorShouldBe(context, context.NO_ERROR);
+
+debug("Testing attempts to manipulate the default framebuffer");
+shouldBeUndefined("context.bindFramebuffer(context.FRAMEBUFFER, 0)");
+glErrorShouldBe(context, context.NO_ERROR);
+shouldBeUndefined("context.framebufferRenderbuffer(context.FRAMEBUFFER, context.DEPTH_ATTACHMENT, context.RENDERBUFFER, 0)");
+// Synthetic OpenGL error
+glErrorShouldBe(context, context.INVALID_OPERATION);
+// Error state should be clear by this point
+glErrorShouldBe(context, context.NO_ERROR);
+shouldBeUndefined("context.framebufferTexture2D(context.FRAMEBUFFER, context.COLOR_ATTACHMENT0, context.TEXTURE_2D, 0, 0)");
+// Synthetic OpenGL error
+glErrorShouldBe(context, context.INVALID_OPERATION);
+// Error state should be clear by this point
+glErrorShouldBe(context, context.NO_ERROR);
+
+successfullyParsed = true;
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/resources/floatUniformShader.vert
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2009 The Chromium Authors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *    * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+uniform float fval;
+uniform vec2 fval2;
+uniform vec3 fval3;
+uniform vec4 fval4;
+
+void main()
+{
+    float sum = fval
+            + fval2[0] + fval2[1]
+            + fval3[0] + fval3[1] + fval3[2]
+            + fval4[0] + fval4[1] + fval4[2] + fval4[3];
+    gl_Position = vec4(sum, 0.0, 0.0, 1.0);
+}
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/resources/fragmentShader.frag
@@ -0,0 +1,31 @@
+/*
+Copyright (C) 2009 Apple Computer, Inc.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+varying vec3 v_normal;
+
+void main()
+{
+    gl_FragColor = vec4(v_normal/2.0+vec3(0.5), 1);
+}
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/resources/get-active-test.js
@@ -0,0 +1,84 @@
+/*
+Copyright (C) 2009 Apple Computer, Inc.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+description("Test of getActiveAttrib and getActiveUniform");
+
+var context = create3DContext();
+var context2 = create3DContext();
+var program = loadStandardProgram(context);
+var program2 = loadStandardProgram(context2);
+
+glErrorShouldBe(context, context.NO_ERROR);
+shouldBe("context.getActiveUniform(program, 0).name", "'u_modelViewProjMatrix'");
+shouldBe("context.getActiveUniform(program, 0).type", "context.FLOAT_MAT4");
+shouldBe("context.getActiveUniform(program, 0).size", "1");
+shouldBe("context.getActiveUniform(program, 1)", "null");
+glErrorShouldBe(context, context.INVALID_VALUE);
+shouldBe("context.getActiveUniform(program, -1)", "null");
+glErrorShouldBe(context, context.INVALID_VALUE);
+shouldBe("context.getActiveUniform(null, 0)", "null");
+glErrorShouldBe(context, context.INVALID_VALUE);
+
+// we don't know the order the attribs will appear.
+var info = [
+  context.getActiveAttrib(program, 0),
+  context.getActiveAttrib(program, 1)
+];
+
+var expected = [
+  { name: 'a_normal', type: context.FLOAT_VEC3, size: 1 },
+  { name: 'a_vertex', type: context.FLOAT_VEC4, size: 1 }
+];
+
+if (info[0].name != expected[0].name) {
+  t = info[0];
+  info[0] = info[1];
+  info[1] = t;
+}
+
+for (var ii = 0; ii < info.length; ++ii) {
+  shouldBe("info[ii].name", "expected[ii].name");
+  shouldBe("info[ii].type", "expected[ii].type");
+  shouldBe("info[ii].size", "expected[ii].size");
+}
+shouldBe("context.getActiveAttrib(program, 2)", "null");
+glErrorShouldBe(context, context.INVALID_VALUE);
+shouldBe("context.getActiveAttrib(program, -1)", "null");
+glErrorShouldBe(context, context.INVALID_VALUE);
+shouldBe("context.getActiveAttrib(null, 0)", "null");
+glErrorShouldBe(context, context.INVALID_VALUE);
+
+shouldBe("context2.getActiveAttrib(program, 0)", "null");
+glErrorShouldBe(context2, context2.INVALID_VALUE);
+shouldBe("context2.getActiveUniform(program, 0)", "null");
+glErrorShouldBe(context2, context2.INVALID_VALUE);
+
+context.deleteProgram(program);
+shouldBe("context.getActiveUniform(program, 0)", "null");
+glErrorShouldBe(context, context.INVALID_VALUE);
+shouldBe("context.getActiveAttrib(program, 0)", "null");
+glErrorShouldBe(context, context.INVALID_VALUE);
+
+successfullyParsed = true;
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/resources/gl-object-get-calls.js
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2009 The Chromium Authors. All rights reserved.
+ * Copyright (C) 2009 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *    * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+description("Test of get calls against GL objects like getBufferParameter, etc.");
+
+var gl = create3DContext();
+
+var standardVert = loadStandardVertexShader(gl);
+var standardFrag = loadStandardFragmentShader(gl);
+var standardProgram = gl.createProgram();
+gl.attachShader(standardProgram, standardVert);
+gl.attachShader(standardProgram, standardFrag);
+gl.linkProgram(standardProgram);
+
+// Test getBufferParameter
+var buffer = gl.createBuffer();
+gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+gl.bufferData(gl.ARRAY_BUFFER, 16, gl.DYNAMIC_DRAW);
+shouldBe('gl.getBufferParameter(gl.ARRAY_BUFFER, gl.BUFFER_SIZE)', '16');
+shouldBe('gl.getBufferParameter(gl.ARRAY_BUFFER, gl.BUFFER_USAGE)', 'gl.DYNAMIC_DRAW');
+
+// Test getFramebufferAttachmentParameter
+var texture = gl.createTexture();
+gl.bindTexture(gl.TEXTURE_2D, texture);
+gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 2, 2, 0, gl.RGBA, gl.UNSIGNED_BYTE,
+              new WebGLUnsignedByteArray([0, 0, 0, 255,
+                                          255, 255, 255, 255,
+                                          255, 255, 255, 255,
+                                          0, 0, 0, 255]));
+gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+gl.bindTexture(gl.TEXTURE_2D, null);
+var framebuffer = gl.createFramebuffer();
+gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
+gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
+var renderbuffer = gl.createRenderbuffer();
+glErrorShouldBe(gl, gl.NO_ERROR);
+gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer);
+glErrorShouldBe(gl, gl.NO_ERROR);
+gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT, 2, 2);
+glErrorShouldBe(gl, gl.NO_ERROR);
+gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, renderbuffer);
+// FIXME: on some machines (in particular the WebKit commit bots) the
+// framebuffer status is FRAMEBUFFER_UNSUPPORTED; more investigation
+// is needed why this is the case, because the FBO allocated
+// internally by the WebKit implementation has almost identical
+// parameters to this one. See https://bugs.webkit.org/show_bug.cgi?id=31843.
+//shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)', 'gl.TEXTURE');
+shouldBeNonNull('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)');
+shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL)', '0');
+shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE)', '0');
+
+shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)', 'gl.RENDERBUFFER');
+shouldBeNonNull('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)');
+
+// Test getProgramParameter
+shouldBe('gl.getProgramParameter(standardProgram, gl.DELETE_STATUS)', 'false');
+shouldBe('gl.getProgramParameter(standardProgram, gl.LINK_STATUS)', 'true');
+shouldBe('typeof gl.getProgramParameter(standardProgram, gl.VALIDATE_STATUS)', '"boolean"');
+shouldBe('typeof gl.getProgramParameter(standardProgram, gl.INFO_LOG_LENGTH)', '"number"');
+shouldBe('gl.getProgramParameter(standardProgram, gl.ATTACHED_SHADERS)', '2');
+shouldBe('gl.getProgramParameter(standardProgram, gl.ACTIVE_ATTRIBUTES)', '2');
+shouldBeNonZero('gl.getProgramParameter(standardProgram, gl.ACTIVE_ATTRIBUTE_MAX_LENGTH)');
+shouldBe('gl.getProgramParameter(standardProgram, gl.ACTIVE_UNIFORMS)', '1');
+shouldBeNonZero('gl.getProgramParameter(standardProgram, gl.ACTIVE_UNIFORM_MAX_LENGTH)');
+
+// Test getRenderbufferParameter
+shouldBe('gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_WIDTH)', '2');
+shouldBe('gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_HEIGHT)', '2');
+// Note: we can't test the actual value of the internal format since
+// the implementation is allowed to change it.
+shouldBeNonZero('gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_INTERNAL_FORMAT)');
+shouldBeNonZero('gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_DEPTH_SIZE)');
+var colorbuffer = gl.createRenderbuffer();
+glErrorShouldBe(gl, gl.NO_ERROR);
+gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer);
+glErrorShouldBe(gl, gl.NO_ERROR);
+gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 2, 2);
+shouldBeNonZero('gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_RED_SIZE)');
+shouldBeNonZero('gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_GREEN_SIZE)');
+shouldBeNonZero('gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_BLUE_SIZE)');
+shouldBeNonZero('gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_ALPHA_SIZE)');
+
+// Test getShaderParameter
+shouldBe('gl.getShaderParameter(standardVert, gl.SHADER_TYPE)', 'gl.VERTEX_SHADER');
+shouldBe('gl.getShaderParameter(standardVert, gl.DELETE_STATUS)', 'false');
+shouldBe('gl.getShaderParameter(standardVert, gl.COMPILE_STATUS)', 'true');
+shouldBe('typeof gl.getShaderParameter(standardVert, gl.INFO_LOG_LENGTH)', '"number"');
+shouldBeNonZero('gl.getShaderParameter(standardVert, gl.SHADER_SOURCE_LENGTH)');
+
+// Test getTexParameter
+gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
+gl.bindTexture(gl.TEXTURE_2D, texture);
+gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+shouldBe('gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER)', 'gl.NEAREST');
+shouldBe('gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER)', 'gl.NEAREST');
+shouldBe('gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S)', 'gl.CLAMP_TO_EDGE');
+shouldBe('gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T)', 'gl.CLAMP_TO_EDGE');
+
+// Test getUniform with all variants of data types
+// Boolean uniform variables
+var boolProgram = loadProgram(gl, "resources/boolUniformShader.vert", "resources/noopUniformShader.frag");
+shouldBe('gl.getProgramParameter(boolProgram, gl.LINK_STATUS)', 'true');
+var bvalLoc = gl.getUniformLocation(boolProgram, "bval");
+var bval2Loc = gl.getUniformLocation(boolProgram, "bval2");
+var bval3Loc = gl.getUniformLocation(boolProgram, "bval3");
+var bval4Loc = gl.getUniformLocation(boolProgram, "bval4");
+gl.useProgram(boolProgram);
+gl.uniform1i(bvalLoc, 1);
+gl.uniform2i(bval2Loc, 1, 0);
+gl.uniform3i(bval3Loc, 1, 0, 1);
+gl.uniform4i(bval4Loc, 1, 0, 1, 0);
+glErrorShouldBe(gl, gl.NO_ERROR);
+shouldBe('gl.getUniform(boolProgram, bvalLoc)', 'true');
+shouldBe('gl.getUniform(boolProgram, bval2Loc)', '[1, 0]');
+shouldBe('gl.getUniform(boolProgram, bval3Loc)', '[1, 0, 1]');
+shouldBe('gl.getUniform(boolProgram, bval4Loc)', '[1, 0, 1, 0]');
+// Integer uniform variables
+var intProgram = loadProgram(gl, "resources/intUniformShader.vert", "resources/noopUniformShader.frag");
+shouldBe('gl.getProgramParameter(intProgram, gl.LINK_STATUS)', 'true');
+var ivalLoc = gl.getUniformLocation(intProgram, "ival");
+var ival2Loc = gl.getUniformLocation(intProgram, "ival2");
+var ival3Loc = gl.getUniformLocation(intProgram, "ival3");
+var ival4Loc = gl.getUniformLocation(intProgram, "ival4");
+gl.useProgram(intProgram);
+gl.uniform1i(ivalLoc, 1);
+gl.uniform2i(ival2Loc, 2, 3);
+gl.uniform3i(ival3Loc, 4, 5, 6);
+gl.uniform4i(ival4Loc, 7, 8, 9, 10);
+glErrorShouldBe(gl, gl.NO_ERROR);
+shouldBe('gl.getUniform(intProgram, ivalLoc)', '1');
+shouldBe('gl.getUniform(intProgram, ival2Loc)', '[2, 3]');
+shouldBe('gl.getUniform(intProgram, ival3Loc)', '[4, 5, 6]');
+shouldBe('gl.getUniform(intProgram, ival4Loc)', '[7, 8, 9, 10]');
+// Float uniform variables
+var floatProgram = loadProgram(gl, "resources/floatUniformShader.vert", "resources/noopUniformShader.frag");
+shouldBe('gl.getProgramParameter(floatProgram, gl.LINK_STATUS)', 'true');
+var fvalLoc = gl.getUniformLocation(floatProgram, "fval");
+var fval2Loc = gl.getUniformLocation(floatProgram, "fval2");
+var fval3Loc = gl.getUniformLocation(floatProgram, "fval3");
+var fval4Loc = gl.getUniformLocation(floatProgram, "fval4");
+gl.useProgram(floatProgram);
+gl.uniform1f(fvalLoc, 11);
+gl.uniform2f(fval2Loc, 12, 13);
+gl.uniform3f(fval3Loc, 14, 15, 16);
+gl.uniform4f(fval4Loc, 17, 18, 19, 20);
+glErrorShouldBe(gl, gl.NO_ERROR);
+shouldBe('gl.getUniform(floatProgram, fvalLoc)', '11');
+shouldBe('gl.getUniform(floatProgram, fval2Loc)', '[12, 13]');
+shouldBe('gl.getUniform(floatProgram, fval3Loc)', '[14, 15, 16]');
+shouldBe('gl.getUniform(floatProgram, fval4Loc)', '[17, 18, 19, 20]');
+// Matrix uniform variables
+var matProgram = loadProgram(gl, "resources/matUniformShader.vert", "resources/noopUniformShader.frag");
+shouldBe('gl.getProgramParameter(matProgram, gl.LINK_STATUS)', 'true');
+var mval2Loc = gl.getUniformLocation(matProgram, "mval2");
+var mval3Loc = gl.getUniformLocation(matProgram, "mval3");
+var mval4Loc = gl.getUniformLocation(matProgram, "mval4");
+gl.useProgram(matProgram);
+gl.uniformMatrix2fv(mval2Loc, false, [1, 2, 3, 4]);
+gl.uniformMatrix3fv(mval3Loc, false, [5, 6, 7, 8, 9, 10, 11, 12, 13]);
+gl.uniformMatrix4fv(mval4Loc, false, [14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]);
+glErrorShouldBe(gl, gl.NO_ERROR);
+shouldBe('gl.getUniform(matProgram, mval2Loc)', '[1, 2, 3, 4]');
+shouldBe('gl.getUniform(matProgram, mval3Loc)', '[5, 6, 7, 8, 9, 10, 11, 12, 13]');
+shouldBe('gl.getUniform(matProgram, mval4Loc)', '[14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]');
+
+// Test getVertexAttrib
+var array = new WebGLFloatArray([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
+gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+gl.bufferData(gl.ARRAY_BUFFER, array, gl.DYNAMIC_DRAW);
+// Vertex attribute 0 is special in that it has no current state, so
+// fetching GL_CURRENT_VERTEX_ATTRIB generates an error. Use attribute
+// 1 for these tests instead.
+gl.enableVertexAttribArray(1);
+gl.vertexAttribPointer(1, 4, gl.FLOAT, false, 0, 0);
+shouldBeNonNull('gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING)');
+shouldBe('gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_ENABLED)', 'true');
+shouldBe('gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_SIZE)', '4');
+shouldBe('(gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_STRIDE) == 0) || (gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_STRIDE) == 4 * gl.sizeInBytes(gl.FLOAT))', 'true');
+shouldBe('gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_TYPE)', 'gl.FLOAT');
+shouldBe('gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_NORMALIZED)', 'false');
+gl.disableVertexAttribArray(1);
+shouldBe('gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_ENABLED)', 'false');
+gl.vertexAttrib4f(1, 5, 6, 7, 8);
+shouldBe('gl.getVertexAttrib(1, gl.CURRENT_VERTEX_ATTRIB)', '[5, 6, 7, 8]');
+glErrorShouldBe(gl, gl.NO_ERROR);
+
+successfullyParsed = true;
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/resources/incorrect-context-object-behaviour.js
@@ -0,0 +1,67 @@
+/*
+Copyright (C) 2009 Apple Computer, Inc.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+description("Tests calling WebGL APIs with objects from other contexts");
+
+var contextA = create3DContext();
+var contextB = create3DContext();
+var programA = loadStandardProgram(contextA);
+var programB = loadStandardProgram(contextB);
+var shaderA = loadStandardVertexShader(contextA);
+var shaderB = loadStandardVertexShader(contextB);
+var textureA = contextA.createTexture();
+var textureB = contextB.createTexture();
+var frameBufferA = contextA.createFramebuffer();
+var frameBufferB = contextB.createFramebuffer();
+var renderBufferA = contextA.createRenderbuffer();
+var renderBufferB = contextB.createRenderbuffer();
+var locationA = contextA.getUniformLocation(programA, 'u_modelViewProjMatrix');
+var locationB = contextB.getUniformLocation(programB, 'u_modelViewProjMatrix');
+
+
+shouldGenerateGLError(contextA, contextA.INVALID_OPERATION, "contextA.compileShader(shaderB)");
+shouldGenerateGLError(contextA, contextA.INVALID_OPERATION, "contextA.linkProgram(programB)");
+shouldGenerateGLError(contextA, contextA.INVALID_OPERATION, "contextA.attachShader(programA, shaderB)");
+shouldGenerateGLError(contextA, contextA.INVALID_OPERATION, "contextA.attachShader(programB, shaderA)");
+shouldGenerateGLError(contextA, contextA.INVALID_OPERATION, "contextA.attachShader(programB, shaderB)");
+shouldGenerateGLError(contextA, contextA.INVALID_OPERATION, "contextA.detachShader(programA, shaderB)");
+shouldGenerateGLError(contextA, contextA.INVALID_OPERATION, "contextA.detachShader(programB, shaderA)");
+shouldGenerateGLError(contextA, contextA.INVALID_OPERATION, "contextA.detachShader(programB, shaderB)");
+shouldGenerateGLError(contextA, contextA.INVALID_OPERATION, "contextA.shaderSource(shaderB, 'foo')");
+shouldGenerateGLError(contextA, contextA.INVALID_OPERATION, "contextA.bindAttribLocation(programB, 0, 'foo')");
+shouldGenerateGLError(contextA, contextA.INVALID_OPERATION, "contextA.bindFramebuffer(contextA.FRAMEBUFFER, frameBufferB)");
+shouldGenerateGLError(contextA, contextA.INVALID_OPERATION, "contextA.bindRenderbuffer(contextA.RENDERBUFFER, renderBufferB)");
+shouldGenerateGLError(contextA, contextA.INVALID_OPERATION, "contextA.bindTexture(contextA.TEXTURE_2D, textureB)");
+shouldGenerateGLError(contextA, contextA.INVALID_OPERATION, "contextA.framebufferRenderbuffer(contextA.FRAMEBUFFER, contextA.DEPTH_ATTACHMENT, contextA.RENDERBUFFER, renderBufferB)");
+shouldGenerateGLError(contextA, contextA.INVALID_OPERATION, "contextA.framebufferTexture2D(contextA.FRAMEBUFFER, contextA.COLOR_ATTACHMENT0, contextA.TEXTURE_2D, textureB, 0)");
+shouldGenerateGLError(contextA, contextA.INVALID_OPERATION, "contextA.getProgramParameter(programB, 0)");
+shouldGenerateGLError(contextA, contextA.INVALID_OPERATION, "contextA.getProgramInfoLog(programB, 0)");
+shouldGenerateGLError(contextA, contextA.INVALID_OPERATION, "contextA.getShaderParameter(shaderB, 0)");
+shouldGenerateGLError(contextA, contextA.INVALID_OPERATION, "contextA.getShaderInfoLog(shaderB, 0)");
+shouldGenerateGLError(contextA, contextA.INVALID_OPERATION, "contextA.getShaderSource(shaderB)");
+shouldGenerateGLError(contextA, contextA.INVALID_OPERATION, "contextA.getUniform(programB, locationA)");
+shouldGenerateGLError(contextA, contextA.INVALID_OPERATION, "contextA.getUniformLocation(programB, 'u_modelViewProjMatrix')");
+
+successfullyParsed = true;
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/resources/index-validation.js
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2009 The Chromium Authors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *    * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+description("Tests that index validation verifies the correct number of indices");
+
+var gl = create3DContext();
+var program = loadStandardProgram(gl);
+
+// 3 vertices => 1 triangle, interleaved data
+var data = new WebGLFloatArray([0, 0, 0, 1,
+                                0, 0, 1,
+                                1, 0, 0, 1,
+                                0, 0, 1,
+                                1, 1, 1, 1,
+                                0, 0, 1]);
+var indices = new WebGLUnsignedShortArray([0, 1, 2]);
+
+var buffer = gl.createBuffer();
+gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
+var elements = gl.createBuffer();
+gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elements);
+gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
+gl.useProgram(program);
+var vertexLoc = gl.getAttribLocation(program, "a_vertex");
+var normalLoc = gl.getAttribLocation(program, "a_normal");
+gl.vertexAttribPointer(vertexLoc, 4, gl.FLOAT, false, 7 * gl.sizeInBytes(gl.FLOAT), 0);
+gl.enableVertexAttribArray(vertexLoc);
+gl.vertexAttribPointer(normalLoc, 3, gl.FLOAT, false, 7 * gl.sizeInBytes(gl.FLOAT), 3 * gl.sizeInBytes(gl.FLOAT));
+gl.enableVertexAttribArray(normalLoc);
+shouldBe('gl.getError()', '0');
+shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_SHORT, 0)');
+shouldBe('gl.getError()', '0');
+
+successfullyParsed = true;
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/resources/intUniformShader.vert
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2009 The Chromium Authors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *    * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+uniform int ival;
+uniform ivec2 ival2;
+uniform ivec3 ival3;
+uniform ivec4 ival4;
+
+void main()
+{
+    int sum = ival
+            + ival2[0] + ival2[1]
+            + ival3[0] + ival3[1] + ival3[2]
+            + ival4[0] + ival4[1] + ival4[2] + ival4[3];
+    gl_Position = vec4(sum, 0.0, 0.0, 1.0);
+}
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/resources/matUniformShader.vert
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2009 The Chromium Authors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *    * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+uniform mat2 mval2;
+uniform mat3 mval3;
+uniform mat4 mval4;
+
+void main()
+{
+    gl_Position = vec4(mval2 * vec2(1.0, 2.0), 0.0, 0.0)
+            + vec4(mval3 * vec3(1.0, 2.0, 3.0), 0.0)
+            + mval4 * vec4(1.0, 2.0, 3.0, 4.0);
+}
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/resources/noopUniformShader.frag
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2009 The Chromium Authors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *    * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+void main()
+{
+    gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
+}
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/resources/null-object-behaviour.js
@@ -0,0 +1,56 @@
+/*
+Copyright (C) 2009 Apple Computer, Inc.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+description("Tests calling WebGL APIs without providing the necessary objects");
+
+var context = create3DContext();
+var program = loadStandardProgram(context);
+var shader = loadStandardVertexShader(context);
+
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.compileShader()");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.linkProgram()");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.attachShader()");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.attachShader(program, undefined)");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.attachShader(undefined, shader)");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.detachShader(program, undefined)");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.detachShader(undefined, shader)");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.shaderSource()");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.shaderSource(undefined, 'foo')");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.bindAttribLocation(undefined, 0, 'foo')");
+shouldGenerateGLError(context, context.NO_ERROR, "context.bindBuffer(context.ARRAY_BUFFER, 0)");
+shouldGenerateGLError(context, context.NO_ERROR, "context.bindFramebuffer(context.FRAMEBUFFER, 0)");
+shouldGenerateGLError(context, context.NO_ERROR, "context.bindRenderbuffer(context.RENDERBUFFER, 0)");
+shouldGenerateGLError(context, context.NO_ERROR, "context.bindTexture(context.TEXTURE_2D, 0)");
+shouldGenerateGLError(context, context.INVALID_OPERATION, "context.framebufferRenderbuffer(context.FRAMEBUFFER, context.DEPTH_ATTACHMENT, context.RENDERBUFFER, 0)");
+shouldGenerateGLError(context, context.INVALID_OPERATION, "context.framebufferTexture2D(context.FRAMEBUFFER, context.COLOR_ATTACHMENT0, context.TEXTURE_2D, 0, 0)");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.getProgramParameter(undefined, 0)");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.getProgramInfoLog(undefined, 0)");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.getShaderParameter(undefined, 0)");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.getShaderInfoLog(undefined, 0)");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.getShaderSource(undefined)");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.getUniform(undefined, 0)");
+shouldGenerateGLError(context, context.INVALID_VALUE, "context.getUniformLocation(undefined, 'foo')");
+
+successfullyParsed = true;
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/resources/structUniformShader.vert
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2009 The Chromium Authors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *    * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+attribute vec4 a_vertex;
+attribute vec3 a_normal;
+
+uniform mat4 u_modelViewProjMatrix;
+
+struct MyStruct
+{
+  int x;
+  int y;
+};
+
+uniform MyStruct u_struct;
+uniform float u_array[4];
+
+varying vec3 v_normal;
+
+void main()
+{ 
+    v_normal = a_normal;
+    gl_Position = u_modelViewProjMatrix * a_vertex +
+        vec4(u_struct.x, u_struct.y, 0, 1) +
+        vec4(u_array[0], u_array[1], u_array[2], u_array[3]);
+}
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/resources/testrunner.js
@@ -0,0 +1,101 @@
+/*
+ * testrunner.js: simple object-oriented test runner for WebGL.
+ *
+ * Copyright (c) 2010 Cedric Vivier <cedricv@neonux.com>.
+ * Use of this source code is governed by a MIT license.
+ *
+ * Example usage:
+ *
+ * var testsuite = {
+ *     "enable an invalid capability should generate INVALID_VALUE" : function () {
+ *         this.setup = function () {
+ *             gl.enable(0x666);
+ *         };
+ *         this.expects = gl.INVALID_VALUE;
+ *     },
+ *     "not using correct parameter type should throw a TypeError" : function () {
+ *         this.setup = function () {
+ *             gl.enable("not a number");
+ *         };
+ *         this.expects = "TypeError";
+ *     },
+ *     "check that correct image is drawn" : function () {
+ *         this.setup = function () {
+ *             //draw something
+ *         };
+ *         this.expects = function () {
+ *             //read pixels
+ *             //return true if pixels are okay, false otherwise
+ *         };
+ *     }
+ * };
+ * runTestsuite(testsuite);
+ *
+ */
+
+function runTestsuite(testsuite) {
+	var testname;
+	function testFatal(message) {
+		testFailed("FATAL: " + testname + " :: " + message);
+	}
+
+	var n = 0;
+	for (testname in testsuite) {
+try {
+		if (testname === "setup" || testname === "teardown") //special functions
+			continue;
+
+		var test = new testsuite[testname]();
+
+		if (n > 0 && typeof(testsuite.teardown) === "function")
+			testsuite.teardown();  // teardown code run _after_ EACH test
+		if (typeof(testsuite.setup) === "function")
+			testsuite.setup(); // setup code run _before_ EACH test
+
+		n++;
+
+		if (typeof(test.setup) !== "function") {
+			testFatal("`setup' is not a function.");
+			continue;
+		}
+		test.setup();
+
+		var err = gl.getError();
+		switch (typeof(test.expects)) {
+		case "number": // expect a GL error
+			if (err !== test.expects) {
+				testFailed(testname + " :: got GL error `" + getGLErrorAsString(gl, err) + "' instead of expected `" + getGLErrorAsString(gl, test.expects) + "'.");
+				continue;
+			}
+			break;
+		case "string": // expect an exception starting with given string
+				testFailed(testname + " :: expected a `" + test.expects + "' exception but no exception has been caught.");
+				continue;
+		case "function": // expect no error and the function to return true
+			if (err !== gl.NO_ERROR) {
+				testFailed(testname + " :: got GL error `" + getGLErrorAsString(gl, err) + "' when none was expected.");
+				continue;
+			}
+			if (test.expects() !== true) {
+				testFailed(testname);
+				continue;
+			}
+			break;
+		default:
+			testFatal("`expects' is neither a function or a number (GL error) but `" + typeof(test.expects) + "'.");
+			continue;
+		}
+		testPassed(testname);
+} catch (e) {
+	if (test && typeof(test.expects) === "string") { // an exception was expected
+		if (e.toString().indexOf(test.expects) === 0) // got expected exception
+			testPassed(testname);
+		else // got another exception
+			testFailed(testname + " :: caught exception `" + e + "' when a `" + test.expects + "' exception was expected.");
+		continue;
+	}
+	testFailed(testname + " :: caught unexpected exception `" + e + "'.");
+}
+	}
+}
+
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/resources/uniform-location.js
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2009 The Chromium Authors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *    * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+description("Tests the WebGLUniformLocation API");
+
+var contextA = create3DContext();
+var contextB = create3DContext();
+var programA1 = loadStandardProgram(contextA);
+var programA2 = loadStandardProgram(contextA);
+var programB = loadStandardProgram(contextB);
+var programS = loadProgram(contextA, "resources/structUniformShader.vert", "resources/fragmentShader.frag");
+var programV = loadProgram(contextA, "resources/floatUniformShader.vert", "resources/noopUniformShader.frag");
+var locationA = contextA.getUniformLocation(programA1, 'u_modelViewProjMatrix');
+var locationB = contextB.getUniformLocation(programB, 'u_modelViewProjMatrix');
+var locationSx = contextA.getUniformLocation(programS, "u_struct.x");
+var locationArray0 = contextA.getUniformLocation(programS, "u_array[0]");
+var locationVec4 = contextA.getUniformLocation(programV, "fval4");
+
+var vec = [1, 2, 3, 4];
+var mat = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
+
+shouldGenerateGLError(contextA, contextA.NO_ERROR, "contextA.useProgram(programA2)");
+shouldGenerateGLError(contextA, contextA.INVALID_OPERATION, "contextA.uniformMatrix4fv(locationA, false, mat)");
+shouldGenerateGLError(contextA, contextA.NO_ERROR, "contextA.useProgram(programA1)");
+shouldGenerateGLError(contextA, contextA.NO_ERROR, "contextA.uniformMatrix4fv(locationA, false, mat)");
+shouldGenerateGLError(contextA, contextA.INVALID_VALUE, "contextA.uniformMatrix4fv(0, false, mat)");
+
+shouldGenerateGLError(contextA, contextA.NO_ERROR, "contextA.useProgram(programS)");
+shouldGenerateGLError(contextA, contextA.NO_ERROR, "contextA.uniform1i(locationSx, 3)");
+shouldGenerateGLError(contextA, contextA.NO_ERROR, "contextA.uniform1f(locationArray0, 4.0)");
+
+shouldBe("contextA.getUniform(programS, locationSx)", "3");
+shouldBe("contextA.getUniform(programS, locationArray0)", "4.0");
+
+shouldGenerateGLError(contextA, contextA.NO_ERROR, "contextA.useProgram(programV)");
+shouldGenerateGLError(contextA, contextA.NO_ERROR, "contextA.uniform4fv(locationVec4, vec)");
+shouldBe("contextA.getUniform(programV, locationVec4)", "vec");
+
+shouldBeNull("contextA.getUniformLocation(programV, \"IDontExist\")");
+shouldGenerateGLError(contextA, contextA.NO_ERROR, "contextA.linkProgram(programA1)");
+// After linking all boxes are bad.
+shouldGenerateGLError(contextA, contextA.INVALID_OPERATION, "contextA.uniformMatrix4fv(locationA, false, mat)");
+
+
+successfullyParsed = true;
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/resources/utils3d.js
@@ -0,0 +1,592 @@
+/*
+Copyright (C) 2009 Apple Computer, Inc.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+//
+// initWebGL
+//
+// Initialize the Canvas element with the passed name as a WebGL object and return the
+// WebGLRenderingContext. 
+//
+// Load shaders with the passed names and create a program with them. Return this program 
+// in the 'program' property of the returned context.
+//
+// For each string in the passed attribs array, bind an attrib with that name at that index.
+// Once the attribs are bound, link the program and then use it.
+//
+// Set the clear color to the passed array (4 values) and set the clear depth to the passed value.
+// Enable depth testing and blending with a blend func of (SRC_ALPHA, ONE_MINUS_SRC_ALPHA)
+//
+function initWebGL(canvasName, vshader, fshader, attribs, clearColor, clearDepth)
+{
+    var canvas = document.getElementById(canvasName);
+    var gl = create3DContext(canvas);
+    if (!gl) {
+        alert("No WebGL context found");
+        return null;
+    }
+
+    // create our shaders
+    var vertexShader = loadShaderFromScript(gl, vshader);
+    var fragmentShader = loadShaderFromScript(gl, fshader);
+
+    if (!vertexShader || !fragmentShader)
+        return null;
+
+    // Create the program object
+    gl.program = gl.createProgram();
+
+    if (!gl.program)
+        return null;
+
+    // Attach our two shaders to the program
+    gl.attachShader (gl.program, vertexShader);
+    gl.attachShader (gl.program, fragmentShader);
+
+    // Bind attributes
+    for (var i in attribs)
+        gl.bindAttribLocation (gl.program, i, attribs[i]);
+
+    // Link the program
+    gl.linkProgram(gl.program);
+
+    // Check the link status
+    var linked = gl.getProgramParameter(gl.program, gl.LINK_STATUS);
+    if (!linked) {
+        // something went wrong with the link
+        var error = gl.getProgramInfoLog (gl.program);
+        console.log("Error in program linking:"+error);
+
+        gl.deleteProgram(gl.program);
+        gl.deleteProgram(fragmentShader);
+        gl.deleteProgram(vertexShader);
+
+        return null;
+    }
+
+    gl.useProgram(gl.program);
+
+    gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
+    gl.clearDepth(clearDepth);
+
+    gl.enable(gl.DEPTH_TEST);
+    gl.enable(gl.BLEND);
+    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
+
+    return gl;
+}
+
+//
+// getShaderSource
+//
+// Load the source from the passed shader file.
+//
+function getShaderSource(file)
+{
+    var xhr = new XMLHttpRequest();
+    xhr.open("GET", file, false);
+    xhr.send();
+    return xhr.responseText;
+}
+
+//
+// loadShader
+//
+// 'shader' is either the id of a <script> element containing the shader source string
+// or the URL of a file containing the shader source. Load this shader and return the 
+// WebGLShader object corresponding to it.
+//
+function loadShader(ctx, shaderId, shaderType, isFile)
+{
+    var shaderSource = "";
+    
+    if (isFile)
+        shaderSource = getShaderSource(shaderId);
+    else {
+        var shaderScript = document.getElementById(shaderId);
+        if (!shaderScript) {
+            console.log("*** Error: shader script '"+shaderId+"' not found");
+            return null;
+        }
+        
+        // this overrides the passed in shader type
+        if (shaderScript.type == "x-shader/x-vertex")
+            shaderType = ctx.VERTEX_SHADER;
+        else if (shaderScript.type == "x-shader/x-fragment")
+            shaderType = ctx.FRAGMENT_SHADER;
+        else if (shaderType != ctx.VERTEX_SHADER && shaderType != ctx.FRAGMENT_SHADER) {
+            console.log("*** Error: unknown shader type");       
+            return null;
+        }
+        
+        shaderSource = shaderScript.text;
+    }
+
+    // Create the shader object
+    var shader = ctx.createShader(shaderType);
+    if (shader == null) {
+        console.log("*** Error: unable to create shader '"+shaderId+"'");       
+        return null;
+    }
+
+    // Load the shader source
+    ctx.shaderSource(shader, shaderSource);
+    
+    // Compile the shader
+    ctx.compileShader(shader);
+
+    // Check the compile status
+    var compiled = ctx.getShaderParameter(shader, ctx.COMPILE_STATUS);
+    if (!compiled) {
+        // Something went wrong during compilation; get the error
+        var error = ctx.getShaderInfoLog(shader);
+        console.log("*** Error compiling shader '"+shader+"':"+error);
+        ctx.deleteShader(shader);
+        return null;
+    }
+
+    return shader;
+}
+
+function loadShaderFromFile(ctx, file, type)
+{
+    return loadShader(ctx, file, type, true);
+}
+
+function loadShaderFromScript(ctx, script)
+{
+    return loadShader(ctx, script, 0, false);
+}
+
+// 
+// makeBox
+//
+// Create a box with vertices, normals and texCoords. Create VBOs for each as well as the index array.
+// Return an object with the following properties:
+//
+//  normalObject        WebGLBuffer object for normals
+//  texCoordObject      WebGLBuffer object for texCoords
+//  vertexObject        WebGLBuffer object for vertices
+//  indexObject         WebGLBuffer object for indices
+//  numIndices          The number of indices in the indexObject
+// 
+function makeBox(ctx)
+{
+    // box
+    //    v6----- v5
+    //   /|      /|
+    //  v1------v0|
+    //  | |     | |
+    //  | |v7---|-|v4
+    //  |/      |/
+    //  v2------v3
+    //
+    // vertex coords array
+    var vertices = new WebGLFloatArray(
+        [  1, 1, 1,  -1, 1, 1,  -1,-1, 1,   1,-1, 1,    // v0-v1-v2-v3 front
+           1, 1, 1,   1,-1, 1,   1,-1,-1,   1, 1,-1,    // v0-v3-v4-v5 right
+           1, 1, 1,   1, 1,-1,  -1, 1,-1,  -1, 1, 1,    // v0-v5-v6-v1 top
+          -1, 1, 1,  -1, 1,-1,  -1,-1,-1,  -1,-1, 1,    // v1-v6-v7-v2 left
+          -1,-1,-1,   1,-1,-1,   1,-1, 1,  -1,-1, 1,    // v7-v4-v3-v2 bottom
+           1,-1,-1,  -1,-1,-1,  -1, 1,-1,   1, 1,-1 ]   // v4-v7-v6-v5 back
+    );
+
+    // normal array
+    var normals = new WebGLFloatArray(
+        [  0, 0, 1,   0, 0, 1,   0, 0, 1,   0, 0, 1,     // v0-v1-v2-v3 front
+           1, 0, 0,   1, 0, 0,   1, 0, 0,   1, 0, 0,     // v0-v3-v4-v5 right
+           0, 1, 0,   0, 1, 0,   0, 1, 0,   0, 1, 0,     // v0-v5-v6-v1 top
+          -1, 0, 0,  -1, 0, 0,  -1, 0, 0,  -1, 0, 0,     // v1-v6-v7-v2 left
+           0,-1, 0,   0,-1, 0,   0,-1, 0,   0,-1, 0,     // v7-v4-v3-v2 bottom
+           0, 0,-1,   0, 0,-1,   0, 0,-1,   0, 0,-1 ]    // v4-v7-v6-v5 back
+       );
+
+
+    // texCoord array
+    var texCoords = new WebGLFloatArray(
+        [  1, 1,   0, 1,   0, 0,   1, 0,    // v0-v1-v2-v3 front
+           0, 1,   0, 0,   1, 0,   1, 1,    // v0-v3-v4-v5 right
+           1, 0,   1, 1,   0, 1,   0, 0,    // v0-v5-v6-v1 top
+           1, 1,   0, 1,   0, 0,   1, 0,    // v1-v6-v7-v2 left
+           0, 0,   1, 0,   1, 1,   0, 1,    // v7-v4-v3-v2 bottom
+           0, 0,   1, 0,   1, 1,   0, 1 ]   // v4-v7-v6-v5 back
+       );
+
+    // index array
+    var indices = new WebGLUnsignedByteArray(
+        [  0, 1, 2,   0, 2, 3,    // front
+           4, 5, 6,   4, 6, 7,    // right
+           8, 9,10,   8,10,11,    // top
+          12,13,14,  12,14,15,    // left
+          16,17,18,  16,18,19,    // bottom
+          20,21,22,  20,22,23 ]   // back
+      );
+
+    var retval = { };
+    
+    retval.normalObject = ctx.createBuffer();
+    ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.normalObject);
+    ctx.bufferData(ctx.ARRAY_BUFFER, normals, ctx.STATIC_DRAW);
+    
+    retval.texCoordObject = ctx.createBuffer();
+    ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.texCoordObject);
+    ctx.bufferData(ctx.ARRAY_BUFFER, texCoords, ctx.STATIC_DRAW);
+
+    retval.vertexObject = ctx.createBuffer();
+    ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.vertexObject);
+    ctx.bufferData(ctx.ARRAY_BUFFER, vertices, ctx.STATIC_DRAW);
+    
+    ctx.bindBuffer(ctx.ARRAY_BUFFER, 0);
+
+    retval.indexObject = ctx.createBuffer();
+    ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, retval.indexObject);
+    ctx.bufferData(ctx.ELEMENT_ARRAY_BUFFER, indices, ctx.STATIC_DRAW);
+    ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, 0);
+    
+    retval.numIndices = indices.length;
+
+    return retval;
+}
+
+// 
+// makeSphere
+//
+// Create a sphere with the passed number of latitude and longitude bands and the passed radius. 
+// Sphere has vertices, normals and texCoords. Create VBOs for each as well as the index array.
+// Return an object with the following properties:
+//
+//  normalObject        WebGLBuffer object for normals
+//  texCoordObject      WebGLBuffer object for texCoords
+//  vertexObject        WebGLBuffer object for vertices
+//  indexObject         WebGLBuffer object for indices
+//  numIndices          The number of indices in the indexObject
+// 
+function makeSphere(ctx, radius, lats, longs)
+{
+    var geometryData = [ ];
+    var normalData = [ ];
+    var texCoordData = [ ];
+    var indexData = [ ];
+    
+    for (var latNumber = 0; latNumber <= lats; ++latNumber) {
+        for (var longNumber = 0; longNumber <= longs; ++longNumber) {
+            var theta = latNumber * Math.PI / lats;
+            var phi = longNumber * 2 * Math.PI / longs;
+            var sinTheta = Math.sin(theta);
+            var sinPhi = Math.sin(phi);
+            var cosTheta = Math.cos(theta);
+            var cosPhi = Math.cos(phi);
+            
+            var x = cosPhi * sinTheta;
+            var y = cosTheta;
+            var z = sinPhi * sinTheta;
+            var u = 1-(longNumber/longs);
+            var v = latNumber/lats;
+            
+            normalData.push(x);
+            normalData.push(y);
+            normalData.push(z);
+            texCoordData.push(u);
+            texCoordData.push(v);
+            geometryData.push(radius * x);
+            geometryData.push(radius * y);
+            geometryData.push(radius * z);
+        }
+    }
+    
+    longs += 1;
+    for (var latNumber = 0; latNumber < lats; ++latNumber) {
+        for (var longNumber = 0; longNumber < longs; ++longNumber) {
+            var first = (latNumber * longs) + (longNumber % longs);
+            var second = first + longs;
+            indexData.push(first);
+            indexData.push(second);
+            indexData.push(first+1);
+
+            indexData.push(second);
+            indexData.push(second+1);
+            indexData.push(first+1);
+        }
+    }
+    
+    var retval = { };
+    
+    retval.normalObject = ctx.createBuffer();
+    ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.normalObject);
+    ctx.bufferData(ctx.ARRAY_BUFFER, new WebGLFloatArray(normalData), ctx.STATIC_DRAW);
+
+    retval.texCoordObject = ctx.createBuffer();
+    ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.texCoordObject);
+    ctx.bufferData(ctx.ARRAY_BUFFER, new WebGLFloatArray(texCoordData), ctx.STATIC_DRAW);
+
+    retval.vertexObject = ctx.createBuffer();
+    ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.vertexObject);
+    ctx.bufferData(ctx.ARRAY_BUFFER, new WebGLFloatArray(geometryData), ctx.STATIC_DRAW);
+    
+    retval.numIndices = indexData.length;
+    retval.indexObject = ctx.createBuffer();
+    ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, retval.indexObject);
+    ctx.bufferData(ctx.ELEMENT_ARRAY_BUFFER, new WebGLUnsignedShortArray(indexData), ctx.STREAM_DRAW);
+    
+    return retval;
+}
+
+//
+// loadObj
+//
+// Load a .obj file from the passed URL. Return an object with a 'loaded' property set to false.
+// When the object load is complete, the 'loaded' property becomes true and the following 
+// properties are set:
+//
+//  normalObject        WebGLBuffer object for normals
+//  texCoordObject      WebGLBuffer object for texCoords
+//  vertexObject        WebGLBuffer object for vertices
+//  indexObject         WebGLBuffer object for indices
+//  numIndices          The number of indices in the indexObject
+//  
+function loadObj(ctx, url)
+{
+    var obj = { loaded : false };
+    obj.ctx = ctx;
+    var req = new XMLHttpRequest();
+    req.obj = obj;
+    req.onreadystatechange = function () { processLoadObj(req) };
+    req.open("GET", url, true);
+    req.send(null);
+    return obj;
+}
+
+function processLoadObj(req) 
+{
+    console.log("req="+req)
+    // only if req shows "complete"
+    if (req.readyState == 4) {
+        doLoadObj(req.obj, req.responseText);
+    }
+}
+
+function doLoadObj(obj, text)
+{
+    vertexArray = [ ];
+    normalArray = [ ];
+    textureArray = [ ];
+    indexArray = [ ];
+    
+    var vertex = [ ];
+    var normal = [ ];
+    var texture = [ ];
+    var facemap = { };
+    var index = 0;
+        
+    var lines = text.split("\n");
+    for (var lineIndex in lines) {
+        var line = lines[lineIndex].replace(/[ \t]+/g, " ").replace(/\s\s*$/, "");
+        
+        // ignore comments
+        if (line[0] == "#")
+            continue;
+            
+        var array = line.split(" ");
+        if (array[0] == "v") {
+            // vertex
+            vertex.push(parseFloat(array[1]));
+            vertex.push(parseFloat(array[2]));
+            vertex.push(parseFloat(array[3]));
+        }
+        else if (array[0] == "vt") {
+            // normal
+            texture.push(parseFloat(array[1]));
+            texture.push(parseFloat(array[2]));
+        }
+        else if (array[0] == "vn") {
+            // normal
+            normal.push(parseFloat(array[1]));
+            normal.push(parseFloat(array[2]));
+            normal.push(parseFloat(array[3]));
+        }
+        else if (array[0] == "f") {
+            // face
+            if (array.length != 4) {
+                console.log("*** Error: face '"+line+"' not handled");
+                continue;
+            }
+            
+            for (var i = 1; i < 4; ++i) {
+                if (!(array[i] in facemap)) {
+                    // add a new entry to the map and arrays
+                    var f = array[i].split("/");
+                    var vtx, nor, tex;
+                    
+                    if (f.length == 1) {
+                        vtx = parseInt(f[0]) - 1;
+                        nor = vtx;
+                        tex = vtx;
+                    }
+                    else if (f.length = 3) {
+                        vtx = parseInt(f[0]) - 1;
+                        tex = parseInt(f[1]) - 1;
+                        nor = parseInt(f[2]) - 1;
+                    }
+                    else {
+                        console.log("*** Error: did not understand face '"+array[i]+"'");
+                        return null;
+                    }
+                    
+                    // do the vertices
+                    var x = 0;
+                    var y = 0;
+                    var z = 0;
+                    if (vtx * 3 + 2 < vertex.length) {
+                        x = vertex[vtx*3];
+                        y = vertex[vtx*3+1];
+                        z = vertex[vtx*3+2];
+                    }
+                    vertexArray.push(x);
+                    vertexArray.push(y);
+                    vertexArray.push(z);
+                    
+                    // do the textures
+                    x = 0;
+                    y = 0;
+                    if (tex * 2 + 1 < texture.length) {
+                        x = texture[tex*2];
+                        y = texture[tex*2+1];
+                    }
+                    textureArray.push(x);
+                    textureArray.push(y);
+                    
+                    // do the normals
+                    x = 0;
+                    y = 0;
+                    z = 1;
+                    if (nor * 3 + 2 < normal.length) {
+                        x = normal[nor*3];
+                        y = normal[nor*3+1];
+                        z = normal[nor*3+2];
+                    }
+                    normalArray.push(x);
+                    normalArray.push(y);
+                    normalArray.push(z);
+                    
+                    facemap[array[i]] = index++;
+                }
+                
+                indexArray.push(facemap[array[i]]);
+            }
+        }
+    }
+
+    // set the VBOs
+    obj.normalObject = obj.ctx.createBuffer();
+    obj.ctx.bindBuffer(obj.ctx.ARRAY_BUFFER, obj.normalObject);
+    obj.ctx.bufferData(obj.ctx.ARRAY_BUFFER, new WebGLFloatArray(normalArray), obj.ctx.STATIC_DRAW);
+
+    obj.texCoordObject = obj.ctx.createBuffer();
+    obj.ctx.bindBuffer(obj.ctx.ARRAY_BUFFER, obj.texCoordObject);
+    obj.ctx.bufferData(obj.ctx.ARRAY_BUFFER, new WebGLFloatArray(textureArray), obj.ctx.STATIC_DRAW);
+
+    obj.vertexObject = obj.ctx.createBuffer();
+    obj.ctx.bindBuffer(obj.ctx.ARRAY_BUFFER, obj.vertexObject);
+    obj.ctx.bufferData(obj.ctx.ARRAY_BUFFER, new WebGLFloatArray(vertexArray), obj.ctx.STATIC_DRAW);
+    
+    obj.numIndices = indexArray.length;
+    obj.indexObject = obj.ctx.createBuffer();
+    obj.ctx.bindBuffer(obj.ctx.ELEMENT_ARRAY_BUFFER, obj.indexObject);
+    obj.ctx.bufferData(obj.ctx.ELEMENT_ARRAY_BUFFER, new WebGLUnsignedShortArray(indexArray), obj.ctx.STREAM_DRAW);
+    
+    obj.loaded = true;
+}
+
+//
+// loadImageTexture
+//
+// Load the image at the passed url, place it in a new WebGLTexture object and return the WebGLTexture.
+//
+function loadImageTexture(ctx, url)
+{
+    var texture = ctx.createTexture();
+    texture.image = new Image();
+    texture.image.onload = function() { doLoadImageTexture(ctx, texture.image, texture) }
+    texture.image.src = url;
+    return texture;
+}
+
+function doLoadImageTexture(ctx, image, texture)
+{
+    ctx.enable(ctx.TEXTURE_2D);
+    ctx.bindTexture(ctx.TEXTURE_2D, texture);
+    ctx.texImage2D(ctx.TEXTURE_2D, 0, image);
+    ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.LINEAR);
+    ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.LINEAR_MIPMAP_LINEAR);
+    ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_S, ctx.CLAMP_TO_EDGE);
+    ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_T, ctx.CLAMP_TO_EDGE);
+    ctx.generateMipmap(ctx.TEXTURE_2D)
+    ctx.bindTexture(ctx.TEXTURE_2D, 0);
+}
+
+//
+// Framerate object
+//
+// This object keeps track of framerate and displays it as the innerHTML text of the 
+// HTML element with the passed id. Once created you call snapshot at the end
+// of every rendering cycle. Every 500ms the framerate is updated in the HTML element.
+//
+Framerate = function(id)
+{
+    this.numFramerates = 10;
+    this.framerateUpdateInterval = 500;
+    this.id = id;
+
+    this.renderTime = -1;
+    this.framerates = [ ];
+    self = this;
+    var fr = function() { self.updateFramerate() }
+    setInterval(fr, this.framerateUpdateInterval);
+}
+
+Framerate.prototype.updateFramerate = function()
+{
+    var tot = 0;
+    for (var i = 0; i < this.framerates.length; ++i)
+        tot += this.framerates[i];
+        
+    var framerate = tot / this.framerates.length;
+    framerate = Math.round(framerate);
+    document.getElementById(this.id).innerHTML = "Framerate:"+framerate+"fps";
+}
+
+Framerate.prototype.snapshot = function()
+{
+    if (this.renderTime < 0)
+        this.renderTime = new Date().getTime();
+    else {
+        var newTime = new Date().getTime();
+        var t = newTime - this.renderTime;
+        var framerate = 1000/t;
+        this.framerates.push(framerate);
+        while (this.framerates.length > this.numFramerates)
+            this.framerates.shift();
+        this.renderTime = newTime;
+    }
+}
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/resources/vertexShader.vert
@@ -0,0 +1,36 @@
+/*
+Copyright (C) 2009 Apple Computer, Inc.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+attribute vec4 a_vertex;
+attribute vec3 a_normal;
+
+uniform mat4 u_modelViewProjMatrix;
+
+varying vec3 v_normal;
+
+void main()
+{ 
+    v_normal = a_normal;
+    gl_Position =  u_modelViewProjMatrix * a_vertex;
+}
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/resources/webgl-test-utils.js
@@ -0,0 +1,616 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+WebGLTestUtils = (function() {
+
+/**
+ * Wrapped logging function.
+ * @param {string} msg The message to log.
+ */
+var log = function(msg) {
+  if (window.console && window.console.log) {
+    window.console.log(msg);
+  }
+};
+
+/**
+ * A vertex shader for a single texture.
+ * @type {string}
+ */
+var simpleTextureVertexShader = '' +
+  'attribute vec4 vPosition;\n' +
+  'attribute vec2 texCoord0;\n' +
+  'varying vec2 texCoord;\n' +
+  'void main() {\n' +
+  '    gl_Position = vPosition;\n' +
+  '    texCoord = texCoord0;\n' +
+  '}\n';
+
+/**
+ * A fragment shader for a single texture.
+ * @type {string}
+ */
+var simpleTextureFragmentShader = '' +
+  'uniform sampler2D tex;\n' +
+  'varying vec2 texCoord;\n' +
+  'void main() {\n' +
+  '    gl_FragColor = texture2D(tex, texCoord);\n' +
+  '}\n';
+
+/**
+ * Creates a simple texture vertex shader.
+ * @param {!WebGLContext} gl The WebGLContext to use.
+ * @return {!WebGLShader}
+ */
+var setupSimpleTextureVertexShader = function(gl) {
+    return loadShader(gl, simpleTextureVertexShader, gl.VERTEX_SHADER, false);
+};
+
+/**
+ * Creates a simple texture fragment shader.
+ * @param {!WebGLContext} gl The WebGLContext to use.
+ * @return {!WebGLShader}
+ */
+var setupSimpleTextureFragmentShader = function(gl) {
+    return loadShader(
+        gl, simpleTextureFragmentShader, gl.FRAGMENT_SHADER, false);
+};
+
+/**
+ * Creates a simple texture program.
+ * @param {!WebGLContext} gl The WebGLContext to use.
+ * @param {number} opt_positionLocation The attrib location for position.
+ * @param {number} opt_texcoordLocation The attrib location for texture coords.
+ * @return {WebGLProgram}
+ */
+var setupSimpleTextureProgram = function(
+    gl, opt_positionLocation, opt_texcoordLocation) {
+  opt_positionLocation = opt_positionLocation || 0;
+  opt_texcoordLocation = opt_texcoordLocation || 1;
+  var vs = setupSimpleTextureVertexShader(gl);
+  var fs = setupSimpleTextureFragmentShader(gl);
+  if (!vs || !fs) {
+    return null;
+  }
+  var program = gl.createProgram();
+  gl.attachShader(program, vs);
+  gl.attachShader(program, fs);
+  gl.bindAttribLocation(program, opt_positionLocation, 'vPosition');
+  gl.bindAttribLocation(program, opt_texcoordLocation, 'texCoord0');
+  gl.linkProgram(program);
+
+  // Check the link status
+  var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
+  if (!linked) {
+      // something went wrong with the link
+      var error = gl.getProgramInfoLog (program);
+      log("Error in program linking:"+error);
+
+      gl.deleteProgram(program);
+      gl.deleteProgram(fs);
+      gl.deleteProgram(vs);
+
+      return null;
+  }
+
+  gl.useProgram(program);
+  return program;
+};
+
+/**
+ * Creates buffers for a textured unit quad and attaches them to vertex attribs.
+ * @param {!WebGLContext} gl The WebGLContext to use.
+ * @param {number} opt_positionLocation The attrib location for position.
+ * @param {number} opt_texcoordLocation The attrib location for texture coords.
+ */
+var setupUnitQuad = function(gl, opt_positionLocation, opt_texcoordLocation) {
+  opt_positionLocation = opt_positionLocation || 0;
+  opt_texcoordLocation = opt_texcoordLocation || 1;
+
+  var vertexObject = gl.createBuffer();
+  gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
+  gl.bufferData(gl.ARRAY_BUFFER, new WebGLFloatArray(
+      [-1,1,0, 1,1,0, -1,-1,0,
+       -1,-1,0, 1,1,0, 1,-1,0]), gl.STATIC_DRAW);
+  gl.enableVertexAttribArray(opt_positionLocation);
+  gl.vertexAttribPointer(opt_positionLocation, 3, gl.FLOAT, false, 0, 0);
+
+  var vertexObject = gl.createBuffer();
+  gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
+  gl.bufferData(gl.ARRAY_BUFFER, new WebGLFloatArray(
+      [0,0, 1,0, 0,1,
+       0,1, 1,0, 1,1]), gl.STATIC_DRAW);
+  gl.enableVertexAttribArray(opt_texcoordLocation);
+  gl.vertexAttribPointer(opt_texcoordLocation, 2, gl.FLOAT, false, 0, 0);
+};
+
+/**
+ * Creates a program and buffers for rendering a textured quad.
+ * @param {!WebGLContext} gl The WebGLContext to use.
+ * @param {number} opt_positionLocation The attrib location for position.
+ * @param {number} opt_texcoordLocation The attrib location for texture coords.
+ * @return {!WebGLProgram}
+ */
+var setupTexturedQuad = function(
+    gl, opt_positionLocation, opt_texcoordLocation) {
+  var program = setupSimpleTextureProgram(
+      gl, opt_positionLocation, opt_texcoordLocation);
+  setupUnitQuad(gl, opt_positionLocation, opt_texcoordLocation);
+  return program;
+};
+
+/**
+ * Fills the given texture with a solid color
+ * @param {!WebGLContext} gl The WebGLContext to use.
+ * @param {!WebGLTexture} tex The texture to fill.
+ * @param {number} width The width of the texture to create.
+ * @param {number} height The height of the texture to create.
+ * @param {!Array.<number>} color The color to fill with. A 4 element array
+ *        where each element is in the range 0 to 255.
+ * @param {number} opt_level The level of the texture to fill. Default = 0.
+ */
+var fillTexture = function(gl, tex, width, height, color, opt_level) {
+  opt_level = opt_level || 0;
+  var canvas = document.createElement('canvas');
+  canvas.width = width;
+  canvas.height = height;
+  var ctx2d = canvas.getContext('2d');
+  ctx2d.fillStyle = "rgba(" + color[0] + "," + color[1] + "," + color[2] + "," + color[3] + ")";
+  ctx2d.fillRect(0, 0, width, height);
+  gl.bindTexture(gl.TEXTURE_2D, tex);
+  gl.texImage2D(gl.TEXTURE_2D, opt_level, canvas);
+};
+
+/**
+ * Creates a textures and fills it with a solid color
+ * @param {!WebGLContext} gl The WebGLContext to use.
+ * @param {number} width The width of the texture to create.
+ * @param {number} height The height of the texture to create.
+ * @param {!Array.<number>} color The color to fill with. A 4 element array
+ *        where each element is in the range 0 to 255.
+ * @return {!WebGLTexture}
+ */
+var createColoredTexture = function(gl, width, height, color) {
+  var tex = gl.createTexture();
+  fillTexture(gl, text, width, height, color);
+  return tex;
+};
+
+/**
+ * Draws a previously setup quad.
+ * @param {!WebGLContext} gl The WebGLContext to use.
+ * @param {!Array.<number>} opt_color The color to fill clear with before
+ *        drawing. A 4 element array where each element is in the range 0 to
+ *        255. Default [255, 255, 255, 255]
+ */
+var drawQuad = function(gl, opt_color) {
+  opt_color = opt_color || [255, 255, 255, 255];
+  gl.clearColor(
+      opt_color[0] / 255,
+      opt_color[1] / 255,
+      opt_color[2] / 255,
+      opt_color[3] / 255);
+  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+  gl.drawArrays(gl.TRIANGLES, 0, 6);
+};
+
+/**
+ * Checks that an entire canvas is 1 color.
+ * @param {!WebGLContext} gl The WebGLContext to use.
+ * @param {!Array.<number>} color The color to fill clear with before drawing. A
+ *        4 element array where each element is in the range 0 to 255.
+ * @param {string} msg Message to associate with success. Eg ("should be red").
+ */
+var checkCanvas = function(gl, color, msg) {
+  var width = gl.canvas.width;
+  var height = gl.canvas.height;
+  var buf = gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE);
+  for (var i = 0; i < width * height; ++i) {
+    var offset = i * 4;
+    if (buf[offset + 0] != color[0] ||
+        buf[offset + 1] != color[1] ||
+        buf[offset + 2] != color[2] ||
+        buf[offset + 3] != color[3]) {
+      testFailed(msg);
+      debug('expected: ' +
+          color[0] + ', ' +
+          color[1] + ', ' +
+          color[2] + ', ' +
+          color[3] + ' was: ' +
+          buf[offset + 0] + ', ' +
+          buf[offset + 1] + ', ' +
+          buf[offset + 2] + ', ' +
+          buf[offset + 3]);
+      return;
+    }
+  }
+  testPassed(msg);
+};
+
+/**
+ * Creates a webgl context.
+ * @param {!Canvas} opt_canvas The canvas tag to get context from. If one is not
+ *     passed in one will be created.
+ * @return {!WebGLContext} The created context.
+ */
+var create3DContext = function(opt_canvas) {
+  opt_canvas = opt_canvas || document.createElement("canvas");
+  var context = null;
+  try {
+    context = opt_canvas.getContext("experimental-webgl");
+  } catch(e) {}
+  if (!context) {
+    try {
+      context = opt_canvas.getContext("webkit-3d");
+    } catch(e) {}
+  }
+  if (!context) {
+    try {
+      context = opt_canvas.getContext("moz-webgl");
+    } catch(e) {}
+  }
+  if (!context) {
+    testFailed("Unable to fetch WebGL rendering context for Canvas");
+  }
+  return context;
+}
+
+/**
+ * Gets a GLError value as a string.
+ * @param {!WebGLContext} gl The WebGLContext to use.
+ * @param {number} err The webgl error as retrieved from gl.getError().
+ * @return {string} the error as a string.
+ */
+var getGLErrorAsString = function(gl, err) {
+  if (err === gl.NO_ERROR) {
+    return "NO_ERROR";
+  }
+  for (var name in gl) {
+    if (gl[name] === err) {
+      return name;
+    }
+  }
+  return err.toString();
+};
+
+/**
+ * Wraps a WebGL function with a function that throws an exception if there is
+ * an error.
+ * @param {!WebGLContext} gl The WebGLContext to use.
+ * @param {string} fname Name of function to wrap.
+ * @return {function} The wrapped function.
+ */
+var createGLErrorWrapper = function(context, fname) {
+  return function() {
+    var rv = context[fname].apply(context, arguments);
+    var err = context.getError();
+    if (err != 0)
+      throw "GL error " + getGLErrorAsString(err) + " in " + fname;
+    return rv;
+  };
+};
+
+/**
+ * Creates a WebGL context where all functions are wrapped to throw an exception
+ * if there is an error.
+ * @param {!Canvas} canvas The HTML canvas to get a context from.
+ * @return {!Object} The wrapped context.
+ */
+function create3DContextWithWrapperThatThrowsOnGLError(canvas) {
+  var context = create3DContext(canvas);
+  var wrap = {};
+  for (var i in context) {
+    try {
+      if (typeof context[i] == 'function') {
+        wrap[i] = createGLErrorWrapper(context, i);
+      } else {
+        wrap[i] = context[i];
+      }
+    } catch (e) {
+      log("createContextWrapperThatThrowsOnGLError: Error accessing " + i);
+    }
+  }
+  wrap.getError = function() {
+      return context.getError();
+  };
+  return wrap;
+};
+
+/**
+ * Tests that an evaluated expression generates a specific GL error.
+ * @param {!WebGLContext} gl The WebGLContext to use.
+ * @param {number} glError The expected gl error.
+ * @param {string} evalSTr The string to evaluate.
+ */
+var shouldGenerateGLError = function(gl, glError, evalStr) {
+  var exception;
+  try {
+    eval(evalStr);
+  } catch (e) {
+    exception = e;
+  }
+  if (exception) {
+    testFailed(evalStr + " threw exception " + exception);
+  } else {
+    var err = gl.getError();
+    if (err != glError) {
+      testFailed(evalStr + " expected: " + getGLErrorAsString(gl, glError) + ". Was " + getGLErrorAsString(gl, err) + ".");
+    } else {
+      testPassed(evalStr + " was expected value: " + getGLErrorAsString(gl, glError) + ".");
+    }
+  }
+};
+
+/**
+ * Tests that the first error GL returns is the specified error.
+ * @param {!WebGLContext} gl The WebGLContext to use.
+ * @param {number} glError The expected gl error.
+ */
+var glErrorShouldBe = function(gl, glError) {
+  var err = gl.getError();
+  if (err != glError) {
+    testFailed("getError expected: " + getGLErrorAsString(gl, glError) + ". Was " + getGLErrorAsString(gl, err) + ".");
+  } else {
+    testPassed("getError was expected value: " + getGLErrorAsString(gl, glError) + ".");
+  }
+};
+
+/**
+ * Links a WebGL program, throws if there are errors.
+ * @param {!WebGLContext} gl The WebGLContext to use.
+ * @param {!WebGLProgram} program The WebGLProgram to link.
+ */
+var linkProgram = function(gl, program) {
+  // Link the program
+  gl.linkProgram(program);
+
+  // Check the link status
+  var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
+  if (!linked) {
+    // something went wrong with the link
+    var error = gl.getProgramInfoLog (program);
+
+    gl.deleteProgram(program);
+    gl.deleteProgram(fragmentShader);
+    gl.deleteProgram(vertexShader);
+
+    testFailed("Error in program linking:" + error);
+  }
+};
+
+/**
+ * Sets up WebGL with shaders.
+ * @param {string} canvasName The id of the canvas.
+ * @param {string} vshader The id of the script tag that contains the vertex
+ *     shader source.
+ * @param {string} fshader The id of the script tag that contains the fragment
+ *     shader source.
+ * @param {!Array.<string>} attribs An array of attrib names used to bind
+ *     attribs to the ordinal of the name in this array.
+ * @param {!Array.<number>} opt_clearColor The color to cla
+ * @return {!WebGLContext} The created WebGLContext.
+ */
+var setupWebGLWithShaders = function(
+   canvasName, vshader, fshader, attribs) {
+  var canvas = document.getElementById(canvasName);
+  var gl = create3DContext(canvas);
+  if (!gl) {
+    testFailed("No WebGL context found");
+  }
+
+  // create our shaders
+  var vertexShader = loadShaderFromScript(gl, vshader);
+  var fragmentShader = loadShaderFromScript(gl, fshader);
+
+  if (!vertexShader || !fragmentShader) {
+    return null;
+  }
+
+  // Create the program object
+  program = gl.createProgram();
+
+  if (!program) {
+    return null;
+  }
+
+  // Attach our two shaders to the program
+  gl.attachShader (program, vertexShader);
+  gl.attachShader (program, fragmentShader);
+
+  // Bind attributes
+  for (var i in attribs) {
+    gl.bindAttribLocation (program, i, attribs[i]);
+  }
+
+  linkProgram(gl, program);
+
+  gl.useProgram(program);
+
+  gl.enable(gl.DEPTH_TEST);
+  gl.enable(gl.BLEND);
+  gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
+
+  gl.program = program;
+  return gl;
+};
+
+/**
+ * Gets shader source from a file/URL
+ * @param {string} file the URL of the file to get.
+ * @return {string} The contents of the file.
+ */
+var getShaderSource = function(file) {
+  var xhr = new XMLHttpRequest();
+  xhr.open("GET", file, false);
+  xhr.send();
+  return xhr.responseText;
+};
+
+/**
+ * Loads a shader.
+ * @param {!WebGLContext} gl The WebGLContext to use.
+ * @param {string} shaderSource The shader source.
+ * @param {number} shaderType The type of shader.
+ * @return {!WebGLShader} The created shader.
+ */
+var loadShader = function(gl, shaderSource, shaderType) {
+  // Create the shader object
+  var shader = gl.createShader(shaderType);
+  if (shader == null) {
+    log("*** Error: unable to create shader '"+shaderSource+"'");
+    return null;
+  }
+
+  // Load the shader source
+  gl.shaderSource(shader, shaderSource);
+
+  // Compile the shader
+  gl.compileShader(shader);
+
+  // Check the compile status
+  var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
+  if (!compiled) {
+    // Something went wrong during compilation; get the error
+    var error = gl.getShaderInfoLog(shader);
+    log("*** Error compiling shader '"+shader+"':"+error);
+    gl.deleteShader(shader);
+    return null;
+  }
+
+  return shader;
+}
+
+/**
+ * Loads a shader from a URL.
+ * @param {!WebGLContext} gl The WebGLContext to use.
+ * @param {file} file The URL of the shader source.
+ * @param {number} type The type of shader.
+ * @return {!WebGLShader} The created shader.
+ */
+var loadShaderFromFile = function(gl, file, type) {
+  var shaderSource = getShaderSource(file);
+  return loadShader(gl, shaderSource, type);
+};
+
+/**
+ * Loads a shader from a script tag.
+ * @param {!WebGLContext} gl The WebGLContext to use.
+ * @param {string} scriptId The id of the script tag.
+ * @param {number} opt_shaderType The type of shader. If not passed in it will
+ *     be derived from the type of the script tag.
+ * @return {!WebGLShader} The created shader.
+ */
+var loadShaderFromScript = function(gl, scriptId, opt_shaderType) {
+  var shaderSource = "";
+
+  var shaderScript = document.getElementById(scriptId);
+  if (!shaderScript) {
+    throw("*** Error: unknown script element" + scriptId);
+  } else if (!opt_shaderType) {
+    if (shaderScript.type == "x-shader/x-vertex") {
+      opt_shaderType = gl.VERTEX_SHADER;
+    } else if (shaderScript.type == "x-shader/x-fragment") {
+      opt_shaderType = gl.FRAGMENT_SHADER;
+    } else if (shaderType != gl.VERTEX_SHADER && shaderType != gl.FRAGMENT_SHADER) {
+      throw("*** Error: unknown shader type");
+      return null;
+    }
+
+    shaderSource = shaderScript.text;
+  }
+
+  return loadShader(
+      gl, shaderSource, opt_shaderType ? opt_shaderType : shaderType);
+};
+
+var loadStandardProgram = function(gl) {
+  var program = gl.createProgram();
+  gl.attachShader(program, loadStandardVertexShader(gl));
+  gl.attachShader(program, loadStandardFragmentShader(gl));
+  linkProgram(gl, program);
+  return program;
+};
+
+/**
+ * Loads shaders from files, creates a program, attaches the shaders and links.
+ * @param {!WebGLContext} gl The WebGLContext to use.
+ * @param {string} vertexShaderPath The URL of the vertex shader.
+ * @param {string} fragmentShaderPath The URL of the fragment shader.
+ * @return {!WebGLProgram} The created program.
+ */
+var loadProgramFromFile = function(gl, vertexShaderPath, fragmentShaderPath) {
+  var program = gl.createProgram();
+  gl.attachShader(
+      program,
+      loadShaderFromFile(gl, vertexShaderPath, gl.VERTEX_SHADER));
+  gl.attachShader(
+      program,
+      loadShaderFromFile(gl, fragmentShaderPath, gl.FRAGMENT_SHADER));
+  linkProgram(gl, program);
+  return program;
+};
+
+/**
+ * Loads shaders from script tags, creates a program, attaches the shaders and
+ * links.
+ * @param {!WebGLContext} gl The WebGLContext to use.
+ * @param {string} vertexScriptId The id of the script tag that contains the
+ *        vertex shader.
+ * @param {string} fragmentScriptId The id of the script tag that contains the
+ *        fragment shader.
+ * @return {!WebGLProgram} The created program.
+ */
+var loadProgramFromScript = function loadProgramFromScript(
+  gl, vertexScriptId, fragmentScriptId) {
+  var program = gl.createProgram();
+  gl.attachShader(
+      program,
+      loadShaderFromScript(gl, vertexScriptId, gl.VERTEX_SHADER));
+  gl.attachShader(
+      program,
+      loadShaderFromScript(gl, fragmentScriptId,  gl.FRAGMENT_SHADER));
+  linkProgram(gl, program);
+  return program;
+};
+
+var loadStandardVertexShader = function(gl) {
+  return loadShaderFromFile(
+      gl, "resources/vertexShader.vert", gl.VERTEX_SHADER);
+};
+
+var loadStandardFragmentShader = function(gl) {
+  return loadShaderFromfile(
+      gl, "resources/fragmentShader.frag", gl.FRAGMENT_SHADER);
+};
+
+return {
+    create3DContext: create3DContext,
+    create3DContextWithWrapperThatThrowsOnGLError:
+        create3DContextWithWrapperThatThrowsOnGLError,
+    checkCanvas: checkCanvas,
+    createColoredTexture: createColoredTexture,
+    drawQuad: drawQuad,
+    glErrorShouldBe: glErrorShouldBe,
+    fillTexture: fillTexture,
+    loadProgramFromFile: loadProgramFromFile,
+    loadProgramFromScript: loadProgramFromScript,
+    loadShader: loadShader,
+    loadShaderFromFile: loadShaderFromFile,
+    loadShaderFromScript: loadShaderFromScript,
+    loadStandardProgram: loadStandardProgram,
+    loadStandardVertexShader: loadStandardVertexShader,
+    loadStandardFragmentShader: loadStandardFragmentShader,
+    setupSimpleTextureFragmentShader: setupSimpleTextureFragmentShader,
+    setupSimpleTextureProgram: setupSimpleTextureProgram,
+    setupSimpleTextureVertexShader: setupSimpleTextureVertexShader,
+    setupTexturedQuad: setupTexturedQuad,
+    setupUnitQuad: setupUnitQuad,
+    shouldGenerateGLError: shouldGenerateGLError,
+
+    none: false
+};
+
+}());
+
+
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/resources/webgl-test.js
@@ -0,0 +1,723 @@
+/*
+Copyright (C) 2009 Apple Computer, Inc.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+function webglTestLog(msg) {
+  if (window.console && window.console.log) {
+    window.console.log(msg);
+  }
+}
+
+//
+// create3DContext
+//
+// Return the WebGLRenderingContext for any known implementation
+//
+function create3DContext(canvas)
+{
+    if (!canvas)
+        canvas = document.createElement("canvas");
+    var context = null;
+    try {
+        context = canvas.getContext("experimental-webgl");
+    } catch(e) {}
+    if (!context) {
+        try {
+            context = canvas.getContext("webkit-3d");
+        } catch(e) {}
+    }
+    if (!context) {
+        try {
+            context = canvas.getContext("moz-webgl");
+        } catch(e) {}
+    }
+    if (!context) {
+        throw "Unable to fetch WebGL rendering context for Canvas";
+    }
+    return context;
+}
+
+function createGLErrorWrapper(context, fname) {
+    return function() {
+        var rv = context[fname].apply(context, arguments);
+        var err = context.getError();
+        if (err != 0)
+            throw "GL error " + err + " in " + fname;
+        return rv;
+    };
+}
+
+function create3DContextWithWrapperThatThrowsOnGLError(canvas) {
+  var context = create3DContext(canvas);
+  // Thanks to Ilmari Heikkinen for the idea on how to implement this so elegantly.
+  var wrap = {};
+  for (var i in context) {
+    try {
+      if (typeof context[i] == 'function') {
+        wrap[i] = createGLErrorWrapper(context, i);
+      } else {
+        wrap[i] = context[i];
+      }
+    } catch (e) {
+      webglTestLog("createContextWrapperThatThrowsOnGLError: Error accessing " + i);
+    }
+  }
+  wrap.getError = function() {
+      return context.getError();
+  };
+  return wrap;
+}
+
+function getGLErrorAsString(ctx, err) {
+  if (err === ctx.NO_ERROR) {
+    return "NO_ERROR";
+  }
+  for (var name in ctx) {
+    if (ctx[name] === err) {
+      return name;
+    }
+  }
+  return err.toString();
+}
+
+function shouldGenerateGLError(ctx, glError, evalStr) {
+  var exception;
+  try {
+    eval(evalStr);
+  } catch (e) {
+    exception = e;
+  }
+  if (exception) {
+    testFailed(evalStr + " threw exception " + exception);
+  } else {
+    var err = ctx.getError();
+    if (err != glError) {
+      testFailed(evalStr + " expected: " + getGLErrorAsString(ctx, glError) + ". Was " + getGLErrorAsString(ctx, err) + ".");
+    } else {
+      testPassed(evalStr + " was expected value: " + getGLErrorAsString(ctx, glError) + ".");
+    }
+  }
+}
+
+function glErrorShouldBe(ctx, glError) {
+  var err = ctx.getError();
+  if (err != glError) {
+    testFailed("getError expected: " + getGLErrorAsString(ctx, glError) + ". Was " + getGLErrorAsString(ctx, err) + ".");
+  } else {
+    testPassed("getError was expected value: " + getGLErrorAsString(ctx, glError) + ".");
+  }
+}
+
+//
+// initWebGL
+//
+// Initialize the Canvas element with the passed name as a WebGL object and return the
+// WebGLRenderingContext.
+//
+// Load shaders with the passed names and create a program with them. Return this program
+// in the 'program' property of the returned context.
+//
+// For each string in the passed attribs array, bind an attrib with that name at that index.
+// Once the attribs are bound, link the program and then use it.
+//
+// Set the clear color to the passed array (4 values) and set the clear depth to the passed value.
+// Enable depth testing and blending with a blend func of (SRC_ALPHA, ONE_MINUS_SRC_ALPHA)
+//
+function initWebGL(canvasName, vshader, fshader, attribs, clearColor, clearDepth)
+{
+    var canvas = document.getElementById(canvasName);
+    var gl = create3DContext(canvas);
+    if (!gl) {
+        alert("No WebGL context found");
+        return null;
+    }
+
+    // create our shaders
+    var vertexShader = loadShaderFromScript(gl, vshader);
+    var fragmentShader = loadShaderFromScript(gl, fshader);
+
+    if (!vertexShader || !fragmentShader)
+        return null;
+
+    // Create the program object
+    gl.program = gl.createProgram();
+
+    if (!gl.program)
+        return null;
+
+    // Attach our two shaders to the program
+    gl.attachShader (gl.program, vertexShader);
+    gl.attachShader (gl.program, fragmentShader);
+
+    // Bind attributes
+    for (var i in attribs)
+        gl.bindAttribLocation (gl.program, i, attribs[i]);
+
+    // Link the program
+    gl.linkProgram(gl.program);
+
+    // Check the link status
+    var linked = gl.getProgramParameter(gl.program, gl.LINK_STATUS);
+    if (!linked) {
+        // something went wrong with the link
+        var error = gl.getProgramInfoLog (gl.program);
+        webglTestLog("Error in program linking:"+error);
+
+        gl.deleteProgram(gl.program);
+        gl.deleteProgram(fragmentShader);
+        gl.deleteProgram(vertexShader);
+
+        return null;
+    }
+
+    gl.useProgram(gl.program);
+
+    gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
+    gl.clearDepth(clearDepth);
+
+    gl.enable(gl.DEPTH_TEST);
+    gl.enable(gl.BLEND);
+    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
+
+    return gl;
+}
+
+//
+// getShaderSource
+//
+// Load the source from the passed shader file.
+//
+function getShaderSource(file)
+{
+    var xhr = new XMLHttpRequest();
+    xhr.open("GET", file, false);
+    xhr.send();
+    return xhr.responseText;
+}
+
+
+//
+// loadShader
+//
+// 'shader' is either the id of a <script> element containing the shader source
+// string, the shader string itself,  or the URL of a file containing the shader
+// source. Load this shader and return the WebGLShader object corresponding to
+// it.
+//
+function loadShader(ctx, shaderId, shaderType, isFile)
+{
+    var shaderSource = "";
+
+    if (isFile)
+        shaderSource = getShaderSource(shaderId);
+    else {
+        var shaderScript = document.getElementById(shaderId);
+        if (!shaderScript) {
+            shaderSource = shaderId;
+        } else {
+            if (shaderScript.type == "x-shader/x-vertex") {
+                shaderType = ctx.VERTEX_SHADER;
+            } else if (shaderScript.type == "x-shader/x-fragment") {
+                shaderType = ctx.FRAGMENT_SHADER;
+            } else if (shaderType != ctx.VERTEX_SHADER && shaderType != ctx.FRAGMENT_SHADER) {
+                webglTestLog("*** Error: unknown shader type");
+                return null;
+            }
+
+            shaderSource = shaderScript.text;
+        }
+    }
+
+    // Create the shader object
+    var shader = ctx.createShader(shaderType);
+    if (shader == null) {
+        webglTestLog("*** Error: unable to create shader '"+shaderId+"'");
+        return null;
+    }
+
+    // Load the shader source
+    ctx.shaderSource(shader, shaderSource);
+
+    // Compile the shader
+    ctx.compileShader(shader);
+
+    // Check the compile status
+    var compiled = ctx.getShaderParameter(shader, ctx.COMPILE_STATUS);
+    if (!compiled) {
+        // Something went wrong during compilation; get the error
+        var error = ctx.getShaderInfoLog(shader);
+        webglTestLog("*** Error compiling shader '"+shader+"':"+error);
+        ctx.deleteShader(shader);
+        return null;
+    }
+
+    return shader;
+}
+
+function loadShaderFromFile(ctx, file, type)
+{
+    return loadShader(ctx, file, type, true);
+}
+
+function loadShaderFromScript(ctx, script)
+{
+    return loadShader(ctx, script, 0, false);
+}
+
+function loadStandardProgram(context) {
+    var program = context.createProgram();
+    context.attachShader(program, loadStandardVertexShader(context));
+    context.attachShader(program, loadStandardFragmentShader(context));
+    context.linkProgram(program);
+    return program;
+}
+
+function loadProgram(context, vertexShaderPath, fragmentShaderPath, isFile) {
+    isFile = (isFile === undefined) ? true : isFile;
+    var program = context.createProgram();
+    context.attachShader(program, loadShader(context, vertexShaderPath, context.VERTEX_SHADER, isFile));
+    context.attachShader(program, loadShader(context, fragmentShaderPath, context.FRAGMENT_SHADER, isFile));
+    context.linkProgram(program);
+    return program;
+}
+
+function loadStandardVertexShader(context) {
+    return loadShader(context, "resources/vertexShader.vert", context.VERTEX_SHADER, true);
+}
+
+function loadStandardFragmentShader(context) {
+    return loadShader(context, "resources/fragmentShader.frag", context.FRAGMENT_SHADER, true);
+}
+
+//
+// makeBox
+//
+// Create a box with vertices, normals and texCoords. Create VBOs for each as well as the index array.
+// Return an object with the following properties:
+//
+//  normalObject        WebGLBuffer object for normals
+//  texCoordObject      WebGLBuffer object for texCoords
+//  vertexObject        WebGLBuffer object for vertices
+//  indexObject         WebGLBuffer object for indices
+//  numIndices          The number of indices in the indexObject
+//
+function makeBox(ctx)
+{
+    // box
+    //    v6----- v5
+    //   /|      /|
+    //  v1------v0|
+    //  | |     | |
+    //  | |v7---|-|v4
+    //  |/      |/
+    //  v2------v3
+    //
+    // vertex coords array
+    var vertices = new WebGLFloatArray(
+        [  1, 1, 1,  -1, 1, 1,  -1,-1, 1,   1,-1, 1,    // v0-v1-v2-v3 front
+           1, 1, 1,   1,-1, 1,   1,-1,-1,   1, 1,-1,    // v0-v3-v4-v5 right
+           1, 1, 1,   1, 1,-1,  -1, 1,-1,  -1, 1, 1,    // v0-v5-v6-v1 top
+          -1, 1, 1,  -1, 1,-1,  -1,-1,-1,  -1,-1, 1,    // v1-v6-v7-v2 left
+          -1,-1,-1,   1,-1,-1,   1,-1, 1,  -1,-1, 1,    // v7-v4-v3-v2 bottom
+           1,-1,-1,  -1,-1,-1,  -1, 1,-1,   1, 1,-1 ]   // v4-v7-v6-v5 back
+    );
+
+    // normal array
+    var normals = new WebGLFloatArray(
+        [  0, 0, 1,   0, 0, 1,   0, 0, 1,   0, 0, 1,     // v0-v1-v2-v3 front
+           1, 0, 0,   1, 0, 0,   1, 0, 0,   1, 0, 0,     // v0-v3-v4-v5 right
+           0, 1, 0,   0, 1, 0,   0, 1, 0,   0, 1, 0,     // v0-v5-v6-v1 top
+          -1, 0, 0,  -1, 0, 0,  -1, 0, 0,  -1, 0, 0,     // v1-v6-v7-v2 left
+           0,-1, 0,   0,-1, 0,   0,-1, 0,   0,-1, 0,     // v7-v4-v3-v2 bottom
+           0, 0,-1,   0, 0,-1,   0, 0,-1,   0, 0,-1 ]    // v4-v7-v6-v5 back
+       );
+
+
+    // texCoord array
+    var texCoords = new WebGLFloatArray(
+        [  1, 1,   0, 1,   0, 0,   1, 0,    // v0-v1-v2-v3 front
+           0, 1,   0, 0,   1, 0,   1, 1,    // v0-v3-v4-v5 right
+           1, 0,   1, 1,   0, 1,   0, 0,    // v0-v5-v6-v1 top
+           1, 1,   0, 1,   0, 0,   1, 0,    // v1-v6-v7-v2 left
+           0, 0,   1, 0,   1, 1,   0, 1,    // v7-v4-v3-v2 bottom
+           0, 0,   1, 0,   1, 1,   0, 1 ]   // v4-v7-v6-v5 back
+       );
+
+    // index array
+    var indices = new WebGLUnsignedByteArray(
+        [  0, 1, 2,   0, 2, 3,    // front
+           4, 5, 6,   4, 6, 7,    // right
+           8, 9,10,   8,10,11,    // top
+          12,13,14,  12,14,15,    // left
+          16,17,18,  16,18,19,    // bottom
+          20,21,22,  20,22,23 ]   // back
+      );
+
+    var retval = { };
+
+    retval.normalObject = ctx.createBuffer();
+    ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.normalObject);
+    ctx.bufferData(ctx.ARRAY_BUFFER, normals, ctx.STATIC_DRAW);
+
+    retval.texCoordObject = ctx.createBuffer();
+    ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.texCoordObject);
+    ctx.bufferData(ctx.ARRAY_BUFFER, texCoords, ctx.STATIC_DRAW);
+
+    retval.vertexObject = ctx.createBuffer();
+    ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.vertexObject);
+    ctx.bufferData(ctx.ARRAY_BUFFER, vertices, ctx.STATIC_DRAW);
+
+    ctx.bindBuffer(ctx.ARRAY_BUFFER, 0);
+
+    retval.indexObject = ctx.createBuffer();
+    ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, retval.indexObject);
+    ctx.bufferData(ctx.ELEMENT_ARRAY_BUFFER, indices, ctx.STATIC_DRAW);
+    ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, 0);
+
+    retval.numIndices = indices.length;
+
+    return retval;
+}
+
+//
+// makeSphere
+//
+// Create a sphere with the passed number of latitude and longitude bands and the passed radius.
+// Sphere has vertices, normals and texCoords. Create VBOs for each as well as the index array.
+// Return an object with the following properties:
+//
+//  normalObject        WebGLBuffer object for normals
+//  texCoordObject      WebGLBuffer object for texCoords
+//  vertexObject        WebGLBuffer object for vertices
+//  indexObject         WebGLBuffer object for indices
+//  numIndices          The number of indices in the indexObject
+//
+function makeSphere(ctx, radius, lats, longs)
+{
+    var geometryData = [ ];
+    var normalData = [ ];
+    var texCoordData = [ ];
+    var indexData = [ ];
+
+    for (var latNumber = 0; latNumber <= lats; ++latNumber) {
+        for (var longNumber = 0; longNumber <= longs; ++longNumber) {
+            var theta = latNumber * Math.PI / lats;
+            var phi = longNumber * 2 * Math.PI / longs;
+            var sinTheta = Math.sin(theta);
+            var sinPhi = Math.sin(phi);
+            var cosTheta = Math.cos(theta);
+            var cosPhi = Math.cos(phi);
+
+            var x = cosPhi * sinTheta;
+            var y = cosTheta;
+            var z = sinPhi * sinTheta;
+            var u = 1-(longNumber/longs);
+            var v = latNumber/lats;
+
+            normalData.push(x);
+            normalData.push(y);
+            normalData.push(z);
+            texCoordData.push(u);
+            texCoordData.push(v);
+            geometryData.push(radius * x);
+            geometryData.push(radius * y);
+            geometryData.push(radius * z);
+        }
+    }
+
+    longs += 1;
+    for (var latNumber = 0; latNumber < lats; ++latNumber) {
+        for (var longNumber = 0; longNumber < longs; ++longNumber) {
+            var first = (latNumber * longs) + (longNumber % longs);
+            var second = first + longs;
+            indexData.push(first);
+            indexData.push(second);
+            indexData.push(first+1);
+
+            indexData.push(second);
+            indexData.push(second+1);
+            indexData.push(first+1);
+        }
+    }
+
+    var retval = { };
+
+    retval.normalObject = ctx.createBuffer();
+    ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.normalObject);
+    ctx.bufferData(ctx.ARRAY_BUFFER, new WebGLFloatArray(normalData), ctx.STATIC_DRAW);
+
+    retval.texCoordObject = ctx.createBuffer();
+    ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.texCoordObject);
+    ctx.bufferData(ctx.ARRAY_BUFFER, new WebGLFloatArray(texCoordData), ctx.STATIC_DRAW);
+
+    retval.vertexObject = ctx.createBuffer();
+    ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.vertexObject);
+    ctx.bufferData(ctx.ARRAY_BUFFER, new WebGLFloatArray(geometryData), ctx.STATIC_DRAW);
+
+    retval.numIndices = indexData.length;
+    retval.indexObject = ctx.createBuffer();
+    ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, retval.indexObject);
+    ctx.bufferData(ctx.ELEMENT_ARRAY_BUFFER, new WebGLUnsignedShortArray(indexData), ctx.STREAM_DRAW);
+
+    return retval;
+}
+
+//
+// loadObj
+//
+// Load a .obj file from the passed URL. Return an object with a 'loaded' property set to false.
+// When the object load is complete, the 'loaded' property becomes true and the following
+// properties are set:
+//
+//  normalObject        WebGLBuffer object for normals
+//  texCoordObject      WebGLBuffer object for texCoords
+//  vertexObject        WebGLBuffer object for vertices
+//  indexObject         WebGLBuffer object for indices
+//  numIndices          The number of indices in the indexObject
+//
+function loadObj(ctx, url)
+{
+    var obj = { loaded : false };
+    obj.ctx = ctx;
+    var req = new XMLHttpRequest();
+    req.obj = obj;
+    req.onreadystatechange = function () { processLoadObj(req) };
+    req.open("GET", url, true);
+    req.send(null);
+    return obj;
+}
+
+function processLoadObj(req)
+{
+    webglTestLog("req="+req)
+    // only if req shows "complete"
+    if (req.readyState == 4) {
+        doLoadObj(req.obj, req.responseText);
+    }
+}
+
+function doLoadObj(obj, text)
+{
+    vertexArray = [ ];
+    normalArray = [ ];
+    textureArray = [ ];
+    indexArray = [ ];
+
+    var vertex = [ ];
+    var normal = [ ];
+    var texture = [ ];
+    var facemap = { };
+    var index = 0;
+
+    var lines = text.split("\n");
+    for (var lineIndex in lines) {
+        var line = lines[lineIndex].replace(/[ \t]+/g, " ").replace(/\s\s*$/, "");
+
+        // ignore comments
+        if (line[0] == "#")
+            continue;
+
+        var array = line.split(" ");
+        if (array[0] == "v") {
+            // vertex
+            vertex.push(parseFloat(array[1]));
+            vertex.push(parseFloat(array[2]));
+            vertex.push(parseFloat(array[3]));
+        }
+        else if (array[0] == "vt") {
+            // normal
+            texture.push(parseFloat(array[1]));
+            texture.push(parseFloat(array[2]));
+        }
+        else if (array[0] == "vn") {
+            // normal
+            normal.push(parseFloat(array[1]));
+            normal.push(parseFloat(array[2]));
+            normal.push(parseFloat(array[3]));
+        }
+        else if (array[0] == "f") {
+            // face
+            if (array.length != 4) {
+                webglTestLog("*** Error: face '"+line+"' not handled");
+                continue;
+            }
+
+            for (var i = 1; i < 4; ++i) {
+                if (!(array[i] in facemap)) {
+                    // add a new entry to the map and arrays
+                    var f = array[i].split("/");
+                    var vtx, nor, tex;
+
+                    if (f.length == 1) {
+                        vtx = parseInt(f[0]) - 1;
+                        nor = vtx;
+                        tex = vtx;
+                    }
+                    else if (f.length = 3) {
+                        vtx = parseInt(f[0]) - 1;
+                        tex = parseInt(f[1]) - 1;
+                        nor = parseInt(f[2]) - 1;
+                    }
+                    else {
+                        webglTestLog("*** Error: did not understand face '"+array[i]+"'");
+                        return null;
+                    }
+
+                    // do the vertices
+                    var x = 0;
+                    var y = 0;
+                    var z = 0;
+                    if (vtx * 3 + 2 < vertex.length) {
+                        x = vertex[vtx*3];
+                        y = vertex[vtx*3+1];
+                        z = vertex[vtx*3+2];
+                    }
+                    vertexArray.push(x);
+                    vertexArray.push(y);
+                    vertexArray.push(z);
+
+                    // do the textures
+                    x = 0;
+                    y = 0;
+                    if (tex * 2 + 1 < texture.length) {
+                        x = texture[tex*2];
+                        y = texture[tex*2+1];
+                    }
+                    textureArray.push(x);
+                    textureArray.push(y);
+
+                    // do the normals
+                    x = 0;
+                    y = 0;
+                    z = 1;
+                    if (nor * 3 + 2 < normal.length) {
+                        x = normal[nor*3];
+                        y = normal[nor*3+1];
+                        z = normal[nor*3+2];
+                    }
+                    normalArray.push(x);
+                    normalArray.push(y);
+                    normalArray.push(z);
+
+                    facemap[array[i]] = index++;
+                }
+
+                indexArray.push(facemap[array[i]]);
+            }
+        }
+    }
+
+    // set the VBOs
+    obj.normalObject = obj.ctx.createBuffer();
+    obj.ctx.bindBuffer(obj.ctx.ARRAY_BUFFER, obj.normalObject);
+    obj.ctx.bufferData(obj.ctx.ARRAY_BUFFER, new WebGLFloatArray(normalArray), obj.ctx.STATIC_DRAW);
+
+    obj.texCoordObject = obj.ctx.createBuffer();
+    obj.ctx.bindBuffer(obj.ctx.ARRAY_BUFFER, obj.texCoordObject);
+    obj.ctx.bufferData(obj.ctx.ARRAY_BUFFER, new WebGLFloatArray(textureArray), obj.ctx.STATIC_DRAW);
+
+    obj.vertexObject = obj.ctx.createBuffer();
+    obj.ctx.bindBuffer(obj.ctx.ARRAY_BUFFER, obj.vertexObject);
+    obj.ctx.bufferData(obj.ctx.ARRAY_BUFFER, new WebGLFloatArray(vertexArray), obj.ctx.STATIC_DRAW);
+
+    obj.numIndices = indexArray.length;
+    obj.indexObject = obj.ctx.createBuffer();
+    obj.ctx.bindBuffer(obj.ctx.ELEMENT_ARRAY_BUFFER, obj.indexObject);
+    obj.ctx.bufferData(obj.ctx.ELEMENT_ARRAY_BUFFER, new WebGLUnsignedShortArray(indexArray), obj.ctx.STREAM_DRAW);
+
+    obj.loaded = true;
+}
+
+//
+// loadImageTexture
+//