Index: gfx/src/thebes/nsThebesImage.cpp =================================================================== RCS file: /cvsroot/mozilla/gfx/src/thebes/nsThebesImage.cpp,v retrieving revision 1.86 diff -u -8 -p -w -r1.86 nsThebesImage.cpp --- gfx/src/thebes/nsThebesImage.cpp 28 Apr 2008 21:27:05 -0000 1.86 +++ gfx/src/thebes/nsThebesImage.cpp 9 Jul 2008 15:52:34 -0000 @@ -16,16 +16,17 @@ * * The Initial Developer of the Original Code is * mozilla.org. * Portions created by the Initial Developer are Copyright (C) 2005 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Vladimir Vukicevic + * Francis Robichaud * * 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 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your @@ -75,16 +76,19 @@ nsThebesImage::nsThebesImage() gDisableOptimize = PR_TRUE; } hasCheckedOptimize = PR_TRUE; } #ifdef XP_WIN mIsDDBSurface = PR_FALSE; #endif +#ifdef XP_UNIX + mTinySurf = nsnull; +#endif } nsresult nsThebesImage::Init(PRInt32 aWidth, PRInt32 aHeight, PRInt32 aDepth, nsMaskRequirements aMaskRequirements) { mWidth = aWidth; mHeight = aHeight; @@ -326,21 +330,26 @@ nsThebesImage::Optimize(nsIDeviceContext #ifdef XP_MACOSX if (mQuartzSurface) { mQuartzSurface->Flush(); mOptSurface = mQuartzSurface; } #endif +#ifndef XP_UNIX if (mOptSurface == nsnull) mOptSurface = gfxPlatform::GetPlatform()->OptimizeImage(mImageSurface, mFormat); +#endif + if (mOptSurface) { +#ifndef XP_UNIX mImageSurface = nsnull; +#endif #ifdef XP_WIN mWinSurface = nsnull; #endif #ifdef XP_MACOSX mQuartzSurface = nsnull; #endif } @@ -451,16 +460,90 @@ nsThebesImage::Draw(nsIRenderingContext gfxFloat xscale = aDestRect.size.width / aSourceRect.size.width; gfxFloat yscale = aDestRect.size.height / aSourceRect.size.height; gfxRect srcRect(aSourceRect); gfxRect subimageRect(aSubimageRect); gfxRect destRect(aDestRect); +#ifdef XP_UNIX + // We optimize the image surface to it's visible size and use scaling algorithms + // to reduce X memory consumption, bug 395260. + if (subimageRect.Height() > destRect.Height() || + subimageRect.Width() > destRect.Width() || + xscale < 1.0 || yscale < 1.0) { + + gfxIntSize tinySize(NS_lroundf(destRect.Width()), NS_lroundf(destRect.Height())); + GdkPixbuf* tinyPix; + GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data(mImageSurface->Data(), GDK_COLORSPACE_RGB, + PR_TRUE, 8, mWidth, mHeight, + mStride, nsnull, nsnull); + // We generate a new tiny surface + mTinySurf = new gfxImageSurface(tinySize, mFormat); + + if (!pixbuf) + return NS_ERROR_FAILURE; + + if (subimageRect.Height() > destRect.Height() || subimageRect.Width() > destRect.Width()) { + tinyPix = gdk_pixbuf_new_subpixbuf(pixbuf, + NS_lroundf(srcRect.pos.x), + NS_lroundf(srcRect.pos.y), + NS_lroundf(srcRect.size.width), + NS_lroundf(srcRect.size.height)); + } else { + tinyPix = pixbuf; + } + + if (!tinyPix) + return NS_ERROR_FAILURE; + + // XXX Shouldn't Cairo have it's own scaling algorithm for image surfaces and use Sun's mediaLib ? + // We can't allow a 1x1 downscaling, causes badalloc with gdk_pixbufs + if ((xscale < 1.0 || yscale < 1.0) && + (tinySize.width != 1 && tinySize.height != 1)) { + // Scales down the pixbuf, R and B channels are inverted but this should not cause any issue. + // XXX we should still verify how GDK_INTERP_BILINEAR reacts to this abstraction. + tinyPix = gdk_pixbuf_scale_simple(tinyPix, tinySize.width, tinySize.height, GDK_INTERP_BILINEAR); + if (!tinyPix) + return NS_ERROR_FAILURE; + + // Disables further scaling operation to avoid bug 364968 explained below. + xscale = 1.0; + yscale = 1.0; + } + + unsigned char* pixels = gdk_pixbuf_get_pixels(tinyPix); + PRInt32 stride = gdk_pixbuf_get_rowstride(tinyPix); + for (int i=0; iData() + mTinySurf->Stride()*i, src, mTinySurf->Stride()); + } + + mOptSurface = gfxPlatform::GetPlatform()->OptimizeImage(mTinySurf, mFormat); + + // Release the gdk objects without affecting the actual image data + g_object_unref(tinyPix); + g_object_unref(pixbuf); + + // Origin could be different than (0,0) + // We always set these values when using a tiny surface + subimageRect.pos.x -= srcRect.pos.x; + srcRect.pos.x -= srcRect.pos.x; + subimageRect.pos.y -= srcRect.pos.y; + srcRect.pos.y -= srcRect.pos.y; + + } else if (mTinySurf || !mOptSurface) { + // We were using a tiny surface and we now see the full image, restore the complete pixmap + mTinySurf = nsnull; + // Send image to X + mOptSurface = gfxPlatform::GetPlatform()->OptimizeImage(mImageSurface, mFormat); + } +#endif + if (!GetIsImageComplete()) { gfxRect decoded = gfxRect(mDecoded.x, mDecoded.y, mDecoded.width, mDecoded.height); srcRect = srcRect.Intersect(decoded); subimageRect = subimageRect.Intersect(decoded); // This happens when mDecoded.width or height is zero. bug 368427. if (NS_UNLIKELY(srcRect.size.width == 0 || srcRect.size.height == 0)) @@ -603,17 +686,16 @@ nsThebesImage::Draw(nsIRenderingContext gfxContext::GraphicsOperator op = ctx->CurrentOperator(); if (op == gfxContext::OPERATOR_OVER && mFormat == gfxASurface::ImageFormatRGB24) ctx->SetOperator(gfxContext::OPERATOR_SOURCE); ctx->NewPath(); ctx->SetPattern(pat); ctx->Rectangle(destRect); ctx->Fill(); - ctx->SetOperator(op); ctx->SetDeviceColor(gfxRGBA(0,0,0,0)); return NS_OK; } nsresult nsThebesImage::ThebesDrawTile(gfxContext *thebesContext, Index: gfx/src/thebes/nsThebesImage.h =================================================================== RCS file: /cvsroot/mozilla/gfx/src/thebes/nsThebesImage.h,v retrieving revision 1.33 diff -u -8 -p -w -r1.33 nsThebesImage.h --- gfx/src/thebes/nsThebesImage.h 31 Mar 2008 09:40:54 -0000 1.33 +++ gfx/src/thebes/nsThebesImage.h 9 Jul 2008 15:52:34 -0000 @@ -35,17 +35,20 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #ifndef _NSTHEBESIMAGE_H_ #define _NSTHEBESIMAGE_H_ #include "nsIImage.h" - +#if defined(XP_UNIX) +#include +#include +#endif #include "gfxColor.h" #include "gfxASurface.h" #include "gfxImageSurface.h" #include "gfxPattern.h" #if defined(XP_WIN) #include "gfxWindowsSurface.h" #elif defined(XP_MACOSX) #include "gfxQuartzImageSurface.h" @@ -166,16 +169,19 @@ protected: #ifdef XP_WIN PRPackedBool mIsDDBSurface; #endif gfxRGBA mSinglePixelColor; nsRefPtr mImageSurface; nsRefPtr mOptSurface; +#if defined(XP_UNIX) + nsRefPtr mTinySurf; +#endif #if defined(XP_WIN) nsRefPtr mWinSurface; #elif defined(XP_MACOSX) nsRefPtr mQuartzSurface; #endif PRUint8 mAlphaDepth;