Fix local conformance tests. draft
authorJeff Gilbert <jdashg@gmail.com>
Thu, 17 Dec 2015 16:16:51 -0800
changeset 316076 1924b658e989a2255cdad39ce6fe042dc509933c
parent 316075 99d1b9f623cbbe39c68e79c5526b9294aed0aed0
child 316077 024d3b6003293ddee6914f2469f656bf721b9682
push id8514
push userjgilbert@mozilla.com
push dateFri, 18 Dec 2015 00:24:33 +0000
milestone45.0a1
Fix local conformance tests.
dom/canvas/TexUnpackBlob.cpp
dom/canvas/WebGLContext.cpp
dom/canvas/WebGLContext.h
dom/canvas/WebGLContextGL.cpp
dom/canvas/WebGLRenderbuffer.cpp
dom/canvas/WebGLRenderbuffer.h
dom/canvas/WebGLStrongTypes.h
dom/canvas/test/webgl-conformance/conformance/extensions/oes-texture-float.html
dom/canvas/test/webgl-conformance/conformance/misc/object-deletion-behaviour.html
dom/canvas/test/webgl-conformance/conformance/more/functions/texImage2DBadArgs.html
dom/canvas/test/webgl-conformance/conformance/more/functions/texSubImage2DBadArgs.html
dom/canvas/test/webgl-conformance/conformance/more/util.js
dom/canvas/test/webgl-conformance/conformance/renderbuffers/framebuffer-test.html
dom/canvas/test/webgl-conformance/conformance/resources/webgl-test-utils.js
dom/canvas/test/webgl-conformance/conformance/textures/tex-input-validation.html
dom/canvas/test/webgl-conformance/conformance/textures/texture-formats-test.html
--- a/dom/canvas/TexUnpackBlob.cpp
+++ b/dom/canvas/TexUnpackBlob.cpp
@@ -294,22 +294,22 @@ TexUnpackBytes::TexOrSubImage(bool isSub
     *out_glError = error;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////
 // TexUnpackDataSurface
 
 static bool
-GuessAlignment(const void* data, size_t width, size_t stride, size_t maxAlignment,
+GuessAlignment(const void* data, size_t bytesPerRow, size_t stride, size_t maxAlignment,
                size_t* const out_alignment)
 {
     size_t alignmentGuess = maxAlignment;
     while (alignmentGuess) {
-        size_t guessStride = RoundUpToMultipleOf(width, alignmentGuess);
+        size_t guessStride = RoundUpToMultipleOf(bytesPerRow, alignmentGuess);
         if (guessStride == stride &&
             uintptr_t(data) % alignmentGuess == 0)
         {
             *out_alignment = alignmentGuess;
             return true;
         }
         alignmentGuess /= 2;
     }
@@ -403,24 +403,28 @@ TexUnpackSurface::UploadDataSurface(bool
 
     if (!chosenDUI)
         return false;
 
     gfx::DataSourceSurface::ScopedMap map(surf, gfx::DataSourceSurface::MapType::READ);
     if (!map.IsMapped())
         return false;
 
+    const webgl::PackingInfo pi = {chosenDUI->unpackFormat, chosenDUI->unpackType};
+    const auto bytesPerPixel = webgl::BytesPerPixel(pi);
+    const size_t bytesPerRow = width * bytesPerPixel;
+
     const GLint kMaxUnpackAlignment = 8;
     size_t unpackAlignment;
-    if (!GuessAlignment(map.GetData(), width, map.GetStride(), kMaxUnpackAlignment,
+    if (!GuessAlignment(map.GetData(), bytesPerRow, map.GetStride(), kMaxUnpackAlignment,
                         &unpackAlignment))
     {
         return false;
         // TODO: Consider using UNPACK_ settings to set the stride based on the too-large
-        // alignment used for many SourceSurfaces.
+        // alignment used for some SourceSurfaces. (D2D allegedy likes alignment=16)
     }
 
     gl->MakeCurrent();
 
     ScopedUnpackReset scopedReset(webgl);
     gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, unpackAlignment);
 
     const GLsizei depth = 1;
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -1909,32 +1909,16 @@ ScopedUnpackReset::UnwrapImpl()
         }
 
         mGL->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, pbo);
     }
 }
 
 ////////////////////////////////////////
 
-bool
-GuessAlignmentFromStride(size_t width, size_t stride, size_t maxAlignment,
-                         size_t* const out_alignment)
-{
-    size_t alignmentGuess = maxAlignment;
-    while (alignmentGuess) {
-        size_t guessStride = RoundUpToMultipleOf(width, alignmentGuess);
-        if (guessStride == stride) {
-            *out_alignment = alignmentGuess;
-            return true;
-        }
-        alignmentGuess /= 2;
-    }
-    return false;
-}
-
 void
 Intersect(uint32_t srcSize, int32_t dstStartInSrc, uint32_t dstSize,
           uint32_t* const out_intStartInSrc, uint32_t* const out_intStartInDst,
           uint32_t* const out_intSize)
 {
     // Only >0 if dstStartInSrc is >0:
     // 0  3          // src coords
     // |  [========] // dst box
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -1676,21 +1676,16 @@ RoundUpToMultipleOf(const V& value, cons
 bool
 ValidateTexTarget(WebGLContext* webgl, const char* funcName, GLenum rawTexTarget,
                   TexTarget* const out_texTarget, WebGLTexture** const out_tex);
 bool
 ValidateTexImageTarget(WebGLContext* webgl, const char* funcName, uint8_t funcDims,
                        GLenum rawTexImageTarget, TexImageTarget* const out_texImageTarget,
                        WebGLTexture** const out_tex);
 
-
-bool
-GuessAlignmentFromStride(size_t width, size_t stride, size_t maxAlignment,
-                         size_t* const out_alignment);
-
 class UniqueBuffer
 {
     // Like UniquePtr<>, but for void* and malloc/calloc/free.
     void* mBuffer;
 
 public:
     UniqueBuffer()
         : mBuffer(nullptr)
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -893,25 +893,22 @@ WebGLContext::GetRenderbufferParameter(G
         case LOCAL_GL_RENDERBUFFER_WIDTH:
         case LOCAL_GL_RENDERBUFFER_HEIGHT:
         case LOCAL_GL_RENDERBUFFER_RED_SIZE:
         case LOCAL_GL_RENDERBUFFER_GREEN_SIZE:
         case LOCAL_GL_RENDERBUFFER_BLUE_SIZE:
         case LOCAL_GL_RENDERBUFFER_ALPHA_SIZE:
         case LOCAL_GL_RENDERBUFFER_DEPTH_SIZE:
         case LOCAL_GL_RENDERBUFFER_STENCIL_SIZE:
+        case LOCAL_GL_RENDERBUFFER_INTERNAL_FORMAT:
         {
             // RB emulation means we have to ask the RB itself.
             GLint i = mBoundRenderbuffer->GetRenderbufferParameter(target, pname);
             return JS::Int32Value(i);
         }
-        case LOCAL_GL_RENDERBUFFER_INTERNAL_FORMAT:
-        {
-            return JS::NumberValue(mBoundRenderbuffer->GetInternalFormat());
-        }
         default:
             ErrorInvalidEnumInfo("getRenderbufferParameter: parameter", pname);
     }
 
     return JS::NullValue();
 }
 
 already_AddRefed<WebGLTexture>
--- a/dom/canvas/WebGLRenderbuffer.cpp
+++ b/dom/canvas/WebGLRenderbuffer.cpp
@@ -265,30 +265,34 @@ WebGLRenderbuffer::GetRenderbufferParame
     case LOCAL_GL_RENDERBUFFER_BLUE_SIZE:
     case LOCAL_GL_RENDERBUFFER_ALPHA_SIZE:
     case LOCAL_GL_RENDERBUFFER_DEPTH_SIZE:
         {
             GLint i = 0;
             gl->fGetRenderbufferParameteriv(target.get(), pname.get(), &i);
             return i;
         }
+
+    case LOCAL_GL_RENDERBUFFER_INTERNAL_FORMAT:
+        {
+            GLenum ret = 0;
+            if (mFormat) {
+                ret = mFormat->format->sizedFormat;
+
+                if (!mContext->IsWebGL2() && ret == LOCAL_GL_DEPTH24_STENCIL8) {
+                    ret = LOCAL_GL_DEPTH_STENCIL;
+                }
+            }
+            return ret;
+        }
     }
 
     MOZ_ASSERT(false,
                "This function should only be called with valid `pname`.");
     return 0;
 }
 
-GLenum
-WebGLRenderbuffer::GetInternalFormat() const
-{
-    if (!mFormat)
-        return 0;
-
-    return mFormat->format->sizedFormat;
-}
-
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLRenderbuffer)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLRenderbuffer, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLRenderbuffer, Release)
 
 } // namespace mozilla
