Skip to content

Commit

Permalink
Bug 1201796 (Part 2) - Add GetFrameAtSize() to support downscale-duri…
Browse files Browse the repository at this point in the history
…ng-decode for GetFrame() use cases. r=tn
  • Loading branch information
sethfowler committed Sep 19, 2015
1 parent 30373cd commit ddc24de
Show file tree
Hide file tree
Showing 12 changed files with 127 additions and 31 deletions.
10 changes: 10 additions & 0 deletions image/ClippedImage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 4 additions & 0 deletions image/ClippedImage.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ class ClippedImage : public ImageWrapper
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>)
Expand Down
14 changes: 11 additions & 3 deletions image/DynamicImage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,18 +168,26 @@ 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";
return nullptr;
}
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);

Expand Down
8 changes: 8 additions & 0 deletions image/FrozenImage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
4 changes: 4 additions & 0 deletions image/FrozenImage.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ class FrozenImage : public ImageWrapper
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>)
Expand Down
8 changes: 8 additions & 0 deletions image/ImageWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()
{
Expand Down
10 changes: 10 additions & 0 deletions image/OrientedImage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
4 changes: 4 additions & 0 deletions image/OrientedImage.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ class OrientedImage : public ImageWrapper
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>)
Expand Down
32 changes: 23 additions & 9 deletions image/RasterImage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>());
}
Expand All @@ -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>());
Expand All @@ -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);
}
Expand All @@ -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.
Expand Down
4 changes: 3 additions & 1 deletion image/RasterImage.h
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,9 @@ class RasterImage final : public ImageResource
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,
Expand Down
43 changes: 26 additions & 17 deletions image/VectorImage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -695,21 +684,41 @@ 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;
}

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);

Expand Down
17 changes: 16 additions & 1 deletion image/imgIContainer.idl
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
/**
Expand Down Expand Up @@ -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).
*/
Expand Down

0 comments on commit ddc24de

Please sign in to comment.