speed up image drawing by decoding directly in to 32bpp buffers. bug 331298. r=vlad

This commit is contained in:
pavlov%pavlov.net 2006-03-25 00:34:48 +00:00
Родитель fb365662e6
Коммит 44f55dc046
21 изменённых файлов: 363 добавлений и 354 удалений

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

@ -42,6 +42,10 @@
#include "nsIRenderingContext.h"
#include "nsRect.h"
#ifdef MOZ_CAIRO_GFX
class gfxASurface;
#endif
class nsIDeviceContext;
struct nsColorMap
@ -279,6 +283,10 @@ public:
* @return error result
*/
NS_IMETHOD UnlockImagePixels(PRBool aMaskPixels) = 0;
#ifdef MOZ_CAIRO_GFX
NS_IMETHOD GetSurface(gfxASurface **aSurface) = 0;
#endif
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIImage, NS_IIMAGE_IID)

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

@ -59,19 +59,12 @@
#endif
#endif
static PRUint8 Unpremultiply(PRUint8 aVal, PRUint8 aAlpha);
static void ARGBToThreeChannel(PRUint32* aARGB, PRUint8* aData);
static PRUint8 Premultiply(PRUint8 aVal, PRUint8 aAlpha);
static PRUint32 ThreeChannelToARGB(PRUint8* aData, PRUint8 aAlpha);
NS_IMPL_ISUPPORTS1(nsThebesImage, nsIImage)
nsThebesImage::nsThebesImage()
: mWidth(0),
mHeight(0),
mDecoded(0,0,0,0),
mLockedData(nsnull),
mLockedAlpha(nsnull),
mAlphaDepth(0),
mLocked(PR_FALSE),
mHadAnyData(PR_FALSE),
@ -82,57 +75,42 @@ nsThebesImage::nsThebesImage()
nsresult
nsThebesImage::Init(PRInt32 aWidth, PRInt32 aHeight, PRInt32 aDepth, nsMaskRequirements aMaskRequirements)
{
NS_ASSERTION(aDepth == 24, "nsThebesImage::Init called with depth != 24");
mWidth = aWidth;
mHeight = aHeight;
gfxImageSurface::gfxImageFormat format;
switch(aMaskRequirements)
{
case nsMaskRequirements_kNeeds1Bit:
format = gfxImageSurface::gfxImageFormat::ImageFormatARGB32;
mAlphaDepth = 1;
break;
case nsMaskRequirements_kNeeds8Bit:
format = gfxImageSurface::gfxImageFormat::ImageFormatARGB32;
mAlphaDepth = 8;
break;
default:
format = gfxImageSurface::gfxImageFormat::ImageFormatRGB24;
mAlphaDepth = 0;
break;
}
mImageSurface = new gfxImageSurface(format, mWidth, mHeight);
memset(mImageSurface->Data(), 0, mHeight * mImageSurface->Stride());
mStride = mImageSurface->Stride();
return NS_OK;
}
void
nsThebesImage::EnsureImageSurface()
{
if (!mImageSurface) {
// always read images as ARGB32
mImageSurface = new gfxImageSurface (gfxImageSurface::ImageFormatARGB32, mWidth, mHeight);
memset(mImageSurface->Data(), 0xFF, mHeight * mImageSurface->Stride());
if (mOptSurface) {
nsRefPtr<gfxContext> tmpCtx(new gfxContext(mImageSurface));
tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
tmpCtx->SetSource(mOptSurface);
tmpCtx->Paint();
}
}
}
nsThebesImage::~nsThebesImage()
{
if (mLockedData)
nsMemory::Free(mLockedData);
if (mLockedAlpha)
nsMemory::Free(mLockedAlpha);
}
PRInt32
nsThebesImage::GetBytesPix()
{
// not including alpha
return 3;
return 4;
}
PRBool
@ -156,14 +134,15 @@ nsThebesImage::GetHeight()
PRUint8 *
nsThebesImage::GetBits()
{
//NS_ASSERTION(mLocked == PR_TRUE, "GetBits called outside of Lock!");
return mLockedData;
if (mImageSurface)
return mImageSurface->Data();
return nsnull;
}
PRInt32
nsThebesImage::GetLineStride()
{
return mWidth * 3;
return mStride;
}
PRBool
@ -175,14 +154,13 @@ nsThebesImage::GetHasAlphaMask()
PRUint8 *
nsThebesImage::GetAlphaBits()
{
//NS_ASSERTION(mLocked == PR_TRUE, "GetAlphaBits called outside of Lock!");
return (PRUint8 *) mLockedAlpha;
return nsnull;
}
PRInt32
nsThebesImage::GetAlphaLineStride()
{
return mAlphaDepth == 1 ? (mWidth+7)/8 : mWidth;
return mStride;
}
void
@ -200,28 +178,12 @@ nsThebesImage::GetIsImageComplete()
nsresult
nsThebesImage::Optimize(nsIDeviceContext* aContext)
{
UpdateFromLockedData();
EnsureImageSurface();
if (mOptSurface)
return NS_OK;
if (!mOptSurface) {
gfxASurface::gfxImageFormat real_format;
mOptSurface = gfxPlatform::GetPlatform()->OptimizeImage(mImageSurface);
if (mRealAlphaDepth == 0)
real_format = gfxASurface::ImageFormatRGB24;
else
real_format = gfxASurface::ImageFormatARGB32;
mOptSurface = gfxPlatform::GetPlatform()->CreateOffscreenSurface(mWidth, mHeight, real_format);
}
if (mOptSurface) {
nsRefPtr<gfxContext> tmpCtx(new gfxContext(mOptSurface));
tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
tmpCtx->SetSource(mImageSurface);
tmpCtx->Paint();
mImageSurface = nsnull;
}
mImageSurface = nsnull;
return NS_OK;
}
@ -247,173 +209,19 @@ nsThebesImage::GetBitInfo()
NS_IMETHODIMP
nsThebesImage::LockImagePixels(PRBool aMaskPixels)
{
//NS_ASSERTION(!mLocked, "LockImagePixels called on already locked image!");
PRUint32 tmpSize;
// if we already have locked data allocated,
// and we have some data, and we're not up to date,
// then don't bother updating frmo the image surface
// to the 2 buffers -- the 2 buffers are more current,
// because UpdateFromLockedData() hasn't been called yet.
//
// UpdateFromLockedData() is only called right before we
// actually try to draw, because the image decoders
// will call Lock/Unlock pretty frequently as they decode
// rows of the image.
if (mLockedData && mHadAnyData && !mUpToDate)
return NS_OK;
EnsureImageSurface();
if (mAlphaDepth > 0) {
NS_ASSERTION(mAlphaDepth == 1 || mAlphaDepth == 8,
"Bad alpha depth");
tmpSize = mHeight*(mAlphaDepth == 1 ? ((mWidth+7)/8) : mWidth);
if (!mLockedAlpha)
mLockedAlpha = (PRUint8*)nsMemory::Alloc(tmpSize);
if (!mLockedAlpha)
return NS_ERROR_OUT_OF_MEMORY;
}
tmpSize = mWidth * mHeight * 3;
if (!mLockedData)
mLockedData = (PRUint8*)nsMemory::Alloc(tmpSize);
if (!mLockedData)
return NS_ERROR_OUT_OF_MEMORY;
if (mAlphaDepth > 0 && mHadAnyData) {
// fill from existing ARGB buffer
if (mAlphaDepth == 8) {
PRInt32 destCount = 0;
for (PRInt32 row = 0; row < mHeight; ++row) {
PRUint32* srcRow = (PRUint32*) (mImageSurface->Data() + (mImageSurface->Stride()*row));
for (PRInt32 col = 0; col < mWidth; ++col) {
mLockedAlpha[destCount++] = (PRUint8)(srcRow[col] >> 24);
}
}
} else {
PRInt32 i = 0;
for (PRInt32 row = 0; row < mHeight; ++row) {
PRUint32* srcRow = (PRUint32*) (mImageSurface->Data() + (mImageSurface->Stride()*row));
PRUint8 alphaBits = 0;
for (PRInt32 col = 0; col < mWidth; ++col) {
PRUint8 mask = 1 << (7 - (col&7));
if (srcRow[col] & 0xFF000000) {
alphaBits |= mask;
}
if (mask == 0x01) {
// This mask byte is complete, write it back
mLockedAlpha[i] = alphaBits;
alphaBits = 0;
++i;
}
}
if (mWidth & 7) {
// write back the incomplete alpha mask
mLockedAlpha[i] = alphaBits;
++i;
}
}
}
}
if (mHadAnyData) {
int destCount = 0;
for (PRInt32 row = 0; row < mHeight; ++row) {
PRUint32* srcRow = (PRUint32*) (mImageSurface->Data() + (mImageSurface->Stride()*row));
for (PRInt32 col = 0; col < mWidth; ++col) {
ARGBToThreeChannel(&srcRow[col], &mLockedData[destCount*3]);
destCount++;
}
}
}
mLocked = PR_TRUE;
mOptSurface = nsnull;
if (aMaskPixels)
return NS_ERROR_NOT_IMPLEMENTED;
return NS_OK;
}
NS_IMETHODIMP
nsThebesImage::UnlockImagePixels(PRBool aMaskPixels)
{
//NS_ASSERTION(mLocked, "UnlockImagePixels called on unlocked image!");
mLocked = PR_FALSE;
mUpToDate = PR_FALSE;
if (aMaskPixels)
return NS_ERROR_NOT_IMPLEMENTED;
return NS_OK;
}
void
nsThebesImage::UpdateFromLockedData()
{
if (!mLockedData || mUpToDate)
return;
mUpToDate = PR_TRUE;
NS_ASSERTION(mAlphaDepth == 0 || mAlphaDepth == 1 || mAlphaDepth == 8,
"Bad alpha depth");
mRealAlphaDepth = 0;
PRInt32 alphaIndex = 0;
PRInt32 lockedBufIndex = 0;
for (PRInt32 row = 0; row < mHeight; ++row) {
PRUint32 *destPtr = (PRUint32*) (mImageSurface->Data() + (row * mImageSurface->Stride()));
for (PRInt32 col = 0; col < mWidth; ++col) {
PRUint8 alpha = 0xFF;
if (mAlphaDepth == 1) {
PRUint8 mask = 1 << (7 - (col&7));
if (!(mLockedAlpha[alphaIndex] & mask)) {
alpha = 0;
}
if (mask == 0x01) {
++alphaIndex;
}
} else if (mAlphaDepth == 8) {
alpha = mLockedAlpha[lockedBufIndex];
}
if (mRealAlphaDepth == 0 && alpha != 0xff)
mRealAlphaDepth = mAlphaDepth;
*destPtr++ =
ThreeChannelToARGB(&mLockedData[lockedBufIndex*3], alpha);
++lockedBufIndex;
}
if (mAlphaDepth == 1) {
if (mWidth & 7) {
++alphaIndex;
}
}
}
if (PR_FALSE) { // Enabling this saves memory but can lead to pathologically bad
// performance. Would also cause problems with premultiply/unpremultiply too
nsMemory::Free(mLockedData);
mLockedData = nsnull;
if (mLockedAlpha) {
nsMemory::Free(mLockedAlpha);
mLockedAlpha = nsnull;
}
}
mHadAnyData = PR_TRUE;
}
/* NB: These are pixels, not twips. */
NS_IMETHODIMP
nsThebesImage::Draw(nsIRenderingContext &aContext, nsIDrawingSurface *aSurface,
@ -429,8 +237,6 @@ nsThebesImage::Draw(nsIRenderingContext &aContext, nsIDrawingSurface *aSurface,
PRInt32 aSX, PRInt32 aSY, PRInt32 aSWidth, PRInt32 aSHeight,
PRInt32 aDX, PRInt32 aDY, PRInt32 aDWidth, PRInt32 aDHeight)
{
UpdateFromLockedData();
nsThebesRenderingContext *thebesRC = NS_STATIC_CAST(nsThebesRenderingContext*, &aContext);
gfxContext *ctx = thebesRC->Thebes();
@ -469,8 +275,6 @@ nsThebesImage::DrawTile(nsIRenderingContext &aContext,
PRInt32 aPadX, PRInt32 aPadY,
const nsRect &aTileRect)
{
UpdateFromLockedData();
nsThebesRenderingContext *thebesRC = NS_STATIC_CAST(nsThebesRenderingContext*, &aContext);
gfxContext *ctx = thebesRC->Thebes();
@ -537,8 +341,6 @@ nsThebesImage::DrawTile(nsIRenderingContext &aContext,
NS_IMETHODIMP
nsThebesImage::DrawToImage(nsIImage* aDstImage, PRInt32 aDX, PRInt32 aDY, PRInt32 aDWidth, PRInt32 aDHeight)
{
UpdateFromLockedData();
nsThebesImage *dstThebesImage = NS_STATIC_CAST(nsThebesImage*, aDstImage);
nsRefPtr<gfxContext> dst = new gfxContext(dstThebesImage->ThebesSurface());
@ -557,63 +359,3 @@ nsThebesImage::DrawToImage(nsIImage* aDstImage, PRInt32 aDX, PRInt32 aDY, PRInt3
return NS_OK;
}
/** Image conversion utils **/
static PRUint8 Unpremultiply(PRUint8 aVal, PRUint8 aAlpha) {
return (aVal*255)/aAlpha;
}
static void ARGBToThreeChannel(PRUint32* aARGB, PRUint8* aData) {
#ifdef IS_LITTLE_ENDIAN
PRUint8 a = (PRUint8)(*aARGB >> 24);
PRUint8 r = (PRUint8)(*aARGB >> 16);
PRUint8 g = (PRUint8)(*aARGB >> 8);
PRUint8 b = (PRUint8)(*aARGB >> 0);
#else
PRUint8 a = (PRUint8)(*aARGB >> 0);
PRUint8 r = (PRUint8)(*aARGB >> 8);
PRUint8 g = (PRUint8)(*aARGB >> 16);
PRUint8 b = (PRUint8)(*aARGB >> 24);
#endif
if (a != 0xFF) {
if (a == 0) {
r = 0;
g = 0;
b = 0;
} else {
r = Unpremultiply(r, a);
g = Unpremultiply(g, a);
b = Unpremultiply(b, a);
}
}
// RGB, red byte first
aData[0] = r; aData[1] = g; aData[2] = b;
}
static PRUint8 Premultiply(PRUint8 aVal, PRUint8 aAlpha) {
PRUint32 r;
FAST_DIVIDE_BY_255(r, aVal*aAlpha);
return (PRUint8)r;
}
static PRUint32 ThreeChannelToARGB(PRUint8* aData, PRUint8 aAlpha) {
PRUint8 r, g, b;
// RGB, red byte first
r = aData[0]; g = aData[1]; b = aData[2];
if (aAlpha != 0xFF) {
if (aAlpha == 0) {
r = 0;
g = 0;
b = 0;
} else {
r = Premultiply(r, aAlpha);
g = Premultiply(g, aAlpha);
b = Premultiply(b, aAlpha);
}
}
// Output is always ARGB with A in the high byte of a dword
return (aAlpha << 24) | (r << 16) | (g << 8) | b;
}

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

@ -88,31 +88,28 @@ public:
NS_IMETHOD LockImagePixels(PRBool aMaskPixels);
NS_IMETHOD UnlockImagePixels(PRBool aMaskPixels);
void UpdateFromLockedData();
NS_IMETHOD GetSurface(gfxASurface **aSurface) {
*aSurface = ThebesSurface();
NS_ADDREF(*aSurface);
return NS_OK;
}
gfxASurface* ThebesSurface() {
if (mOptSurface)
return mOptSurface;
EnsureImageSurface();
return mImageSurface;
}
protected:
void EnsureImageSurface();
PRInt32 mWidth;
PRInt32 mHeight;
PRInt32 mStride;
nsRect mDecoded;
nsRefPtr<gfxImageSurface> mImageSurface;
nsRefPtr<gfxASurface> mOptSurface;
// temporary buffers for Lock()
PRUint8* mLockedData;
PRUint8* mLockedAlpha;
PRUint8 mAlphaDepth;
PRUint8 mRealAlphaDepth;
PRPackedBool mLocked;

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

@ -66,7 +66,7 @@ public:
virtual ~gfxImageSurface();
// ImageSurface methods
int Format() const { return mFormat; }
gfxImageFormat Format() const { return mFormat; }
long Width() const { return mWidth; }
long Height() const { return mHeight; }
/**
@ -82,7 +82,7 @@ public:
private:
unsigned char *mData;
int mFormat;
gfxImageFormat mFormat;
long mWidth;
long mHeight;
};

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

@ -44,6 +44,8 @@
#include "gfxTypes.h"
#include "gfxASurface.h"
class gfxImageSurface;
class NS_EXPORT gfxPlatform {
public:
/**
@ -69,9 +71,12 @@ public:
* create a surface that is optimized for rapid pixel
* changing.
*/
virtual gfxASurface *CreateOffscreenSurface(PRUint32 width,
PRUint32 height,
gfxASurface::gfxImageFormat imageFormat) = 0;
virtual already_AddRefed<gfxASurface> CreateOffscreenSurface(PRUint32 width,
PRUint32 height,
gfxASurface::gfxImageFormat imageFormat) = 0;
virtual already_AddRefed<gfxASurface> OptimizeImage(gfxImageSurface *aSurface);
/*
* Font bits

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

@ -54,9 +54,9 @@ public:
return (gfxWindowsPlatform*) gfxPlatform::GetPlatform();
}
gfxASurface *CreateOffscreenSurface(PRUint32 width,
PRUint32 height,
gfxASurface::gfxImageFormat imageFormat);
already_AddRefed<gfxASurface> CreateOffscreenSurface(PRUint32 width,
PRUint32 height,
gfxASurface::gfxImageFormat imageFormat);
nsresult GetFontList(const nsACString& aLangGroup,
const nsACString& aGenericFamily,

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

@ -45,6 +45,9 @@
#include "gfxPlatformGtk.h"
#endif
#include "gfxContext.h"
#include "gfxImageSurface.h"
#ifdef MOZ_ENABLE_GLITZ
#include <stdlib.h>
#endif
@ -92,6 +95,27 @@ gfxPlatform::SetUseGlitz(PRBool use)
gGlitzState = (use ? 1 : 0);
}
already_AddRefed<gfxASurface>
gfxPlatform::OptimizeImage(gfxImageSurface* aSurface)
{
nsRefPtr<gfxASurface> optSurface;
optSurface = CreateOffscreenSurface(aSurface->Width(),
aSurface->Height(),
aSurface->Format());
if (!optSurface)
return nsnull;
nsRefPtr<gfxContext> tmpCtx(new gfxContext(optSurface));
tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
tmpCtx->SetSource(aSurface);
tmpCtx->Paint();
gfxASurface *ret = optSurface;
NS_ADDREF(ret);
return ret;
}
nsresult
gfxPlatform::GetFontList(const nsACString& aLangGroup,
const nsACString& aGenericFamily,

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

@ -70,7 +70,7 @@ gfxPlatformGtk::gfxPlatformGtk()
#endif
}
gfxASurface*
already_AddRefed<gfxASurface>
gfxPlatformGtk::CreateOffscreenSurface(PRUint32 width,
PRUint32 height,
gfxASurface::gfxImageFormat imageFormat)
@ -178,6 +178,7 @@ gfxPlatformGtk::CreateOffscreenSurface(PRUint32 width,
#endif
}
NS_IF_ADDREF(newSurface);
return newSurface;
}

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

@ -53,7 +53,7 @@ gfxPlatformMac::gfxPlatformMac()
#endif
}
gfxASurface*
already_AddRefed<gfxASurface>
gfxPlatformMac::CreateOffscreenSurface(PRUint32 width,
PRUint32 height,
gfxASurface::gfxImageFormat imageFormat)
@ -129,5 +129,6 @@ gfxPlatformMac::CreateOffscreenSurface(PRUint32 width,
#endif
}
NS_IF_ADDREF(newSurface);
return newSurface;
}

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

@ -79,12 +79,14 @@ gfxWindowsPlatform::Init()
mFontList->Compact();
}
gfxASurface*
already_AddRefed<gfxASurface>
gfxWindowsPlatform::CreateOffscreenSurface(PRUint32 width,
PRUint32 height,
gfxASurface::gfxImageFormat imageFormat)
{
return new gfxWindowsSurface(nsnull, width, height, imageFormat);
gfxASurface *surf = new gfxWindowsSurface(nsnull, width, height, imageFormat);
NS_IF_ADDREF(surf);
return surf;
}
int CALLBACK

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

@ -89,6 +89,7 @@ SHARED_LIBRARY_LIBS = \
EXTRA_DSO_LIBS = \
gkgfx \
thebes \
$(NULL)

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

@ -159,6 +159,13 @@ nsresult nsBMPDecoder::WriteRLERows(PRUint32 rows)
for (bit = 128; bit; bit >>= 1)
byte |= *pos++ & bit;
mAlpha[cnt] = byte;
#ifdef MOZ_CAIRO_GFX
#ifdef IS_LITTLE_ENDIAN
mDecoded[(cnt * 4) + 3] = byte ? 255 : 0;
#else
mDecoded[(cnt * 4)] = byte ? 255 : 0;
#endif
#endif
}
for (cnt = 0; cnt < rows; cnt++) {

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

@ -125,7 +125,7 @@ struct bitFields {
#define RLE_GFXFORMAT_ALPHA gfxIFormats::RGB_A1
#endif
#if !defined(MOZ_CAIRO_GFX) && (defined(XP_MAC) || defined(XP_MACOSX))
#if defined(MOZ_CAIRO_GFX) || defined(XP_MAC) || defined(XP_MACOSX)
#define GFXBYTESPERPIXEL 4
#else
#define GFXBYTESPERPIXEL 3
@ -230,9 +230,26 @@ private:
/** Sets the pixel data in aDecoded to the given values.
* The variable passed in as aDecoded will be moved on 3 bytes! */
inline void SetPixel(PRUint8*& aDecoded, PRUint8 aRed, PRUint8 aGreen, PRUint8 aBlue)
inline void SetPixel(PRUint8*& aDecoded, PRUint8 aRed, PRUint8 aGreen, PRUint8 aBlue, PRUint8 aAlpha = 0xFF)
{
#if !defined(MOZ_CAIRO_GFX) && (defined(XP_MAC) || defined(XP_MACOSX))
#if defined(MOZ_CAIRO_GFX)
#ifdef IS_LITTLE_ENDIAN
// BGRX
*aDecoded++ = aBlue;
*aDecoded++ = aGreen;
*aDecoded++ = aRed;
*aDecoded++ = aAlpha;
#else
// XRGB
*aDecoded++ = aAlpha;
*aDecoded++ = aRed;
*aDecoded++ = aGreen;
*aDecoded++ = aBlue;
#endif
#else // MOZ_CAIRO_GFX
#if defined(XP_MAC) || defined(XP_MACOSX)
*aDecoded++ = 0; // Mac needs this padding byte
#endif
#ifdef USE_RGB
@ -244,6 +261,7 @@ inline void SetPixel(PRUint8*& aDecoded, PRUint8 aRed, PRUint8 aGreen, PRUint8 a
*aDecoded++ = aGreen;
*aDecoded++ = aRed;
#endif
#endif // MOZ_CAIRO_GFX
}
inline void SetPixel(PRUint8*& aDecoded, PRUint8 idx, colorTable* aColors)

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

@ -73,7 +73,7 @@ nsresult nsICODecoder::SetImageData()
// Since the ICO is decoded into an exact sized array, the frame may use
// more bytes per row of pixels than the decoding array.
#if !defined(MOZ_CAIRO_GFX) && (defined(XP_MAC) || defined(XP_MACOSX))
#if defined(MOZ_CAIRO_GFX) || defined(XP_MAC) || defined(XP_MACOSX)
PRUint32 decodedLineLen = mDirEntry.mWidth * 4;
#else
PRUint32 decodedLineLen = mDirEntry.mWidth * 3;
@ -400,7 +400,7 @@ nsresult nsICODecoder::ProcessData(const char* aBuffer, PRUint32 aCount) {
if (mPos == (mImageOffset + BITMAPINFOSIZE + mNumColors*4)) {
// Increment mPos to avoid reprocessing the info header.
mPos++;
#if !defined(MOZ_CAIRO_GFX) && (defined(XP_MAC) || defined(XP_MACOSX))
#if defined(MOZ_CAIRO_GFX) || defined(XP_MAC) || defined(XP_MACOSX)
mDecodedBuffer = (PRUint8*)malloc(mDirEntry.mHeight*mDirEntry.mWidth*4);
#else
mDecodedBuffer = (PRUint8*)malloc(mDirEntry.mHeight*mDirEntry.mWidth*3);

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

@ -51,6 +51,8 @@ LIBXUL_LIBRARY = 1
REQUIRES = xpcom \
string \
gfx \
thebes \
cairo \
imglib2 \
$(NULL)

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

@ -48,6 +48,10 @@
#include "nsIInterfaceRequestorUtils.h"
#include "nsMemory.h"
#ifdef MOZ_CAIRO_GFX
#include "gfxContext.h"
#endif
NS_IMPL_ISUPPORTS2(imgContainerGIF, imgIContainer, nsITimerCallback)
//******************************************************************************
@ -951,11 +955,28 @@ void imgContainerGIF::SetMaskVisibility(gfxIImageFrame *aFrame, PRBool aVisible)
PRUint32 alphaDataLength;
const PRUint8 setMaskTo = aVisible ? 0xFF : 0x00;
#ifdef MOZ_CAIRO_GFX
aFrame->LockImageData();
nsresult res = aFrame->GetImageData(&alphaData, &alphaDataLength);
if (NS_SUCCEEDED(res)) {
for (PRUint32 i = 0; i < alphaDataLength; i+=4) {
#ifdef IS_LITTLE_ENDIAN
alphaData[i+3] = setMaskTo;
#else
alphaData[i] = setMaskTo;
#endif
}
}
aFrame->UnlockImageData();
#else
aFrame->LockAlphaData();
nsresult res = aFrame->GetAlphaData(&alphaData, &alphaDataLength);
if (NS_SUCCEEDED(res) && alphaData && alphaDataLength)
memset(alphaData, setMaskTo, alphaDataLength);
aFrame->UnlockAlphaData();
#endif
}
//******************************************************************************
@ -964,11 +985,23 @@ void imgContainerGIF::BlackenFrame(gfxIImageFrame *aFrame)
{
if (!aFrame)
return;
#ifdef MOZ_CAIRO_GFX
nsCOMPtr<nsIImage> img(do_GetInterface(aFrame));
if (!img)
return;
nsRefPtr<gfxASurface> surf;
img->GetSurface(getter_AddRefs(surf));
nsRefPtr<gfxContext> ctx = new gfxContext(surf);
ctx->SetColor(gfxRGBA(0, 0, 0));
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
ctx->Paint();
#else
PRUint32 aDataLength;
aFrame->GetImageDataLength(&aDataLength);
aFrame->SetImageData(nsnull, aDataLength, 0);
#endif
}
//******************************************************************************
@ -994,7 +1027,7 @@ void imgContainerGIF::BlackenFrame(gfxIImageFrame *aFrame,
PRUint32 bpr; // Bytes Per Row
aFrame->GetImageBytesPerRow(&bpr);
#if !defined(MOZ_CAIRO_GFX) && (defined(XP_MAC) || defined(XP_MACOSX))
#if defined(MOZ_CAIRO_GFX) && (defined(XP_MAC) || defined(XP_MACOSX))
const PRUint8 bpp = 4;
#else
const PRUint8 bpp = 3;
@ -1035,6 +1068,7 @@ PRBool imgContainerGIF::CopyFrameImage(gfxIImageFrame *aSrcFrame,
memcpy(aDataDest, aDataSrc, aDataLengthSrc);
aDstFrame->UnlockImageData();
#ifndef MOZ_CAIRO_GFX
// Copy Alpha/Mask Over
// If no mask, lockAlpha will tell us
if (NS_SUCCEEDED(aDstFrame->LockAlphaData())) {
@ -1047,6 +1081,7 @@ PRBool imgContainerGIF::CopyFrameImage(gfxIImageFrame *aSrcFrame,
aDstFrame->UnlockAlphaData();
}
#endif
// Tell the image that it's data has been updated
nsCOMPtr<nsIInterfaceRequestor> ireq(do_QueryInterface(aDstFrame));

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

@ -503,18 +503,55 @@ int nsGIFDecoder2::HaveDecodedRow(
} else {
PRUint8* rgbRowIndex = decoder->mRGBLine;
PRUint8* rowBufIndex = aRowBufPtr;
#if defined(MOZ_CAIRO_GFX)
while (rowBufIndex != decoder->mGIFStruct->rowend) {
if (*rowBufIndex >= cmapsize ||
((format == gfxIFormats::RGB_A1 || format == gfxIFormats::BGR_A1) &&
(*rowBufIndex == decoder->mGIFStruct->tpixel))) {
*rgbRowIndex++ = 0;
*rgbRowIndex++ = 0;
*rgbRowIndex++ = 0;
*rgbRowIndex++ = 0;
++rowBufIndex;
continue;
}
const PRUint32 colorIndex = *rowBufIndex * 3;
const PRUint8 r = cmap[colorIndex]; // red
const PRUint8 g = cmap[colorIndex + 1]; // green
const PRUint8 b = cmap[colorIndex + 2]; // blue
#ifdef IS_LITTLE_ENDIAN
// BGRX
*rgbRowIndex++ = b;
*rgbRowIndex++ = g;
*rgbRowIndex++ = r;
*rgbRowIndex++ = 0xFF;
#else
// XRGB
*rgbRowIndex++ = 0xFF;
*rgbRowIndex++ = r;
*rgbRowIndex++ = g;
*rgbRowIndex++ = b;
#endif
++rowBufIndex;
}
for (int i=0; i<aDuplicateCount; i++)
decoder->mImageFrame->SetImageData(decoder->mRGBLine, bpr, (aRowNumber+i)*bpr);
#else
switch (format) {
case gfxIFormats::RGB:
case gfxIFormats::BGR:
{
while (rowBufIndex != decoder->mGIFStruct->rowend) {
#if !defined(MOZ_CAIRO_GFX) && (defined(XP_MAC) || defined(XP_MACOSX))
#if defined(XP_MAC) || defined(XP_MACOSX)
*rgbRowIndex++ = 0; // Mac is always 32bits per pixel, this is pad
#endif
if (*rowBufIndex < cmapsize) {
PRUint32 colorIndex = *rowBufIndex * 3;
#if !defined(MOZ_CAIRO_GFX) && (defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS) || defined(MOZ_WIDGET_PHOTON))
#if defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS) || defined(MOZ_WIDGET_PHOTON)
*rgbRowIndex++ = cmap[colorIndex + 2]; // blue
*rgbRowIndex++ = cmap[colorIndex + 1]; // green
*rgbRowIndex++ = cmap[colorIndex]; // red
@ -543,12 +580,12 @@ int nsGIFDecoder2::HaveDecodedRow(
memset(decoder->mAlphaLine, 0, abpr);
for (PRUint32 x = 0; x < (PRUint32)width; ++x) {
if (*rowBufIndex != decoder->mGIFStruct->tpixel) {
#if !defined(MOZ_CAIRO_GFX) && (defined(XP_MAC) || defined(XP_MACOSX))
#if defined(XP_MAC) || defined(XP_MACOSX)
*rgbRowIndex++ = 0; // Mac is always 32bits per pixel, this is pad
#endif
if (*rowBufIndex < cmapsize) {
PRUint32 colorIndex = *rowBufIndex * 3;
#if !defined(MOZ_CAIRO_GFX) && (defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS) || defined(MOZ_WIDGET_PHOTON))
#if defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS) || defined(MOZ_WIDGET_PHOTON)
*rgbRowIndex++ = cmap[colorIndex + 2]; // blue
*rgbRowIndex++ = cmap[colorIndex + 1]; // green
*rgbRowIndex++ = cmap[colorIndex]; // red
@ -564,7 +601,7 @@ int nsGIFDecoder2::HaveDecodedRow(
}
decoder->mAlphaLine[x>>3] |= 1<<(7-x&0x7);
} else {
#if !defined(MOZ_CAIRO_GFX) && (defined(XP_MAC) || defined(XP_MACOSX))
#if defined(XP_MAC) || defined(XP_MACOSX)
rgbRowIndex+=4;
#else
rgbRowIndex+=3;
@ -581,6 +618,7 @@ int nsGIFDecoder2::HaveDecodedRow(
break;
}
}
#endif
}
decoder->mCurrentRow = aRowNumber + aDuplicateCount - 1;

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

@ -146,12 +146,40 @@ NS_IMETHODIMP nsIconDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PR
NS_ERROR_UNEXPECTED);
PRInt32 rownum;
#if defined(MOZ_CAIRO_GFX)
PRUint8 *row = malloc(bpr);
PRUint8 *adata = data + (bpr * height);
for (rownum = 0; rownum < height; ++rownum, data += bpr) {
PRInt8 *rowdata = data;
for (int i = 0; i < bpr; i++) {
const PRUint8 r = *rowdata++;
const PRUint8 g = *rowdata++;
const PRUint8 b = *rowdata++;
const PRUint8 a = (format == gfxIFormat::RGB_A1) ? abpr[i>>3] : abpr[i];
#ifdef IS_LITTLE_ENDIAN
// BGRX
*row++ = b;
*row++ = g;
*row++ = r;
*row++ = a;
#else
// XRGB
*row++ = a;
*row++ = r;
*row++ = g;
*row++ = b;
#endif
}
mFrame->SetImageData(row, bpr, rownum * bpr);
}
free(row);
#else
for (rownum = 0; rownum < height; ++rownum, data += bpr)
mFrame->SetImageData(data, bpr, rownum * bpr);
for (rownum = 0; rownum < height; ++rownum, data += abpr)
mFrame->SetAlphaData(data, abpr, rownum * abpr);
#endif
nsIntRect r(0, 0, width, height);
mObserver->OnDataAvailable(nsnull, mFrame, &r);

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

@ -353,7 +353,7 @@ NS_IMETHODIMP nsJPEGDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PR
// Note! row_stride here must match the row_stride in
// nsJPEGDecoder::OutputScanlines
#if !defined(MOZ_CAIRO_GFX) && (defined(XP_MAC) || defined(XP_MACOSX))
#if defined(MOZ_CAIRO_GFX) || defined(XP_MAC) || defined(XP_MACOSX)
row_stride = mInfo.output_width * 4;
#else
row_stride = mInfo.output_width * 3;
@ -363,7 +363,7 @@ NS_IMETHODIMP nsJPEGDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PR
JPOOL_IMAGE,
row_stride, 1);
#if defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS) || defined(XP_MAC) || defined(XP_MACOSX) || defined(MOZ_WIDGET_PHOTON)
#if defined(MOZ_CAIRO_GFX) || defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS) || defined(XP_MAC) || defined(XP_MACOSX) || defined(MOZ_WIDGET_PHOTON)
// allocate buffer to do byte flipping / padding
mRGBRow = (PRUint8*) PR_MALLOC(row_stride);
#endif
@ -517,7 +517,32 @@ nsJPEGDecoder::OutputScanlines()
break;
}
#if !defined(MOZ_CAIRO_GFX) && (defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS) || defined(MOZ_WIDGET_PHOTON))
#if defined(MOZ_CAIRO_GFX)
PRUint8 *ptrOutputBuf = mRGBRow;
JSAMPLE *j1 = mSamples[0];
for (PRUint32 i=0; i < mInfo.output_width; ++i) {
const PRUint8 r = *j1++;
const PRUint8 g = *j1++;
const PRUint8 b = *j1++;
#ifdef IS_LITTLE_ENDIAN
// BGRX
*ptrOutputBuf++ = b;
*ptrOutputBuf++ = g;
*ptrOutputBuf++ = r;
*ptrOutputBuf++ = 0xFF;
#else
// XRGB
*ptrOutputBuf++ = 0xFF;
*ptrOutputBuf++ = r;
*ptrOutputBuf++ = g;
*ptrOutputBuf++ = b;
#endif
}
samples = mRGBRow;
#elif defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS) || defined(MOZ_WIDGET_PHOTON)
PRUint8 *ptrOutputBuf = mRGBRow;
JSAMPLE *j1 = mSamples[0];
@ -529,7 +554,7 @@ nsJPEGDecoder::OutputScanlines()
}
samples = mRGBRow;
#elif !defined(MOZ_CAIRO_GFX) && (defined(XP_MAC) || defined(XP_MACOSX))
#elif defined(XP_MAC) || defined(XP_MACOSX)
PRUint8 *ptrOutputBuf = mRGBRow;
JSAMPLE *j1 = mSamples[0];
@ -548,7 +573,7 @@ nsJPEGDecoder::OutputScanlines()
// Note! row_stride here must match the row_stride in
// nsJPEGDecoder::WriteFrom
#if !defined(MOZ_CAIRO_GFX) && (defined(XP_MAC) || defined(XP_MACOSX))
#if defined(MOZ_CAIRO_GFX) || defined(XP_MAC) || defined(XP_MACOSX)
int row_stride = mInfo.output_width * 4;
#else
int row_stride = mInfo.output_width * 3;

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

@ -21,7 +21,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
* Stuart Parmenter <stuart@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -435,7 +435,29 @@ row_callback(png_structp png_ptr, png_bytep new_row,
switch (format) {
case gfxIFormats::RGB:
case gfxIFormats::BGR:
#if !defined(MOZ_CAIRO_GFX) && (defined(XP_MAC) || defined(XP_MACOSX))
{
#if defined(MOZ_CAIRO_GFX)
cptr = decoder->colorLine;
for (PRUint32 x=0; x<iwidth; x++) {
const PRUint8 r = *line++;
const PRUint8 g = *line++;
const PRUint8 b = *line++;
#ifdef IS_LITTLE_ENDIAN
// BGRX
*cptr++ = b;
*cptr++ = g;
*cptr++ = r;
*cptr++ = 0xFF;
#else
// XRGB
*cptr++ = 0xFF;
*cptr++ = r;
*cptr++ = g;
*cptr++ = b;
#endif
}
decoder->mFrame->SetImageData(decoder->colorLine, bpr, row_num*bpr);
#elif defined(XP_MAC) || defined(XP_MACOSX)
cptr = decoder->colorLine;
for (PRUint32 x=0; x<iwidth; x++) {
*cptr++ = 0;
@ -447,10 +469,41 @@ row_callback(png_structp png_ptr, png_bytep new_row,
#else
decoder->mFrame->SetImageData((PRUint8*)line, bpr, row_num*bpr);
#endif
}
break;
case gfxIFormats::RGB_A1:
case gfxIFormats::BGR_A1:
{
#if defined(MOZ_CAIRO_GFX)
cptr = decoder->colorLine;
for (PRUint32 x=0; x<iwidth; x++) {
if (line[3]) {
const PRUint8 r = *line++;
const PRUint8 g = *line++;
const PRUint8 b = *line++;
#ifdef IS_LITTLE_ENDIAN
*cptr++ = b;
*cptr++ = g;
*cptr++ = r;
*cptr++ = 0xFF;
#else
*cptr++ = 0xFF;
*cptr++ = r;
*cptr++ = g;
*cptr++ = b;
#endif
line++;
} else {
*cptr++ = 0;
*cptr++ = 0;
*cptr++ = 0;
*cptr++ = 0;
line += 4;
}
}
decoder->mFrame->SetImageData(decoder->colorLine, bpr, row_num*bpr);
#else
cptr = decoder->colorLine;
aptr = decoder->alphaLine;
memset(aptr, 0, abpr);
@ -473,45 +526,56 @@ row_callback(png_structp png_ptr, png_bytep new_row,
}
decoder->mFrame->SetAlphaData(decoder->alphaLine, abpr, row_num*abpr);
decoder->mFrame->SetImageData(decoder->colorLine, bpr, row_num*bpr);
#endif
}
break;
case gfxIFormats::RGB_A8:
case gfxIFormats::BGR_A8:
{
cptr = decoder->colorLine;
aptr = decoder->alphaLine;
#if defined(MOZ_CAIRO_GFX)
for (PRUint32 x=0; x<iwidth; x++) {
#if !defined(MOZ_CAIRO_GFX) && (defined(XP_MAC) || defined(XP_MACOSX))
*cptr++ = 0;
#endif
*cptr++ = *line++;
*cptr++ = *line++;
*cptr++ = *line++;
*aptr++ = *line++;
}
decoder->mFrame->SetAlphaData(decoder->alphaLine, abpr, row_num*abpr);
decoder->mFrame->SetImageData(decoder->colorLine, bpr, row_num*bpr);
}
break;
case gfxIFormats::RGBA:
case gfxIFormats::BGRA:
#if !defined(MOZ_CAIRO_GFX) && (defined(XP_MAC) || defined(XP_MACOSX))
{
cptr = decoder->colorLine;
aptr = decoder->alphaLine;
for (PRUint32 x=0; x<iwidth; x++) {
*cptr++ = 0;
*cptr++ = *line++;
*cptr++ = *line++;
*cptr++ = *line++;
*aptr++ = *line++;
}
decoder->mFrame->SetAlphaData(decoder->alphaLine, abpr, row_num*abpr);
decoder->mFrame->SetImageData(decoder->colorLine, bpr, row_num*bpr);
}
const PRUint8 r = *line++;
const PRUint8 g = *line++;
const PRUint8 b = *line++;
const PRUint8 a = *line++;
if (a == 0) {
*cptr++ = 0;
*cptr++ = 0;
*cptr++ = 0;
*cptr++ = 0;
} else {
#ifdef IS_LITTLE_ENDIAN
// BGRA
FAST_DIVIDE_BY_255(*cptr++, b*a);
FAST_DIVIDE_BY_255(*cptr++, g*a);
FAST_DIVIDE_BY_255(*cptr++, r*a);
*cptr++ = a;
#else
decoder->mFrame->SetImageData(line, bpr, row_num*bpr);
// ARGB
*cptr++ = a;
FAST_DIVIDE_BY_255(*cptr++, r*a);
FAST_DIVIDE_BY_255(*cptr++, g*a);
FAST_DIVIDE_BY_255(*cptr++, b*a);
#endif
}
}
decoder->mFrame->SetImageData(decoder->colorLine, bpr, row_num*bpr);
#else
for (PRUint32 x=0; x<iwidth; x++) {
#if defined(XP_MAC) || defined(XP_MACOSX)
*cptr++ = 0;
#endif
*cptr++ = *line++;
*cptr++ = *line++;
*cptr++ = *line++;
*aptr++ = *line++;
}
decoder->mFrame->SetAlphaData(decoder->alphaLine, abpr, row_num*abpr);
decoder->mFrame->SetImageData(decoder->colorLine, bpr, row_num*bpr);
#endif
}
break;
}

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

@ -256,19 +256,30 @@ nsresult nsXBMDecoder::ProcessData(const char* aData, PRUint32 aCount) {
hiByte = !hiByte;
}
#ifdef MOZ_CAIRO_GFX
PRUint32 *ar = ((PRUint32*)mAlphaRow) + mCurCol;
for (int i = 0; i < 8; i++) {
const PRUint8 val = ((pixel & (1 << i)) >> i) ? 255 : 0;
*ar++ = (val << 24) | 0;
}
#else // MOZ_CAIRO_GFX
mAlphaRow[mCurCol/8] = 0;
for (int i = 0; i < 8; i++) {
PRUint8 val = (pixel & (1 << i)) >> i;
mAlphaRow[mCurCol/8] |= val << (7 - i);
}
#endif
mCurCol = PR_MIN(mCurCol + 8, mWidth);
if (mCurCol == mWidth || mState == RECV_DONE) {
#ifdef MOZ_CAIRO_GFX
mFrame->SetImageData(mAlphaRow, abpr, mCurRow * abpr);
#else
// Row finished. Set Data.
mFrame->SetAlphaData(mAlphaRow, abpr, mCurRow * abpr);
// nsnull gets interpreted as all-zeroes, which is what we
// want
mFrame->SetImageData(nsnull, bpr, mCurRow * bpr);
#endif
nsIntRect r(0, mCurRow, mWidth, 1);
mObserver->OnDataAvailable(nsnull, mFrame, &r);