--- a/dom/canvas/WebGLRenderbuffer.h
+++ b/dom/canvas/WebGLRenderbuffer.h
@@ -45,18 +45,16 @@ public:
     }
 
     GLsizei Samples() const { return mSamples; }
 
     GLuint PrimaryGLName() const { return mPrimaryRB; }
 
     const webgl::FormatUsageInfo* Format() const { return mFormat; }
 
-    GLenum GetInternalFormat() const;
-
     int64_t MemoryUsage() const;
 
     WebGLContext* GetParentObject() const {
         return mContext;
     }
 
     void BindRenderbuffer() const;
     void RenderbufferStorage(GLsizei samples, const webgl::FormatUsageInfo* format,
--- a/dom/canvas/WebGLStrongTypes.h
+++ b/dom/canvas/WebGLStrongTypes.h
@@ -431,16 +431,17 @@ STRONG_GLENUM_BEGIN(FBStatus)
     STRONG_GLENUM_VALUE(FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER),
     STRONG_GLENUM_VALUE(FRAMEBUFFER_INCOMPLETE_READ_BUFFER),
     STRONG_GLENUM_VALUE(FRAMEBUFFER_UNSUPPORTED),
 STRONG_GLENUM_END(FBStatus)
 
 STRONG_GLENUM_BEGIN(RBParam)
     STRONG_GLENUM_VALUE(RENDERBUFFER_WIDTH),
     STRONG_GLENUM_VALUE(RENDERBUFFER_HEIGHT),
+    STRONG_GLENUM_VALUE(RENDERBUFFER_INTERNAL_FORMAT),
     STRONG_GLENUM_VALUE(RENDERBUFFER_RED_SIZE),
     STRONG_GLENUM_VALUE(RENDERBUFFER_GREEN_SIZE),
     STRONG_GLENUM_VALUE(RENDERBUFFER_BLUE_SIZE),
     STRONG_GLENUM_VALUE(RENDERBUFFER_ALPHA_SIZE),
     STRONG_GLENUM_VALUE(RENDERBUFFER_DEPTH_SIZE),
     STRONG_GLENUM_VALUE(RENDERBUFFER_STENCIL_SIZE),
 STRONG_GLENUM_END(RBParam)
 
--- a/dom/canvas/test/webgl-conformance/conformance/extensions/oes-texture-float.html
+++ b/dom/canvas/test/webgl-conformance/conformance/extensions/oes-texture-float.html
@@ -126,17 +126,18 @@ function runTextureCreationTest(testProg
     var height = 2;
     var numberOfChannels = 4;
     var data = new Float32Array(width * height * numberOfChannels);
     for (var ii = 0; ii < data.length; ++ii) {
         data[ii] = 10000;
     }
     gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.FLOAT, data);
     if (expectFailure) {
-        glErrorShouldBe(gl, gl.INVALID_ENUM, "floating-point texture allocation must be disallowed if OES_texture_float isn't enabled");
+        wtu.glErrorShouldBeIn(gl, [gl.INVALID_ENUM, gl.INVALID_OPERATION],
+                              "floating-point texture allocation must be disallowed if OES_texture_float isn't enabled");
         return;
     } else {
         glErrorShouldBe(gl, gl.NO_ERROR, "floating-point texture allocation should succeed if OES_texture_float is enabled");
     }
     // Verify that the texture actually works for sampling and contains the expected data.
     gl.uniform1i(gl.getUniformLocation(testProgram, "tex"), 0);
     wtu.drawQuad(gl);
     checkRenderingResults();
--- a/dom/canvas/test/webgl-conformance/conformance/misc/object-deletion-behaviour.html
+++ b/dom/canvas/test/webgl-conformance/conformance/misc/object-deletion-behaviour.html
@@ -71,17 +71,17 @@ shouldGenerateGLError(gl, gl.NO_ERROR, "
 shouldBe("gl.getParameter(gl.TEXTURE_BINDING_2D)", "tex");
 shouldGenerateGLError(gl, gl.NO_ERROR, "gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0)");
 shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", "tex");
 shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)", "gl.TEXTURE");
 shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteTexture(tex)");
 // Deleting a texture bound to the currently-bound fbo is the same as
 // detaching the textue from fbo first, then delete the texture.
 shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)", "gl.NONE");
