Index: gfx/public/nsIImage.h =================================================================== RCS file: /cvsroot/mozilla/gfx/public/nsIImage.h,v retrieving revision 1.38 diff -u -8 -p -r1.38 nsIImage.h --- gfx/public/nsIImage.h 9 Mar 2008 21:55:06 -0000 1.38 +++ gfx/public/nsIImage.h 31 Jul 2008 13:01:47 -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 @@ -182,19 +182,16 @@ NS_IMETHODIMP gfxImageFrame::GetMutable( NS_IMETHODIMP gfxImageFrame::SetMutable(PRBool aMutable) { if (!mInitialized) return NS_ERROR_NOT_INITIALIZED; mMutable = aMutable; - if (!aMutable && mImage) - mImage->Optimize(nsnull); - return NS_OK; } /* readonly attribute PRInt32 x; */ NS_IMETHODIMP gfxImageFrame::GetX(PRInt32 *aX) { if (!mInitialized) return NS_ERROR_NOT_INITIALIZED; Index: gfx/src/thebes/nsThebesImage.cpp =================================================================== RCS file: /cvsroot/mozilla/gfx/src/thebes/nsThebesImage.cpp,v retrieving revision 1.86 diff -u -8 -p -r1.86 nsThebesImage.cpp --- gfx/src/thebes/nsThebesImage.cpp 28 Apr 2008 21:27:05 -0000 1.86 +++ gfx/src/thebes/nsThebesImage.cpp 31 Jul 2008 13:01:48 -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 @@ -41,17 +42,21 @@ #include "gfxContext.h" #include "gfxPattern.h" #include "gfxPlatform.h" #include "prenv.h" +#include "nsIPrefBranch.h" +#include "nsIPrefService.h" + static PRBool gDisableOptimize = PR_FALSE; +static gfxFloat gPreScaleThreshold = 0.5; #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) @@ -59,29 +64,42 @@ static PRUint32 gTotalDDBSize = 0; NS_IMPL_ISUPPORTS1(nsThebesImage, nsIImage) nsThebesImage::nsThebesImage() : mFormat(gfxImageSurface::ImageFormatRGB24), mWidth(0), mHeight(0), mDecoded(0,0,0,0), - mImageComplete(PR_FALSE), + mImgDecodingIncomplete(PR_FALSE), + mPaintedFullImage(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; + nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); + if (prefs) { + PRInt32 threshold; + nsresult rv = prefs->GetIntPref("browser.image_manipulation_threshold", &threshold); + if (NS_SUCCEEDED(rv)) { + // Store a value between 1 and 100 + threshold = (threshold > 0 || threshold <= 100) ? threshold: NS_lroundf(gPreScaleThreshold*100); + gPreScaleThreshold = gfxFloat(threshold) / 100; + } + } + hasLoadedStatic = PR_TRUE; } + mOptSurface = nsnull; + #ifdef XP_WIN mIsDDBSurface = PR_FALSE; #endif } nsresult nsThebesImage::Init(PRInt32 aWidth, PRInt32 aHeight, PRInt32 aDepth, nsMaskRequirements aMaskRequirements) { @@ -206,29 +224,28 @@ PRInt32 nsThebesImage::GetAlphaLineStride() { return (mAlphaDepth > 0) ? mStride : 0; } void nsThebesImage::ImageUpdated(nsIDeviceContext *aContext, PRUint8 aFlags, nsRect *aUpdateRect) { + mImgDecodingIncomplete = 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)) && !mImgDecodingIncomplete; } nsresult nsThebesImage::Optimize(nsIDeviceContext* aContext) { if (gDisableOptimize) return NS_OK; @@ -426,16 +443,32 @@ nsThebesImage::Draw(nsIRenderingContext #if 0 fprintf (stderr, "nsThebesImage::Draw src [%f %f %f %f] dest [%f %f %f %f] trans: [%f %f] dec: [%f %f]\n", aSourceRect.pos.x, aSourceRect.pos.y, aSourceRect.size.width, aSourceRect.size.height, aDestRect.pos.x, aDestRect.pos.y, aDestRect.size.width, aDestRect.size.height, ctx->CurrentMatrix().GetTranslation().x, ctx->CurrentMatrix().GetTranslation().y, mDecoded.x, mDecoded.y, mDecoded.width, mDecoded.height); #endif + gfxFloat xscale = aDestRect.size.width / aSourceRect.size.width; + gfxFloat yscale = aDestRect.size.height / aSourceRect.size.height; + gfxSize xyScale(xscale, yscale); + + PRBool isImgOverflowing = !mPaintedFullImage && + (mWidth > (aDestRect.size.width / gPreScaleThreshold) || + mHeight > (aDestRect.size.height / gPreScaleThreshold)); + PRBool isImgOverScaled = xscale < gPreScaleThreshold || yscale < gPreScaleThreshold || + xscale > (1.0 / gPreScaleThreshold) || yscale > (1.0 / gPreScaleThreshold); + if (!mPaintedFullImage && !isImgOverflowing && !isImgOverScaled) { + if (GetIsImageComplete()) { + Optimize(nsnull); + mPaintedFullImage = PR_TRUE; + } + } + if (mSinglePixel) { // if a == 0, it's a noop if (mSinglePixelColor.a == 0.0) return NS_OK; // otherwise gfxContext::GraphicsOperator op = ctx->CurrentOperator(); if (op == gfxContext::OPERATOR_OVER && mSinglePixelColor.a == 1.0) @@ -444,19 +477,16 @@ nsThebesImage::Draw(nsIRenderingContext ctx->SetDeviceColor(mSinglePixelColor); ctx->NewPath(); ctx->Rectangle(aDestRect, PR_TRUE); ctx->Fill(); ctx->SetOperator(op); return NS_OK; } - 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); if (!GetIsImageComplete()) { gfxRect decoded = gfxRect(mDecoded.x, mDecoded.y, mDecoded.width, mDecoded.height); srcRect = srcRect.Intersect(decoded); @@ -513,38 +543,41 @@ nsThebesImage::Draw(nsIRenderingContext pat = new gfxPattern(temp); srcRect.MoveBy(-subimageRect.pos); } /* See bug 364968 to understand the necessity of this goop; we basically * have to pre-downscale any image that would fall outside of a scaled 16-bit * coordinate space. + * Also bug 395260, we reduce the image surface to it's visible size and use + * cairo scaling algorithms to decrease memory consumption in the graphics engine. */ if (aDestRect.pos.x * (1.0 / xscale) >= 32768.0 || - aDestRect.pos.y * (1.0 / yscale) >= 32768.0) + aDestRect.pos.y * (1.0 / yscale) >= 32768.0 || + isImgOverflowing || isImgOverScaled) { gfxIntSize dim(NS_lroundf(destRect.size.width), NS_lroundf(destRect.size.height)); // nothing to do in this case if (dim.width == 0 || dim.height == 0) return NS_OK; - nsRefPtr temp = - gfxPlatform::GetPlatform()->CreateOffscreenSurface (dim, mFormat); + nsRefPtr temp = new gfxImageSurface(dim, mFormat); if (!temp || temp->CairoStatus() != 0) return NS_ERROR_FAILURE; gfxContext tempctx(temp); gfxMatrix mat; mat.Translate(srcRect.pos); mat.Scale(1.0 / xscale, 1.0 / yscale); pat->SetMatrix(mat); + pat->SetExtend(gfxPattern::EXTEND_PAD); tempctx.SetPattern(pat); tempctx.SetOperator(gfxContext::OPERATOR_SOURCE); tempctx.NewPath(); tempctx.Rectangle(gfxRect(0.0, 0.0, dim.width, dim.height)); tempctx.Fill(); pat = new gfxPattern(temp); Index: gfx/src/thebes/nsThebesImage.h =================================================================== RCS file: /cvsroot/mozilla/gfx/src/thebes/nsThebesImage.h,v retrieving revision 1.33 diff -u -8 -p -r1.33 nsThebesImage.h --- gfx/src/thebes/nsThebesImage.h 31 Mar 2008 09:40:54 -0000 1.33 +++ gfx/src/thebes/nsThebesImage.h 31 Jul 2008 13:01:48 -0000 @@ -35,17 +35,17 @@ * 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" - +#include "nsIServiceManager.h" #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 +155,18 @@ protected: return PR_TRUE; } gfxImageSurface::gfxImageFormat mFormat; PRInt32 mWidth; PRInt32 mHeight; PRInt32 mStride; nsRect mDecoded; - PRPackedBool mImageComplete; + PRPackedBool mImgDecodingIncomplete; + PRPackedBool mPaintedFullImage; 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 -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 31 Jul 2008 13:01:50 -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); + // 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); + 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 -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 31 Jul 2008 13:01:51 -0000 @@ -97,16 +97,17 @@ 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); +pref("browser.image_manipulation_threshold", 50); // between 1 and 100 to define images to manipulate with cairo // 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");