From 8b8423f08ccea96429412f170673573a88bde9d2 Mon Sep 17 00:00:00 2001 From: Mark Steele Date: Sun, 1 Nov 2009 16:33:47 -0800 Subject: [PATCH] b=524042, [webgl] texImage & texSubImage need to support flipY, r=vlad --- content/canvas/src/WebGLContext.h | 3 +- content/canvas/src/WebGLContextGL.cpp | 365 +++++++++++++------------- 2 files changed, 187 insertions(+), 181 deletions(-) diff --git a/content/canvas/src/WebGLContext.h b/content/canvas/src/WebGLContext.h index 5feda3da3b19..2eb14de53b92 100644 --- a/content/canvas/src/WebGLContext.h +++ b/content/canvas/src/WebGLContext.h @@ -265,7 +265,8 @@ protected: void MakeContextCurrent() { mGLPbuffer->MakeContextCurrent(); } nsresult TexImageElementBase(nsIDOMHTMLElement *imageOrCanvas, - gfxImageSurface **imageOut); + gfxImageSurface **imageOut, + bool flipY, bool premultiplyAlpha); GLuint mActiveTexture; diff --git a/content/canvas/src/WebGLContextGL.cpp b/content/canvas/src/WebGLContextGL.cpp index a8ed4b501fce..84a2fdbfbcb9 100644 --- a/content/canvas/src/WebGLContextGL.cpp +++ b/content/canvas/src/WebGLContextGL.cpp @@ -2334,7 +2334,8 @@ GL_SAME_METHOD_4(StencilOpSeparate, StencilOpSeparate, GLenum, GLenum, GLenum, G nsresult WebGLContext::TexImageElementBase(nsIDOMHTMLElement *imageOrCanvas, - gfxImageSurface **imageOut) + gfxImageSurface **imageOut, + bool flipY, bool premultiplyAlpha) { gfxImageSurface *surf = nsnull; @@ -2426,86 +2427,37 @@ WebGLContext::TexImageElementBase(nsIDOMHTMLElement *imageOrCanvas, return NS_ERROR_FAILURE; } + if (flipY) { + nsRefPtr tmpsurf = new gfxImageSurface(res.mSize, + gfxASurface::ImageFormatARGB32); + if (!tmpsurf || tmpsurf->CairoStatus()) + return NS_ERROR_FAILURE; + + nsRefPtr tmpctx = new gfxContext(tmpsurf); + + if (!tmpctx || tmpctx->HasError()) + return NS_ERROR_FAILURE; + + tmpctx->Translate(gfxPoint(0, res.mSize.height)); + tmpctx->Scale(1.0, -1.0); + + tmpctx->NewPath(); + tmpctx->Rectangle(gfxRect(0, 0, res.mSize.width, res.mSize.height)); + + tmpctx->SetSource(res.mSurface); + tmpctx->SetOperator(gfxContext::OPERATOR_SOURCE); + tmpctx->Fill(); + + NS_ADDREF(surf = tmpsurf); + tmpctx = nsnull; + } + res.mSurface.forget(); *imageOut = surf; return NS_OK; } -#if 0 -NS_IMETHODIMP -WebGLContext::TexSubImage2DHTML(PRUint32 target, PRUint32 level, PRInt32 x, PRInt32 y, nsIDOMHTMLElement *imageOrCanvas) -{ - - NativeJSContext js; - if (NS_FAILED(js.error)) - return js.error; - - switch (target) { - case LOCAL_GL_TEXTURE_2D: - case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X: - case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X: - case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y: - case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: - case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z: - case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - break; - default: - return ErrorMessage("texImage2DHTML: unsupported target"); - } - - nsRefPtr isurf; - nsresult rv; - - rv = TexImageElementBase(imageOrCanvas, - getter_AddRefs(isurf)); - if (NS_FAILED(rv)) - return rv; - - MakeContextCurrent(); - - gl->fTexSubImage2D(target, level, x, y, isurf->Width(), isurf->Height(), LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, isurf->Data()); - - return NS_OK; -} - -NS_IMETHODIMP -WebGLContext::TexImage2DHTML(PRUint32 target, PRUint32 level, nsIDOMHTMLElement *imageOrCanvas) -{ - NativeJSContext js; - if (NS_FAILED(js.error)) - return js.error; - - switch (target) { - case LOCAL_GL_TEXTURE_2D: - case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X: - case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X: - case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y: - case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: - case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z: - case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - break; - default: - return ErrorMessage("texImage2DHTML: unsupported target"); - } - - nsRefPtr isurf; - nsresult rv; - - rv = TexImageElementBase(imageOrCanvas, - getter_AddRefs(isurf)); - if (NS_FAILED(rv)) - return rv; - - MakeContextCurrent(); - - gl->fTexImage2D(target, level, LOCAL_GL_RGBA, isurf->Width(), isurf->Height(), 0, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, isurf->Data()); - - return NS_OK; -} - -#endif /* XXX todo */ - GL_SAME_METHOD_2(Uniform1i, Uniform1i, GLint, GLint) GL_SAME_METHOD_3(Uniform2i, Uniform2i, GLint, GLint, GLint) GL_SAME_METHOD_4(Uniform3i, Uniform3i, GLint, GLint, GLint, GLint) @@ -2946,142 +2898,196 @@ WebGLContext::ValidateGL() NS_IMETHODIMP WebGLContext::TexSubImage2D() { - // XXX TODO - return NS_ERROR_FAILURE; + // void texSubImage2D(in GLenum target, in GLint level, in GLint xoffset, in GLint yoffset, + // in GLsizei width, in GLsizei height, + // in GLenum format, in GLenum type, in CanvasArray pixels) + // void texSubImage2D(in GLenum target, in GLint level, in GLint xoffset, in GLint yoffset, + // in ImageData pixels, + // [Optional] GLboolean flipY, [Optional] in asPremultipliedAlpha) + // void texSubImage2D(in GLenum target, in GLint level, in GLint xoffset, in GLint yoffset, + // in HTMLImageElement image, + // [Optional] GLboolean flipY, [Optional] in asPremultipliedAlpha) + // void texSubImage2D(in GLenum target, in GLint level, in GLint xoffset, in GLint yoffset, + // in HTMLCanvasElement image, + // [Optional] GLboolean flipY, [Optional] in asPremultipliedAlpha) + // void texSubImage2D(in GLenum target, in GLint level, in GLint xoffset, in GLint yoffset, + // in HTMLVideoElement image, + // [Optional] GLboolean flipY, [Optional] in asPremultipliedAlpha) -#if 0 + // XXX TODO NativeJSContext js; if (NS_FAILED(js.error)) return js.error; - if (js.argc != 9) { - return ErrorMessage("texSubImage2D: expected 9 arguments"); + if (js.argc < 5 || js.argc > 9) { + return ErrorMessage("texSubImage2D: expected 5 to 9 arguments"); return NS_ERROR_DOM_SYNTAX_ERR; } - jsuint argTarget, argLevel, argX, argY, argWidth, argHeight, argFormat, argType; - JSObject *argPixelsObj; - jsuint argPixelsLen; - if (!::JS_ConvertArguments(js.ctx, js.argc, js.argv, "uuuuuuuuo", - &argTarget, &argLevel, &argX, &argY, - &argWidth, &argHeight, &argFormat, &argType, - &argPixelsObj) || - !argPixelsObj || - !::JS_IsArrayObject(js.ctx, argPixelsObj) || - !::JS_GetArrayLength(js.ctx, argPixelsObj, &argPixelsLen)) - { - return ErrorMessage("texSubImage2D: argument error"); - return NS_ERROR_DOM_SYNTAX_ERR; - } + if (js.argc < 8) { + jsuint argTarget, argLevel, argX, argY; + JSObject *argPixelsObj; + JSBool flipY = JS_FALSE; + JSBool premultiplyAlpha = JS_TRUE; - switch (argTarget) { - case LOCAL_GL_TEXTURE_2D: - case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X: - case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X: - case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y: - case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: - case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z: - case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - break; - default: - return ErrorMessage("texSubImage2D: unsupported target"); + if (!::JS_ConvertArguments(js.ctx, js.argc, js.argv, "uuuuo/bb", + &argTarget, &argLevel, &argX, &argY, + &argPixelsObj, &flipY, &premultiplyAlpha) || + !argPixelsObj) + { + return ErrorMessage("texSubImage2D: argument error"); + return NS_ERROR_DOM_SYNTAX_ERR; + } + nsCOMPtr imgElt; + nsresult rv; + rv = nsContentUtils::XPConnect()->WrapJS(js.ctx, argPixelsObj, NS_GET_IID(nsIDOMHTMLElement), getter_AddRefs(imgElt)); + + nsRefPtr isurf; + + rv = TexImageElementBase(imgElt, getter_AddRefs(isurf), flipY, premultiplyAlpha); + + if (NS_FAILED(rv)) + return ErrorMessage("texImage2D: failed to get image for element"); + + MakeContextCurrent(); + + gl->fTexSubImage2D (argTarget, argLevel, argX, argY, isurf->Width(), isurf->Height(), LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, isurf->Data()); + } else { + jsuint argTarget, argLevel, argX, argY, argWidth, argHeight, argFormat, argType; + JSObject *argPixelsObj; + jsuint argPixelsLen; + if (!::JS_ConvertArguments(js.ctx, js.argc, js.argv, "uuuuuuuuo", + &argTarget, &argLevel, &argX, &argY, + &argWidth, &argHeight, &argFormat, &argType, + &argPixelsObj) || + !argPixelsObj || + !::JS_IsArrayObject(js.ctx, argPixelsObj) || + !::JS_GetArrayLength(js.ctx, argPixelsObj, &argPixelsLen)) + { + return ErrorMessage("texSubImage2D: argument error"); + return NS_ERROR_DOM_SYNTAX_ERR; + } + + switch (argTarget) { + case LOCAL_GL_TEXTURE_2D: + case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + break; + default: + return ErrorMessage("texSubImage2D: unsupported target"); + return NS_ERROR_DOM_SYNTAX_ERR; + } + + PRUint32 bufferType, bufferSize; + switch (argFormat) { + case LOCAL_GL_RED: + case LOCAL_GL_GREEN: + case LOCAL_GL_BLUE: + case LOCAL_GL_ALPHA: + case LOCAL_GL_LUMINANCE: + bufferSize = 1; + break; + case LOCAL_GL_LUMINANCE_ALPHA: + bufferSize = 2; + break; + case LOCAL_GL_RGB: + bufferSize = 3; + break; + case LOCAL_GL_RGBA: + bufferSize = 4; + break; + default: + return ErrorMessage("texSubImage2D: pixel format not supported"); + return NS_ERROR_DOM_SYNTAX_ERR; + } + + switch (argType) { + case LOCAL_GL_SHORT: + case LOCAL_GL_UNSIGNED_SHORT: + case LOCAL_GL_BYTE: + case LOCAL_GL_UNSIGNED_BYTE: + case LOCAL_GL_INT: + case LOCAL_GL_UNSIGNED_INT: + case LOCAL_GL_FLOAT: + bufferType = argType; + 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: + bufferType = LOCAL_GL_UNSIGNED_SHORT; + break; + default: + return ErrorMessage("texSubImage2D: pixel packing not supported"); + return NS_ERROR_DOM_SYNTAX_ERR; + } + + // make sure the size is valid + PRInt32 tmp = argWidth * argHeight; + if (tmp && tmp / argHeight != argWidth) { + return ErrorMessage("texSubImage2D: too large width or height"); return NS_ERROR_DOM_SYNTAX_ERR; - } + } - PRUint32 bufferType, bufferSize; - switch (argFormat) { - case LOCAL_GL_RED: - case LOCAL_GL_GREEN: - case LOCAL_GL_BLUE: - case LOCAL_GL_ALPHA: - case LOCAL_GL_LUMINANCE: - bufferSize = 1; - break; - case LOCAL_GL_LUMINANCE_ALPHA: - bufferSize = 2; - break; - case LOCAL_GL_RGB: - bufferSize = 3; - break; - case LOCAL_GL_RGBA: - bufferSize = 4; - break; - default: - return ErrorMessage("texSubImage2D: pixel format not supported"); + tmp = tmp * bufferSize; + if (tmp && tmp / bufferSize != (argWidth * argHeight)) { + return ErrorMessage("texSubImage2D: too large width or height (after multiplying with pixel size)"); return NS_ERROR_DOM_SYNTAX_ERR; - } + } - switch (argType) { - case LOCAL_GL_SHORT: - case LOCAL_GL_UNSIGNED_SHORT: - case LOCAL_GL_BYTE: - case LOCAL_GL_UNSIGNED_BYTE: - case LOCAL_GL_INT: - case LOCAL_GL_UNSIGNED_INT: - case LOCAL_GL_FLOAT: - bufferType = argType; - 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: - bufferType = LOCAL_GL_UNSIGNED_SHORT; - break; - default: - return ErrorMessage("texSubImage2D: pixel packing not supported"); + if ((PRUint32) tmp > argPixelsLen) { + return ErrorMessage("texSubImage2D: array dimensions too small for width, height and pixel format"); return NS_ERROR_DOM_SYNTAX_ERR; + } + + SimpleBuffer sbuffer(bufferType, bufferSize, js.ctx, argPixelsObj, argPixelsLen); + if (!sbuffer.Valid()) + return NS_ERROR_FAILURE; + + MakeContextCurrent(); + gl->fTexSubImage2D (argTarget, argLevel, argX, argY, argWidth, argHeight, argFormat, argType, (void *) sbuffer.data); } - - // make sure the size is valid - PRInt32 tmp = argWidth * argHeight; - if (tmp && tmp / argHeight != argWidth) { - return ErrorMessage("texSubImage2D: too large width or height"); - return NS_ERROR_DOM_SYNTAX_ERR; - } - - tmp = tmp * bufferSize; - if (tmp && tmp / bufferSize != (argWidth * argHeight)) { - return ErrorMessage("texSubImage2D: too large width or height (after multiplying with pixel size)"); - return NS_ERROR_DOM_SYNTAX_ERR; - } - - if ((PRUint32) tmp > argPixelsLen) { - return ErrorMessage("texSubImage2D: array dimensions too small for width, height and pixel format"); - return NS_ERROR_DOM_SYNTAX_ERR; - } - - SimpleBuffer sbuffer(bufferType, bufferSize, js.ctx, argPixelsObj, argPixelsLen); - if (!sbuffer.Valid()) - return NS_ERROR_FAILURE; - - MakeContextCurrent(); - gl->fTexSubImage2D (argTarget, argLevel, argX, argY, argWidth, argHeight, argFormat, argType, (void *) sbuffer.data); - return NS_OK; -#endif } NS_IMETHODIMP WebGLContext::TexImage2D() { - //return NS_ERROR_FAILURE; + // void texImage2D(in GLenum target, in GLint level, in GLenum internalformat, + // in GLsizei width, in GLsizei height, in GLint border, in GLenum format, + // in GLenum type, in CanvasArray pixels) + // void texImage2D(in GLenum target, in GLint level, in ImageData pixels, + // [Optional] GLboolean flipY, [Optional] in asPremultipliedAlpha) + // void texImage2D(in GLenum target, in GLint level, in HTMLImageElement image, + // [Optional] GLboolean flipY, [Optional] in asPremultipliedAlpha) + // void texImage2D(in GLenum target, in GLint level, in HTMLCanvasElement image, + // [Optional] GLboolean flipY, [Optional] in asPremultipliedAlpha) + // void texImage2D(in GLenum target, in GLint level, in HTMLVideoElement image, + // [Optional] GLboolean flipY, [Optional] in asPremultipliedAlpha) + // XXX TODO - //#if 0 NativeJSContext js; if (NS_FAILED(js.error)) return js.error; - if (js.argc != 3 && js.argc != 9) { - return ErrorMessage("texImage2D: expected 3 or 9 arguments"); + if (js.argc < 3 || js.argc > 9) { + return ErrorMessage("texImage2D: expected 3-5 or 9 arguments, got %d", js.argc); return NS_ERROR_DOM_SYNTAX_ERR; } jsuint argTarget, argLevel, argInternalFormat, argWidth, argHeight, argBorder, argFormat, argType; - if (js.argc == 3) { + if (js.argc > 2 && js.argc < 6) { JSObject *argPixelsObj; - if (!::JS_ConvertArguments(js.ctx, js.argc, js.argv, "uuo", + JSBool flipY = JS_FALSE; + JSBool premultiplyAlpha = JS_TRUE; + + if (!::JS_ConvertArguments(js.ctx, js.argc, js.argv, "uuo/bb", &argTarget, &argLevel, - &argPixelsObj) || + &argPixelsObj, &flipY, &premultiplyAlpha) || !argPixelsObj) { return ErrorMessage("texImage2D: argument error"); @@ -3093,7 +3099,7 @@ WebGLContext::TexImage2D() nsRefPtr isurf; - rv = TexImageElementBase(imgElt, getter_AddRefs(isurf)); + rv = TexImageElementBase(imgElt, getter_AddRefs(isurf), flipY, premultiplyAlpha); if (NS_FAILED(rv)) return ErrorMessage("texImage2D: failed to get image for element"); @@ -3226,7 +3232,6 @@ WebGLContext::TexImage2D() MakeContextCurrent(); gl->fTexImage2D (argTarget, argLevel, argInternalFormat, argWidth, argHeight, argBorder, argFormat, argType, (void *) sbuffer.data); } - //#endif } return NS_OK; }