diff --git a/gfx/public/nsIImage.h b/gfx/public/nsIImage.h index b7e08398d73..f1f142ade65 100644 --- a/gfx/public/nsIImage.h +++ b/gfx/public/nsIImage.h @@ -258,9 +258,22 @@ public: */ NS_IMETHOD UnlockImagePixels(PRBool aMaskPixels) = 0; -#ifdef MOZ_CAIRO_GFX + /** + * GetSurface + * Return the Thebes gfxASurface in aSurface. + * + * aSurface will be AddRef'd (as with most getters), so + * getter_AddRefs should be used. + */ NS_IMETHOD GetSurface(gfxASurface **aSurface) = 0; -#endif + + /** + * SetHasNoAlpha + * + * Hint to the image that all the pixels are fully opaque, even if + * the original format requested a 1-bit or 8-bit alpha mask + */ + virtual void SetHasNoAlpha() = 0; }; NS_DEFINE_STATIC_IID_ACCESSOR(nsIImage, NS_IIMAGE_IID) diff --git a/gfx/src/shared/gfxImageFrame.cpp b/gfx/src/shared/gfxImageFrame.cpp index 76eb6810c20..da09fb57a01 100644 --- a/gfx/src/shared/gfxImageFrame.cpp +++ b/gfx/src/shared/gfxImageFrame.cpp @@ -551,4 +551,3 @@ NS_IMETHODIMP gfxImageFrame::GetInterface(const nsIID & aIID, void * *result) return NS_NOINTERFACE; } - diff --git a/gfx/src/thebes/nsThebesImage.cpp b/gfx/src/thebes/nsThebesImage.cpp index 4fbc3a4e3b0..8ec3fec62f1 100644 --- a/gfx/src/thebes/nsThebesImage.cpp +++ b/gfx/src/thebes/nsThebesImage.cpp @@ -606,3 +606,16 @@ nsThebesImage::ShouldUseImageSurfaces() return PR_FALSE; } + +// A hint from the image decoders that this image has no alpha, even +// though we created is ARGB32. This changes our format to RGB24, +// which in turn will cause us to Optimize() to RGB24. Has no effect +// after Optimize() is called, though in all cases it will be just a +// performance win -- the pixels are still correct and have the A byte +// set to 0xff. +void +nsThebesImage::SetHasNoAlpha() +{ + if (mFormat == gfxASurface::ImageFormatARGB32) + mFormat = gfxASurface::ImageFormatRGB24; +} diff --git a/gfx/src/thebes/nsThebesImage.h b/gfx/src/thebes/nsThebesImage.h index 5e8915fafe6..0ff8103d3bf 100644 --- a/gfx/src/thebes/nsThebesImage.h +++ b/gfx/src/thebes/nsThebesImage.h @@ -103,6 +103,8 @@ public: return mImageSurface; } + void SetHasNoAlpha(); + protected: static PRBool AllowedImageSize(PRInt32 aWidth, PRInt32 aHeight) { NS_ASSERTION(aWidth > 0, "invalid image width"); diff --git a/gfx/thebes/public/gfxPlatform.h b/gfx/thebes/public/gfxPlatform.h index 32881e2abda..82d3bebb366 100644 --- a/gfx/thebes/public/gfxPlatform.h +++ b/gfx/thebes/public/gfxPlatform.h @@ -134,12 +134,6 @@ public: virtual gfxFontGroup *CreateFontGroup(const nsAString& aFamilies, const gfxFontStyle *aStyle) = 0; - /* Returns PR_TRUE if the given block of ARGB32 data really has alpha, otherwise PR_FALSE */ - static PRBool DoesARGBImageDataHaveAlpha(PRUint8* data, - PRUint32 width, - PRUint32 height, - PRUint32 stride); - void GetPrefFonts(const char *aLangGroup, nsString& array, PRBool aAppendUnicode = PR_TRUE); /** diff --git a/gfx/thebes/src/gfxPlatform.cpp b/gfx/thebes/src/gfxPlatform.cpp index 45c6c72fb90..62ad1b1ab0a 100644 --- a/gfx/thebes/src/gfxPlatform.cpp +++ b/gfx/thebes/src/gfxPlatform.cpp @@ -181,26 +181,6 @@ gfxPlatform::SetUseGlitz(PRBool use) gGlitzState = (use ? 1 : 0); } -PRBool -gfxPlatform::DoesARGBImageDataHaveAlpha(PRUint8* data, - PRUint32 width, - PRUint32 height, - PRUint32 stride) -{ - PRUint32 *r; - - for (PRUint32 j = 0; j < height; j++) { - r = (PRUint32*) (data + stride*j); - for (PRUint32 i = 0; i < width; i++) { - if ((*r++ & 0xff000000) != 0xff000000) { - return PR_TRUE; - } - } - } - - return PR_FALSE; -} - already_AddRefed gfxPlatform::OptimizeImage(gfxImageSurface *aSurface) { @@ -208,17 +188,6 @@ gfxPlatform::OptimizeImage(gfxImageSurface *aSurface) gfxASurface::gfxImageFormat realFormat = aSurface->Format(); - if (realFormat == gfxASurface::ImageFormatARGB32) { - // this might not really need alpha; figure that out - if (!DoesARGBImageDataHaveAlpha(aSurface->Data(), - surfaceSize.width, - surfaceSize.height, - aSurface->Stride())) - { - realFormat = gfxASurface::ImageFormatRGB24; - } - } - nsRefPtr optSurface = CreateOffscreenSurface(surfaceSize, realFormat); if (!optSurface) diff --git a/gfx/thebes/src/gfxWindowsSurface.cpp b/gfx/thebes/src/gfxWindowsSurface.cpp index bbc60c3526a..229eb89c821 100644 --- a/gfx/thebes/src/gfxWindowsSurface.cpp +++ b/gfx/thebes/src/gfxWindowsSurface.cpp @@ -119,16 +119,6 @@ already_AddRefed gfxWindowsSurface::OptimizeToDDB(HDC dc, const gfxIntSize& size, gfxImageFormat format) { gfxImageFormat realFormat = format; - if (realFormat == ImageFormatARGB32) { - cairo_surface_t *isurf = cairo_win32_surface_get_image(CairoSurface()); - if (isurf && !gfxPlatform::DoesARGBImageDataHaveAlpha(cairo_image_surface_get_data(isurf), - cairo_image_surface_get_width(isurf), - cairo_image_surface_get_height(isurf), - cairo_image_surface_get_stride(isurf))) - { - realFormat = ImageFormatRGB24; - } - } if (realFormat != ImageFormatRGB24) return nsnull; diff --git a/modules/libpr0n/decoders/gif/nsGIFDecoder2.cpp b/modules/libpr0n/decoders/gif/nsGIFDecoder2.cpp index c7fcc8b55bb..c48530e4f97 100644 --- a/modules/libpr0n/decoders/gif/nsGIFDecoder2.cpp +++ b/modules/libpr0n/decoders/gif/nsGIFDecoder2.cpp @@ -77,6 +77,9 @@ mailing address. #include "prlog.h" #include "GIF2.h" +#include "nsIImage.h" +#include "nsIInterfaceRequestorUtils.h" + #include "nsGIFDecoder2.h" #include "nsIInputStream.h" #include "nsIComponentManager.h" @@ -320,6 +323,7 @@ void nsGIFDecoder2::EndGIF() void nsGIFDecoder2::BeginImageFrame() { mImageFrame = nsnull; // clear out our current frame reference + mFrameHasNoAlpha = PR_TRUE; if (!mGIFStruct.images_decoded) { // Send a onetime OnDataAvailable (Display Refresh) for the first frame @@ -350,6 +354,11 @@ void nsGIFDecoder2::EndImageFrame() // timeout for the image until here to help ensure that we have the whole // image frame decoded before we go off and try to display another frame. mImageFrame->SetTimeout(mGIFStruct.delay_time); + + if (mFrameHasNoAlpha) { + nsCOMPtr img(do_GetInterface(mImageFrame)); + img->SetHasNoAlpha(); + } } mImageContainer->EndFrameDecode(mGIFStruct.images_decoded, mGIFStruct.delay_time); @@ -442,12 +451,14 @@ void nsGIFDecoder2::HaveDecodedRow( } else { PRUint8* rowBufIndex = aRowBufPtr; PRUint32* rgbRowIndex = (PRUint32*)mRGBLine; + PRBool rowHasNoAlpha = PR_TRUE; const PRInt32 tpixel = mGIFStruct.is_transparent ? mGIFStruct.tpixel : -1; while (rowBufIndex != mGIFStruct.rowend) { if (*rowBufIndex >= cmapsize || *rowBufIndex == tpixel) { + rowHasNoAlpha = PR_FALSE; *rgbRowIndex++ = 0x00000000; ++rowBufIndex; continue; @@ -462,6 +473,8 @@ void nsGIFDecoder2::HaveDecodedRow( } for (int i=0; iSetImageData(mRGBLine, bpr, (aRowNumber+i)*bpr); + if (!rowHasNoAlpha) + mFrameHasNoAlpha = PR_FALSE; } mCurrentRow = aRowNumber + aDuplicateCount - 1; diff --git a/modules/libpr0n/decoders/gif/nsGIFDecoder2.h b/modules/libpr0n/decoders/gif/nsGIFDecoder2.h index 020c5e974d5..98e1124f271 100644 --- a/modules/libpr0n/decoders/gif/nsGIFDecoder2.h +++ b/modules/libpr0n/decoders/gif/nsGIFDecoder2.h @@ -102,6 +102,7 @@ private: PRUint8 mCurrentPass; PRUint8 mLastFlushedPass; PRPackedBool mGIFOpen; + PRPackedBool mFrameHasNoAlpha; gif_struct mGIFStruct; }; diff --git a/modules/libpr0n/decoders/png/nsPNGDecoder.cpp b/modules/libpr0n/decoders/png/nsPNGDecoder.cpp index 85f0216e981..59b81421621 100644 --- a/modules/libpr0n/decoders/png/nsPNGDecoder.cpp +++ b/modules/libpr0n/decoders/png/nsPNGDecoder.cpp @@ -119,6 +119,8 @@ void nsPNGDecoder::CreateFrame(png_uint_32 x_offset, png_uint_32 y_offset, if (mObserver) mObserver->OnStartFrame(nsnull, mFrame); + + mFrameHasNoAlpha = PR_TRUE; } // set timeout and frame disposal method for the current frame @@ -648,6 +650,7 @@ row_callback(png_structp png_ptr, png_bytep new_row, PRUint32 imageDataLength, bpr = width * sizeof(PRUint32); decoder->mFrame->GetImageData(&imageData, &imageDataLength); PRUint32 *cptr32 = (PRUint32*)(imageData + (row_num*bpr)); + PRBool rowHasNoAlpha = PR_TRUE; if (decoder->mTransform) { if (decoder->mCMSLine) { @@ -679,6 +682,8 @@ row_callback(png_structp png_ptr, png_bytep new_row, { for (PRUint32 x=iwidth; x>0; --x) { *cptr32++ = GFX_PACKED_PIXEL(line[3]?0xFF:0x00, line[0], line[1], line[2]); + if (line[3] == 0) + rowHasNoAlpha = PR_FALSE; line += 4; } } @@ -688,12 +693,17 @@ row_callback(png_structp png_ptr, png_bytep new_row, { for (PRUint32 x=width; x>0; --x) { *cptr32++ = GFX_PACKED_PIXEL(line[3], line[0], line[1], line[2]); + if (line[3] != 0xff) + rowHasNoAlpha = PR_FALSE; line += 4; } } break; } + if (!rowHasNoAlpha) + decoder->mFrameHasNoAlpha = PR_FALSE; + nsIntRect r(0, row_num, width, 1); nsCOMPtr img(do_GetInterface(decoder->mFrame)); img->ImageUpdated(nsnull, nsImageUpdateFlags_kBitsChanged, &r); @@ -714,6 +724,10 @@ frame_info_callback(png_structp png_ptr, png_uint_32 frame_num) if (!(decoder->apngFlags & FRAME_HIDDEN)) { PRInt32 timeout; decoder->mFrame->GetTimeout(&timeout); + if (decoder->mFrameHasNoAlpha) { + nsCOMPtr img(do_GetInterface(decoder->mFrame)); + img->SetHasNoAlpha(); + } decoder->mImage->EndFrameDecode(frame_num, timeout); decoder->mObserver->OnStopFrame(nsnull, decoder->mFrame); } @@ -753,6 +767,10 @@ end_callback(png_structp png_ptr, png_infop info_ptr) if (!(decoder->apngFlags & FRAME_HIDDEN)) { PRInt32 timeout; decoder->mFrame->GetTimeout(&timeout); + if (decoder->mFrameHasNoAlpha) { + nsCOMPtr img(do_GetInterface(decoder->mFrame)); + img->SetHasNoAlpha(); + } decoder->mImage->EndFrameDecode(decoder->mPNG->num_frames_read, timeout); } diff --git a/modules/libpr0n/decoders/png/nsPNGDecoder.h b/modules/libpr0n/decoders/png/nsPNGDecoder.h index 9fc3f15da2a..a0b00c5f9f5 100644 --- a/modules/libpr0n/decoders/png/nsPNGDecoder.h +++ b/modules/libpr0n/decoders/png/nsPNGDecoder.h @@ -93,6 +93,7 @@ public: PRUint8 apngFlags; PRUint8 mChannels; PRPackedBool mError; + PRPackedBool mFrameHasNoAlpha; }; #endif // nsPNGDecoder_h__ diff --git a/modules/libpr0n/decoders/xbm/Makefile.in b/modules/libpr0n/decoders/xbm/Makefile.in index 51f04bf739b..3334742a5aa 100644 --- a/modules/libpr0n/decoders/xbm/Makefile.in +++ b/modules/libpr0n/decoders/xbm/Makefile.in @@ -52,6 +52,7 @@ LIBXUL_LIBRARY = 1 REQUIRES = xpcom \ gfx \ imglib2 \ + thebes \ $(NULL) CPPSRCS = nsXBMDecoder.cpp diff --git a/modules/libpr0n/decoders/xbm/nsXBMDecoder.cpp b/modules/libpr0n/decoders/xbm/nsXBMDecoder.cpp index 835698338a7..d2bf215f40c 100644 --- a/modules/libpr0n/decoders/xbm/nsXBMDecoder.cpp +++ b/modules/libpr0n/decoders/xbm/nsXBMDecoder.cpp @@ -47,19 +47,14 @@ #include "nsIInputStream.h" #include "nsIComponentManager.h" +#include "nsIImage.h" +#include "nsIInterfaceRequestorUtils.h" #include "imgILoad.h" #include "nsIProperties.h" #include "nsISupportsPrimitives.h" -#if defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS) || defined(MOZ_WIDGET_PHOTON) -#define GFXFORMAT gfxIFormats::BGR_A1 -#else -#define USE_RGB -#define GFXFORMAT gfxIFormats::RGB_A1 -#endif - NS_IMPL_ISUPPORTS1(nsXBMDecoder, imgIDecoder) nsXBMDecoder::nsXBMDecoder() : mBuf(nsnull), mPos(nsnull), mAlphaRow(nsnull) @@ -92,12 +87,18 @@ NS_IMETHODIMP nsXBMDecoder::Init(imgILoad *aLoad) mCurRow = mBufSize = mWidth = mHeight = 0; mState = RECV_HEADER; + mHasNoAlpha = PR_TRUE; return NS_OK; } NS_IMETHODIMP nsXBMDecoder::Close() { + if (mHasNoAlpha) { + nsCOMPtr img(do_GetInterface(mFrame)); + img->SetHasNoAlpha(); + } + mObserver->OnStopContainer(nsnull, mImage); mObserver->OnStopDecode(nsnull, NS_OK, nsnull); mObserver = nsnull; @@ -185,7 +186,7 @@ nsresult nsXBMDecoder::ProcessData(const char* aData, PRUint32 aCount) { mImage->Init(mWidth, mHeight, mObserver); mObserver->OnStartContainer(nsnull, mImage); - nsresult rv = mFrame->Init(0, 0, mWidth, mHeight, GFXFORMAT, 24); + nsresult rv = mFrame->Init(0, 0, mWidth, mHeight, gfxIFormats::RGB_A1, 24); if (NS_FAILED(rv)) return rv; @@ -240,6 +241,7 @@ nsresult nsXBMDecoder::ProcessData(const char* aData, PRUint32 aCount) { PRUint32 abpr; mFrame->GetAlphaBytesPerRow(&abpr); PRBool hiByte = PR_TRUE; + PRBool chunkHasNoAlpha = PR_TRUE; do { PRUint32 pixel = strtoul(mPos, &endPtr, 0); @@ -273,6 +275,8 @@ nsresult nsXBMDecoder::ProcessData(const char* aData, PRUint32 aCount) { for (int i = 0; i < alphas; i++) { const PRUint8 val = ((pixel & (1 << i)) >> i) ? 255 : 0; *ar++ = (val << 24) | 0; + if (val == 0) + chunkHasNoAlpha = PR_FALSE; } mCurCol = PR_MIN(mCurCol + 8, mWidth); @@ -297,6 +301,9 @@ nsresult nsXBMDecoder::ProcessData(const char* aData, PRUint32 aCount) { if (*mPos == ',') mPos++; } while ((mState == RECV_DATA) && *mPos); + + if (!chunkHasNoAlpha) + mHasNoAlpha = PR_FALSE; } return NS_OK; diff --git a/modules/libpr0n/decoders/xbm/nsXBMDecoder.h b/modules/libpr0n/decoders/xbm/nsXBMDecoder.h index 77cf1ffee2c..34cde061336 100644 --- a/modules/libpr0n/decoders/xbm/nsXBMDecoder.h +++ b/modules/libpr0n/decoders/xbm/nsXBMDecoder.h @@ -90,6 +90,7 @@ private: PRPackedBool mIsCursor; PRPackedBool mIsX10; // X10 flavor XBM? + PRPackedBool mHasNoAlpha; enum { RECV_HEADER,