b=572018; DOMElementToImageSurface: fix memleak and work in one pass; r=vladimir

This commit is contained in:
Benoit Jacob 2010-06-19 10:47:53 -04:00
Родитель b7b8ad89af
Коммит 69fb98d9f1
1 изменённых файлов: 71 добавлений и 84 удалений

Просмотреть файл

@ -2317,6 +2317,42 @@ GL_SAME_METHOD_3(StencilOp, StencilOp, WebGLenum, WebGLenum, WebGLenum)
GL_SAME_METHOD_4(StencilOpSeparate, StencilOpSeparate, WebGLenum, WebGLenum, WebGLenum, WebGLenum) GL_SAME_METHOD_4(StencilOpSeparate, StencilOpSeparate, WebGLenum, WebGLenum, WebGLenum, WebGLenum)
template<int format>
inline void convert_pixel(PRUint8* dst, const PRUint8* src)
{
// since has_alpha is a compile time constant, any if(has_alpha) evaluates
// at compile time, so has zero runtime cost.
enum { has_alpha = format == gfxASurface::ImageFormatARGB32 };
#ifdef IS_LITTLE_ENDIAN
PRUint8 b = *src++;
PRUint8 g = *src++;
PRUint8 r = *src++;
PRUint8 a = *src;
#else
PRUint8 a = *src++;
PRUint8 r = *src++;
PRUint8 g = *src++;
PRUint8 b = *src;
#endif
if (has_alpha) {
// Convert to non-premultiplied color
if (a != 0) {
r = (r * 255) / a;
g = (g * 255) / a;
b = (b * 255) / a;
}
}
*dst++ = r;
*dst++ = g;
*dst++ = b;
if (has_alpha)
*dst = a;
else
*dst = 255;
}
nsresult nsresult
WebGLContext::DOMElementToImageSurface(nsIDOMElement *imageOrCanvas, WebGLContext::DOMElementToImageSurface(nsIDOMElement *imageOrCanvas,
@ -2347,94 +2383,45 @@ WebGLContext::DOMElementToImageSurface(nsIDOMElement *imageOrCanvas,
if (width <= 0 || height <= 0) if (width <= 0 || height <= 0)
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
if (surf->Format() == gfxASurface::ImageFormatARGB32) { // this wants some SSE love
PRUint8* src = surf->Data(); int row1 = 0, row2 = height-1;
PRUint8* dst = surf->Data(); for (; flipY ? (row1 <= row2) : (row1 < height); row1++, row2--) {
PRUint8 *row1_start = surf->Data() + row1 * surf->Stride();
PRUint8 *row1_end = row1_start + surf->Stride();
PRUint8 *row2_start = surf->Data() + row2 * surf->Stride();
// this wants some SSE love if (flipY == PR_FALSE || row1 == row2) {
if (surf->Format() == gfxASurface::ImageFormatARGB32) {
for (int j = 0; j < height; j++) { for (PRUint8 *row1_ptr = row1_start; row1_ptr != row1_end; row1_ptr += 4) {
src = surf->Data() + j * surf->Stride(); convert_pixel<gfxASurface::ImageFormatARGB32>(row1_ptr, row1_ptr);
// note that dst's stride is always tightly packed
for (int i = 0; i < width; i++) {
#ifdef IS_LITTLE_ENDIAN
PRUint8 b = *src++;
PRUint8 g = *src++;
PRUint8 r = *src++;
PRUint8 a = *src++;
#else
PRUint8 a = *src++;
PRUint8 r = *src++;
PRUint8 g = *src++;
PRUint8 b = *src++;
#endif
// Convert to non-premultiplied color
if (a != 0) {
r = (r * 255) / a;
g = (g * 255) / a;
b = (b * 255) / a;
} }
} else if (surf->Format() == gfxASurface::ImageFormatRGB24) {
*dst++ = r; for (PRUint8 *row1_ptr = row1_start; row1_ptr != row1_end; row1_ptr += 4) {
*dst++ = g; convert_pixel<gfxASurface::ImageFormatRGB24>(row1_ptr, row1_ptr);
*dst++ = b; }
*dst++ = a; } else {
return NS_ERROR_FAILURE;
}
} else {
PRUint8 *row1_ptr = row1_start;
PRUint8 *row2_ptr = row2_start;
PRUint8 tmp[4];
if (surf->Format() == gfxASurface::ImageFormatARGB32) {
for (; row1_ptr != row1_end; row1_ptr += 4, row2_ptr += 4) {
convert_pixel<gfxASurface::ImageFormatARGB32>(tmp, row1_ptr);
convert_pixel<gfxASurface::ImageFormatARGB32>(row1_ptr, row2_ptr);
*reinterpret_cast<PRUint32*>(row2_ptr) = *reinterpret_cast<PRUint32*>(tmp);
}
} else if (surf->Format() == gfxASurface::ImageFormatRGB24) {
for (; row1_ptr != row1_end; row1_ptr += 4, row2_ptr += 4) {
convert_pixel<gfxASurface::ImageFormatRGB24>(tmp, row1_ptr);
convert_pixel<gfxASurface::ImageFormatRGB24>(row1_ptr, row2_ptr);
*reinterpret_cast<PRUint32*>(row2_ptr) = *reinterpret_cast<PRUint32*>(tmp);
}
} else {
return NS_ERROR_FAILURE;
} }
} }
} else if (surf->Format() == gfxASurface::ImageFormatRGB24) {
PRUint8* dst = surf->Data();
// this wants some SSE love
for (int j = 0; j < height; j++) {
PRUint8* src = surf->Data() + j * surf->Stride();
// note that dst's stride is always tightly packed
for (int i = 0; i < width; i++) {
#ifdef IS_LITTLE_ENDIAN
PRUint8 b = *src++;
PRUint8 g = *src++;
PRUint8 r = *src++;
src++;
#else
src++;
PRUint8 r = *src++;
PRUint8 g = *src++;
PRUint8 b = *src++;
#endif
*dst++ = r;
*dst++ = g;
*dst++ = b;
*dst++ = 255;
}
}
} else {
return NS_ERROR_FAILURE;
}
if (flipY) {
nsRefPtr<gfxImageSurface> tmpsurf = new gfxImageSurface(res.mSize,
gfxASurface::ImageFormatARGB32);
if (!tmpsurf || tmpsurf->CairoStatus())
return NS_ERROR_FAILURE;
nsRefPtr<gfxContext> 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(); res.mSurface.forget();