Bug 1534937 - Update webgl-conf checkout to tip. r=lsalzman
authorJeff Gilbert <jgilbert@mozilla.com>
Wed, 24 Apr 2019 03:34:48 +0000
changeset 530030 74842652868985ee3ff7b7c0e895e2c31da7533d
parent 530029 2e4a7bcc1a95d8761359d693f242453d2ceae6cf
child 530031 dc42ae4e7a3a98147cee86a53923bfffdf77e1de
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslsalzman
bugs1534937
milestone68.0a1
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
Bug 1534937 - Update webgl-conf checkout to tip. r=lsalzman Differential Revision: https://phabricator.services.mozilla.com/D28592
dom/canvas/test/webgl-conf/checkout/README.md
dom/canvas/test/webgl-conf/checkout/conformance/attribs/00_test_list.txt
dom/canvas/test/webgl-conf/checkout/conformance/attribs/gl-bindAttribLocation-aliasing.html
dom/canvas/test/webgl-conf/checkout/conformance/attribs/gl-disabled-vertex-attrib-update.html
dom/canvas/test/webgl-conf/checkout/conformance/attribs/gl-vertex-attrib-context-switch.html
dom/canvas/test/webgl-conf/checkout/conformance/attribs/gl-vertex-attrib-unconsumed-out-of-bounds.html
dom/canvas/test/webgl-conf/checkout/conformance/buffers/00_test_list.txt
dom/canvas/test/webgl-conf/checkout/conformance/buffers/vertex-buffer-updated-after-draw.html
dom/canvas/test/webgl-conf/checkout/conformance/context/deleted-object-behavior.html
dom/canvas/test/webgl-conf/checkout/conformance/extensions/00_test_list.txt
dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float-linear.html
dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float-with-video.html
dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float.html
dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float-linear.html
dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float-with-video.html
dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float.html
dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-compressed-texture-astc.html
dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-compressed-texture-s3tc.html
dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-depth-texture.html
dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-draw-buffers-feedback-loop.html
dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-draw-buffers.html
dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-multi-draw.html
dom/canvas/test/webgl-conf/checkout/conformance/glsl/samplers/glsl-function-texture2dprojlod.html
dom/canvas/test/webgl-conf/checkout/conformance/more/00_test_list.txt
dom/canvas/test/webgl-conf/checkout/conformance/more/conformance/quickCheckAPI.js
dom/canvas/test/webgl-conf/checkout/conformance/more/demos/opengl_web.html
dom/canvas/test/webgl-conf/checkout/conformance/more/demos/video.html
dom/canvas/test/webgl-conf/checkout/conformance/more/functions/bufferSubDataBadArgs.html
dom/canvas/test/webgl-conf/checkout/conformance/more/functions/drawArrays.html
dom/canvas/test/webgl-conf/checkout/conformance/more/functions/drawArraysOutOfBounds.html
dom/canvas/test/webgl-conf/checkout/conformance/more/functions/texImage2DBadArgs.html
dom/canvas/test/webgl-conf/checkout/conformance/more/functions/texSubImage2DBadArgs.html
dom/canvas/test/webgl-conf/checkout/conformance/more/glsl/longLoops.html
dom/canvas/test/webgl-conf/checkout/conformance/more/glsl/unusedAttribsUniforms.html
dom/canvas/test/webgl-conf/checkout/conformance/more/performance/CPUvsGPU.html
dom/canvas/test/webgl-conf/checkout/conformance/more/performance/bandwidth.html
dom/canvas/test/webgl-conf/checkout/conformance/more/performance/jsGCPause.html
dom/canvas/test/webgl-conf/checkout/conformance/more/performance/jsMatrixMult.html
dom/canvas/test/webgl-conf/checkout/conformance/more/performance/jsToGLOverhead.html
dom/canvas/test/webgl-conf/checkout/conformance/more/util.js
dom/canvas/test/webgl-conf/checkout/conformance/offscreencanvas/context-attribute-preserve-drawing-buffer.html
dom/canvas/test/webgl-conf/checkout/conformance/offscreencanvas/offscreencanvas-resize.html
dom/canvas/test/webgl-conf/checkout/conformance/reading/fbo-remains-unchanged-after-read-pixels.html
dom/canvas/test/webgl-conf/checkout/conformance/reading/read-pixels-pack-alignment.html
dom/canvas/test/webgl-conf/checkout/conformance/reading/read-pixels-test.html
dom/canvas/test/webgl-conf/checkout/conformance/rendering/00_test_list.txt
dom/canvas/test/webgl-conf/checkout/conformance/rendering/blending.html
dom/canvas/test/webgl-conf/checkout/conformance/rendering/color-mask-preserved-during-implicit-clears.html
dom/canvas/test/webgl-conf/checkout/conformance/rendering/draw-webgl-to-canvas-2d-repeatedly.html
dom/canvas/test/webgl-conf/checkout/conformance/rendering/out-of-bounds-array-buffers.html
dom/canvas/test/webgl-conf/checkout/conformance/rendering/out-of-bounds-index-buffers.html
dom/canvas/test/webgl-conf/checkout/conformance/rendering/rendering-sampling-feedback-loop.html
dom/canvas/test/webgl-conf/checkout/conformance/textures/misc/00_test_list.txt
dom/canvas/test/webgl-conf/checkout/conformance/textures/misc/canvas-teximage-after-multiple-drawimages.html
dom/canvas/test/webgl-conf/checkout/conformance/textures/misc/compressed-tex-image.html
dom/canvas/test/webgl-conf/checkout/conformance/textures/misc/tex-video-using-tex-unit-non-zero.html
dom/canvas/test/webgl-conf/checkout/conformance/textures/misc/texture-active-bind.html
dom/canvas/test/webgl-conf/checkout/conformance/textures/misc/texture-npot-video.html
dom/canvas/test/webgl-conf/checkout/conformance/textures/misc/texture-size-limit.html
dom/canvas/test/webgl-conf/checkout/conformance/textures/misc/texture-video-transparent.html
dom/canvas/test/webgl-conf/checkout/conformance2/buffers/get-buffer-sub-data-validity.html
dom/canvas/test/webgl-conf/checkout/conformance2/extensions/00_test_list.txt
dom/canvas/test/webgl-conf/checkout/conformance2/extensions/ext-float-blend.html
dom/canvas/test/webgl-conf/checkout/conformance2/extensions/ovr_multiview2.html
dom/canvas/test/webgl-conf/checkout/conformance2/extensions/ovr_multiview2_depth.html
dom/canvas/test/webgl-conf/checkout/conformance2/extensions/ovr_multiview2_draw_buffers.html
dom/canvas/test/webgl-conf/checkout/conformance2/extensions/ovr_multiview2_flat_varying.html
dom/canvas/test/webgl-conf/checkout/conformance2/extensions/ovr_multiview2_instanced_draw.html
dom/canvas/test/webgl-conf/checkout/conformance2/extensions/ovr_multiview2_non_multiview_shaders.html
dom/canvas/test/webgl-conf/checkout/conformance2/extensions/ovr_multiview2_single_view_operations.html
dom/canvas/test/webgl-conf/checkout/conformance2/extensions/ovr_multiview2_timer_query.html
dom/canvas/test/webgl-conf/checkout/conformance2/extensions/ovr_multiview2_transform_feedback.html
dom/canvas/test/webgl-conf/checkout/conformance2/extensions/webgl_multiview.html
dom/canvas/test/webgl-conf/checkout/conformance2/extensions/webgl_multiview_depth.html
dom/canvas/test/webgl-conf/checkout/conformance2/extensions/webgl_multiview_draw_buffers.html
dom/canvas/test/webgl-conf/checkout/conformance2/extensions/webgl_multiview_flat_varying.html
dom/canvas/test/webgl-conf/checkout/conformance2/extensions/webgl_multiview_instanced_draw.html
dom/canvas/test/webgl-conf/checkout/conformance2/extensions/webgl_multiview_non_multiview_shaders.html
dom/canvas/test/webgl-conf/checkout/conformance2/extensions/webgl_multiview_single_view_operations.html
dom/canvas/test/webgl-conf/checkout/conformance2/extensions/webgl_multiview_timer_query.html
dom/canvas/test/webgl-conf/checkout/conformance2/extensions/webgl_multiview_transform_feedback.html
dom/canvas/test/webgl-conf/checkout/conformance2/rendering/00_test_list.txt
dom/canvas/test/webgl-conf/checkout/conformance2/rendering/blitframebuffer-resolve-to-back-buffer.html
dom/canvas/test/webgl-conf/checkout/conformance2/rendering/depth-stencil-feedback-loop.html
dom/canvas/test/webgl-conf/checkout/conformance2/rendering/draw-buffers.html
dom/canvas/test/webgl-conf/checkout/conformance2/rendering/framebuffer-texture-changing-base-level.html
dom/canvas/test/webgl-conf/checkout/conformance2/rendering/fs-color-type-mismatch-color-buffer-type.html
dom/canvas/test/webgl-conf/checkout/conformance2/rendering/rendering-sampling-feedback-loop.html
dom/canvas/test/webgl-conf/checkout/conformance2/rendering/vertex-id.html
dom/canvas/test/webgl-conf/checkout/conformance2/textures/misc/00_test_list.txt
dom/canvas/test/webgl-conf/checkout/conformance2/textures/misc/copy-texture-image.html
dom/canvas/test/webgl-conf/checkout/conformance2/textures/misc/generate-mipmap-with-large-base-level.html
dom/canvas/test/webgl-conf/checkout/conformance2/textures/misc/integer-cubemap-specification-order-bug.html
dom/canvas/test/webgl-conf/checkout/conformance2/textures/misc/npot-video-sizing.html
dom/canvas/test/webgl-conf/checkout/conformance2/textures/misc/tex-mipmap-levels.html
dom/canvas/test/webgl-conf/checkout/conformance2/textures/misc/tex-unpack-params-imagedata.html
dom/canvas/test/webgl-conf/checkout/conformance2/transform_feedback/00_test_list.txt
dom/canvas/test/webgl-conf/checkout/conformance2/transform_feedback/default_transform_feedback.html
dom/canvas/test/webgl-conf/checkout/conformance2/transform_feedback/transform_feedback.html
dom/canvas/test/webgl-conf/checkout/conformance2/uniforms/incompatible-texture-type-for-sampler.html
dom/canvas/test/webgl-conf/checkout/conformance2/vertex_arrays/00_test_list.txt
dom/canvas/test/webgl-conf/checkout/conformance2/vertex_arrays/vertex-array-object-and-disabled-attributes.html
dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuSkipList.js
dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuTestCase.js
dom/canvas/test/webgl-conf/checkout/deqp/functional/gles3/00_test_list.txt
dom/canvas/test/webgl-conf/checkout/deqp/functional/gles3/es3fFboColorbufferTests.js
dom/canvas/test/webgl-conf/checkout/deqp/functional/gles3/es3fLifetimeTests.js
dom/canvas/test/webgl-conf/checkout/deqp/functional/gles3/es3fNegativeVertexArrayApiTests.js
dom/canvas/test/webgl-conf/checkout/deqp/functional/gles3/es3fShaderOperatorTests.js
dom/canvas/test/webgl-conf/checkout/deqp/functional/gles3/es3fShaderTextureFunctionTests.js
dom/canvas/test/webgl-conf/checkout/deqp/functional/gles3/es3fTextureFilteringTests.js
dom/canvas/test/webgl-conf/checkout/deqp/functional/gles3/shaderoperator/00_test_list.txt
dom/canvas/test/webgl-conf/checkout/deqp/functional/gles3/shaderoperator/angle_and_trigonometry.html
dom/canvas/test/webgl-conf/checkout/deqp/functional/gles3/shaderoperator/binary_operator.html
dom/canvas/test/webgl-conf/checkout/deqp/functional/gles3/shaderoperator/bool_compare.html
dom/canvas/test/webgl-conf/checkout/deqp/functional/gles3/shaderoperator/common_functions.html
dom/canvas/test/webgl-conf/checkout/deqp/functional/gles3/shaderoperator/common_functions_00.html
dom/canvas/test/webgl-conf/checkout/deqp/functional/gles3/shaderoperator/common_functions_01.html
dom/canvas/test/webgl-conf/checkout/deqp/functional/gles3/shaderoperator/common_functions_02.html
dom/canvas/test/webgl-conf/checkout/deqp/functional/gles3/shaderoperator/common_functions_03.html
dom/canvas/test/webgl-conf/checkout/deqp/functional/gles3/shaderoperator/common_functions_04.html
dom/canvas/test/webgl-conf/checkout/deqp/functional/gles3/shaderoperator/common_functions_05.html
dom/canvas/test/webgl-conf/checkout/deqp/functional/gles3/shaderoperator/common_functions_06.html
dom/canvas/test/webgl-conf/checkout/deqp/functional/gles3/shaderoperator/float_compare.html
dom/canvas/test/webgl-conf/checkout/deqp/functional/gles3/shaderoperator/geometric.html
dom/canvas/test/webgl-conf/checkout/deqp/functional/gles3/shaderoperator/int_compare.html
dom/canvas/test/webgl-conf/checkout/deqp/functional/gles3/shaderoperator/selection.html
dom/canvas/test/webgl-conf/checkout/deqp/functional/gles3/shaderoperator/sequence.html
dom/canvas/test/webgl-conf/checkout/deqp/functional/gles3/shaderoperator/shaderoperator_test_generator.py
dom/canvas/test/webgl-conf/checkout/deqp/functional/gles3/shaderoperator/unary_operator.html
dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsShaderExecUtil.js
dom/canvas/test/webgl-conf/checkout/deqp/temp_externs/html5.js
dom/canvas/test/webgl-conf/checkout/extra/tex-image-with-video-test.js
dom/canvas/test/webgl-conf/checkout/js/js-test-pre.js
dom/canvas/test/webgl-conf/checkout/js/tests/canvas-tests-utils.js
dom/canvas/test/webgl-conf/checkout/js/tests/ext-float-blend.js
dom/canvas/test/webgl-conf/checkout/js/tests/iterable-test.js
dom/canvas/test/webgl-conf/checkout/js/tests/oes-texture-float-and-half-float-linear.js
dom/canvas/test/webgl-conf/checkout/js/tests/out-of-bounds-test.js
dom/canvas/test/webgl-conf/checkout/js/tests/ovr_multiview2_util.js
dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-canvas-sub-rectangle.js
dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-canvas.js
dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-video.js
dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-data.js
dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-video.js
dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-webgl-canvas.js
dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-video.js
dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-video.js
dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-with-image-bitmap-utils.js
dom/canvas/test/webgl-conf/checkout/js/tests/texture-corner-case-videos.js
dom/canvas/test/webgl-conf/checkout/js/tests/webgl-compressed-texture-size-limit.js
dom/canvas/test/webgl-conf/checkout/js/tests/webgl_multiview_util.js
dom/canvas/test/webgl-conf/checkout/js/webgl-test-utils.js
dom/canvas/test/webgl-conf/checkout/performance/parallel_shader_compile/index.html
dom/canvas/test/webgl-conf/checkout/performance/parallel_shader_compile/shaders/aquarium/README
dom/canvas/test/webgl-conf/checkout/performance/parallel_shader_compile/shaders/aquarium/shader-cache.txt
dom/canvas/test/webgl-conf/checkout/resources/transparent-2frames.webm
dom/canvas/test/webgl-conf/checkout/test-guidelines.md
dom/canvas/test/webgl-conf/checkout/webgl-conformance-tests.html
dom/canvas/test/webgl-conf/cherry_picks.txt
dom/canvas/test/webgl-conf/generated-mochitest.ini
dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__ext-float-blend.html
dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__ovr_multiview2.html
dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__ovr_multiview2_depth.html
dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__ovr_multiview2_draw_buffers.html
dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__ovr_multiview2_flat_varying.html
dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__ovr_multiview2_instanced_draw.html
dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__ovr_multiview2_non_multiview_shaders.html
dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__ovr_multiview2_single_view_operations.html
dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__ovr_multiview2_timer_query.html
dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__ovr_multiview2_transform_feedback.html
dom/canvas/test/webgl-conf/generated/test_2_conformance2__rendering__vertex-id.html
dom/canvas/test/webgl-conf/generated/test_2_conformance2__textures__misc__generate-mipmap-with-large-base-level.html
dom/canvas/test/webgl-conf/generated/test_2_conformance2__transform_feedback__default_transform_feedback.html
dom/canvas/test/webgl-conf/generated/test_2_conformance2__vertex_arrays__vertex-array-object-and-disabled-attributes.html
dom/canvas/test/webgl-conf/generated/test_2_conformance__attribs__gl-disabled-vertex-attrib-update.html
dom/canvas/test/webgl-conf/generated/test_2_conformance__attribs__gl-vertex-attrib-context-switch.html
dom/canvas/test/webgl-conf/generated/test_2_conformance__buffers__vertex-buffer-updated-after-draw.html
dom/canvas/test/webgl-conf/generated/test_2_conformance__extensions__webgl-multi-draw.html
dom/canvas/test/webgl-conf/generated/test_2_conformance__rendering__blending.html
dom/canvas/test/webgl-conf/generated/test_2_conformance__rendering__color-mask-preserved-during-implicit-clears.html
dom/canvas/test/webgl-conf/generated/test_2_conformance__rendering__draw-webgl-to-canvas-2d-repeatedly.html
dom/canvas/test/webgl-conf/generated/test_2_conformance__rendering__out-of-bounds-array-buffers.html
dom/canvas/test/webgl-conf/generated/test_2_conformance__rendering__rendering-sampling-feedback-loop.html
dom/canvas/test/webgl-conf/generated/test_2_conformance__textures__misc__texture-video-transparent.html
dom/canvas/test/webgl-conf/generated/test_2_deqp__functional__gles3__shaderoperator__common_functions_00.html
dom/canvas/test/webgl-conf/generated/test_2_deqp__functional__gles3__shaderoperator__common_functions_01.html
dom/canvas/test/webgl-conf/generated/test_2_deqp__functional__gles3__shaderoperator__common_functions_02.html
dom/canvas/test/webgl-conf/generated/test_2_deqp__functional__gles3__shaderoperator__common_functions_03.html
dom/canvas/test/webgl-conf/generated/test_2_deqp__functional__gles3__shaderoperator__common_functions_04.html
dom/canvas/test/webgl-conf/generated/test_2_deqp__functional__gles3__shaderoperator__common_functions_05.html
dom/canvas/test/webgl-conf/generated/test_2_deqp__functional__gles3__shaderoperator__common_functions_06.html
dom/canvas/test/webgl-conf/generated/test_conformance__attribs__gl-disabled-vertex-attrib-update.html
dom/canvas/test/webgl-conf/generated/test_conformance__attribs__gl-vertex-attrib-context-switch.html
dom/canvas/test/webgl-conf/generated/test_conformance__buffers__vertex-buffer-updated-after-draw.html
dom/canvas/test/webgl-conf/generated/test_conformance__extensions__webgl-multi-draw.html
dom/canvas/test/webgl-conf/generated/test_conformance__rendering__blending.html
dom/canvas/test/webgl-conf/generated/test_conformance__rendering__color-mask-preserved-during-implicit-clears.html
dom/canvas/test/webgl-conf/generated/test_conformance__rendering__draw-webgl-to-canvas-2d-repeatedly.html
dom/canvas/test/webgl-conf/generated/test_conformance__rendering__out-of-bounds-array-buffers.html
dom/canvas/test/webgl-conf/generated/test_conformance__rendering__rendering-sampling-feedback-loop.html
dom/canvas/test/webgl-conf/generated/test_conformance__textures__misc__texture-video-transparent.html
dom/canvas/test/webgl-conf/mochitest-errata.ini
--- a/dom/canvas/test/webgl-conf/checkout/README.md
+++ b/dom/canvas/test/webgl-conf/checkout/README.md
@@ -18,18 +18,17 @@ a formal conformance submission.
 1. Open webgl-conformance-tests.html in your target browser
 
 2. Press the "run tests" button
 
 3. At the end of the run, press "display text summary"
 
 4. Verify that the User Agent and WebGL renderer strings identify your browser and target correctly.
 
-5. Copy the contents of the text summary (starting with "WebGL Conformance Test Results") and send via email to
-   webgl_conformance_submissions@khronos.org
+5. Submit a PR with the results to [https://github.com/KhronosGroup/WebGLConformanceSubmissions].
 
 Please see CONFORMANCE_RULES.txt in this directory for guidelines
 about what constitutes a conformant WebGL implementation.
 
 Usage Notes:
 ------------
 
 There are various URL options you can pass in.
@@ -72,9 +71,9 @@ History
 The dates below are when work on the conformance suite version was started.
 
 - 2011/02/24: Version 1.0.0
 - 2012/02/23: Version 1.0.1
 - 2012/03/20: Version 1.0.2
 - 2013/02/14: Version 1.0.3
 - 2013/10/11: Version 2.0.0
 - 2014/11/14: Version 1.0.4
-- 2016/11/21: Version 2.0.1
\ No newline at end of file
+- 2016/11/21: Version 2.0.1
--- a/dom/canvas/test/webgl-conf/checkout/conformance/attribs/00_test_list.txt
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/attribs/00_test_list.txt
@@ -1,13 +1,15 @@
 --min-version 1.0.3 gl-bindAttribLocation-aliasing.html
 --min-version 1.0.3 gl-bindAttribLocation-matrix.html
 --min-version 1.0.4 gl-bindAttribLocation-nonexistent-attribute.html
 --min-version 1.0.4 gl-bindAttribLocation-repeated.html
 --min-version 1.0.2 gl-disabled-vertex-attrib.html
+--min-version 1.0.4 gl-disabled-vertex-attrib-update.html
 gl-enable-vertex-attrib.html
 --min-version 1.0.3 gl-matrix-attributes.html
 --max-version 1.9.9 gl-vertex-attrib.html
 gl-vertexattribpointer.html
 gl-vertexattribpointer-offsets.html
 --min-version 1.0.2 gl-vertex-attrib-render.html
 gl-vertex-attrib-zero-issues.html
 --min-version 1.0.4 gl-vertex-attrib-unconsumed-out-of-bounds.html
+--min-version 1.0.4 gl-vertex-attrib-context-switch.html
--- a/dom/canvas/test/webgl-conf/checkout/conformance/attribs/gl-bindAttribLocation-aliasing.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/attribs/gl-bindAttribLocation-aliasing.html
@@ -1,31 +1,12 @@
 <!--
-/*
-** Copyright (c) 2014 The Khronos Group Inc.
-**
-** Permission is hereby granted, free of charge, to any person obtaining a
-** copy of this software and/or associated documentation files (the
-** "Materials"), to deal in the Materials without restriction, including
-** without limitation the rights to use, copy, modify, merge, publish,
-** distribute, sublicense, and/or sell copies of the Materials, and to
-** permit persons to whom the Materials are furnished to do so, subject to
-** the following conditions:
-**
-** The above copyright notice and this permission notice shall be included
-** in all copies or substantial portions of the Materials.
-**
-** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
-*/
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
 -->
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8">
 <link rel="stylesheet" href="../../resources/js-test-style.css"/>
 <script src="../../js/js-test-pre.js"></script>
 <script src="../../js/webgl-test-utils.js"></script>
new file mode 100644
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/attribs/gl-disabled-vertex-attrib-update.html
@@ -0,0 +1,100 @@
+<!--
+
+/*
+** Copyright (c) 2018 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL Disabled Vertex Attrib Update Test</title>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.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 a_position;
+attribute float a_actualValue;
+uniform float u_expectedValue;
+varying float v_result;
+void main() {
+  gl_Position = a_position;
+  v_result = a_actualValue == u_expectedValue ? 1.0 : 0.0;
+}
+</script>
+
+<script id="fshader" type="x-shader/x-fragment">
+precision mediump float;
+varying float v_result;
+void main() {
+  gl_FragColor = v_result > 0.0 ? vec4(0.0, 1.0, 0.0, 1.0) : vec4(1.0, 0.0, 0.0, 1.0);
+}
+</script>
+
+<script>
+// Tests that repeatedly updating a disabled vertex attribute works as expected.
+// This covers an ANGLE bug where dirty bits for current values were ignoring repeated updates.
+// Based on ANGLE test (VertexAttributeTest, DisabledAttribUpdates) from https://github.com/google/angle/blob/f7f0b8c3ab21c52cc2915048959361cf628d95f0/src/tests/gl_tests/VertexAttributeTest.cpp
+"use strict";
+var wtu = WebGLTestUtils;
+description();
+
+var gl = wtu.create3DContext("example");
+
+var program = wtu.setupProgram(gl, ['vshader', 'fshader']);
+gl.useProgram(program);
+
+var positionLocation = gl.getAttribLocation(program, "a_position");
+var attribLoc = gl.getAttribLocation(program, "a_actualValue");
+gl.vertexAttribPointer(attribLoc, 1, gl.FLOAT, gl.FALSE, 0, 0);
+
+var uniLoc = gl.getUniformLocation(program, "u_expectedValue");
+
+var gridRes = 1;
+wtu.setupIndexedQuad(gl, gridRes, positionLocation);
+
+var testValues = [1, 2, 3, 4];
+for (var i = 0; i < testValues.length; ++i) {
+  var testValue = testValues[i];
+  gl.uniform1f(uniLoc, testValue);
+  gl.vertexAttrib1f(attribLoc, testValue);
+  wtu.clearAndDrawIndexedQuad(gl, gridRes);
+  wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green");
+}
+
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/attribs/gl-vertex-attrib-context-switch.html
@@ -0,0 +1,79 @@
+<!--
+/*
+** Copyright (c) 2019 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+-->
+
+<!DOCTYPE html>
+<html>
+  <head>
+<meta charset="utf-8">
+    <title>WebGL Vertex Attrib Context Switch Test</title>
+    <link rel="stylesheet" href="../../resources/js-test-style.css"/>
+    <script src="../../js/js-test-pre.js"></script>
+    <script src="../../js/webgl-test-utils.js"> </script>
+</head>
+<body>
+<canvas id="one" width="50" height="50">
+</canvas>
+<canvas id="two" width="50" height="50">
+</canvas>
+<div id="description"></div>
+<div id="console"></div>
+<script>
+"use strict";
+description("tests that vertex attrib value is preserved across context switches");
+var wtu = WebGLTestUtils;
+var positionLocation = 0;
+var colorLocation = 1;
+var gridRes = 1;
+
+var canvas1 = document.getElementById("one");
+var gl1 = wtu.create3DContext(canvas1);
+var program1 = wtu.setupSimpleVertexColorProgram(gl1, positionLocation, colorLocation);
+gl1.vertexAttrib4f(colorLocation, 0.0, 1.0, 0.0, 1.0);
+wtu.setupIndexedQuad(gl1, gridRes, positionLocation);
+wtu.clearAndDrawIndexedQuad(gl1, gridRes);
+wtu.checkCanvas(gl1, [0, 255, 0, 255], "should be green 1");
+
+var canvas2 = document.getElementById("two");
+var gl2 = wtu.create3DContext(canvas2);
+var program2 = wtu.setupSimpleVertexColorProgram(gl2, positionLocation, colorLocation);
+wtu.setupIndexedQuad(gl2, gridRes, positionLocation);
+wtu.clearAndDrawIndexedQuad(gl2, gridRes);
+wtu.checkCanvas(gl2, [0, 0, 0, 255], "should be black 1");
+
+wtu.checkCanvas(gl1, [0, 255, 0, 255], "should be green 2");
+
+wtu.clearAndDrawIndexedQuad(gl2, gridRes);
+wtu.checkCanvas(gl2, [0, 0, 0, 255], "should be black 2");
+
+wtu.clearAndDrawIndexedQuad(gl1, gridRes);
+wtu.checkCanvas(gl1, [0, 255, 0, 255], "should be green 3");
+
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
+
--- a/dom/canvas/test/webgl-conf/checkout/conformance/attribs/gl-vertex-attrib-unconsumed-out-of-bounds.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/attribs/gl-vertex-attrib-unconsumed-out-of-bounds.html
@@ -46,17 +46,19 @@
 <script id="vshader_attrib" type="x-shader/x-vertex">
     attribute vec4 vPosition;
     void main() {
         gl_Position = vPosition;
     }
 </script>
 
 <script id="fshader" type="x-shader/x-fragment">
-    void main() { }
+    void main() {
+      gl_FragColor = vec4(1);
+    }
 </script>
 
 <script>
 "use strict";
 description("Test that unconsumed vertex attributes are not read out of bounds");
 // Tests for http://crbug.com/756293 (driver crash on macOS)
 // and a class of similar bugs that could exist on other systems.
 
--- a/dom/canvas/test/webgl-conf/checkout/conformance/buffers/00_test_list.txt
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/buffers/00_test_list.txt
@@ -5,9 +5,10 @@ buffer-data-and-buffer-sub-data.html
 --min-version 1.0.4 buffer-uninitialized.html
 --min-version 1.0.2 element-array-buffer-delete-recreate.html
 index-validation-copies-indices.html
 index-validation-crash-with-buffer-sub-data.html
 --min-version 1.0.2 index-validation-large-buffer.html
 index-validation-verifies-too-many-indices.html
 index-validation-with-resized-buffer.html
 index-validation.html
+--min-version 1.0.4 vertex-buffer-updated-after-draw.html
 
new file mode 100644
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/buffers/vertex-buffer-updated-after-draw.html
@@ -0,0 +1,115 @@
+<!--
+
+/*
+** Copyright (c) 2018 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL Vertex Buffer Updated After Draw Test</title>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.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 vec2 a_position;
+attribute vec4 a_color;
+varying vec4 v_outcolor;
+void main() {
+  gl_Position = vec4(a_position, 0, 1);
+  v_outcolor = a_color;
+}
+</script>
+
+<script id="fshader" type="x-shader/x-fragment">
+varying mediump vec4 v_outcolor;
+void main() {
+    gl_FragColor = v_outcolor;
+}
+</script>
+
+<script>
+// Tests that D3D11 dirty bit updates don't forget about BufferSubData attrib updates.
+// Based on ANGLE test (StateChangeTest, VertexBufferUpdatedAfterDraw) from https://github.com/google/angle/blob/f7f0b8c3ab21c52cc2915048959361cf628d95f0/src/tests/gl_tests/StateChangeTest.cpp
+"use strict";
+var wtu = WebGLTestUtils;
+description();
+
+var gl = wtu.create3DContext("example");
+
+var program = wtu.setupProgram(gl, ['vshader', 'fshader']);
+
+var colorLoc = gl.getAttribLocation(program, "a_color");
+var green = new Uint8Array(4 * 6);
+var red = new Uint8Array(4 * 6);
+
+for (var i = 0; i < 6; ++i) {
+  var ci = i * 4;
+
+  green[ci] = 0;
+  red[ci] = 255;
+
+  green[ci + 1] = 255;
+  red[ci + 1] = 0;
+
+  green[ci + 2] = red[ci + 2] = 0;
+
+  green[ci + 3] = red[ci + 3] = 255;
+}
+
+var positionLoc = gl.getAttribLocation(program, "a_position");
+
+var gridRes = 1;
+wtu.setupIndexedQuad(gl, gridRes, positionLoc);
+
+var colorBuf = gl.createBuffer();
+gl.bindBuffer(gl.ARRAY_BUFFER, colorBuf);
+gl.bufferData(gl.ARRAY_BUFFER, green, gl.STATIC_DRAW);
+gl.vertexAttribPointer(colorLoc, 4, gl.UNSIGNED_BYTE, true, 0, 0);
+gl.enableVertexAttribArray(colorLoc);
+
+wtu.clearAndDrawIndexedQuad(gl, gridRes);
+wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green");
+
+gl.bufferSubData(gl.ARRAY_BUFFER, 0, red);
+
+wtu.clearAndDrawIndexedQuad(gl, gridRes);
+wtu.checkCanvas(gl, [255, 0, 0, 255], "should be red");
+
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/context/deleted-object-behavior.html
@@ -0,0 +1,258 @@
+<!--
+
+/*
+** Copyright (c) 2019 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Deleted Object Behavior</title>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="canvases">
+<canvas id="canvas1">
+</div>
+<div id="console"></div>
+
+<script>
+"use strict";
+description("Verifies behavior of deleted objects");
+
+const wtu = WebGLTestUtils;
+const canvas1 = document.getElementById("canvas1");
+const sz = 64;
+canvas1.width = sz;
+canvas1.height = sz;
+const gl = wtu.create3DContext("canvas1");
+let tex, rb; // for shouldBe
+
+function testBoundFBOTexture() {
+  debug("Verifies that a texture attached to a bound framebuffer and then deleted is automatically detached");
+
+  let fb = gl.createFramebuffer();
+  gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+  tex = gl.createTexture();
+  gl.bindTexture(gl.TEXTURE_2D, tex);
+  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, sz, sz, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+  gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
+  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors during framebuffer setup");
+  // The WebGL 1.0 spec guarantees that this combination of attachments results
+  // in a complete framebuffer.
+  shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE",
+           "Framebuffer should be complete after setup");
+  debug("Texture should still be bound to the context");
+  shouldBe("gl.getParameter(gl.TEXTURE_BINDING_2D)", "tex");
+  // Delete the texture.
+  gl.deleteTexture(tex);
+  debug("Texture should have been unbound from the context");
+  shouldBeNull("gl.getParameter(gl.TEXTURE_BINDING_2D)");
+  debug("Framebuffer should report that the texture was detached");
+  shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)", "gl.NONE");
+  debug("Framebuffer should be incomplete after texture was deleted");
+  shouldNotBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
+  debug("Texture should not report that it's still a texture after deletion");
+  shouldBe("gl.isTexture(tex)", "false");
+  // Framebuffer should not function.
+  gl.clearColor(0.0, 1.0, 0.0, 1.0);
+  gl.clear(gl.COLOR_BUFFER_BIT);
+  wtu.glErrorShouldBe(gl, gl.INVALID_FRAMEBUFFER_OPERATION, "Framebuffer should not work after deleting its only attachment");
+  // Default framebuffer shouldn't have been touched.
+  gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+  wtu.checkCanvasRect(gl, 0, 0, sz, sz, [0, 0, 0, 0], "default framebuffer should be transparent black");
+  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors after verifying default framebuffer's contents");
+  // Attempt to bind deleted texture should fail.
+  gl.bindTexture(gl.TEXTURE_2D, tex);
+  wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "from binding deleted texture");
+  debug("");
+  gl.deleteFramebuffer(fb);
+}
+
+function testUnboundFBOTexture() {
+  debug("Verifies that a texture attached to an unbound framebuffer and then deleted remains usable until detached");
+
+  let fb = gl.createFramebuffer();
+  gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+  tex = gl.createTexture();
+  gl.bindTexture(gl.TEXTURE_2D, tex);
+  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, sz, sz, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+  gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
+  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors during framebuffer setup");
+  // The WebGL 1.0 spec guarantees that this combination of attachments results
+  // in a complete framebuffer.
+  shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE",
+           "Framebuffer should be complete after setup");
+  // Unbind the framebuffer from the context so that deleting the texture
+  // doesn't automatically unbind it from the framebuffer.
+  gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+  debug("Texture should still be bound to the context");
+  shouldBe("gl.getParameter(gl.TEXTURE_BINDING_2D)", "tex");
+  // Delete the texture.
+  gl.deleteTexture(tex);
+  debug("Texture should have been unbound from the context");
+  shouldBeNull("gl.getParameter(gl.TEXTURE_BINDING_2D)");
+  // Framebuffer should still be complete.
+  gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+  debug("Framebuffer should still be complete after texture was deleted");
+  shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
+  debug("Framebuffer should report that the texture is still attached");
+  shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", "tex");
+  debug("Texture should not report that it's still a texture after deletion");
+  shouldBe("gl.isTexture(tex)", "false");
+  // Framebuffer should still function.
+  gl.clearColor(0.0, 1.0, 0.0, 1.0);
+  gl.clear(gl.COLOR_BUFFER_BIT);
+  wtu.checkCanvasRect(gl, 0, 0, sz, sz, [0, 255, 0, 255], "framebuffer should be green");
+  // Deleting texture a second time should not unbind it from the framebuffer.
+  gl.deleteTexture(tex);
+  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "deleting an object twice is not an error");
+  debug("Framebuffer should still report that the texture is attached");
+  shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", "tex");
+  // Default framebuffer shouldn't have been touched.
+  gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+  wtu.checkCanvasRect(gl, 0, 0, sz, sz, [0, 0, 0, 0], "default framebuffer should be transparent black");
+  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors after verifying framebuffers' contents");
+  // Attempt to bind deleted texture should fail.
+  gl.bindTexture(gl.TEXTURE_2D, tex);
+  wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "from binding deleted texture");
+  debug("");
+  gl.deleteFramebuffer(fb);
+}
+
+function testBoundFBORenderbuffer() {
+  debug("Verifies that a renderbuffer attached to a bound framebuffer and then deleted is automatically detached");
+
+  let fb = gl.createFramebuffer();
+  gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+  rb = gl.createRenderbuffer();
+  gl.bindRenderbuffer(gl.RENDERBUFFER, rb);
+  gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, sz, sz)
+  gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb);
+  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors during framebuffer setup");
+  // The WebGL 1.0 spec doesn't guarantee that this framebuffer configuration
+  // will be complete.
+  if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
+    debug("Framebuffer with GL_RGBA4 renderbuffer was incomplete; skipping test");
+    return;
+  }
+  debug("Renderbuffer should still be bound to the context");
+  shouldBe("gl.getParameter(gl.RENDERBUFFER_BINDING)", "rb");
+  // Delete the renderbuffer.
+  gl.deleteRenderbuffer(rb);
+  debug("Renderbuffer should have been unbound from the context");
+  shouldBeNull("gl.getParameter(gl.RENDERBUFFER_BINDING)");
+  debug("Framebuffer should report that the texture was detached");
+  shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)", "gl.NONE");
+  debug("Framebuffer should be incomplete after renderbuffer was deleted");
+  shouldNotBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
+  debug("Renderbuffer should not report that it's still a renderbuffer after deletion");
+  shouldBe("gl.isRenderbuffer(rb)", "false");
+  // Framebuffer should not function.
+  gl.clearColor(0.0, 1.0, 0.0, 1.0);
+  gl.clear(gl.COLOR_BUFFER_BIT);
+  wtu.glErrorShouldBe(gl, gl.INVALID_FRAMEBUFFER_OPERATION, "Framebuffer should not work after deleting its only attachment");
+  // Default framebuffer shouldn't have been touched.
+  gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+  wtu.checkCanvasRect(gl, 0, 0, sz, sz, [0, 0, 0, 0], "default framebuffer should be transparent black");
+  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors after verifying framebuffers' contents");
+  // Attempt to bind deleted renderbuffer should fail.
+  gl.bindRenderbuffer(gl.RENDERBUFFER, rb);
+  wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "from binding deleted renderbuffer");
+  debug("");
+  gl.deleteFramebuffer(fb);
+}
+
+function testUnboundFBORenderbuffer() {
+  debug("Verifies that a renderbuffer attached to an unbound framebuffer and then deleted remains usable until detached");
+
+  let fb = gl.createFramebuffer();
+  gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+  rb = gl.createRenderbuffer();
+  gl.bindRenderbuffer(gl.RENDERBUFFER, rb);
+  gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, sz, sz)
+  gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb);
+  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors during framebuffer setup");
+  // The WebGL 1.0 spec doesn't guarantee that this framebuffer configuration
+  // will be complete.
+  if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
+    debug("Framebuffer with GL_RGBA4 renderbuffer was incomplete; skipping test");
+    return;
+  }
+  // Unbind the framebuffer from the context so that deleting the renderbuffer
+  // doesn't automatically unbind it from the framebuffer.
+  gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+  debug("Renderbuffer should still be bound to the context");
+  shouldBe("gl.getParameter(gl.RENDERBUFFER_BINDING)", "rb");
+  // Delete the renderbuffer.
+  gl.deleteRenderbuffer(rb);
+  debug("Renderbuffer should have been unbound from the context");
+  shouldBeNull("gl.getParameter(gl.RENDERBUFFER_BINDING)");
+  // Framebuffer should still be complete.
+  gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+  debug("Framebuffer should still be complete after renderbuffer was deleted");
+  shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
+  debug("Framebuffer should report that the renderbuffer is still attached");
+  shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", "rb");
+  debug("Renderbuffer should not report that it's still a renderbuffer after deletion");
+  shouldBe("gl.isRenderbuffer(rb)", "false");
+  // Framebuffer should still function.
+  gl.clearColor(0.0, 1.0, 0.0, 1.0);
+  gl.clear(gl.COLOR_BUFFER_BIT);
+  // Use a high tolerance to accommodate low bit depth precision.
+  wtu.checkCanvasRect(gl, 0, 0, sz, sz, [0, 255, 0, 255], "framebuffer should be green", 20);
+  // Deleting renderbuffer a second time should not unbind it from the framebuffer.
+  gl.deleteRenderbuffer(rb);
+  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "deleting an object twice is not an error");
+  debug("Framebuffer should still report that the renderbuffer is attached");
+  shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", "rb");
+  // Default framebuffer shouldn't have been touched.
+  gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+  wtu.checkCanvasRect(gl, 0, 0, sz, sz, [0, 0, 0, 0], "default framebuffer should be transparent black");
+  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors after verifying framebuffers' contents");
+  // Attempt to bind deleted renderbuffer should fail.
+  gl.bindRenderbuffer(gl.RENDERBUFFER, rb);
+  wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "from binding deleted renderbuffer");
+  debug("");
+  gl.deleteFramebuffer(fb);
+}
+
+function runTests() {
+  testBoundFBOTexture();
+  testUnboundFBOTexture();
+  testBoundFBORenderbuffer();
+  testUnboundFBORenderbuffer();
+  finishTest();
+}
+
+requestAnimationFrame(runTests);
+
+var successfullyParsed = true;
+</script>
+</body>
+</html>
--- a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/00_test_list.txt
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/00_test_list.txt
@@ -32,11 +32,11 @@ webgl-debug-shaders.html
 --min-version 1.0.4 webgl-compressed-texture-etc1.html
 --min-version 1.0.3 webgl-compressed-texture-pvrtc.html
 --min-version 1.0.2 webgl-compressed-texture-s3tc.html
 --min-version 1.0.4 webgl-compressed-texture-s3tc-srgb.html
 --min-version 1.0.3 webgl-compressed-texture-size-limit.html
 --min-version 1.0.2 --max-version 1.9.9 webgl-depth-texture.html
 --min-version 1.0.3 --max-version 1.9.9 webgl-draw-buffers.html
 --min-version 1.0.4 --max-version 1.9.9 webgl-draw-buffers-broadcast-return.html
---min-version 1.0.3 --max-version 1.9.9 webgl-draw-buffers-feedback-loop.html
 --min-version 1.0.4 --max-version 1.9.9 webgl-draw-buffers-framebuffer-unsupported.html
 --min-version 1.0.4 --max-version 1.9.9 webgl-draw-buffers-max-draw-buffers.html
+--min-version 1.0.4 webgl-multi-draw.html
--- a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float-linear.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float-linear.html
@@ -28,26 +28,36 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8">
 <link rel="stylesheet" href="../../resources/js-test-style.css"/>
 <script src="../../js/js-test-pre.js"></script>
 <script src="../../js/webgl-test-utils.js"></script>
 <script src="../../js/tests/oes-texture-float-and-half-float-linear.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
 <script>
 "use strict";
-function testPrologue(gl, extensionTypeName) {
-    if (!gl.getExtension(extensionTypeName)) {
-        testPassed("No " + extensionTypeName + " support -- this is legal");
-        return false;
+
+description("Test OES_texture_float_linear, if available.");
+
+const wtu = WebGLTestUtils;
+const gl = wtu.create3DContext();
+
+(function() {
+    if (!(gl instanceof WebGL2RenderingContext)) {
+        if (!gl.getExtension("OES_texture_float")) {
+            testPassed("No OES_texture_float support -- this is legal");
+            return;
+        }
     }
-    testPassed("Successfully enabled " + extensionTypeName + " extension");
-    return true;
-}
+    testTexLinear(gl, "OES_texture_float_linear", "RGBA32F", "FLOAT");
+})();
+
+debug("");
+const successfullyParsed = true;
 </script>
-</head>
-<body onload='generateTest("OES_texture_float", "OES_texture_float_linear", "FLOAT", testPrologue)()'>
-<div id="description"></div>
-<canvas id="canvas" style="width: 50px; height: 50px;"> </canvas>
-<div id="console"></div>
+<script src="../../js/js-test-post.js"></script>
 </body>
 </html>
--- a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float-with-video.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float-with-video.html
@@ -46,15 +46,15 @@ function testPrologue(gl) {
     return true;
 }
 </script>
 </head>
 <body onload='generateTest("RGBA", "RGBA", "FLOAT", testPrologue, "../../resources/")()'>
 <canvas id="example" width="32" height="32"></canvas>
 <div id="description"></div>
 <div id="console"></div>
-<video width="640" height="228" id="vid" controls>
+<video width="640" height="228" id="vid" controls muted>
   <source src="../../resources/red-green.mp4"  type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"' />
   <source src="../../resources/red-green.webmvp8.webm" type='video/webm; codecs="vp8, vorbis"' />
   <source src="../../resources/red-green.theora.ogv"  type='video/ogg; codecs="theora, vorbis"' />
 </video>
 </body>
 </html>
--- a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float.html
@@ -24,20 +24,21 @@
 */
 
 -->
 
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8">
-<title>WebGL OES_texture_float Conformance Tests</title>
+<title>OES_texture_float/WEBGL_color_buffer_float</title>
 <link rel="stylesheet" href="../../resources/js-test-style.css"/>
 <script src="../../js/js-test-pre.js"></script>
 <script src="../../js/webgl-test-utils.js"></script>
+<script src="../../js/tests/ext-float-blend.js"></script>
 </head>
 <body>
 <div id="description"></div>
 <canvas id="canvas" style="width: 50px; height: 50px;"> </canvas>
 <div id="console"></div>
 <!-- Shaders for testing floating-point textures -->
 <script id="testFragmentShader" type="x-shader/x-fragment">
 precision mediump float;
@@ -68,17 +69,17 @@ void main()
 <script id="floatingPointFragmentShader" type="x-shader/x-fragment">
 void main()
 {
     gl_FragColor = vec4(10000.0, 10000.0, 10000.0, 10000.0);
 }
 </script>
 <script>
 "use strict";
-description("This test verifies the functionality of the OES_texture_float extension, if it is available.");
+description("This test verifies the functionality of the OES_texture_float and WEBGL_color_buffer_float extensions, if available.");
 
 debug("");
 
 var wtu = WebGLTestUtils;
 var canvas = document.getElementById("canvas");
 var gl = wtu.create3DContext(canvas);
 
 if (!gl) {
@@ -122,16 +123,29 @@ if (!gl) {
             } else if (supported && !renderable) {
                 testFailed(renderableExtName + " is exposed but RGBA/FLOAT is not color renderable");
             }
             if (supported) {
                 runRenderTargetAndReadbackTest(testProgram, gl.RGBA, 4, [10000, 10000, 10000, 10000], 0, true);
                 runRenderTargetAndReadbackTest(testProgram, gl.RGB, 3, [10000, 10000, 10000, 1], 0, false);
                 runRenderTargetAndReadbackTest(testProgram, gl.RGBA, 4, [10000, 10000, 10000, 10000], 1, true);
                 runRenderTargetAndReadbackTest(testProgram, gl.RGBA, 4, [10000, 10000, 10000, 10000], 0.5, true);
+                runFramebufferTest();
+
+                debug("");
+                debug("Test float32 blending without EXT_float_blend.");
+                testExtFloatBlend(gl.RGBA);
+
+                debug("");
+                debug("Testing that float32 blending succeeds with EXT_float_blend.");
+                if (!gl.getExtension("EXT_float_blend")) {
+                    testPassed("No EXT_float_blend support -- this is legal");
+                    return;
+                }
+                testExtFloatBlend(gl.RGBA);
             }
         })();
 
         runUniqueObjectTest();
     }
 }
 
 function isRenderable(gl) {
@@ -310,16 +324,124 @@ function runUniqueObjectTest()
 {
     debug("");
     debug("Testing that getExtension() returns the same object each time");
     gl.getExtension("OES_texture_float").myProperty = 2;
     webglHarnessCollectGarbage();
     shouldBe('gl.getExtension("OES_texture_float").myProperty', '2');
 }
 
+// Make sure we can call readPixels with the passed in arrayBufferConstructor and that the color
+// channels are the ones we expect. If there is a mismatch between the glType and arrayBuffer type,
+// fail the test.
+function verifyReadPixelsColors(red, green, blue, alpha, alphaRGB, glFormat, glType, arrayBufferConstructor) {
+    var typeName = wtu.glEnumToString(gl, glType);
+
+    debug(wtu.glEnumToString(gl, glFormat) + " framebuffer with " + typeName + " readback.");
+
+    var arrayBuffer = new arrayBufferConstructor(4);
+    gl.readPixels(0, 0, 1, 1, gl.RGBA, glType, arrayBuffer);
+    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "readPixels should return NO_ERROR when reading " + typeName + " data.");
+
+    assertMsg(arrayBuffer[0] === red, "Red channel should be " + red + " for " + typeName + " readPixels. Received: " + arrayBuffer[0]);
+    assertMsg(arrayBuffer[1] === green, "Green channel should be " + green + " for " + typeName + " readPixels. Received: " + arrayBuffer[1]);
+    assertMsg(arrayBuffer[2] === blue, "Blue channel should be " + blue + " for " + typeName + " readPixels. Received: " + arrayBuffer[2]);
+    if (glFormat === gl.RGBA) {
+        assertMsg(arrayBuffer[3] === alpha, "Alpha channel should be " + alpha + " for " + typeName + " readPixels. Received: " + arrayBuffer[3]);
+    } else if (glFormat === gl.RGB) {
+        assertMsg(arrayBuffer[3] === alphaRGB, "Alpha channel should be " + alphaRGB + " for " + typeName + " readPixels. Received: " + arrayBuffer[3]);
+    }
+
+    // Make sure any arrayBuffer types that are not equal to arrayBufferConstructor fail readPixels.
+    if (arrayBufferConstructor !== Uint8Array) {
+        arrayBuffer = new Uint8Array(4);
+        gl.readPixels(0, 0, 1, 1, gl.RGBA, glType, arrayBuffer);
+        wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "readPixels should return INVALID_OPERATION when reading mismatched types. " + Uint8Array.toString());
+    }
+    if (arrayBufferConstructor !== Float32Array) {
+        arrayBuffer = new Float32Array(4);
+        gl.readPixels(0, 0, 1, 1, gl.RGBA, glType, arrayBuffer);
+        wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "readPixels should return INVALID_OPERATION when reading mismatched types. " + Float32Array.toString());
+    }
+    if (arrayBufferConstructor !== Uint16Array) {
+        arrayBuffer = new Uint16Array(4);
+        gl.readPixels(0, 0, 1, 1, gl.RGBA, glType, arrayBuffer);
+        wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "readPixels should return INVALID_OPERATION when reading mismatched types. " + Uint16Array.toString());
+    }
+}
+
+// Verify that float textures attached to frame buffers function correctly with regard to framebuffer
+// completness, IMPLEMENTATION_COLOR_READ_FORMAT/TYPE and readPixels
+function runFramebufferTest() {
+    debug("");
+    debug("Framebuffer Tests");
+
+    var texture = allocateTexture();
+    gl.bindTexture(gl.TEXTURE_2D, texture);
+
+    var fbo = gl.createFramebuffer();
+    gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
+
+    debug("Ensure non-color-renderable formats [LUMINANCE, LUMINANCE_ALPHA, ALPHA] fail.");
+    var arrayBufferFloatOutput = new Float32Array(4); // 4 color channels
+    [gl.LUMINANCE, gl.LUMINANCE_ALPHA, gl.ALPHA].forEach(function(badFormat) {
+        debug(wtu.glEnumToString(gl, badFormat) + " framebuffer");
+
+        gl.texImage2D(gl.TEXTURE_2D, 0, badFormat, 1, 1, 0, badFormat, gl.FLOAT, null);
+        shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
+
+        shouldBeNull("gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT)");
+        wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "IMPLEMENTATION_COLOR_READ_FORMAT should fail for incomplete framebuffers.");
+
+        shouldBeNull("gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE)");
+        wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "IMPLEMENTATION_COLOR_READ_TYPE should fail for incomplete framebuffers.");
+
+        gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.FLOAT, arrayBufferFloatOutput);
+        wtu.glErrorShouldBe(gl, gl.INVALID_FRAMEBUFFER_OPERATION , "readPixels should fail on incomplete framebuffers.");
+        debug("");
+    });
+
+    debug("Ensure color renderable formats [RGBA, RGB] succeed.");
+    var arrayBufferFloatInput = new Float32Array(4); // 4 color channels
+    arrayBufferFloatInput[0] = 0;
+    arrayBufferFloatInput[1] = .25;
+    arrayBufferFloatInput[2] = .50;
+    arrayBufferFloatInput[3] = .75;
+
+    [gl.RGBA, gl.RGB].forEach(function(goodFormat) {
+        debug("");
+        debug(wtu.glEnumToString(gl, goodFormat) + " framebuffer tests");
+
+        gl.texImage2D(gl.TEXTURE_2D, 0, goodFormat, 1, 1, 0, goodFormat, gl.FLOAT, arrayBufferFloatInput);
+        if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
+            testPassed("Format is not renderable. This is allowed.");
+            return;
+        }
+        verifyReadPixelsColors(
+            0.00, // red
+            0.25, // green
+            0.50, // blue
+            0.75, // alpha
+            1.0,  // alphaRGB
+            goodFormat,
+            gl.FLOAT,
+            Float32Array);
+
+        var implementationColorReadFormat = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT);
+        assertMsg(implementationColorReadFormat === gl.RGBA || implementationColorReadFormat === gl.RGB,
+            "IMPLEMENTATION_COLOR_READ_FORMAT should be color renderable: RGBA or RGB. Received: " + wtu.glEnumToString(gl, implementationColorReadFormat));
+
+        var implementationColorReadType = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE);
+        assertMsg(implementationColorReadType === gl.UNSIGNED_BYTE ||
+                  implementationColorReadType === gl.FLOAT ||
+                  "IMPLEMENTATION_COLOR_READ_TYPE must be one of UNSIGNED_BYTE or FLOAT " +
+                  "Received: " + wtu.glEnumToString(gl, implementationColorReadType));
+    });
+}
 
 debug("");
 var successfullyParsed = true;
 </script>
 <script src="../../js/js-test-post.js"></script>
 
 </body>
 </html>
--- a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float-linear.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float-linear.html
@@ -28,29 +28,40 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8">
 <link rel="stylesheet" href="../../resources/js-test-style.css"/>
 <script src="../../js/js-test-pre.js"></script>
 <script src="../../js/webgl-test-utils.js"></script>
 <script src="../../js/tests/oes-texture-float-and-half-float-linear.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
 <script>
 "use strict";
-function testPrologue(gl, extensionTypeName) {
-    var ext = null;
-    if (!(ext = gl.getExtension(extensionTypeName))) {
-        testPassed("No " + extensionTypeName + " support -- this is legal");
-        return false;
+
+description("Test OES_texture_half_float_linear, if available.");
+
+const wtu = WebGLTestUtils;
+const gl = wtu.create3DContext();
+
+(function() {
+    if (gl instanceof WebGL2RenderingContext)
+        throw new Error("OES_texture_half_float_linear is core in WebGL 2.");
+
+    const ext = gl.getExtension("OES_texture_half_float");
+    if (!ext) {
+        testPassed("No OES_texture_half_float support -- this is legal");
+        return;
     }
     // Required by the test harness.
     gl.HALF_FLOAT_OES = ext.HALF_FLOAT_OES;
-    testPassed("Successfully enabled " + extensionTypeName + " extension");
-    return true;
-}
+    testTexLinear(gl, "OES_texture_half_float_linear", undefined, "HALF_FLOAT_OES");
+})();
+
+debug("");
+const successfullyParsed = true;
 </script>
-</head>
-<body onload='generateTest("OES_texture_half_float", "OES_texture_half_float_linear", "HALF_FLOAT_OES", testPrologue)()'>
-<div id="description"></div>
-<canvas id="canvas" style="width: 50px; height: 50px;"> </canvas>
-<div id="console"></div>
+<script src="../../js/js-test-post.js"></script>
 </body>
 </html>
--- a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float-with-video.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float-with-video.html
@@ -51,15 +51,15 @@ function testPrologue(gl) {
     return true;
 }
 </script>
 </head>
 <body onload='generateTest("RGBA", "RGBA", "HALF_FLOAT_OES", testPrologue, "../../resources/")()'>
 <canvas id="example" width="32" height="32"></canvas>
 <div id="description"></div>
 <div id="console"></div>
-<video width="640" height="228" id="vid" controls>
+<video width="640" height="228" id="vid" controls muted>
   <source src="../../resources/red-green.mp4"  type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"' />
   <source src="../../resources/red-green.webmvp8.webm" type='video/webm; codecs="vp8, vorbis"' />
   <source src="../../resources/red-green.theora.ogv"  type='video/ogg; codecs="theora, vorbis"' />
 </video>
 </body>
 </html>
--- a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float.html
@@ -219,43 +219,16 @@ function getNumberOfChannels(format)
     else if (format == gl.RGB)
         return 3;
     else if (format == gl.LUMINANCE || format == gl.ALPHA)
         return 1;
     else if (format == gl.LUMINANCE_ALPHA)
         return 2;
 }
 
-function getFormatName(format)
-{
-    if (format == gl.RGBA)
-        return "RGBA";
-    else if (format == gl.RGB)
-        return "RGB";
-    else if (format == gl.LUMINANCE)
-        return "LUMINANCE";
-    else if (format == gl.ALPHA)
-        return "ALPHA";
-    else if (format == gl.LUMINANCE_ALPHA)
-        return "LUMINANCE_ALPHA";
-}
-
-function getTypeName(type) {
-    if (type === gl.UNSIGNED_BYTE)
-        return "UNSIGNED_BYTE";
-    else if (type === ext.HALF_FLOAT_OES)
-        return "HALF_FLOAT_OES";
-    else if (type === gl.UNSIGNED_SHORT_4_4_4_4)
-        return "UNSIGNED_SHORT_4_4_4_4";
-    else if (type === gl.UNSIGNED_SHORT_5_5_5_1)
-        return "UNSIGNED_SHORT_5_6_5";
-    else if (type === gl.FLOAT)
-        return "FLOAT";
-}
-
 function allocateTexture()
 {
     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);
     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);
@@ -267,17 +240,17 @@ function runTextureCreationTest(extensio
 {
     var format = opt_format || gl.RGBA;
     var data = opt_data || null;
     var expectSuccess = true;
 
     if (!extensionEnabled || !opt_expected)
         expectSuccess = false;
     debug("Testing texture creation with extension " + (extensionEnabled ? "enabled" : "disabled") +
-          ", format " + getFormatName(format) + ", and data " + (data ? "non-null" : "null") +
+          ", format " + wtu.glEnumToString(gl, format) + ", and data " + (data ? "non-null" : "null") +
           ". Expect " + (expectSuccess ? "Success" : "Failure"));
 
     var texture = allocateTexture();
     var width = 2;
     var height = 2;
     gl.texImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, format, halfFloatOESEnum, data);
     if(!extensionEnabled) {
         wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "Half floating point texture must be disallowed if OES_texture_half_float isn't enabled");
@@ -381,19 +354,19 @@ function runUniqueObjectTest()
     webglHarnessCollectGarbage();
     shouldBe('gl.getExtension("OES_texture_half_float").myProperty', '2');
 }
 
 // Make sure we can call readPixels with the passed in arrayBufferConstructor and that the color
 // channels are the ones we expect. If there is a mismatch between the glType and arrayBuffer type,
 // fail the test.
 function verifyReadPixelsColors(red, green, blue, alpha, alphaRGB, glFormat, glType, arrayBufferConstructor) {
-    var typeName = getTypeName(glType);
+    var typeName = wtu.glEnumToString(gl, glType);
 
-    debug(getFormatName(glFormat) + " framebuffer with " + typeName + " readback.");
+    debug(wtu.glEnumToString(gl, glFormat) + " framebuffer with " + typeName + " readback.");
 
     var arrayBuffer = new arrayBufferConstructor(4);
     gl.readPixels(0, 0, 1, 1, gl.RGBA, glType, arrayBuffer);
     wtu.glErrorShouldBe(gl, gl.NO_ERROR, "readPixels should return NO_ERROR when reading " + typeName + " data.");
 
     assertMsg(arrayBuffer[0] === red, "Red channel should be " + red + " for " + typeName + " readPixels. Received: " + arrayBuffer[0]);
     assertMsg(arrayBuffer[1] === green, "Green channel should be " + green + " for " + typeName + " readPixels. Received: " + arrayBuffer[1]);
     assertMsg(arrayBuffer[2] === blue, "Blue channel should be " + blue + " for " + typeName + " readPixels. Received: " + arrayBuffer[2]);
@@ -432,17 +405,17 @@ function runFramebufferTest() {
 
     var fbo = gl.createFramebuffer();
     gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
     gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
 
     debug("Ensure non-color-renderable formats [LUMINANCE, LUMINANCE_ALPHA, ALPHA] fail.");
     var arrayBufferFloatOutput = new Float32Array(4); // 4 color channels
     [gl.LUMINANCE, gl.LUMINANCE_ALPHA, gl.ALPHA].forEach(function(badFormat) {
-        debug(getFormatName(badFormat) + " framebuffer");
+        debug(wtu.glEnumToString(gl, badFormat) + " framebuffer");
 
         gl.texImage2D(gl.TEXTURE_2D, 0, badFormat, 1, 1, 0, badFormat, ext.HALF_FLOAT_OES, null);
         shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
 
         shouldBeNull("gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT)");
         wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "IMPLEMENTATION_COLOR_READ_FORMAT should fail for incomplete framebuffers.");
 
         shouldBeNull("gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE)");
@@ -456,17 +429,17 @@ function runFramebufferTest() {
     debug("Ensure color renderable formats [RGBA, RGB] succeed.");
     var arrayBufferHalfFloatInput = new Uint16Array(4); // 4 color channels
     arrayBufferHalfFloatInput[0] = 0;      // 0 in half float
     arrayBufferHalfFloatInput[1] = 0x3400; // 0.25 in half float
     arrayBufferHalfFloatInput[2] = 0x3800; // 0.50 in half float
     arrayBufferHalfFloatInput[3] = 0x3A00; // 0.75 in half float
 
     [gl.RGBA, gl.RGB].forEach(function(goodFormat) {
-        debug(getFormatName(goodFormat) + " framebuffer tests");
+        debug(wtu.glEnumToString(gl, goodFormat) + " framebuffer tests");
         debug("");
 
         gl.texImage2D(gl.TEXTURE_2D, 0, goodFormat, 1, 1, 0, goodFormat, ext.HALF_FLOAT_OES, arrayBufferHalfFloatInput);
         if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE) {
             // Per the OES_color_buffer_half_float, RGBA/FLOAT should always succeed for readPixels
             verifyReadPixelsColors(
                 0.00, // red
                 0.25, // green
@@ -474,32 +447,32 @@ function runFramebufferTest() {
                 0.75, // alpha
                 1.0,  // alphaRGB
                 goodFormat,
                 gl.FLOAT,
                 Float32Array);
 
             var implementationColorReadFormat = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT);
             assertMsg(implementationColorReadFormat === gl.RGBA || implementationColorReadFormat === gl.RGB,
-                "IMPLEMENTATION_COLOR_READ_FORMAT should be color renderable: RGBA or RGB. Received: " + getFormatName(implementationColorReadFormat));
+                "IMPLEMENTATION_COLOR_READ_FORMAT should be color renderable: RGBA or RGB. Received: " + wtu.glEnumToString(gl, implementationColorReadFormat));
 
             var implementationColorReadType = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE);
 
             // There is nothing in the specifications that keeps the
             // implementation color read format and type from being the
             // same as the implicitly supported one. For this reason, keep
             // gl.FLOAT as one of the valid options.
             assertMsg(implementationColorReadType === gl.UNSIGNED_BYTE ||
                       implementationColorReadType === gl.FLOAT ||
                       implementationColorReadType === ext.HALF_FLOAT_OES ||
                       implementationColorReadType === gl.UNSIGNED_SHORT_4_4_4_4 ||
                       implementationColorReadType === gl.UNSIGNED_SHORT_5_5_5_1 ||
                       implementationColorReadType === gl.UNSIGNED_SHORT_5_6_5,
                       "IMPLEMENTATION_COLOR_READ_TYPE must be one of UNSIGNED_BYTE, UNSIGNED_SHORT_4_4_4_4, UNSIGNED_SHORT_5_5_5_1, UNSIGNED_SHORT_5_6_5, FLOAT, or HALF_FLOAT_OES. " +
-                      "Received: " + getTypeName(implementationColorReadType));
+                      "Received: " + wtu.glEnumToString(gl, implementationColorReadType));
 
             // Test the RGBA/HALF_FLOAT_OES combination
             if (implementationColorReadFormat === gl.RGBA && implementationColorReadType === ext.HALF_FLOAT_OES) {
                 verifyReadPixelsColors(
                     0,      // red
                     0x3400, // green
                     0x3800, // blue
                     0x3A00, // alpha
--- a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-compressed-texture-astc.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-compressed-texture-astc.html
@@ -1780,18 +1780,18 @@ function testASTCTexture(test, useTexSto
     gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
     gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
     gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
     if (useTexStorage) {
         gl.texStorage2D(gl.TEXTURE_2D, 1, format, width, height);
         wtu.glErrorShouldBe(gl, gl.NO_ERROR, "allocating compressed texture via texStorage2D");
         wtu.clearAndDrawUnitQuad(gl);
         wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing unit quad");
-        var clearColor = [0, 0, 0, 0];
-        wtu.checkCanvas(gl, clearColor, "texture should be initialized to black");
+        var clearColor = [255, 0, 255, 255];
+        wtu.checkCanvas(gl, clearColor, "texture should be initialized to error color");
         gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, format, data);
         wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture data via compressedTexSubImage2D");
     } else {
         gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, data);
         wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture");
     }
 
     wtu.clearAndDrawUnitQuad(gl);
--- a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-compressed-texture-s3tc.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-compressed-texture-s3tc.html
@@ -152,16 +152,21 @@ function runTestExtension() {
     // Test that texture upload buffer size is validated correctly.
     ctu.testFormatRestrictionsOnBufferSize(gl, validFormats, expectedByteLength, getBlockDimensions);
 
     // Test each format
     testDXT1_RGB();
     testDXT1_RGBA();
     testDXT3_RGBA();
     testDXT5_RGBA();
+
+    // Test compressed PBOs with a single format
+    if (contextVersion >= 2) {
+        testDXT5_RGBA_PBO();
+    }
 }
 
 function testDXT1_RGB() {
     var tests = [
         {   width: 4,
             height: 4,
             channels: 3,
             data: img_4x4_rgb_dxt1,
@@ -604,16 +609,56 @@ function testDXTTexture(test, useTexStor
             gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
             wtu.clearAndDrawUnitQuad(gl);
             wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing unit quad");
             compareRect(width, height, test.channels, uncompressedData, "LINEAR");
         }
     }
 }
 
+function testDXT5_RGBA_PBO() {
+    var width = 8;
+    var height = 8;
+    var channels = 4;
+    var data = img_8x8_rgba_dxt5;
+    var format = ext.COMPRESSED_RGBA_S3TC_DXT5_EXT;
+    var uncompressedData = uncompressDXT(width, height, data, format);
+
+    var tex = gl.createTexture();
+
+    // First, PBO size = image size
+    var pbo1 = gl.createBuffer();
+    gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, pbo1);
+    gl.bufferData(gl.PIXEL_UNPACK_BUFFER, data, gl.STATIC_DRAW);
+    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading a PBO");
+
+    gl.bindTexture(gl.TEXTURE_2D, tex);
+    gl.texStorage2D(gl.TEXTURE_2D, 1, format, width, height);
+    gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, format, data.length, 0);
+    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading a texture from a PBO");
+
+    gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, null);
+    wtu.clearAndDrawUnitQuad(gl);
+    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing unit quad");
+    compareRect(width, height, channels, uncompressedData, "NEAREST");
+
+    // Second, image is just a subrange of the PBO
+    var pbo2 = gl.createBuffer();
+    gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, pbo2);
+    gl.bufferData(gl.PIXEL_UNPACK_BUFFER, data.length*3, gl.STATIC_DRAW);
+    gl.bufferSubData(gl.PIXEL_UNPACK_BUFFER, data.length, data);
+    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading a PBO subrange");
+    gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, format, data.length, data.length);
+    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading a texture from a PBO subrange");
+    gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, null);
+    wtu.clearAndDrawUnitQuad(gl);
+    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing unit quad");
+    compareRect(width, height, channels, uncompressedData, "NEAREST");
+}
+
 function compareRect(width, height, channels, expectedData, filteringMode) {
     var actual = new Uint8Array(width * height * 4);
     gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, actual);
     wtu.glErrorShouldBe(gl, gl.NO_ERROR, "reading back pixels");
 
     var div = document.createElement("div");
     div.className = "testimages";
     ctu.insertCaptionedImg(div, "expected", ctu.makeScaledImage(width, height, width, expectedData, channels == 4));
--- a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-depth-texture.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-depth-texture.html
@@ -43,17 +43,17 @@ void main()
 </script>
 
 <script id="fshader" type="x-shader/x-fragment">
 precision mediump float;
 uniform sampler2D u_texture;
 uniform vec2 u_resolution;
 void main()
 {
-    vec2 texcoord = gl_FragCoord.xy / u_resolution;
+    vec2 texcoord = (gl_FragCoord.xy - vec2(0.5)) / (u_resolution - vec2(1.0));
     gl_FragColor = texture2D(u_texture, texcoord);
 }
 </script>
 <div id="description"></div>
 <div id="console"></div>
 <canvas id="canvas" width="8" height="8" style="width: 8px; height: 8px;"></canvas>
 <script>
 "use strict";
@@ -137,29 +137,30 @@ function dumpIt(gl, res, msg) {
       strs.push("(" + actualPixels[actual] + "," + actualPixels[actual+1] + "," + actualPixels[actual + 2] + "," + actualPixels[actual + 3] + ")");
     }
     debug(strs.join(" "));
   }
 }
 function runTestExtension(unpackFlipY) {
     debug("Testing WEBGL_depth_texture. UNPACK_FLIP_Y_WEBGL: " + unpackFlipY);
 
-    var res = 8;
+    const res = 2;
+    const destRes = 4;
 
     // make canvas for testing.
     canvas2 = document.createElement("canvas");
     canvas2.width = res;
     canvas2.height = res;
     var ctx = canvas2.getContext("2d");
     ctx.fillStyle = "blue";
     ctx.fillRect(0, 0, canvas2.width, canvas2.height);
 
     var program = wtu.setupProgram(gl, ['vshader', 'fshader'], ['a_position']);
     gl.useProgram(program);
-    gl.uniform2f(gl.getUniformLocation(program, "u_resolution"), res, res);
+    gl.uniform2f(gl.getUniformLocation(program, "u_resolution"), destRes, destRes);
 
     var buffer = gl.createBuffer();
     gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
     gl.bufferData(
         gl.ARRAY_BUFFER,
         new Float32Array(
             [   1,  1,  1,
                -1,  1,  0,
@@ -208,16 +209,17 @@ function runTestExtension(unpackFlipY) {
         // doesn't have much meaning, and isn't supported in WebGL
         // 2.0. Still, test both.
         var filterModes = [
           'LINEAR',
           'NEAREST'
         ];
 
         for (var jj = 0; jj < filterModes.length; ++jj) {
+            debug('');
             debug('testing ' + filterModes[jj] + ' filtering');
             var filterMode = gl[filterModes[jj]];
 
             // check 2d textures.
             tex = gl.createTexture();
             gl.bindTexture(gl.TEXTURE_2D, tex);
             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);
@@ -275,68 +277,109 @@ function runTestExtension(unpackFlipY) {
                 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, colorTex, 0);
             }
 
             shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
 
             // use the default texture to render with while we return to the depth texture.
             gl.bindTexture(gl.TEXTURE_2D, null);
 
-            // render the z-quad
-            gl.enable(gl.DEPTH_TEST);
-            gl.clearColor(1, 0, 0, 1);
-            gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
-            gl.drawArrays(gl.TRIANGLES, 0, 6);
+            /* Setup 2x2 depth texture:
+             * 1 0.6 0.8
+             * |
+             * 0 0.2 0.4
+             *    0---1
+             */
+            const d00 = 0.2;
+            const d01 = 0.4;
+            const d10 = 0.6;
+            const d11 = 0.8;
+
+            gl.enable(gl.SCISSOR_TEST);
 
-            dumpIt(gl, res, "--first--");
+            gl.scissor(0, 0, 1, 1);
+            gl.clearDepth(d00);
+            gl.clear(gl.DEPTH_BUFFER_BIT);
+
+            gl.scissor(1, 0, 1, 1);
+            gl.clearDepth(d10);
+            gl.clear(gl.DEPTH_BUFFER_BIT);
+
+            gl.scissor(0, 1, 1, 1);
+            gl.clearDepth(d01);
+            gl.clear(gl.DEPTH_BUFFER_BIT);
+
+            gl.scissor(1, 1, 1, 1);
+            gl.clearDepth(d11);
+            gl.clear(gl.DEPTH_BUFFER_BIT);
+
+            gl.disable(gl.SCISSOR_TEST);
 
             // render the depth texture.
             gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+            gl.canvas.width = destRes;
+            gl.canvas.height = destRes;
+            gl.viewport(0, 0, destRes, destRes);
             gl.bindTexture(gl.TEXTURE_2D, tex);
-            gl.clearColor(0, 0, 1, 1);
+
+            gl.disable(gl.DITHER);
+            gl.enable(gl.DEPTH_TEST);
+            gl.clearColor(1, 0, 0, 1);
+            gl.clearDepth(1.0);
             gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
             gl.drawArrays(gl.TRIANGLES, 0, 6);
 
-            var actualPixels = new Uint8Array(res * res * 4);
-            gl.readPixels(0, 0, res, res, gl.RGBA, gl.UNSIGNED_BYTE, actualPixels);
-
             dumpIt(gl, res, "--depth--");
 
-            // Check that each pixel's R value is less than that of the previous pixel
-            // in either direction. Basically verify we have a gradient.
-            var success = true;
-            for (var yy = 0; yy < res; ++yy) {
-                for (var xx = 0; xx < res; ++xx) {
-                    var actual = (yy * res + xx) * 4;
-                    var left = actual - 4;
-                    var down = actual - res * 4;
+            var actualPixels = new Uint8Array(destRes * destRes * 4);
+            gl.readPixels(0, 0, destRes, destRes, gl.RGBA, gl.UNSIGNED_BYTE, actualPixels);
+
+            const eps = 0.002;
+
+            let expectedMin;
+            let expectedMax;
+            if (filterMode == gl.NEAREST) {
+                expectedMin = [
+                    d00, d00, d10, d10,
+                    d00, d00, d10, d10,
+                    d01, d01, d11, d11,
+                    d01, d01, d11, d11
+                ];
+                expectedMax = expectedMin.slice();
 
-                    if (xx > 0) {
-                        if (actualPixels[actual] <= actualPixels[left]) {
-                            testFailed("actual(" + actualPixels[actual] + ") < left(" + actualPixels[left] + ")");
-                            success = false;
-                        }
-                    }
-                    if (yy > 0) {
-                        if (actualPixels[actual] <= actualPixels[down]) {
-                            testFailed("actual(" + actualPixels[actual] + ") < down(" + actualPixels[down] + ")");
-                            success = false;
-                        }
-                    }
-                }
+                expectedMin = expectedMin.map(x => x - eps);
+                expectedMax = expectedMax.map(x => x + eps);
+            } else {
+                expectedMin = [
+                    d00-eps, d00, d00, d10-eps,
+                    d00, d00, d00, d10,
+                    d00, d00, d00, d10,
+                    d01-eps, d01, d01, d11-eps,
+                ];
+                expectedMax = [
+                    d00+eps, d10, d10, d10+eps,
+                    d01, d11, d11, d11,
+                    d01, d11, d11, d11,
+                    d01+eps, d11, d11, d11+eps,
+                ];
             }
 
-            // Check that bottom left corner is vastly different thatn top right.
-            if (actualPixels[(res * res - 1) * 4] - actualPixels[0] < 0xC0) {
-                testFailed("corners are not different enough");
-                success = false;
-            }
-
-            if (success) {
-                testPassed("depth texture rendered correctly.");
+            for (var yy = 0; yy < destRes; ++yy) {
+                for (var xx = 0; xx < destRes; ++xx) {
+                    const t = xx + destRes*yy;
+                    const was = actualPixels[4*t] / 255.0; // 4bpp
+                    const eMin = expectedMin[t];
+                    const eMax = expectedMax[t];
+                    let func = testPassed;
+                    const text = `At ${xx},${yy}, expected within [${eMin},${eMax}], was ${was.toFixed(3)}`
+                    if (was <= eMin || was >= eMax) {
+                        func = testFailed;
+                    }
+                    func(text);
+                }
             }
 
             // check limitations
             gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
             gl.framebufferTexture2D(gl.FRAMEBUFFER, gl[typeInfo.attachment], gl.TEXTURE_2D, null, 0);
             var badAttachment = typeInfo.attachment == 'DEPTH_ATTACHMENT' ? 'DEPTH_STENCIL_ATTACHMENT' : 'DEPTH_ATTACHMENT';
             wtu.shouldGenerateGLError(gl, gl.NO_ERROR, 'gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.' + badAttachment + ', gl.TEXTURE_2D, tex, 0)');
             shouldNotBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
deleted file mode 100644
--- a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-draw-buffers-feedback-loop.html
+++ /dev/null
@@ -1,161 +0,0 @@
-<!--
-
-/*
-** Copyright (c) 2016 The Khronos Group Inc.
-**
-** Permission is hereby granted, free of charge, to any person obtaining a
-** copy of this software and/or associated documentation files (the
-** "Materials"), to deal in the Materials without restriction, including
-** without limitation the rights to use, copy, modify, merge, publish,
-** distribute, sublicense, and/or sell copies of the Materials, and to
-** permit persons to whom the Materials are furnished to do so, subject to
-** the following conditions:
-**
-** The above copyright notice and this permission notice shall be included
-** in all copies or substantial portions of the Materials.
-**
-** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
-*/
-
--->
-
-<!DOCTYPE html>
-<html>
-<head>
-<meta charset="utf-8">
-<title>WebGL Rendering and Sampling Feedback Loop Tests For WEBGL_draw_buffers Extension</title>
-<link rel="stylesheet" href="../../resources/js-test-style.css"/>
-<script src="../../js/js-test-pre.js"></script>
-<script src="../../js/webgl-test-utils.js"></script>
-</head>
-<body>
-<canvas id="example" width="8" height="8"></canvas>
-<div id="description"></div>
-<div id="console"></div>
-
-<script id="vshader" type="x-shader/x-vertex">
-attribute vec4 aPosition;
-attribute vec2 aTexCoord;
-varying vec2 texCoord;
-void main() {
-    gl_Position = aPosition;
-    texCoord = aTexCoord;
-}
-</script>
-
-<script id="fshader" type="x-shader/x-fragment">
-#extension GL_EXT_draw_buffers : require
-precision mediump float;
-uniform sampler2D tex;
-varying vec2 texCoord;
-void main() {
-    gl_FragData[0] = texture2D(tex, texCoord);
-    gl_FragData[1] = texture2D(tex, texCoord);
-}
-</script>
-
-<script>
-"use strict";
-
-var wtu = WebGLTestUtils;
-var canvas = document.getElementById("example");
-description("This test verifies the functionality of rendering to the same texture where it samples from.");
-
-var gl = wtu.create3DContext(canvas);
-
-var width = 8;
-var height = 8;
-var tex0;
-var tex1;
-var fbo;
-var ext;
-var program;
-var positionLoc;
-var texCoordLoc;
-
-if (!gl) {
-    testFailed("WebGL context does not exist");
-} else {
-    testPassed("WebGL context exists");
-
-    ext = gl.getExtension("WEBGL_draw_buffers");
-    if (!ext) {
-        testPassed("No WEBGL_draw_buffers support -- this is legal");
-
-        finishTest();
-    } else {
-        testPassed("Successfully enabled WEBGL_draw_buffers extension");
-
-        init();
-
-        // The sampling texture is bound to COLOR_ATTACHMENT1 during resource allocation
-        allocate_resource();
-
-        rendering_sampling_feedback_loop([gl.NONE, ext.COLOR_ATTACHMENT1_WEBGL], gl.INVALID_OPERATION);
-        rendering_sampling_feedback_loop([gl.COLOR_ATTACHMENT0, ext.COLOR_ATTACHMENT1_WEBGL], gl.INVALID_OPERATION);
-        rendering_sampling_feedback_loop([gl.COLOR_ATTACHMENT0, gl.NONE], gl.NO_ERROR);
-    }
-}
-
-function init() {
-    program = wtu.setupProgram(gl, ['vshader', 'fshader'], ['aPosition', 'aTexCoord'], [0, 1]);
-    positionLoc = gl.getAttribLocation(program, "aPosition");
-    texCoordLoc = gl.getAttribLocation(program, "aTexCoord");
-    if (!program || positionLoc < 0 || texCoordLoc < 0) {
-        testFailed("Set up program failed");
-        return;
-    }
-    testPassed("Set up program succeeded");
-
-    wtu.setupUnitQuad(gl, 0, 1);
-    gl.viewport(0, 0, width, height);
-}
-
-function allocate_resource() {
-    tex0 = gl.createTexture();
-    tex1 = gl.createTexture();
-    fbo = gl.createFramebuffer();
-    wtu.fillTexture(gl, tex0, width, height, [0xff, 0x0, 0x0, 0xff], 0, gl.RGBA, gl.UNSIGNED_BYTE, gl.RGBA);
-    wtu.fillTexture(gl, tex1, width, height, [0x0, 0xff, 0x0, 0xff], 0, gl.RGBA, gl.UNSIGNED_BYTE, gl.RGBA);
-
-    gl.bindTexture(gl.TEXTURE_2D, tex1);
-    var texLoc = gl.getUniformLocation(program, "tex");
-    gl.uniform1i(texLoc, 0);
-
-    gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
-    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex0, 0);
-    gl.framebufferTexture2D(gl.FRAMEBUFFER, ext.COLOR_ATTACHMENT1_WEBGL, gl.TEXTURE_2D, tex1, 0);
-}
-
-function rendering_sampling_feedback_loop(draw_buffers, error) {
-    // gl.drawBuffers(draw_buffers);
-    ext.drawBuffersWEBGL(draw_buffers);
-
-    // Make sure framebuffer is complete before feedback loop detection
-    if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
-        testFailed("Framebuffer incomplete.");
-        return;
-    }
-
-    wtu.clearAndDrawUnitQuad(gl);
-    wtu.glErrorShouldBe(gl, error, "Rendering to a texture where it samples from should geneates INVALID_OPERATION. Otherwise, it should be NO_ERROR");
-}
-
-gl.bindTexture(gl.TEXTURE_2D, null);
-gl.bindFramebuffer(gl.FRAMEBUFFER, null);
-gl.deleteTexture(tex0);
-gl.deleteTexture(tex1);
-gl.deleteFramebuffer(fbo);
-
-var successfullyParsed = true;
-</script>
-<script src="../../js/js-test-post.js"></script>
-
-</body>
-</html>
--- a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-draw-buffers.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-draw-buffers.html
@@ -526,38 +526,36 @@ function runDrawTests() {
   debug("test a fragment shader writing to neither gl_FragColor nor gl_FragData does not touch attachments");
   var noWriteProgram = wtu.setupProgram(gl, [wtu.simpleVertexShader, "fshaderNoWrite"], ["vPosition"]);
   wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no GL error setting up the program");
   if (!noWriteProgram) {
     testFailed("Setup a program where fragment shader writes nothing failed");
   } else {
     gl.useProgram(noWriteProgram);
     wtu.drawUnitQuad(gl);
-
+    wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Active draw buffers with missing frag outputs.");
     drawBuffersUtils.checkAttachmentsForColor(attachments, [0, 255, 0, 255]);
     gl.deleteProgram(noWriteProgram);
   }
 
   debug("test that NONE draws nothing");
   gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
   ext.drawBuffersWEBGL(nones);
   gl.useProgram(redProgram);
   wtu.clearAndDrawUnitQuad(gl);
 
   drawBuffersUtils.checkAttachmentsForColor(attachments, [0, 255, 0, 255]);
 
   debug("test that gl_FragColor does not broadcast unless extension is enabled in fragment shader");
   gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
-  ext.drawBuffersWEBGL([gl.COLOR_ATTACHMENT0]); // While the WG debates whether how to handle this.
+  ext.drawBuffersWEBGL(bufs);
   gl.useProgram(redProgram);
+  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
   wtu.drawUnitQuad(gl);
-
-  drawBuffersUtils.checkAttachmentsForColorFn(attachments, function(attachment, index) {
-    return (index == 0) ? [255, 0, 0, 255] : [0, 255, 0, 255];
-  });
+  wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Active draw buffers with missing frag outputs.");
 
   debug("test that gl_FragColor broadcasts if extension is enabled in fragment shader");
   gl.clear(gl.COLOR_BUFFER_BIT);
   gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
   ext.drawBuffersWEBGL(bufs);
   gl.useProgram(redProgramWithExtension);
   wtu.drawUnitQuad(gl);
 
new file mode 100644
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-multi-draw.html
@@ -0,0 +1,834 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL ANGLE_multi_draw Conformance Tests</title>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/desktop-gl-constants.js"></script>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+</head>
+<body>
+<script id="vshaderIllegalDrawID" type="x-shader/x-vertex">
+attribute vec2 vPosition;
+varying vec4 color;
+void main()
+{
+  color = vec4(1.0, 0.0, 0.0, 1.0);
+  gl_Position = vec4(vPosition * 2.0 - 1.0, gl_DrawID, 1);
+}
+</script>
+<script id="vshaderDrawIDZero" type="x-shader/x-vertex">
+#extension GL_ANGLE_multi_draw : require
+attribute vec2 vPosition;
+varying vec4 color;
+void main()
+{
+  if (gl_DrawID == 0) {
+    color = vec4(0, 1, 0, 1);
+  } else {
+    color = vec4(1, 0, 0, 1);
+  }
+  gl_Position = vec4(vPosition * 2.0 - 1.0, 0, 1);
+}
+</script>
+<!-- The behavior of the shaders below is described in runPixelTests() -->
+<script id="vshaderWithDrawID" type="x-shader/x-vertex">
+#extension GL_ANGLE_multi_draw : require
+attribute vec2 vPosition;
+attribute float vInstance;
+varying vec4 color;
+void main()
+{
+  // color_id = (gl_DrawID / 2) % 3
+  float quad_id = float(gl_DrawID / 2);
+  float color_id = quad_id - (3.0 * floor(quad_id / 3.0));
+  if (color_id < 0.5) {
+    color = vec4(1, 0, 0, 1);
+  } else if (color_id < 1.5) {
+    color = vec4(0, 1, 0, 1);
+  } else {
+    color = vec4(0, 0, 1, 1);
+  }
+  mat3 transform = mat3(1.0);
+  // vInstance starts at 1.0 on instanced calls
+  if (vInstance >= 1.0) {
+    transform[0][0] = 0.5;
+    transform[1][1] = 0.5;
+  }
+  if (vInstance == 1.0) {
+  } else if (vInstance == 2.0) {
+      transform[2][0] = 0.5;
+  } else if (vInstance == 3.0) {
+      transform[2][1] = 0.5;
+  } else if (vInstance == 4.0) {
+      transform[2][0] = 0.5;
+      transform[2][1] = 0.5;
+  }
+  gl_Position = vec4(transform * vec3(vPosition, 1.0) * 2.0 - 1.0, 1);
+}
+</script>
+<script id="vshaderEmulatedDrawID" type="x-shader/x-vertex">
+uniform int drawID;
+attribute vec2 vPosition;
+attribute float vInstance;
+varying vec4 color;
+void main()
+{
+  float quad_id = float(drawID / 2);
+  float color_id = quad_id - (3.0 * floor(quad_id / 3.0));
+  if (color_id == 0.0) {
+    color = vec4(1, 0, 0, 1);
+  } else if (color_id == 1.0) {
+    color = vec4(0, 1, 0, 1);
+  } else {
+    color = vec4(0, 0, 1, 1);
+  }
+  mat3 transform = mat3(1.0);
+  // vInstance starts at 1.0 on instanced calls
+  if (vInstance >= 1.0) {
+    transform[0][0] = 0.5;
+    transform[1][1] = 0.5;
+  }
+  if (vInstance == 1.0) {
+  } else if (vInstance == 2.0) {
+      transform[2][0] = 0.5;
+  } else if (vInstance == 3.0) {
+      transform[2][1] = 0.5;
+  } else if (vInstance == 4.0) {
+      transform[2][0] = 0.5;
+      transform[2][1] = 0.5;
+  }
+  gl_Position = vec4(transform * vec3(vPosition, 1.0) * 2.0 - 1.0, 1);
+}
+</script>
+<script id="vshaderNoDrawID" type="x-shader/x-vertex">
+attribute vec2 vPosition;
+attribute float vInstance;
+varying vec4 color;
+void main()
+{
+  color = vec4(1.0, 0.0, 0.0, 1.0);
+  mat3 transform = mat3(1.0);
+  // vInstance starts at 1.0 on instanced calls
+  if (vInstance >= 1.0) {
+    transform[0][0] = 0.5;
+    transform[1][1] = 0.5;
+  }
+  if (vInstance == 1.0) {
+  } else if (vInstance == 2.0) {
+      transform[2][0] = 0.5;
+  } else if (vInstance == 3.0) {
+      transform[2][1] = 0.5;
+  } else if (vInstance == 4.0) {
+      transform[2][0] = 0.5;
+      transform[2][1] = 0.5;
+  }
+  gl_Position = vec4(transform * vec3(vPosition, 1.0) * 2.0 - 1.0, 1);
+}
+</script>
+<script id="fshader" type="x-shader/x-fragment">
+precision mediump float;
+varying vec4 color;
+void main() {
+  gl_FragColor = color;
+}
+</script>
+<div id="description"></div>
+<canvas id="canvas" width="128" height="128"> </canvas>
+<div id="console"></div>
+
+<script>
+"use strict";
+description("This test verifies the functionality of the ANGLE_multi_draw extension, if it is available.");
+
+const wtu = WebGLTestUtils;
+const canvas = document.getElementById("canvas");
+const gl = wtu.create3DContext(canvas);
+const instancedExt = gl && gl.getExtension('ANGLE_instanced_arrays');
+
+// Check if the extension is either both enabled and supported or
+// not enabled and not supported.
+function runSupportedTest(extensionName, extensionEnabled) {
+  const supported = gl.getSupportedExtensions();
+  if (supported.indexOf(extensionName) >= 0) {
+    if (extensionEnabled) {
+      testPassed(extensionName + ' listed as supported and getExtension succeeded');
+      return true;
+    } else {
+      testFailed(extensionName + ' listed as supported but getExtension failed');
+    }
+  } else {
+    if (extensionEnabled) {
+      testFailed(extensionName + ' not listed as supported but getExtension succeeded');
+    } else {
+      testPassed(extensionName + ' not listed as supported and getExtension failed -- this is legal');
+    }
+  }
+  return false;
+}
+
+function runTest() {
+  if (!gl) {
+    return function() {
+      testFailed('WebGL context does not exist');
+    }
+  }
+
+  doTest('WEBGL_multi_draw', false);
+  doTest('WEBGL_multi_draw_instanced', true);
+}
+
+function doTest(extensionName, instanced) {
+  const ext = gl.getExtension(extensionName);
+
+  if (!runSupportedTest(extensionName, ext)) {
+    return;
+  }
+
+  function runValidationTests() {
+    const vertexBuffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0.2,0.2, 0.8,0.2, 0.5,0.8 ]), gl.STATIC_DRAW);
+
+    const indexBuffer = gl.createBuffer();
+    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
+    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint8Array([ 0, 1, 2, 0]), gl.STATIC_DRAW);
+
+    const instanceBuffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, instanceBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0, 1, 2, 3 ]), gl.STATIC_DRAW);
+
+    const program = wtu.setupProgram(gl, ["vshaderNoDrawID", "fshader"], ["vPosition", "vInstance"], [0, 1]);
+    expectTrue(program != null, "can compile simple program");
+
+    function setupDrawArrays() {
+      gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
+      gl.enableVertexAttribArray(0);
+      gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
+    }
+
+    function setupDrawElements() {
+      gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
+      gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
+      gl.enableVertexAttribArray(0);
+      gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
+    }
+
+    function setupInstanced() {
+      gl.bindBuffer(gl.ARRAY_BUFFER, instanceBuffer);
+      gl.enableVertexAttribArray(1);
+      gl.vertexAttribPointer(1, 1, gl.FLOAT, false, 0, 0);
+      if (wtu.getDefault3DContextVersion() < 2) {
+        instancedExt.vertexAttribDivisorANGLE(1, 1);
+      } else {
+        gl.vertexAttribDivisor(1, 1);
+      }
+    }
+
+    function setupDrawArraysInstanced() {
+      setupDrawArrays();
+      setupInstanced();
+    }
+
+    function setupDrawElementsInstanced() {
+      setupDrawElements();
+      setupInstanced();
+    }
+
+    // Wrap a draw call in a function to setup the draw call, execute,
+    // and check errors.
+    // The `drawFunc` is one of the extension entrypoints being tested. It may
+    // be undefined if that entrypoint is not supported on the context
+    function makeDrawCheck(drawFunc, setup) {
+      if (!drawFunc) {
+        return function() {};
+      }
+      return function(f_args, expect, msg) {
+        setup();
+        drawFunc.apply(ext, f_args);
+        wtu.glErrorShouldBe(gl, expect, drawFunc.name + " " + msg);
+        gl.disableVertexAttribArray(0);
+        gl.disableVertexAttribArray(1);
+      }
+    }
+
+    const checkMultiDrawArrays = makeDrawCheck(
+        ext.multiDrawArraysWEBGL, setupDrawArrays);
+    const checkMultiDrawElements = makeDrawCheck(
+        ext.multiDrawElementsWEBGL, setupDrawElements);
+    const checkMultiDrawArraysInstanced = makeDrawCheck(
+        ext.multiDrawArraysInstancedWEBGL, setupDrawArraysInstanced);
+    const checkMultiDrawElementsInstanced = makeDrawCheck(
+        ext.multiDrawElementsInstancedWEBGL, setupDrawElementsInstanced);
+
+    gl.useProgram(program);
+
+    // Check that drawing a single triangle works
+    if (!instanced) {
+      checkMultiDrawArrays(
+        [gl.TRIANGLES, [0], 0, [3], 0, 1],
+        gl.NO_ERROR, "with gl.TRIANGLES");
+      checkMultiDrawElements(
+        [gl.TRIANGLES, [3], 0, gl.UNSIGNED_BYTE, [0], 0, 1],
+        gl.NO_ERROR, "with gl.TRIANGLES");
+    } else {
+      checkMultiDrawElementsInstanced(
+        [gl.TRIANGLES, [3], 0, gl.UNSIGNED_BYTE, [0], 0, [1], 0, 1],
+        gl.NO_ERROR, "with gl.TRIANGLES");
+      checkMultiDrawArraysInstanced(
+        [gl.TRIANGLES, [0], 0, [3], 0, [1], 0, 1],
+        gl.NO_ERROR, "with gl.TRIANGLES");
+    }
+
+    // Zero drawcount permitted
+    if (!instanced) {
+      checkMultiDrawArrays(
+        [gl.TRIANGLES, [0], 0, [3], 0, 0],
+        gl.NO_ERROR, "with drawcount == 0");
+      checkMultiDrawElements(
+        [gl.TRIANGLES, [3], 0, gl.UNSIGNED_BYTE, [0], 0, 0],
+        gl.NO_ERROR, "with drawcount == 0");
+    } else {
+      checkMultiDrawElementsInstanced(
+        [gl.TRIANGLES, [3], 0, gl.UNSIGNED_BYTE, [0], 0, [1], 0, 0],
+        gl.NO_ERROR, "with drawcount == 0");
+      checkMultiDrawArraysInstanced(
+        [gl.TRIANGLES, [0], 0, [3], 0, [1], 0, 0],
+        gl.NO_ERROR, "with drawcount == 0");
+    }
+
+    // Check negative drawcount
+    if (!instanced) {
+      checkMultiDrawArrays(
+        [gl.TRIANGLES, [0], 0, [3], 0, -1],
+        gl.INVALID_VALUE, "with drawcount < 0");
+      checkMultiDrawElements(
+        [gl.TRIANGLES, [3], 0, gl.UNSIGNED_BYTE, [0], 0, -1],
+        gl.INVALID_VALUE, "with drawcount < 0");
+    } else {
+      checkMultiDrawElementsInstanced(
+        [gl.TRIANGLES, [3], 0, gl.UNSIGNED_BYTE, [0], 0, [1], 0, -1],
+        gl.INVALID_VALUE, "with drawcount < 0");
+      checkMultiDrawArraysInstanced(
+        [gl.TRIANGLES, [0], 0, [3], 0, [1], 0, -1],
+        gl.INVALID_VALUE, "with drawcount < 0");
+    }
+
+    // Check offsets greater than array length
+    if (!instanced) {
+      checkMultiDrawArrays(
+        [gl.TRIANGLES, [0], 1, [3], 0, 1],
+        gl.INVALID_OPERATION, "with firstsStart >= firstsList.length");
+      checkMultiDrawArrays(
+        [gl.TRIANGLES, [0], 0, [3], 1, 1],
+        gl.INVALID_OPERATION, "with countsStart >= countsList.length");
+
+      checkMultiDrawElements(
+        [gl.TRIANGLES, [3], 1, gl.UNSIGNED_BYTE, [0], 0, 1],
+        gl.INVALID_OPERATION, "with countsStart >= countsList.length");
+      checkMultiDrawElements(
+        [gl.TRIANGLES, [3], 0, gl.UNSIGNED_BYTE, [0], 1, 1],
+        gl.INVALID_OPERATION, "with offsetsStart >= offsetsList.length");
+    } else {
+      checkMultiDrawArraysInstanced(
+        [gl.TRIANGLES, [0], 1, [3], 0, [1], 0, 1],
+        gl.INVALID_OPERATION, "with firstsStart >= firstsList.length");
+      checkMultiDrawArraysInstanced(
+        [gl.TRIANGLES, [0], 0, [3], 1, [1], 0, 1],
+        gl.INVALID_OPERATION, "with countsStart >= countsList.length");
+      checkMultiDrawArraysInstanced(
+        [gl.TRIANGLES, [0], 0, [3], 0, [1], 1, 1],
+        gl.INVALID_OPERATION, "with instanceCountsStart >= instanceCountsList.length");
+
+      checkMultiDrawElementsInstanced(
+        [gl.TRIANGLES, [3], 1, gl.UNSIGNED_BYTE, [0], 0, [1], 0, 1],
+        gl.INVALID_OPERATION, "with countsStart >= countsList.length");
+      checkMultiDrawElementsInstanced(
+        [gl.TRIANGLES, [3], 0, gl.UNSIGNED_BYTE, [0], 1, [1], 0, 1],
+        gl.INVALID_OPERATION, "with offsetsStart >= offsetsList.length");
+      checkMultiDrawElementsInstanced(
+        [gl.TRIANGLES, [3], 0, gl.UNSIGNED_BYTE, [0], 0, [1], 1, 1],
+        gl.INVALID_OPERATION, "with instanceCountsStart >= instanceCountsList.length");
+    }
+  }
+
+  function runShaderTests() {
+    const illegalProgram = wtu.setupProgram(gl, ["vshaderIllegalDrawID", "fshader"], ["vPosition"], [0]);
+    expectTrue(illegalProgram == null, "cannot compile program with gl_DrawID but no extension directive");
+
+    const drawIDProgram = wtu.setupProgram(gl, ["vshaderDrawIDZero", "fshader"], ["vPosition"], [0]);
+    wtu.setupProgram(gl, ["vshaderDrawIDZero", "fshader"], ["vPosition"], [0]);
+    expectTrue(drawIDProgram !== null, "can compile program with gl_DrawID");
+    gl.useProgram(drawIDProgram);
+    gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0,0, 1,0, 0,1, 0,1, 1,0, 1,1 ]), gl.STATIC_DRAW);
+    gl.enableVertexAttribArray(0);
+    gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
+    gl.drawArrays(gl.TRIANGLES, 0, 6);
+    wtu.checkCanvas(gl, [0, 255, 0, 255], "gl_DrawID is 0 for non-Multi* draw calls", 0);
+  }
+
+  function runPixelTests() {
+    // An array of quads is tiled across the screen.
+    // gl_DrawID is checked by using it to select the color of the draw.
+    // Instanced entrypoints are tested here scaling and then instancing the
+    // array of quads over four quadrants on the screen.
+
+    // These tests also include "manyDraw" tests which emulate a multiDraw with
+    // a Javascript for-loop and gl_DrawID with a uniform constiable. They are
+    // included to ensure the test is written correctly.
+
+    const width = gl.canvas.width;
+    const height = gl.canvas.height;
+    const x_count = 8;
+    const y_count = 8;
+    const quad_count = x_count * y_count;
+    const tri_count = quad_count * 2;
+    const tileSize = [ 1/x_count, 1/y_count ];
+    const tilePixelSize = [ Math.floor(width / x_count), Math.floor(height / y_count) ];
+    const quadRadius = [ 0.25 * tileSize[0], 0.25 * tileSize[1] ];
+    const pixelCheckSize = [ Math.floor(quadRadius[0] * width), Math.floor(quadRadius[1] * height) ];
+
+    function getTileCenter(x, y) {
+      return [ tileSize[0] * (0.5 + x), tileSize[1] * (0.5 + y) ];
+    }
+
+    function getQuadVertices(x, y) {
+      const center = getTileCenter(x, y);
+      return [
+        [center[0] - quadRadius[0], center[1] - quadRadius[1], 0],
+        [center[0] + quadRadius[0], center[1] - quadRadius[1], 0],
+        [center[0] + quadRadius[0], center[1] + quadRadius[1], 0],
+        [center[0] - quadRadius[0], center[1] + quadRadius[1], 0],
+      ]
+    }
+
+    const indicesData = [];
+    const verticesData = [];
+    const nonIndexedVerticesData = [];
+    {
+      const is = new Uint16Array([0, 1, 2, 0, 2, 3]);
+      for (let y = 0; y < y_count; ++y) {
+        for (let x = 0; x < x_count; ++x) {
+          const quadIndex = y * x_count + x;
+          const starting_index = 4 * quadIndex;
+          const vs = getQuadVertices(x, y);
+          for (let i = 0; i < is.length; ++i) {
+            indicesData.push(starting_index + is[i]);
+          }
+          for (let i = 0; i < vs.length; ++i) {
+            for (let v = 0; v < vs[i].length; ++v) verticesData.push(vs[i][v]);
+          }
+          for (let i = 0; i < is.length; ++i) {
+            for (let v = 0; v < vs[is[i]].length; ++v) nonIndexedVerticesData.push(vs[is[i]][v]);
+          }
+        }
+      }
+    }
+
+    const indices = new Uint16Array(indicesData);
+    const vertices = new Float32Array(verticesData);
+    const nonIndexedVertices = new Float32Array(nonIndexedVerticesData);
+
+    const indexBuffer = gl.createBuffer();
+    const vertexBuffer = gl.createBuffer();
+    const nonIndexedVertexBuffer = gl.createBuffer();
+    const instanceBuffer = gl.createBuffer();
+
+    gl.bindBuffer(gl.ARRAY_BUFFER, nonIndexedVertexBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, nonIndexedVertices, gl.STATIC_DRAW);
+
+    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
+
+    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
+    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
+
+    gl.bindBuffer(gl.ARRAY_BUFFER, instanceBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([1, 2, 3, 4]), gl.STATIC_DRAW);
+
+    function checkResult(config, msg) {
+      const rects = [];
+      const expected = [
+        [255, 0, 0, 255],
+        [0, 255, 0, 255],
+        [0, 0, 255, 255],
+      ];
+      for (let y = 0; y < y_count; ++y) {
+        for (let x = 0; x < x_count; ++x) {
+          const center_x = x * tilePixelSize[0] + Math.floor(tilePixelSize[0] / 2);
+          const center_y = y * tilePixelSize[1] + Math.floor(tilePixelSize[1] / 2);
+          const quadID = y * x_count + x;
+          const colorID = config.drawID ? quadID % 3 : 0;
+          if (config.instanced) {
+            rects.push(wtu.makeCheckRect(
+                center_x / 2 - Math.floor(pixelCheckSize[0] / 4),
+                center_y / 2 - Math.floor(pixelCheckSize[1] / 4),
+                pixelCheckSize[0] / 2,
+                pixelCheckSize[1] / 2,
+                expected[colorID],
+                msg + " (" + x + "," + y + ")", 0));
+            rects.push(wtu.makeCheckRect(
+                center_x / 2 - Math.floor(pixelCheckSize[0] / 4) + width / 2,
+                center_y / 2 - Math.floor(pixelCheckSize[1] / 4),
+                pixelCheckSize[0] / 2,
+                pixelCheckSize[1] / 2,
+                expected[colorID],
+                msg + " (" + x + "," + y + ")", 0));
+            rects.push(wtu.makeCheckRect(
+                center_x / 2 - Math.floor(pixelCheckSize[0] / 4),
+                center_y / 2 - Math.floor(pixelCheckSize[1] / 4) + height / 2,
+                pixelCheckSize[0] / 2,
+                pixelCheckSize[1] / 2,
+                expected[colorID],
+                msg + " (" + x + "," + y + ")", 0));
+            rects.push(wtu.makeCheckRect(
+                center_x / 2 - Math.floor(pixelCheckSize[0] / 4) + width / 2,
+                center_y / 2 - Math.floor(pixelCheckSize[1] / 4) + height / 2,
+                pixelCheckSize[0] / 2,
+                pixelCheckSize[1] / 2,
+                expected[colorID],
+                msg + " (" + x + "," + y + ")", 0));
+          } else {
+            rects.push(wtu.makeCheckRect(
+                center_x - Math.floor(pixelCheckSize[0] / 2),
+                center_y - Math.floor(pixelCheckSize[1] / 2),
+                pixelCheckSize[0],
+                pixelCheckSize[1],
+                expected[colorID],
+                msg + " (" + x + "," + y + ")", 0));
+          }
+        }
+      }
+      wtu.checkCanvasRects(gl, rects);
+    }
+
+    const firsts = new Uint32Array(tri_count);
+    const counts = new Uint32Array(tri_count);
+    const offsets = new Uint32Array(tri_count);
+    const instances = new Uint32Array(tri_count);
+
+    for (let i = 0; i < firsts.length; ++i) firsts[i] = i * 3;
+    counts.fill(3);
+    for (let i = 0; i < offsets.length; ++i) offsets[i] = i * 3 * 2;
+    instances.fill(4);
+
+    const firstsOffset = 47;
+    const countsOffset = firstsOffset + firsts.length;
+    const offsetsOffset = countsOffset + counts.length;
+    const instancesOffset = offsetsOffset + instances.length;
+
+    const buffer = new Uint32Array(firstsOffset + firsts.length + counts.length + offsets.length + instances.length);
+    buffer.set(firsts, firstsOffset);
+    buffer.set(counts, countsOffset);
+    buffer.set(offsets, offsetsOffset);
+    buffer.set(instances, instancesOffset);
+
+    let drawIDLocation;
+
+    const multiDrawArrays = function() {
+      ext.multiDrawArraysWEBGL(gl.TRIANGLES, firsts, 0, counts, 0, tri_count);
+    }
+
+    const multiDrawArraysWithNonzeroOffsets = function() {
+      ext.multiDrawArraysWEBGL(gl.TRIANGLES, buffer, firstsOffset, buffer, countsOffset, tri_count);
+    }
+
+    const multiDrawElements = function() {
+      ext.multiDrawElementsWEBGL(gl.TRIANGLES, counts, 0, gl.UNSIGNED_SHORT, offsets, 0, tri_count);
+    }
+
+    const multiDrawElementsWithNonzeroOffsets = function() {
+      ext.multiDrawElementsWEBGL(gl.TRIANGLES, buffer, countsOffset, gl.UNSIGNED_SHORT, buffer, offsetsOffset, tri_count);
+    }
+
+    const multiDrawArraysInstanced = function() {
+      ext.multiDrawArraysInstancedWEBGL(gl.TRIANGLES, firsts, 0, counts, 0, instances, 0, tri_count);
+    }
+
+    const multiDrawArraysInstancedWithNonzeroOffsets = function() {
+      ext.multiDrawArraysInstancedWEBGL(gl.TRIANGLES, buffer, firstsOffset, buffer, countsOffset, buffer, instancesOffset, tri_count);
+    }
+
+    const multiDrawElementsInstanced = function() {
+      ext.multiDrawElementsInstancedWEBGL(gl.TRIANGLES, counts, 0, gl.UNSIGNED_SHORT, offsets, 0, instances, 0, tri_count);
+    }
+
+    const multiDrawElementsInstancedWithNonzeroOffsets = function() {
+      ext.multiDrawElementsInstancedWEBGL(gl.TRIANGLES, buffer, countsOffset, gl.UNSIGNED_SHORT, buffer, offsetsOffset, buffer, instancesOffset, tri_count);
+    }
+
+    const manyDrawArrays = function() {
+      for (let i = 0; i < tri_count; ++i) {
+        gl.drawArrays(gl.TRIANGLES, firsts[i], counts[i]);
+      }
+    }
+
+    const manyDrawElements = function() {
+      for (let i = 0; i < tri_count; ++i) {
+        gl.drawElements(gl.TRIANGLES, counts[i], gl.UNSIGNED_SHORT, offsets[i]);
+      }
+    }
+
+    const manyDrawArraysEmulateDrawID = function() {
+      for (let i = 0; i < tri_count; ++i) {
+        gl.uniform1i(drawIDLocation, i);
+        gl.drawArrays(gl.TRIANGLES, firsts[i], counts[i]);
+      }
+    }
+
+    const manyDrawElementsEmulateDrawID = function() {
+      for (let i = 0; i < tri_count; ++i) {
+        gl.uniform1i(drawIDLocation, i);
+        gl.drawElements(gl.TRIANGLES, counts[i], gl.UNSIGNED_SHORT, offsets[i]);
+      }
+    }
+
+    function drawArraysInstanced() {
+      if (wtu.getDefault3DContextVersion() < 2) {
+        instancedExt.drawArraysInstancedANGLE.apply(instancedExt, arguments);
+      } else {
+        gl.drawArraysInstanced.apply(gl, arguments);
+      }
+    }
+
+    function drawElementsInstanced() {
+      if (wtu.getDefault3DContextVersion() < 2) {
+        instancedExt.drawElementsInstancedANGLE.apply(instancedExt, arguments);
+      } else {
+        gl.drawElementsInstanced.apply(gl, arguments);
+      }
+    }
+
+    function vertexAttribDivisor(attrib, divisor) {
+      if (wtu.getDefault3DContextVersion() < 2) {
+        instancedExt.vertexAttribDivisorANGLE(attrib, divisor);
+      } else {
+        gl.vertexAttribDivisor(attrib, divisor);
+      }
+    }
+
+    const manyDrawArraysInstanced = function() {
+      for (let i = 0; i < tri_count; ++i) {
+        drawArraysInstanced(gl.TRIANGLES, firsts[i], counts[i], 4);
+      }
+    }
+
+    const manyDrawElementsInstanced = function() {
+      for (let i = 0; i < tri_count; ++i) {
+        drawElementsInstanced(gl.TRIANGLES, counts[i], gl.UNSIGNED_SHORT, offsets[i], 4);
+      }
+    }
+
+    const manyDrawArraysInstancedEmulateDrawID = function() {
+      for (let i = 0; i < tri_count; ++i) {
+        gl.uniform1i(drawIDLocation, i);
+        drawArraysInstanced(gl.TRIANGLES, firsts[i], counts[i], 4);
+      }
+    }
+
+    const manyDrawElementsInstancedEmulateDrawID = function() {
+      for (let i = 0; i < tri_count; ++i) {
+        gl.uniform1i(drawIDLocation, i);
+        drawElementsInstanced(gl.TRIANGLES, counts[i], gl.UNSIGNED_SHORT, offsets[i], 4);
+      }
+    }
+
+    function checkDraw(config) {
+      gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+      if (config.indexed) {
+        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
+        gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
+        gl.enableVertexAttribArray(0);
+        gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
+      } else {
+        gl.bindBuffer(gl.ARRAY_BUFFER, nonIndexedVertexBuffer);
+        gl.enableVertexAttribArray(0);
+        gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
+      }
+
+      if (config.instanced) {
+        gl.bindBuffer(gl.ARRAY_BUFFER, instanceBuffer);
+        gl.enableVertexAttribArray(1);
+        gl.vertexAttribPointer(1, 1, gl.FLOAT, false, 0, 0);
+        vertexAttribDivisor(1, 1);
+      }
+
+      config.drawFunc();
+      wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+      checkResult(config, config.drawFunc.name + (
+        config.instanced ? ' instanced' : ''
+      ) + (
+        config.drawID ? ' with gl_DrawID' : ''
+      ));
+
+      gl.disableVertexAttribArray(0);
+      gl.disableVertexAttribArray(1);
+    }
+
+    const noDrawIDProgram = wtu.setupProgram(gl, ["vshaderNoDrawID", "fshader"], ["vPosition", "vInstance"], [0, 1]);
+    expectTrue(noDrawIDProgram != null, "can compile simple program");
+    if (noDrawIDProgram) {
+      gl.useProgram(noDrawIDProgram);
+
+      if (!instanced) {
+        checkDraw({
+          drawFunc: multiDrawArrays,
+          drawID: false,
+        });
+        checkDraw({
+          drawFunc: multiDrawArraysWithNonzeroOffsets,
+          drawID: false,
+        });
+        checkDraw({
+          drawFunc: multiDrawElements,
+          indexed: true,
+          drawID: false,
+        });
+        checkDraw({
+          drawFunc: multiDrawElementsWithNonzeroOffsets,
+          indexed: true,
+          drawID: false,
+        });
+        checkDraw({
+          drawFunc: manyDrawArrays,
+          drawID: false,
+        });
+        checkDraw({
+          drawFunc: manyDrawElements,
+          indexed: true,
+          drawID: false,
+        });
+      } else {
+        checkDraw({
+          drawFunc: multiDrawArraysInstanced,
+          drawID: false,
+          instanced: true,
+        });
+        checkDraw({
+          drawFunc: multiDrawArraysInstancedWithNonzeroOffsets,
+          drawID: false,
+          instanced: true,
+        });
+        checkDraw({
+          drawFunc: multiDrawElementsInstanced,
+          indexed: true,
+          drawID: false,
+          instanced: true,
+        });
+        checkDraw({
+          drawFunc: multiDrawElementsInstancedWithNonzeroOffsets,
+          indexed: true,
+          drawID: false,
+          instanced: true,
+        });
+        checkDraw({
+          drawFunc: manyDrawArraysInstanced,
+          drawID: false,
+          instanced: true,
+        });
+        checkDraw({
+          drawFunc: manyDrawElementsInstanced,
+          indexed: true,
+          drawID: false,
+          instanced: true,
+        });
+      }
+    }
+
+    const withDrawIDProgram = wtu.setupProgram(gl, ["vshaderWithDrawID", "fshader"], ["vPosition", "vInstance"], [0, 1]);
+    expectTrue(withDrawIDProgram != null, "can compile program with ANGLE_multi_draw");
+    if (withDrawIDProgram) {
+      gl.useProgram(withDrawIDProgram);
+
+      if (!instanced) {
+        checkDraw({
+          drawFunc: multiDrawArrays,
+          drawID: true,
+        });
+        checkDraw({
+          drawFunc: multiDrawArraysWithNonzeroOffsets,
+          drawID: true,
+        });
+        checkDraw({
+          drawFunc: multiDrawElements,
+          indexed: true,
+          drawID: true,
+        });
+        checkDraw({
+          drawFunc: multiDrawElementsWithNonzeroOffsets,
+          indexed: true,
+          drawID: true,
+        });
+      } else {
+        checkDraw({
+          drawFunc: multiDrawArraysInstanced,
+          drawID: true,
+          instanced: true,
+        });
+        checkDraw({
+          drawFunc: multiDrawArraysInstancedWithNonzeroOffsets,
+          drawID: true,
+          instanced: true,
+        });
+        checkDraw({
+          drawFunc: multiDrawElementsInstanced,
+          indexed: true,
+          drawID: true,
+          instanced: true,
+        });
+        checkDraw({
+          drawFunc: multiDrawElementsInstancedWithNonzeroOffsets,
+          indexed: true,
+          drawID: true,
+          instanced: true,
+        });
+      }
+    }
+
+    const emulatedDrawIDProgram = wtu.setupProgram(gl, ["vshaderEmulatedDrawID", "fshader"], ["vPosition", "vInstance"], [0, 1]);
+    expectTrue(emulatedDrawIDProgram != null, "can compile program to emulate gl_DrawID");
+    drawIDLocation = gl.getUniformLocation(emulatedDrawIDProgram, "drawID");
+    if (emulatedDrawIDProgram) {
+      gl.useProgram(emulatedDrawIDProgram);
+
+      if (!instanced) {
+        checkDraw({
+          drawFunc: manyDrawArraysEmulateDrawID,
+          drawID: true,
+        });
+        checkDraw({
+          drawFunc: manyDrawElementsEmulateDrawID,
+          indexed: true,
+          drawID: true,
+        });
+      } else {
+        checkDraw({
+          drawFunc: manyDrawArraysInstancedEmulateDrawID,
+          drawID: true,
+          instanced: true,
+        });
+        checkDraw({
+          drawFunc: manyDrawElementsInstancedEmulateDrawID,
+          indexed: true,
+          drawID: true,
+          instanced: true,
+        });
+      }
+    }
+  }
+
+  runValidationTests();
+  runShaderTests();
+  runPixelTests();
+}
+
+runTest();
+
+const successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+</body>
+</html>
--- a/dom/canvas/test/webgl-conf/checkout/conformance/glsl/samplers/glsl-function-texture2dprojlod.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/glsl/samplers/glsl-function-texture2dprojlod.html
@@ -34,28 +34,28 @@
 <link rel="stylesheet" href="../../../resources/glsl-feature-tests.css"/>
 <script src="../../../js/js-test-pre.js"></script>
 <script src="../../../js/webgl-test-utils.js"> </script>
 </head>
 <body>
 <canvas id="example" width="256" height="256" style="width: 16px; height: 16px;"></canvas>
 <div id="description"></div>
 <div id="console"></div>
-<script id="vshader2d0" type="x-shader/x-vertex">
+<script id="vshader2dvec3" type="x-shader/x-vertex">
 attribute vec4 vPosition;
 varying vec4 color;
 uniform sampler2D tex;
 uniform float divisor;
 uniform float lod;
 void main() {
     gl_Position = vPosition;
     color = texture2DProjLod(tex, vec3(0.75 * divisor, 0.25 * divisor, divisor), lod);
 }
 </script>
-<script id="vshader2d1" type="x-shader/x-vertex">
+<script id="vshader2dvec4" type="x-shader/x-vertex">
 attribute vec4 vPosition;
 varying vec4 color;
 uniform sampler2D tex;
 uniform float divisor;
 uniform float lod;
 void main() {
     gl_Position = vPosition;
     color = texture2DProjLod(tex, vec4(0.75 * divisor, 0.25 * divisor, 123.0, divisor), lod);
@@ -84,76 +84,98 @@ var colors = [
   {name: 'blue', color:[0, 0, 255, 255]},
   {name: 'yellow', color:[255, 255, 0, 255]},
   {name: 'magenta', color:[255, 0, 255, 255]},
   {name: 'cyan', color:[0, 255, 255, 255]},
   {name: 'pink', color:[255, 128, 128, 255]},
   {name: 'gray', color:[128, 128, 128, 255]},
   {name: 'light green', color:[128, 255, 128, 255]},
 ];
+var contextTypes = ["2d", "webgl"];
+var vectorTypes = ["vec3", "vec4"];
 
 var gl = wtu.create3DContext(canvas);
 if (gl.getParameter(gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS) > 0) {
   runTest();
 } else {
   testPassed("MAX_VERTEX_TEXTURE_IMAGE_UNITS == 0, this is okay.");
 }
 
+
 function runTest() {
-  shouldBe("colors.length", "9");
-  for (var ss = 0; ss < 2; ++ss) {
-    debug("");
-    debug(ss ? "testing vec4 version" : "testing vec3 version");
-    var program = wtu.setupProgram(
-        gl, ['vshader2d' + ss, 'fshader2d'], ['vPosition', 'texCoord0'], [0, 1]);
-    wtu.setupUnitQuad(gl, 0, 1);
+  // Avoid creating a WebGL context for every test, as it causes:
+  // Too many active WebGL contexts. Oldest context will be lost.
+  var canvasWebGL = document.createElement("canvas");
+  var ctxWebGL = canvasWebGL.getContext("webgl");
+
+  // Might as well do the same for canvas 2d
+  var canvas2d = document.createElement("canvas");
+  var ctx2d = canvas2d.getContext("2d");
 
-    var tex = gl.createTexture();
-    gl.bindTexture(gl.TEXTURE_2D, tex);
-    gl.texParameteri(
-        gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_NEAREST);
-    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
-    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
-    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
+  shouldBe("colors.length", "9");
+  contextTypes.forEach((context) => {
+    vectorTypes.forEach((vectorType) => {
+      debug("");
+      debug(`testing ${context} context with ${vectorType} vertex shader`);
+      var program = wtu.setupProgram(
+          gl, ['vshader2d' + vectorType, 'fshader2d'], ['vPosition', 'texCoord0'], [0, 1]);
+      wtu.setupUnitQuad(gl, 0, 1);
 
-    // Fill the top right quadrant of each texture level with one of the colors
-    for (var ii = 0; ii < colors.length; ++ii) {
-      var color = colors[ii];
-      var size = Math.pow(2, colors.length - ii - 1);
+      var tex = gl.createTexture();
+      gl.bindTexture(gl.TEXTURE_2D, tex);
+      gl.texParameteri(
+          gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_NEAREST);
+      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
+      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
+
+      // Fill the top right quadrant of each texture level with one of the colors
+      for (var ii = 0; ii < colors.length; ++ii) {
+        var color = colors[ii];
+        var size = Math.pow(2, colors.length - ii - 1);
 
-      var c = document.createElement("canvas");
-      c.width = size;
-      c.height = size;
-      var ctx = c.getContext("2d");
-      ctx.fillStyle = "rgb(0,0,0)";
-      ctx.fillRect(0, 0, size, size);
-      ctx.fillStyle = "rgb(" + color.color[0] + "," + color.color[1] + "," + color.color[2] + ")";
-      ctx.fillRect(size / 2, 0, size / 2, size / 2);
-
-      gl.texImage2D(gl.TEXTURE_2D, ii, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, c);
-    }
-
-    var lodLoc = gl.getUniformLocation(program, "lod");
-    var divLoc = gl.getUniformLocation(program, "divisor");
+        if (context === "2d") {
+          canvas2d.width = size;
+          canvas2d.height = size;
+          ctx2d.fillStyle = "rgb(0,0,0)";
+          ctx2d.fillRect(0, 0, size, size);
+          ctx2d.fillStyle = "rgb(" + color.color[0] + "," + color.color[1] + "," + color.color[2] + ")";
+          ctx2d.fillRect(size / 2, 0, size / 2, size / 2);
+          gl.texImage2D(gl.TEXTURE_2D, ii, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, canvas2d);
+        } else if (context === "webgl") {
+          canvasWebGL.width = canvasWebGL.height = size;
+          ctxWebGL.clearColor(0, 0, 0, 1);
+          ctxWebGL.clear(gl.COLOR_BUFFER_BIT);
+          ctxWebGL.enable(gl.SCISSOR_TEST);
+          ctxWebGL.scissor(size/2, size/2, size/2, size/2)
+          ctxWebGL.clearColor(color.color[0]/255, color.color[1]/255, color.color[2]/255, 1)
+          ctxWebGL.clear(gl.COLOR_BUFFER_BIT);
+          gl.texImage2D(gl.TEXTURE_2D, ii, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, canvasWebGL);
+        }
+      }
 
-    for (var div = 1; div < 4; ++div) {
-      for (var ii = 0; ii < colors.length - 1; ++ii) {
-        gl.uniform1f(lodLoc, ii);
-        gl.uniform1f(divLoc, div);
-        var lodColor = colors[ii];
-        var size = Math.pow(2, colors.length - ii - 1);
-        wtu.clearAndDrawUnitQuad(gl);
-        wtu.checkCanvas(
-            gl, lodColor.color,
-            "sampling with lod = " + ii +
-            " divider = " + div +
-            " should be " + lodColor.name);
+      var lodLoc = gl.getUniformLocation(program, "lod");
+      var divLoc = gl.getUniformLocation(program, "divisor");
+
+      for (var div = 1; div < 4; ++div) {
+        for (var ii = 0; ii < colors.length - 1; ++ii) {
+          gl.uniform1f(lodLoc, ii);
+          gl.uniform1f(divLoc, div);
+          var lodColor = colors[ii];
+          var size = Math.pow(2, colors.length - ii - 1);
+          wtu.clearAndDrawUnitQuad(gl);
+          wtu.checkCanvas(
+              gl, lodColor.color,
+              "sampling with lod = " + ii +
+              " divider = " + div +
+              " should be " + lodColor.name);
+        }
       }
-    }
-  }
+    });
+  });
   wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors.");
 }
 
 var successfullyParsed = true;
 
 </script>
 <script src="../../../js/js-test-post.js"></script>
 
--- a/dom/canvas/test/webgl-conf/checkout/conformance/more/00_test_list.txt
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/more/00_test_list.txt
@@ -20,17 +20,16 @@ functions/bufferDataBadArgs.html
 functions/bufferSubData.html
 functions/bufferSubDataBadArgs.html
 functions/copyTexImage2D.html
 functions/copyTexImage2DBadArgs.html
 functions/copyTexSubImage2D.html
 functions/copyTexSubImage2DBadArgs.html
 functions/deleteBufferBadArgs.html
 functions/drawArrays.html
-functions/drawArraysOutOfBounds.html
 functions/drawElements.html
 functions/isTests.html
 --min-version 1.0.2 functions/isTestsBadArgs.html
 functions/readPixels.html
 functions/readPixelsBadArgs.html
 functions/texImage2D.html
 functions/texImage2DBadArgs.html
 functions/texImage2DHTML.html
@@ -46,12 +45,10 @@ functions/uniformi.html
 functions/uniformiBadArgs.html
 functions/uniformMatrix.html
 functions/uniformMatrixBadArgs.html
 functions/vertexAttrib.html
 functions/vertexAttribBadArgs.html
 functions/vertexAttribPointer.html
 functions/vertexAttribPointerBadArgs.html
 glsl/arrayOutOfBounds.html
-#glsl/longLoops.html // No interactive tests.
 glsl/uniformOutOfBounds.html
-#glsl/unusedAttribsUniforms.html // No interactive tests.
 
--- a/dom/canvas/test/webgl-conf/checkout/conformance/more/conformance/quickCheckAPI.js
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/more/conformance/quickCheckAPI.js
@@ -354,16 +354,17 @@ randomImage = function(w,h) {
   var img;
   var r = Math.random();
   if (r < 0.25) {
     img = document.createElement('canvas');
     img.width = w; img.height = h;
     img.getContext('2d').fillRect(0,0,w,h);
   } else if (r < 0.5) {
     img = document.createElement('video');
+    img.muted = true;
     img.width = w; img.height = h;
   } else if (r < 0.75) {
     img = document.createElement('img');
     img.width = w; img.height = h;
   } else {
     img = canvas2D.getContext('2d').createImageData(w,h);
   }
   return img
deleted file mode 100644
--- a/dom/canvas/test/webgl-conf/checkout/conformance/more/demos/opengl_web.html
+++ /dev/null
@@ -1,607 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<meta charset="utf-8">
-<!--
-
-/*
-** Copyright (c) 2012 The Khronos Group Inc.
-**
-** Permission is hereby granted, free of charge, to any person obtaining a
-** copy of this software and/or associated documentation files (the
-** "Materials"), to deal in the Materials without restriction, including
-** without limitation the rights to use, copy, modify, merge, publish,
-** distribute, sublicense, and/or sell copies of the Materials, and to
-** permit persons to whom the Materials are furnished to do so, subject to
-** the following conditions:
-**
-** The above copyright notice and this permission notice shall be included
-** in all copies or substantial portions of the Materials.
-**
-** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
-*/
-
--->
-
-<title>OpenGL for the web</title>
-
-<script type="application/javascript" src="../util.js"></script>
-
-    <script type="application/javascript">
-
-function log(msg) {
-  document.getElementById('note').textContent += "\n"+msg;
-}
-
-
-
-
-function init(ev) {
-    var canvas = document.getElementById('canvas');
-    var gl = getGLContext(canvas);
-
-    var shader = new Shader(gl, "ppix-vert", "ppix-frag");
-    shader.compile();
-    var fbo = new FBO(gl, canvas.width, canvas.height);
-    var fbo2 = new FBO(gl, canvas.width, canvas.height);
-    var fbo3 = new FBO(gl, canvas.width, canvas.height);
-    var depth = new Shader(gl, "depth-vert", "depth-frag");
-    var identity = new Filter(gl, "identity-vert", "identity-frag");
-    var unpremult = new Filter(gl, "identity-vert", "unpremult-frag");
-    var hblur = new Filter(gl, "identity-vert", "hblur-frag");
-    var vblur = new Filter(gl, "identity-vert", "vblur-frag");
-    var hdof = new Filter(gl, "identity-vert", "hdof-frag");
-    var vdof = new Filter(gl, "identity-vert", "vdof-frag");
-
-    redraw(canvas, gl, shader, fbo, fbo2, fbo3, depth, identity, unpremult, hblur, vblur, hdof, vdof);
-
-    setInterval(function(){
-        redraw(canvas, gl, shader, fbo, fbo2, fbo3, depth, identity, unpremult, hblur, vblur, hdof, vdof);
-    }, 33);
-}
-
-function drawCube (gl, shader, angle, axis, x,y,z, s, va, na, ta) {
-    Matrix.copyMatrix(look, vmat);
-    Matrix.translate3InPlace(x,y,z,vmat);
-    Matrix.scale1InPlace(s,vmat);
-    Matrix.rotateInPlace(angle, axis, vmat);
-
-    // Note: we could just use mat3(MVMatrix) as the normal matrix
-    // as MVMatrix has only rotations, translations and uniform scaling
-    // <=> MVMatrix is a scaled orthonormal matrix
-    // hence normalize(mat3(MVMatrix)*v) == normalize(mat3(transpose(inverse(MVMatrix))*v)
-    //
-    // But let's do it the hard way to see if Matrix.inverse3x3 works...
-    Matrix.inverseTo3x3InPlace(vmat, nmat);
-    Matrix.transpose3x3InPlace(nmat);
-
-    shader.uniformMatrix4fv("MVMatrix", vmat);
-    shader.uniformMatrix3fv("NMatrix", nmat);
-
-    var cube = Cube.getCachedVBO(gl);
-    cube.draw(va, na, ta);
-}
-
-var carr = [];
-for (var i=0; i<25; i++) {
-    carr.push([Math.random(), Math.random(), Math.random()]);
-}
-
-function drawScene (gl, shader, va, na, ta) {
-    var ot = new Date().getTime();
-    var t = ot;
-
-    shader.uniformMatrix4fv("PMatrix", pmat);
-    for (var i=0; i<carr.length; i++){
-        var c = carr[i];
-        var f = c[1] < 0.5 ? 1 : -1;
-        var t = ot;
-        drawCube(gl, shader,
-                (t/(f*400*(c[0]+0.5))) % (2*Math.PI), c,
-
-                0.45+0.8*c[2],
-                -0.4+Math.cos((i/carr.length*Math.PI*2)+t/1000),
-                0.8+Math.sin((i/carr.length*Math.PI*2)+t/1000)*3.2,
-
-                0.05 + Math.pow((c[0]+c[1]+c[2])*0.33, 2)*0.3,
-                va, na, ta);
-    }
-}
-
-var nmat = Matrix.newIdentity3x3();
-var vmat = Matrix.newIdentity();
-var vmat2 = Matrix.newIdentity();
-var pmat = null;
-var look = Matrix.lookAt([4,-1,8], [-0.2,0,0], [0,1,0]);
-var useDoF = false;
-
-var firstFrame = true;
-
-function redraw(canvas, gl, shader, fbo, fbo2, fbo3, depth, identity, unpremult, hblur, vblur, hdof, vdof) {
-
-    var doDoF = useDoF;
-    gl.viewport(0, 0, canvas.width, canvas.height);
-    gl.clearColor(0.0, 0.0, 0.0, 0.0);
-    gl.enable(gl.DEPTH_TEST);
-
-    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
-    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
-
-    fbo.use();
-    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
-
-    shader.use();
-
-    var va = shader.attrib("Vertex");
-    var na = shader.attrib("Normal");
-    var ta = shader.attrib("Tex");
-
-    if (pmat == null)
-        pmat = Matrix.perspective(30, canvas.width/canvas.height, 1, 100);
-
-    shader.uniform4f("MaterialSpecular", 0.95, 0.9, 0.6, 1);
-    shader.uniform4f("MaterialDiffuse", 0.50, 0.35, 0.35, 1);
-    shader.uniform4f("MaterialAmbient", 0.0, 0.1, 0.2, 1);
-    shader.uniform1f("MaterialShininess", 1.5);
-
-    shader.uniform4f("GlobalAmbient", 0.1, 0.1, 0.1, 1);
-
-    shader.uniform4f("LightPos", 1, 5, 3, 1.0);
-
-    shader.uniform4f("LightSpecular", 0.9, 0.9, 0.9, 1);
-    shader.uniform4f("LightDiffuse", 0.8, 0.8, 0.8, 1);
-    shader.uniform4f("LightAmbient", 0.0, 0.06, 0.2, 1);
-    shader.uniform1f("LightConstantAtt", 0.0);
-    shader.uniform1f("LightLinearAtt", 0.1);
-    shader.uniform1f("LightQuadraticAtt", 0.0);
-
-    drawScene(gl, shader, va, na);
-
-    if (doDoF || firstFrame) {
-
-        fbo3.use();
-        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
-        depth.use();
-        var dva = depth.attrib("Vertex");
-
-        drawScene(gl, depth, dva);
-
-        gl.disable(gl.DEPTH_TEST);
-        gl.activeTexture(gl.TEXTURE1);
-        gl.bindTexture(gl.TEXTURE_2D, fbo3.texture);
-        gl.activeTexture(gl.TEXTURE0);
-
-
-        for (var i=0; i<3; i++) {
-            fbo2.use();
-            gl.bindTexture(gl.TEXTURE_2D, fbo.texture);
-
-            hdof.apply(function(f){
-                f.uniform1i("Texture", 0);
-                f.uniform1i("Depth", 1);
-                f.uniform1f("iter", i);
-                f.uniform1f("step", 1.0/canvas.width);
-            });
-
-            fbo.use();
-            gl.bindTexture(gl.TEXTURE_2D, fbo2.texture);
-
-            vdof.apply(function(f){
-                f.uniform1i("Texture", 0);
-                f.uniform1i("Depth", 1);
-                f.uniform1f("iter", i);
-                f.uniform1f("step", 1.0/canvas.width);
-            });
-        }
-
-    }
-    firstFrame = false;
-
-    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
-
-    gl.activeTexture(gl.TEXTURE1);
-    gl.bindTexture(gl.TEXTURE_2D, null);
-    gl.activeTexture(gl.TEXTURE0);
-    gl.bindTexture(gl.TEXTURE_2D, fbo.texture);
-
-    // The DoF blur blurs the color from the transparent black background with
-    // the cubes. To get rid of the border, we can treat it as premultiplied alpha.
-    // To see the problem, try replacing unpremult with identity.
-    unpremult.apply(function(f){
-      f.uniform1i("Texture", 0);
-    });
-
-}
-
-window.addEventListener("load", init, false);
-    </script>
-
-    <script id="ppix-vert" type="x-shader/x-vertex">
-      attribute vec3 Vertex;
-      attribute vec3 Normal;
-      attribute vec2 Tex;
-
-      uniform mat4 PMatrix;
-      uniform mat4 MVMatrix;
-      uniform mat3 NMatrix;
-
-      uniform vec4 MaterialAmbient;
-      uniform vec4 MaterialDiffuse;
-
-      uniform vec4 LightAmbient;
-      uniform vec4 LightDiffuse;
-
-      uniform vec4 GlobalAmbient;
-
-      uniform vec4 LightPos;
-
-      varying vec4 diffuse, ambientGlobal, ambient;
-      varying vec3 normal, lightDir, halfVector;
-      varying float dist;
-
-      void main()
-      {
-        vec4 worldPos;
-        vec3 lightVector;
-        vec4 v = vec4(Vertex, 1.0);
-
-        /* transform vertex normal into world space and normalize */
-        normal = normalize(NMatrix * Normal);
-
-        /* transform vertex into world space and compute the vector
-          from it to the light */
-        worldPos = MVMatrix * v;
-        lightVector = vec3(LightPos - worldPos);
-        lightDir = normalize(lightVector);
-        dist = length(lightVector);
-
-        /* Half-vector used in Blinn-Phong shading due to computational efficiency */
-        halfVector = normalize(lightVector - vec3(worldPos));
-
-        diffuse = MaterialDiffuse * LightDiffuse;
-
-        /* The ambient terms have been separated since one of them */
-        /* suffers attenuation */
-        ambient = MaterialAmbient * LightAmbient;
-        ambientGlobal = GlobalAmbient * MaterialAmbient;
-
-        gl_Position = PMatrix * worldPos;
-      }
-    </script>
-
-    <script id="ppix-frag" type="x-shader/x-fragment">
-      precision mediump float;
-
-      uniform vec4 LightSpecular;
-      uniform vec4 MaterialSpecular;
-      uniform float MaterialShininess;
-
-      uniform float LightConstantAtt;
-      uniform float LightLinearAtt;
-      uniform float LightQuadraticAtt;
-
-      varying vec4 diffuse,ambientGlobal, ambient;
-      varying vec3 normal, lightDir, halfVector;
-      varying float dist;
-
-      void main()
-      {
-        vec3 n, halfV, viewV, ldir;
-        float NdotL, NdotHV;
-        vec4 color = ambientGlobal;
-        float att;
-
-        n = normalize(normal);
-
-        NdotL = max(dot(n, normalize(lightDir)), 0.0);
-
-        if (NdotL > 0.0) {
-
-          att = 1.0 / (LightConstantAtt + LightLinearAtt * dist + LightQuadraticAtt * dist * dist);
-
-          color += att * (diffuse * NdotL + ambient);
-
-          halfV = normalize(halfVector);
-          NdotHV = max( dot(normal, halfV), 0.0 );
-
-          color += att * MaterialSpecular * LightSpecular * pow(NdotHV, MaterialShininess);
-        }
-
-        gl_FragColor = color;
-      }
-    </script>
-    <script id="depth-vert" type="x-shader/x-vertex">
-      attribute vec3 Vertex;
-      uniform mat4 PMatrix;
-      uniform mat4 MVMatrix;
-      varying float depth;
-      void main()
-      {
-        gl_Position = PMatrix * (MVMatrix * vec4(Vertex, 1.0));
-        depth = 1.0-(gl_Position.z / gl_Position.w);
-      }
-    </script>
-    <script id="depth-frag" type="x-shader/x-fragment">
-      precision mediump float;
-
-      varying float depth;
-      void main()
-      {
-        vec4 c = vec4(depth, 0.0, 0.0, 1.0);
-        gl_FragColor = c;
-      }
-    </script>
-
-    <script id="identity-vert" type="x-shader/x-vertex">
-      attribute vec3 Vertex;
-      attribute vec2 Tex;
-
-      varying vec4 texCoord0;
-      void main()
-      {
-        texCoord0 = vec4(Tex,0.0,0.0);
-        gl_Position = vec4(Vertex, 1.0);
-      }
-    </script>
-    <script id="identity-frag" type="x-shader/x-fragment">
-      precision mediump float;
-
-      uniform sampler2D Texture;
-
-      varying vec4 texCoord0;
-      void main()
-      {
-        vec4 c = texture2D(Texture, texCoord0.st);
-        gl_FragColor = c;
-      }
-    </script>
-    <script id="premult-frag" type="x-shader/x-fragment">
-      precision mediump float;
-
-      uniform sampler2D Texture;
-
-      varying vec4 texCoord0;
-      void main()
-      {
-        vec4 c = texture2D(Texture, texCoord0.st);
-        float a = c.a;
-        c *= a;
-        c.a = a;
-        gl_FragColor = c;
-      }
-    </script>
-    <script id="unpremult-frag" type="x-shader/x-fragment">
-      precision mediump float;
-
-      uniform sampler2D Texture;
-
-      varying vec4 texCoord0;
-      void main()
-      {
-        vec4 c = texture2D(Texture, texCoord0.st);
-        float a = c.a;
-        c /= a;
-        c.a = a;
-        gl_FragColor = c;
-      }
-    </script>
-
-    <script id="hblur-frag" type="x-shader/x-fragment">
-      precision mediump float;
-
-      uniform sampler2D Texture;
-      uniform float step;
-      float kernel[7] = float[](0.046, 0.111, 0.202, 0.283, 0.202, 0.111, 0.046);
-
-      varying vec4 texCoord0;
-      void main()
-      {
-        int i=0;
-        if (texture2D(Texture, texCoord0.st).a > 0.0) {
-          vec4 sum = vec4(0.0);
-          for (i=0; i<7; i++) {
-            vec4 tmp = texture2D(Texture, texCoord0.st + vec2(i*step,0));
-            sum += tmp * kernel[i];
-          }
-          gl_FragColor = sum;
-        } else {
-          gl_FragColor = texture2D(Texture, texCoord0.st);
-        }
-      }
-    </script>
-    <script id="vblur-frag" type="x-shader/x-fragment">
-      precision mediump float;
-
-      uniform sampler2D Texture;
-      uniform float step;
-      float kernel[7] = float[](0.046, 0.111, 0.202, 0.283, 0.202, 0.111, 0.046);
-
-      varying vec4 texCoord0;
-      void main()
-      {
-        int i=0;
-        if (texture2D(Texture, texCoord0.st).a > 0.0) {
-          vec4 sum = vec4(0.0);
-          for (i=0; i<7; i++) {
-            vec4 tmp = texture2D(Texture, texCoord0.st + vec2(0,i*step));
-            sum += tmp * kernel[i];
-          }
-          gl_FragColor = sum;
-        } else {
-          gl_FragColor = texture2D(Texture, texCoord0.st);
-        }
-      }
-    </script>
-    <script id="hdof-frag" type="x-shader/x-fragment">
-      precision mediump float;
-
-      uniform sampler2D Texture;
-      uniform sampler2D Depth;
-      uniform float step;
-      uniform float iter;
-      float kernel[7] = { 0.046, 0.111, 0.202, 0.283, 0.202, 0.111, 0.046 };
-
-      varying vec4 texCoord0;
-      void main()
-      {
-        vec4 tmp;
-        vec4 sum = vec4(0.0);
-        bool b = (iter < -26.0+36.0*(1.0-texture2D(Depth, texCoord0.st).r) && texture2D(Texture, texCoord0.st).a > 0.0);
-        tmp = texture2D(Texture, texCoord0.st + vec2(float(0-3)*step,0));
-        sum += tmp * kernel[0];
-        tmp = texture2D(Texture, texCoord0.st + vec2(float(1-3)*step,0));
-        sum += tmp * kernel[1];
-        tmp = texture2D(Texture, texCoord0.st + vec2(float(2-3)*step,0));
-        sum += tmp * kernel[2];
-        tmp = texture2D(Texture, texCoord0.st + vec2(float(3-3)*step,0));
-        sum += tmp * kernel[3];
-        tmp = texture2D(Texture, texCoord0.st + vec2(float(4-3)*step,0));
-        sum += tmp * kernel[4];
-        tmp = texture2D(Texture, texCoord0.st + vec2(float(5-3)*step,0));
-        sum += tmp * kernel[5];
-        tmp = texture2D(Texture, texCoord0.st + vec2(float(6-3)*step,0));
-        sum += tmp * kernel[6];
-        gl_FragColor = mix(texture2D(Texture, texCoord0.st), sum, b ? 1.0 : 0.0);
-      }
-    </script>
-    <script id="vdof-frag" type="x-shader/x-fragment">
-      precision mediump float;
-
-      uniform sampler2D Texture;
-      uniform sampler2D Depth;
-      uniform float step;
-      uniform float iter;
-      float kernel[7] = float[7](0.046, 0.111, 0.202, 0.283, 0.202, 0.111, 0.046);
-
-      varying vec4 texCoord0;
-      void main()
-      {
-        vec4 tmp;
-        vec4 sum = vec4(0.0);
-        bool b = (iter < -26.0+36.0*(1.0-texture2D(Depth, texCoord0.st).r) && texture2D(Texture, texCoord0.st).a > 0.0);
-        tmp = texture2D(Texture, texCoord0.st + vec2(0,float(0-3)*step));
-        sum += tmp * kernel[0];
-        tmp = texture2D(Texture, texCoord0.st + vec2(0,float(1-3)*step));
-        sum += tmp * kernel[1];
-        tmp = texture2D(Texture, texCoord0.st + vec2(0,float(2-3)*step));
-        sum += tmp * kernel[2];
-        tmp = texture2D(Texture, texCoord0.st + vec2(0,float(3-3)*step));
-        sum += tmp * kernel[3];
-        tmp = texture2D(Texture, texCoord0.st + vec2(0,float(4-3)*step));
-        sum += tmp * kernel[4];
-        tmp = texture2D(Texture, texCoord0.st + vec2(0,float(5-3)*step));
-        sum += tmp * kernel[5];
-        tmp = texture2D(Texture, texCoord0.st + vec2(0,float(6-3)*step));
-        sum += tmp * kernel[6];
-        gl_FragColor = mix(texture2D(Texture, texCoord0.st), sum, b ? 1.0 : 0.0);
-      }
-    </script>
-
-    <style>
-      * { margin: 0px; padding: 0px; }
-      html {
-        background-color: #707888;
-        color: #222222;
-      }
-      #canvas {
-        position: absolute;
-        cursor: pointer;
-        top: 115px; left: 550px;
-      }
-      #note {
-        position: absolute;
-        top: 4px;
-        left: 4px;
-      }
-      #content {
-        margin-left: 99px;
-        padding-left: 8px;
-        padding-right: 8px;
-        padding-bottom: 16px;
-        width: 600px;
-        background-color: rgba(255,255,255,1.0);
-        text-align: center;
-        border-left: 1px solid rgba(0,0,0,0.5);
-        border-right: 2px solid rgba(0,0,0,0.75);
-      }
-      h1 {
-        padding-top: 24px;
-        padding-bottom: 16px;
-        margin-bottom: 24px;
-        border-bottom: 1px solid black;
-        font-family: Times New Roman, Serif;
-        font-weight: bold;
-        font-size: 40px;
-      }
-      #content p {
-        text-indent: 24px;
-        margin-left: 24px;
-        margin-right: 32px;
-        text-align: justify;
-        font-family: Serif;
-        padding-bottom: 16px;
-      }
-      #above {
-        position: absolute;
-        top: 300px;
-        left: 716px;
-        padding: 10px 20px;
-        background-color: rgba(0,225,0,0.5);
-        border-left: 2px solid rgba(0,64,0,0.75);
-        color: white;
-        font-size: small;
-        font-family: sans-serif;
-      }
-      #above p {
-        text-align: center;
-      }
-    </style>
-
-</head><body>
-    <canvas id="canvas" width="400" height="400" title="Click to toggle DOF shader" onclick="useDoF = !useDoF"></canvas>
-    <pre id="note"></pre>
-
-    <div id="content">
-    <h1>OpenGL for the web</h1>
-    <p>
-The WebGL specification gives web developers access to an
-OpenGL ES 2.0 drawing context for the canvas tag. What that means is
-that you can finally harness the power of the GPU for awesome visuals
-and heavy-duty number crunching in your web apps. </p><p> OpenGL ES 2.0 is a subset of OpenGL 2.0 aimed at embedded
-devices and game consoles. As such, it's a very minimalistic low-level
-API, even more so than desktop OpenGL. In fact, if you took desktop
-OpenGL and stripped out everything but shaders, vertex arrays and
-textures, you'd get something quite like OpenGL ES 2.0. </p>
-    <p>
-      As there is no fixed-function pipeline, you need to write GLSL shaders to draw <i>anything</i>.
-And you need to do your own transformation math, including keeping
-track of the transformation matrix stack. So the raw API is really not
-for the faint of heart; you do need to know your 3D math and shading
-equations. </p>
-    <p> For example, to draw the spinning cubes on the
-right - around 200 lines of application code, 250 lines of shaders and
-800 lines of library code - I had to scrounge the internet for <a href="http://www.lighthouse3d.com/opengl/glsl/index.php?pointlight">GLSL shaders</a>
-to do the transformation and lighting, write a small matrix math
-library in JavaScript and a DOF blur shader. While highly educational,
-it was also a rather steep hill to climb. </p>
-    <p> So, the intended audience of the raw context
-interface are not really end-users, but library developers who can
-write easy-to-use interfaces to the functionality, and 3D developers
-who require a high level of control over the rendering pipeline. </p>
-    <p> The really cool thing about the OpenGL Canvas is
-that it doesn't make policy decisions. There's no single set-in-stone
-use case for it: In addition to 3D graphics, you can also use it for
-filtering images, visualizing fluid dynamics, doing real-time video
-effects, or just crunching a whole lot of FP math. If you can do it on
-the GPU, you're in luck! </p>
-    </div>
-    <div id="above">
-      <p>You can also place content above the canvas</p>
-    </div>
-  </body></html>
deleted file mode 100644
--- a/dom/canvas/test/webgl-conf/checkout/conformance/more/demos/video.html
+++ /dev/null
@@ -1,163 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<meta charset="utf-8">
-<!--
-
-/*
-** Copyright (c) 2012 The Khronos Group Inc.
-**
-** Permission is hereby granted, free of charge, to any person obtaining a
-** copy of this software and/or associated documentation files (the
-** "Materials"), to deal in the Materials without restriction, including
-** without limitation the rights to use, copy, modify, merge, publish,
-** distribute, sublicense, and/or sell copies of the Materials, and to
-** permit persons to whom the Materials are furnished to do so, subject to
-** the following conditions:
-**
-** The above copyright notice and this permission notice shall be included
-** in all copies or substantial portions of the Materials.
-**
-** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
-*/
-
--->
-<script type="application/javascript" src="../util.js"></script>
-<script>
-"use strict";
-var processor = {
-  lastTime : new Date,
-  timerCallback: function() {
-    if (this.video.paused || this.video.ended) {
-      return;
-    }
-    this.computeFrame();
-    var t = new Date;
-    var elapsed = t - this.lastTime;
-    this.lastTime = t;
-    var self = this;
-    setTimeout(function () {
-        self.timerCallback();
-      }, Math.max(0, 33-elapsed));
-  },
-
-  init: function() {
-    if (this.initDone) return;
-    this.c2 = document.getElementById("c2");
-    this.ctx2 = getGLContext(this.c2);
-    this.greenScreen = new Filter(this.ctx2, 'identity-flip-vert', 'greenScreen');
-    this.ctx2.activeTexture(this.ctx2.TEXTURE0);
-    this.tex = loadTexture(this.ctx2, this.c1, false);
-    this.ctx2.activeTexture(this.ctx2.TEXTURE1);
-    this.tex2 = loadTexture(this.ctx2, document.getElementById('i'), false);
-    this.ctx2.activeTexture(this.ctx2.TEXTURE0);
-    this.initDone = true;
-  },
-
-  doLoad: function() {
-    this.video = document.getElementById("video");
-    this.c1 = document.getElementById("c1");
-    this.ctx1 = this.c1.getContext("2d");
-    this.ctx1.globalCompositeOperation = 'copy';
-    this.ctx1.fillRect(0,0,this.c1.width, this.c1.height);
-    var self = this;
-    this.video.addEventListener("play", function() {
-        self.init();
-        self.width = self.video.videoWidth;
-        self.height = self.video.videoHeight;
-        self.lastTime = new Date;
-        self.timerCallback();
-      }, false);
-  },
-
-  computeFrame: function() {
-//     this.ctx1.drawImage(this.video, 0, 0, this.width, this.height);
-    this.ctx2.texImage2D(this.ctx2.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.video);
-    this.greenScreen.apply(function(s) {
-        s.uniform1i('Texture', 0);
-        s.uniform1i('Texture2', 1);
-    });
-
-    return;
-  }
-};
-
-</script>
-<script id="identity-flip-vert" type="x-shader/x-vertex">
-    attribute vec3 Vertex;
-    attribute vec2 Tex;
-
-    varying vec4 texCoord0;
-    void main()
-    {
-        texCoord0 = vec4(Tex.s,1.0-Tex.t,0.0,0.0);
-        gl_Position = vec4(Vertex, 1.0);
-    }
-</script>
-<script id="greenScreen" type="x-shader/x-fragment">
-    precision mediump float;
-
-    uniform sampler2D Texture;
-    uniform sampler2D Texture2;
-
-    varying vec4 texCoord0;
-    void main()
-    {
-        vec4 c = texture2D(Texture, texCoord0.st);
-        float r = c.r * 0.5;
-        float a = c.g * 6.28;
-        float x = cos(a) * r;
-        float y = sin(a) * r;
-        vec4 c2 = texture2D(Texture2, vec2(0.7+x, 0.5+y));
-        // Shaders with branches are not allowed when dealing with non-SOP content
-        // so instead of "if (b) c2.a = 0;", we use mix()
-        bool b = (c.g > 120.0/255.0 && c.r > 120.0/255.0 && c.b < 50.0/255.0);
-        c2.a = mix(c2.a, 0.0, float(b));
-        gl_FragColor = c2;
-    }
-</script>
-    <style>
-      body {
-        background: black;
-        color:#CCCCCC;
-      }
-      a {
-          color: white;
-      }
-      #c2 {
-        background-image: url(http://www.mozbox.org/pub/green/foo.png);
-        background-repeat: repeat;
-      }
-      div {
-        float: left;
-        border :1px solid #444444;
-        padding:10px;
-        margin: 10px;
-        background:#3B3B3B;
-      }
-      img { display: none; }
-    </style>
- </head>
-  <body onload="processor.doLoad()">
-    <div>
-        This is a port of Paul Rouget's <a href="http://blog.mozbox.org/post/2009/02/25/video-canvas%3A-special-effects">Canvas+Video green screen demo</a>, plus a texture lookup from the Firefox logo based on the values of the green and red color channels.
-    </div>
-    <div>
-      <video id="video" controls="true">
-        <source src="http://www.mozbox.org/pub/green/video.ogv"></source>
-        <source src="http://cs.helsinki.fi/u/ilmarihe/c3d/demos/video.mp4"></source>
-      </video>
-      <canvas id="c1" width="320" height="192"></canvas>
-    </div>
-    <div>
-      <canvas id="c2" width="640" height="384"></canvas>
-    </div>
-    <img id="i" src="http://www.mozbox.org/pub/green/foo.png">
-  </body>
-</html>
--- a/dom/canvas/test/webgl-conf/checkout/conformance/more/functions/bufferSubDataBadArgs.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/more/functions/bufferSubDataBadArgs.html
@@ -62,18 +62,24 @@ Tests.testBufferData = function(gl) {
     assertFail("offset out of range",
         function(){gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, 24, new Uint16Array([1,2,3]));});
     assertFail("offset out of range",
         function(){gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, 2400000, new Uint16Array([1,2,3]));});
     assertFail("offset out of range",
         function(){gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, 19, new Uint16Array([1,2,3]));});
     assertFail("data too large",
         function(){gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, 0, new Uint16Array(data.concat([1])));});
-    assertOk("offset + data too large",
+    assertOk("offset + data.length = end",
         function(){gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, 18, new Uint16Array([1,2,3]));});
+    assertOk("offset Infinity",
+        function(){gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, Infinity, new Uint16Array([1,2,3]));});
+    assertOk("offset -Infinity",
+        function(){gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, -Infinity, new Uint16Array([1,2,3]));});
+    assertOk("offset NaN",
+        function(){gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, NaN, new Uint16Array([1,2,3]));});
     assertOk("good args",
         function(){gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, 0, new Uint16Array([1,2,3]));});
     throwError(gl, 'bufferData0');
     gl.bindBuffer(gl.ARRAY_BUFFER, null);
     assertFail("setting buffer 0",
       function(){gl.bufferSubData(gl.ARRAY_BUFFER, 0, new Float32Array([1,2,3]));});
     throwError(gl, 'bufferData1');
     gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
--- a/dom/canvas/test/webgl-conf/checkout/conformance/more/functions/drawArrays.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/more/functions/drawArrays.html
@@ -84,26 +84,22 @@ Tests.testDrawArraysVBOMulti = function(
     {size:3, data:Quad.normals},
     {size:2, data:Quad.texcoords});
   vbo.draw(v, n, t);
   assert(0 == checkError(gl, "vbo.draw"));
   assertOk(function(){gl.drawArrays(gl.TRIANGLES, 5, 1);});
   assertOk(function(){gl.drawArrays(gl.TRIANGLES, 0, 2);});
   assertOk(function(){gl.drawArrays(gl.TRIANGLES, 0, 6);});
   assertOk(function(){gl.drawArrays(gl.TRIANGLES, 1, 5);});
-  assertFail(function(){gl.drawArrays(gl.TRIANGLES, 1, 6);});
-  assertFail(function(){gl.drawArrays(gl.TRIANGLES, 6, 1);});
   gl.bindBuffer(gl.ARRAY_BUFFER, vbo.vbos[1]);
   gl.vertexAttribPointer(n, 3, gl.FLOAT, false, 0, 0);
   assertOk(function(){gl.drawArrays(gl.TRIANGLES, 5, 1);});
   assertOk(function(){gl.drawArrays(gl.TRIANGLES, 0, 2);});
   assertOk(function(){gl.drawArrays(gl.TRIANGLES, 0, 6);});
   assertOk(function(){gl.drawArrays(gl.TRIANGLES, 1, 5);});
-  assertFail(function(){gl.drawArrays(gl.TRIANGLES, 1, 6);});
-  assertFail(function(){gl.drawArrays(gl.TRIANGLES, 6, 1);});
   vbo.destroy();
   assert(0 == checkError(gl, "vbo.destroy"));
 }
 
 
 </script>
 <script id="vert" type="x-shader/x-vertex">
   attribute vec3 Vertex;
deleted file mode 100644
--- a/dom/canvas/test/webgl-conf/checkout/conformance/more/functions/drawArraysOutOfBounds.html
+++ /dev/null
@@ -1,305 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<meta charset="utf-8">
-<!--
-
-/*
-** Copyright (c) 2012 The Khronos Group Inc.
-**
-** Permission is hereby granted, free of charge, to any person obtaining a
-** copy of this software and/or associated documentation files (the
-** "Materials"), to deal in the Materials without restriction, including
-** without limitation the rights to use, copy, modify, merge, publish,
-** distribute, sublicense, and/or sell copies of the Materials, and to
-** permit persons to whom the Materials are furnished to do so, subject to
-** the following conditions:
-**
-** The above copyright notice and this permission notice shall be included
-** in all copies or substantial portions of the Materials.
-**
-** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
-*/
-
--->
-<link rel="stylesheet" type="text/css" href="../unit.css" />
-<script type="application/javascript" src="../unit.js"></script>
-<script type="application/javascript" src="../util.js"></script>
-<script type="application/javascript">
-
-var verts = [0.0, 0.0, 0.0,   1.0, 0.0, 0.0,   0.0, 1.0, 0.0];
-var normals = [0.0, 0.0, 1.0,   0.0, 0.0, 1.0,   0.0, 0.0, 1.0];
-var texcoords = [0.0,0.0,  1.0,0.0,  0.0,1.0];
-
-var vertsA = new Float32Array(verts);
-var normalsA = new Float32Array(normals);
-var texcoordsA = new Float32Array(texcoords);
-
-Tests.startUnit = function () {
-  var canvas = document.getElementById('gl');
-  var gl = wrapGLContext(getGLContext(canvas));
-  var prog = new Shader(gl, 'vert', 'frag');
-  prog.use();
-  var v = prog.attrib('Vertex');
-  var n = prog.attrib('Normal');
-  var t = prog.attrib('Tex');
-  return [gl,prog,v,n,t];
-}
-
-Tests.setup = function(gl, prog, v,n,t) {
-  return [gl, prog, v,n,t];
-}
-Tests.teardown = function(gl, prog, v,n,t) {
-  gl.disableVertexAttribArray(v);
-  gl.disableVertexAttribArray(n);
-  gl.disableVertexAttribArray(t);
-}
-
-Tests.endUnit = function(gl, prog, v,n,t) {
-  prog.destroy();
-}
-
-Tests.testDrawArraysEmpty = function(gl, prog, v,n,t) {
-  var b = gl.createBuffer();
-  gl.bindBuffer(gl.ARRAY_BUFFER, b);
-  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([]), gl.STATIC_DRAW);
-  assertOk(function(){gl.vertexAttribPointer(v, 3, gl.FLOAT, false, 0, 0);})
-  gl.enableVertexAttribArray(v);
-  assertGLError(gl, gl.INVALID_OPERATION, "zero size array",
-      function(){gl.drawArrays(gl.TRIANGLES, 0, 1);});
-  gl.deleteBuffer(b);
-}
-
-Tests.testDrawArraysOutOfBounds = function(gl, prog, v,n,t) {
-  var b = gl.createBuffer();
-  gl.bindBuffer(gl.ARRAY_BUFFER, b);
-  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([]), gl.STATIC_DRAW);
-  assertOk(function(){gl.vertexAttribPointer(v, 3, gl.FLOAT, false, 0, 0);});
-  gl.enableVertexAttribArray(v);
-  assertGLError(gl, gl.INVALID_OPERATION, "zero size array",
-      function(){gl.drawArrays(gl.TRIANGLES, 0, 1);});
-  assertGLError(gl, gl.INVALID_OPERATION, "zero size array 10000",
-      function(){gl.drawArrays(gl.TRIANGLES, 0, 10000);});
-  assertGLError(gl, gl.INVALID_OPERATION, "zero size array 10000000000000",
-      function(){gl.drawArrays(gl.TRIANGLES, 0, 10000000000000);});
-  assertGLError(gl, gl.INVALID_OPERATION, "zero size array fraction",
-      function(){gl.drawArrays(gl.TRIANGLES, 0, 1.6);});
-  assertGLError(gl, gl.INVALID_VALUE, "negative offset",
-      function(){gl.drawArrays(gl.TRIANGLES, 0, -1);});
-  assertGLError(gl, gl.INVALID_OPERATION, "count out of range",
-      function(){gl.drawArrays(gl.TRIANGLES, 0, 1);});
-  assertGLError(gl, gl.INVALID_VALUE, "negative count",
-      function(){gl.drawArrays(gl.TRIANGLES, 0, -1);});
-  assertGLError(gl, gl.INVALID_VALUE, "positive count, negative offset",
-      function(){gl.drawArrays(gl.TRIANGLES, -1, 1);});
-  assertGLError(gl, gl.INVALID_VALUE, "negative count, positive offset",
-      function(){gl.drawArrays(gl.TRIANGLES, 1, -1);});
-  gl.deleteBuffer(b);
-}
-
-
-Tests.testDrawArraysWithDataOutOfBounds = function(gl, prog, v,n,t) {
-  var b = gl.createBuffer();
-  gl.bindBuffer(gl.ARRAY_BUFFER, b);
-  gl.bufferData(gl.ARRAY_BUFFER, vertsA, gl.STATIC_DRAW);
-  gl.vertexAttribPointer(v, 3, gl.FLOAT, false, 0, 0);
-  gl.enableVertexAttribArray(v);
-  assertGLError(gl, gl.INVALID_OPERATION, "3 element array",
-      function(){gl.drawArrays(gl.TRIANGLES, 3, 2);});
-  assertGLError(gl, gl.INVALID_OPERATION, "3 element array 10000",
-      function(){gl.drawArrays(gl.TRIANGLES, 0, 10000);});
-  assertGLError(gl, gl.INVALID_OPERATION, "3 element array 10000000000000",
-      function(){gl.drawArrays(gl.TRIANGLES, 0, 10000000000000);});
-  assertGLError(gl, gl.INVALID_OPERATION, "fractional count",
-      function(){gl.drawArrays(gl.TRIANGLES, 3, 1.6);});
-  assertGLError(gl, gl.INVALID_VALUE, "negative offset",
-      function(){gl.drawArrays(gl.TRIANGLES, 0, -1);});
-  assertGLError(gl, gl.INVALID_OPERATION, "count out of range",
-      function(){gl.drawArrays(gl.TRIANGLES, 0, 4);});
-  assertGLError(gl, gl.INVALID_VALUE, "negative count",
-      function(){gl.drawArrays(gl.TRIANGLES, 0, -1);});
-  assertGLError(gl, gl.INVALID_VALUE, "positive count, negative offset",
-      function(){gl.drawArrays(gl.TRIANGLES, -1, 2);});
-  assertGLError(gl, gl.INVALID_VALUE, "negative count, positive offset",
-      function(){gl.drawArrays(gl.TRIANGLES, 1, -1);});
-  gl.deleteBuffer(b);
-}
-
-Tests.testDrawArraysMultiOutOfBounds = function(gl, prog, v,n,t) {
-  var bs = [];
-  bs.push(gl.createBuffer());
-  gl.bindBuffer(gl.ARRAY_BUFFER, bs[bs.length-1]);
-  gl.bufferData(gl.ARRAY_BUFFER, vertsA, gl.STATIC_DRAW);
-  gl.vertexAttribPointer(v, 3, gl.FLOAT, false, 0, 0);
-  bs.push(gl.createBuffer());
-  gl.bindBuffer(gl.ARRAY_BUFFER, bs[bs.length-1]);
-  gl.bufferData(gl.ARRAY_BUFFER, normalsA, gl.STATIC_DRAW);
-  gl.vertexAttribPointer(n, 3, gl.FLOAT, false, 0, 0);
-  bs.push(gl.createBuffer());
-  gl.bindBuffer(gl.ARRAY_BUFFER, bs[bs.length-1]);
-  gl.bufferData(gl.ARRAY_BUFFER, texcoordsA, gl.STATIC_DRAW);
-  gl.vertexAttribPointer(t, 2, gl.FLOAT, false, 0, 0);
-  gl.enableVertexAttribArray(v);
-  gl.enableVertexAttribArray(n);
-  gl.enableVertexAttribArray(t);
-  assertGLError(gl, gl.INVALID_OPERATION, "multi array 1",
-      function(){gl.drawArrays(gl.TRIANGLES, 3, 2);});
-  bs.push(gl.createBuffer());
-  gl.bindBuffer(gl.ARRAY_BUFFER, bs[bs.length-1]);
-  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verts.concat(verts)), gl.STATIC_DRAW);
-  bs.push(gl.createBuffer());
-  gl.bindBuffer(gl.ARRAY_BUFFER, bs[bs.length-1]);
-  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(texcoords.concat(texcoords)), gl.STATIC_DRAW);
-  gl.vertexAttribPointer(v, 3, gl.FLOAT, false, 0, 0);
-  gl.bindBuffer(gl.ARRAY_BUFFER, bs[1]);
-  gl.vertexAttribPointer(n, 3, gl.FLOAT, false, 0, 0);
-  gl.bindBuffer(gl.ARRAY_BUFFER, bs[2]);
-  gl.vertexAttribPointer(t, 2, gl.FLOAT, false, 0, 0);
-  gl.enableVertexAttribArray(v);
-  gl.enableVertexAttribArray(n);
-  gl.enableVertexAttribArray(t);
-  assertGLError(gl, gl.INVALID_OPERATION, "multi array 2",
-      function(){gl.drawArrays(gl.TRIANGLES, 3, 2);});
-  assertGLError(gl, gl.INVALID_OPERATION, "multi array 3",
-      function(){gl.drawArrays(gl.TRIANGLES, 4, 2);});
-  gl.bindBuffer(gl.ARRAY_BUFFER, bs[0]);
-  gl.vertexAttribPointer(v, 3, gl.FLOAT, false, 0, 0);
-  gl.bindBuffer(gl.ARRAY_BUFFER, bs[3]);
-  gl.vertexAttribPointer(n, 3, gl.FLOAT, false, 0, 0);
-  gl.bindBuffer(gl.ARRAY_BUFFER, bs[2]);
-  gl.vertexAttribPointer(t, 2, gl.FLOAT, false, 0, 0);
-  gl.enableVertexAttribArray(v);
-  gl.enableVertexAttribArray(n);
-  gl.enableVertexAttribArray(t);
-  assertGLError(gl, gl.INVALID_OPERATION, "multi array 4",
-      function(){gl.drawArrays(gl.TRIANGLES, 3, 2);});
-  assertGLError(gl, gl.INVALID_OPERATION, "multi array 5",
-      function(){gl.drawArrays(gl.TRIANGLES, 4, 2);});
-  gl.bindBuffer(gl.ARRAY_BUFFER, bs[0]);
-  gl.vertexAttribPointer(v, 3, gl.FLOAT, false, 0, 0);
-  gl.bindBuffer(gl.ARRAY_BUFFER, bs[1]);
-  gl.vertexAttribPointer(n, 3, gl.FLOAT, false, 0, 0);
-  gl.bindBuffer(gl.ARRAY_BUFFER, bs[4]);
-  gl.vertexAttribPointer(t, 2, gl.FLOAT, false, 0, 0);
-  gl.enableVertexAttribArray(v);
-  gl.enableVertexAttribArray(n);
-  gl.enableVertexAttribArray(t);
-  assertGLError(gl, gl.INVALID_OPERATION, "multi array 6",
-      function(){gl.drawArrays(gl.TRIANGLES, 3, 2);});
-  assertGLError(gl, gl.INVALID_OPERATION, "multi array 7",
-      function(){gl.drawArrays(gl.TRIANGLES, 3, 2);});
-  gl.bindBuffer(gl.ARRAY_BUFFER, bs[3]);
-  gl.vertexAttribPointer(v, 3, gl.FLOAT, false, 0, 0);
-  gl.bindBuffer(gl.ARRAY_BUFFER, bs[3]);
-  gl.vertexAttribPointer(n, 3, gl.FLOAT, false, 0, 0);
-  gl.bindBuffer(gl.ARRAY_BUFFER, bs[2]);
-  gl.vertexAttribPointer(t, 2, gl.FLOAT, false, 0, 0);
-  gl.enableVertexAttribArray(v);
-  gl.enableVertexAttribArray(n);
-  gl.enableVertexAttribArray(t);
-  assertGLError(gl, gl.INVALID_OPERATION, "multi array 8",
-      function(){gl.drawArrays(gl.TRIANGLES, 4, 1);});
-  assertGLError(gl, gl.INVALID_VALUE, "negative count",
-      function(){gl.drawArrays(gl.TRIANGLES, -1, 2);});
-  assertGLError(gl, gl.INVALID_OPERATION, "zero count???",
-      function(){gl.drawArrays(gl.TRIANGLES, 0, 4);});
-  assertGLError(gl, gl.INVALID_OPERATION, "multi array 9",
-      function(){gl.drawArrays(gl.TRIANGLES, 1, 4);});
-  bs.forEach(function(b){ gl.deleteBuffer(b) });
-}
-
-
-Tests.testDrawArraysVBOOutOfBounds = function(gl, prog, v,n,t) {
-  var vbo = new VBO(gl, {size:3, data:Quad.vertices});
-  vbo.use(v);
-  assertGLError(gl, gl.INVALID_OPERATION, "1",
-      function(){gl.drawArrays(gl.TRIANGLES, 6, 1);});
-  assertGLError(gl, gl.INVALID_VALUE, "negative count",
-      function(){gl.drawArrays(gl.TRIANGLES, 2, -1);});
-  assertGLError(gl, gl.INVALID_OPERATION, "3",
-      function(){gl.drawArrays(gl.TRIANGLES, 0, 7);});
-  assertGLError(gl, gl.INVALID_OPERATION, "4",
-      function(){gl.drawArrays(gl.TRIANGLES, 1, 6);});
-  vbo.destroy();
-}
-
-Tests.testDrawArraysVBOMultiOutOfBounds = function(gl, prog, v,n,t) {
-  // creates VBOs for the quad arrays, binds them with
-  // vertexAttribPointer and calls drawArrays
-  var vbo = new VBO(gl,
-    {size:3, data:Quad.vertices},
-    {size:3, data:Quad.normals},
-    {size:2, data:Quad.texcoords});
-  vbo.use(v, n, t);
-  assertGLError(gl, gl.INVALID_OPERATION, "1",
-      function(){gl.drawArrays(gl.TRIANGLES, 6, 1);});
-  assertGLError(gl, gl.INVALID_VALUE, "negative count",
-      function(){gl.drawArrays(gl.TRIANGLES, 2, -1);});
-  assertGLError(gl, gl.INVALID_OPERATION, "2",
-      function(){gl.drawArrays(gl.TRIANGLES, 0, 7);});
-  assertGLError(gl, gl.INVALID_OPERATION, "3",
-      function(){gl.drawArrays(gl.TRIANGLES, 1, 6);});
-  vbo.destroy();
-}
-
-Tests.testDrawArraysOOBShaderJuggle = function(gl, prog, v,n,t) {
-  var vbo = new VBO(gl,
-    {size:3, data:[0,0,0]},
-    {size:3, data:[0,0,0,0,0,0]});
-  vbo.init();
-  gl.bindBuffer(gl.ARRAY_BUFFER, vbo.vbos[0]);
-  gl.vertexAttribPointer(v, 3, gl.FLOAT, false, 0, 0);
-  gl.enableVertexAttribArray(v);
-  assertGLError(gl, gl.INVALID_OPERATION, "offset too big",
-      function(){gl.drawArrays(gl.TRIANGLES, 0, 2);});
-  var sh2 = new Shader(gl, 'vert', 'frag');
-  sh2.use();
-  gl.bindBuffer(gl.ARRAY_BUFFER, vbo.vbos[1]);
-  gl.vertexAttribPointer(sh2.attrib('Vertex'), 3, gl.FLOAT, false, 0, 0);
-  gl.enableVertexAttribArray(sh2.attrib('Vertex'));
-  assertOk(function(){gl.drawArrays(gl.TRIANGLES, 0, 2);});
-  assertGLError(gl, gl.INVALID_OPERATION, "offset too big 2",
-      function(){gl.drawArrays(gl.TRIANGLES, 0, 3);});
-  prog.use();
-  gl.vertexAttribPointer(prog.attrib('Vertex'), 3, gl.FLOAT, false, 0, 0);
-  gl.enableVertexAttribArray(prog.attrib('Vertex'));
-  assertOk(function(){gl.drawArrays(gl.TRIANGLES, 0, 2);});
-  assertGLError(gl, gl.INVALID_OPERATION, "offset too big 3",
-      function(){gl.drawArrays(gl.TRIANGLES, 0, 3);});
-  sh2.destroy();
-}
-
-</script>
-<script id="vert" type="x-shader/x-vertex">
-  attribute vec3 Vertex;
-  attribute vec3 Normal;
-  attribute vec2 Tex;
-
-  varying vec4 texCoord0;
-  void main()
-  {
-    gl_Position = vec4(Vertex * Normal, 1.0);
-    texCoord0 = vec4(Tex,0.0,0.0) + gl_Position;
-  }
-</script>
-<script id="frag" type="x-shader/x-fragment">
-  precision mediump float;
-
-  varying vec4 texCoord0;
-  void main()
-  {
-    gl_FragColor = texCoord0;
-  }
-</script>
-
-
-<style>canvas{ position:absolute; }</style>
-</head><body>
-  <canvas id="gl" width="1" height="1"></canvas>
-</body></html>
--- a/dom/canvas/test/webgl-conf/checkout/conformance/more/functions/texImage2DBadArgs.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/more/functions/texImage2DBadArgs.html
@@ -89,16 +89,35 @@ Tests.testTexImage2D = function(gl) {
         gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1,1,0,gl.RGBA,gl.UNSIGNED_BYTE, new Uint8Array(3));
     });
     assertGLError(gl, gl.INVALID_OPERATION, "format and type incompatible",function(){
         gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1,1,0,gl.RGBA,gl.UNSIGNED_SHORT_5_6_5, null);
     });
     assertGLError(gl, gl.INVALID_OPERATION, "format and type incompatible",function(){
         gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, 1,1,0,gl.RGB,gl.UNSIGNED_SHORT_4_4_4_4, null);
     });
+
+    assertThrows(gl, true, "too few args", function(){
+        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 2, 2, 0, gl.RGBA, gl.UNSIGNED_BYTE);
+    });
+    assertThrows(gl, false, "too many args", function(){
+        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 2, 2, 0, gl.RGBA, gl.UNSIGNED_BYTE, null, null);
+    });
+
+    assertThrows(gl, true, "bad TexSourceType", function(){
+        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, window);
+    });
+    assertThrows(gl, true, "fake TexSourceType", function(){
+        var fakeObj = {
+            get width() { throw 7 },
+            get height() { throw 7 },
+            data: new Uint8ClampedArray(10)
+        };
+        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, fakeObj);
+    });
 }
 
 
 Tests.endUnit = function(gl) {
 }
 
 </script>
 <style>canvas{ position:absolute; }</style>
--- a/dom/canvas/test/webgl-conf/checkout/conformance/more/functions/texSubImage2DBadArgs.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/more/functions/texSubImage2DBadArgs.html
@@ -98,16 +98,35 @@ Tests.testTexImage2D = function(gl) {
         gl.texSubImage2D(gl.TEXTURE_2D, 0, 0,0, 1,1,gl.RGBA,gl.UNSIGNED_BYTE, new Uint8Array([0,0,0]));
     });
     assertGLError(gl, gl.INVALID_OPERATION, "format does not match internal format", function(){
         gl.texSubImage2D(gl.TEXTURE_2D, 0, 0,0, 1,1,gl.RGB,gl.UNSIGNED_BYTE, new Uint8Array([0,0,0]));
     });
     assertGLError(gl, gl.INVALID_OPERATION, "type does not match original", function(){
         gl.texSubImage2D(gl.TEXTURE_2D, 0, 0,0, 1,1,gl.RGBA,gl.UNSIGNED_SHORT_4_4_4_4, new Uint16Array([0]));
     });
+
+    assertThrows(gl, true, "too few args", function(){
+        gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE);
+    });
+    assertThrows(gl, false, "too many args", function(){
+        gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([0,0,0,0]), null);
+    });
+
+    assertThrows(gl, true, "bad TexSourceType", function(){
+        gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, window);
+    });
+    assertThrows(gl, true, "fake TexSourceType", function(){
+        var fakeObj = {
+            get width() { throw 7 },
+            get height() { throw 7 },
+            data: new Uint8ClampedArray(10)
+        };
+        gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, fakeObj);
+    });
 }
 
 
 Tests.endUnit = function(gl) {
 }
 
 </script>
 <style>canvas{ position:absolute; }</style>
deleted file mode 100644
--- a/dom/canvas/test/webgl-conf/checkout/conformance/more/glsl/longLoops.html
+++ /dev/null
@@ -1,253 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<meta charset="utf-8">
-<!--
-
-/*
-** Copyright (c) 2012 The Khronos Group Inc.
-**
-** Permission is hereby granted, free of charge, to any person obtaining a
-** copy of this software and/or associated documentation files (the
-** "Materials"), to deal in the Materials without restriction, including
-** without limitation the rights to use, copy, modify, merge, publish,
-** distribute, sublicense, and/or sell copies of the Materials, and to
-** permit persons to whom the Materials are furnished to do so, subject to
-** the following conditions:
-**
-** The above copyright notice and this permission notice shall be included
-** in all copies or substantial portions of the Materials.
-**
-** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
-*/
-
--->
-<link rel="stylesheet" type="text/css" href="../unit.css" />
-<script type="application/javascript" src="../unit.js"></script>
-<script type="application/javascript" src="../util.js"></script>
-<script type="application/javascript">
-
-Tests.startUnit = function () {
-  var canvas = document.getElementById('gl');
-  var gl = getGLContext(canvas);
-  return [gl];
-}
-
-Tests.autorun = false;
-Tests.message = "Caution: might hang your GPU"
-
-var arr = ['whiletrue', 'loop100M', 'loopComp', 'variable'];
-arr.forEach(function(e){
-    Tests['test'+e+'vert'] = function(gl) {
-        var sh = new Filter(gl, e+'vert', 'frag');
-        assertOk(function(){
-            sh.apply();
-        });
-        sh.destroy();
-    }
-    Tests['test'+e+'frag'] = function(gl) {
-        var sh = new Filter(gl, 'vert', e+'frag');
-        assertOk(function(){
-            sh.apply();
-        });
-        sh.destroy();
-    }
-});
-
-Tests.testMandelbrot = function(gl) {
-    gl.disable(gl.DEPTH_TEST);
-    var sh = new Filter(gl, 'identity-vert', 'mandelbrot-frag');
-    sh.apply(function(s){
-        s.uniform1f('z', 0.15);
-        s.uniform1f('x', -1.25);
-    });
-    for (var i=0; i<256; i++) {
-        sh.apply();
-    }
-    sh.destroy();
-}
-
-</script>
-<script id="identity-vert" type="x-shader/x-vertex">
-
-  attribute vec3 Vertex;
-  attribute vec2 Tex;
-
-  varying vec2 texCoord0;
-  void main()
-  {
-    texCoord0 = vec2(Tex.s, Tex.t);
-    gl_Position = vec4(Vertex, 1.0);
-  }
-</script>
-<script id="mandelbrot-frag" type="x-shader/x-fragment">
-    precision mediump float;
-
-    uniform float x,y,z;
-    varying vec2 texCoord0;
-    vec4 iter_z(float cr, float ci) {
-        int i;
-        float nzr, nzi, zr = 0.0, zi = 0.0;
-        vec4 color = vec4(0.0);
-        for (i=0; i<2500; i++) {
-            nzr = zr * zr - zi * zi + cr;
-            nzi = 2.0 * zr * zi + ci;
-            zr = nzr;
-            zi = nzi;
-        }
-        color = vec4(zi);
-        color.a = 1.0;
-        return color;
-    }
-
-    void main()
-    {
-        gl_FragColor = iter_z(x+z*(2.0*texCoord0.s-1.5), y+z*(2.0*texCoord0.t-1.0));
-    }
-</script>
-<script id="whiletruevert" type="x-shader/x-vertex">
-
-
-    attribute vec3 Vertex; attribute vec2 Tex;
-    varying vec2 TexCoord;
-    void main()
-    {
-        float z = 1.0;
-        while(true) { z += 0.1; z *= 0.995; }
-        TexCoord = Tex.st;
-        gl_Position = vec4(Vertex, z);
-    }
-</script>
-<script id="loop100Mvert" type="x-shader/x-vertex">
-
-
-    attribute vec3 Vertex; attribute vec2 Tex;
-    varying vec2 TexCoord;
-    void main()
-    {
-        int i;
-        float z = 1.0;
-        for (i = 0; i<1000000000; i++) {
-            z += 0.1; z *= 0.995;
-        }
-        TexCoord = Tex.st;
-        gl_Position = vec4(Vertex, z);
-    }
-</script>
-<script id="loopCompvert" type="x-shader/x-vertex">
-
-
-    attribute vec3 Vertex; attribute vec2 Tex;
-    varying vec2 TexCoord;
-    void main()
-    {
-        float z = 1.0;
-        while(z > 0.0) { z += 0.1; z *= 0.995; }
-        TexCoord = Tex.st;
-        gl_Position = vec4(Vertex, z);
-    }
-</script>
-<script id="variablevert" type="x-shader/x-vertex">
-
-
-    attribute vec3 Vertex; attribute vec2 Tex;
-    varying vec2 TexCoord;
-
-    void main()
-    {
-        float z = 1.0;
-        while(z > Vertex.z) { z += 0.1; z *= 0.995; }
-        TexCoord = Tex.st;
-        gl_Position = vec4(Vertex, z);
-    }
-</script>
-<script id="vert" type="x-shader/x-vertex">
-
-
-    attribute vec3 Vertex; attribute vec2 Tex;
-    varying vec2 TexCoord;
-    void main()
-    {
-        TexCoord = Tex.st;
-        gl_Position = vec4(Vertex, 0.0);
-    }
-</script>
-
-<script id="whiletruefrag" type="x-shader/x-fragment">
-
-
-    precision mediump float;
-
-    varying vec2 TexCoord;
-    void main()
-    {
-        float z = 1.0;
-        while(true) { z += 0.1; z *= 0.995; }
-        gl_FragColor = vec4(1.0, TexCoord.s, TexCoord.t, z);
-    }
-</script>
-<script id="loop100Mfrag" type="x-shader/x-fragment">
-
-
-    precision mediump float;
-
-    varying vec2 TexCoord;
-    void main()
-    {
-        int i;
-        float z = 1.0;
-        for (i = 0; i<1000000000; i++) {
-            z += 0.1; z *= 0.995;
-        }
-        gl_FragColor = vec4(1.0, TexCoord.s, TexCoord.t, z);
-    }
-</script>
-<script id="loopCompfrag" type="x-shader/x-fragment">
-
-
-    precision mediump float;
-
-    varying vec2 TexCoord;
-    void main()
-    {
-        float z = TexCoord.s;
-        while(z > 0.0) { z += 0.1; z *= 0.995; }
-        gl_FragColor = vec4(1.0, TexCoord.s, TexCoord.t, z);
-    }
-</script>
-<script id="variablefrag" type="x-shader/x-fragment">
-
-
-    precision mediump float;
-
-    varying vec2 TexCoord;
-    void main()
-    {
-        float z = 1.0;
-        while(z > TexCoord.s) { z += 0.1; z *= 0.995; }
-        gl_FragColor = vec4(1.0, TexCoord.s, TexCoord.t, z);
-    }
-</script>
-<script id="frag" type="x-shader/x-fragment">
-
-
-  precision mediump float;
-
-  varying vec2 TexCoord;
-  void main()
-  {
-    gl_FragColor = vec4(1.0, TexCoord.s, TexCoord.t, 1.0);
-  }
-</script>
-
-
-<style>canvas{ position:absolute; }</style>
-</head><body>
-  <canvas id="gl" width="512" height="512"></canvas>
-</body></html>
deleted file mode 100644
--- a/dom/canvas/test/webgl-conf/checkout/conformance/more/glsl/unusedAttribsUniforms.html
+++ /dev/null
@@ -1,115 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<meta charset="utf-8">
-<!--
-
-/*
-** Copyright (c) 2012 The Khronos Group Inc.
-**
-** Permission is hereby granted, free of charge, to any person obtaining a
-** copy of this software and/or associated documentation files (the
-** "Materials"), to deal in the Materials without restriction, including
-** without limitation the rights to use, copy, modify, merge, publish,
-** distribute, sublicense, and/or sell copies of the Materials, and to
-** permit persons to whom the Materials are furnished to do so, subject to
-** the following conditions:
-**
-** The above copyright notice and this permission notice shall be included
-** in all copies or substantial portions of the Materials.
-**
-** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
-*/
-
--->
-<link rel="stylesheet" type="text/css" href="../unit.css" />
-<script type="application/javascript" src="../unit.js"></script>
-<script type="application/javascript" src="../util.js"></script>
-<script type="application/javascript">
-
-Tests.autorun = false;
-Tests.message = "Caution: may crash the browser";
-
-Tests.startUnit = function () {
-  var canvas = document.getElementById('gl');
-  var gl = getGLContext(canvas);
-  return [gl];
-}
-
-Tests.testPassingTooManyVBOs = function(gl) {
-    var sh = new Filter(gl, 'vert', 'frag');
-    assertFail(function(){sh.apply();});
-    sh.destroy();
-}
-Tests.testPassingTooManyUniforms = function(gl) {
-    var sh = new Filter(gl, 'vert2', 'frag2');
-    sh.apply(function(f){
-        assertFail(function(){f.uniform1f('foo', 3.0);throwError("foo")});
-        f.uniform1f('bar', 1.0);
-        assertFail(function(){f.uniform1f('baz', 1.0);throwError("baz")});
-    });
-    sh.destroy();
-}
-
-</script>
-
-<script id="vert" type="x-shader/x-vertex">
-
-
-  attribute vec3 Vertex; attribute vec2 Tex;
-  varying vec2 TexCoord;
-  void main()
-  {
-    TexCoord = Vertex.st;
-    gl_Position = vec4(Vertex, 0.0);
-  }
-</script>
-
-<script id="frag" type="x-shader/x-fragment">
-
-
-  precision mediump float;
-
-  void main()
-  {
-    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
-  }
-</script>
-<script id="vert2" type="x-shader/x-vertex">
-
-
-  uniform float foo, bar;
-  attribute vec3 Vertex; attribute vec2 Tex;
-  varying vec2 TexCoord;
-  void main()
-  {
-    TexCoord = Tex.st;
-    gl_Position = vec4(Vertex, bar);
-  }
-</script>
-
-<script id="frag2" type="x-shader/x-fragment">
-
-
-  precision mediump float;
-
-  uniform float baz;
-
-  varying vec2 TexCoord;
-  void main()
-  {
-    gl_FragColor = vec4(1.0, TexCoord.s, 0.0, 1.0);
-  }
-</script>
-
-
-<style>canvas{ position:absolute; }</style>
-</head><body>
-  <canvas id="gl" width="1" height="1"></canvas>
-</body></html>
deleted file mode 100644
--- a/dom/canvas/test/webgl-conf/checkout/conformance/more/performance/CPUvsGPU.html
+++ /dev/null
@@ -1,360 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<meta charset="utf-8">
-<!--
-
-/*
-** Copyright (c) 2012 The Khronos Group Inc.
-**
-** Permission is hereby granted, free of charge, to any person obtaining a
-** copy of this software and/or associated documentation files (the
-** "Materials"), to deal in the Materials without restriction, including
-** without limitation the rights to use, copy, modify, merge, publish,
-** distribute, sublicense, and/or sell copies of the Materials, and to
-** permit persons to whom the Materials are furnished to do so, subject to
-** the following conditions:
-**
-** The above copyright notice and this permission notice shall be included
-** in all copies or substantial portions of the Materials.
-**
-** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
-*/
-
--->
-
-<link rel="stylesheet" type="text/css" href="../unit.css" />
-<script type="application/javascript" src="../unit.js"></script>
-<script type="application/javascript" src="../util.js"></script>
-<script type="application/javascript">
-
-Tests.autorun = false;
-Tests.message = "This might take a few seconds to run"
-
-Tests.startUnit = function() {
-  var gl = document.getElementById('gl').getContext(GL_CONTEXT_ID);
-  var ctx = document.getElementById('2d').getContext('2d');
-  return [gl, ctx];
-}
-
-var kernel = [0.006, 0.061, 0.242, 0.383, 0.242, 0.061, 0.006];
-
-Tests.testGPU = function(gl, ctx) {
-  Tests.gpuGaussianBlur(gl);
-}
-
-Tests.testCPU = function(gl, ctx) {
-  Tests.cpuGaussianBlur(ctx);
-}
-
-function hblur(ctx,idata) {
-  var d = idata.data;
-  var res = ctx.createImageData(256,256);
-  var rd = res.data;
-  var sumR=0.0,sumG=0.0,sumB=0.0,sumA=0.0, kv=0.0;
-  var col_offset = 0, row_offset = 0, k4 = 0;
-  for (var y=0; y<idata.height; ++y) {
-    col_offset = y * idata.width * 4;
-    for (var x=3; x<idata.width-3; ++x) {
-      row_offset = col_offset+x*4;
-      sumR=sumG=sumB=sumA=0.0;
-      for (var k=-3; k<4; ++k) {
-        k4 = k * 4;
-        kv = kernel[k+3];
-        sumR += d[row_offset+k4+0] * kv;
-        sumG += d[row_offset+k4+1] * kv;
-        sumB += d[row_offset+k4+2] * kv;
-        sumA += d[row_offset+k4+3] * kv;
-      }
-      rd[row_offset+0] = Math.floor(sumR);
-      rd[row_offset+1] = Math.floor(sumG);
-      rd[row_offset+2] = Math.floor(sumB);
-      rd[row_offset+3] = Math.floor(sumA);
-    }
-  }
-  var xr = 3;
-  for (var y=0; y<idata.height; ++y) {
-    col_offset = y * idata.width * 4;
-    for (var x=0; x<xr; ++x) {
-      row_offset = col_offset+x*4;
-      sumR=sumG=sumB=sumA=0.0;
-      for (var k=-3; k<4; ++k) {
-        if (k+x < 0)
-          k4 = 0;
-        else
-          k4 = k * 4;
-        kv = kernel[k+3];
-        sumR += d[row_offset+k4+0] * kv;
-        sumG += d[row_offset+k4+1] * kv;
-        sumB += d[row_offset+k4+2] * kv;
-        sumA += d[row_offset+k4+3] * kv;
-      }
-      rd[row_offset+0] = Math.floor(sumR);
-      rd[row_offset+1] = Math.floor(sumG);
-      rd[row_offset+2] = Math.floor(sumB);
-      rd[row_offset+3] = Math.floor(sumA);
-    }
-  }
-  var xr = idata.width-3;
-  for (var y=0; y<idata.height; ++y) {
-    col_offset = y * idata.width * 4;
-    for (var x=xr; x<idata.width; ++x) {
-      row_offset = col_offset+x*4;
-      sumR=sumG=sumB=sumA=0.0;
-      for (var k=-3; k<4; ++k) {
-        if (k+x >= idata.width)
-          k4 = (idata.width-x-1)*4;
-        else
-          k4 = k * 4;
-        kv = kernel[k+3];
-        sumR += d[row_offset+k4+0] * kv;
-        sumG += d[row_offset+k4+1] * kv;
-        sumB += d[row_offset+k4+2] * kv;
-        sumA += d[row_offset+k4+3] * kv;
-      }
-      rd[row_offset+0] = Math.floor(sumR);
-      rd[row_offset+1] = Math.floor(sumG);
-      rd[row_offset+2] = Math.floor(sumB);
-      rd[row_offset+3] = Math.floor(sumA);
-    }
-  }
-  return res;
-}
-
-function vblur(ctx,idata) {
-  var d = idata.data;
-  var res = ctx.createImageData(256,256);
-  var rd = res.data;
-  var sumR=0.0,sumG=0.0,sumB=0.0,sumA=0.0, kv=0.0;
-  var col_offset = 0, row_offset = 0, kfac = idata.width*4;
-  for (var y=3; y<idata.height-3; ++y) {
-    col_offset = y * idata.width * 4;
-    for (var x=0; x<idata.width; ++x) {
-      row_offset = col_offset+x*4;
-      sumR=sumG=sumB=sumA=0.0;
-      for (var k=-3; k<4; ++k) {
-        k4 = k * kfac;
-        kv = kernel[k+3];
-        sumR += d[row_offset+k4+0] * kv;
-        sumG += d[row_offset+k4+1] * kv;
-        sumB += d[row_offset+k4+2] * kv;
-        sumA += d[row_offset+k4+3] * kv;
-      }
-      rd[row_offset+0] = Math.floor(sumR);
-      rd[row_offset+1] = Math.floor(sumG);
-      rd[row_offset+2] = Math.floor(sumB);
-      rd[row_offset+3] = Math.floor(sumA);
-    }
-  }
-  var yr = 3;
-  for (var y=0; y<yr; ++y) {
-    col_offset = y * idata.width * 4;
-    for (var x=0; x<idata.width; ++x) {
-      row_offset = col_offset+x*4;
-      sumR=sumG=sumB=sumA=0.0;
-      for (var k=-3; k<4; ++k) {
-        if (k+y < 0)
-          k4 = 0;
-        else
-          k4 = k * kfac;
-        kv = kernel[k+3];
-        sumR += d[row_offset+k4+0] * kv;
-        sumG += d[row_offset+k4+1] * kv;
-        sumB += d[row_offset+k4+2] * kv;
-        sumA += d[row_offset+k4+3] * kv;
-      }
-      rd[row_offset+0] = Math.floor(sumR);
-      rd[row_offset+1] = Math.floor(sumG);
-      rd[row_offset+2] = Math.floor(sumB);
-      rd[row_offset+3] = Math.floor(sumA);
-    }
-  }
-  var yr = idata.height-3;
-  for (var y=yr; y<idata.height; ++y) {
-    col_offset = y * idata.width * 4;
-    for (var x=0; x<idata.width; ++x) {
-      row_offset = col_offset+x*4;
-      sumR=sumG=sumB=sumA=0.0;
-      for (var k=-3; k<4; ++k) {
-        if (k+y >= idata.height)
-          k4 = (idata.height-y-1)*kfac;
-        else
-          k4 = k * kfac;
-        kv = kernel[k+3];
-        sumR += d[row_offset+k4+0] * kv;
-        sumG += d[row_offset+k4+1] * kv;
-        sumB += d[row_offset+k4+2] * kv;
-        sumA += d[row_offset+k4+3] * kv;
-      }
-      rd[row_offset+0] = Math.floor(sumR);
-      rd[row_offset+1] = Math.floor(sumG);
-      rd[row_offset+2] = Math.floor(sumB);
-      rd[row_offset+3] = Math.floor(sumA);
-    }
-  }
-  return res;
-}
-
-Tests.cpuGaussianBlur = function(ctx) {
-  var s = document.getElementById('cpustat');
-  var t0 = new Date().getTime();
-  ctx.drawImage(document.getElementById('logo'),0,0);
-  var idata = ctx.getImageData(0,0,256,256);
-  for (var i=0; i<1; i++){
-    idata = hblur(ctx,idata);
-    idata = vblur(ctx,idata);
-  }
-  ctx.putImageData(idata, 0, 0);
-  var t1 = new Date().getTime();
-  s.textContent = 'Done! Time: '+(t1-t0)+'ms';
-}
-
-Tests.gpuGaussianBlur = function(gl) {
-  var s = document.getElementById('gpustat');
-  var t0 = new Date().getTime();
-
-  var fbo1 = new FBO(gl, 256, 256);
-  var fbo2 = new FBO(gl, 256, 256);
-  var hblur = new Filter(gl, 'identity-vert', 'hblur-frag');
-  var vblur = new Filter(gl, 'identity-vert', 'vblur-frag');
-  var identity = new Filter(gl, 'identity-vert', 'identity-frag');
-  var identityFlip = new Filter(gl, 'identity-flip-vert', 'identity-frag');
-
-  gl.viewport(0,0,256,256);
-  gl.clearColor(0,0,1,1);
-  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
-  gl.disable(gl.DEPTH_TEST);
-  gl.activeTexture(gl.TEXTURE0);
-
-  fbo1.use();
-  var tex = loadTexture(gl, document.getElementById('logo'));
-  gl.bindTexture(gl.TEXTURE_2D, tex);
-  identityFlip.apply(); // draw image
-
-  // gaussian blur
-  for (var i=0; i<1000; i++) {
-    fbo2.use();
-    gl.bindTexture(gl.TEXTURE_2D, fbo1.texture);
-    hblur.apply(function(f){
-      f.uniform1f('width', 256.0);
-      f.uniform1i('Texture', 0);
-    });
-    fbo1.use();
-    gl.bindTexture(gl.TEXTURE_2D, fbo2.texture);
-    vblur.apply(function(f){
-      f.uniform1f('height', 256.0);
-      f.uniform1i('Texture', 0);
-    });
-  }
-
-  gl.bindFramebuffer(gl.FRAMEBUFFER, null);
-  gl.bindTexture(gl.TEXTURE_2D, fbo1.texture);
-  identity.apply(); // draw blurred image on screen
-
-  fbo1.destroy();
-  fbo2.destroy();
-  hblur.destroy();
-  vblur.destroy();
-  identity.destroy();
-  identityFlip.destroy();
-  gl.deleteTexture(tex);
-  checkError(gl, "end");
-  var t1 = new Date().getTime();
-  s.textContent = 'Done! Time: '+(t1-t0)+'ms';
-}
-
-
-</script>
-<script id="identity-vert" type="x-shader/x-vertex">
-
-  attribute vec3 Vertex;
-  attribute vec2 Tex;
-
-  varying vec4 texCoord0;
-  void main()
-  {
-    texCoord0 = vec4(Tex, 0.0, 0.0);
-    gl_Position = vec4(Vertex, 1.0);
-  }
-</script>
-<script id="identity-flip-vert" type="x-shader/x-vertex">
-
-  attribute vec3 Vertex;
-  attribute vec2 Tex;
-
-  varying vec4 texCoord0;
-  void main()
-  {
-    texCoord0 = vec4(Tex.s, 1.0-Tex.t, 0.0, 0.0);
-    gl_Position = vec4(Vertex, 1.0);
-  }
-</script>
-<script id="identity-frag" type="x-shader/x-fragment">
-
-  precision mediump float;
-
-  uniform sampler2D Texture;
-
-  varying vec4 texCoord0;
-  void main()
-  {
-    gl_FragColor = texture2D(Texture, texCoord0.st);
-  }
-</script>
-<script id="hblur-frag" type="x-shader/x-fragment">
-
-  precision mediump float;
-
-  uniform sampler2D Texture;
-  uniform float width;
-
-  varying vec4 texCoord0;
-  void main()
-  {
-    float kernel[7] = float[7](0.006, 0.061, 0.242, 0.383, 0.242, 0.061, 0.006);
-    int i;
-    float step = 1.0 / width;
-    vec4 sum = vec4(0.0);
-    for (i=-3; i<=3; i++) {
-      vec4 tmp = texture2D(Texture, texCoord0.st + vec2(float(i)*step, 0.0));
-      sum = (tmp * kernel[i+3]) + sum;
-    }
-    gl_FragColor = sum;
-  }
-</script>
-<script id="vblur-frag" type="x-shader/x-fragment">
-
-  precision mediump float;
-
-  uniform sampler2D Texture;
-  uniform float height;
-
-  varying vec4 texCoord0;
-  void main()
-  {
-    float kernel[7] = float[7](0.006, 0.061, 0.242, 0.383, 0.242, 0.061, 0.006);
-    int i;
-    float step = 1.0 / height;
-    vec4 sum = vec4(0.0);
-    for (i=-3; i<=3; i++) {
-      vec4 tmp = texture2D(Texture, texCoord0.st + vec2(0.0, float(i)*step));
-      sum = (tmp * kernel[i+3]) + sum;
-    }
-    gl_FragColor = sum;
-  }
-</script>
-</head><body>
-<img id="logo" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAAgAElEQVR4nO19bWiUZ9b/+BJfsP8oJfXlyUMDNkSSfnvGhgh2Qak6IPRZJ9QPtTIlYMQ2RQvWHagSxcgiCYTtulsCCinb1mWfriy20pSnLkL1Q2Fqv5RktThhaxseWFGXFQbZdc//w8y55lznPtfLfc99J6OZCw73PTOZSYz5/c7vvFznSkFjNVZjzduVmusfoLEaq7HmbjUIoLEaax6vBgE0VmPN49UggMZqrHm8GgTQWI01j1eDABqrsebxahBAYzXWPF4NAmisxprHq0EAjdVY83g1CKCxGmserwYBPKarWJyGs2c/hTff/BjefPNjWL/tV7A7ewRWtQwoS6X61dVk9OtXtQzA0x1H1Wf9fP/78OabH8PZs5/C5OQklEqluf5nN1bMq0EAdbxmZmZg4otvFcApsOfKKEm8+ebHMPHFt3Dv3r25/lU1VsTVIIA6Wffu3VNgf7rjqB/Q1x6E1NqD8HTHUVjccxoW95yGRb2/haaBP8DSX3wKy0/8GZaNXoNlo9fg/330F/h/H/0F/nPi/+A/J/5PPb/8xJ9h+Yk/w7MHPoTU6x/Bot7fqs/Cz0+tPehFDA1SePxWgwDmYJVKJbh37x68f+Z/4Of733eDvQLy1I4RBW4ELwKZAp3fI/ip/efE/4nP0/fwz1t+4s/QNPAHSGV+A2vSv4RU59vO0OLn+9+Hs2c/bRBCna4GAcziKhQK8OabH5fBY/PqnW8rT44empoJ/Cbgo9enZgM+vV9+4s8aCXDDnyn1+kewuOd0magMhLAm/Ut4/8z/wMQX3zbyCXWyGgSQ4CqVSjDxxbd2L7/2YFluv/4RLP3Fp5otP/FndfUlARvoTSTAVYJJAdiM/3xLf/EppDK/MYYQq1oG4M03P4bJycm5/m+a16tBAAmsyclJFcu7PDxKerz6gN9EAD6gt6kAE/BRCUig51fJ8N+n8grsd/J0x1F4882PoVAozPV/3bxbDQKIaWFML8r7tQch9dKgBnpu3PvbSEACHwI1KgFI8t8nDLCBn/4buCl1wH5Xa9K/hLNnP22ECLO0GgRQ4zJK/HWvKU+fev0jSL3+UTmBVrly8IclAQTezwb/FAn8tBpgI4GfDf7JKwdg8/4mEsB/f2rHSIAMGiHC7KwGAURcE198C+u3/Sro7TvfhtSOkSrw+8ecBOAiAZcKiCL/fZKBthyAj/w3gZ/+O+nvAEuQUnmxkThMZjUIIMRCmR+I7ZtfhtQLeVjU+9sy8Cugj0ICUVRAVO9PCeC/3/tfq+fH5+KQ/5QEpN9D6vWPRFXQCA/iXw0C8Fj37t2Ds2c/1YHf/HJZ5hPgc6PA1+5DqgAXAUQFf1wKIKz8t4FfIwEkUdZv8HTHUTh79tO5/rN4IlaDACyrVCoZgb+457SS+hz06p6qgIphx12YZKCNBGoBv5QIdCmBpBUAVUmUNBtEkMxqEIBhTXzxrezxXxosy1OM8wUS4GRgUgBREoIUfLVIf5+KQNyxv68CSPWPaSrARQRr0r+EiS++nes/mcdyNQiArUKhoCf3iNRH4HuBn3h/iQS4Enj2wIcaOPAxBf+zBz5UII3D+9uIgHv+/37vfxOX/ybvn+of08hU/Y4ZEazf9qtG1SDkahBAZRWL0/Dmmx/r5bxKco96fW42IuB/tFQB2MIAmwLg/fxJmav0F9X7+8T+oveniVUaZgnJwjff/LiRKPRcDQIAgPfP/E8Q+J1vQ+qlQRXrSySwqPe3qsEnTBiA3t9XCVBAITiTBD8lAa4EsBLgIoGfDf4J/vu9/4WhY3kYGjoNhw8fhsOHD5cfH8ur++G+LXD48GH4+f73YXf2CDx74EPYsOfXAe8vgV/7Pb+Q14hgVctAIz/gseY1ARQKBb1zr/nl8h9Rxesv7jntJIHI4YCjJGiqBiwbvQZLf/Fpzdn/KEqA5yBsCuDZAx/CwBvvwNCxPHx+bj/cOdUNcHUnwNWdUPrqRPUKQ+p5uLoTYCwNMJaG0vEuuJzfCpfzW2HoWB5yuRz8fP/7VrJthAXh17wkgHv37gXlPsb5L+TLgEfpXzFFAhFCAVMugHr/Zw98qIGf5wCoEkCAhd38E9WWn/iz5vlN3p9XKziBPXvgQ/j5/vdh6Fgefn98M5SOd8Gj4Y0AV3fCwzO9ANAPAEOaIVkgOZSOd8GdU91wOb8VBt54B3K5XFkxVJSYImpCBNhV2FjBNe8IYHJyUk/yrXsNUhv2KvAr4CMRECVQiwoQG4QsSoAnzBD0UjmQqoEkyABVgCv5Fzbxl+ofg5/vfx8OHz4Ml/NboXS8SyMFuLoTOCGUrb9KDIQUhvu2VAlhx0j5/5JtR26oAX3VDQF8/0keHv3tWqLf4+zZT8V+fQ38SZOApRqAj21KgKoB9MxJhwFU9nMlwAkgdN2flPyePfAh5HI5pQ4enOyG0vGuclggkkE/ub6oEcKtwXYY7tsCA2+8UyZ41jvQSBKWV10QQOmrE3D3wGr4/pN8Ip9fLE7Dz/e/r4Mfvb5AACoEIAQQIIE4cgFCKOBTFqRqIKlyoLQVOGr231n3FxJ+qf4xyOVymjJAMqiGC9xerNrVnQATbUpRXM5vhZFMlwr7fr7/fZiZmUnk7+1xWnNPAIUxmH5rDcy8uxI+P7c/9o8PNPSg10czkAAlgjhJAAng2QMfaqFA2A5BBFsSyUCa/UfQuzx/FPAr5eMo9W3Y82sY7tuiEYEWKsCLECAASFWv36wGmGiDBye74dHwRpga6IDhvi2w8fneeT/teE4J4NHfrsH9Q+th5t2VcGuwHaYGOmL77FKpBO+f+R9Z8nPwm8IAlhD0CQOcvQG0kYX1BZiUAFcBs6EAuPRPatMPVwBSqU/9vl8ahJFMV4AIVJjwzWpAAvj335vINVW1b1bDow/K4cWDk90wNdABn5/bP29nFs4ZAdy7dw9uDbbDzLsrNRK4d+8elEqlmlh5ZmZGl/zYzUfBLykAiQgQ+J4kQMGfyvzGGQpoNW+HEpA6BJPMAdCuwLCJP2/pT72/UONX2X1SkUmn03C+v1VUBI+GNxIiSAUI4N9/byrbDys0VfBoeKPKQ80nRTBnBPD9J3kN/PcPrYfpt9bAP4sXNBII+59RLE4HW3krY7iMFiIXEOgNiLEsaGsOspFAEpn/JON+XvmQvH+qf0wEv7LFnUY18Gh4Y1kVTLSB5v0pAVRIAIkASQCJAP8Gn/Q1JwTwz+IFBXxKAjPvroTr43vh3r17ysIQQaFQCO7T37C3DG6TAvDIBRgrAj5VAYMK4CTgkxOgwKf3SfQC0NJfIht+pL5/SfoT+Y//D6mXBiG1YS+sbNsGr6TXWkkAFYEGfAQ/IYF//7ACHn3QpRFB6asTkR3R47JmnQBKpRLcOdWteX5KBNNvrYGZmRmYmZkJEIFtTXzxrcrwLlu0uQx4BD0FPxJCSBKQwoA4EoISEfC9AjwPQPsCku4KxERg3NKfJ/8C3p/8/hT4N+wNXDkJIPAD9x90VYlAAD98s1pdkQgenOyGh2d64dHfrj2ximBWCaBUKsHt7y4EwI+5AHzupyvvQbE47U0CWrIP430O/rUH7eB3JANtCUFbOBAqFKjcNw38AX42+KeASU1Czx74MDHwm0iA70/gPQrenl/a6ss3+nDpT0mgYi0tzwRyAhIRPBreCI8+6NKAbyIBGhY8ONmt1MCTRgSzRgD4y7tzqlv0/JwQisVpRQJIBFyKaZn+5pd1z7/2YLXLD8GPuYAoKgDlp1QWrKEqsGHPr+Fng3+C0dFRuHTpEtz+7gL8s1g1+Mfv4NKlS1oeAEGGQJyNVmDegRhL1p9YAPy2HIBAApQATODn+QEj+InRsODhmV5vRfq4rFklAOr9TSSA999/ktdIgP/isZ9fBD8aBz8C30UEEfIB1qRgJQ+A1/868DGMjo7CT1fe04DOgX/7uwvws8E/Qap/LNAhiECjZcC4B4RI3p83I4Xx/qL8pyEALZGS3ZaaEnghrwE/k8nA5fxWuH9ofQD4qipwdafK9gdeqwBdAj8qAZ4kfPS3azAzM/NE5AZmhQC49zd5ff64cO0KTE5OaiSAv3QE/7JFm2XwcxXAQwJXOCCQgLZJKGSb8IY9v4bx8XHl4TnguY2Pj8OzBz4MbB3meQEKVAnAcXj+WON+adiHYasvJYHd2SOQzWZhuG8LDPdtCXQImgwlPLYS8z0Ej4Y3lkFuAj8hARhLKxK5/d2FJ0INzBoBFIvTCuAS2KXH33+Sh0KhAJOTkyoUUDX+5pchlUqbwW8KBXySgo7eAFdCkKqBN9/8GC5dumQEOvzjdwCFMc0OHz6sAcI0P4A3AUmgdxEBfV0iEawE8AakqOCn/5ZU/xhs2PNrGHjjHfj98c1wOb8VpgY61B4AbPChgKav2bL/pnu4urP8O6/sJ3h4pldtQXYSwESbIoFHwxsBCmOPPQkkTgDo/b//JG/M/Juut/etgsK1K1AoFFQ4EAr8lASQAKgCsPUH2MIAQ6swJYGf738/4O0R7P8sXgiAvvTVCSh9dQJyuZyYJJSUAJfqPsD3eZ5/JhKBa7OPS/prxnZGLur9LezOHoGhY3m4Ndge7PJT8wP0nYCcIHzzABoR4LWyf8AE/kcfdGkkgMlBXrJ+nNasEQDN9Nvif/6YhgJl2Z/WwY9Zf5r9d5GABH6XEvBUAQh8KvElsFPQl746AQ/P9MLu7BExWciVAEp/Cai+ZMDBzUuJ0mdiPkDy/lKOwhbzSxuj6L95d/aIvf+feHE6VIQqBCcJjKWr7yefV/rqhGoQ4oYkwPsFisVpKwnUKzkkSgClUgngXz+UJbzF29teu3tgNVwf31sGB/X8zS/7gR+9vkQCPg1Cnp2CG/b8Gi5duhSQ9BLYKejxmsvlAvkDU8nQB/wSGdhATUnA9Z5IcX8I8HPbnT0SUAVY21dThRiA4epOYwVAA+9x+TPK9/1VVTBBwP9Bpa+A5ARKX50wVqsAyvtesKegnlbiBHDv3j24Pr5XBP2twXaRBHhO4P6h9dCX2VQGfipdBb9EAGGVAK0KRAgFFvechqGh06EBT224b4te5jIRQKUawAeDRiEBmuGnLb88+88JAhWAC/yUBJb+4tNI4NeagXaMwO7sETUrQN4VGBweUvrqhAZUExkoNcCVhUACmhEy+enKe8a+lUKhAHdOdVe2MtfPSowAEPz37t2DqYEObwUgEcH0W2vg9r5V0JfZpIPfRgS+uYAaugQX95yGa388agW6BHhqUwMdcq97paLAQcFBGpYE+Ht5v79J6kdN+tHPXDZ6TT3v4/m1dmBSCly/7VeB8AClfxlgBiJgqoDfPzjZDfpYMjpwpEoElAC0pOBYGn668p5YtgYAON/fqkKGelmJE0CxOO2M800dgQj+uwdWw/Rba2Bq71LY+HyvHgL4gj9MPsCjS3D9tl/B95/kjaDHNlJquAUV7f6h9dXPxOYWixLg3j+KEqAHf/D5fhgCmBJ+tM5vq/nTuB/3KqTGChq50Jq/tQRo6QfY+HyvmCdQ2X5xnFg5XyCFArRvQAM+HzoyllbgR6Ofdfu7CwESKJVKMNy3RX3tP4sXkoJeqJU4Afx05T2v0h+/Tr+1Rnl+vE4NdCgSsCoAExmY8gG0KuChAtZv+5XVu1PwI9ipl7p/aD3cP7QestlstamFdhsaVAD1phL4fciA7+7j9/TrTF7fd5cffh4Ff2qsoAwVgW8IEGgIeqk8/BObgRDI9PctEkElvn94pjdABCocuLoT9ElD7EqqEJwEHp7pFUlgfHxcI496mEGQCAEg+GdmZuDzc/vh7oHVzhAAAU8NwT+1dync3rcKbuxaATd2rYDz/a1uEhBsd/YIbHy+Vw2h/Pzcfu16+PBh2J09Uk44GkgAwW8CPvfweOWmpL+wwQX/yNHzISBc4OdEwGW+aWMPHzCK7wsj+3nMTwEvgd9GBCLwaZMVactW5LlhL/RlNsGdU8EqQFV2y2qA5wh0JcAnDRH7ZnU5sfdBkEQenunV+lfu3bsHk5OT5aE336yum92GiRMAj/+5l+fgl0A//dYaBX60mzuaYWXbNiMJ7M4egcOHD8Pn5/bDT1feg9JXJ+CnK+9piTp8TJ/Hr8PrtT8ehdHRURh44x3YnT0Cl/NbIwGeG46yVqBnYQA23iAQTN7fRQq2/fy2Md+UBHxjfpPXp49NJMCJwEoCwtZgpeLWvQbDfVvkJiBa9uPxPZPxuhIwEAC8WC4XVt7L8wEPz/Rq+1lmZmbKYQDZbGSrHMzGSpwApt9aE5D7JuCj3di1AqYGOgKgRytsXwg3dzTD9Z5lsLJtGyxbtBk2Pl8upX1+br+KzVGm01idApyTgUQS9HUKehfYqdQXvT8OwOT97ZXHCEr8Ohq7+4QBtr38rnP96PfBfIAJ/EhUHPAc9C7wU1v6i0/9wM/zJ5Xf4cq2bbCybRvcGmxX4QAlBGOMT9SARgQc9Nq4sfKVqwAkgJ+uvKe1sw8dy5d3JP69SakA3FcwF0QQOwFQ8BeL06LX57E9eni8Tu1dKgKeXq/3LIPrPctgaqDDKMm//yQP33+SDyTokBBMxMBJAsEvgdoGdMnuHlhd9v5IANTwj7uSPKPn8UkAM5kL4GHCAK4EsAXZRkZc9ocBvzJpUxUfxkI3aJENQtRGMpbSX2CiMEnyETA/ONld9vR82Ki6lo1XBdDonpZLly6VT0mClFIBxeK0OARnNlaiBHD7uwsK4DZvT+N7CfgU9Pgc9ozzpJvNkAzoPc/gQ2FMJIgwILeZ5v0rtvQXn0Kqf0zruafglyR1VALwIQfb57q+d1SvzxWANf6n8p+WZ2koVVECqQ17IZ1OKzUgZ/xpnF+5n9DnBcJYWnl8PmZMs4k2UQlgS/vk5CSc729VQ0keDZdHkPEhOE8EAXx+bn9ob4/xfWH7Qrixa4UCPfX4VH7zOBytVmKgBOEb1/tYLpcTwY9yn5/Bh6AISwIuzx6FAHzBXwsBLBu9Jst/An6lArgCYFuFFQmsew1Wtm1TOwgDswFMcX4lWafi+w+6wAp+RgJUDeDGtkKhUM0DVFQDqoCwU7DiWLETAP7wxeI0fH5uf2hvT+N7CvybO5q9AOYihrDk8PBMbySg3z2wWrynwOdmA7+P97WpAB+CqIUAYpH9Du8fkP88F4CJQBMRNL8MfZlNYjNQOUEoxPkkyafmBxiAjxOIMSfAk4M/XXkPJr74FoaO5dXn/PuHFVYVkDQJxEoA1PtjxrMWb8+9fi3GE3e+5BDF+0vgv3tgNVzOb9W8vgv8pjp6WCLwVQhhCcAE+qjgT40VylUFm/SXFAAlAAQ/kgELB1a2bYN0Og13TskDQqqxfjXO55n+wFkDDPxoUn/ApUuX4NKlS3BrsF29F1UA5gmKxelZUwGJEUCxOA3n+1vh7oHVcHNHs9HbU9Bz8Eten4IrTjMRgw/Qpav03O7sESX1Md6nsT73/FHlf5TwwJXYcwE/DvCnxgrlioJL+psUgIMEMBRINb8M6XRaCwlkEtDBrTL9lVBAAj2fPMyTgt9/kodLly7B+f7W6udXVADOwiwW5SlYSazECSCst7/Y3gTXe5bBjV0rAoCyAS4JUvAFuw38aDPvrixv52Xg5wk/EzAkL1sr+HmisVbZH5dpA0EN2X+jCnCRAMsLTA10yN2AlQnC3MsjCYijxh0kgLMLLl26BLlcTvtsGCurktlWAYkRwOTkJIxkusTyHQf+xfYmKGxfCBfbm+Dmjma4vW9VAECS+XjdOJSDSdL7/IxomP2nkt8H+JQAfLxvUpak1xdVAJX+OFPRJv8lAuCbvAQlgCSAIQEnAUnqY3zvAr4igG9Wa0rg+vheGDqW1wmm0lXI+waSJoFYCYAmAIvFabjY3mT09ujp6fXmjmaYeXW5ChvuHlgNM68uh/uH1hsf+xBELcrBF/wuMvj98c0qy08JwBcU9Qr+uA1/L5gMxB2Qy0avyTMZXeCXCABnRG7Yqw6PwZ16LhLQ4vuJNvNhI8KhI3SS0LU/HoW710gYUQkDro/vVeXCYlGfhZnEil0BoPxHBcDBj4D/8rlFTvBjDsCXDOjj+4fWq8dRlYMPsF2v479puG8LZLNZscEnrJmALxGB62tsj02ePmnw80NJl41eK88TeGlQBr1EAtwcOYFU88uqt8REAlrMX5H2CuwG4GtHkBEVcOdUN9y9VkkyIqlMlHsPpGG4SW0cio0AePw/OTmpSXvu7b98bpEiAQT/zKvLNfDbrpJSwGst9mN2gfZ5YY2+D+9v71sF51qb4FxrE2QymWqbb42AMeUFXIqhFvAnZVIylJJAYBOQj/x/abBcVeAkQCdFUyLYsFftKpQSg2J8P9FmBr9w8AiSwMMzvUoBKAKovE6H4RaLyaqAxAigUCjASKYLvu5cIoIfrzd2rVDApyQggVMiCheY6TWKhQE6v9J7JIBzrU2wftuvYiEAExn4eG8X8GcD9C7wUxJQeQGT9OfgfyGv2pcDCkAigeaXVTs27Rq0kgA5UMTXaJOQFkJUPhuTgdg0VCw+xgTAPT0F/9edSxSQf8wugBu7VqgrBbtEEDOvLofb+1Zp1zBE4EMM9HOjgB/fj899tiAFe9YtUSSwYc+vEwOUC/Sur5kN0IcBPx1FplUHLCSwqPe3KuGa2jESDAd4LuAl/RQiKSmojhUTknxO4NPDR7AqMBFUD0gQtHW4WEyuIpAoAZxrDXr9i08tgOs9y+DH7AIFftM9gp6Cn3YWxkECPgpA8uwc4FIYgvc0BOAkELcSCEMQc21hwM87G5f+4lOj5091vi2OMVPlRdpCvGNEPJIsm82aScBT8nNyUCQw0VZVAIYw4fNz+2FychIK164kqgISVwDKnloAXz63CArbF4pANz2HVw58iQDCEEHUcEC6cjLgP8uNXSsCCmA2lEA9mw/wTeBXIcHrHxlj/zBnGPATilENZLNZuTIwEQSu0+uTe0wImj5HhQGzoAISIYDJyUmdACrgR5BjYxCX/iYFQDcTxUECPkY/RwI4zz+YXsP3cuDvWbcEPluQgnOtTeUJRHUAynoAvwn4JhJQEp+AH6cS+Q4zVROLqRKohAI4XERsFArj9Q1Hj5nyBNg2nHQyMDECmJychHOtZfB/3bkEpvYuhZlXl6sr3RsgEQFepS3ENkuKBGxAl8iCksaP2QUB74/gny9KgO5vCCP5bduX6VmFGOfbPH8YEqDzGayVAU+v7yIAThqPhjfCtT8e1VTAY0UAqAAQ6Hw3IJIAXrkKwE1E0rgwHxKIyyRvzhOEJqVAH3MFwO1ie1N5SGgdgHWuvL4Eftoy7SSBSuY/yjhzflIxbUfesOfX9qQgA74V9MyM7x0r71WY+OLbRMOARAlgau9SBf7b+1ape64GuBKYeXW5OCTUhwTiiPVdRGDz/NLX3dzR7AT/udZyojSbzc5JYnCuvL5Pws8H/KgCfMDPSSBwghFVARUSMOYDXECOSAKPPuiCO6e6y2EAOR8zbhWQGAFcH9+rAZOCX1IBSAI28LtIII66v03+u4AuvdeUA7j41AKNAKiNZLpq6hSsB/P1+FHAj8CXSCDKQSYSCWjjySuhwO+PbzaGAr5gd5EANbp9OKkwIHYCKBan4ftP8gqUElAxFJDyAi7wSyRAQR8nCZjkvgRwm1KQCMAEfiyZjmS64NkDHz5WRFCrx3eBnwPfBX7J65vif64A1JUeTOLoD/AG/ESb19dhHiDJZGDsBPDTlfe0OYCcBExKAB/jFGFfErCBPy4SsOUBfEhh5tXlSuaj55eAz1unC9sXQi6Xg/868LGyeiWDMB7fp8TnI/tdnl8CPx1h7jrIVAsDKqFALpezhgLewKf3Jqv0AyQZBsS3GahyCnAYyc6Tgxz8NiIwgT9p4NPnTf0Akor48rlFgZifg59vjcYNVIXtC6GwfaFqq6af1ZfZBK+k10Imk1Gmpg7Xkcd3ef0w0j8K+MPIf36QqTafwFAVgLG0H/j51aYAPuiCqYGORMOAWBXAnVPd3nE7VwIU8Bz4/DEFP5qNBJIgBBfoJQVgM75pamrvUm1+Ahq+jiSC5cXNa6rW0vKMsnoAfi2gDwN436SfE/xCHoCGAaYuQSPIw17xfqIN7pzqhvHxcWNTUK0rNgL4/pO8U7qbSIASACcB6TNdcj+OEMBU6gsDemqF7QuN0h/BT68S+PlYNdpUtGfdEgX+zWuaILWwpWyVGQRRcwkU7FGkvqmrr5ZkX5ikny/4TSQQWQVMtJmvaB5k8Gh4I4yPjycWBsRCAPQEoOm31sDUQEcoEuCAt5EA9fpJk4Dk6aNuOUZwmyQ/lfsU+HSMGu2gxBLrxXadAJAEFAG8NCgCl4I6LrBH8fq+ib9aYn5b7d8G/EA1gM0oNLUJi2A3Gf066Z7kAS5duqSa7OqKAKj3D6MCMAGIoOfGP88m+5NKAMZlN3atcMb7PuCn5VLcI1HYvtBIABRgtQK6VvAvP/HnKphe/0gEO4I1DvCHjvt9SaCyLVkqCyoVMNEWjggkIw1BNA9QLFZnBs49AfzrBwVU9PwuJYA1e/wDNgGf3nPP7xP/xxUCRJX9JgLgnp9Lf5vnx8+iV1QYSACphS2wZ90SyOVymoyebcBz8lGZdXLwpwZKNg3Yp9SXlOdXP+vrH8HQsTxczm8tJ1eJCni646h8luBEW2z26IMuuJzfWg0DYs4D1EwA6P19Yvfpt8qn/lLwmrw//Rzu+R9HBXB73ypjvC/F+hT8tEPSdL25oxnO97fC0LF8+YDTf/0An5/br4GES+84AO8CPyUBra4unfwjGAI6Kc/vQwS7s0fURN+BN97RzigQ9wl80GUG9dWd4UkgwTxAbQTwrx9gaqBDAy0+lpSAJOFtBCCBX3ps8vym1+fKJM/vkvzUy0v3t/etUmcaPvrbNc1+NvgnbRIxelIO4FqB75vgC8TSJqMTgS3tvbV4/jDyP/X6RxrAf0GxQZUAACAASURBVH98swoDMpkMPDzTq4UAVhVwdadGApwsxMdjaUUANAyYcwKg3t8Vv0senEp9yWio4JL9LhKYa4Vwe98q8RAUG/hNHv/2vlVw51R3+fTif/2gAE/vh47lxVOIpARcLfKey3xbQk9rqvEEv+/23jCePyz4U69/BJfzW7WpvkgCi3tOw63B9kAewKoCYEgDO7/y+wcnu7VEYJz9ADURwJ1T3V4EYAKxS/674n6X1Qv4qdeWYn5TvM/Bf2uwHUpfnQgAXiOBf/wOhoZOiycQ+5KA9HytTTzLT/xZjPONoCcHgizq/a0WCkj3ccT8mmV+E8gDPPqgSx0M8uBkd/mg1xfy0JfZFMgF4MCPAMCv7iwTwNWd6vNsZIBfczm/Fc6e/TT2PEBkArj93QWnfHeB2PbeWsHvIoHZ9v6cACjoJc9P90lIEp+CHu32dxeq8SnuZw9JAqYrB54v6KUwIAB8wylA/Ipz/mqp84cmggoZDLzxThnYlVN8EOjZbBZSL+RVY5B2kKgAaE4AFORGIqhUAmgeYM4JwCb/fT24b9wvgT/u4R+zRQKuTD8SxfRba+D7T/Lwz+KFANAlEjh8+HB5uGX/mBpyyUkAwwEEtCTfpStvhrGV8nzq+dK5f+IRYPQcABwJTioHLs8fBfRU9uP9ot7fwoY9v9aGgND5/qkX8vLBIhKYkQBgSIGbkgA37AW4c6obRkdHY08ERiKAUqlUE/ht8b8t7kcCoOCvZyKgzUO3962CuwdWO5N99w+th5+uvAf/LF5Q4JdIAMF/+7sLkMlkynPtXxqsgp8qgf6xMggcuQDp8dJffBoAP7+iZ7YBn96bDv00nv/HxoFTJRBXvG8kgsqxZIt6f6ufFDTRpoB+Ob8VXkmvFfMAAS9PCECpAPK1JntwsjuRRGAkArj93QUoHe+KJN9dBOADftMIsHoiA945iCTAQa8k/0AHlL46Abe/KwMfrzYS+Pzc/sDBl4oEhBCAl9Q4WCVZn3r9I+/SHSUCUxsvEopGUgz82vl/0lkArH8grnIf9fg0D4AkoLL7eEoQkfuvpNcG9gdwYMNYOkAAGlEYiACPGUcFEGciMDQBlEolq/z3Ab8p/g8LfhsZzKVx0NMzBabfWqN5f/T4UBiD299dUFcEv0QA1OvTc+9tCsCVB7DF7GHq9ijJMelHgU8VhdPrU9DzE4Eyv4nV81PZT0FPQ59Fvb8t1/wrR4PjgZ4I9luD7SoMoKcBcxBrBABD1ecNhu/FSoCpIWhWFYAp+z/zqjl2dxGAS/q7wM9HguHPMtte3wZ+SgIY40NhTAQ/JwEkgM/P7VfApwSgKQAhEUjjZqknwFi68y3bsZKd8vKVPAElnkC8jyCnQJc8PzWDCgjr+aWYXyMBPJk48xu4nN8KD052VwmAJQSnBjoCPQEYw2sE8I/feROAIoJKqKEqAZVE4E9X3qtpTmBoAnj0t2vW2J0CzzcB6JMwtM0V4OCfC+C7PD8/TPT+ofXw8Ewv3P7ugor58cpVAN7ncjkR/KL39wwBXErAC/jksdYvX7nS75t6/aMA4PmR314HgBICiDvm554fiQB7///9wwqQVIAUAgSMK4BKGOBjvBJQKBTU39CsEcBPV94zJv0oKLDlVyICTgAu5eAzXEQC/2wQgS/47x9aD9NvrQkcP1463iWGAJQEfrryHqTT6QD4rd6/RvDjawFAO+r2YkaftPTSzTSi3Pe1SrgRR8yvPD5/bu1BSHW+DYt7TsPintPQl9kUJACmAgIhALtyAih9dUIPERwKYHx8vDwfoHJ24OX8Vnh4pnf2CODhmV4r+LF+bVMBdAOQy/vT8WKcBCgR8O85G57f1+NLwEe7c6ob7h9aL4YCUBhTkr+l5ZmawC/11PMEnZS8axr4gxP8UgKPx/ZiUo/H9mHMAv4opT5J+qfWHoRUql8ZHhKiKgGCCpB2B+J9OXwYCpqNMAgBSIlALBFGDQNCE4CUuOPgl5SAqQLgI/1tW4tp6DHbXp/H/JwIqNyXrHS8S5HAg5PdCvSFa1cACmMw3LelDPTFnWbwW4DPvT9efYBPr6qDzxP8xho+v4b1/J1vq65Ak+yvJeanjxf3nA4QQF9mUxnEE20aAfz7700i4DF5R58rfXXCSADS+zmhoALAMACfLxajJQNDEQCP/xFwONmHA5+CUlIArsSfDfyuuYBJe34EOgX87X2rNNBLnv/WYHvA++P14ZleFQ6MZLrMnv+lwVBxfxjvb7rHpJ7k4W2ZfGs5LwTw1WcQkGveO6wR2c8z/6gAFvecLn/vCgFkMplqgw9VAKwvwAZiUQFc3Wl9H1UAQ8fyMD4+DhNffAvX/nhUfQ3mAcKSQCgCoPE/lf68BCcpAQnYtXh/02iwJL0+nQ4kyX6Xx+de//6h9fDgZLemAn668h6MZLogtbDFHvOHBL9EAhLgTc8b5b3J29cKegp8vK8ogNSOEe05DAl8pb+U7V/cc7oq/TO/qXr+tQfL1vwybHy+10gAtDuQyvcAiAUCwDyATTlIeYDPz+1Xr3//SV7rCfAlgVAEQCf/SOU5qgQ4GXACkJSBpBIQ7PSev382CMAn3neBn3v8O6e6oXS8S4H/zqlumBrocIPfQ/qbPL8N+CYiSL3+kSzvLTI/Mug5+BHk0mP+Wog6v3qOSHwu+VNrD6rcx+Ke07A7e6QKbq4AWDLQGNdLCgD6vRQAEgDmAXCH4sMzvXA5vzVwdJgPCYQigDunKn+kJMPv05TD8wC+3p/vKsR7qeSYZKzP43wb6LnsvzXYrrw+gh09PwX+g5PVeynjHzbm9/H8vkZLd8a4nt/bnvMBvYkEKODpa5XwIEzMv7jntA54Zot7TmvJz93ZI3BrsB1gLA3//ntTuRsQuwIrYYDJcz8a3lipAPSLJGBTDvQzqQJAAoCrO+HOqW6tNdiXBEIRwK3Bdg3MrqYcqghsgLd5f4kEOFkkQQImjy/JfluWn0t+yevz6/n+Vu8uP3V4RULg5517opevJZsfBvScAHaM6KFBmJIfXjvfhtTagzIZrD1Y/jpCAAhMJABq2PRjjP/H0oAeX7dgHoACn37OnVPdMDR0GsbHx5X3xx4BbA0OQwLeBPDob9fgzqluBbypgQ5tpr+LDMIQgG06MI/7kwC/tIknLPAR8NTru8BPVUCYLj8O/rgJoGngD7V5dp/43gf0npLf5PlNnX5a3Z8SQOfbigAW95yuJgEtBMA9t0YASgEIViEAmxLAx6OjozA6Oqo+E0vzfIOQT1LQmwBuf3dBxd6YqOLlOBsR+IJ/5tXlGuDpPZf+cYK/1oYe7vFNnl+S/PT+4ZleeHCyG07k/iNSzB83+KkKqDm2N3n5MCSwYW/13hXv2zw/zQVI4CfeH9WPSwHwDUKBngAPArAlANGGjuVVAhBHjD0a3iieH+iaF+BNAN9/koeHZ3qVpJAm/tpIwDcMoE1CXAHwz4jb6/vE+r6JPh7vu4D/4GQZ/EgCtwbbreCn0p/3w1MC4ERge2x6r2q4ieL1bRI/rNdnJGCU/Qaw8919XAGo2j+GBCj/KyEAPRHo3z+sKIOeXdWuPrEE+GIF8Pxavse/BykMoCpg6Fh5JPnDM706AZDTg3goUDMBPPrbNXVvOgOQkwCv1YeV/67NQknG+1FifZrwM8l9k9eXrul0Wiz3aXH/6x85wR/XVSUDo0j7WkBPvT69l8IAWt/3JAObqUTgC3ldAVQGgyirkAANA7D7r9oF+CIDv04EXn0EY2kY7tuiJQBxP4HpFOFYCABXqVSCa3886jzKGwkgbALQd8BIXJKfSv84vD6P+U2xPoKc3mNS59HwRnh4phf6MpsCCsAG/jhJIPX6R+JjDAWcwI8T9PQxXte9piUDnbv6JM/PHvPXeAiQzWbNBFAxmgjEK5JAFfQyEfjmAH5/fLMaR47hw8MzvdomIa4CYiWAy/mtgbq8iQSiZP9t24xpEjDOJF8Ur2+K9X3kPpZUqdfn91MDHXb5b/D+tZCB7bPQFAkkKO9F0HPwb9hbluwb9vp5einxZwI+k/9r0r/UjgY3EgDbF0BlfZAAmFVALuUAeC/ArcH2al9BJQTgw0KKxelkCICfAGQyV7KPXyX5b1IRcQFf8v42r4+tvCap75L9FOT4GD0+BT8+piGA2p5KwG9SAVHNlwisJBCHvHd5fgr+tQe1OYVWz+8DfOb9MfE53LdF/X8h2L0JYKLNSQCPPuhSZT1TNQFLflpZkRMAmxk4MzMTHwHwg0BNRGCT/jOvBncNmgggrtg/TJY/akefzdsj4E0xv8kymUwwBHj9I2sIMFumcgJRPL0N/CbQS1f8mrCJvxfy5fe/kNfjfer98blKAxTuBnz0QZcCv3TlOwAxW19uGHqxArsy6KvPvSiWAnkSUKwqVN7HZwVQFRALAZRKJTUO3EYCNulvAujU3qXeY8Likvx8So9vnM89P15tdX3u/dHrS9Kf2nDfFqP8T0oF+IJfIwGJCOhzNk8vSX307hzoeI+vr3utSgidbweGeFDPrzb30Pcg4PH7CglAVAAqBLAQAN0TgAB+cLK7MkPgRZEE1H1FPUihAFUC+nCRftUJyIeGJkIAP115z9qo4yP96cx7evUdMVZrhj9MDz8C3qebzxTjc/BTsGPiz2Tn+1utOYDZAD8nGvo91XNsg45SKr5e3gV+IvcV8NcerL5OQS15fgp8CfzsOQp+JAB1DmCFAKgp728IAbReAQX+lH6PQ0KxaiD0FGivky7CqYEOfatw3ARQKpXg3r17zsNAXVl/vlOQPo7T+/t4fZ8kH5b2+N59W4Zf8vgmzy8ZZnW1PADKf2wCYmGAFZwWpeD79dJr/F611vLHNm/PwY6vIagpCSB4ufdHw+e43DeBf8dI9bnml3XZX7nSFmgVe0+0BQiAEgEnAH3zUBX4uhpIiRUEPhBEUwWEAOgmISkPEBsB8IlAlAx8vD+CE4FPy3E+Q0Kjen1KAgh6HvPj8zd2rYCbO5qVfd25BL7uXALXe5ape2r4/PWeZcq+7lwCUwMdcHNHM0wNdGiKwNdQ2mkKYMdIVQWwGrgNxLVcvcHP7aXB8Nl87u0psE3AlwwJRyIJmgNA8OPPREmAyP/FPaerp/9YCEBSAHyAiGT//nuTFgJwFcD3Bmj7CioKYHR0VMwDxEoAEvh9pvsgeCng6T3PAYTNIZjq+nwfP71Su7mjGb58bhFcfGoBXHxqAXz53CL4bEFKu8fX6RXvv+5coj33decSONfaBC0tz0BqYYtme9YtgRO5/4DL+a2KFKjXf3imF0pfnVD3tBeAVgIoCXAwmoDqA3YfoDvBjxt1bGAXsvki2CXg+xKBzZpfrn7WC3lILe4UFQCSgJLhHgSggZiPEDORAMsf2EqB1dmCZQIY7tuiEQA9PKRYnK6dALCjyAT+mzuanQSAm4foTkGqBnznBPqoAN+vQw+PAKdXn+cR/Pj4684lsGfdEg3wLS3PQGpxp35lr49kukQygKs7xWYgUxtsWCCHBraPcfA7SngKzFJyLw6gc8Czq+r2W9hiBD8SAIyly4CmJMAIgSuAatwfjgBMewMefdBVGS1WbiPGXBHuEhwfH49XAaD3n5mZEcE/NdAB13uWeTX6UO9PVQAlAFcJ0dZLEMau9yyDi08tsIJeeoxenj/3decS2LymqQzsCtBxph/O9aPP4T0lhM1rmuB8f6sC//ef5I0EUNNIrKQs8xu5fMeTetLVdh8H4E0kgFJ/YYuS+zz+3509AqXj5Lw+BD4ngom2oOemMwMcBOD0/Dz+ZwrAdHpQLARgOhEYz7r3IQDTTkGaA3B9ji8R2EiBA5iDnHt2Ku3pc/Rr0fMrUAug53P++GtUIaAqCOwHwNZXQy5gTs1Uu+dy3iXx4/L2NuDjfefb5d/rwhZIbdgb8P6Le05X24CxAkDBzwhBA+pEmzY4RBokosiB9BDYdgXquwrLQ0X7MptEBVAsxhACuAjgswUpL9Dy3YK0ZwAVQNj24VrBL8l4H08vPaYSX+3nF0BvmvQbmAKEYYK0H4D0v9cNCewYMcv6JD29r8fn980vw+X81nKzVeY31d83K/9hF6BK6DmMAlZtFLKYIgdHDkAlAWn8D/1qgxDmAHBoaGwKAOW/RAAoo8MSgDTWO6z3t11t4KcApgk8Dmzu+flj+tzF9ibl/ak3d4HcSgCmAaD1Gga8kA96eA5++lxSHt8Q61PgUwJ4NLyx3HCFBEDmHmDzkNp95wI/G+7pAr/WG1BRALZ5ANX6f1UBPBreCLlcDoaGTscfAtD4//r43sC5gJj59gEuBb802TfK7sEwZHC9Z5kGcAns0mPu7fkV5b9pjLfpOC/ba9owED4TgBzLPdcEoH1/KvWl+D4u7y+B3cPbSyRwOb+1HNsPb4Tz/a1lFdf8sj74pPPtcgkQ438HASjAftDlTQBYBpR6/2lY8PBMrwZ+gH4oHe+Cw4cPG0OAWAmAZ/5RNvsSgGnPAFYF4gK/VBWQMvZhwW66vpJe6/T8CGYR4DbDQRwWBTCbRGA8Ugtr6yYvH1dSz8fL24igYssWVbfVonc9399aTtqSrc5PdxxV8h9JwEgG1HN/s7oKcJ9QYKItUPuX+/9R/le7ACkBJKoAuPdHwEQlAArmMN7fBX5OBBywPjE9lflSAxB9Pp1O20/wiWJU+rNeAFcYYByN5fk4AG7Tc/SeNt4kUb7zIQEL4E0hACoAtFfSa7W25kwmU/a8DPgiGRDw8mEh4pUQBC0hmpQA9/5wdSf8/vjmoAKonB1YLNaoALD+PzMzo/Yh3xpshxu7VsBnC1KxEcCP2QWJ5AB+zC5QTT6S1HdJe9M97wTcvKbJPcdfur6Qt78uyH8eAnAV4AVm8nxY8Afeh6/R7rrZAH8NwEej5/2hCrg12F7+/6sQwHDflnJsT0wiAIz/YSxdlf8+JFC58goC7wcol//oVOGyAhjJlEMAWgaMNQSYmZmBYnFaseWtwXYVQ3+2IOVVAvQhgCjmQwK1enqXXe9ZBq+k14YDP0p612NuAgGE8tKmkVkeX2/cb195bXHP6dmr3dcIfDTc4cd7+EcyXUoFXM5vDQBfIgNtHqAwKyBABuwe32/cBaidK1AdJtqX2QRDx/JaCBALAVD5TxXA1ECHAv9nC1JeXYCUALDbL2zMHwX8P2YXOD17LeBHAuCz/EXwm0BNx2zz5wzgxw0vgUEXgoc2kYR1XHbIq/o5Zkvm1wh8TPRpJ/4SCX7nVDc83XEUUhv2qoSey6jnNoLfQgiagmC7AHn3H5IAbhkfOpYX9wIUi9PRJwJRAkAFQEt/VAH4xORxEoBvDgA35vhI+ah2c0czzLy6vJwHoEk+H/D7Go6nMigAkyxP+nHgyjfgYDItTELPJfFrBD4lAFQAuGGHqwBsAEJZ70UAH3SFIwCcJmToADRl/3GOYDabVSEAJYCatwObFAAF/2cLUlDYvtCZgccWYLp9OCoBhMkBmGL7uOx6zzJFAKgCAjE+Bz8Ds+nobRPwqce1KYBEr6Z73GJb2XWnfj4kAd8SXgKA16wysESd91chANrI8+Bkt1YlcJIAAneiLRYCCGb/mfyHfrg12A4Db7yjegCkeQCxKIDJyUm4nN8K9w+t18CPIYCp8Ybu98cegDAtv1HIgBNAnGCXrvhvm3l1eXWSr+D5tbPmolgFYE7w42u1PrbM1DPN2DNO3e182z+uTwLwFVu2aLPy/ot7TgdO/P3335uC8pt7ZfT2/Mqy/6aZgbZhoqa9AJL3xz0AvALAS4CxhgCYOJMUAAe8RAQ+E3/iUAA/Zhdoe/njBj293ti1QptBkMlkAt5fgZ/Mm+Pz50yAl95jVAISSA3e2vW69pxEMI6fQwN/WNAnSAKpzrdVo4+a9U+P/J5o8yIB9T6yRx/lPwW6NDaME0FgD4Eo/80VAFMXYOwKgMt/kwKQiODHbHXuf5QcACUM3wRgWKC7wE4HfuA9fj86d2Dj8726AuDAdhn9OsN7TEpAUgaLe057vy56dIk0hMeB57j0nyVPr2Q+gh2nD5HdfqnOt2FN+pfwaHgjlI4TAmBbejkBaJ6Ze2w2IswGfG2UGCMdnB4VbP4hRFDZBGTqAoxNARSL00oBcPAjAdCTgKUrArfeFICPh5dAT42CH4eQTL+1pkwCXAH4EoDFJC9rG3Ft9PSm91m+xudeMx/QJ0QEdFcfN6oCFNDI1lwTAUgxOpf/NhIwXlnST1MctPOP7QKkCUBTD0CsCkAigOs9y8S9/vRxnATgmwOQCIADPCroOQHwcwY0EsD95nitkQB8AW4DaGhPHtU27E3WyxtifC73bSSAnYDa/vwJcxhgJIWJNuukID48lBIA7wCUt/7qJDA10KFtAsL4H3cCxkYAxeI0TE5Owufn9osE8HXnEiPw+dmANAmYhAKQSoAu7+4DcpPd3NEcyAFQEri9bxVks1l1hJV26GTMROAkhwiv12qLe07PSlxPgY/36rnKYZ+iAuh8W1QAvDHIRxG4wG8kgYk2Efzln4mCXt8DcL6/tVwBEHoAaPwfmQDwzUgA4+PjRgVAR3zZTgamgz+S7ANAAvCR9mHAbrpKg0gpIeRyuURVQF1bAsAPeHoHCXACeLrjqEYApeNdgak9cXt/o03ILcCm2j82AJ3I/YdWAjQlAGMLAa798ahIAF8+t8gIfk4AtBIQRgFIX+ubA6jVy7vAz5OAJjIY7tuik8AcKALNdozA+m2/glwuBwNvvAPDfVvUybPDfVsgl8tBLpeD3dkjNX0PVQJMAPgc6KYrDQW0xCBRAOXDO6KFAZHBX9kCzON/fd+/Dn6M/zOZjFcJsFQqRScAbAKanJyES5cuOQnANPGHWi0hQJgmoFqAbgI7dv7ZFAC/0gnFI5kuWL/tV0YCSFwd7BiBXC4Hw31bAseg4fkH9FQjPJugdLwLLue3Qi6Xg/XbfiUTlqG8qfYIxOzpQ5FBBfTU8y/uOQ2ptQc1AtAGdPgSgHBQSBiTyox68i9IBA9OdqsEoG0bcE0EwEOAQqEgEsDFp/RhH/xqIoCpvUsTrwLU4tldV2o2+U+fn35rDUztXSqSQGJkUPH0CHq0uwdWB8DO7ftP8uqKo8ofnOyG4b4t1X9D5jfOK52yE0UR+Hr6ADmk0oE8gEkBaPv32Ygup/efaDNOCXbJf+79cSCsrAD0+N+nAlCTAuAEIPUBfLYgFeqUYMwD1FIF8FEAkjc3eXqTZzeBnj92yX+uBDA5qCWmJOBwIvAhB+KJOfDR46Onp0eXUaPPIQmUvjpR3pBSGIPvPymXz4b7tgSUjPZveCFfk7T3ie8DYBeuFPhPdxwtb/TpfBue7jgqKgA0b++PoJeIQCKEynO0hVg7+8/i/bX437IJKPYQoFAowLnWJpEAbuxa4U0AmAdIYjcgrQRQsEqADuPhXebKAfCDSvAeD/8MQwTW5yrg3/h8L1zObxVPPKYAN11NaqD01Qn46cp7AIUx+GfxAjw80wtTAx2wO3tEzm/UKPsje/zKlScBUQkg+LPZrCoDSoM66Iw/MfM/0SZPB/a5frNaTvwF+v7ZtdIA5LMHwJYA9CIAmgQsFAowkukKRQAmme9zAIhPMtBFAmEBb7r3IQCT/DcdUYZfM/3WGujLbFKSWv2x0um0HjIbd7dNDXQEjj7jHl8CvA389LQiKIxpJFD66gSUjneV90FUEm5a+29IWe/9nMHjL1u0WTMq+TUSWHtQdQJqCoBcrXkA14hw13VCzv6LXX8Vw991HAnASAQw3LfFWArk4MfJQRKQa9kOHDYRGEXSR1UAkuyX1IB0YOnUQAcM922BNelfBoBvA/3u7JFAUo96fBrn+3h+mxpAFcCVABTG4MHJ7vIgDUfyLorEN4FfeqyBn4BdUgB9mU06AbAhHaa2YJ8JwZpJJCBt/LHF/pUNQDT+HzqWh/HxcTh79lOxBTgWAigWy63AhUIBRkdHjZUADn5UAFKsb0oQxpUDwPs4wB1VAVCQS2rAZkgGw31bYHf2CGx8vhd2Z4/A7uwR6MtsUuU623HnEuglw6+lx6FLpEGVwPef5AEKYwCFMbj93QX4Z7FslARcnjysxHeBnX/NskWbA7E/JwOc968RgLBLT/T+YQhAMmPd3xz/PxouzynI5XKB+J+eB5iYArCVAinw8f56jzwuDKVvLSGAbyIwCcMThOnVpAJcnt9m+PV4ejH18BzwPMHHQY7g5glBHysd7wqQAFcBSAQPTnaXh6OElPlhwe8iAqsCWHsQUmsPVvf7W4Z41Oz9uZHkn1b6C7T9Brv/Hg1vNMf/Qgdg7ARQuHZFJACsBNCBH9NvrYHrPctEBYBhQC3e3wX+uEkAwY6fST+btwObSKAWMjB5eknuc7CbgO8iAf45rlAAieByfqtRrvsAnXtyHuvbQM/jfyn2x92Bd06Vf1/SNl4TAcTp/bUTfwLgD8r/qYGOav2/Iv+jJgBDEUCxWA4BJr741lgJ4PLfpgCiEIBPAlAig7i8PP0sfk8VQBgSiMM4WDkxSEQRxvtTk8IBiQS+/ySveWkfErBl8qNaau1BVfaj5T/MASBhomeWhnfwk3md4L660/o6n/1X9f4vVgCPV93wFOBcLmedAeAr/yMRQOHaFWMl4HrPMg38SAC2MGA2FIAvCZgAzz39zR3luj99DR+7EoFxen8OaEkVmMBfOt4VWQlIKgD7A25/V04I3jnVLcbmUYEe2vOjchC8/9MdRyG19mB1GhDr5efbdTW5PiGfB6Dur+4sG60OcOPjvsbSFdBTY0Rwdacq/2H8bzsHIDYCoGPBkQCGjuWNeQDp7ECbCghLAj7gl4gAgRsF9Py52/tWieB39QIkpQAksLuIQCIGG/iRNCQVQIng4ZleKB3vKicCBcD6lO6ien0FehI2iOCvyH+cCEwJQNquS6f/2MBfnipUBqvpBCFp8i/Ai5X2Y04CxCrxgT4REQAAIABJREFUfyaTiaUByIsAAIR24GtXjInAi08tEAnAdnRY1NmAPglAKSFoAvyNXSvUcyaA0+dR8k8NdGhVALo12hYOJJEHiAPsM++uDOQLpDAD73mOoHS8C6YGOsqHbKbSykyeXIrzowKfJwYR6FLyjyYAS8fNvfzasA7LgSDK+1eSdUaFwAeJkFmEZbCnRAJ4NLxR7f+31f+LRf/4PxoBVCoBpjzA1EBHqNODOYDjAL8tFDB5eh/vLsl9fi1sXwgX25vgxq4VsVYDXMAPA34fQsAeCt4+je+ZGuiAPeuWwEim7O3P97fC1N6l5WO1FraUz9cjBBAF2KG8PfkekufXwM9agF27+VynAVW9/xAADDlPDqIKgG9B1jYjoTKoeH8s/8UV/3sRgKkUaMoD3NzR7EUAEmjjVgAmApDkPQU6f4ykgGBGQCNh8MfnWpvgXGsTXO9ZJnr+JJKAYRSBLSdwe98q66apc61N5RN08ShtyRZ3igQQFwnwsCHwfda9Bqm1B8vbmEnMj9fU2oNaC7BrN594BgACGh9f3Qnwj98pAhBJgGf+v1mtgV+3FxUhoAKR4v9a5H9kAgiTB7jes0xNDvaJ3WvNAfiQgSmRR4HOrxIRSK/fPbAaLrY3KRI419oEhe0LYwe/y/uHUQLo8W/u0OcnIOgL2xfCudYmO+gR+JQAYlQBUnyvWo4xl1AhhsU95XHfD05268DHwaBc/k+06f35HgQQAHnF+wMMaeQggR+vurcPGt2ReOdUtzX+p4eAJEYAxWI1EeibB7i5o1mNDXN56CSrAKbKwP1D60Xw42P6+syry9VjBP39Q+u1HgB8nRIAJ4I4Q4GoYYAk9aWhKRfbPTx+CAKIlMlnMp96eR7X0/r+1ECHBnokg1UtA7r8R/Abrs4TgRD4//gdYLee6dQg6v0pARiJYKINHp7phZFMV7X91xH/+4I/MgFMfPGtdx4AFcDFp8zgNLULRwkDwoQCkqe3efi7B1Zb5//RK1cB1L58bpH6nDjVgO+Ve3sT+Dev8fD6NvAbCMBGAlbQcyOgltp7z/e3arIfbbhvi3YkuKYAhKsV/ET6wz9+pyoApjMDtZODDUZzAfg+lP9xxv9eBABgrgTYNgbxHADuGOSgRwuzMchXAfgqAhrHc6lv8/z0PfQxVgFMBEANJXat3t8m/fHfI4Fdur/YHgL4UuyPFQALAWhJuzCg51YJBWicjxOMRjJdAZJIrT0IUwMdqlyJMv3utZRx847k0WXvPyQSQED6812HJiKYaNPkv9T/X0v8700ApkSgaWMQDQNQAdDhoRL4fAnAB/xhQgHq0SkR0OQdB7evdLepAMkutpftes8yVZb0+T74893et0rlNwrbFxrPRDSBv7B9IexZtyQ86CMoAIkEIhsr7aF3T6f111a1DKjDPrUEIAW+YNJRYOWDRBj4//E7p/eHCXZuoIUI8L1S918t/f+xEYBPGIA5AEwQIjgRbHSa8GxUAUzGY3gb+KnZAOqrAjgJ8HskBpd9+dyigGEfBhJBYftCkQQK2xfWBnoJ/J4EEMaWLSq39/LEX2rtQcjlcnD/0HoF8I3P9wbk/9RARzD+D0EAijSo9KckQA4QDRz0YdpwxGYQoPfn2X/X/v+ZmZlQ4I9EAMViNRF49uynznLgjV0rAoNDpLMD+PTgpPoAXCQQZ9fe/UPrQ6sADnwfIvjyuUUiAXzduQQutjcp8Ju8vpbhpzJeAr0v8BMAPwI9te61ACk83XFUA//UQIdKFKbWHoRUql95f6UAPDf1qBCANu8I4C99dUI8LFR5f2GjkYkQ6PvS6XQs8/9qJgApD2AMA9qbyoM/BzoC+QEJ/Lf3rQo1JDRuBYA/k82bR43PwxKABH4EuS8JYCxPwS+RgJbo4wC2xfgm0Cft+RWgdWKYGuhQuyBRNpu8P5f/NiLgh39WJ/YMBUkAW4ClXv+JNnGjkWkGAe4QRPkfZ/tvaAIAMHcEjo+PW8MAJICLTy1QZjtDYLZzACYlEEcyDh+jl41KADYFYPL+FPxcARi9vkQAHPAu8Mft9Umcr2X0172m+gFoVh/bk/sym9TXrWoZ0Cb/0Pq/T4dfYGIPzfqzBKB0ZiBtNDIdGqoRAJkO/Ep6beztv5EIwJYH6MtsMoYB5/tbAwSAdXVqYUaE+VYBkiIB3+w7vfqGAq4cgEQEJhKQcgCBTj4G4JVt29ylvdkEPkv08bIe7uhD4ON9Op2GVKpfkQBVByj/eUefRACl40TOm+J+7ADkwCfSP7C/wEACdL/ArcF2lf33OQE4rPePTADFot4QNDo6Ko4Lv9jeBNNvrdHAf/GpBYGThOgZAr55gCQVgIkEwrbc1hIK+Mb/PjmA6z3Lgtl9G5jnKMHnQwA8q48lP0oCpeOVkWTrXoNUqj9Q9+dlPRsJaEC2gF/F/4wETB2GxlOEyWdg8i8p+R+JAKQ8AIYBEglMDXQo0FMCuLmjWQ0QQfD7qoDZUAC0JBiGCFwEETX550oCSiHAnnVLNG/f0vKMEfQr27bNvcwPQQBPdxyFqYEODfRIAuf7W8vef91rsPH5Xt3zW2r6oqktu4a4n8T/Ac8f9sDQieqU4DunymPVjOU/Qf4nSgCUBPi+gPHxccjlcsamIAQ/vaIK8DlHYLZyAAh6mxqweXife9/SYBgFQMMGsXvPAWoF/uaX6xP8mP0nnh+7/STvr8aTr3stkPij8t/HYCxd9u428MMQPDzTG/T+YU8KIlOCRzJdkM1mA+2/UvdflPJfzQRQLE5reQBTMlACP15NZwn4hAFJVAEkIsB+AKkKIHl+nzDh7oHVsGfdEjjX2qSuYWzPuiWwZ90Sd6uuw6Mj8OkQjnoGPm/l5abF/80vw0imq9rxFwH8peNd1T3+UtKPEIIo/RH4/CrZhMX7JyT/YyEAWg0wJQO556cmEYArDHCBP4lQIExY4FIHlAQ2r2kyWmphS7h+fM/YnQJ/2aLN5cfNL9cX+AXpj518EvipLVu0We0GDIC/EgJQMpCIoTqnb0g3Afylr04Eh3wgAZhIgJOB4P3DZP9nhQAAquVAqRowdCwvJwOfWqCy0FKWOnCa0ECHdYxY0grABnxJDbiUgE0VjGS6/Hfb1dCYo3n7xZ3VZho8nKMewZ9Ka808NvDT+H9l2zatKYjH/5wMJEKAibYg+G3yn/YLUPBzEpCIYKJNhRDU+4uz/2LK/uMKTQAmFYA/4CvptSIBSODHZBXmAuhA0Ru7VogkMBc5AAQ+JwEfMrDlDNBu7miukoAtC2+S9Y64XcX4qTSsbNume306o7/ewI8KoNLF5/L8uAGI7gfgCoATAYyltdeqY7roeXwWEsD2X9Lw421IADbvn6D8B4iBAHg14PDhw6IKMBHA151L1OYhTgLYMzDbVQAKbltegF4pEdjAbiKK2/tW6eO0TKD2rctzAFdAzoGveurrEfzNLzvBzxOA5/tbZfBj8w8CnocFtN1XOpTDpACu7qwmAD06C437DIj3l5J/Sch/gAgEAGCvBoyPj8OedUvEXAANA2iX2sWnFqhQgBIAbiTiSoCCNekcgOT9w5CAb48ADQlCgdwHsIaz+vj76WDO+jB/zy+B3UYEJmKwnswjkIAJ/N5kQNTDK+m1yvvT2n+cvf981UwAxaLeFGQrCfJdafTxxacWwI1dK9Q2YqoCMFfgSwBxA9+WDzCRAD4OWx24e6A8dCSdrt0ra4M2KPDx1N51r1UNk231QgCLO6Evsyk0+GshA9OBHLZwgCb+pOYiKwkQ8If1/nVBANLeAOwMlEqCF59aoDrTKAng0JCLTy2Aqb1LFQlMDXTA9Ftr1HtdKiAOIuB5AJv0NykBSRG4qgP8uZlXl5fVgAfw+WhsDnyNADjoKfipmY72niXwj2T8gG8DfTzgtxAANv+YeggmHHsNSOOQy/vXOvnHtCIRAIB9b8D4+Dhks1lrLoCSAN7j63y0OC0jYk5AAm/cKsCnEuACP1UCvglDUQ0YPLsT8Bp4+4Pgx375sJYUGSzuVHF8HJ7fhwSMp/E4SIB2/LlIIKAGiPe/nN+qZf5N3r9QKKjGn7oigGIx2BNgUgE4IRhJAAmgsH2hIgw+WBTbiflQEZPFrQJ45j9MCOAzV8DVL3D3wGo4399qBLoR8BL4K1l1o+cPY2xffi22bNFmaGl5JtDeG4UIage/BwlUvD833+5CuuNv85omL+9fLE7HlvzDFZkAAOw9AaOjo0YVcPGpBVDYvlAHf2X7qmm68I1dK7S9BHF7e1sOgIJfUgJhVICNDFzVg9v7VkFfZpMb8Kn+SljQXwU/HaZBhmSI9zZD8lCfXZu3R+vLbIL7h9ZHAn8UEihn+18E63l8jpN6tZ7/MGRAmoZGMl3K+9ti/7iTf7hqIgBXMnB0dNRYEaAKgBpVAZwEsGKAYUSSBCCpAZvkd5GASwWEIYOpgY5yydDk6fmVS/25kv1C9WLZos2hJH+YMMDk+eXDOMMRgQv8JjKg3v/R8EZoaXlGSX/f2L/uCMA0KAQrApIKwFDgYnuTRgB0iCjPCUwNdGj5gK87lyQKeFvGP6znr3XEmIkINj7fK3v7VL9+bwI+f85FFBhyRAC7ep4k+mr1+j7xf3TwyyTw8EyvvPPPhwjIlmSa+HPF/sVi/N4foEYCAKhNBdBQgBomBCUSuLFrhdZIlEQoIHUE+mb++TVsPiAqEZRP42Xg52YDuOvedqUhAW0s4tfK/SvptTA10BEb+H2z/TDRpg7hdJ7GayIBtu2XmtYRaAE/jvqiib+58P4AMRJAVBWAlQBuEllgbwDOu8MwIukcAI//qYf3UQIS6OM6IozbSKYyDddEAi4i8FECPgQhtBfHDfxQsn+ijYBePoHXSwlc3anlEXyJgD7/4GS3lviTev6TqvvzVTMBALhLgkNDp8U9ApwEpvYuVVeuAnDCEDYL0a7CJBOCpopA1Nh/Ns4GxNHmfZlNsKplwE4AYb2977Vyv2zRZujLbFLZ/STA7yIBPIZLO3HXSwUEScAGfF9SeCW9Vo36cvX8J+n9ARIgAE4CyGiHDx82lgWx3bewfSH85Y0ligS4aqBdgZgPwCGXSeYA+L1P3O/TBxA3EUiHf2KI0JfZpCsDA2DjuK5qGYCNz/fC5fxWuHtgtRW0cWb+AyTwQXkOPz9xNzIJCHF8mMdY829peaYuvD9ATAQA4FYBo6OjkE6njaEAJgUR/KgGbJuK8JCLuFVAVK9vywMkoQJcJGC6jmS6dELwIQPbfaofNj7fC32ZTTDct0WBGomIAz3pEKB0vItI/uCJu5wMvKxS9qvFYCwdkP6m036STPzRlQgBFItyLmDoWN6YEKRKAAlgau/SQFUAZwvQvQSoHpLKAZhyAlGVQFwkEGU6sWRTAx1wvr8V+jKbVA7BZiOZLtidPQI3dzTD5fzWAMhN17CePyxRqOYeTfLbwe+XF+jXdw1G8PxU+vPtvknv+LOt2AgAwE8F2BKCNNaf2rsU/vLGEjEfQBUA7i0whQI/ZstbisMSwI/ZBQq4pg7AsCSQVBgQxvvbiMDHTJ7dF/xhgG8jEJP3p+fsScdtB4/j9lACNXh/GCsfBz410KFJf2PTzyx6f4AECaBYNKsAW0KQgvwvbyyB8/2tgXwAbh+mewkwHJBCAfwaejqxr/yXZgP4hgS2MCAJ+R8F/C5C4IC/e2B1aBKwgZ+HBtL39vH+MNGmHa3lIgHu+W05ASSZqJ7/zqluBX7c7Wcq+01OTmrDPh8rAgAwzwrgKsCWEKRARyXA8wHYQORLAmFDBRfgbeGAVO+fjRxAlGsYzx8F/D45AF+VYfL+d6+lRPCbSIA+L1UHNDPU/H2z/tjwg1t9aexvqvkXi7Pj/QESJgBTRWBo6LQzIciTgxIJoOznLcVSh+CNXSu0M/F8iMAE/HrOAfheEdC+3l8CdNQwgL7f9jO4PgMm2nTwG0jApgJMSgDgRYBvVkf2/PRsP571tyX+ki778RU7AQD4dQcODZ2GzWvcKkDtC2hvgr+8sUTLB2AowJuIEOg8pkfw012IUljgC3xXLqCecwBhlIAE+LCenr/X9HP7hgF3r6XK4P97UyQSCD4fJIFaM/63Bttl8Fs6/orF5BN/dCVKAKaBIagCXL0BptZhSgKmTkIkBx8SKGxfaM0P2EIA6TWT508K/GGUgI/nl6S/j3d2EYSNsHxUQOl4F/z1bBnsCHoK/rvXKuBGAvDIB1SBr5MAz/qHVQJ3TpW7/WjWv14Sf3QlQgAAbhWAJJDJZLxDASr96Xts7cS8AkBBz69oNnBLSUFXLmC2VEASnh9JI4zcp+/Bfy8aPr5/aL26+qiAmXdXKq/PjRNBmHxAUA28qA7piBrzY8lPivttNf9icXa9P8AsEACqgGJRP0kIJdDQsTy0tDwTigBsnYS0mehie5NIAibg8w1JqCBMMb8pYWiaFsRtLsOBsErAFhZIkl4ixps7mrV/uy/4fYCP4UCAADxzAsr7k7jfF/DcaNyvzfgj7b58xn+xOPveHyBBAgCQy4KTk5MBFXD48GFng5BvspDuKaDzBZAEfswuUGcOmMBPtyXjaHJXOOAKBeh9ksCPqgh8AW+K49Hwd4VHwCPo8SopARNB/fVsGeh49SYCixLQM/9MCbDTeaMoAKz3o/QfeOMd81Zfg/R/4ghACwWuXQmGAsfykM1mQ+UDbCRg6iSkOQE+kchkNMxwlQtN+wXmAvwuQgibA3AZgp5f7x4ozzXEK6oD08818+5K+OvZlDf4AyQgJQU9S4NRwE/fg/V+Gvcbe/1Z1h8P+Lx3716SkAysRAkAwG+CMFYFwpQGXYlCSgI0aYgk8GNWnkVgIwGqBlzAx+clNTCXJJCE3dzRDDd3NMONXSucCgDJgCsACnwTAYRRAqJZSMCU9Atjm9c0yXG/I+s/F9IfV+IEAOAeIEpDgc1rmmomAaoEsJ2YJw2xRdgEehpG0FACk5C2SgEnBAn0TwIJINCpIQkg+GdeXa5AjyQw8+pymBroMAKfg99HBSD4nTkBiQQmwif9uGHSj0p/W6//XEt/XLNKALYOQU4CtRIA7R0QOwkr3twVAkj5BKomfJRAEqVAUww+V8DnBMDDAAp+PAFaAn6tZGANBSQVMFEb+HGwZ9i4f7YbfkxrVggAwN4hyKsCuVwulqQgzg9AEuA7CxHEfDQZHUzCn5M2JpmShLx6gP0H+PVz7cGjAh//DXjlhl9HPT8m/6jHN3n/WpSAszpAKgMw0ab1+Uex8/2tkFrYEoj7pZLfXDb8mNasEQCAfygwNHQa+jKbYiGBzxZU9w3wTkJKFCjtTSTgmlZEiUCaKYh2c0ezSCKUHCh46sGwakLNRgCUCDAM+8sbS+CvZ1OBqw8J1BISmJSAb7nPZjzjL4G/HuN+uuaEAHxDgUwmE0tlgCcHbTkGqgZcJGA680DafkyVgYkIXD//bCoHlPLYVk33UdhI4MauFRroOfhn3l0ZAP+skUDF+9+9loIHJ7tjA7803sun5DfvCADAr00YqwIDb7wD6XQ6VhL48rlFMLV3qfNr+ZxCOqqMTiyykcnXnUsCLcZcHeAmpbD/FlQNcZECBTw1H/Dz3wsHPxoFfxQSCFsVkEiAxvxR5T+W+zDpxyf72sBfLNaH9Mc16wQAYJ8bwPMBSAJxVAYoEWDs7/panFBESQArC1KZ0fb9pG3KVBkg2KL+u+jR6xywHLgIcPzZ6XHtklEikBQSBb+NBGpVArWUBmGiDe4fWh8AdBgiwB5/LPe5+vzrMe6na04JwGevAJJAS8szsZIAAtP36/gfOv+jlxKMps/6unNJIEzgygC9sc/PKA1PpVe+eYqqIU4cnAToxilblQR/F+f7W43gjyMXEKVJ6O61cp2fAj2K9zeB3zfpN9clP2nNCQEAmEMBEwnkcrlESCAsYZg83vn+VnV+YdjPRLDZTj5GINrUBgc+vdqATw1JACsePt2SnARwklNUEgjTG+BDBnGD35XxRwLA1vdisb7ifrrmjAAA/PIBNCmYlBIITQTtTarHQJK9tch4DmZMNuJnUvDi+Ym+n4VfjyRAz1lEw0NaOQmYdlyi8RyJKxRw5QTiUgJ0ZiAHvy8ROMHPNvnUe9xP15wTgCsfQJOChw8fhlwuF1u3YBwgxaQiVQIIhjBZ/tn4WTmpSCRAwwAfEpB6JVxKAIEv5QHwcRTw03ta45fA70sCtYC/Xpp9bGtOCQBAzgdIY8SQBOolHJAARtuP41QDcZOASwV83blETVv2DQds1ZKoKsAVCpiIgEp+17VW8Pts8qlX8APUAQEAWPoDJBI4lldKIM4SYZxGjz5XexHa6+Pn9FUCUXMClAgkZeRbEfBRApQI8F4aGsrBnhT4H4ekH191QQAA/k1ClAQwJ1CPJKAAVznE1LSfYLbBbyMBCfimMMClBOjVtzRIScC3NEhJwDY5OEwOAJt8JPC7av31nvTjq24IAMC8X0CsDFQahbBPIK624aRtrvMCroSglBMwJQZ9wwEEt6tM+NezKZjauzS0ErCdFxA2BzA10AGphS1Gz+9T66fgr/dVdwRgSgqayoM0HHhcSKAejBIAElOYMABzBL6lQd9cgFQmtCkB1+hw3zDgwclubWNPHOCvZ8+Pq64IACAcCfCcQCaTqZsKweNgvklBSgI0MRgmFDCVTH17A7gSsE0OjqIERjJdTvDzbD8F/+OQ8ZdW3REAgL0ywM8XQBLA6kAmk6m7CkE9my8J0DCg1sqAjxKQqgNICD4jyn3A/+BkN5SOd8Er6bXaxp4wnr8eN/iEWXVJAADu8qAtMZjNZus+OVgvZiMAbECiRIAKIIoSoIQQRQncPeB3ipBNBVASuDXYDpvXNFnBb8v2Pw6NPq5VtwQA4K8EpGYhTA42QoJwRPDZAns+AGN/mgNw5QNqyQnMvLtSTVFyDTV1kQAFP47upsk+n2z/kwR+gDonAIDaSaAREviBn5KAKx+ACgCBj/e+4EcV4NovgOCnh4iYSCBMMhAlvwn888Hz46p7AgCITgJIBNg52KgSuInAVwlIRODbJOTaPsxPEkKrVQFMDXSIkn++gh/gMSEAgGgkgFuJ8T83nU431EAIEvCpDPBj2m1KwJQQPN/fClN7l8LtfavUKDQEP04PrpUEcHAnen0KfvwbwTySLdtfLD6+CT9pPTYEAOBHAqZeAUoEqAYaRBAEvy8JmBqEfJUAVQP0HAFphPjdA6th+q01kQjg/qH1Ackvgd+0pZeDv1h8Mjw/rseKAADCkwDPC3A10KgUyETAycAWBlAlwKsDNhK4sWuFGkVGpwff3NGsThBC4PuoAJ4HoIk+OsTDVOaz7eorFp8sz4/rsSMAXJQEpA1EppCAE0FLyzOweU1TgwgsJEBnD/iQgK0/wHaWAJIAP0x05tXlWiLQpQRorC95fSnen4/gB3iMCYB3DLp6BaT2YZR/WCmI40CSJ8nCbB92kYDPGQLo+W/sWqFyAPgcgh/JwAR+7OijwJc29FiTffME/ACPMQEAVEmgVCqJJOAKCUxhQSM/EI4EMBeA1QA+lNR1hgAlAX6uIBICJgZNpwmj3Pfx+ij55zv4AR5zAgDQlUDYvICkBrLZbIMIGAF8tiAYBkhJQT5INAwJ0LME6aGi6PG5EsDr+f5W2LymKeD1pcYem+THGX7SMI8nFfwATwAB4OIkQPMCk5OT5pCAqAFaKWgQQZAEuBLgwLedIxCGBGg+AMHPS4M3dq0Q4/y4vP7jMMwjjvXEEACATALFoq4GJr741qoGOAlQIpjPbcV0mjCfG2g6RyAMAbgSgQj+kUyXN/DR61tLfA7J/ySDH+AJIwAAj5DAkCDkuQFKBJgoxGRhamELnGt98smAVwIQ/PjYRABhVQCCn54szI8X9wE+r+vToZ2m+v58ivel9cQRAC4fNSDlBujOQik/kM1mFRFQVfAkkIGpFZgSAEp/rgRcKgCBbwsBsC8AE4FTAx2wZ90SMbnHgU/J2hXr2yT/fAI/wBNMAAAeJOBKEloUARIBhgePc66AN/5wwEtXVxjAVQAefOKTC0Bvj4k9F/C1br4K8Gmsb/P6xeL0vJL8fD3RBAAghwQ+akDKD/CyIVcF6XQaUgtbILWwRZFBvRMCB75ECibw08c+KsAE/us9y2Ak0wV71i2B1MIWzdtLmX1bnG8EPvP6xeL8i/el9cQTAC5KAqbcgJMIHIoAiYAqg9TCFtVpWK9kwEmAA990LzUChckF7Fm3RHl62rJr8vaSx3fJfZfXn2+Sn695QwAAnmoggiKQKgf4x8uVAQ0V6okQpJHhEhlIyUCfisDF9iZN2ts8vc3bS1KfAr/h9cOteUUAuEyVgmIxvCKIQgaoDGi4gAphrkhBCgV8FQCfD3Cutax4UNJLgJfM5u15I48P8E0Z/vnu9emalwQAECSBqEQgqQL6R8vJwBYqcFKYLWKQwM89P+0DQLBToFPP7gt4WybfJPOjAL/h9c1r3hIALhsR4LhniQjoZGKXKuBk4CIEEylwckCCQLvYXiULvHcBPzAItL1J+0z8PhLAJbCHAbwk7ynoeXwfBvjFYsPr+6x5TwC4bPmBYtGsCKyqwEMZIBmYQgaRGBZ3WgkiCcNSpy/QTWCXQM8n8uDvjYIer1pyLwTwG+CXV4MA2ApDBBNffBsIDy5duqT90ZrIIAwhcKXAyYETBO1N4IbkYTL8HB+Am4DuA3atfFc514F6epO3dwG/IffDrQYBGJYPEfiqAhsZ2JKIYYjBRBKcLEyPbVeTcZCbwC7KehbTc08vgr7h8WNfDQJwLFOOwJgnqOw1oINKeZehlECUFALvNzApBhNJULKQiIM/Z3q/9H0kj849OyU47d9JEnk2Ty95+wbw410NAvBcLiIoFmVVwJWBTR1IKkFSCkgMNtVge87nNZMSwe/LgR7w7B4enpKjCfQumd8Afm2rQQAhl0QEPmTRpst5AAABr0lEQVSAMwmkUEFKJHJiUKRAwCURg80k0ErPSR4cvbhWkiNxuxS/+4D90qVLKpfCQd8AfvKrQQA1LJsqsCoDMpvARyFwUpDIIUASLLSgisL4GvPc1INzgJtA7uPdTV7eB/QN4Me7GgQQw6KzCX3JIEAIQv5AIoYwBGEiDBeQTZ/hC/IA0FkCz+Tli8UG6Gd7NQgg5uVDBmEIwaYUTMaBycEqEYn0mvSZJpBLmXqXhy8Wp7XfiQn0DeAntxoEkOAykYGNEIpFD1IwkAMliTCEIYGa3qsY3QJwCegc7MWiGfD4O2qAfnZXgwBmaXEycCkETgrF4nQAXJOTk05Axm3Sz8B/zmJxOvBv4QTY8PL1sRoEMEfLhxBMSkEiBzQEpATUsEY/jxv9WXzB3gB8/a0GAdTRouCQwgYfgrARhs/VZfR7+wK9Afj6XQ0CqPMlAUlSDGGMA9gH0BLAG0B//FeDAB7jJYHPRBQcsC4Q26yxnpzVIIDGaqx5vBoE0FiNNY9XgwAaq7Hm8WoQQGM11jxeDQJorMaax6tBAI3VWPN4NQigsRprHq8GATRWY83j9f8BXw26zxg/U0gAAAAASUVORK5CYII=" width="256" height="256"><br>
-<div id="cpu">CPU 1x Gaussian blur</div>
-<div id="cpustat"></div>
-<canvas id="2d" width="256" height="256"></canvas>
-<div id="gpu">GPU 1000x Gaussian blur</div>
-<div id="gpustat"></div>
-<canvas id="gl" width="256" height="256"></canvas><br>
-</body></html>
deleted file mode 100644
--- a/dom/canvas/test/webgl-conf/checkout/conformance/more/performance/bandwidth.html
+++ /dev/null
@@ -1,238 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<meta charset="utf-8">
-<!--
-
-/*
-** Copyright (c) 2012 The Khronos Group Inc.
-**
-** Permission is hereby granted, free of charge, to any person obtaining a
-** copy of this software and/or associated documentation files (the
-** "Materials"), to deal in the Materials without restriction, including
-** without limitation the rights to use, copy, modify, merge, publish,
-** distribute, sublicense, and/or sell copies of the Materials, and to
-** permit persons to whom the Materials are furnished to do so, subject to
-** the following conditions:
-**
-** The above copyright notice and this permission notice shall be included
-** in all copies or substantial portions of the Materials.
-**
-** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
-*/
-
--->
-
-<link rel="stylesheet" type="text/css" href="../unit.css" />
-<script type="application/javascript" src="../unit.js"></script>
-<script type="application/javascript" src="../util.js"></script>
-<script type="application/javascript">
-
-Tests.autorun = false;
-Tests.message = "This might take a second or two. Take the upload numbers with a dose of salt, as there's no drawing code using the data.";
-
-Tests.startUnit = function () {
-  var canvas = document.getElementById('gl');
-  var gl = getGLContext(canvas);
-  return [gl];
-}
-
-Tests.testTexImage2D = function(gl) {
-    var tex = gl.createTexture();
-    var texArr = new Array(256*256*4);
-    var bufData = new Array(256*256*4);
-    for (var i=0; i<texArr.length; i++) texArr[i] = 0;
-    for (var i=0; i<bufData.length; i++) bufData[i] = 0.5;
-    gl.bindTexture(gl.TEXTURE_2D, tex);
-    time("texImage2D", function() {
-        for (var i=0; i<100; i++)
-            gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 256, 256, 0, gl.RGBA, gl.UNSIGNED_BYTE, texArr);
-    });
-    time("texImage2D", function() {
-        for (var i=0; i<100; i++)
-            gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 256, 256, 0, gl.RGBA, gl.UNSIGNED_BYTE, texArr);
-    });
-    time("texSubImage2D", function() {
-        for (var i=0; i<100; i++)
-            gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 256, 256, gl.RGBA, gl.UNSIGNED_BYTE, texArr);
-    });
-    var img = document.getElementById('logo');
-    time("texImage2DHTML", function() {
-        for (var i=0; i<100; i++)
-            gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
-    });
-    time("texSubImage2DHTML", function() {
-        for (var i=0; i<100; i++)
-            gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, img);
-    });
-    var bufs = [gl.createBuffer(), gl.createBuffer()];
-    var buf = bufs[0], buf2 = bufs[1];
-    gl.bindBuffer(gl.ARRAY_BUFFER, buf);
-    var bufArr = new Float32Array(bufData);
-    time("bufferDataNoChange", function() {
-        for (var i=0; i<100; i++)
-            gl.bufferData(gl.ARRAY_BUFFER, bufArr, gl.STATIC_DRAW);
-    });
-    time("bufferSubDataNoChange", function() {
-        for (var i=0; i<100; i++)
-            gl.bufferSubData(gl.ARRAY_BUFFER, 0, bufArr);
-    });
-    time("bufferData", function() {
-        var bufArr = new Float32Array(bufData);
-        for (var i=0; i<25; i++)
-            gl.bufferData(gl.ARRAY_BUFFER, bufArr, gl.STATIC_DRAW);
-    });
-    time("bufferSubData", function() {
-        var bufArr = new Float32Array(bufData);
-        for (var i=0; i<25; i++)
-            gl.bufferSubData(gl.ARRAY_BUFFER, 0, bufArr);
-    });
-    var sh = new Shader(gl, 'vert-v', 'frag-v');
-    gl.disable(gl.DEPTH_TEST);
-    sh.use();
-    var v = sh.attrib('Vertex');
-    for (var i=0; i<16; i++)
-        gl.disableVertexAttribArray(i);
-    gl.enableVertexAttribArray(v);
-    gl.vertexAttribPointer(v, 4, gl.FLOAT, false, 0, 0);
-    time("verticeDraw", function() {
-        for (var i=0; i<100; i++)
-            gl.drawArrays(gl.TRIANGLES, 0, 256*256);
-        gl.readPixels(0,0,1,1,gl.RGBA, gl.UNSIGNED_BYTE);
-    });
-    gl.bindBuffer(gl.ARRAY_BUFFER, buf2);
-    gl.bufferData(gl.ARRAY_BUFFER, bufArr, gl.STATIC_DRAW);
-    time("verticeDrawC", function() {
-        for (var i=0; i<100; i++) {
-            gl.bindBuffer(gl.ARRAY_BUFFER, (i % 2 == 0) ? buf : buf2);
-            gl.drawArrays(gl.TRIANGLES, 0, 256*256);
-        }
-        gl.readPixels(0,0,1,1,gl.RGBA, gl.UNSIGNED_BYTE);
-    });
-    // Drawing arrays with vertexAttribPointer seems to have been removed from WebGL.
-/*    gl.bindBuffer(gl.ARRAY_BUFFER, null);
-    gl.vertexAttribPointer(v, 4, gl.FLOAT, false, 0, bufArr);
-    time("verticeDrawVA", function() {
-        for (var i=0; i<100; i++)
-            gl.drawArrays(gl.TRIANGLES, 0, 256*256);
-        gl.readPixels(0,0,1,1,gl.RGBA, gl.UNSIGNED_BYTE);
-    });
-    time("verticeDrawVAC", function() {
-        for (var i=0; i<100; i++) {
-            gl.vertexAttribPointer(v, 4, gl.FLOAT, false, 0, bufArr);
-            gl.drawArrays(gl.TRIANGLES, 0, 256*256);
-        }
-        gl.readPixels(0,0,1,1,gl.RGBA, gl.UNSIGNED_BYTE);
-    });*/
-    sh.destroy();
-    sh = new Filter(gl, 'vert-t', 'frag-t');
-    sh.apply();
-    time("textureDraw", function() {
-        for (var i=0; i<1000; i++)
-            gl.drawArrays(gl.TRIANGLES, 0, 6);
-        gl.readPixels(0,0,1,1,gl.RGBA, gl.UNSIGNED_BYTE);
-    });
-    sh.destroy();
-    time("readPixels", function() {
-        for (var i=0; i<100; i++)
-            gl.readPixels(0, 0, 256, 256, gl.RGBA, gl.UNSIGNED_BYTE);
-    });
-    time("getImageData", function() {
-        for (var i=0; i<100; i++)
-            gl.getImageData(0, 0, 256, 256);
-    });
-    gl.bindTexture(gl.TEXTURE_2D, null);
-    gl.bindBuffer(gl.ARRAY_BUFFER, null);
-    bufs.forEach(function(buf){ gl.deleteBuffer(buf) });
-    gl.deleteTexture(tex);
-}
-
-
-Tests.endUnit = function(gl) {
-}
-
-</script>
-<script id="vert-v" type="x-shader/x-vertex">
-
-  attribute vec4 Vertex;
-  void main()
-  {
-    gl_Position = Vertex;
-  }
-</script>
-<script id="frag-v" type="x-shader/x-fragment">
-
-  precision mediump float;
-
-  void main()
-  {
-    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
-  }
-</script>
-<script id="vert-t" type="x-shader/x-vertex">
-
-
-  attribute vec3 Vertex;
-  attribute vec2 Tex;
-  varying vec2 texCoord0;
-  void main()
-  {
-    gl_Position = vec4(Vertex, 1.0);
-    texCoord0 = Tex;
-  }
-</script>
-<script id="frag-t" type="x-shader/x-fragment">
-
-  precision mediump float;
-
-  uniform sampler2D Texture;
-
-  varying vec2 texCoord0;
-  void main()
-  {
-    gl_FragColor = texture2D(Texture, texCoord0);
-  }
-</script>
-
-<style>canvas{ position:absolute; }
-img{ display:none; }</style>
-</head><body>
-<h3>100x 256x256x4 texture upload with texImage2D (26.2MB total)</h3>
-<p id="texImage2D"></p>
-<h3>100x 256x256x4 texture upload with texSubImage2D (26.2MB total)</h3>
-<p id="texSubImage2D"></p>
-<h3>100x 256x256x4 texture upload with texImage2DHTML (26.2MB total)</h3>
-<p id="texImage2DHTML"></p>
-<h3>100x 256x256x4 texture upload with texSubImage2DHTML (26.2MB total)</h3>
-<p id="texSubImage2DHTML"></p>
-<h3>100x 256x256x4 readPixels (26.2MB total)</h3>
-<p id="readPixels"></p>
-<h3>100x 256x256x4 getImageData (26.2MB total)</h3>
-<p id="getImageData"></p>
-<h3>25x 256x256x4 float bufferData (6.6MB total)</h3>
-<p id="bufferData"></p>
-<h3>25x 256x256x4 float bufferSubData (6.6MB total)</h3>
-<p id="bufferSubData"></p>
-<h3>100x 256x256x4 float bufferData, reuse Float32Array (26.2MB total)</h3>
-<p id="bufferDataNoChange"></p>
-<h3>100x 256x256x4 float bufferSubData, reuse Float32Array (26.2MB total)</h3>
-<p id="bufferSubDataNoChange"></p>
-<h3>100x 256x256 vert VBO draw</h3>
-<p id="verticeDraw"></p>
-<h3>100x 256x256 vert VBO draw, change VBO after each draw</h3>
-<p id="verticeDrawC"></p>
-<!--<h3>100x 256x256 vert vertex array draw</h3>
-<p id="verticeDrawVA"></p>
-<h3>100x 256x256 vert vertex array draw, change array after each draw</h3>
-<p id="verticeDrawVAC"></p>-->
-<h3>1000x 256x256 texture draw</h3>
-<p id="textureDraw"></p>
-<canvas id="gl" width="256" height="256"></canvas>
-<img id="logo" src="data:image/png;base64,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" width="256" height="256">
-</body></html>
deleted file mode 100644
--- a/dom/canvas/test/webgl-conf/checkout/conformance/more/performance/jsGCPause.html
+++ /dev/null
@@ -1,85 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<meta charset="utf-8">
-<!--
-
-/*
-** Copyright (c) 2012 The Khronos Group Inc.
-**
-** Permission is hereby granted, free of charge, to any person obtaining a
-** copy of this software and/or associated documentation files (the
-** "Materials"), to deal in the Materials without restriction, including
-** without limitation the rights to use, copy, modify, merge, publish,
-** distribute, sublicense, and/or sell copies of the Materials, and to
-** permit persons to whom the Materials are furnished to do so, subject to
-** the following conditions:
-**
-** The above copyright notice and this permission notice shall be included
-** in all copies or substantial portions of the Materials.
-**
-** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
-*/
-
--->
-<link rel="stylesheet" type="text/css" href="../unit.css" />
-<script type="application/javascript" src="../unit.js"></script>
-<script type="application/javascript" src="../util.js"></script>
-<script type="application/javascript">
-
-Tests.autorun = false;
-
-Tests.testInterval = function() {
-    document.getElementById('dtMax').textContent = "Running, please wait...";
-    setTimeout(function() {
-        var t0 = new Date().getTime();
-        var t = t0;
-        var dtMax = 0;
-        var frames = [];
-        var iv;
-        iv = setInterval(function() {
-            if (t > t0 + 10000) {
-                var hist = [];
-                var dtMed = 0, maxi = [0, 0];
-                for (var i=0; i<dtMax; i++) hist[i] = 0;
-                for (var i=0; i<frames.length; i++)
-                    hist[frames[i]]++;
-                for (var i=0; i<hist.length; i++)
-                    if (hist[i] > maxi[1]) maxi = [i, hist[i]];
-                dtMed = maxi[0];
-                var dtAvg = frames.reduce(function(s,i){return s + i;})/frames.length;
-                document.getElementById('dtMax').textContent = "Longest frame: " + dtMax + " ms. Average frame: " + Math.floor(dtAvg*100)*0.01 + " ms. Median frame: " + dtMed + " ms.";
-                clearInterval(iv);
-                var c = document.getElementById('dtCanvas');
-                c.width = frames.length;
-                c.height = dtMax;
-                var ctx = c.getContext('2d');
-                for (var i=0; i<frames.length; i++)
-                    ctx.fillRect(i,0,1,frames[i]);
-            }
-            var t1 = new Date().getTime();
-            if (t1-t > dtMax) dtMax = t1-t;
-            frames.push(t1-t);
-            t = t1;
-            var rot = Matrix.rotate((t/400) % (2*Math.PI), [0, 1+(t%1000), 1]);
-            var trans = Matrix.translate3(0, Math.cos(t/1000)*1, Math.sin(t/1000)*3);
-            for (var i=0; i<200; i++)
-                var mat = Matrix.mul4x4(rot, trans);
-        }, 16);
-    }, 0);
-}
-
-</script>
-<style>canvas{ position:absolute; }</style>
-</head><body>
-<h3>10 seconds of 60fps 200x mul4x4, frame time statistics</h3>
-<p id="dtMax"></p>
-<canvas id="dtCanvas"></canvas>
-</body></html>
-
deleted file mode 100644
--- a/dom/canvas/test/webgl-conf/checkout/conformance/more/performance/jsMatrixMult.html
+++ /dev/null
@@ -1,77 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<meta charset="utf-8">
-<!--
-
-/*
-** Copyright (c) 2012 The Khronos Group Inc.
-**
-** Permission is hereby granted, free of charge, to any person obtaining a
-** copy of this software and/or associated documentation files (the
-** "Materials"), to deal in the Materials without restriction, including
-** without limitation the rights to use, copy, modify, merge, publish,
-** distribute, sublicense, and/or sell copies of the Materials, and to
-** permit persons to whom the Materials are furnished to do so, subject to
-** the following conditions:
-**
-** The above copyright notice and this permission notice shall be included
-** in all copies or substantial portions of the Materials.
-**
-** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
-*/
-
--->
-<link rel="stylesheet" type="text/css" href="../unit.css" />
-<script type="application/javascript" src="../unit.js"></script>
-<script type="application/javascript" src="../util.js"></script>
-<script type="application/javascript">
-
-Tests.autorun = false;
-Tests.message = "This might take a second or two (or ten)";
-
-Tests.testMatrixMultiply = function() {
-    time("testMatrixMultiply", function() {
-        var mat = Matrix.identity;
-        for (var i=0; i<1000000; i++)
-            Matrix.mul4x4(mat, mat);
-    });
-}
-Tests.testTransformStack = function() {
-    time("testTransformStack", function() {
-        var j = 0;
-        for (var i=0; i<1000; i++) {
-            var t = new Date().getTime();
-            var pmat = Matrix.perspective(30, 600/400, 1, 100+(t%1000));
-            var look = Matrix.lookAt([4,-1,8], [-0.2,0+(t%1000),0], [0,1,0]);
-            var rot = Matrix.rotate((t/400) % (2*Math.PI), [0, 1+(t%1000), 1]);
-            var trans = Matrix.translate3(0, Math.cos(t/1000)*1, Math.sin(t/1000)*3);
-            var sca = Matrix.scale1(0.6+(t%1000));
-            var vmat = Matrix.identity;
-            vmat = Matrix.mul4x4(vmat, pmat);
-            vmat = Matrix.mul4x4(vmat, look);
-            vmat = Matrix.mul4x4(vmat, trans);
-            vmat = Matrix.mul4x4(vmat, sca);
-            vmat = Matrix.mul4x4(vmat, rot);
-            j += vmat.length;
-        }
-        Tests.j = j;
-    });
-}
-
-
-</script>
-<style>canvas{ position:absolute; }</style>
-</head><body>
-<h3>1000000x JavaScript Matrix.mul4x4</h3>
-<p id="testMatrixMultiply"></p>
-<h3>1000x JavaScript transform stack</h3>
-<p id="testTransformStack"></p>
-</body></html>
-
deleted file mode 100644
--- a/dom/canvas/test/webgl-conf/checkout/conformance/more/performance/jsToGLOverhead.html
+++ /dev/null
@@ -1,67 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<meta charset="utf-8">
-<!--
-
-/*
-** Copyright (c) 2012 The Khronos Group Inc.
-**
-** Permission is hereby granted, free of charge, to any person obtaining a
-** copy of this software and/or associated documentation files (the
-** "Materials"), to deal in the Materials without restriction, including
-** without limitation the rights to use, copy, modify, merge, publish,
-** distribute, sublicense, and/or sell copies of the Materials, and to
-** permit persons to whom the Materials are furnished to do so, subject to
-** the following conditions:
-**
-** The above copyright notice and this permission notice shall be included
-** in all copies or substantial portions of the Materials.
-**
-** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
-*/
-
--->
-<link rel="stylesheet" type="text/css" href="../unit.css" />
-<script type="application/javascript" src="../unit.js"></script>
-<script type="application/javascript" src="../util.js"></script>
-<script type="application/javascript">
-
-Tests.autorun = false;
-Tests.message = "This might take a second or two";
-
-Tests.testGLOverhead = function() {
-    var gl = document.getElementById("gl").getContext(GL_CONTEXT_ID);
-    var fakeGl = {getError: function(){ return 0; }};
-    time("testGLOverhead", function() {
-        for (var i=0; i<1000000; i++)
-            gl.getError();
-    });
-    time("testJSOverhead", function() {
-        for (var i=0; i<1000000; i++)
-            fakeGl.getError();
-    });
-    time("testLoopOverhead", function() {
-        for (var i=0; i<1000000;)
-            i++;
-    });
-}
-
-</script>
-<style>canvas{ position:absolute; }</style>
-</head><body>
-<canvas id="gl" width="16" height="16"></canvas>
-<h3>1000000x gl.getError() (measuring JS->GL call overhead)</h3>
-<p id="testGLOverhead"></p>
-<h3>1000000x fakeGl.getError() (measuring JS->JS call overhead)</h3>
-<p id="testJSOverhead"></p>
-<h3>1000000x i++ (measuring loop overhead)</h3>
-<p id="testLoopOverhead"></p>
-</body></html>
-
--- a/dom/canvas/test/webgl-conf/checkout/conformance/more/util.js
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/more/util.js
@@ -1092,16 +1092,34 @@ function assertThrowNoGLError(gl, name, 
         getGLErrorAsString(gl, glErr), name, f);
       return false;
     }
   }
   testPassed("assertThrowNoGLError", name, f);
   return true;
 }
 
+function assertThrows(gl, shouldThrow, info, func) {
+  var didThrow = false;
+  try {
+    func();
+  } catch (e) {
+    var didGLError = (e instanceof GLError);
+    if (!didGLError) {
+      didThrow = true;
+    }
+  }
+
+  var text = shouldThrow ? "Should throw: "
+                         : "Should not throw: ";
+  var func = (didThrow == shouldThrow) ? testPassed : testFailed;
+
+  func(text + info);
+}
+
 Quad = {
   vertices : [
     -1,-1,0,
     1,-1,0,
     -1,1,0,
     1,-1,0,
     1,1,0,
     -1,1,0
--- a/dom/canvas/test/webgl-conf/checkout/conformance/offscreencanvas/context-attribute-preserve-drawing-buffer.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/offscreencanvas/context-attribute-preserve-drawing-buffer.html
@@ -35,42 +35,76 @@
 <script src="../../js/tests/canvas-tests-utils.js"></script>
 </head>
 <body>
 <div id="description"></div>
 <div id="console"></div>
 <script>
 "use strict";
 description("This test checks whether OffscreenCanvas webgl context honors the preserveDrawingBuffer flag.");
-
-function getPixelsFromOffscreenWebgl(preserveFlag) {
-  var canvas = document.createElement("canvas");
-  var offscreenCanvas = transferredOffscreenCanvasCreation(canvas, 10, 10);
-  var gl = offscreenCanvas.getContext("webgl", {preserveDrawingBuffer: preserveFlag});
+const wtu = WebGLTestUtils;
+const pixels = new Uint8Array(4);
 
-  // Draw some color on gl and commit
-  gl.clearColor(1, 0, 1, 1);
-  gl.clear(gl.COLOR_BUFFER_BIT);
-  gl.commit();
-
-  var pixels = new Uint8Array(4);
-  gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
-  return pixels;
+function checkPixels(color) {
+  return (color[0] === pixels[0]) &&
+    (color[1] === pixels[1]) &&
+    (color[2] === pixels[2]) &&
+    (color[3] === pixels[3]);
 }
 
-if (!window.OffscreenCanvas) {
-    testPassed("No OffscreenCanvas support");
-} else {
-    // Test if OffscreenCanvas.webgl retains context if preserveDrawingBuffer is true.
-    var pixelsPreserve = getPixelsFromOffscreenWebgl(true);
-    shouldBe(pixelsPreserve, [255,0,255,255]);
+const nextFrame = () => new Promise(r => requestAnimationFrame(r));
+
+async function getPixelsFromOffscreenWebgl(preserveFlag, color, msg) {
+  const canvas = document.createElement("canvas");
+  const offscreenCanvas = transferredOffscreenCanvasCreation(canvas, 10, 10);
+  const gl = offscreenCanvas.getContext("webgl", {preserveDrawingBuffer: preserveFlag});
+
+  // Draw some color on gl
+  gl.clearColor(1, 0, 1, 1);
+  gl.clear(gl.COLOR_BUFFER_BIT);
+
+  let t;
+  const t0 = await nextFrame();
+  for (;;) {
+    t = await nextFrame();
 
-    // Test if OffscreenCanvas.webgl loses context if presereDrawingbuffer is false.
-    var pixelsNoPreserve = getPixelsFromOffscreenWebgl(false);
-    shouldBe(pixelsNoPreserve, [0,0,0,0]);
+    gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
+    if (preserveFlag) {
+      if (!checkPixels(color)) {
+        testFailed(msg + '\nexpected: ' + color.toString() + ' was ' + pixels.toString());
+        return;
+      }
+    } else {
+      if (checkPixels(color)) {
+        testPassed(msg);
+        return;
+      }
+    }
+
+    // Keep checking until it takes up to a certain time
+    if (t > t0 + 500) {
+      break;
+    }
+  }
+
+  if (preserveFlag) {
+    testPassed(msg);
+  } else {
+    testFailed(msg + '\nexpected: ' + color.toString() + ' was ' + pixels.toString());
+  }
 }
 
-var successfullyParsed = true;
+(async () => {
+  if (!window.OffscreenCanvas) {
+      testPassed("No OffscreenCanvas support");
+  } else {
+    // Test if OffscreenCanvas.webgl retains contents if preserveDrawingBuffer is true.
+    await getPixelsFromOffscreenWebgl(true, [255,0,255,255], "should be preserved");
+
+    // Test if OffscreenCanvas.webgl loses contents if preserveDrawingBuffer is false.
+    await getPixelsFromOffscreenWebgl(false, [0, 0, 0, 0], "should not be preserved");
+    finishTest();
+  }
+})();
 
 </script>
-<script src="../../js/js-test-post.js"></script>
 </body>
 </html>
--- a/dom/canvas/test/webgl-conf/checkout/conformance/offscreencanvas/offscreencanvas-resize.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/offscreencanvas/offscreencanvas-resize.html
@@ -23,28 +23,28 @@
 ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
 */
 
 -->
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8">
-<title>Resizing Test for OffscreenCanvas</title>
+<title>Resizing Test for OffscreenCanvas commit()</title>
 <link rel="stylesheet" href="../../resources/js-test-style.css"/>
 <script src="../../js/js-test-pre.js"></script>
 <script src="../../js/webgl-test-utils.js"></script>
 <script src="../../js/tests/canvas-tests-utils.js"></script>
 </head>
 <body>
 <div id="description"></div>
 <div id="console"></div>
 <script>
 "use strict";
-description("This test ensures that the OffscreenCanvas context returns the correct image size after resizing.");
+description("This test ensures that the OffscreenCanvas context returns the correct image size after resizing and calling commit().");
 
 function testResizeOnNewOffscreenCanvas() {
   var canvas = new OffscreenCanvas(10, 20);
   canvas.getContext("webgl");
   canvas.width = 30;
   canvas.height = 40;
   assertWidthAndHeight(canvas, "canvas", 30, 40);
   var imagebitmap = canvas.transferToImageBitmap();
@@ -97,15 +97,18 @@ function testResizeOnTransferredOffscree
       }
     });
   }, 0);
 }
 
 if (!window.OffscreenCanvas) {
   testPassed("No OffscreenCanvas support");
   finishTest();
+} else if (!new OffscreenCanvas(10, 20).getContext("webgl").commit) {
+  testPassed("commit() not supported");
+  finishTest();
 } else {
   testResizeOnNewOffscreenCanvas();
   testResizeOnTransferredOffscreenCanvas();
 }
 </script>
 </body>
 </html>
--- a/dom/canvas/test/webgl-conf/checkout/conformance/reading/fbo-remains-unchanged-after-read-pixels.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/reading/fbo-remains-unchanged-after-read-pixels.html
@@ -98,16 +98,17 @@ if (!gl) {
   gl.vertexAttribPointer(1, 4, gl.UNSIGNED_BYTE, true, 0, colorOffset);
   gl.enableVertexAttribArray(1);
   gl.drawArrays(gl.LINES, 0, vertices.length / 3);
 
   var result_1 = new Uint8Array(N * N * 4);
   var result_2 = new Uint8Array(N * N * 4);
   gl.readPixels(0, 0, N, N, gl.RGBA, gl.UNSIGNED_BYTE, result_1);
   gl.readPixels(0, 0, N, N, gl.RGBA, gl.UNSIGNED_BYTE, result_2);
+  wtu.glErrorShouldBe(gl, gl.NO_ERROR);
 
   var tolerance = 0;
   var diff = new Uint8Array(N * N * 4);
   var failed = wtu.comparePixels(result_1, result_2, tolerance, diff);
 
   if (failed) {
     testFailed("default fbo pixels had be changed between two readPixels without drawing operations");
   } else {
--- a/dom/canvas/test/webgl-conf/checkout/conformance/reading/read-pixels-pack-alignment.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/reading/read-pixels-pack-alignment.html
@@ -51,16 +51,17 @@ varying vec4 color;
 void main()
 {
     gl_FragColor = color;
 }
 </script>
 </head>
 <body>
 <canvas id="example" width="32" height="32"></canvas>
+<canvas id="example2" width="32" height="32"></canvas>
 <div id="description"></div>
 <div id="console"></div>
 <script>
 "use strict";
 
 // The below declarations need to be global for "shouldBe" to see them
 var wtu = WebGLTestUtils;
 var gl = null;
@@ -215,49 +216,57 @@ function runTestIteration(format, type, 
         pixel[i] = 0;
     expectedColor = packColor(format, type, 255, 102, 0, 255);
     shouldBeNonNull("expectedColor");
     shouldBe("pixel", "expectedColor");
 }
 
 description('Verify readPixels() works fine with various PACK_ALIGNMENT values.');
 
-shouldBeNonNull("gl = wtu.create3DContext('example')")
-shouldBeNonNull("program = wtu.setupProgram(gl, ['vshader', 'fshader'], ['pos', 'colorIn'])");
 
+debug("<h1>antialias = false</h1>");
+shouldBeNonNull("gl = wtu.create3DContext('example', {antialias: false})")
 var formats = [ gl.RGBA ];
 var formatNames = [ "RGBA" ];
+runAllIterations();
+debug("<h1>antialias = true</h1>");
+shouldBeNonNull("gl = wtu.create3DContext('example2', {antialias: true})")
+runAllIterations();
 
-for (var i = 0; i < formats.length; ++i) {
-    var format = formats[i];
+function runAllIterations() {
+    shouldBeNonNull("program = wtu.setupProgram(gl, ['vshader', 'fshader'], ['pos', 'colorIn'])");
+
+    for (var i = 0; i < formats.length; ++i) {
+        var format = formats[i];
 
-    debug("Testing format = " + formatNames[i] + " and type = UNSIGNED_BYTE");
-    runTestIteration(format, gl.UNSIGNED_BYTE, 1, 1, 2);
-    runTestIteration(format, gl.UNSIGNED_BYTE, 2, 1, 2);
-    runTestIteration(format, gl.UNSIGNED_BYTE, 4, 1, 2);
-    runTestIteration(format, gl.UNSIGNED_BYTE, 8, 1, 2);
-    runTestIteration(format, gl.UNSIGNED_BYTE, 4, 2, 2);
-    runTestIteration(format, gl.UNSIGNED_BYTE, 8, 2, 2);
-    runTestIteration(format, gl.UNSIGNED_BYTE, 4, 3, 2);
-    runTestIteration(format, gl.UNSIGNED_BYTE, 8, 3, 2);
-    runTestIteration(format, gl.UNSIGNED_BYTE, 4, 4, 2);
-    runTestIteration(format, gl.UNSIGNED_BYTE, 8, 4, 2);
-    runTestIteration(format, gl.UNSIGNED_BYTE, 8, 5, 1);
-    runTestIteration(format, gl.UNSIGNED_BYTE, 4, 5, 2);
-    runTestIteration(format, gl.UNSIGNED_BYTE, 8, 5, 2);
-    runTestIteration(format, gl.UNSIGNED_BYTE, 8, 6, 2);
-    runTestIteration(format, gl.UNSIGNED_BYTE, 8, 7, 2);
-    runTestIteration(format, gl.UNSIGNED_BYTE, 8, 8, 2);
-    runTestIteration(format, gl.UNSIGNED_BYTE, 1, 0, 0);
-    runTestIteration(format, gl.UNSIGNED_BYTE, 2, 0, 0);
-    runTestIteration(format, gl.UNSIGNED_BYTE, 4, 0, 0);
-    runTestIteration(format, gl.UNSIGNED_BYTE, 8, 0, 0);
-    runTestIteration(format, gl.UNSIGNED_BYTE, 1, -1, 1);
-    runTestIteration(format, gl.UNSIGNED_BYTE, 2, 1, -1);
-    runTestIteration(format, gl.UNSIGNED_BYTE, 4, 0, -1);
-    runTestIteration(format, gl.UNSIGNED_BYTE, 8, -1, -1);
+        debug("Testing format = " + formatNames[i] + " and type = UNSIGNED_BYTE");
+        runTestIteration(format, gl.UNSIGNED_BYTE, 1, 1, 2);
+        runTestIteration(format, gl.UNSIGNED_BYTE, 2, 1, 2);
+        runTestIteration(format, gl.UNSIGNED_BYTE, 4, 1, 2);
+        runTestIteration(format, gl.UNSIGNED_BYTE, 8, 1, 2);
+        runTestIteration(format, gl.UNSIGNED_BYTE, 4, 2, 2);
+        runTestIteration(format, gl.UNSIGNED_BYTE, 8, 2, 2);
+        runTestIteration(format, gl.UNSIGNED_BYTE, 4, 3, 2);
+        runTestIteration(format, gl.UNSIGNED_BYTE, 8, 3, 2);
+        runTestIteration(format, gl.UNSIGNED_BYTE, 4, 4, 2);
+        runTestIteration(format, gl.UNSIGNED_BYTE, 8, 4, 2);
+        runTestIteration(format, gl.UNSIGNED_BYTE, 8, 5, 1);
+        runTestIteration(format, gl.UNSIGNED_BYTE, 4, 5, 2);
+        runTestIteration(format, gl.UNSIGNED_BYTE, 8, 5, 2);
+        runTestIteration(format, gl.UNSIGNED_BYTE, 8, 6, 2);
+        runTestIteration(format, gl.UNSIGNED_BYTE, 8, 7, 2);
+        runTestIteration(format, gl.UNSIGNED_BYTE, 8, 8, 2);
+        runTestIteration(format, gl.UNSIGNED_BYTE, 1, 0, 0);
+        runTestIteration(format, gl.UNSIGNED_BYTE, 2, 0, 0);
+        runTestIteration(format, gl.UNSIGNED_BYTE, 4, 0, 0);
+        runTestIteration(format, gl.UNSIGNED_BYTE, 8, 0, 0);
+        runTestIteration(format, gl.UNSIGNED_BYTE, 1, -1, 1);
+        runTestIteration(format, gl.UNSIGNED_BYTE, 2, 1, -1);
+        runTestIteration(format, gl.UNSIGNED_BYTE, 4, 0, -1);
+        runTestIteration(format, gl.UNSIGNED_BYTE, 8, -1, -1);
+    }
 }
+var successfullyParsed = true;
 
-var successfullyParsed = true;
 </script>
 <script src="../../js/js-test-post.js"></script>
 </body>
 </html>
--- a/dom/canvas/test/webgl-conf/checkout/conformance/reading/read-pixels-test.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/reading/read-pixels-test.html
@@ -32,287 +32,305 @@
 <title>WebGL ReadPixels conformance test.</title>
 <link rel="stylesheet" href="../../resources/js-test-style.css"/>
 <script src="../../js/desktop-gl-constants.js"></script>
 <script src="../../js/js-test-pre.js"></script>
 <script src="../../js/webgl-test-utils.js"> </script>
 </head>
 <body>
 <canvas id="example" width="200" height="200" style="width: 20px; height: 20px"></canvas>
+<canvas id="example2" width="200" height="200" style="width: 20px; height: 20px"></canvas>
 <div id="description"></div>
 <div id="console"></div>
 <script>
 "use strict";
 description("Checks that ReadPixels works as expected.");
 
 var wtu = WebGLTestUtils;
-var canvas = document.getElementById("example");
-var gl = wtu.create3DContext(canvas);
-var contextVersion = wtu.getDefault3DContextVersion();
+
+debug("<h1>antialias = false</h1>")
+runTest(document.getElementById("example"), false);
+debug("<h1>antialias = true</h1>")
+runTest(document.getElementById("example2"), true);
+finishTest();
 
 var actual;
 var expected;
-var width = 2;
-var height = 2;
-var continueTestFunc = continueTestPart1;
 
-gl.clearColor(1, 1, 1, 1);
-gl.clear(gl.COLOR_BUFFER_BIT);
+function runTest(canvas, antialias) {
+  var gl = wtu.create3DContext(canvas, {antialias: antialias});
+  var contextVersion = wtu.getDefault3DContextVersion();
 
-// Resize the canvas to 2x2. This is an attempt to get stuff in the backbuffer.
-// that shouldn't be there.
-canvas.addEventListener("webglcontextlost", function(e) { e.preventDefault(); }, false);
-canvas.addEventListener("webglcontextrestored", continueTestAfterContextRestored, false);
-canvas.width = width;
-canvas.height = height;
-if (gl.getError() != gl.CONTEXT_LOST_WEBGL) {
-  continueTestPart1();
-}
+  var width = 2;
+  var height = 2;
+  var continueTestFunc = continueTestPart1;
 
-function continueTestAfterContextRestored() {
-  window.gl = wtu.create3DContext(canvas);
-  var func = continueTestFunc;
-  window.continueTestFunc = function() { testFailed("should not be here"); };
-  func();
-}
-
-function continueTestPart1() {
-  gl.clearColor(0.2, 0.6, 0.4, 1);
+  gl.clearColor(1, 1, 1, 1);
   gl.clear(gl.COLOR_BUFFER_BIT);
 
-  var innerColor = [51, 153, 102, 255]; // (0.2, 0.6, 0.4, 1)
-  var outerColor = [19, 72, 0, 198]; // Random color other than [0, 0, 0, 0]
+  // Resize the canvas to 2x2. This is an attempt to get stuff in the backbuffer.
+  // that shouldn't be there.
+  canvas.addEventListener("webglcontextlost", function(e) { e.preventDefault(); }, false);
+  canvas.addEventListener("webglcontextrestored", continueTestAfterContextRestored, false);
+  canvas.width = width;
+  canvas.height = height;
+  if (gl.getError() != gl.CONTEXT_LOST_WEBGL) {
+    continueTestPart1();
+  }
+
+  function continueTestAfterContextRestored() {
+    window.gl = wtu.create3DContext(canvas);
+    var func = continueTestFunc;
+    window.continueTestFunc = function() { testFailed("should not be here"); };
+    func();
+  }
+
+  function continueTestPart1() {
+    gl.clearColor(0.2, 0.6, 0.4, 1);
+    gl.clear(gl.COLOR_BUFFER_BIT);
+
+    var innerColor = [51, 153, 102, 255]; // (0.2, 0.6, 0.4, 1)
+    var outerColor = [19, 72, 0, 198]; // Random color other than [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}
+    ];
 
-  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);
+    }
+
+    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no GL errors");
 
-  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);
+    function checkBuffer(checkColor, x, y, oneColor, oneX, oneY) {
+      var buf = new Uint8Array(width * height * 4);
+      // Initialize buf.
+      for (var ii = 0; ii < width * height; ++ii) {
+        buf[ii * 4] = outerColor[0];
+        buf[ii * 4 + 1] = outerColor[1];
+        buf[ii * 4 + 2] = outerColor[2];
+        buf[ii * 4 + 3] = outerColor[3];
+      }
+      gl.readPixels(x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf);
+      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;
+          var mismatch = false;
+          for (var cc = 0; cc < 4; ++cc) {
+            var expectedColor = expectedColors[cc];
+            var color = buf[offset + cc];
+            var diff = Math.abs(expectedColor - color);
+            if (diff >= 3) {
+              mismatch = true;
+              break;
+            }
+          }
+          assertMsg(!mismatch,
+                    "color pixel at " + xx + ", " + yy + " should be about " + expectedColors +
+                    ", was = " + [buf[offset], buf[offset + 1], buf[offset + 2], buf[offset + 3]]);
+        }
+      }
+    }
+
+    continueTestPart2();
   }
 
-  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no GL errors");
+  function continueTestPart2() {
+    let neverValidFormats = [gl.DEPTH_COMPONENT, gl.DEPTH_STENCIL, desktopGL.R8, gl.RGBA4];
+    let maybeValidFormats = [gl.LUMINANCE, gl.LUMINANCE_ALPHA];
+    if (contextVersion < 2) {
+    // They are valid in WebGL 2 or higher
+      maybeValidFormats = maybeValidFormats.concat([desktopGL.RED, desktopGL.RG_INTEGER, desktopGL.RGBA_INTEGER]);
+    }
+
+    let neverValidTypeInfo = [
+      {type: desktopGL.UNSIGNED_INT_24_8,       dest: new Uint32Array(4)}
+    ];
+    let maybeValidTypeInfo = [];
+    if (contextVersion < 2) {
+    // They are valid in WebGL 2 or Higher
+      maybeValidTypeInfo = maybeValidTypeInfo.concat([
+        {type: gl.UNSIGNED_SHORT,                     dest: new Uint16Array(4)},
+        {type: gl.SHORT,                              dest: new Int16Array(4)},
+        {type: gl.BYTE,                               dest: new Int8Array(4)},
+        {type: gl.UNSIGNED_INT,                       dest: new Uint32Array(4)},
+        {type: desktopGL.UNSIGNED_INT_2_10_10_10_REV, dest: new Uint32Array(4)}
+      ]);
+    }
 
-  function checkBuffer(checkColor, x, y, oneColor, oneX, oneY) {
-    var buf = new Uint8Array(width * height * 4);
-    // Initialize buf.
-    for (var ii = 0; ii < width * height; ++ii) {
-      buf[ii * 4] = outerColor[0];
-      buf[ii * 4 + 1] = outerColor[1];
-      buf[ii * 4 + 2] = outerColor[2];
-      buf[ii * 4 + 3] = outerColor[3];
+    debug("");
+    debug("check non-default format or type");
+    for (let format of neverValidFormats) {
+      var buf = new Uint8Array(4);
+      gl.readPixels(0, 0, 1, 1, format, gl.UNSIGNED_BYTE, buf);
+      wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "Should not be able to read as " + wtu.glEnumToString(gl, format));
+    }
+    for (let format of maybeValidFormats) {
+      var buf = new Uint8Array(4);
+      gl.readPixels(0, 0, 1, 1, format, gl.UNSIGNED_BYTE, buf);
+      wtu.glErrorShouldBe(gl, [gl.INVALID_ENUM, gl.INVALID_OPERATION], "Should not be able to read as " + wtu.glEnumToString(gl, format));
+    }
+
+    for (let info of neverValidTypeInfo) {
+      var type = info.type;
+      var dest = info.dest;
+      gl.readPixels(0, 0, 1, 1, gl.RGBA, type, dest);
+      wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "Should not be able to read as " + wtu.glEnumToString(gl, type));
+    }
+    for (let info of maybeValidTypeInfo) {
+      var type = info.type;
+      var dest = info.dest;
+      gl.readPixels(0, 0, 1, 1, gl.RGBA, type, dest);
+      wtu.glErrorShouldBe(gl, [gl.INVALID_ENUM, gl.INVALID_OPERATION], "Should not be able to read as " + wtu.glEnumToString(gl, type));
     }
-    gl.readPixels(x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf);
-    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;
-        var mismatch = false;
-        for (var cc = 0; cc < 4; ++cc) {
-          var expectedColor = expectedColors[cc];
-          var color = buf[offset + cc];
-          var diff = Math.abs(expectedColor - color);
-          if (diff >= 3) {
-            mismatch = true;
-            break;
-          }
+
+    var combinations = [
+      {
+        format: gl.RGBA,
+        type: gl.UNSIGNED_BYTE,
+        dest: new Uint8Array(4),
+      },
+      {
+        format: gl.RGB,
+        type: gl.UNSIGNED_BYTE,
+        dest: new Uint8Array(3),
+      },
+      {
+        format: gl.RGB,
+        type: gl.UNSIGNED_SHORT_5_6_5,
+        dest: new Uint8Array(3),
+      },
+      {
+        format: gl.RGBA,
+        type: gl.UNSIGNED_SHORT_5_5_5_1,
+        dest: new Uint16Array(1),
+      },
+      {
+        format: gl.RGBA,
+        type: gl.UNSIGNED_SHORT_4_4_4_4,
+        dest: new Uint16Array(1),
+      },
+      {
+        format: gl.ALPHA,
+        type: gl.UNSIGNED_BYTE,
+        dest: new Uint8Array(1),
+      }
+    ];
+    if (contextVersion > 1) {
+      combinations = combinations.concat([
+        {
+          format: gl.RED,
+          type: gl.UNSIGNED_BYTE,
+          dest: new Uint8Array(1),
+        },
+        {
+          format: gl.RGBA_INTEGER,
+          type: gl.UNSIGNED_INT,
+          dest: new Uint32Array(4),
+        },
+        {
+          format: gl.RGBA_INTEGER,
+          type: gl.INT,
+          dest: new Int32Array(4),
         }
-        assertMsg(!mismatch,
-                  "color pixel at " + xx + ", " + yy + " should be about " + expectedColors +
-                  ", was = " + [buf[offset], buf[offset + 1], buf[offset + 2], buf[offset + 3]]);
+      ]);
+    }
+
+    debug("");
+    debug("check invalid combinations of format/type");
+
+    var implFormat = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT);
+    var implType = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE);
+
+    for (var tt = 0; tt < combinations.length; ++ tt) {
+      var info = combinations[tt];
+      var format = info.format;
+      var type = info.type;
+      var dest = info.dest;
+      gl.readPixels(0, 0, 1, 1, format, type, dest);
+      // Only two format/type parameter pairs are accepted. GL_RGBA/GL_UNSIGNED_BYTE is always
+      // accepted on default readbuffer. The other acceptable pair can be discovered by querying
+      // GL_IMPLEMENTATION_COLOR_READ_FORMAT and GL_IMPLEMENTATION_COLOR_READ_TYPE.
+      if ((format == gl.RGBA && type == gl.UNSIGNED_BYTE) || (format == implFormat && type == implType)) {
+        wtu.glErrorShouldBe(
+            gl, gl.NO_ERROR,
+            "Should be able to read as " + wtu.glEnumToString(gl, format) +
+            " / " + wtu.glEnumToString(gl, type));
+      } else {
+        wtu.glErrorShouldBe(
+            gl, gl.INVALID_OPERATION,
+            "Should not be able to read as " + wtu.glEnumToString(gl, format) +
+            " / " + wtu.glEnumToString(gl, type));
       }
     }
+
+    debug("");
+    debug("check reading with lots of drawing");
+    continueTestFunc = continueTestPart3;
+    width = 1024;
+    height = 1024;
+    canvas.width = width;
+    canvas.height = height;
+    if (gl.getError() != gl.CONTEXT_LOST_WEBGL) {
+      continueTestPart3();
+    }
   }
 
-  continueTestPart2();
-}
-
-function continueTestPart2() {
-  var invalidFormat = [gl.DEPTH_COMPONENT, gl.DEPTH_STENCIL, desktopGL.R8, gl.RGBA4, gl.LUMINANCE, gl.LUMINANCE_ALPHA];
-  if (contextVersion < 2) {
-  // They are valid in WebGL 2 or higher
-    invalidFormat = invalidFormat.concat([desktopGL.RED, desktopGL.RG_INTEGER, desktopGL.RGBA_INTEGER]);
-  }
-
-  var invalidTypeInfo = [
-    {type: desktopGL.UNSIGNED_INT_24_8,       dest: new Uint32Array(4)}
-  ];
-  if (contextVersion < 2) {
-  // They are valid in WebGL 2 or Higher
-    invalidTypeInfo = invalidTypeInfo.concat([
-      {type: gl.UNSIGNED_SHORT,                     dest: new Uint16Array(4)},
-      {type: gl.SHORT,                              dest: new Int16Array(4)},
-      {type: gl.BYTE,                               dest: new Int8Array(4)},
-      {type: gl.UNSIGNED_INT,                       dest: new Uint32Array(4)},
-      {type: desktopGL.UNSIGNED_INT_2_10_10_10_REV, dest: new Uint32Array(4)}
-    ]);
-  }
-
-  debug("");
-  debug("check invalid format or type");
-  for (var ff = 0; ff < invalidFormat.length; ++ff) {
-    var format = invalidFormat[ff];
-    var buf = new Uint8Array(4);
-    gl.readPixels(0, 0, 1, 1, format, gl.UNSIGNED_BYTE, buf);
-    wtu.glErrorShouldBe(gl, [gl.INVALID_ENUM, gl.INVALID_OPERATION], "Should not be able to read as " + wtu.glEnumToString(gl, format));
-  }
-
-  for (var tt = 0; tt < invalidTypeInfo.length; ++tt) {
-    var info = invalidTypeInfo[tt];
-    var type = info.type;
-    var dest = info.dest;
-    gl.readPixels(0, 0, 1, 1, gl.RGBA, type, dest);
-    wtu.glErrorShouldBe(gl, [gl.INVALID_ENUM, gl.INVALID_OPERATION], "Should not be able to read as " + wtu.glEnumToString(gl, type));
-  }
-
-  var combinations = [
-    {
-      format: gl.RGBA,
-      type: gl.UNSIGNED_BYTE,
-      dest: new Uint8Array(4),
-    },
-    {
-      format: gl.RGB,
-      type: gl.UNSIGNED_BYTE,
-      dest: new Uint8Array(3),
-    },
-    {
-      format: gl.RGB,
-      type: gl.UNSIGNED_SHORT_5_6_5,
-      dest: new Uint8Array(3),
-    },
-    {
-      format: gl.RGBA,
-      type: gl.UNSIGNED_SHORT_5_5_5_1,
-      dest: new Uint16Array(1),
-    },
-    {
-      format: gl.RGBA,
-      type: gl.UNSIGNED_SHORT_4_4_4_4,
-      dest: new Uint16Array(1),
-    },
-    {
-      format: gl.ALPHA,
-      type: gl.UNSIGNED_BYTE,
-      dest: new Uint8Array(1),
+  function continueTestPart3() {
+    gl.viewport(0, 0, 1024, 1024);
+    var program = wtu.setupTexturedQuad(gl);
+    var loc = gl.getUniformLocation(program, "tex");
+    gl.disable(gl.BLEND);
+    gl.disable(gl.DEPTH_TEST);
+    var colors = [[255, 0, 0, 255], [0, 255, 0, 255], [0, 0, 255, 255]];
+    var textures = [];
+    var results = [];
+    for (var ii = 0; ii < colors.length; ++ii) {
+      gl.activeTexture(gl.TEXTURE0 + ii);
+      var tex = gl.createTexture();
+      wtu.fillTexture(gl, tex, 1, 1, colors[ii]);
+      textures.push(tex);
     }
-  ];
-  if (contextVersion > 1) {
-    combinations = combinations.concat([
-      {
-        format: gl.RED,
-        type: gl.UNSIGNED_BYTE,
-        dest: new Uint8Array(1),
-      },
-      {
-        format: gl.RGBA_INTEGER,
-        type: gl.UNSIGNED_INT,
-        dest: new Uint32Array(4),
-      },
-      {
-        format: gl.RGBA_INTEGER,
-        type: gl.INT,
-        dest: new Int32Array(4),
+    for (var ii = 0; ii < colors.length; ++ii) {
+      for (var jj = 0; jj < 300 + ii + 1; ++jj) {
+        gl.uniform1i(loc, jj % 3);
+        gl.drawArrays(gl.TRIANGLES, 0, 6);
       }
-    ]);
-  }
-
-  debug("");
-  debug("check invalid combinations of format/type");
-
-  var implFormat = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT);
-  var implType = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE);
-
-  for (var tt = 0; tt < combinations.length; ++ tt) {
-    var info = combinations[tt];
-    var format = info.format;
-    var type = info.type;
-    var dest = info.dest;
-    gl.readPixels(0, 0, 1, 1, format, type, dest);
-    // Only two format/type parameter pairs are accepted. GL_RGBA/GL_UNSIGNED_BYTE is always
-    // accepted on default readbuffer. The other acceptable pair can be discovered by querying
-    // GL_IMPLEMENTATION_COLOR_READ_FORMAT and GL_IMPLEMENTATION_COLOR_READ_TYPE.
-    if ((format == gl.RGBA && type == gl.UNSIGNED_BYTE) || (format == implFormat && type == implType)) {
-      wtu.glErrorShouldBe(
-          gl, gl.NO_ERROR,
-          "Should be able to read as " + wtu.glEnumToString(gl, format) +
-          " / " + wtu.glEnumToString(gl, type));
-    } else {
-      wtu.glErrorShouldBe(
-          gl, gl.INVALID_OPERATION,
-          "Should not be able to read as " + wtu.glEnumToString(gl, format) +
-          " / " + wtu.glEnumToString(gl, type));
+      var buf = new Uint8Array(4);
+      gl.readPixels(512, 512, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, buf);
+      results.push(buf);
+      for (var kk = 0; kk < 99; ++kk) {
+        gl.uniform1i(loc, (jj + kk) % 3);
+        gl.drawArrays(gl.TRIANGLES, 0, 6);
+      }
     }
+    for (var ii = 0; ii < colors.length; ++ii) {
+      var buf = results[ii];
+      var color = colors[ii];
+      actual = [buf[0], buf[1], buf[2], buf[3]];
+      expected = [color[0], color[1], color[2], color[3]];
+      shouldBe("actual", "expected");
+    }
+    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no GL errors");
   }
-
-  debug("");
-  debug("check reading with lots of drawing");
-  continueTestFunc = continueTestPart3;
-  width = 1024;
-  height = 1024;
-  canvas.width = width;
-  canvas.height = height;
-  if (gl.getError() != gl.CONTEXT_LOST_WEBGL) {
-    continueTestPart3();
-  }
-}
-
-function continueTestPart3() {
-  gl.viewport(0, 0, 1024, 1024);
-  var program = wtu.setupTexturedQuad(gl);
-  var loc = gl.getUniformLocation(program, "tex");
-  gl.disable(gl.BLEND);
-  gl.disable(gl.DEPTH_TEST);
-  var colors = [[255, 0, 0, 255], [0, 255, 0, 255], [0, 0, 255, 255]];
-  var textures = [];
-  var results = [];
-  for (var ii = 0; ii < colors.length; ++ii) {
-    gl.activeTexture(gl.TEXTURE0 + ii);
-    var tex = gl.createTexture();
-    wtu.fillTexture(gl, tex, 1, 1, colors[ii]);
-    textures.push(tex);
-  }
-  for (var ii = 0; ii < colors.length; ++ii) {
-    for (var jj = 0; jj < 300 + ii + 1; ++jj) {
-      gl.uniform1i(loc, jj % 3);
-      gl.drawArrays(gl.TRIANGLES, 0, 6);
-    }
-    var buf = new Uint8Array(4);
-    gl.readPixels(512, 512, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, buf);
-    results.push(buf);
-    for (var kk = 0; kk < 99; ++kk) {
-      gl.uniform1i(loc, (jj + kk) % 3);
-      gl.drawArrays(gl.TRIANGLES, 0, 6);
-    }
-  }
-  for (var ii = 0; ii < colors.length; ++ii) {
-    var buf = results[ii];
-    var color = colors[ii];
-    actual = [buf[0], buf[1], buf[2], buf[3]];
-    expected = [color[0], color[1], color[2], color[3]];
-    shouldBe("actual", "expected");
-  }
-  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no GL errors");
-
-  debug("");
-  finishTest();
 }
 </script>
 </body>
 </html>
 
--- a/dom/canvas/test/webgl-conf/checkout/conformance/rendering/00_test_list.txt
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/rendering/00_test_list.txt
@@ -1,36 +1,41 @@
+--min-version 1.0.4 blending.html
 --min-version 1.0.4 canvas-alpha-bug.html
 --min-version 1.0.4 --max-version 1.9.9 clipping-wide-points.html
+--min-version 1.0.4 color-mask-preserved-during-implicit-clears.html
 --min-version 1.0.2 culling.html
 --min-version 1.0.4 default-texture-draw-bug.html
 draw-arrays-out-of-bounds.html
 draw-elements-out-of-bounds.html
+--min-version 1.0.4 draw-webgl-to-canvas-2d-repeatedly.html
 --min-version 1.0.4 draw-with-changing-start-vertex-bug.html
 --min-version 1.0.3 framebuffer-switch.html
 --min-version 1.0.3 framebuffer-texture-switch.html
 gl-clear.html
 --min-version 1.0.3 gl-drawarrays.html
 gl-drawelements.html
 gl-scissor-test.html
 --min-version 1.0.2 gl-scissor-fbo-test.html
 --min-version 1.0.3 gl-scissor-canvas-dimensions.html
 --min-version 1.0.3 gl-viewport-test.html
 --min-version 1.0.4 line-rendering-quality.html
 --min-version 1.0.3 many-draw-calls.html
 more-than-65536-indices.html
 multisample-corruption.html
 --min-version 1.0.3 negative-one-index.html
+out-of-bounds-array-buffers.html
 out-of-bounds-index-buffers.html
 --min-version 1.0.3 point-no-attributes.html
 point-size.html
 --min-version 1.0.4 point-specific-shader-variables.html
 --min-version 1.0.3 point-with-gl-pointcoord-in-fragment-shader.html
 --min-version 1.0.3 polygon-offset.html
 --min-version 1.0.4 preservedrawingbuffer-leak.html
+--min-version 1.0.4 rendering-sampling-feedback-loop.html
 --min-version 1.0.4 scissor-rect-repeated-rendering.html
 --min-version 1.0.2 simple.html
 triangle.html
 line-loop-tri-fan.html
 --min-version 1.0.4 framebuffer-texture-clear.html
 --min-version 1.0.4 clear-after-copyTexImage2D.html
 --min-version 1.0.4 texture-switch-performance.html
 --min-version 1.0.4 rendering-stencil-large-viewport.html
new file mode 100644
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/rendering/blending.html
@@ -0,0 +1,216 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+
+<script id="eVsSrc" type="text/plain">
+void main()
+{
+    gl_PointSize = 1.0;
+    gl_Position = vec4(0, 0, 0, 1);
+}
+</script>
+
+<script id="eFsSrc" type="text/plain">
+precision mediump float;
+uniform vec4 uColor;
+
+void main()
+{
+    gl_FragColor = uColor;
+}
+</script>
+
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<script>
+"use strict";
+description('Blending tests');
+
+const wtu = WebGLTestUtils;
+
+function CreateContext() {
+    const gl = wtu.create3DContext();
+    gl.viewport(0, 0, 1, 1);
+
+    gl.prog = wtu.setupProgram(gl, [eVsSrc.innerHTML, eFsSrc.innerHTML]);
+    gl.prog.uColor = (() => {
+        const loc = gl.getUniformLocation(gl.prog, 'uColor');
+        return x => gl.uniform4fv(loc, x);
+    })();
+    gl.useProgram(gl.prog);
+    gl.prog.uColor([1 / 255, 2 / 255, 3 / 255, 4 / 255]);
+
+    gl.drawAndRead = type => {
+        gl.drawArrays(gl.POINTS, 0, 1);
+        let ret;
+        if (type == gl.UNSIGNED_BYTE) {
+            ret = new Uint8Array(4);
+        } else if (type == gl.FLOAT) {
+            ret = new Float32Array(4);
+        }
+        gl.readPixels(0, 0, 1, 1, gl.RGBA, type, ret);
+        return ret;
+    };
+
+    gl.enable(gl.BLEND);
+    gl.blendFunc(gl.CONSTANT_COLOR, gl.ZERO);
+    gl.blendColor(10, 1, 1, 1);
+
+    return gl;
+}
+
+function CreateValidFb(gl, formats) {
+    const fb = gl.createFramebuffer();
+    gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+
+    for (let i in formats) {
+        i = i|0; // Otherwise i is a string. :(
+        const f = formats[i];
+        if (!f)
+            continue;
+        if (f.length == 1) {
+            const rb = gl.createRenderbuffer();
+            gl.bindRenderbuffer(gl.RENDERBUFFER, rb);
+            gl.renderbufferStorage(gl.RENDERBUFFER, f[0], 1, 1);
+            gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0+i,
+                                       gl.RENDERBUFFER, rb);
+            continue;
+        }
+        if (f.length == 3) {
+            let internalFormat = f[0];
+            if (internalFormat === undefined) {
+                internalFormat = f[1];
+            }
+
+            const tex = gl.createTexture();
+            gl.bindTexture(gl.TEXTURE_2D, tex);
+            gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, 1,1,0, f[1],f[2], null);
+            gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0+i,
+                                    gl.TEXTURE_2D, tex, 0);
+            continue;
+        }
+        throw new Error('Invalid format length: ' + f);
+    }
+
+    const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
+    if (status != gl.FRAMEBUFFER_COMPLETE) {
+        gl.deleteFramebuffer(fb);
+        return null;
+    }
+    return fb;
+}
+
+let was, fb;
+
+const TESTS = [
+    () => {
+        debug('');
+        debug("State queries don't clamp.");
+
+        const gl = wtu.create3DContext();
+        gl.blendColor(1000, 1, 1, 1);
+        const was = gl.getParameter(gl.BLEND_COLOR);
+        expectArray(was, [1000, 1, 1, 1]);
+    },
+    () => {
+        debug('');
+        debug('Blending for RGBA8:');
+
+        const gl = CreateContext();
+        fb = CreateValidFb(gl, [[gl.RGBA8, gl.RGBA, gl.UNSIGNED_BYTE]]);
+        shouldBeNonNull('fb');
+
+        const was = gl.drawAndRead(gl.UNSIGNED_BYTE);
+        expectArray(was, [1, 2, 3, 4]);
+
+        if (gl.getExtension('EXT_color_buffer_float') ||
+            gl.getExtension('EXT_color_buffer_half_float'))
+        {
+            debug('Enable color_buffer_half_float and retest');
+            gl.blendColor(1000, 1, 1, 1);
+            const was = gl.drawAndRead(gl.UNSIGNED_BYTE);
+            expectArray(was, [1, 2, 3, 4]);
+        }
+    },
+    () => {
+        debug('');
+        debug('Blending for RGBA16F:');
+
+        const gl = CreateContext();
+        if (gl.blitFramebuffer) {
+            if (!gl.getExtension('EXT_color_buffer_float')) {
+                testPassed('Missing ext EXT_color_buffer_float is optional, skipping.');
+                return;
+            }
+        } else {
+            if (!gl.getExtension('EXT_color_buffer_half_float')) {
+                testPassed('Missing ext EXT_color_buffer_half_float is optional, skipping.');
+                return;
+            }
+            const ext = gl.getExtension('OES_texture_half_float');
+            gl.HALF_FLOAT = ext.HALF_FLOAT_OES; // These aren't the same value, but this'll work.
+        }
+
+        fb = CreateValidFb(gl, [[gl.RGBA16F, gl.RGBA, gl.HALF_FLOAT]]);
+        shouldBeNonNull('fb');
+        gl.prog.uColor([1, 2, 3, 4]);
+        const was = gl.drawAndRead(gl.FLOAT);
+        expectArray(was, [10, 2, 3, 4]);
+    },
+    () => {
+        debug('');
+        debug('Blending for RGBA32F:');
+
+        const gl = CreateContext();
+        if (gl.blitFramebuffer) {
+            if (!gl.getExtension('EXT_color_buffer_float')) {
+                testPassed('Missing ext EXT_color_buffer_float is optional, skipping.');
+                return;
+            }
+        } else {
+            if (!gl.getExtension('WEBGL_color_buffer_float')) {
+                testPassed('Missing ext WEBGL_color_buffer_float is optional, skipping.');
+                return;
+            }
+            gl.getExtension('OES_texture_float');
+        }
+        fb = CreateValidFb(gl, [[gl.RGBA32F, gl.RGBA, gl.FLOAT]]);
+        shouldBeNonNull('fb');
+        gl.prog.uColor([1, 2, 3, 4]);
+        const was = gl.drawAndRead(gl.FLOAT);
+
+        if (!gl.getExtension('EXT_float_blend')) {
+            wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, 'Should not be able to blend 32F formats.');
+            return;
+        }
+        wtu.glErrorShouldBe(gl, 0, 'Should be able to blend 32F formats.');
+        expectArray(was, [10, 2, 3, 4]);
+    },
+];
+
+async function Test() {
+    for (const fn of TESTS) {
+        await wtu.dispatchPromise(fn);
+    }
+    wtu.destroyAllContexts();
+    finishTest();
+}
+
+Test();
+
+var successfullyParsed = true;
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/rendering/color-mask-preserved-during-implicit-clears.html
@@ -0,0 +1,132 @@
+<!--
+
+/*
+** Copyright (c) 2018 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>ColorMask Must Be Preserved During Implicit Clears</title>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<script>
+"use strict";
+const wtu = WebGLTestUtils;
+const sz = 128;
+let frames;
+let gl;
+let tests = [
+  { alpha: false, antialias: false, premultipliedAlpha: false },
+  { alpha: false, antialias: false, premultipliedAlpha: true  },
+  { alpha: false, antialias: true,  premultipliedAlpha: false },
+  { alpha: false, antialias: true,  premultipliedAlpha: true  },
+];
+let currentTest;
+let testIndex = 0;
+
+function initTest() {
+  description();
+  debug('ColorMask must be preserved during implicit clears of textures.');
+  debug('Regression test for <a href="http://crbug.com/911918">http://crbug.com/911918</a>');
+
+  requestAnimationFrame(nextTest);
+}
+
+function nextTest() {
+  if (testIndex >= tests.length) {
+    finishTest();
+    return;
+  }
+
+  frames = 20;
+  let canvases = document.getElementById('canvases');
+  let canvas = document.createElement('canvas');
+  canvas.width = sz;
+  canvas.height = sz;
+  canvases.appendChild(canvas);
+  currentTest = tests[testIndex];
+  ++testIndex;
+  gl = wtu.create3DContext(canvas, currentTest);
+  requestAnimationFrame(runTest);
+}
+
+function runTest() {
+  // Create a user-defined framebuffer which has an alpha channel.
+  let fb = gl.createFramebuffer();
+  gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+  // Set color mask to disable alpha writes. This is important; see below.
+  gl.colorMask(true, true, true, false);
+  let tex = gl.createTexture();
+  gl.bindTexture(gl.TEXTURE_2D, tex);
+  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, sz, sz, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+  // Upload a sub-rectangle. In Chrome, this was lazily clearing level 0 of the
+  // texture using OpenGL, setting the driver's color mask to (true, true, true,
+  // true) in the process. Because the user's color mask was set to (true, true,
+  // true, false) above, incorrect caching code was failing to reset the
+  // driver's color mask later. On macOS, Chrome implements alpha:false WebGL
+  // contexts on top of RGBA textures whose alpha channel is cleared to 1.0 and
+  // where the color mask is set to (true, true, true, false) during all writes.
+  // This bug was allowing that texture's alpha channel to be destroyed.
+  gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(4));
+  gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
+  // We have to issue one clear to this framebuffer to get the color mask
+  // latched into the internal caching code.
+  gl.clear(gl.COLOR_BUFFER_BIT);
+
+  // Switch back to default framebuffer.
+  gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+  // Set clear color to transparent green.
+  gl.clearColor(0, 1, 0, 0);
+  // Clear. Result should be opaque green. Was transparent green when
+  // bug was encountered.
+  gl.clear(gl.COLOR_BUFFER_BIT);
+  wtu.checkCanvasRect(gl, 0, 0, sz, sz,
+                      [ 0, 255, 0, 255 ],
+                      "default framebuffer should be opaque green for " + JSON.stringify(currentTest));
+
+  gl.deleteFramebuffer(fb);
+  gl.deleteTexture(tex);
+
+  --frames;
+  if (frames == 0) {
+    requestAnimationFrame(nextTest);
+  } else {
+    requestAnimationFrame(runTest);
+  }
+}
+
+requestAnimationFrame(initTest);
+</script>
+</head>
+<body>
+<div id="description"></div>
+<div id="canvases"></div>
+<div id="console"></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/rendering/draw-webgl-to-canvas-2d-repeatedly.html
@@ -0,0 +1,112 @@
+<!--
+
+/*
+** Copyright (c) 2018 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Draw WebGL to Canvas2D Repeatedly</title>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<script>
+"use strict";
+const wtu = WebGLTestUtils;
+
+const sz = 256;
+
+function drawTo2DCanvas(c2, webGLCanvas) {
+  // Always clear 2D canvas to solid green first.
+  c2.clearRect(0, 0, sz, sz);
+  c2.fillStyle = 'rgb(0,255,0)';
+  c2.fillRect(0, 0, sz, sz);
+  // Draw WebGL canvas to this canvas.
+  c2.drawImage(webGLCanvas, 0, 0);
+}
+
+function runTest() {
+  description();
+  debug('Repeatedly drawing a WebGL canvas to a 2D canvas should only draw the most recently rendered WebGL content.');
+  debug('Regression test for <a href="http://crbug.com/894021">http://crbug.com/894021</a>');
+
+  let c2 = document.getElementById('canvas-2d').getContext('2d');
+  let webGLCanvas = document.getElementById('canvas-webgl');
+  let gl = wtu.create3DContext(webGLCanvas, { alpha: true, antialias: false, premultipliedAlpha: true });
+  let tolerance = 2;
+
+  // Clear left half of WebGL canvas to red and right half to
+  // transparent black.
+  gl.disable(gl.SCISSOR_TEST);
+  gl.clearColor(0.0, 0.0, 0.0, 0.0);
+  gl.clear(gl.COLOR_BUFFER_BIT);
+  gl.scissor(0, 0, sz / 2, sz);
+  gl.enable(gl.SCISSOR_TEST);
+  gl.clearColor(1.0, 0.0, 0.0, 1.0);
+  gl.clear(gl.COLOR_BUFFER_BIT);
+  // Draw to 2D canvas.
+  drawTo2DCanvas(c2, webGLCanvas);
+
+  // Clear right half of WebGL canvas to red and left half to
+  // transparent black.
+  gl.disable(gl.SCISSOR_TEST);
+  gl.clearColor(0.0, 0.0, 0.0, 0.0);
+  gl.clear(gl.COLOR_BUFFER_BIT);
+  gl.scissor(sz / 2, 0, sz / 2, sz);
+  gl.enable(gl.SCISSOR_TEST);
+  gl.clearColor(1.0, 0.0, 0.0, 1.0);
+  gl.clear(gl.COLOR_BUFFER_BIT);
+  // Draw to 2D canvas.
+  drawTo2DCanvas(c2, webGLCanvas);
+
+  // Clear WebGL canvas to transparent black.
+  gl.disable(gl.SCISSOR_TEST);
+  gl.clearColor(0.0, 0.0, 0.0, 0.0);
+  gl.clear(gl.COLOR_BUFFER_BIT);
+  // Draw to 2D canvas.
+  drawTo2DCanvas(c2, webGLCanvas);
+
+  // 2D canvas should be green.
+  // In the error case, the rendering results from earlier draws were
+  // being accumulated, so the 2D canvas was ultimately red.
+  wtu.checkCanvasRect(c2, 0, 0, sz, sz,
+                      [ 0, 255, 0, 255 ],
+                      "should be green",
+                      tolerance);
+
+  finishTest();
+}
+
+requestAnimationFrame(runTest);
+</script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<canvas id="canvas-webgl" width="256" height="256"></canvas>
+<canvas id="canvas-2d" width="256" height="256"></canvas>
+</body>
+</html>
copy from dom/canvas/test/webgl-conf/checkout/conformance/rendering/out-of-bounds-index-buffers.html
copy to dom/canvas/test/webgl-conf/checkout/conformance/rendering/out-of-bounds-array-buffers.html
--- a/dom/canvas/test/webgl-conf/checkout/conformance/rendering/out-of-bounds-index-buffers.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/rendering/out-of-bounds-array-buffers.html
@@ -1,12 +1,12 @@
 <!--
 
 /*
-** Copyright (c) 2016 The Khronos Group Inc.
+** Copyright (c) 2019 The Khronos Group Inc.
 **
 ** Permission is hereby granted, free of charge, to any person obtaining a
 ** copy of this software and/or associated documentation files (the
 ** "Materials"), to deal in the Materials without restriction, including
 ** without limitation the rights to use, copy, modify, merge, publish,
 ** distribute, sublicense, and/or sell copies of the Materials, and to
 ** permit persons to whom the Materials are furnished to do so, subject to
 ** the following conditions:
@@ -25,17 +25,17 @@
 -->
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8">
 <link rel="stylesheet" href="../../resources/js-test-style.css"/>
 <script src="../../js/js-test-pre.js"></script>
 <script src="../../js/webgl-test-utils.js"></script>
-<title>WebGL Out-of-Bounds Index Buffer Conformance Test</title>
+<title>WebGL Out-of-Bounds Array Buffer Conformance Test</title>
 </head>
 <body>
 <canvas id="canvas" width="8" height="8" style="width: 100px; height: 100px;"></canvas>
 <div id="description"></div>
 <div id="console"></div>
 <script id="vsCheckOutOfBounds" type="x-shader/x-vertex">
     precision mediump float;
     attribute vec2 position;
@@ -61,96 +61,86 @@
         } else {
             v_color = vec4(1.0, 0.0, 0.0, 1.0); // red -- Unexpected value
         }
         gl_Position = vec4(position, 0.0, 1.0);
     }
 </script>
 <script>
 "use strict";
-description("This test verifies that out-of-bounds index buffers behave according to spec.");
-
-// Prepare an element array buffer that indexes out-of-bounds beginning with the start index passed in.
-// Ensure that drawElements flags either no error or INVALID_OPERATION. In the case of INVALID_OPERATION,
-// no canvas pixels can be touched.  In the case of NO_ERROR, all written values must either be the
-// zero vertex or a value in the vertex buffer.  See vsCheckOutOfBounds shader.
-function drawAndVerifyOutOfBoundsIndex(gl, startIndex) {
-    gl.clearColor(0.0, 0.0, 1.0, 1.0);  // Start with blue to indicate no pixels touched.
-    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
-
-    prepareElementArrayBuffer(gl, /*StartIndex*/startIndex);
-
-    gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_SHORT, /*offset*/0);
-    var error = gl.getError();
-    if (error === gl.INVALID_OPERATION) {
-        testPassed("drawElements flagged INVALID_OPERATION, which is valid so long as all canvas pixels were not touched.");
-        wtu.checkCanvas(gl, [0, 0, 255, 255]);
-    } else if (error === gl.NO_ERROR) {
-        testPassed("drawElements flagged NO_ERROR, which is valid so long as all canvas pixels are green.");
-        wtu.checkCanvas(gl, [0, 255, 0, 255]);
-    } else {
-        testFailed("Invalid error flagged by drawElements. Should be INVALID_OPERATION or NO_ERROR");
-    }
-}
-
-// Create an element array buffer with a tri-strip that starts at startIndex and make
-// it the active element array buffer.
-function prepareElementArrayBuffer(gl, startIndex) {
-    var glElementArrayBuffer = gl.createBuffer();
-    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, glElementArrayBuffer);
-    var quadIndices = new Uint16Array(4);
-    for (var i = 0; i < quadIndices.length; i++) {
-        quadIndices[i] = startIndex + i;
-    }
-    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, quadIndices, gl.STATIC_DRAW);
-}
-
+description("This test verifies that out-of-bounds array buffers behave according to spec.");
 
 var wtu = WebGLTestUtils;
 var canvas = document.getElementById("canvas");
 var gl = wtu.create3DContext(canvas, {antialias: false});
 
 var numberOfQuads = 200;
 
-// Create a vertex buffer with 200 properly formed tri-strip quads. These quads will cover the canvas texture
-// such that every single pixel is touched by the fragment shader.
+// Draw out-of-bounds beginning with the start offset passed in.
+// Ensure that drawArray