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-18 10:54:35 -07:00
parent d919167ec8
commit 070157c0f4
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); 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> already_AddRefed<SourceSurface>
ClippedImage::GetFrameInternal(const nsIntSize& aSize, ClippedImage::GetFrameInternal(const nsIntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext, const Maybe<SVGImageContext>& aSVGContext,

View File

@ -37,6 +37,10 @@ public:
NS_IMETHOD GetIntrinsicRatio(nsSize* aRatio) override; NS_IMETHOD GetIntrinsicRatio(nsSize* aRatio) override;
NS_IMETHOD_(already_AddRefed<SourceSurface>) NS_IMETHOD_(already_AddRefed<SourceSurface>)
GetFrame(uint32_t aWhichFrame, uint32_t aFlags) override; 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, NS_IMETHOD_(bool) IsImageContainerAvailable(layers::LayerManager* aManager,
uint32_t aFlags) override; uint32_t aFlags) override;
NS_IMETHOD_(already_AddRefed<layers::ImageContainer>) NS_IMETHOD_(already_AddRefed<layers::ImageContainer>)

View File

@ -168,10 +168,18 @@ DynamicImage::GetFrame(uint32_t aWhichFrame,
uint32_t aFlags) uint32_t aFlags)
{ {
gfxIntSize size(mDrawable->Size()); 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()-> RefPtr<DrawTarget> dt = gfxPlatform::GetPlatform()->
CreateOffscreenContentDrawTarget(IntSize(size.width, size.height), CreateOffscreenContentDrawTarget(aSize, SurfaceFormat::B8G8R8A8);
SurfaceFormat::B8G8R8A8);
if (!dt) { if (!dt) {
gfxWarning() << gfxWarning() <<
"DynamicImage::GetFrame failed in CreateOffscreenContentDrawTarget"; "DynamicImage::GetFrame failed in CreateOffscreenContentDrawTarget";
@ -179,7 +187,7 @@ DynamicImage::GetFrame(uint32_t aWhichFrame,
} }
nsRefPtr<gfxContext> context = new gfxContext(dt); 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, aWhichFrame, GraphicsFilter::FILTER_NEAREST,
Nothing(), aFlags); Nothing(), aFlags);

View File

@ -44,6 +44,14 @@ FrozenImage::GetFrame(uint32_t aWhichFrame,
return InnerImage()->GetFrame(FRAME_FIRST, aFlags); 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) NS_IMETHODIMP_(bool)
FrozenImage::IsImageContainerAvailable(LayerManager* aManager, uint32_t aFlags) FrozenImage::IsImageContainerAvailable(LayerManager* aManager, uint32_t aFlags)
{ {

View File

@ -37,6 +37,10 @@ public:
NS_IMETHOD GetAnimated(bool* aAnimated) override; NS_IMETHOD GetAnimated(bool* aAnimated) override;
NS_IMETHOD_(already_AddRefed<SourceSurface>) NS_IMETHOD_(already_AddRefed<SourceSurface>)
GetFrame(uint32_t aWhichFrame, uint32_t aFlags) override; 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, NS_IMETHOD_(bool) IsImageContainerAvailable(layers::LayerManager* aManager,
uint32_t aFlags) override; uint32_t aFlags) override;
NS_IMETHOD_(already_AddRefed<layers::ImageContainer>) NS_IMETHOD_(already_AddRefed<layers::ImageContainer>)

View File

@ -174,6 +174,14 @@ ImageWrapper::GetFrame(uint32_t aWhichFrame,
return mInnerImage->GetFrame(aWhichFrame, aFlags); 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) NS_IMETHODIMP_(bool)
ImageWrapper::IsOpaque() ImageWrapper::IsOpaque()
{ {

View File

@ -122,6 +122,16 @@ OrientedImage::GetFrame(uint32_t aWhichFrame,
return target->Snapshot(); 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) NS_IMETHODIMP_(bool)
OrientedImage::IsImageContainerAvailable(LayerManager* aManager, uint32_t aFlags) OrientedImage::IsImageContainerAvailable(LayerManager* aManager, uint32_t aFlags)
{ {

View File

@ -34,6 +34,10 @@ public:
NS_IMETHOD GetIntrinsicRatio(nsSize* aRatio) override; NS_IMETHOD GetIntrinsicRatio(nsSize* aRatio) override;
NS_IMETHOD_(already_AddRefed<SourceSurface>) NS_IMETHOD_(already_AddRefed<SourceSurface>)
GetFrame(uint32_t aWhichFrame, uint32_t aFlags) override; 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, NS_IMETHOD_(bool) IsImageContainerAvailable(layers::LayerManager* aManager,
uint32_t aFlags) override; uint32_t aFlags) override;
NS_IMETHOD_(already_AddRefed<layers::ImageContainer>) NS_IMETHOD_(already_AddRefed<layers::ImageContainer>)

View File

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

View File

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

View File

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

View File

@ -119,7 +119,7 @@ native nsIntSizeByVal(nsIntSize);
* *
* Internally, imgIContainer also manages animation of images. * 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 interface imgIContainer : nsISupports
{ {
/** /**
@ -267,6 +267,21 @@ interface imgIContainer : nsISupports
[noscript, notxpcom] TempRefSourceSurface getFrame(in uint32_t aWhichFrame, [noscript, notxpcom] TempRefSourceSurface getFrame(in uint32_t aWhichFrame,
in uint32_t aFlags); 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). * Whether this image is opaque (i.e., needs a background painted behind it).
*/ */