b=415854, make single-pixel optimized images release memory; patch from joe@drew.ca; r+sr=vlad

This commit is contained in:
vladimir@pobox.com 2008-03-05 22:51:13 -08:00
parent b08890d80f
commit 104f6a38a1
16 changed files with 208 additions and 75 deletions

View File

@ -2220,9 +2220,18 @@ nsCanvasRenderingContext2D::CairoSurfaceFromElement(nsIDOMElement *imgElt,
if (heightOut)
*heightOut = imgHeight;
nsRefPtr<gfxASurface> gfxsurf;
rv = img->GetSurface(getter_AddRefs(gfxsurf));
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<gfxPattern> gfxpattern;
img->GetPattern(getter_AddRefs(gfxpattern));
nsRefPtr<gfxASurface> gfxsurf = gfxpattern->GetSurface();
if (!gfxsurf) {
gfxsurf = new gfxImageSurface (gfxIntSize(imgWidth, imgHeight), gfxASurface::ImageFormatARGB32);
nsRefPtr<gfxContext> ctx = new gfxContext(gfxsurf);
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
ctx->SetPattern(gfxpattern);
ctx->Paint();
}
*aCairoSurface = gfxsurf->CairoSurface();
cairo_surface_reference (*aCairoSurface);

View File

@ -174,7 +174,6 @@ INCLUDES += \
-I$(srcdir)/../../../events/src \
-I$(srcdir)/../../../html/content/src \
-I$(topsrcdir)/content/xbl/src \
-I$(topsrcdir)/gfx/src/thebes \
$(NULL)
DEFINES += -D_IMPL_NS_LAYOUT

View File

@ -63,7 +63,7 @@
#include "nsImageLoadingContent.h"
#include "imgIContainer.h"
#include "gfxIImageFrame.h"
#include "nsThebesImage.h"
#include "nsIImage.h"
#include "nsSVGAnimatedPreserveAspectRatio.h"
#include "nsSVGPreserveAspectRatio.h"
#include "nsIInterfaceRequestorUtils.h"
@ -5582,19 +5582,14 @@ nsSVGFEImageElement::Filter(nsSVGFilterInstance *instance)
if (imageContainer)
imageContainer->GetCurrentFrame(getter_AddRefs(currentFrame));
gfxASurface *thebesSurface = nsnull;
nsRefPtr<gfxPattern> thebesPattern = nsnull;
if (currentFrame) {
nsCOMPtr<nsIImage> img(do_GetInterface(currentFrame));
nsThebesImage *thebesImage = nsnull;
if (img)
thebesImage = static_cast<nsThebesImage*>(img.get());
if (thebesImage)
thebesSurface = thebesImage->ThebesSurface();
img->GetPattern(getter_AddRefs(thebesPattern));
}
if (thebesSurface) {
if (thebesPattern) {
PRInt32 x, y, nativeWidth, nativeHeight;
currentFrame->GetX(&x);
currentFrame->GetY(&y);
@ -5611,7 +5606,7 @@ nsSVGFEImageElement::Filter(nsSVGFilterInstance *instance)
xy->Multiply(trans, getter_AddRefs(fini));
gfxContext ctx(targetSurface);
nsSVGUtils::CompositeSurfaceMatrix(&ctx, thebesSurface, fini, 1.0);
nsSVGUtils::CompositePatternMatrix(&ctx, thebesPattern, fini, nativeWidth, nativeHeight, 1.0);
}
return NS_OK;

View File

@ -44,6 +44,7 @@
#include "gfxRect.h"
class gfxASurface;
class gfxPattern;
class nsIDeviceContext;
@ -213,7 +214,11 @@ public:
/**
* LockImagePixels
* Lock the image pixels so that we can access them directly,
* with safely. May be a noop on some platforms.
* with safety. May be a noop on some platforms.
*
* If you want to be able to call GetSurface(), wrap the call in
* LockImagePixels()/UnlockImagePixels(). This also allows you to write to
* the surface returned by GetSurface().
*
* aMaskPixels = PR_TRUE for the mask, PR_FALSE for the image
*
@ -239,13 +244,24 @@ public:
/**
* GetSurface
* Return the Thebes gfxASurface in aSurface.
* Return the Thebes gfxASurface in aSurface, if there is one. Should be
* wrapped by LockImagePixels()/UnlockImagePixels().
*
* aSurface will be AddRef'd (as with most getters), so
* getter_AddRefs should be used.
*/
NS_IMETHOD GetSurface(gfxASurface **aSurface) = 0;
/**
* GetSurface
* Return the Thebes gfxPattern in aPattern. It is always possible to get a
* gfxPattern (unlike the gfxASurface from GetSurface()).
*
* aPattern will be AddRef'd (as with most getters), so
* getter_AddRefs should be used.
*/
NS_IMETHOD GetPattern(gfxPattern **aPattern) = 0;
/**
* SetHasNoAlpha
*

View File

@ -259,13 +259,6 @@ nsThebesImage::Optimize(nsIDeviceContext* aContext)
mSinglePixel = PR_TRUE;
// XXX we can't do this until we either teach anyone
// who calls GetSurface() about single-color stuff,
// or until we make GetSurface() create a new temporary
// surface to return (and that callers understand that
// modifying that surface won't modify the image).
// Current users are drag & drop and clipboard.
#if 0
// blow away the older surfaces, to release data
mImageSurface = nsnull;
@ -275,7 +268,6 @@ nsThebesImage::Optimize(nsIDeviceContext* aContext)
#endif
#ifdef XP_MACOSX
mQuartzSurface = nsnull;
#endif
#endif
return NS_OK;
}
@ -391,7 +383,15 @@ nsThebesImage::LockImagePixels(PRBool aMaskPixels)
else
context.SetSource(mOptSurface);
context.Paint();
#ifdef XP_WIN
mWinSurface = nsnull;
#endif
#ifdef XP_MACOSX
mQuartzSurface = nsnull;
#endif
}
return NS_OK;
}

View File

@ -44,6 +44,7 @@
#include "gfxColor.h"
#include "gfxASurface.h"
#include "gfxImageSurface.h"
#include "gfxPattern.h"
#if defined(XP_WIN)
#include "gfxWindowsSurface.h"
#elif defined(XP_MACOSX)
@ -96,6 +97,22 @@ public:
return NS_OK;
}
NS_IMETHOD GetPattern(gfxPattern **aPattern) {
*aPattern = ThebesPattern();
NS_ADDREF(*aPattern);
return NS_OK;
}
gfxPattern* ThebesPattern() {
gfxPattern *pattern;
if (mSinglePixel)
pattern = new gfxPattern(mSinglePixelColor);
else
pattern = new gfxPattern(ThebesSurface());
return pattern;
}
gfxASurface* ThebesSurface() {
if (mOptSurface)
return mOptSurface;

View File

@ -78,6 +78,17 @@ public:
void SetExtend(GraphicsExtend extend);
GraphicsExtend Extend() const;
enum GraphicsPatternType {
PATTERN_SOLID,
PATTERN_SURFACE,
PATTERN_LINEAR,
PATTERN_RADIAL
};
GraphicsPatternType GetType() const;
int CairoStatus();
void SetFilter(int filter);
int Filter() const;

View File

@ -168,6 +168,17 @@ gfxPattern::GetSurface()
if (cairo_pattern_get_surface (mPattern, &surf) != CAIRO_STATUS_SUCCESS)
return nsnull;
return gfxASurface::Wrap(surf);
}
gfxPattern::GraphicsPatternType
gfxPattern::GetType() const
{
return (GraphicsPatternType) cairo_pattern_get_type(mPattern);
}
int
gfxPattern::CairoStatus()
{
return cairo_pattern_status(mPattern);
}

View File

@ -117,7 +117,6 @@ LOCAL_INCLUDES = \
-I$(srcdir)/../../../xul/base/src \
-I$(srcdir)/../../../../content/svg/content/src \
-I$(srcdir)/../../../../content/base/src \
-I$(topsrcdir)/gfx/src/thebes \
$(NULL)
libs::

View File

@ -47,7 +47,7 @@
#include "nsSVGMatrix.h"
#include "gfxContext.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsThebesImage.h"
#include "nsIImage.h"
class nsSVGImageFrame;
@ -257,19 +257,14 @@ nsSVGImageFrame::PaintSVG(nsSVGRenderState *aContext, nsRect *aDirtyRect)
if (mImageContainer)
mImageContainer->GetCurrentFrame(getter_AddRefs(currentFrame));
gfxASurface *thebesSurface = nsnull;
nsRefPtr<gfxPattern> thebesPattern = nsnull;
if (currentFrame) {
nsCOMPtr<nsIImage> img(do_GetInterface(currentFrame));
nsThebesImage *thebesImage = nsnull;
if (img)
thebesImage = static_cast<nsThebesImage*>(img.get());
if (thebesImage)
thebesSurface = thebesImage->ThebesSurface();
img->GetPattern(getter_AddRefs(thebesPattern));
}
if (thebesSurface) {
if (thebesPattern) {
gfxContext *gfx = aContext->GetGfxContext();
if (GetStyleDisplay()->IsScrollableOverflow()) {
@ -293,7 +288,7 @@ nsSVGImageFrame::PaintSVG(nsSVGRenderState *aContext, nsRect *aDirtyRect)
opacity = GetStyleDisplay()->mOpacity;
}
nsSVGUtils::CompositeSurfaceMatrix(gfx, thebesSurface, fini, opacity);
nsSVGUtils::CompositePatternMatrix(gfx, thebesPattern, fini, width, height, opacity);
if (GetStyleDisplay()->IsScrollableOverflow())
gfx->Restore();

View File

@ -1599,6 +1599,27 @@ nsSVGUtils::CompositeSurfaceMatrix(gfxContext *aContext,
aContext->Restore();
}
void
nsSVGUtils::CompositePatternMatrix(gfxContext *aContext,
gfxPattern *aPattern,
nsIDOMSVGMatrix *aCTM, float aWidth, float aHeight, float aOpacity)
{
gfxMatrix matrix = ConvertSVGMatrixToThebes(aCTM);
if (matrix.IsSingular())
return;
aContext->Save();
SetClipRect(aContext, aCTM, 0, 0, aWidth, aHeight);
aContext->Multiply(matrix);
aContext->SetPattern(aPattern);
aContext->Paint(aOpacity);
aContext->Restore();
}
void
nsSVGUtils::SetClipRect(gfxContext *aContext,
nsIDOMSVGMatrix *aCTM, float aX, float aY,

View File

@ -69,6 +69,7 @@ class nsSVGSVGElement;
class nsAttrValue;
class gfxContext;
class gfxASurface;
class gfxPattern;
class nsIRenderingContext;
class gfxImageSurface;
struct gfxRect;
@ -410,6 +411,10 @@ public:
gfxASurface *aSurface,
nsIDOMSVGMatrix *aCTM, float aOpacity);
static void CompositePatternMatrix(gfxContext *aContext,
gfxPattern *aPattern,
nsIDOMSVGMatrix *aCTM, float aWidth, float aHeight, float aOpacity);
static void SetClipRect(gfxContext *aContext,
nsIDOMSVGMatrix *aCTM, float aX, float aY,
float aWidth, float aHeight);

View File

@ -1039,12 +1039,15 @@ void imgContainer::ClearFrame(gfxIImageFrame *aFrame)
nsCOMPtr<nsIImage> img(do_GetInterface(aFrame));
nsRefPtr<gfxASurface> surf;
img->LockImagePixels(0);
img->GetSurface(getter_AddRefs(surf));
// Erase the surface to transparent
gfxContext ctx(surf);
ctx.SetOperator(gfxContext::OPERATOR_CLEAR);
ctx.Paint();
img->UnlockImagePixels(0);
}
//******************************************************************************
@ -1056,6 +1059,8 @@ void imgContainer::ClearFrame(gfxIImageFrame *aFrame, nsIntRect &aRect)
nsCOMPtr<nsIImage> img(do_GetInterface(aFrame));
nsRefPtr<gfxASurface> surf;
img->LockImagePixels(0);
img->GetSurface(getter_AddRefs(surf));
// Erase the destination rectangle to transparent
@ -1063,6 +1068,7 @@ void imgContainer::ClearFrame(gfxIImageFrame *aFrame, nsIntRect &aRect)
ctx.SetOperator(gfxContext::OPERATOR_CLEAR);
ctx.Rectangle(gfxRect(aRect.x, aRect.y, aRect.width, aRect.height));
ctx.Fill();
img->UnlockImagePixels(0);
}
@ -1184,11 +1190,13 @@ nsresult imgContainer::DrawFrameTo(gfxIImageFrame *aSrc,
}
nsCOMPtr<nsIImage> srcImg(do_GetInterface(aSrc));
nsRefPtr<gfxASurface> srcSurf;
srcImg->GetSurface(getter_AddRefs(srcSurf));
nsRefPtr<gfxPattern> srcPatt;
srcImg->GetPattern(getter_AddRefs(srcPatt));
nsCOMPtr<nsIImage> dstImg(do_GetInterface(aDst));
nsRefPtr<gfxASurface> dstSurf;
// Note: dstImage has LockImageData() called on it above, so it's safe to get
// the surface.
dstImg->GetSurface(getter_AddRefs(dstSurf));
gfxContext dst(dstSurf);
@ -1204,7 +1212,7 @@ nsresult imgContainer::DrawFrameTo(gfxIImageFrame *aSrc,
dst.Fill();
dst.SetOperator(defaultOperator);
}
dst.SetSource(srcSurf);
dst.SetPattern(srcPatt);
dst.Paint();
return NS_OK;

View File

@ -319,9 +319,8 @@ NS_IMETHODIMP imgTools::EncodeScaledImage(imgIContainer *aContainer,
// Prepare to draw a scaled version of the image to a temporary surface...
// Get the source image surface
nsRefPtr<gfxASurface> gfxsurf;
rv = img->GetSurface(getter_AddRefs(gfxsurf));
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<gfxPattern> gfxpat;
img->GetPattern(getter_AddRefs(gfxpat));
// Create a temporary image surface
dest = new gfxImageSurface(gfxIntSize(aScaledWidth, aScaledHeight),
@ -338,7 +337,7 @@ NS_IMETHODIMP imgTools::EncodeScaledImage(imgIContainer *aContainer,
// Paint a scaled image
ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
ctx.SetSource(gfxsurf);
ctx.SetPattern(gfxpat);
ctx.Paint();
bitmapData = dest->Data();

View File

@ -71,40 +71,15 @@ nsImageToPixbuf::ImageToPixbuf(nsIImage* aImage)
PRInt32 width = aImage->GetWidth(),
height = aImage->GetHeight();
nsRefPtr<gfxASurface> surface;
aImage->GetSurface(getter_AddRefs(surface));
nsRefPtr<gfxPattern> pattern;
aImage->GetPattern(getter_AddRefs(pattern));
return SurfaceToPixbuf(surface, width, height);
return PatternToPixbuf(pattern, width, height);
}
GdkPixbuf*
nsImageToPixbuf::SurfaceToPixbuf(gfxASurface* aSurface, PRInt32 aWidth, PRInt32 aHeight)
nsImageToPixbuf::ImgSurfaceToPixbuf(gfxImageSurface* aImgSurface, PRInt32 aWidth, PRInt32 aHeight)
{
if (aSurface->CairoStatus()) {
NS_ERROR("invalid surface");
return nsnull;
}
nsRefPtr<gfxImageSurface> imgSurface;
if (aSurface->GetType() == gfxASurface::SurfaceTypeImage) {
imgSurface = static_cast<gfxImageSurface*>
(static_cast<gfxASurface*>(aSurface));
} else {
imgSurface = new gfxImageSurface(gfxIntSize(aWidth, aHeight),
gfxImageSurface::ImageFormatARGB32);
if (!imgSurface)
return nsnull;
nsRefPtr<gfxContext> context = new gfxContext(imgSurface);
if (!context)
return nsnull;
context->SetOperator(gfxContext::OPERATOR_SOURCE);
context->SetSource(aSurface);
context->Paint();
}
GdkPixbuf* pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, PR_TRUE, 8,
aWidth, aHeight);
if (!pixbuf)
@ -113,10 +88,10 @@ nsImageToPixbuf::SurfaceToPixbuf(gfxASurface* aSurface, PRInt32 aWidth, PRInt32
PRUint32 rowstride = gdk_pixbuf_get_rowstride (pixbuf);
guchar* pixels = gdk_pixbuf_get_pixels (pixbuf);
long cairoStride = imgSurface->Stride();
unsigned char* cairoData = imgSurface->Data();
long cairoStride = aImgSurface->Stride();
unsigned char* cairoData = aImgSurface->Data();
gfxASurface::gfxImageFormat format = imgSurface->Format();
gfxASurface::gfxImageFormat format = aImgSurface->Format();
for (PRInt32 row = 0; row < aHeight; ++row) {
for (PRInt32 col = 0; col < aWidth; ++col) {
@ -152,3 +127,70 @@ nsImageToPixbuf::SurfaceToPixbuf(gfxASurface* aSurface, PRInt32 aWidth, PRInt32
return pixbuf;
}
GdkPixbuf*
nsImageToPixbuf::SurfaceToPixbuf(gfxASurface* aSurface, PRInt32 aWidth, PRInt32 aHeight)
{
if (aSurface->CairoStatus()) {
NS_ERROR("invalid surface");
return nsnull;
}
nsRefPtr<gfxImageSurface> imgSurface;
if (aSurface->GetType() == gfxASurface::SurfaceTypeImage) {
imgSurface = static_cast<gfxImageSurface*>
(static_cast<gfxASurface*>(aSurface));
} else {
imgSurface = new gfxImageSurface(gfxIntSize(aWidth, aHeight),
gfxImageSurface::ImageFormatARGB32);
if (!imgSurface)
return nsnull;
nsRefPtr<gfxContext> context = new gfxContext(imgSurface);
if (!context)
return nsnull;
context->SetOperator(gfxContext::OPERATOR_SOURCE);
context->SetSource(aSurface);
context->Paint();
}
return ImgSurfaceToPixbuf(imgSurface, aWidth, aHeight);
}
GdkPixbuf*
nsImageToPixbuf::PatternToPixbuf(gfxPattern* aPattern, PRInt32 aWidth, PRInt32 aHeight)
{
if (aPattern->CairoStatus()) {
NS_ERROR("invalid pattern");
return nsnull;
}
nsRefPtr<gfxImageSurface> imgSurface;
if (aPattern->GetType() == gfxPattern::PATTERN_SURFACE) {
nsRefPtr<gfxASurface> surface = aPattern->GetSurface();
if (surface->GetType() == gfxASurface::SurfaceTypeImage) {
imgSurface = static_cast<gfxImageSurface*>
(static_cast<gfxASurface*>(surface.get()));
}
}
if (!imgSurface) {
imgSurface = new gfxImageSurface(gfxIntSize(aWidth, aHeight),
gfxImageSurface::ImageFormatARGB32);
if (!imgSurface)
return nsnull;
nsRefPtr<gfxContext> context = new gfxContext(imgSurface);
if (!context)
return nsnull;
context->SetOperator(gfxContext::OPERATOR_SOURCE);
context->SetPattern(aPattern);
context->Paint();
}
return ImgSurfaceToPixbuf(imgSurface, aWidth, aHeight);
}

View File

@ -41,6 +41,8 @@
#include "nsIImageToPixbuf.h"
class gfxASurface;
class gfxPattern;
class gfxImageSurface;
class nsImageToPixbuf : public nsIImageToPixbuf {
public:
@ -52,7 +54,11 @@ class nsImageToPixbuf : public nsIImageToPixbuf {
static GdkPixbuf* ImageToPixbuf(nsIImage* aImage);
static GdkPixbuf* SurfaceToPixbuf(gfxASurface* aSurface,
PRInt32 aWidth, PRInt32 aHeight);
static GdkPixbuf* PatternToPixbuf(gfxPattern* aPattern,
PRInt32 aWidth, PRInt32 aHeight);
private:
static GdkPixbuf* ImgSurfaceToPixbuf(gfxImageSurface* aImgSurface,
PRInt32 aWidth, PRInt32 aHeight);
~nsImageToPixbuf() {}
};