mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 19:35:51 +00:00
Bug 859377 (Part 3) - Make ClippedImage cache temporary surfaces. r=joe
--HG-- extra : rebase_source : 060615904e1b416f84b4d6ecf6329841896f13da
This commit is contained in:
parent
fa19988b4c
commit
38bbbc4266
@ -6,6 +6,7 @@
|
||||
#include "gfxDrawable.h"
|
||||
#include "gfxPlatform.h"
|
||||
#include "gfxUtils.h"
|
||||
#include "mozilla/dom/SVGSVGElement.h"
|
||||
|
||||
#include "ClippedImage.h"
|
||||
|
||||
@ -15,6 +16,48 @@ using mozilla::layers::ImageContainer;
|
||||
namespace mozilla {
|
||||
namespace image {
|
||||
|
||||
class ClippedImageCachedSurface
|
||||
{
|
||||
public:
|
||||
ClippedImageCachedSurface(gfxASurface* aSurface,
|
||||
const nsIntSize& aViewportSize,
|
||||
const SVGImageContext* aSVGContext,
|
||||
float aFrame,
|
||||
uint32_t aFlags)
|
||||
: mSurface(aSurface)
|
||||
, mViewportSize(aViewportSize)
|
||||
, mFrame(aFrame)
|
||||
, mFlags(aFlags)
|
||||
{
|
||||
MOZ_ASSERT(mSurface, "Must have a valid surface");
|
||||
if (aSVGContext) {
|
||||
mSVGContext.construct(*aSVGContext);
|
||||
}
|
||||
}
|
||||
|
||||
bool Matches(const nsIntSize& aViewportSize,
|
||||
const SVGImageContext* aSVGContext,
|
||||
float aFrame,
|
||||
uint32_t aFlags)
|
||||
{
|
||||
bool matchesSVGContext = (!aSVGContext && mSVGContext.empty()) ||
|
||||
*aSVGContext == mSVGContext.ref();
|
||||
return mViewportSize == aViewportSize &&
|
||||
matchesSVGContext &&
|
||||
mFrame == aFrame &&
|
||||
mFlags == aFlags;
|
||||
}
|
||||
|
||||
gfxASurface* Surface() { return mSurface; }
|
||||
|
||||
private:
|
||||
nsRefPtr<gfxASurface> mSurface;
|
||||
const nsIntSize mViewportSize;
|
||||
Maybe<SVGImageContext> mSVGContext;
|
||||
const float mFrame;
|
||||
const uint32_t mFlags;
|
||||
};
|
||||
|
||||
class DrawSingleTileCallback : public gfxDrawingCallback
|
||||
{
|
||||
public:
|
||||
@ -64,6 +107,9 @@ ClippedImage::ClippedImage(Image* aImage,
|
||||
MOZ_ASSERT(aImage != nullptr, "ClippedImage requires an existing Image");
|
||||
}
|
||||
|
||||
ClippedImage::~ClippedImage()
|
||||
{ }
|
||||
|
||||
bool
|
||||
ClippedImage::ShouldClip()
|
||||
{
|
||||
@ -175,25 +221,41 @@ ClippedImage::GetFrameInternal(const nsIntSize& aViewportSize,
|
||||
return InnerImage()->GetFrame(aWhichFrame, aFlags, _retval);
|
||||
}
|
||||
|
||||
// Create a surface to draw into.
|
||||
gfxImageSurface::gfxImageFormat format = gfxASurface::ImageFormatARGB32;
|
||||
nsRefPtr<gfxASurface> surface = gfxPlatform::GetPlatform()
|
||||
->CreateOffscreenSurface(gfxIntSize(mClip.width, mClip.height),
|
||||
gfxImageSurface::ContentFromFormat(format));
|
||||
// Create our callback.
|
||||
nsRefPtr<gfxDrawingCallback> drawTileCallback =
|
||||
new DrawSingleTileCallback(this, mClip, aViewportSize, aSVGContext, aWhichFrame, aFlags);
|
||||
nsRefPtr<gfxDrawable> drawable =
|
||||
new gfxCallbackDrawable(drawTileCallback, mClip.Size());
|
||||
float frameToDraw = InnerImage()->GetFrameIndex(aWhichFrame);
|
||||
if (!mCachedSurface || !mCachedSurface->Matches(aViewportSize,
|
||||
aSVGContext,
|
||||
frameToDraw,
|
||||
aFlags)) {
|
||||
// Create a surface to draw into.
|
||||
gfxImageSurface::gfxImageFormat format = gfxASurface::ImageFormatARGB32;
|
||||
nsRefPtr<gfxASurface> surface = gfxPlatform::GetPlatform()
|
||||
->CreateOffscreenSurface(gfxIntSize(mClip.width, mClip.height),
|
||||
gfxImageSurface::ContentFromFormat(format));
|
||||
|
||||
// Actually draw. The callback will end up invoking DrawSingleTile.
|
||||
nsRefPtr<gfxContext> ctx = new gfxContext(surface);
|
||||
gfxRect imageRect(0, 0, mClip.width, mClip.height);
|
||||
gfxUtils::DrawPixelSnapped(ctx, drawable, gfxMatrix(),
|
||||
imageRect, imageRect, imageRect, imageRect,
|
||||
gfxASurface::ImageFormatARGB32, gfxPattern::FILTER_FAST);
|
||||
// Create our callback.
|
||||
nsRefPtr<gfxDrawingCallback> drawTileCallback =
|
||||
new DrawSingleTileCallback(this, mClip, aViewportSize, aSVGContext, aWhichFrame, aFlags);
|
||||
nsRefPtr<gfxDrawable> drawable =
|
||||
new gfxCallbackDrawable(drawTileCallback, mClip.Size());
|
||||
|
||||
*_retval = surface.forget().get();
|
||||
// Actually draw. The callback will end up invoking DrawSingleTile.
|
||||
nsRefPtr<gfxContext> ctx = new gfxContext(surface);
|
||||
gfxRect imageRect(0, 0, mClip.width, mClip.height);
|
||||
gfxUtils::DrawPixelSnapped(ctx, drawable, gfxMatrix(),
|
||||
imageRect, imageRect, imageRect, imageRect,
|
||||
format, gfxPattern::FILTER_FAST);
|
||||
|
||||
// Cache the resulting surface.
|
||||
mCachedSurface = new ClippedImageCachedSurface(surface,
|
||||
aViewportSize,
|
||||
aSVGContext,
|
||||
frameToDraw,
|
||||
aFlags);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mCachedSurface, "Should have a cached surface now");
|
||||
*_retval = mCachedSurface->Surface();
|
||||
NS_ADDREF(*_retval);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -206,6 +268,10 @@ ClippedImage::GetImageContainer(LayerManager* aManager, ImageContainer** _retval
|
||||
// actually benefit from GetImageContainer, it would be a good idea to fix
|
||||
// that method for performance reasons.
|
||||
|
||||
if (!ShouldClip()) {
|
||||
return InnerImage()->GetImageContainer(aManager, _retval);
|
||||
}
|
||||
|
||||
*_retval = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
@ -330,5 +396,14 @@ ClippedImage::DrawSingleTile(gfxContext* aContext,
|
||||
viewportSize, aSVGContext, aWhichFrame, aFlags);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ClippedImage::RequestDiscard()
|
||||
{
|
||||
// We're very aggressive about discarding.
|
||||
mCachedSurface = nullptr;
|
||||
|
||||
return InnerImage()->RequestDiscard();
|
||||
}
|
||||
|
||||
} // namespace image
|
||||
} // namespace mozilla
|
||||
|
@ -11,6 +11,7 @@
|
||||
namespace mozilla {
|
||||
namespace image {
|
||||
|
||||
class ClippedImageCachedSurface;
|
||||
class DrawSingleTileCallback;
|
||||
|
||||
/**
|
||||
@ -25,7 +26,7 @@ class ClippedImage : public ImageWrapper
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
virtual ~ClippedImage() { }
|
||||
virtual ~ClippedImage();
|
||||
|
||||
virtual nsIntRect FrameRect(uint32_t aWhichFrame) MOZ_OVERRIDE;
|
||||
|
||||
@ -47,6 +48,7 @@ public:
|
||||
const SVGImageContext* aSVGContext,
|
||||
uint32_t aWhichFrame,
|
||||
uint32_t aFlags) MOZ_OVERRIDE;
|
||||
NS_IMETHOD RequestDiscard() MOZ_OVERRIDE;
|
||||
|
||||
protected:
|
||||
ClippedImage(Image* aImage, nsIntRect aClip);
|
||||
@ -74,6 +76,9 @@ private:
|
||||
uint32_t aWhichFrame,
|
||||
uint32_t aFlags);
|
||||
|
||||
// If we are forced to draw a temporary surface, we cache it here.
|
||||
nsAutoPtr<ClippedImageCachedSurface> mCachedSurface;
|
||||
|
||||
nsIntRect mClip; // The region to clip to.
|
||||
Maybe<bool> mShouldClip; // Memoized ShouldClip() if present.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user