Bug 1201796 (Part 2) - Add GetFrameAtSize() to support downscale-during-decode for GetFrame() use cases. r=tn

This commit is contained in:
Seth Fowler 2015-09-19 13:34:09 -07:00
parent 3a7ad009ae
commit 8abd0f3b26
12 changed files with 127 additions and 31 deletions

View File

@ -220,6 +220,16 @@ ClippedImage::GetFrame(uint32_t aWhichFrame,
return GetFrameInternal(mClip.Size(), Nothing(), aWhichFrame, aFlags);
}
NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
ClippedImage::GetFrameAtSize(const IntSize& aSize,
uint32_t aWhichFrame,
uint32_t aFlags)
{
// XXX(seth): It'd be nice to support downscale-during-decode for this case,
// but right now we just fall back to the intrinsic size.
return GetFrame(aWhichFrame, aFlags);
}
already_AddRefed<SourceSurface>
ClippedImage::GetFrameInternal(const nsIntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,

View File

@ -37,6 +37,10 @@ public:
NS_IMETHOD GetIntrinsicRatio(nsSize* aRatio) override;
NS_IMETHOD_(already_AddRefed<SourceSurface>)
GetFrame(uint32_t aWhichFrame, uint32_t aFlags) override;
NS_IMETHOD_(already_AddRefed<SourceSurface>)
GetFrameAtSize(const gfx::IntSize& aSize,
uint32_t aWhichFrame,
uint32_t aFlags) override;
NS_IMETHOD_(bool) IsImageContainerAvailable(layers::LayerManager* aManager,
uint32_t aFlags) override;
NS_IMETHOD_(already_AddRefed<layers::ImageContainer>)

View File

@ -168,10 +168,18 @@ DynamicImage::GetFrame(uint32_t aWhichFrame,
uint32_t aFlags)
{
gfxIntSize size(mDrawable->Size());
return GetFrameAtSize(IntSize(size.width, size.height),
aWhichFrame,
aFlags);
}
NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
DynamicImage::GetFrameAtSize(const IntSize& aSize,
uint32_t aWhichFrame,
uint32_t aFlags)
{
RefPtr<DrawTarget> dt = gfxPlatform::GetPlatform()->
CreateOffscreenContentDrawTarget(IntSize(size.width, size.height),
SurfaceFormat::B8G8R8A8);
CreateOffscreenContentDrawTarget(aSize, SurfaceFormat::B8G8R8A8);
if (!dt) {
gfxWarning() <<
"DynamicImage::GetFrame failed in CreateOffscreenContentDrawTarget";
@ -179,7 +187,7 @@ DynamicImage::GetFrame(uint32_t aWhichFrame,
}
nsRefPtr<gfxContext> context = new gfxContext(dt);
auto result = Draw(context, size, ImageRegion::Create(size),
auto result = Draw(context, aSize, ImageRegion::Create(aSize),
aWhichFrame, GraphicsFilter::FILTER_NEAREST,
Nothing(), aFlags);

View File

@ -44,6 +44,14 @@ FrozenImage::GetFrame(uint32_t aWhichFrame,
return InnerImage()->GetFrame(FRAME_FIRST, aFlags);
}
NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
FrozenImage::GetFrameAtSize(const IntSize& aSize,
uint32_t aWhichFrame,
uint32_t aFlags)
{
return InnerImage()->GetFrameAtSize(aSize, FRAME_FIRST, aFlags);
}
NS_IMETHODIMP_(bool)
FrozenImage::IsImageContainerAvailable(LayerManager* aManager, uint32_t aFlags)
{

View File

@ -37,6 +37,10 @@ public:
NS_IMETHOD GetAnimated(bool* aAnimated) override;
NS_IMETHOD_(already_AddRefed<SourceSurface>)
GetFrame(uint32_t aWhichFrame, uint32_t aFlags) override;
NS_IMETHOD_(already_AddRefed<SourceSurface>)
GetFrameAtSize(const gfx::IntSize& aSize,
uint32_t aWhichFrame,
uint32_t aFlags) override;
NS_IMETHOD_(bool) IsImageContainerAvailable(layers::LayerManager* aManager,
uint32_t aFlags) override;
NS_IMETHOD_(already_AddRefed<layers::ImageContainer>)

View File

@ -174,6 +174,14 @@ ImageWrapper::GetFrame(uint32_t aWhichFrame,
return mInnerImage->GetFrame(aWhichFrame, aFlags);
}
NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
ImageWrapper::GetFrameAtSize(const IntSize& aSize,
uint32_t aWhichFrame,
uint32_t aFlags)
{
return mInnerImage->GetFrameAtSize(aSize, aWhichFrame, aFlags);
}
NS_IMETHODIMP_(bool)
ImageWrapper::IsOpaque()
{

View File

@ -122,6 +122,16 @@ OrientedImage::GetFrame(uint32_t aWhichFrame,
return target->Snapshot();
}
NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
OrientedImage::GetFrameAtSize(const IntSize& aSize,
uint32_t aWhichFrame,
uint32_t aFlags)
{
// XXX(seth): It'd be nice to support downscale-during-decode for this case,
// but right now we just fall back to the intrinsic size.
return GetFrame(aWhichFrame, aFlags);
}
NS_IMETHODIMP_(bool)
OrientedImage::IsImageContainerAvailable(LayerManager* aManager, uint32_t aFlags)
{

View File

@ -34,6 +34,10 @@ public:
NS_IMETHOD GetIntrinsicRatio(nsSize* aRatio) override;
NS_IMETHOD_(already_AddRefed<SourceSurface>)
GetFrame(uint32_t aWhichFrame, uint32_t aFlags) override;
NS_IMETHOD_(already_AddRefed<SourceSurface>)
GetFrameAtSize(const gfx::IntSize& aSize,
uint32_t aWhichFrame,
uint32_t aFlags) override;
NS_IMETHOD_(bool) IsImageContainerAvailable(layers::LayerManager* aManager,
uint32_t aFlags) override;
NS_IMETHOD_(already_AddRefed<layers::ImageContainer>)

View File

@ -698,14 +698,28 @@ NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
RasterImage::GetFrame(uint32_t aWhichFrame,
uint32_t aFlags)
{
return GetFrameInternal(aWhichFrame, aFlags).second().forget();
return GetFrameInternal(mSize, aWhichFrame, aFlags).second().forget();
}
NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
RasterImage::GetFrameAtSize(const IntSize& aSize,
uint32_t aWhichFrame,
uint32_t aFlags)
{
return GetFrameInternal(aSize, aWhichFrame, aFlags).second().forget();
}
Pair<DrawResult, RefPtr<SourceSurface>>
RasterImage::GetFrameInternal(uint32_t aWhichFrame, uint32_t aFlags)
RasterImage::GetFrameInternal(const IntSize& aSize,
uint32_t aWhichFrame,
uint32_t aFlags)
{
MOZ_ASSERT(aWhichFrame <= FRAME_MAX_VALUE);
if (aSize.IsEmpty()) {
return MakePair(DrawResult::BAD_ARGS, RefPtr<SourceSurface>());
}
if (aWhichFrame > FRAME_MAX_VALUE) {
return MakePair(DrawResult::BAD_ARGS, RefPtr<SourceSurface>());
}
@ -718,7 +732,7 @@ RasterImage::GetFrameInternal(uint32_t aWhichFrame, uint32_t aFlags)
// not waiting for the data to be loaded from the network or not passing
// FLAG_SYNC_DECODE
DrawableFrameRef frameRef =
LookupFrame(GetRequestedFrameIndex(aWhichFrame), mSize, aFlags);
LookupFrame(GetRequestedFrameIndex(aWhichFrame), aSize, aFlags);
if (!frameRef) {
// The OS threw this frame away and we couldn't redecode it.
return MakePair(DrawResult::TEMPORARY_ERROR, RefPtr<SourceSurface>());
@ -727,15 +741,15 @@ RasterImage::GetFrameInternal(uint32_t aWhichFrame, uint32_t aFlags)
// If this frame covers the entire image, we can just reuse its existing
// surface.
RefPtr<SourceSurface> frameSurf;
IntRect frameRect = frameRef->GetRect();
if (frameRect.x == 0 && frameRect.y == 0 &&
frameRect.width == mSize.width &&
frameRect.height == mSize.height) {
if (!frameRef->NeedsPadding() &&
frameRef->GetSize() == aSize) {
frameSurf = frameRef->GetSurface();
}
// The image doesn't have a usable surface because it's been optimized away or
// because it's a partial update frame from an animation. Create one.
// because it's a partial update frame from an animation. Create one. (In this
// case we fall back to returning a surface at our intrinsic size, even if a
// different size was originally specified.)
if (!frameSurf) {
frameSurf = CopyFrame(aWhichFrame, aFlags);
}
@ -756,7 +770,7 @@ RasterImage::GetCurrentImage(ImageContainer* aContainer, uint32_t aFlags)
DrawResult drawResult;
RefPtr<SourceSurface> surface;
Tie(drawResult, surface) =
GetFrameInternal(FRAME_CURRENT, aFlags | FLAG_ASYNC_NOTIFY);
GetFrameInternal(mSize, FRAME_CURRENT, aFlags | FLAG_ASYNC_NOTIFY);
if (!surface) {
// The OS threw out some or all of our buffer. We'll need to wait for the
// redecode (which was automatically triggered by GetFrame) to complete.

View File

@ -265,7 +265,9 @@ private:
uint32_t aFlags);
Pair<DrawResult, RefPtr<gfx::SourceSurface>>
GetFrameInternal(uint32_t aWhichFrame, uint32_t aFlags);
GetFrameInternal(const gfx::IntSize& aSize,
uint32_t aWhichFrame,
uint32_t aFlags);
LookupResult LookupFrameInternal(uint32_t aFrameNum,
const gfx::IntSize& aSize,

View File

@ -668,19 +668,8 @@ VectorImage::IsOpaque()
/* [noscript] SourceSurface getFrame(in uint32_t aWhichFrame,
* in uint32_t aFlags; */
NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
VectorImage::GetFrame(uint32_t aWhichFrame,
uint32_t aFlags)
VectorImage::GetFrame(uint32_t aWhichFrame, uint32_t aFlags)
{
MOZ_ASSERT(aWhichFrame <= FRAME_MAX_VALUE);
if (aWhichFrame > FRAME_MAX_VALUE) {
return nullptr;
}
if (mError || !mIsFullyLoaded) {
return nullptr;
}
// Look up height & width
// ----------------------
SVGSVGElement* svgElem = mSVGDocumentWrapper->GetRootSVGElem();
@ -695,12 +684,32 @@ VectorImage::GetFrame(uint32_t aWhichFrame,
return nullptr;
}
return GetFrameAtSize(imageIntSize, aWhichFrame, aFlags);
}
NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
VectorImage::GetFrameAtSize(const IntSize& aSize,
uint32_t aWhichFrame,
uint32_t aFlags)
{
MOZ_ASSERT(aWhichFrame <= FRAME_MAX_VALUE);
if (aSize.IsEmpty()) {
return nullptr;
}
if (aWhichFrame > FRAME_MAX_VALUE) {
return nullptr;
}
if (mError || !mIsFullyLoaded) {
return nullptr;
}
// Make our surface the size of what will ultimately be drawn to it.
// (either the full image size, or the restricted region)
RefPtr<DrawTarget> dt = gfxPlatform::GetPlatform()->
CreateOffscreenContentDrawTarget(IntSize(imageIntSize.width,
imageIntSize.height),
SurfaceFormat::B8G8R8A8);
CreateOffscreenContentDrawTarget(aSize, SurfaceFormat::B8G8R8A8);
if (!dt) {
NS_ERROR("Could not create a DrawTarget");
return nullptr;
@ -708,8 +717,8 @@ VectorImage::GetFrame(uint32_t aWhichFrame,
nsRefPtr<gfxContext> context = new gfxContext(dt);
auto result = Draw(context, imageIntSize,
ImageRegion::Create(imageIntSize),
auto result = Draw(context, aSize,
ImageRegion::Create(aSize),
aWhichFrame, GraphicsFilter::FILTER_NEAREST,
Nothing(), aFlags);

View File

@ -119,7 +119,7 @@ native nsIntSizeByVal(nsIntSize);
*
* Internally, imgIContainer also manages animation of images.
*/
[scriptable, builtinclass, uuid(4880727a-5673-44f7-b248-f6c86e22a434)]
[scriptable, builtinclass, uuid(4e5a0547-6c54-4051-8b52-1f2fdd667696)]
interface imgIContainer : nsISupports
{
/**
@ -267,6 +267,21 @@ interface imgIContainer : nsISupports
[noscript, notxpcom] TempRefSourceSurface getFrame(in uint32_t aWhichFrame,
in uint32_t aFlags);
/**
* Get a surface for the given frame at the specified size. Matching the
* requested size is best effort; it's not guaranteed that the surface you get
* will be a perfect match. (Some reasons you may get a surface of a different
* size include: if you requested upscaling, if downscale-during-decode is
* disabled, or if you didn't request the first frame.)
*
* @param aSize The desired size.
* @param aWhichFrame Frame specifier of the FRAME_* variety.
* @param aFlags Flags of the FLAG_* variety
*/
[noscript, notxpcom] TempRefSourceSurface getFrameAtSize([const] in nsIntSize aSize,
in uint32_t aWhichFrame,
in uint32_t aFlags);
/**
* Whether this image is opaque (i.e., needs a background painted behind it).
*/