Index: ./gfx/public/nsIImage.h =================================================================== RCS file: /cvsroot/mozilla/gfx/public/nsIImage.h,v retrieving revision 1.38 diff -u -8 -p -B -b -r1.38 nsIImage.h --- ./gfx/public/nsIImage.h 9 Mar 2008 21:55:06 -0000 1.38 +++ ./gfx/public/nsIImage.h 22 Jul 2008 20:36:07 -0000 @@ -65,16 +65,17 @@ typedef enum { nsMaskRequirements_kNoMask, nsMaskRequirements_kNeeds1Bit, nsMaskRequirements_kNeeds8Bit } nsMaskRequirements; #define nsImageUpdateFlags_kColorMapChanged 0x1 #define nsImageUpdateFlags_kBitsChanged 0x2 +#define nsImageUpdateFlags_ImageIncomplete 0x4 // IID for the nsIImage interface // 96d9d7ce-e575-4265-8507-35555112a430 #define NS_IIMAGE_IID \ { 0x96d9d7ce, 0xe575, 0x4265, \ { 0x85, 0x07, 0x35, 0x55, 0x51, 0x12, 0xa4, 0x30 } } // Interface to Images Index: ./gfx/src/thebes/nsThebesImage.cpp =================================================================== RCS file: /cvsroot/mozilla/gfx/src/thebes/nsThebesImage.cpp,v retrieving revision 1.86 diff -u -8 -p -B -b -r1.86 nsThebesImage.cpp --- ./gfx/src/thebes/nsThebesImage.cpp 28 Apr 2008 21:27:05 -0000 1.86 +++ ./gfx/src/thebes/nsThebesImage.cpp 22 Jul 2008 20:36:07 -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 @@ -43,48 +44,68 @@ #include "gfxPattern.h" #include "gfxPlatform.h" #include "prenv.h" static PRBool gDisableOptimize = PR_FALSE; +#ifdef XP_UNIX +static gfxFloat gImageThreshold = 0.5; +#include "nsIPrefBranch.h" +#include "nsIPrefService.h" +#endif #ifdef XP_WIN static PRUint32 gTotalDDBs = 0; static PRUint32 gTotalDDBSize = 0; // only use up a maximum of 64MB in DDBs #define kMaxDDBSize (64*1024*1024) // and don't let anything in that's bigger than 4MB #define kMaxSingleDDBSize (4*1024*1024) #endif NS_IMPL_ISUPPORTS1(nsThebesImage, nsIImage) nsThebesImage::nsThebesImage() : mFormat(gfxImageSurface::ImageFormatRGB24), mWidth(0), mHeight(0), mDecoded(0,0,0,0), - mImageComplete(PR_FALSE), + mImageIncomplete(PR_FALSE), mSinglePixel(PR_FALSE), mFormatChanged(PR_FALSE), mAlphaDepth(0) { - static PRBool hasCheckedOptimize = PR_FALSE; - if (!hasCheckedOptimize) { + static PRBool hasLoadedStatic = PR_FALSE; + if (!hasLoadedStatic) { if (PR_GetEnv("MOZ_DISABLE_IMAGE_OPTIMIZE")) { gDisableOptimize = PR_TRUE; } - hasCheckedOptimize = PR_TRUE; +#ifdef XP_UNIX + nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); + if (prefs) { + PRInt32 threshold; + nsresult rv = prefs->GetIntPref("browser.gdk_image_interpolation_threshold", &threshold); + if (NS_SUCCEEDED(rv)) { + // Store a value between 1 and 100 + threshold = (threshold > 0 || threshold <= 100) ? threshold: NS_lroundf(gImageThreshold*100); + gImageThreshold = gfxFloat(threshold) / 100; + } + } +#endif + hasLoadedStatic = 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; @@ -206,29 +227,28 @@ PRInt32 nsThebesImage::GetAlphaLineStride() { return (mAlphaDepth > 0) ? mStride : 0; } void nsThebesImage::ImageUpdated(nsIDeviceContext *aContext, PRUint8 aFlags, nsRect *aUpdateRect) { + mImageIncomplete = aFlags & nsImageUpdateFlags_ImageIncomplete; mDecoded.UnionRect(mDecoded, *aUpdateRect); #ifdef XP_MACOSX if (mQuartzSurface) mQuartzSurface->Flush(); #endif } PRBool nsThebesImage::GetIsImageComplete() { - if (!mImageComplete) - mImageComplete = (mDecoded == nsRect(0, 0, mWidth, mHeight)); - return mImageComplete; + return (mDecoded == nsRect(0, 0, mWidth, mHeight)) && !mImageIncomplete; } nsresult nsThebesImage::Optimize(nsIDeviceContext* aContext) { if (gDisableOptimize) return NS_OK; @@ -326,21 +346,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 } @@ -482,24 +507,108 @@ nsThebesImage::Draw(nsIRenderingContext return NS_ERROR_FAILURE; // Expand the subimageRect to place its edges on integer coordinates. // Basically, if we're allowed to sample part of a pixel we can // sample the whole pixel. subimageRect.RoundOut(); nsRefPtr pat; +#ifdef XP_UNIX + // We optimize the image surface to it's visible size and use scaling algorithms + // to reduce X memory consumption, bug 395260. We bypass 1x1 rectangles to avoid useless operations. + if (destRect.size != gfxSize(1.0, 1.0) && + (mWidth > (destRect.size.width / gImageThreshold) || + mHeight > (destRect.size.height / gImageThreshold) || + xscale < (1.0 * gImageThreshold) || yscale < (1.0 * gImageThreshold) || + xscale > (1.0 / gImageThreshold) || yscale > (1.0 / gImageThreshold))) { + + gfxIntSize tinySize(NS_lroundf(destRect.size.width), NS_lroundf(destRect.size.height)); + GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data(mImageSurface->Data(), GDK_COLORSPACE_RGB, + PR_TRUE, 8, mWidth, mHeight, + mStride, nsnull, nsnull); + if (!pixbuf) + return NS_ERROR_FAILURE; + + GdkPixbuf* tinyPix = pixbuf; + // XXX Cairo should have it's own scaling algorithm for image surfaces and use Sun's mediaLib + if (xscale != 1.0 || yscale != 1.0) { + // Scales the pixbuf, R and B channels are inverted but this should not cause any issue. + tinyPix = gdk_pixbuf_scale_simple(pixbuf, PRInt32(NS_ceilf(mWidth*xscale)), PRInt32(NS_ceilf(mHeight*yscale)), GDK_INTERP_BILINEAR); + if (!tinyPix) + return NS_ERROR_FAILURE; + g_object_unref(pixbuf); + } + + if (subimageRect.size.width >= srcRect.size.width || subimageRect.size.height >= srcRect.size.height) { + // We need to round the visible portion of the image for GDK + GdkPixbuf* tmpPix = gdk_pixbuf_new_subpixbuf(tinyPix, + PRInt32(NS_ceilf(srcRect.pos.x*xscale)), + PRInt32(NS_ceilf(srcRect.pos.y*yscale)), + srcRect.size.width*xscale > 0.0 ? PRInt32(NS_floorf(srcRect.size.width*xscale)) : 1, + srcRect.size.height*yscale > 0.0 ? PRInt32(NS_floorf(srcRect.size.height*yscale)): 1); + if (!tmpPix) + return NS_ERROR_FAILURE; + g_object_unref(tinyPix); + tinyPix = tmpPix; + } + + unsigned char* pixels = gdk_pixbuf_get_pixels(tinyPix); + PRInt32 stride = gdk_pixbuf_get_rowstride(tinyPix); + + // We generate a new tiny surface + nsRefPtr tinySurf = new gfxImageSurface(tinySize, mFormat); + + for (int i=0; i < tinySize.height; i++) { + unsigned char* src = pixels + stride*i; + memcpy(tinySurf->Data() + tinySurf->Stride()*i, src, tinySurf->Stride()); + } + + nsRefPtr tmpSurf = gfxPlatform::GetPlatform()->CreateOffscreenSurface(tinySize, mFormat); + if (!tmpSurf || tmpSurf->CairoStatus() != 0) + return NS_ERROR_FAILURE; + + gfxContext tmpCtx(tmpSurf); + tmpCtx.SetOperator(gfxContext::OPERATOR_SOURCE); + tmpCtx.SetSource(tinySurf); + tmpCtx.Paint(); + + // Use this tiny surface for further rendering + pat = new gfxPattern(tmpSurf); + // Release the gdk objects without affecting the actual image data + g_object_unref(tinyPix); + + // Disables further scaling operation to avoid bug 364968 explained below. + xscale = yscale = 1.0; + + // Origin could be different than (0,0) + 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 (!mOptSurface) { + // Sends pixmaps to X + if (GetIsImageComplete()) { + mOptSurface = gfxPlatform::GetPlatform()->OptimizeImage(mImageSurface, mFormat); + } else { + gfxPlatform::GetPlatform()->OptimizeImage(mImageSurface, mFormat); + } + } +#endif + PRBool ctxHasNonTranslation = ctx->CurrentMatrix().HasNonTranslation(); if ((xscale == 1.0 && yscale == 1.0 && !ctxHasNonTranslation) || subimageRect == gfxRect(0, 0, mWidth, mHeight)) { // No need to worry about sampling outside the subimage rectangle, // so no need for a temporary // XXX should we also check for situations where the source rect // is well inside the subimage so we can't sample outside? - pat = new gfxPattern(ThebesSurface()); + if (!pat) + pat = new gfxPattern(ThebesSurface()); } else { // Because of the RoundOut above, the subimageRect has // integer width and height. gfxIntSize size(PRInt32(subimageRect.Width()), PRInt32(subimageRect.Height())); nsRefPtr temp = gfxPlatform::GetPlatform()->CreateOffscreenSurface(size, mFormat); Index: ./gfx/src/thebes/nsThebesImage.h =================================================================== RCS file: /cvsroot/mozilla/gfx/src/thebes/nsThebesImage.h,v retrieving revision 1.33 diff -u -8 -p -B -b -r1.33 nsThebesImage.h --- ./gfx/src/thebes/nsThebesImage.h 31 Mar 2008 09:40:54 -0000 1.33 +++ ./gfx/src/thebes/nsThebesImage.h 22 Jul 2008 20:36:07 -0000 @@ -35,17 +35,21 @@ * 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 +#include "nsIServiceManager.h" +#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" @@ -155,17 +159,17 @@ protected: return PR_TRUE; } gfxImageSurface::gfxImageFormat mFormat; PRInt32 mWidth; PRInt32 mHeight; PRInt32 mStride; nsRect mDecoded; - PRPackedBool mImageComplete; + PRPackedBool mImageIncomplete; PRPackedBool mSinglePixel; PRPackedBool mFormatChanged; #ifdef XP_WIN PRPackedBool mIsDDBSurface; #endif gfxRGBA mSinglePixelColor; Index: ./modules/libpr0n/decoders/png/nsPNGDecoder.cpp =================================================================== RCS file: /cvsroot/mozilla/modules/libpr0n/decoders/png/nsPNGDecoder.cpp,v retrieving revision 1.81 diff -u -8 -p -B -b -r1.81 nsPNGDecoder.cpp --- ./modules/libpr0n/decoders/png/nsPNGDecoder.cpp 4 Apr 2008 01:01:17 -0000 1.81 +++ ./modules/libpr0n/decoders/png/nsPNGDecoder.cpp 22 Jul 2008 20:36:09 -0000 @@ -176,25 +176,25 @@ void nsPNGDecoder::EndImageFrame() // First tell the container that this frame is complete PRInt32 timeout = 100; PRUint32 numFrames = 0; mFrame->GetTimeout(&timeout); mImage->GetNumFrames(&numFrames); // We can't use mPNG->num_frames_read as it may be one ahead. - if (numFrames > 1) { // Tell the image renderer that the frame is complete PRInt32 width, height; mFrame->GetWidth(&width); mFrame->GetHeight(&height); nsIntRect r(0, 0, width, height); nsCOMPtr img(do_GetInterface(mFrame)); img->ImageUpdated(nsnull, nsImageUpdateFlags_kBitsChanged, &r); + if (numFrames > 1) { mObserver->OnDataAvailable(nsnull, mFrame, &r); } mImage->EndFrameDecode(numFrames, timeout); if (mObserver) mObserver->OnStopFrame(nsnull, mFrame); } @@ -791,17 +791,17 @@ row_callback(png_structp png_ptr, png_by decoder->mFrameHasNoAlpha = PR_FALSE; PRUint32 numFrames = 0; decoder->mImage->GetNumFrames(&numFrames); if (numFrames <= 1) { // Only do incremental image display for the first frame nsIntRect r(0, row_num, width, 1); nsCOMPtr img(do_GetInterface(decoder->mFrame)); - img->ImageUpdated(nsnull, nsImageUpdateFlags_kBitsChanged, &r); + img->ImageUpdated(nsnull, nsImageUpdateFlags_kBitsChanged | nsImageUpdateFlags_ImageIncomplete, &r); decoder->mObserver->OnDataAvailable(nsnull, decoder->mFrame, &r); } } } // got the header of a new frame that's coming void frame_info_callback(png_structp png_ptr, png_uint_32 frame_num) Index: ./modules/libpref/src/init/all.js =================================================================== RCS file: /cvsroot/mozilla/modules/libpref/src/init/all.js,v retrieving revision 3.758 diff -u -8 -p -B -b -r3.758 all.js --- ./modules/libpref/src/init/all.js 2 May 2008 06:27:27 -0000 3.758 +++ ./modules/libpref/src/init/all.js 22 Jul 2008 20:36:11 -0000 @@ -97,16 +97,19 @@ pref("browser.display.show_image_placeho // min font device pixel size at which to turn on high quality pref("browser.display.auto_quality_min_font_size", 20); pref("browser.anchor_color", "#0000EE"); pref("browser.active_color", "#EE0000"); pref("browser.visited_color", "#551A8B"); pref("browser.underline_anchors", true); pref("browser.blink_allowed", true); pref("browser.enable_automatic_image_resizing", false); +#ifdef XP_UNIX +pref("browser.gdk_image_interpolation_threshold", 50); +#endif // See http://whatwg.org/specs/web-apps/current-work/#ping pref("browser.send_pings", false); pref("browser.send_pings.max_per_link", 1); // limit the number of pings that are sent per link click pref("browser.send_pings.require_same_host", false); // only send pings to the same host if this is true pref("browser.display.use_focus_colors", false); pref("browser.display.focus_background_color", "#117722");