mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-11 04:15:43 +00:00
Bug 455364. Add Thebes API to extract a subimage of an image into a new image. r=vlad
This commit is contained in:
parent
ccff0d2450
commit
a66146acfe
@ -74,10 +74,10 @@ typedef enum {
|
||||
#define nsImageUpdateFlags_kBitsChanged 0x2
|
||||
|
||||
// IID for the nsIImage interface
|
||||
// 455fc276-01de-488f-9f8f-19b85a6b112d
|
||||
// c942f66c-97d0-470e-99de-a1efb4586afd
|
||||
#define NS_IIMAGE_IID \
|
||||
{ 0x455fc276, 0x01de, 0x488f, \
|
||||
{ 0x9f, 0x8f, 0x19, 0xb8, 0x5a, 0x6b, 0x11, 0x2d } }
|
||||
{ 0xc942f66c, 0x97d0, 0x470e, \
|
||||
{ 0x99, 0xde, 0xa1, 0xef, 0xb4, 0x58, 0x6a, 0xfd } }
|
||||
|
||||
// Interface to Images
|
||||
class nsIImage : public nsISupports
|
||||
@ -289,6 +289,15 @@ public:
|
||||
* the original format requested a 1-bit or 8-bit alpha mask
|
||||
*/
|
||||
virtual void SetHasNoAlpha() = 0;
|
||||
|
||||
/**
|
||||
* Extract a rectangular region of the nsIImage and return it as a new
|
||||
* nsIImage.
|
||||
* @param aSubimage the region to extract
|
||||
* @param aResult the extracted image
|
||||
*/
|
||||
NS_IMETHOD Extract(const nsIntRect& aSubimage,
|
||||
nsIImage** aResult NS_OUTPARAM) = 0;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIImage, NS_IIMAGE_IID)
|
||||
|
@ -67,6 +67,8 @@ nsThebesImage::nsThebesImage()
|
||||
mImageComplete(PR_FALSE),
|
||||
mSinglePixel(PR_FALSE),
|
||||
mFormatChanged(PR_FALSE),
|
||||
mNeverUseDeviceSurface(PR_FALSE),
|
||||
mSinglePixelColor(0),
|
||||
mAlphaDepth(0)
|
||||
{
|
||||
static PRBool hasCheckedOptimize = PR_FALSE;
|
||||
@ -122,19 +124,25 @@ nsThebesImage::Init(PRInt32 aWidth, PRInt32 aHeight, PRInt32 aDepth, nsMaskRequi
|
||||
|
||||
mFormat = format;
|
||||
|
||||
// For Windows, we must create the device surface first (if we're
|
||||
// going to) so that the image surface can wrap it. Can't be done
|
||||
// the other way around.
|
||||
#ifdef XP_WIN
|
||||
if (!ShouldUseImageSurfaces()) {
|
||||
if (!mNeverUseDeviceSurface && !ShouldUseImageSurfaces()) {
|
||||
mWinSurface = new gfxWindowsSurface(gfxIntSize(mWidth, mHeight), format);
|
||||
if (mWinSurface && mWinSurface->CairoStatus() == 0) {
|
||||
// no error
|
||||
mImageSurface = mWinSurface->GetImageSurface();
|
||||
} else {
|
||||
mWinSurface = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mImageSurface)
|
||||
mWinSurface = nsnull;
|
||||
#endif
|
||||
|
||||
// For other platforms we create the image surface first and then
|
||||
// possibly wrap it in a device surface. This branch is also used
|
||||
// on Windows if we're not using device surfaces or if we couldn't
|
||||
// create one.
|
||||
if (!mImageSurface)
|
||||
mImageSurface = new gfxImageSurface(gfxIntSize(mWidth, mHeight), format);
|
||||
|
||||
@ -145,7 +153,9 @@ nsThebesImage::Init(PRInt32 aWidth, PRInt32 aHeight, PRInt32 aDepth, nsMaskRequi
|
||||
}
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
mQuartzSurface = new gfxQuartzImageSurface(mImageSurface);
|
||||
if (!mNeverUseDeviceSurface && !ShouldUseImageSurfaces()) {
|
||||
mQuartzSurface = new gfxQuartzImageSurface(mImageSurface);
|
||||
}
|
||||
#endif
|
||||
|
||||
mStride = mImageSurface->Stride();
|
||||
@ -301,7 +311,7 @@ nsThebesImage::Optimize(nsIDeviceContext* aContext)
|
||||
|
||||
// if we're being forced to use image surfaces due to
|
||||
// resource constraints, don't try to optimize beyond same-pixel.
|
||||
if (ShouldUseImageSurfaces())
|
||||
if (mNeverUseDeviceSurface || ShouldUseImageSurfaces())
|
||||
return NS_OK;
|
||||
|
||||
mOptSurface = nsnull;
|
||||
@ -690,6 +700,66 @@ nsThebesImage::Draw(gfxContext* aContext,
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsThebesImage::Extract(const nsIntRect& aRegion,
|
||||
nsIImage** aResult)
|
||||
{
|
||||
nsRefPtr<nsThebesImage> subImage(new nsThebesImage());
|
||||
if (!subImage)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// The scaling problems described in bug 468496 are especially
|
||||
// likely to be visible for the sub-image, as at present the only
|
||||
// user is the border-image code and border-images tend to get
|
||||
// stretched a lot. At the same time, the performance concerns
|
||||
// that prevent us from just using Cairo's fallback scaler when
|
||||
// accelerated graphics won't cut it are less relevant to such
|
||||
// images, since they also tend to be small. Thus, we forcibly
|
||||
// disable the use of anything other than a client-side image
|
||||
// surface for the sub-image; this ensures that the correct
|
||||
// (albeit slower) Cairo fallback scaler will be used.
|
||||
subImage->mNeverUseDeviceSurface = PR_TRUE;
|
||||
|
||||
// ->Init() is just going to convert this back, bleah.
|
||||
nsMaskRequirements maskReq;
|
||||
switch (mAlphaDepth) {
|
||||
case 0: maskReq = nsMaskRequirements_kNoMask; break;
|
||||
case 1: maskReq = nsMaskRequirements_kNeeds1Bit; break;
|
||||
case 8: maskReq = nsMaskRequirements_kNeeds8Bit; break;
|
||||
default:
|
||||
NS_NOTREACHED("impossible alpha depth");
|
||||
maskReq = nsMaskRequirements_kNeeds8Bit; // safe
|
||||
}
|
||||
|
||||
nsresult rv = subImage->Init(aRegion.width, aRegion.height,
|
||||
8 /* ignored */, maskReq);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
{ // scope to destroy ctx
|
||||
gfxContext ctx(subImage->ThebesSurface());
|
||||
ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
|
||||
if (mSinglePixel) {
|
||||
ctx.SetDeviceColor(mSinglePixelColor);
|
||||
} else {
|
||||
// SetSource() places point (0,0) of its first argument at
|
||||
// the coordinages given by its second argument. We want
|
||||
// (x,y) of the image to be (0,0) of source space, so we
|
||||
// put (0,0) of the image at (-x,-y).
|
||||
ctx.SetSource(this->ThebesSurface(),
|
||||
gfxPoint(-aRegion.x, -aRegion.y));
|
||||
}
|
||||
ctx.Rectangle(gfxRect(0, 0, aRegion.width, aRegion.height));
|
||||
ctx.Fill();
|
||||
}
|
||||
|
||||
nsIntRect filled(0, 0, aRegion.width, aRegion.height);
|
||||
subImage->ImageUpdated(nsnull, nsImageUpdateFlags_kBitsChanged, &filled);
|
||||
subImage->Optimize(nsnull);
|
||||
|
||||
NS_ADDREF(*aResult = subImage);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsThebesImage::ShouldUseImageSurfaces()
|
||||
{
|
||||
|
@ -116,6 +116,9 @@ public:
|
||||
|
||||
void SetHasNoAlpha();
|
||||
|
||||
NS_IMETHOD Extract(const nsIntRect& aSubimage,
|
||||
nsIImage** aResult NS_OUTPARAM);
|
||||
|
||||
protected:
|
||||
static PRBool AllowedImageSize(PRInt32 aWidth, PRInt32 aHeight) {
|
||||
NS_ASSERTION(aWidth > 0, "invalid image width");
|
||||
@ -156,6 +159,7 @@ protected:
|
||||
PRPackedBool mImageComplete;
|
||||
PRPackedBool mSinglePixel;
|
||||
PRPackedBool mFormatChanged;
|
||||
PRPackedBool mNeverUseDeviceSurface;
|
||||
#ifdef XP_WIN
|
||||
PRPackedBool mIsDDBSurface;
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user