-shouldGenerateGLError(gl, gl.INVALID_ENUM, "gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)");
+shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", "null");
 shouldBeFalse("gl.isTexture(tex)");
 shouldBeNull("gl.getParameter(gl.TEXTURE_BINDING_2D)");
 shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindTexture(gl.TEXTURE_2D, tex)");
 shouldBeNull("gl.getParameter(gl.TEXTURE_BINDING_2D)");
 
 var texCubeMap = gl.createTexture();
 shouldBeNonNull("texCubeMap");
 shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindTexture(gl.TEXTURE_CUBE_MAP, texCubeMap)");
@@ -123,17 +123,17 @@ shouldBeNonNull("rbo3");
 shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindRenderbuffer(gl.RENDERBUFFER, rbo)");
 shouldBe("gl.getParameter(gl.RENDERBUFFER_BINDING)", "rbo");
 shouldGenerateGLError(gl, gl.NO_ERROR, "gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo)");
 shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", "rbo");
 shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteRenderbuffer(rbo)");
 // Deleting a renderbuffer bound to the currently-bound fbo is the same as
 // detaching the renderbuffer from fbo first, then delete the renderbuffer.
 shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)", "gl.NONE");
-shouldGenerateGLError(gl, gl.INVALID_ENUM, "gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)");
+shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", "null");
 shouldBeFalse("gl.isRenderbuffer(rbo)");
 shouldBeNull("gl.getParameter(gl.RENDERBUFFER_BINDING)");
 shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindRenderbuffer(gl.RENDERBUFFER, rbo)");
 shouldBeNull("gl.getParameter(gl.RENDERBUFFER_BINDING)");
 shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindRenderbuffer(gl.RENDERBUFFER, rbo2)");
 shouldBe("gl.getParameter(gl.RENDERBUFFER_BINDING)", "rbo2");
 shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteRenderbuffer(rbo3)");
 shouldBe("gl.getParameter(gl.RENDERBUFFER_BINDING)", "rbo2");
@@ -257,18 +257,18 @@ if (gl.checkFramebufferStatus(gl.FRAMEBU
   shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo2)");
   shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 16, 16, [0,255,0,255], "fbo should be green")');
   shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clearColor(0,0,1,1)");
   shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clear(gl.COLOR_BUFFER_BIT)");
   shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 16, 16, [0,0,255,255], "fbo should be blue")');
   shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", "rbo");
 
   shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
-  shouldGenerateGLError(gl, gl.INVALID_ENUM, "gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)");
-  shouldGenerateGLError(gl, gl.NONE, "gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)");
+  shouldGenerateGLError(gl, gl.NO_ERROR, "gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)");
+  shouldGenerateGLError(gl, gl.NO_ERROR, "gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)");
   shouldNotBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
   // Bind backbuffer.
   shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, null)");
   shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 16, 16, [255,0,0,255], "backbuffer should be red")');
 }
 
 debug("");
 debug("using deleted texture");
@@ -294,17 +294,17 @@ if (gl.checkFramebufferStatus(gl.FRAMEBU
   shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
   shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 1, 1, [0,255,0,255], "fbo should be green")');
   shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clearColor(0,0,1,1)");
   shouldGenerateGLError(gl, gl.NO_ERROR, "gl.clear(gl.COLOR_BUFFER_BIT)");
   shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 1, 1, [0,0,255,255], "fbo should be blue")');
   shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", "tex");
 
   shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
-  shouldGenerateGLError(gl, gl.INVALID_ENUM, "gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)");
+  shouldGenerateGLError(gl, gl.NO_ERROR, "gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)");
   shouldNotBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
   // Bind backbuffer.
   shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, null)");
   shouldGenerateGLError(gl, gl.NO_ERROR, 'wtu.checkCanvasRect(gl, 0, 0, 16, 16, [255,0,0,255], "backbuffer should be red")');
 }
 
 debug("");
 debug("buffer deletion");
--- a/dom/canvas/test/webgl-conformance/conformance/more/functions/texImage2DBadArgs.html
+++ b/dom/canvas/test/webgl-conformance/conformance/more/functions/texImage2DBadArgs.html
@@ -53,63 +53,63 @@ function setup(gl) {
     return tex;
 }
 
 function teardown(gl, tex) {
     gl.bindTexture(gl.TEXTURE_2D, null);
     gl.deleteTexture(tex);
 }
 
