diff --git a/content/canvas/src/WebGLContext.h b/content/canvas/src/WebGLContext.h index d2b2d0d21f8b..1fa253668859 100644 --- a/content/canvas/src/WebGLContext.h +++ b/content/canvas/src/WebGLContext.h @@ -127,9 +127,10 @@ struct WebGLTexelPremultiplicationOp { int GetWebGLTexelFormat(GLenum format, GLenum type); +// Zero is not an integer power of two. inline bool is_pot_assuming_nonnegative(WebGLsizei x) { - return (x & (x-1)) == 0; + return x && (x & (x-1)) == 0; } /* Each WebGL object class WebGLFoo wants to: @@ -585,6 +586,7 @@ public: nsresult ErrorOutOfMemory(const char *fmt = 0, ...); const char *ErrorName(GLenum error); + bool IsTextureFormatCompressed(GLenum format); nsresult DummyFramebufferOperation(const char *info); @@ -1247,14 +1249,26 @@ public: class ImageInfo : public WebGLRectangleObject { public: - ImageInfo() : mFormat(0), mType(0), mIsDefined(false) {} + ImageInfo() + : mFormat(0) + , mType(0) + , mIsDefined(false) + {} + ImageInfo(WebGLsizei width, WebGLsizei height, WebGLenum format, WebGLenum type) - : WebGLRectangleObject(width, height), mFormat(format), mType(type), mIsDefined(true) {} + : WebGLRectangleObject(width, height) + , mFormat(format) + , mType(type) + , mIsDefined(true) + {} bool operator==(const ImageInfo& a) const { - return mWidth == a.mWidth && mHeight == a.mHeight && - mFormat == a.mFormat && mType == a.mType; + return mIsDefined == a.mIsDefined && + mWidth == a.mWidth && + mHeight == a.mHeight && + mFormat == a.mFormat && + mType == a.mType; } bool operator!=(const ImageInfo& a) const { return !(*this == a); diff --git a/content/canvas/src/WebGLContextGL.cpp b/content/canvas/src/WebGLContextGL.cpp index 13365d8684d1..8532c7d83c30 100644 --- a/content/canvas/src/WebGLContextGL.cpp +++ b/content/canvas/src/WebGLContextGL.cpp @@ -1911,15 +1911,20 @@ WebGLContext::GenerateMipmap(WebGLenum target) WebGLTexture *tex = activeBoundTextureForTarget(target); if (!tex) - return ErrorInvalidOperation("generateMipmap: no texture is bound to this target"); + return ErrorInvalidOperation("generateMipmap: No texture is bound to this target."); - if (!tex->IsFirstImagePowerOfTwo()) { - return ErrorInvalidOperation("generateMipmap: the width or height of this texture is not a power of two"); - } + if (!tex->HasImageInfoAt(0, 0)) + return ErrorInvalidOperation("generateMipmap: Level zero of texture is not defined."); - if (!tex->AreAllLevel0ImageInfosEqual()) { - return ErrorInvalidOperation("generateMipmap: the six faces of this cube map have different dimensions, format, or type."); - } + if (!tex->IsFirstImagePowerOfTwo()) + return ErrorInvalidOperation("generateMipmap: Level zero of texture does not have power-of-two width and height."); + + GLenum format = tex->ImageInfoAt(0, 0).Format(); + if (IsTextureFormatCompressed(format)) + return ErrorInvalidOperation("generateMipmap: Texture data at level zero is compressed."); + + if (!tex->AreAllLevel0ImageInfosEqual()) + return ErrorInvalidOperation("generateMipmap: The six faces of this cube map have different dimensions, format, or type."); tex->SetGeneratedMipmap(); diff --git a/content/canvas/src/WebGLContextUtils.cpp b/content/canvas/src/WebGLContextUtils.cpp index 898fb9a05fea..f448fe138eb7 100644 --- a/content/canvas/src/WebGLContextUtils.cpp +++ b/content/canvas/src/WebGLContextUtils.cpp @@ -239,4 +239,27 @@ WebGLContext::ErrorName(GLenum error) NS_ABORT(); return "[unknown WebGL error!]"; } -}; +} + +bool +WebGLContext::IsTextureFormatCompressed(GLenum format) +{ + switch(format) { + case LOCAL_GL_RGB: + case LOCAL_GL_RGBA: + case LOCAL_GL_ALPHA: + case LOCAL_GL_LUMINANCE: + case LOCAL_GL_LUMINANCE_ALPHA: + return false; + + case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: + case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: + return true; + } + + NS_NOTREACHED("Invalid WebGL texture format?"); + NS_ABORT(); + return false; +}