b=391583, DoesARGBImageDataHaveAlpha is slow, r=stuart,a=me

This commit is contained in:
vladimir%pobox.com 2007-08-17 19:55:00 +00:00
Родитель 1572e3189c
Коммит e7ae74d226
14 изменённых файлов: 80 добавлений и 58 удалений

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

@ -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)

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

@ -551,4 +551,3 @@ NS_IMETHODIMP gfxImageFrame::GetInterface(const nsIID & aIID, void * *result)
return NS_NOINTERFACE;
}

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

@ -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;
}

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

@ -103,6 +103,8 @@ public:
return mImageSurface;
}
void SetHasNoAlpha();
protected:
static PRBool AllowedImageSize(PRInt32 aWidth, PRInt32 aHeight) {
NS_ASSERTION(aWidth > 0, "invalid image width");

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

@ -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);
/**

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

@ -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<gfxASurface>
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<gfxASurface> optSurface = CreateOffscreenSurface(surfaceSize, realFormat);
if (!optSurface)

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

@ -119,16 +119,6 @@ already_AddRefed<gfxWindowsSurface>
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;

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

@ -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<nsIImage> 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; i<aDuplicateCount; i++)
mImageFrame->SetImageData(mRGBLine, bpr, (aRowNumber+i)*bpr);
if (!rowHasNoAlpha)
mFrameHasNoAlpha = PR_FALSE;
}
mCurrentRow = aRowNumber + aDuplicateCount - 1;

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

@ -102,6 +102,7 @@ private:
PRUint8 mCurrentPass;
PRUint8 mLastFlushedPass;
PRPackedBool mGIFOpen;
PRPackedBool mFrameHasNoAlpha;
gif_struct mGIFStruct;
};

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

@ -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<nsIImage> 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<nsIImage> 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<nsIImage> img(do_GetInterface(decoder->mFrame));
img->SetHasNoAlpha();
}
decoder->mImage->EndFrameDecode(decoder->mPNG->num_frames_read, timeout);
}

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

@ -93,6 +93,7 @@ public:
PRUint8 apngFlags;
PRUint8 mChannels;
PRPackedBool mError;
PRPackedBool mFrameHasNoAlpha;
};
#endif // nsPNGDecoder_h__

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

@ -52,6 +52,7 @@ LIBXUL_LIBRARY = 1
REQUIRES = xpcom \
gfx \
imglib2 \
thebes \
$(NULL)
CPPSRCS = 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<nsIImage> 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;

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

@ -90,6 +90,7 @@ private:
PRPackedBool mIsCursor;
PRPackedBool mIsX10; // X10 flavor XBM?
PRPackedBool mHasNoAlpha;
enum {
RECV_HEADER,