From f2bab4cf0ce0b3d8535f168d594335644dad3900 Mon Sep 17 00:00:00 2001 From: "reed%reedloden.com" Date: Tue, 27 Nov 2007 09:35:19 +0000 Subject: [PATCH] Bug 364221 - "[cairo] bad page scrolling performance with large background images" [p=alfredkayser@nl.ibm.com (Alfred Kayser) / vladimir@pobox.com (Vladimir Vukicevic [vlad]) r=stuart sr=tor a=blocking1.9+] --- gfx/src/thebes/nsThebesImage.cpp | 28 +++++++++++-------- gfx/src/thebes/nsThebesImage.h | 1 + gfx/thebes/public/gfxPlatform.h | 7 ++--- gfx/thebes/src/gfxPlatform.cpp | 10 +++---- .../libpr0n/decoders/gif/nsGIFDecoder2.cpp | 17 +++++++++++ modules/libpr0n/decoders/gif/nsGIFDecoder2.h | 1 + 6 files changed, 43 insertions(+), 21 deletions(-) diff --git a/gfx/src/thebes/nsThebesImage.cpp b/gfx/src/thebes/nsThebesImage.cpp index 5941aac2e5b..95ec4f5087e 100644 --- a/gfx/src/thebes/nsThebesImage.cpp +++ b/gfx/src/thebes/nsThebesImage.cpp @@ -66,6 +66,7 @@ nsThebesImage::nsThebesImage() mDecoded(0,0,0,0), mImageComplete(PR_FALSE), mSinglePixel(PR_FALSE), + mFormatChanged(PR_FALSE), mAlphaDepth(0) { static PRBool hasCheckedOptimize = PR_FALSE; @@ -254,6 +255,8 @@ nsThebesImage::Optimize(nsIDeviceContext* aContext) if (ShouldUseImageSurfaces()) return NS_OK; + mOptSurface = nsnull; + #ifdef XP_WIN // we need to special-case windows here, because windows has // a distinction between DIB and DDB and we want to use DDBs as much @@ -288,21 +291,22 @@ nsThebesImage::Optimize(nsIDeviceContext* aContext) mOptSurface = wsurf; } } - - if (!mOptSurface) { - // just use the DIB + if (!mOptSurface && !mFormatChanged) { + // just use the DIB if the format has not changed mOptSurface = mWinSurface; } - } else { - mOptSurface = gfxPlatform::GetPlatform()->OptimizeImage(mImageSurface); } - - mWinSurface = nsnull; -#else - mOptSurface = gfxPlatform::GetPlatform()->OptimizeImage(mImageSurface); #endif - mImageSurface = nsnull; + if (mOptSurface == nsnull) + mOptSurface = gfxPlatform::GetPlatform()->OptimizeImage(mImageSurface, mFormat); + + if (mOptSurface) { + mImageSurface = nsnull; +#ifdef XP_WIN + mWinSurface = nsnull; +#endif + } return NS_OK; } @@ -636,6 +640,8 @@ nsThebesImage::ShouldUseImageSurfaces() void nsThebesImage::SetHasNoAlpha() { - if (mFormat == gfxASurface::ImageFormatARGB32) + if (mFormat == gfxASurface::ImageFormatARGB32) { mFormat = gfxASurface::ImageFormatRGB24; + mFormatChanged = PR_TRUE; + } } diff --git a/gfx/src/thebes/nsThebesImage.h b/gfx/src/thebes/nsThebesImage.h index a764086c5c1..08fbae94f80 100644 --- a/gfx/src/thebes/nsThebesImage.h +++ b/gfx/src/thebes/nsThebesImage.h @@ -142,6 +142,7 @@ protected: nsRect mDecoded; PRPackedBool mImageComplete; PRPackedBool mSinglePixel; + PRPackedBool mFormatChanged; #ifdef XP_WIN PRPackedBool mIsDDBSurface; #endif diff --git a/gfx/thebes/public/gfxPlatform.h b/gfx/thebes/public/gfxPlatform.h index 8ee8291ff4a..82e995e1c76 100644 --- a/gfx/thebes/public/gfxPlatform.h +++ b/gfx/thebes/public/gfxPlatform.h @@ -87,15 +87,14 @@ public: /** * Create an offscreen surface of the given dimensions - * and image format. If fastPixelAccess is TRUE, - * create a surface that is optimized for rapid pixel - * changing. + * and image format. */ virtual already_AddRefed CreateOffscreenSurface(const gfxIntSize& size, gfxASurface::gfxImageFormat imageFormat) = 0; - virtual already_AddRefed OptimizeImage(gfxImageSurface *aSurface); + virtual already_AddRefed OptimizeImage(gfxImageSurface *aSurface, + gfxASurface::gfxImageFormat format); /* * Font bits diff --git a/gfx/thebes/src/gfxPlatform.cpp b/gfx/thebes/src/gfxPlatform.cpp index 2a619c0e68f..fc9528eb7d2 100644 --- a/gfx/thebes/src/gfxPlatform.cpp +++ b/gfx/thebes/src/gfxPlatform.cpp @@ -195,15 +195,13 @@ gfxPlatform::SetUseGlitz(PRBool use) } already_AddRefed -gfxPlatform::OptimizeImage(gfxImageSurface *aSurface) +gfxPlatform::OptimizeImage(gfxImageSurface *aSurface, + gfxASurface::gfxImageFormat format) { const gfxIntSize& surfaceSize = aSurface->GetSize(); - gfxASurface::gfxImageFormat realFormat = aSurface->Format(); - - nsRefPtr optSurface = CreateOffscreenSurface(surfaceSize, realFormat); - - if (!optSurface) + nsRefPtr optSurface = CreateOffscreenSurface(surfaceSize, format); + if (!optSurface || optSurface->CairoStatus() != 0) return nsnull; nsRefPtr tmpCtx(new gfxContext(optSurface)); diff --git a/modules/libpr0n/decoders/gif/nsGIFDecoder2.cpp b/modules/libpr0n/decoders/gif/nsGIFDecoder2.cpp index f1abccc1e33..01fd8d37fdc 100644 --- a/modules/libpr0n/decoders/gif/nsGIFDecoder2.cpp +++ b/modules/libpr0n/decoders/gif/nsGIFDecoder2.cpp @@ -121,6 +121,7 @@ nsGIFDecoder2::nsGIFDecoder2() , mLastFlushedPass(0) , mOldColor(0) , mGIFOpen(PR_FALSE) + , mSawTransparency(PR_FALSE) { // Clear out the structure, excluding the arrays memset(&mGIFStruct, 0, sizeof(mGIFStruct)); @@ -380,6 +381,11 @@ void nsGIFDecoder2::EndImageFrame() mGIFStruct.screen_height - realFrameHeight); mObserver->OnDataAvailable(nsnull, mImageFrame, &r); } + // This transparency check is only valid for first frame + if (mGIFStruct.is_transparent && !mSawTransparency) { + nsCOMPtr img(do_GetInterface(mImageFrame)); + img->SetHasNoAlpha(); + } } mCurrentRow = mLastFlushedRow = -1; mCurrentPass = mLastFlushedPass = 0; @@ -458,6 +464,17 @@ PRUint32 nsGIFDecoder2::OutputRow() *--to = cmap[*--from]; } + // check for alpha (only for first frame) + if (mGIFStruct.is_transparent && !mSawTransparency) { + const PRUint32 *rgb = (PRUint32*)rowp; + for (PRUint32 i = mGIFStruct.width; i > 0; i--) { + if (*rgb++ == 0) { + mSawTransparency = PR_TRUE; + break; + } + } + } + // Duplicate rows if (drow_end > drow_start) { // irow is the current row filled diff --git a/modules/libpr0n/decoders/gif/nsGIFDecoder2.h b/modules/libpr0n/decoders/gif/nsGIFDecoder2.h index 3f90468756f..570cca2e1f5 100644 --- a/modules/libpr0n/decoders/gif/nsGIFDecoder2.h +++ b/modules/libpr0n/decoders/gif/nsGIFDecoder2.h @@ -99,6 +99,7 @@ private: PRUint8 mCurrentPass; PRUint8 mLastFlushedPass; PRPackedBool mGIFOpen; + PRPackedBool mSawTransparency; gif_struct mGIFStruct; };