diff --git a/content/canvas/src/WebGLContext.h b/content/canvas/src/WebGLContext.h index 1b3fd3e1301..664ac701f2e 100644 --- a/content/canvas/src/WebGLContext.h +++ b/content/canvas/src/WebGLContext.h @@ -290,6 +290,9 @@ public: nsresult ErrorInvalidEnum(const char *fmt = 0, ...); nsresult ErrorInvalidOperation(const char *fmt = 0, ...); nsresult ErrorInvalidValue(const char *fmt = 0, ...); + nsresult ErrorInvalidEnumInfo(const char *info) { + return ErrorInvalidEnum("%s: invalid enum value", info); + } already_AddRefed GetCanvasLayer(LayerManager *manager); void MarkContextClean() { } @@ -316,14 +319,16 @@ protected: PRBool SafeToCreateCanvas3DContext(nsHTMLCanvasElement *canvasElement); PRBool InitAndValidateGL(); PRBool ValidateBuffers(PRUint32 count); - static PRBool ValidateCapabilityEnum(WebGLenum cap); - static PRBool ValidateBlendEquationEnum(WebGLuint cap); - static PRBool ValidateBlendFuncDstEnum(WebGLuint mode); - static PRBool ValidateBlendFuncSrcEnum(WebGLuint mode); - static PRBool ValidateTextureTargetEnum(WebGLenum target); - static PRBool ValidateComparisonEnum(WebGLenum target); - static PRBool ValidateStencilOpEnum(WebGLenum action); - static PRBool ValidateFaceEnum(WebGLenum target); + PRBool ValidateCapabilityEnum(WebGLenum cap, const char *info); + PRBool ValidateBlendEquationEnum(WebGLuint cap, const char *info); + PRBool ValidateBlendFuncDstEnum(WebGLuint mode, const char *info); + PRBool ValidateBlendFuncSrcEnum(WebGLuint mode, const char *info); + PRBool ValidateTextureTargetEnum(WebGLenum target, const char *info); + PRBool ValidateComparisonEnum(WebGLenum target, const char *info); + PRBool ValidateStencilOpEnum(WebGLenum action, const char *info); + PRBool ValidateFaceEnum(WebGLenum target, const char *info); + PRBool ValidateTexFormatAndType(WebGLenum format, WebGLenum type, + PRUint32 *texelSize, const char *info); void Invalidate(); diff --git a/content/canvas/src/WebGLContextGL.cpp b/content/canvas/src/WebGLContextGL.cpp index 3c5b0a684af..dd1dcc6f4d1 100644 --- a/content/canvas/src/WebGLContextGL.cpp +++ b/content/canvas/src/WebGLContextGL.cpp @@ -296,8 +296,8 @@ GL_SAME_METHOD_4(BlendColor, BlendColor, float, float, float, float) NS_IMETHODIMP WebGLContext::BlendEquation(WebGLenum mode) { - if (!ValidateBlendEquationEnum(mode)) - return ErrorInvalidEnum("BlendEquation: invalid mode"); + if (!ValidateBlendEquationEnum(mode, "blendEquation: mode")) + return NS_OK; MakeContextCurrent(); gl->fBlendEquation(mode); @@ -306,9 +306,9 @@ NS_IMETHODIMP WebGLContext::BlendEquation(WebGLenum mode) NS_IMETHODIMP WebGLContext::BlendEquationSeparate(WebGLenum modeRGB, WebGLenum modeAlpha) { - if (!ValidateBlendEquationEnum(modeRGB) || - !ValidateBlendEquationEnum(modeAlpha)) - return ErrorInvalidEnum("BlendEquationSeparate: invalid mode"); + if (!ValidateBlendEquationEnum(modeRGB, "blendEquationSeparate: modeRGB") || + !ValidateBlendEquationEnum(modeAlpha, "blendEquationSeparate: modeAlpha")) + return NS_OK; MakeContextCurrent(); gl->fBlendEquationSeparate(modeRGB, modeAlpha); @@ -317,10 +317,9 @@ NS_IMETHODIMP WebGLContext::BlendEquationSeparate(WebGLenum modeRGB, WebGLenum m NS_IMETHODIMP WebGLContext::BlendFunc(WebGLenum sfactor, WebGLenum dfactor) { - if (!ValidateBlendFuncSrcEnum(sfactor)) - return ErrorInvalidEnum("BlendFunc: invalid source factor"); - if (!ValidateBlendFuncDstEnum(dfactor)) - return ErrorInvalidEnum("BlendFunc: invalid destination factor"); + if (!ValidateBlendFuncSrcEnum(sfactor, "blendFunc: sfactor") || + !ValidateBlendFuncDstEnum(dfactor, "blendFunc: dfactor")) + return NS_OK; MakeContextCurrent(); gl->fBlendFunc(sfactor, dfactor); @@ -331,12 +330,11 @@ NS_IMETHODIMP WebGLContext::BlendFuncSeparate(WebGLenum srcRGB, WebGLenum dstRGB, WebGLenum srcAlpha, WebGLenum dstAlpha) { - if (!ValidateBlendFuncSrcEnum(srcRGB) || - !ValidateBlendFuncSrcEnum(srcAlpha)) - return ErrorInvalidEnum("BlendFuncSeparate: invalid source factor"); - if (!ValidateBlendFuncDstEnum(dstRGB) || - !ValidateBlendFuncDstEnum(dstAlpha)) - return ErrorInvalidEnum("BlendFuncSeparate: invalid destination factor"); + if (!ValidateBlendFuncSrcEnum(srcRGB, "blendFuncSeparate: srcRGB") || + !ValidateBlendFuncSrcEnum(srcAlpha, "blendFuncSeparate: srcAlpha") || + !ValidateBlendFuncDstEnum(dstRGB, "blendFuncSeparate: dstRGB") || + !ValidateBlendFuncDstEnum(dstAlpha, "blendFuncSeparate: dstAlpha")) + return NS_OK; MakeContextCurrent(); gl->fBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); @@ -807,8 +805,8 @@ WebGLContext::DetachShader(nsIWebGLProgram *pobj, nsIWebGLShader *shobj) NS_IMETHODIMP WebGLContext::DepthFunc(WebGLenum func) { - if (!ValidateComparisonEnum(func)) - return ErrorInvalidEnum("DepthFunc: invalid function enum"); + if (!ValidateComparisonEnum(func, "depthFunc")) + return NS_OK; MakeContextCurrent(); gl->fDepthFunc(func); @@ -955,8 +953,8 @@ WebGLContext::DrawElements(WebGLenum mode, WebGLsizei count, WebGLenum type, Web NS_IMETHODIMP WebGLContext::Enable(WebGLenum cap) { - if (!ValidateCapabilityEnum(cap)) - return ErrorInvalidEnum("Enable: invalid capability enum"); + if (!ValidateCapabilityEnum(cap, "enable")) + return NS_OK; MakeContextCurrent(); gl->fEnable(cap); @@ -965,8 +963,8 @@ NS_IMETHODIMP WebGLContext::Enable(WebGLenum cap) NS_IMETHODIMP WebGLContext::Disable(WebGLenum cap) { - if (!ValidateCapabilityEnum(cap)) - return ErrorInvalidEnum("Disable: invalid capability enum"); + if (!ValidateCapabilityEnum(cap, "disable")) + return NS_OK; MakeContextCurrent(); gl->fDisable(cap); @@ -1131,8 +1129,8 @@ WebGLContext::GetActiveAttrib(nsIWebGLProgram *pobj, PRUint32 index, nsIWebGLAct NS_IMETHODIMP WebGLContext::GenerateMipmap(WebGLenum target) { - if (!ValidateTextureTargetEnum(target)) - return ErrorInvalidEnum("GenerateMipmap: invalid target"); + if (!ValidateTextureTargetEnum(target, "generateMipmap")) + return NS_OK; MakeContextCurrent(); gl->fGenerateMipmap(target); @@ -1855,8 +1853,8 @@ WebGLContext::GetTexParameter(WebGLenum target, WebGLenum pname, nsIVariant **re MakeContextCurrent(); - if (!ValidateTextureTargetEnum(target)) - return ErrorInvalidEnum("GetTexParameter: invalid target"); + if (!ValidateTextureTargetEnum(target, "getTexParameter: target")) + return NS_OK; switch (pname) { case LOCAL_GL_TEXTURE_MIN_FILTER: @@ -1871,7 +1869,7 @@ WebGLContext::GetTexParameter(WebGLenum target, WebGLenum pname, nsIVariant **re break; default: - return ErrorInvalidEnum("GetTexParameter: invalid parameter"); + return ErrorInvalidEnum("getTexParameter: invalid parameter"); } *retval = wrval.forget().get(); @@ -2109,9 +2107,9 @@ WebGLContext::IsTexture(nsIWebGLTexture *tobj, WebGLboolean *retval) NS_IMETHODIMP WebGLContext::IsEnabled(WebGLenum cap, WebGLboolean *retval) { - if (!ValidateCapabilityEnum(cap)) { + if (!ValidateCapabilityEnum(cap, "isEnabled")) { *retval = 0; // as per the OpenGL ES spec - return ErrorInvalidEnum("IsEnabled: invalid capability enum"); + return NS_OK; } MakeContextCurrent(); @@ -2413,8 +2411,8 @@ WebGLContext::Scissor(WebGLint x, WebGLint y, WebGLsizei width, WebGLsizei heigh NS_IMETHODIMP WebGLContext::StencilFunc(WebGLenum func, WebGLint ref, WebGLuint mask) { - if (!ValidateComparisonEnum(func)) - return ErrorInvalidEnum("StencilFunc: invalid function enum"); + if (!ValidateComparisonEnum(func, "stencilFunc: func")) + return NS_OK; MakeContextCurrent(); gl->fStencilFunc(func, ref, mask); @@ -2424,10 +2422,9 @@ WebGLContext::StencilFunc(WebGLenum func, WebGLint ref, WebGLuint mask) NS_IMETHODIMP WebGLContext::StencilFuncSeparate(WebGLenum face, WebGLenum func, WebGLint ref, WebGLuint mask) { - if (!ValidateFaceEnum(face)) - return ErrorInvalidEnum("StencilFuncSeparate: invalid face enum"); - if (!ValidateComparisonEnum(func)) - return ErrorInvalidEnum("StencilFuncSeparate: invalid function enum"); + if (!ValidateFaceEnum(face, "stencilFuncSeparate: face") || + !ValidateComparisonEnum(func, "stencilFuncSeparate: func")) + return NS_OK; MakeContextCurrent(); gl->fStencilFuncSeparate(face, func, ref, mask); @@ -2439,8 +2436,8 @@ GL_SAME_METHOD_1(StencilMask, StencilMask, WebGLuint) NS_IMETHODIMP WebGLContext::StencilMaskSeparate(WebGLenum face, WebGLuint mask) { - if (!ValidateFaceEnum(face)) - return ErrorInvalidEnum("StencilFuncSeparate: invalid face enum"); + if (!ValidateFaceEnum(face, "stencilMaskSeparate: face")) + return NS_OK; MakeContextCurrent(); gl->fStencilMaskSeparate(face, mask); @@ -2450,10 +2447,10 @@ WebGLContext::StencilMaskSeparate(WebGLenum face, WebGLuint mask) NS_IMETHODIMP WebGLContext::StencilOp(WebGLenum sfail, WebGLenum dpfail, WebGLenum dppass) { - if (!ValidateStencilOpEnum(sfail) || - !ValidateStencilOpEnum(dpfail) || - !ValidateStencilOpEnum(dppass)) - return ErrorInvalidEnum("StencilOp: invalid action enum"); + if (!ValidateStencilOpEnum(sfail, "stencilOp: sfail") || + !ValidateStencilOpEnum(dpfail, "stencilOp: dpfail") || + !ValidateStencilOpEnum(dppass, "stencilOp: dppass")) + return NS_OK; MakeContextCurrent(); gl->fStencilOp(sfail, dpfail, dppass); @@ -2463,13 +2460,11 @@ WebGLContext::StencilOp(WebGLenum sfail, WebGLenum dpfail, WebGLenum dppass) NS_IMETHODIMP WebGLContext::StencilOpSeparate(WebGLenum face, WebGLenum sfail, WebGLenum dpfail, WebGLenum dppass) { - if (!ValidateFaceEnum(face)) - return ErrorInvalidEnum("StencilOpSeparate: invalid face enum"); - - if (!ValidateStencilOpEnum(sfail) || - !ValidateStencilOpEnum(dpfail) || - !ValidateStencilOpEnum(dppass)) - return ErrorInvalidEnum("StencilOpSeparate: invalid action enum"); + if (!ValidateFaceEnum(face, "stencilOpSeparate: face") || + !ValidateStencilOpEnum(sfail, "stencilOpSeparate: sfail") || + !ValidateStencilOpEnum(dpfail, "stencilOpSeparate: dpfail") || + !ValidateStencilOpEnum(dppass, "stencilOpSeparate: dppass")) + return NS_OK; MakeContextCurrent(); gl->fStencilOpSeparate(face, sfail, dpfail, dppass); @@ -3013,7 +3008,7 @@ WebGLContext::TexImage2D_base(WebGLenum target, WebGLint level, WebGLenum intern case LOCAL_GL_LUMINANCE_ALPHA: break; default: - return ErrorInvalidValue("TexImage2D: internal format not supported"); + return ErrorInvalidEnum("TexImage2D: invalid internal format"); } if (width < 0 || height < 0) @@ -3022,53 +3017,12 @@ WebGLContext::TexImage2D_base(WebGLenum target, WebGLint level, WebGLenum intern if (border != 0) return ErrorInvalidValue("TexImage2D: border must be 0"); - // number of bytes per pixel - uint32 bufferPixelSize = 0; - switch (format) { - case LOCAL_GL_RED: - case LOCAL_GL_GREEN: - case LOCAL_GL_BLUE: - case LOCAL_GL_ALPHA: - case LOCAL_GL_LUMINANCE: - bufferPixelSize = 1; - break; - case LOCAL_GL_LUMINANCE_ALPHA: - bufferPixelSize = 2; - break; - case LOCAL_GL_RGB: - bufferPixelSize = 3; - break; - case LOCAL_GL_RGBA: - bufferPixelSize = 4; - break; - default: - return ErrorInvalidEnum("TexImage2D: pixel format not supported"); - } - - switch (type) { - case LOCAL_GL_BYTE: - case LOCAL_GL_UNSIGNED_BYTE: - break; - case LOCAL_GL_SHORT: - case LOCAL_GL_UNSIGNED_SHORT: - bufferPixelSize *= 2; - break; - case LOCAL_GL_INT: - case LOCAL_GL_UNSIGNED_INT: - case LOCAL_GL_FLOAT: - bufferPixelSize *= 4; - break; - case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4: - case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1: - case LOCAL_GL_UNSIGNED_SHORT_5_6_5: - bufferPixelSize *= 2; - break; - default: - return ErrorInvalidEnum("TexImage2D: invalid type argument"); - } + PRUint32 texelSize = 0; + if (!ValidateTexFormatAndType(format, type, &texelSize, "texImage2D")) + return NS_OK; // XXX overflow! - uint32 bytesNeeded = width * height * bufferPixelSize; + uint32 bytesNeeded = width * height * texelSize; if (byteLength && byteLength < bytesNeeded) return ErrorInvalidValue("TexImage2D: not enough data for operation (need %d, have %d)", @@ -3193,56 +3147,15 @@ WebGLContext::TexSubImage2D_base(WebGLenum target, WebGLint level, if (width < 0 || height < 0) return ErrorInvalidValue("TexSubImage2D: width and height must be > 0!"); + PRUint32 texelSize = 0; + if (!ValidateTexFormatAndType(format, type, &texelSize, "texSubImage2D")) + return NS_OK; + if (width == 0 || height == 0) return NS_OK; // ES 2.0 says it has no effect, we better return right now - // number of bytes per pixel - uint32 bufferPixelSize = 0; - switch (format) { - case LOCAL_GL_RED: - case LOCAL_GL_GREEN: - case LOCAL_GL_BLUE: - case LOCAL_GL_ALPHA: - case LOCAL_GL_LUMINANCE: - bufferPixelSize = 1; - break; - case LOCAL_GL_LUMINANCE_ALPHA: - bufferPixelSize = 2; - break; - case LOCAL_GL_RGB: - bufferPixelSize = 3; - break; - case LOCAL_GL_RGBA: - bufferPixelSize = 4; - break; - default: - return ErrorInvalidEnum("TexImage2D: pixel format not supported"); - } - - switch (type) { - case LOCAL_GL_BYTE: - case LOCAL_GL_UNSIGNED_BYTE: - break; - case LOCAL_GL_SHORT: - case LOCAL_GL_UNSIGNED_SHORT: - bufferPixelSize *= 2; - break; - case LOCAL_GL_INT: - case LOCAL_GL_UNSIGNED_INT: - case LOCAL_GL_FLOAT: - bufferPixelSize *= 4; - break; - case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4: - case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1: - case LOCAL_GL_UNSIGNED_SHORT_5_6_5: - bufferPixelSize *= 2; - break; - default: - return ErrorInvalidEnum("TexImage2D: invalid type argument"); - } - // XXX overflow! - uint32 bytesNeeded = width * height * bufferPixelSize; + uint32 bytesNeeded = width * height * texelSize; if (byteLength < bytesNeeded) return ErrorInvalidValue("TexSubImage2D: not enough data for operation (need %d, have %d)", bytesNeeded, byteLength); diff --git a/content/canvas/src/WebGLContextValidate.cpp b/content/canvas/src/WebGLContextValidate.cpp index 022afd28e1d..9ea42705323 100644 --- a/content/canvas/src/WebGLContextValidate.cpp +++ b/content/canvas/src/WebGLContextValidate.cpp @@ -125,7 +125,7 @@ WebGLContext::ValidateBuffers(PRUint32 count) return PR_TRUE; } -PRBool WebGLContext::ValidateCapabilityEnum(WebGLenum cap) +PRBool WebGLContext::ValidateCapabilityEnum(WebGLenum cap, const char *info) { switch (cap) { case LOCAL_GL_BLEND: @@ -139,11 +139,12 @@ PRBool WebGLContext::ValidateCapabilityEnum(WebGLenum cap) case LOCAL_GL_STENCIL_TEST: return PR_TRUE; default: + ErrorInvalidEnumInfo(info); return PR_FALSE; } } -PRBool WebGLContext::ValidateBlendEquationEnum(WebGLenum mode) +PRBool WebGLContext::ValidateBlendEquationEnum(WebGLenum mode, const char *info) { switch (mode) { case LOCAL_GL_FUNC_ADD: @@ -151,11 +152,12 @@ PRBool WebGLContext::ValidateBlendEquationEnum(WebGLenum mode) case LOCAL_GL_FUNC_REVERSE_SUBTRACT: return PR_TRUE; default: + ErrorInvalidEnumInfo(info); return PR_FALSE; } } -PRBool WebGLContext::ValidateBlendFuncDstEnum(WebGLenum factor) +PRBool WebGLContext::ValidateBlendFuncDstEnum(WebGLenum factor, const char *info) { switch (factor) { case LOCAL_GL_ZERO: @@ -174,30 +176,32 @@ PRBool WebGLContext::ValidateBlendFuncDstEnum(WebGLenum factor) case LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA: return PR_TRUE; default: + ErrorInvalidEnumInfo(info); return PR_FALSE; } } -PRBool WebGLContext::ValidateBlendFuncSrcEnum(WebGLenum factor) +PRBool WebGLContext::ValidateBlendFuncSrcEnum(WebGLenum factor, const char *info) { - if(factor == LOCAL_GL_SRC_ALPHA_SATURATE) + if (factor == LOCAL_GL_SRC_ALPHA_SATURATE) return PR_TRUE; else - return ValidateBlendFuncDstEnum(factor); + return ValidateBlendFuncDstEnum(factor, info); } -PRBool WebGLContext::ValidateTextureTargetEnum(WebGLenum target) +PRBool WebGLContext::ValidateTextureTargetEnum(WebGLenum target, const char *info) { switch (target) { case LOCAL_GL_TEXTURE_2D: case LOCAL_GL_TEXTURE_CUBE_MAP: return PR_TRUE; default: + ErrorInvalidEnumInfo(info); return PR_FALSE; } } -PRBool WebGLContext::ValidateComparisonEnum(WebGLenum target) +PRBool WebGLContext::ValidateComparisonEnum(WebGLenum target, const char *info) { switch (target) { case LOCAL_GL_NEVER: @@ -210,11 +214,12 @@ PRBool WebGLContext::ValidateComparisonEnum(WebGLenum target) case LOCAL_GL_ALWAYS: return PR_TRUE; default: + ErrorInvalidEnumInfo(info); return PR_FALSE; } } -PRBool WebGLContext::ValidateStencilOpEnum(WebGLenum action) +PRBool WebGLContext::ValidateStencilOpEnum(WebGLenum action, const char *info) { switch (action) { case LOCAL_GL_KEEP: @@ -227,11 +232,12 @@ PRBool WebGLContext::ValidateStencilOpEnum(WebGLenum action) case LOCAL_GL_INVERT: return PR_TRUE; default: + ErrorInvalidEnumInfo(info); return PR_FALSE; } } -PRBool WebGLContext::ValidateFaceEnum(WebGLenum target) +PRBool WebGLContext::ValidateFaceEnum(WebGLenum target, const char *info) { switch (target) { case LOCAL_GL_FRONT: @@ -239,10 +245,63 @@ PRBool WebGLContext::ValidateFaceEnum(WebGLenum target) case LOCAL_GL_FRONT_AND_BACK: return PR_TRUE; default: + ErrorInvalidEnumInfo(info); return PR_FALSE; } } +PRBool WebGLContext::ValidateTexFormatAndType(WebGLenum format, WebGLenum type, + PRUint32 *texelSize, const char *info) +{ + if (type == LOCAL_GL_UNSIGNED_BYTE) + { + switch (format) { + case LOCAL_GL_RED: + case LOCAL_GL_GREEN: + case LOCAL_GL_BLUE: + case LOCAL_GL_ALPHA: + case LOCAL_GL_LUMINANCE: + *texelSize = 1; + return PR_TRUE; + case LOCAL_GL_LUMINANCE_ALPHA: + *texelSize = 2; + return PR_TRUE; + case LOCAL_GL_RGB: + *texelSize = 3; + return PR_TRUE; + case LOCAL_GL_RGBA: + *texelSize = 4; + return PR_TRUE; + default: + ErrorInvalidEnum("%s: invalid format", info); + return PR_FALSE; + } + } else { + switch (type) { + case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4: + case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1: + if (format == LOCAL_GL_RGBA) { + *texelSize = 2; + return PR_TRUE; + } else { + ErrorInvalidOperation("%s: mutually incompatible format and type", info); + return PR_FALSE; + } + case LOCAL_GL_UNSIGNED_SHORT_5_6_5: + if (format == LOCAL_GL_RGB) { + *texelSize = 2; + return PR_TRUE; + } else { + ErrorInvalidOperation("%s: mutually incompatible format and type", info); + return PR_FALSE; + } + default: + ErrorInvalidEnum("%s: invalid type", info); + return PR_FALSE; + } + } +} + PRBool WebGLContext::InitAndValidateGL() {