-function testrunner(gl, expected, desc, fn) {
+function testrunner(gl, expectedList, desc, fn) {
    var tex = setup(gl);
    fn();
-   glErrorShouldBe(gl, expected, desc);
+   wtu.glErrorShouldBeIn(gl, expectedList, desc);
    teardown(gl, tex);
 }
 
  var data = new Uint8Array(4);
- testrunner(gl, gl.INVALID_OPERATION, "not enough data", function(){
+ testrunner(gl, [gl.INVALID_OPERATION], "not enough data", function(){
      gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 2,1,0,gl.RGBA,gl.UNSIGNED_BYTE, data);
  });
- testrunner(gl, gl.INVALID_OPERATION, "not enough data", function(){
+ testrunner(gl, [gl.INVALID_OPERATION], "not enough data", function(){
      gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1,2,0,gl.RGBA,gl.UNSIGNED_BYTE, data);
  });
- testrunner(gl, gl.INVALID_ENUM, "bad target", function(){
+ testrunner(gl, [gl.INVALID_ENUM], "bad target", function(){
      gl.texImage2D(gl.FLOAT, 0, gl.RGBA, 1,1,0,gl.RGBA,gl.UNSIGNED_BYTE, null);
  });
- testrunner(gl, gl.INVALID_ENUM, "bad internal format/format", function(){
+ testrunner(gl, [gl.INVALID_ENUM, gl.INVALID_OPERATION], "bad internal format/format", function(){
      gl.texImage2D(gl.TEXTURE_2D, 0, gl.FLOAT, 1,1,0,gl.FLOAT,gl.UNSIGNED_BYTE, null);
  });
- testrunner(gl, gl.INVALID_VALUE, "border > 0", function(){
+ testrunner(gl, [gl.INVALID_VALUE], "border > 0", function(){
      gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1,1,48,gl.RGBA,gl.UNSIGNED_BYTE, null);
  });
  // The spec says zero size is OK. If you disagree please list the section
  // in the spec that details this issue.
- testrunner(gl, gl.NO_ERROR, "zero size", function(){
+ testrunner(gl, [gl.NO_ERROR], "zero size", function(){
      gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 0,0,0,gl.RGBA,gl.UNSIGNED_BYTE, null);
  });
- testrunner(gl, gl.INVALID_VALUE, "negative width", function(){
+ testrunner(gl, [gl.INVALID_VALUE], "negative width", function(){
      gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, -1,1,0,gl.RGBA,gl.UNSIGNED_BYTE, null);
  });
- testrunner(gl, gl.INVALID_VALUE, "negative height", function(){
+ testrunner(gl, [gl.INVALID_VALUE], "negative height", function(){
      gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1,-1,0,gl.RGBA,gl.UNSIGNED_BYTE, null);
  });
- testrunner(gl, gl.INVALID_ENUM, "bad format", function(){
+ testrunner(gl, [gl.INVALID_ENUM, gl.INVALID_OPERATION], "bad format", function(){
      gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1,1,0,gl.FLOAT,gl.UNSIGNED_BYTE, null);
  });
- testrunner(gl, gl.INVALID_ENUM, "bad type", function(){
+ testrunner(gl, [gl.INVALID_ENUM, gl.INVALID_OPERATION], "bad type", function(){
      gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1,1,0,gl.RGBA,gl.TEXTURE_2D, null);
  });
- testrunner(gl, gl.INVALID_OPERATION, "not enough data", function(){
+ testrunner(gl, [gl.INVALID_OPERATION], "not enough data", function(){
      gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1,1,0,gl.RGBA,gl.UNSIGNED_BYTE, new Uint8Array(3));
  });
- testrunner(gl, gl.INVALID_OPERATION, "format and type incompatible",function(){
+ testrunner(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);
  });
- testrunner(gl, gl.INVALID_OPERATION, "format and type incompatible",function(){
+ testrunner(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);
  });
 
 debug("");
 var successfullyParsed = true;
 </script>
 <script>finishTest();</script>
 </body>
--- a/dom/canvas/test/webgl-conformance/conformance/more/functions/texSubImage2DBadArgs.html
+++ b/dom/canvas/test/webgl-conformance/conformance/more/functions/texSubImage2DBadArgs.html
@@ -26,80 +26,87 @@ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 OTHER DEALINGS IN THE SOFTWARE.
 
 -->
 <link rel="stylesheet" type="text/css" href="../unit.css" />
 <script type="application/x-javascript" src="../unit.js"></script>
 <script type="application/x-javascript" src="../util.js"></script>
+<script src="../../resources/webgl-test-utils.js"></script>
 <script type="application/x-javascript">
+var wtu = WebGLTestUtils;
 
 Tests.startUnit = function () {
     var canvas = document.getElementById('gl');
-    var gl = wrapGLContext(canvas.getContext(GL_CONTEXT_ID));
+    var gl = canvas.getContext(GL_CONTEXT_ID);
     return [gl];
 }
 
 Tests.setup = function(gl) {
     var tex = gl.createTexture();
     gl.bindTexture(gl.TEXTURE_2D, tex);
     return [gl]
 }
 
 Tests.teardown = function(gl,tex) {
     gl.bindTexture(gl.TEXTURE_2D, null);
     gl.deleteTexture(tex);
 }
 
+function assertGLErrorIn(gl, expectedList, desc, func) {
+    func();
+    wtu.glErrorShouldBeIn(gl, expectedList, desc);
+}
+
 Tests.testTexImage2D = function(gl) {
     gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 2,2,0,gl.RGBA,gl.UNSIGNED_BYTE, new Uint8Array([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]));
-    assertGLError(gl, gl.INVALID_OPERATION, "not enough data", function(){
+    assertGLErrorIn(gl, [gl.INVALID_OPERATION], "not enough data", function(){
         gl.texSubImage2D(gl.TEXTURE_2D, 0,0, 0, 2,1,gl.RGBA,gl.UNSIGNED_BYTE, new Uint8Array([0,0,0,0]));
     });
-    assertGLError(gl, gl.INVALID_OPERATION, "not enough data", function(){
+    assertGLErrorIn(gl, [gl.INVALID_OPERATION], "not enough data", function(){
         gl.texSubImage2D(gl.TEXTURE_2D, 0,0, 0, 1,2,gl.RGBA,gl.UNSIGNED_BYTE, new Uint8Array([0,0,0,0]));
     });
-    assertGLError(gl, gl.INVALID_ENUM, "bad target", function(){
+    assertGLErrorIn(gl, [gl.INVALID_ENUM], "bad target", function(){
         gl.texSubImage2D(gl.FLOAT, 0, 0,0, 1,1,gl.RGBA,gl.UNSIGNED_BYTE, new Uint8Array([0,0,0,0]));
     });
-    assertGLError(gl, gl.INVALID_VALUE, "width out of range", function(){
+    assertGLErrorIn(gl, [gl.INVALID_VALUE], "width out of range", function(){
         gl.texSubImage2D(gl.TEXTURE_2D, 0,0, 0, 3,1,gl.RGBA,gl.UNSIGNED_BYTE, new Uint8Array([0,0,0,0,0,0,0,0,0,0,0,0]));
     });
-    assertGLError(gl, gl.INVALID_VALUE, "height out of range", function(){
+    assertGLErrorIn(gl, [gl.INVALID_VALUE], "height out of range", function(){
         gl.texSubImage2D(gl.TEXTURE_2D, 0,0, 0, 1,3,gl.RGBA,gl.UNSIGNED_BYTE, new Uint8Array([0,0,0,0,0,0,0,0,0,0,0,0]));
     });
     assertOk("zero size", function(){
         gl.texSubImage2D(gl.TEXTURE_2D, 0,0, 0, 0,0,gl.RGBA,gl.UNSIGNED_BYTE, new Uint8Array([0,0,0,0]));
     });
-    assertSomeGLError(gl, "negative width", function(){
+    assertGLErrorIn(gl, [gl.INVALID_VALUE], "negative width", function(){
         gl.texSubImage2D(gl.TEXTURE_2D, 0,0, 0, -1,1,gl.RGBA,gl.UNSIGNED_BYTE, new Uint8Array([0,0,0,0]));
     });
-    assertSomeGLError(gl, "negative height", function(){
+    assertGLErrorIn(gl, [gl.INVALID_VALUE], "negative height", function(){
         gl.texSubImage2D(gl.TEXTURE_2D, 0,0, 0, 1,-1,gl.RGBA,gl.UNSIGNED_BYTE, new Uint8Array([0,0,0,0]));
     });
-    assertGLError(gl, gl.INVALID_VALUE, "negative x", function(){
+    assertGLErrorIn(gl, [gl.INVALID_VALUE], "negative x", function(){
         gl.texSubImage2D(gl.TEXTURE_2D, 0,-1,1,1,1,gl.RGBA,gl.UNSIGNED_BYTE, new Uint8Array([0,0,0,0]));
     });
-    assertGLError(gl, gl.INVALID_VALUE, "negative y", function(){
+    assertGLErrorIn(gl, [gl.INVALID_VALUE], "negative y", function(){
         gl.texSubImage2D(gl.TEXTURE_2D, 0,1,-1,1,1,gl.RGBA,gl.UNSIGNED_BYTE, new Uint8Array([0,0,0,0]));
     });
-    assertGLError(gl, gl.INVALID_ENUM, "bad format", function(){
+    assertGLErrorIn(gl, [gl.INVALID_ENUM, gl.INVALID_OPERATION], "bad format", function(){
         gl.texSubImage2D(gl.TEXTURE_2D, 0, 0,0, 1,1,gl.FLOAT,gl.UNSIGNED_BYTE, new Uint8Array([0,0,0,0]));
     });
-    assertGLError(gl, gl.INVALID_ENUM, "bad type", function(){
+    assertGLErrorIn(gl, [gl.INVALID_ENUM, gl.INVALID_OPERATION], "bad type", function(){
         gl.texSubImage2D(gl.TEXTURE_2D, 0, 0,0, 1,1,gl.RGBA,gl.TEXTURE_2D, new Uint8Array([0,0,0,0]));
     });
-    assertGLError(gl, gl.INVALID_OPERATION, "not enough data", function(){
+    assertGLErrorIn(gl, [gl.INVALID_OPERATION], "not enough data", function(){
         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(){
+    assertGLErrorIn(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(){
+    assertGLErrorIn(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]));
     });
 }
 
 
 Tests.endUnit = function(gl) {
 }
 
--- a/dom/canvas/test/webgl-conformance/conformance/more/util.js
+++ b/dom/canvas/test/webgl-conformance/conformance/more/util.js
@@ -1011,16 +1011,50 @@ function assertGLError(gl, err, name, f)
       testFailed("assertGLError: expected: " + getGLErrorAsString(gl, err) +
                  " actual: " + getGLErrorAsString(gl, glErr), name, f);
     }
     return false;
   }
   return true;
 }
 
+// Assert that f generates a specific GL error.
+function assertGLErrorIn(gl, expectedErrorList, name, f) {
+  if (f == null) { f = name; name = null; }
+
+  var actualError = 0;
+  try {
+    f();
+  } catch(e) {
+    if ('glError' in e) {
+      actualError = e.glError;
+    } else {
+      testFailed("assertGLError: UNEXPCETED EXCEPTION", name, f);
+      return false;
+    }
+  }
+
+  var expectedErrorStrList = [];
+  var expectedErrorSet = {};
+  for (var i in expectedErrorList) {
+    var cur = expectedErrorList[i];
+    expectedErrorSet[cur] = true;
+    expectedErrorStrList.push(getGLErrorAsString(gl, cur));
+  }
+  var expectedErrorListStr = "[" + expectedErrorStrList.join(", ") + "]";
+
+  if (actualError in expectedErrorSet) {
+    return true;
+  }
+
+  testFailed("assertGLError: expected: " + expectedErrorListStr +
+             " actual: " + getGLErrorAsString(gl, actualError), name, f);
+  return false;
+}
+
 // Assert that f generates some GL error. Used in situations where it's
 // ambigious which of multiple possible errors will be generated.
 function assertSomeGLError(gl, name, f) {
   if (f == null) { f = name; name = null; }
   var r = false;
   var glErr = 0;
   var err = 0;
   try { f(); } catch(e) { r=true; glErr = e.glError; }
--- a/dom/canvas/test/webgl-conformance/conformance/renderbuffers/framebuffer-test.html
+++ b/dom/canvas/test/webgl-conformance/conformance/renderbuffers/framebuffer-test.html
@@ -127,26 +127,27 @@ if (!gl) {
   var attachment = desktopGL.COLOR_ATTACHMENT1
   gl.framebufferTexture2D(gl.FRAMEBUFFER, attachment, gl.TEXTURE_2D, fbtex, 0);
   glErrorShouldBe(gl, gl.INVALID_ENUM,
             "calling framebufferTexImage2D with attachment = COLOR_ATTACHMENT1 should generate INVALID_ENUM.");
   gl.framebufferRenderbuffer(gl.FRAMEBUFFER, attachment, gl.RENDERBUFFER, rb);
   glErrorShouldBe(gl, gl.INVALID_ENUM,
             "calling framebufferRenderbuffer with attachment = COLOR_ATTACHMENT1 should generate INVALID_ENUM.");
 
+  gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, fbtex, 0);
+  glErrorShouldBe(gl, gl.NO_ERROR,
+            "attaching a texture to a framebuffer should succeed.");
+
+  // Must have a valid attachment, otherwise may also generate INVALID_OPERATION.
   gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER,
                                        gl.COLOR_ATTACHMENT0,
                                        desktopGL.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING);
   glErrorShouldBe(gl, gl.INVALID_ENUM,
             "calling getFramebufferAttachmentParameter with pname = GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING should generate INVALID_ENUM.");
 
-  gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, fbtex, 0);
-  glErrorShouldBe(gl, gl.NO_ERROR,
-            "attaching a texture to a framebuffer should succeed.");
-
   gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, null, 0);
   glErrorShouldBe(gl, gl.NO_ERROR,
             "detaching a texture from a framebuffer should succeed.");
 
   gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, fbtex, 1);
   glErrorShouldBe(gl, gl.INVALID_VALUE,
             "calling framebufferTexture2D with non-zero mipmap level should generate INVALID_VALUE.");
 
--- a/dom/canvas/test/webgl-conformance/conformance/resources/webgl-test-utils.js
+++ b/dom/canvas/test/webgl-conformance/conformance/resources/webgl-test-utils.js
@@ -673,16 +673,46 @@ var glErrorShouldBe = function(gl, glErr
                ". Was " + getGLErrorAsString(gl, err) + " : " + opt_msg);
   } else {
     testPassed("getError was expected value: " +
                 getGLErrorAsString(gl, glError) + " : " + opt_msg);
   }
 };
 
 /**
+ * Tests that the first error GL returns is the specified error.
+ * @param {!WebGLContext} gl The WebGLContext to use.
+ * @param {number} glError The expected gl error.
+ * @param {string} opt_msg
+ */
+var glErrorShouldBeIn = function(gl, expectedErrorList, opt_msg) {
+  opt_msg = opt_msg || "";
+
+  var expectedErrorStrList = [];
+  var expectedErrorSet = {};
+
+  for (var i in expectedErrorList) {
+    var cur = expectedErrorList[i];
+
+    expectedErrorStrList.push(getGLErrorAsString(gl, cur));
+    expectedErrorSet[cur] = true;
+  }
+
+  var expectedErrorStr = "[" + expectedErrorStrList.join(", ") + "]";
+
+  var actualError = gl.getError();
+  if (actualError in expectedErrorSet) {
+    testPassed("getError was in expected values: " + expectedErrorStr + " : " + opt_msg);
+  } else {
+    testFailed("getError expected: " + expectedErrorStr +
+               ". Was " + getGLErrorAsString(gl, actualError) + " : " + opt_msg);
+  }
+};
+
+/**
  * Links a WebGL program, throws if there are errors.
  * @param {!WebGLContext} gl The WebGLContext to use.
  * @param {!WebGLProgram} program The WebGLProgram to link.
  * @param {function(string): void) opt_errorCallback callback for errors.
  */
 var linkProgram = function(gl, program, opt_errorCallback) {
   errFn = opt_errorCallback || testFailed;
   // Link the program
@@ -1360,16 +1390,17 @@ return {
   getExtensionWithKnownPrefixes: getExtensionWithKnownPrefixes,
   getFileListAsync: getFileListAsync,
   getLastError: getLastError,
   getScript: getScript,
   getSupportedExtensionWithKnownPrefixes: getSupportedExtensionWithKnownPrefixes,
   getUrlArguments: getUrlArguments,
   glEnumToString: glEnumToString,
   glErrorShouldBe: glErrorShouldBe,
+  glErrorShouldBeIn: glErrorShouldBeIn,
   fillTexture: fillTexture,
   insertImage: insertImage,
   loadImageAsync: loadImageAsync,
   loadImagesAsync: loadImagesAsync,
   loadProgram: loadProgram,
   loadProgramFromFile: loadProgramFromFile,
   loadProgramFromScript: loadProgramFromScript,
   loadProgramFromScriptExpectError: loadProgramFromScriptExpectError,
--- a/dom/canvas/test/webgl-conformance/conformance/textures/tex-input-validation.html
+++ b/dom/canvas/test/webgl-conformance/conformance/textures/tex-input-validation.html
@@ -34,52 +34,52 @@ function testTexImage2D(testCase)
     var msg = "" +
       " internalFormat: " + enumToString(testCase.internalFormat) +
       " target: " + enumToString(testCase.target) +
       " format: " + enumToString(testCase.format) +
       " type: " + enumToString(testCase.type) +
       " border: " + testCase.border;
 
     gl.texImage2D(testCase.target, level, testCase.internalFormat, width, height, testCase.border, testCase.format, testCase.type, null);
-    error = testCase.expectedError;
-    glErrorShouldBe(gl, error, msg);
+    errors = testCase.expectedErrors;
+    wtu.glErrorShouldBeIn(gl, errors, msg);
 }
 
 function testTexSubImage2D(testCase)
 {
     var level = 0;
     var xoffset = 0;
     var yoffset = 0;
     var width = 16;
     var height = 16;
     var msg = ""+
         " format: " + enumToString(testCase.format) +
         " type: " + enumToString(testCase.type);
     var array = new Uint8Array(width * height * 4);
     gl.texSubImage2D(testCase.target, level, xoffset, yoffset, width, height, testCase.format, testCase.type, array);
-    error = testCase.expectedError;
-    glErrorShouldBe(gl, error, msg);
+    errors = testCase.expectedErrors;
+    wtu.glErrorShouldBeIn(gl, errors, msg);
 }
 
 function testTexParameter(testCase)
 {
     var msg = "paramName: " + enumToString(testCase.pname);
-    error = testCase.expectedError;
+    errors = testCase.expectedErrors;
     gl.texParameteri(testCase.target, testCase.pname, testCase.param);
-    glErrorShouldBe(gl, error, msg);
+    glErrorShouldBe(gl, errors, msg);
     gl.texParameterf(testCase.target, testCase.pname, testCase.param);
-    glErrorShouldBe(gl, error, msg);
+    glErrorShouldBe(gl, errors, msg);
 }
 
 function testGetTexParameter(testCase)
 {
     var msg = "paramName: " + enumToString(testCase.pname);
-    error = testCase.expectedError;
+    errors = testCase.expectedErrors;
     gl.getTexParameter(testCase.target, testCase.pname);
-    glErrorShouldBe(gl, error, msg);
+    glErrorShouldBe(gl, errors, msg);
 }
 
 function testCopyTexImage2D(testCase)
 {
     var level = 0;
     var x = 0;
     var y = 0;
     var width = 16;
@@ -91,18 +91,18 @@ function testCopyTexImage2D(testCase)
       " target: " + enumToString(testCase.target) +
       " border: " + testCase.border;
 
     gl.renderbufferStorage(gl.RENDERBUFFER, testCase.colorBufferFormat, width, height);
     glErrorShouldBe(gl, gl.NO_ERROR);
     shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
 
     gl.copyTexImage2D(testCase.target, level, testCase.internalFormat, x, y, width, height, testCase.border);
-    error = testCase.expectedError;
-    glErrorShouldBe(gl, error, msg);
+    errors = testCase.expectedErrors;
+    wtu.glErrorShouldBeIn(gl, errors, msg);
 }
 
 function testCopyTexSubImage2D(testCase)
 {
     var level = 0;
     var x = 0;
     var y = 0;
     var width = 16;
@@ -119,18 +119,18 @@ function testCopyTexSubImage2D(testCase)
     gl.renderbufferStorage(gl.RENDERBUFFER, testCase.colorBufferFormat, width, height);
     glErrorShouldBe(gl, gl.NO_ERROR);
     shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
 
     gl.texImage2D(testCase.target, level, testCase.internalFormat, xoffset + width, yoffset + height, border, testCase.internalFormat, type, null);
     glErrorShouldBe(gl, gl.NO_ERROR);
 
     gl.copyTexSubImage2D(testCase.target, level, xoffset, yoffset, x, y, width, height);
-    error = testCase.expectedError;
-    glErrorShouldBe(gl, error, msg);
+    errors = testCase.expectedErrors;
+    wtu.glErrorShouldBeIn(gl, errors, msg);
 }
 
 function testCopyFromInternalFBO(testCase)
 {
     var target = gl.TEXTURE_2D;
     var level = 0;
     var x = 0;
     var y = 0;
@@ -154,18 +154,18 @@ function testCopyFromInternalFBO(testCas
     if (testCase.subImage) {
         gl.texImage2D(target, level, testCase.internalFormat, xoffset + width, yoffset + height, border, testCase.internalFormat, type, null);
         glErrorShouldBe(gl, gl.NO_ERROR);
         gl.copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
     } else {
         glErrorShouldBe(gl, gl.NO_ERROR);
         gl.copyTexImage2D(target, level, testCase.internalFormat, x, y, width, height, border);
     }
-    error = testCase.expectedError;
-    glErrorShouldBe(gl, error, msg);
+    errors = testCase.expectedErrors;
+    wtu.glErrorShouldBeIn(gl, errors, msg);
 }
 
 description("Validate tex functions input parameters");
 
 shouldBeNonNull("gl = create3DContext()");
 shouldBeNonNull("tex = gl.createTexture()");
 gl.bindTexture(gl.TEXTURE_2D, tex);
 glErrorShouldBe(gl, gl.NO_ERROR);
@@ -174,108 +174,108 @@ debug("");
 debug("Checking TexImage2D: a set of inputs that are valid in GL but invalid in GLES2");
 
 var testCases =
   [ {target: 0x8064, // GL_PROXY_TEXTURE_2D
      internalFormat: gl.RGBA,
      border: 0,
      format: gl.RGBA,
      type: gl.UNSIGNED_BYTE,
-     expectedError: gl.INVALID_ENUM},
+     expectedErrors: [gl.INVALID_ENUM]},
     {target: gl.TEXTURE_2D,
      internalFormat: 0x1903, // GL_RED
      border: 0,
      format: 0x1903, // GL_RED
      type: gl.UNSIGNED_BYTE,
-     expectedError: gl.INVALID_ENUM},
+     expectedErrors: [gl.INVALID_ENUM, gl.INVALID_OPERATION]},
     {target: gl.TEXTURE_2D,
      internalFormat: gl.RGBA,
      border: 1,
      format: gl.RGBA,
      type: gl.UNSIGNED_BYTE,
-     expectedError: gl.INVALID_VALUE},
+     expectedErrors: [gl.INVALID_VALUE]},
     {target: gl.TEXTURE_2D,
      internalFormat: gl.RGBA,
      border: 0,
      format: gl.RGB,
      type: gl.UNSIGNED_BYTE,
-     expectedError: gl.INVALID_OPERATION},
+     expectedErrors: [gl.INVALID_OPERATION]},
     {target: gl.TEXTURE_2D,
      internalFormat: gl.RGBA,
      border: 0,
      format: gl.RGBA,
      type: gl.BYTE,
-     expectedError: gl.INVALID_ENUM},
+     expectedErrors: [gl.INVALID_ENUM, gl.INVALID_OPERATION]},
     {target: gl.TEXTURE_2D,
      internalFormat: gl.RGBA,
      border: 0,
      format: gl.RGBA,
      type: gl.UNSIGNED_BYTE,
-     expectedError: gl.NO_ERROR} ];
+     expectedErrors: [gl.NO_ERROR]} ];
 
 for (var ii = 0; ii < testCases.length; ++ii)
     testTexImage2D(testCases[ii]);
 
 debug("");
 debug("Checking TexSubImage2D: a set of inputs that are valid in GL but invalid in GLES2");
 
 testCases =
   [ {target: gl.TEXTURE_2D,
      format: 0x1903, // GL_RED
      type: gl.UNSIGNED_BYTE,
-     expectedError: gl.INVALID_ENUM},
+     expectedErrors: [gl.INVALID_ENUM, gl.INVALID_OPERATION]},
     {target: gl.TEXTURE_2D,
      format: gl.RGBA,
      type: gl.BYTE,
-     expectedError: gl.INVALID_ENUM},
+     expectedErrors: [gl.INVALID_ENUM, gl.INVALID_OPERATION]},
     {target: gl.TEXTURE_2D,
      format: gl.RGBA,
      type: gl.UNSIGNED_BYTE,
-     expectedError: gl.NO_ERROR} ];
+     expectedErrors: [gl.NO_ERROR]} ];
 
 for (var ii = 0; ii < testCases.length; ++ii)
     testTexSubImage2D(testCases[ii]);
 
 debug("");
 debug("Checking TexParameter: a set of inputs that are valid in GL but invalid in GLES2");
 
 testCases =
   [ {target: 0x0DE0, // GL_TEXTURE_1D
      pname: gl.TEXTURE_WRAP_T,
      param: gl.REPEAT,
-     expectedError: gl.INVALID_ENUM},
+     expectedErrors: [gl.INVALID_ENUM]},
     {target: gl.TEXTURE_2D,
      pname: 0x813A, // GL_TEXTURE_MIN_LOD
      param: 0,
-     expectedError: gl.INVALID_ENUM},
+     expectedErrors: [gl.INVALID_ENUM]},
     {target: gl.TEXTURE_2D,
      pname: gl.TEXTURE_WRAP_T,
      param: 0x2900, // GL_CLAMP
-     expectedError: gl.INVALID_ENUM},
+     expectedErrors: [gl.INVALID_ENUM]},
     {target: gl.TEXTURE_2D,
      pname: gl.TEXTURE_WRAP_T,
      param: gl.REPEAT,
-     expectedError: gl.NO_ERROR} ];
+     expectedErrors: [gl.NO_ERROR]} ];
 
 for (var ii = 0; ii < testCases.length; ++ii)
     testTexParameter(testCases[ii]);
 
 debug("");
 debug("Checking GetTexParameter: a set of inputs that are valid in GL but invalid in GLES2");
 
 testCases =
   [ {target: 0x0DE0, // GL_TEXTURE_1D
      pname: gl.TEXTURE_WRAP_T,
-     expectedError: gl.INVALID_ENUM},
+     expectedErrors: [gl.INVALID_ENUM]},
     {target: gl.TEXTURE_2D,
      pname: 0x813A, // GL_TEXTURE_MIN_LOD
-     expectedError: gl.INVALID_ENUM},
+     expectedErrors: [gl.INVALID_ENUM]},
     {target: gl.TEXTURE_2D,
      pname: gl.TEXTURE_WRAP_T,
-     expectedError: gl.NO_ERROR} ];
+     expectedErrors: [gl.NO_ERROR]} ];
 
 for (var ii = 0; ii < testCases.length; ++ii)
     testGetTexParameter(testCases[ii]);
 
 debug("");
 debug("Checking CopyTexImage2D: a set of inputs that are valid in GL but invalid in GLES2");
 
 var colorBuffer = null;
@@ -288,72 +288,72 @@ gl.bindRenderbuffer(gl.RENDERBUFFER, col
 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorBuffer);
 glErrorShouldBe(gl, gl.NO_ERROR);
 
 testCases =
   [ {target: gl.TEXTURE_2D,
      colorBufferFormat: gl.RGB565,
      internalFormat: 0x8054, // GL_RGB16
      border: 0,
-     expectedError: gl.INVALID_ENUM},
+     expectedErrors: [gl.INVALID_ENUM]},
     {target: gl.TEXTURE_2D,
      colorBufferFormat: gl.RGB565,
      internalFormat: gl.RGBA,
      border: 1,
-     expectedError: gl.INVALID_VALUE},
+     expectedErrors: [gl.INVALID_VALUE]},
     {target: gl.TEXTURE_2D,
      colorBufferFormat: gl.RGB565,
      internalFormat: gl.RGBA,
      border: 0,
-     expectedError: gl.INVALID_OPERATION},
+     expectedErrors: [gl.INVALID_OPERATION]},
     {target: gl.TEXTURE_2D,
      colorBufferFormat: gl.RGB565,
      internalFormat: gl.RGB,
      border: 0,
-     expectedError: gl.NO_ERROR} ];
+     expectedErrors: [gl.NO_ERROR]} ];
 
 for (var ii = 0; ii < testCases.length; ++ii)
     testCopyTexImage2D(testCases[ii]);
 
 debug("");
 debug("Checking CopyTexSubImage2D: a set of inputs that are valid in GL but invalid in GLES2");
 
 testCases =
   [ {target: gl.TEXTURE_2D,
      colorBufferFormat: gl.RGB5_A1,
      internalFormat: gl.RGBA,
-     expectedError: gl.NO_ERROR},
+     expectedErrors: [gl.NO_ERROR]},
     {target: gl.TEXTURE_2D,
      colorBufferFormat: gl.RGB565,
      internalFormat: gl.RGBA,
-     expectedError: gl.INVALID_OPERATION} ];
+     expectedErrors: [gl.INVALID_OPERATION]} ];
 
 for (var ii = 0; ii < testCases.length; ++ii)
     testCopyTexSubImage2D(testCases[ii]);
 
 debug("");
 debug("Checking CopyTex{Sub}Image2D: copy from WebGL internal framebuffer");
 
 testCases =
   [ {contextAlpha: true,
      internalFormat: gl.RGBA,
      subImage: false,
-     expectedError: gl.NO_ERROR},
+     expectedErrors: [gl.NO_ERROR]},
     {contextAlpha: false,
      internalFormat: gl.RGBA,
      subImage: false,
-     expectedError: gl.INVALID_OPERATION},
+     expectedErrors: [gl.INVALID_OPERATION]},
     {contextAlpha: true,
      internalFormat: gl.RGBA,
      subImage: true,
-     expectedError: gl.NO_ERROR},
+     expectedErrors: [gl.NO_ERROR]},
     {contextAlpha: false,
      internalFormat: gl.RGBA,
      subImage: true,
-     expectedError: gl.INVALID_OPERATION} ];
+     expectedErrors: [gl.INVALID_OPERATION]} ];
 
 for (var ii = 0; ii < testCases.length; ++ii)
     testCopyFromInternalFBO(testCases[ii]);
 
 successfullyParsed = true;
 </script>
 
 <script>finishTest();</script>
--- a/dom/canvas/test/webgl-conformance/conformance/textures/texture-formats-test.html
+++ b/dom/canvas/test/webgl-conformance/conformance/textures/texture-formats-test.html
@@ -61,19 +61,19 @@ if (!gl) {
                 "was able to create texture of " + formatName);
   }
 
   function testInvalidFormat(internalFormat, formatName) {
       createTexture(internalFormat, internalFormat);
       var err = gl.getError();
       if (err == gl.NO_ERROR) {
           testFailed("should NOT be able to create texture of type " + formatName);
-      } else if (err == gl.INVALID_OPERATION) {
-          testFailed("should return gl.INVALID_ENUM for type " + formatName);
-      } else if (err == gl.INVALID_ENUM) {
+      } else if (err == gl.INVALID_ENUM ||
+                 err == gl.INVALID_OPERATION)
+      {
           testPassed("not able to create invalid format: " + formatName);
       }
   }
 
   var invalidEnums = [
     '1',
     '2',
     '3',