Bug 1550523 - Ensure that decoding methods for frozen images request the correct frame. r=tnikkel

With WebRender, we had observed that the print preview for animated
images was not displaying correctly. It should display the first frame
but it was showing nothing the first time the preview was opened. Once
the decoded image was available in the cache, it would display
correctly if the preview was reloaded.

The StartDecoding and RequestDecode variants always requested
FRAME_CURRENT for animated images. They should use FRAME_FIRST for
static requests / FrozenImage. Correcting this fixes the print preview.


Differential Revision: https://phabricator.services.mozilla.com/D32033
This commit is contained in:
Andrew Osmond 2019-05-21 13:34:14 -04:00
parent ae27e42724
commit 774c428cae
8 changed files with 117 additions and 36 deletions

View File

@ -219,14 +219,23 @@ DynamicImage::Draw(gfxContext* aContext, const nsIntSize& aSize,
}
NS_IMETHODIMP
DynamicImage::StartDecoding(uint32_t aFlags) { return NS_OK; }
DynamicImage::StartDecoding(uint32_t aFlags, uint32_t aWhichFrame) {
return NS_OK;
}
bool DynamicImage::StartDecodingWithResult(uint32_t aFlags) { return true; }
bool DynamicImage::StartDecodingWithResult(uint32_t aFlags,
uint32_t aWhichFrame) {
return true;
}
bool DynamicImage::RequestDecodeWithResult(uint32_t aFlags) { return true; }
bool DynamicImage::RequestDecodeWithResult(uint32_t aFlags,
uint32_t aWhichFrame) {
return true;
}
NS_IMETHODIMP
DynamicImage::RequestDecodeForSize(const nsIntSize& aSize, uint32_t aFlags) {
DynamicImage::RequestDecodeForSize(const nsIntSize& aSize, uint32_t aFlags,
uint32_t aWhichFrame) {
return NS_OK;
}

View File

@ -92,6 +92,27 @@ FrozenImage::Draw(gfxContext* aContext, const nsIntSize& aSize,
aSamplingFilter, aSVGContext, aFlags, aOpacity);
}
NS_IMETHODIMP
FrozenImage::StartDecoding(uint32_t aFlags, uint32_t aWhichFrame) {
return InnerImage()->StartDecoding(aFlags, FRAME_FIRST);
}
bool FrozenImage::StartDecodingWithResult(uint32_t aFlags,
uint32_t aWhichFrame) {
return InnerImage()->StartDecodingWithResult(aFlags, FRAME_FIRST);
}
bool FrozenImage::RequestDecodeWithResult(uint32_t aFlags,
uint32_t aWhichFrame) {
return InnerImage()->RequestDecodeWithResult(aFlags, FRAME_FIRST);
}
NS_IMETHODIMP
FrozenImage::RequestDecodeForSize(const nsIntSize& aSize, uint32_t aFlags,
uint32_t aWhichFrame) {
return InnerImage()->RequestDecodeForSize(aSize, aFlags, FRAME_FIRST);
}
NS_IMETHODIMP_(void)
FrozenImage::RequestRefresh(const TimeStamp& aTime) {
// Do nothing.

View File

@ -59,6 +59,13 @@ class FrozenImage : public ImageWrapper {
uint32_t aWhichFrame, gfx::SamplingFilter aSamplingFilter,
const Maybe<SVGImageContext>& aSVGContext, uint32_t aFlags,
float aOpacity) override;
NS_IMETHOD StartDecoding(uint32_t aFlags, uint32_t aWhichFrame) override;
NS_IMETHOD_(bool)
StartDecodingWithResult(uint32_t aFlags, uint32_t aWhichFrame) override;
NS_IMETHOD_(bool)
RequestDecodeWithResult(uint32_t aFlags, uint32_t aWhichFrame) override;
NS_IMETHOD RequestDecodeForSize(const nsIntSize& aSize, uint32_t aFlags,
uint32_t aWhichFrame) override;
NS_IMETHOD_(void) RequestRefresh(const TimeStamp& aTime) override;
NS_IMETHOD GetAnimationMode(uint16_t* aAnimationMode) override;
NS_IMETHOD SetAnimationMode(uint16_t aAnimationMode) override;

View File

@ -193,21 +193,24 @@ ImageWrapper::Draw(gfxContext* aContext, const nsIntSize& aSize,
}
NS_IMETHODIMP
ImageWrapper::StartDecoding(uint32_t aFlags) {
return mInnerImage->StartDecoding(aFlags);
ImageWrapper::StartDecoding(uint32_t aFlags, uint32_t aWhichFrame) {
return mInnerImage->StartDecoding(aFlags, aWhichFrame);
}
bool ImageWrapper::StartDecodingWithResult(uint32_t aFlags) {
return mInnerImage->StartDecodingWithResult(aFlags);
bool ImageWrapper::StartDecodingWithResult(uint32_t aFlags,
uint32_t aWhichFrame) {
return mInnerImage->StartDecodingWithResult(aFlags, aWhichFrame);
}
bool ImageWrapper::RequestDecodeWithResult(uint32_t aFlags) {
return mInnerImage->RequestDecodeWithResult(aFlags);
bool ImageWrapper::RequestDecodeWithResult(uint32_t aFlags,
uint32_t aWhichFrame) {
return mInnerImage->RequestDecodeWithResult(aFlags, aWhichFrame);
}
NS_IMETHODIMP
ImageWrapper::RequestDecodeForSize(const nsIntSize& aSize, uint32_t aFlags) {
return mInnerImage->RequestDecodeForSize(aSize, aFlags);
ImageWrapper::RequestDecodeForSize(const nsIntSize& aSize, uint32_t aFlags,
uint32_t aWhichFrame) {
return mInnerImage->RequestDecodeForSize(aSize, aFlags, aWhichFrame);
}
NS_IMETHODIMP

View File

@ -1046,7 +1046,7 @@ bool RasterImage::CanDiscard() {
}
NS_IMETHODIMP
RasterImage::StartDecoding(uint32_t aFlags) {
RasterImage::StartDecoding(uint32_t aFlags, uint32_t aWhichFrame) {
if (mError) {
return NS_ERROR_FAILURE;
}
@ -1058,10 +1058,11 @@ RasterImage::StartDecoding(uint32_t aFlags) {
uint32_t flags = (aFlags & FLAG_ASYNC_NOTIFY) | FLAG_SYNC_DECODE_IF_FAST |
FLAG_HIGH_QUALITY_SCALING;
return RequestDecodeForSize(mSize, flags);
return RequestDecodeForSize(mSize, flags, aWhichFrame);
}
bool RasterImage::StartDecodingWithResult(uint32_t aFlags) {
bool RasterImage::StartDecodingWithResult(uint32_t aFlags,
uint32_t aWhichFrame) {
if (mError) {
return false;
}
@ -1073,11 +1074,13 @@ bool RasterImage::StartDecodingWithResult(uint32_t aFlags) {
uint32_t flags = (aFlags & FLAG_ASYNC_NOTIFY) | FLAG_SYNC_DECODE_IF_FAST |
FLAG_HIGH_QUALITY_SCALING;
DrawableSurface surface = RequestDecodeForSizeInternal(mSize, flags);
DrawableSurface surface =
RequestDecodeForSizeInternal(mSize, flags, aWhichFrame);
return surface && surface->IsFinished();
}
bool RasterImage::RequestDecodeWithResult(uint32_t aFlags) {
bool RasterImage::RequestDecodeWithResult(uint32_t aFlags,
uint32_t aWhichFrame) {
MOZ_ASSERT(NS_IsMainThread());
if (mError) {
@ -1085,27 +1088,33 @@ bool RasterImage::RequestDecodeWithResult(uint32_t aFlags) {
}
uint32_t flags = aFlags | FLAG_ASYNC_NOTIFY;
DrawableSurface surface = RequestDecodeForSizeInternal(mSize, flags);
DrawableSurface surface =
RequestDecodeForSizeInternal(mSize, flags, aWhichFrame);
return surface && surface->IsFinished();
}
NS_IMETHODIMP
RasterImage::RequestDecodeForSize(const IntSize& aSize, uint32_t aFlags) {
RasterImage::RequestDecodeForSize(const IntSize& aSize, uint32_t aFlags,
uint32_t aWhichFrame) {
MOZ_ASSERT(NS_IsMainThread());
if (mError) {
return NS_ERROR_FAILURE;
}
RequestDecodeForSizeInternal(aSize, aFlags);
RequestDecodeForSizeInternal(aSize, aFlags, aWhichFrame);
return NS_OK;
}
DrawableSurface RasterImage::RequestDecodeForSizeInternal(const IntSize& aSize,
uint32_t aFlags) {
DrawableSurface RasterImage::RequestDecodeForSizeInternal(
const IntSize& aSize, uint32_t aFlags, uint32_t aWhichFrame) {
MOZ_ASSERT(NS_IsMainThread());
if (aWhichFrame > FRAME_MAX_VALUE) {
return DrawableSurface();
}
if (mError) {
return DrawableSurface();
}
@ -1125,10 +1134,8 @@ DrawableSurface RasterImage::RequestDecodeForSizeInternal(const IntSize& aSize,
shouldSyncDecodeIfFast ? aFlags : aFlags & ~FLAG_SYNC_DECODE_IF_FAST;
// Perform a frame lookup, which will implicitly start decoding if needed.
PlaybackType playbackType =
mAnimationState ? PlaybackType::eAnimated : PlaybackType::eStatic;
LookupResult result =
LookupFrame(aSize, flags, playbackType, /* aMarkUsed = */ false);
LookupResult result = LookupFrame(aSize, flags, ToPlaybackType(aWhichFrame),
/* aMarkUsed = */ false);
return std::move(result.Surface());
}
@ -1697,7 +1704,8 @@ void RasterImage::NotifyDecodeComplete(
if (mWantFullDecode) {
mWantFullDecode = false;
RequestDecodeForSize(mSize,
DECODE_FLAGS_DEFAULT | FLAG_HIGH_QUALITY_SCALING);
DECODE_FLAGS_DEFAULT | FLAG_HIGH_QUALITY_SCALING,
FRAME_CURRENT);
}
}
}

View File

@ -452,7 +452,8 @@ class RasterImage final : public ImageResource,
bool IsOpaque();
DrawableSurface RequestDecodeForSizeInternal(const gfx::IntSize& aSize,
uint32_t aFlags);
uint32_t aFlags,
uint32_t aWhichFrame);
protected:
explicit RasterImage(nsIURI* aURI = nullptr);

View File

@ -1202,23 +1202,26 @@ void VectorImage::RecoverFromLossOfSurfaces() {
}
NS_IMETHODIMP
VectorImage::StartDecoding(uint32_t aFlags) {
VectorImage::StartDecoding(uint32_t aFlags, uint32_t aWhichFrame) {
// Nothing to do for SVG images
return NS_OK;
}
bool VectorImage::StartDecodingWithResult(uint32_t aFlags) {
bool VectorImage::StartDecodingWithResult(uint32_t aFlags,
uint32_t aWhichFrame) {
// SVG images are ready to draw when they are loaded
return mIsFullyLoaded;
}
bool VectorImage::RequestDecodeWithResult(uint32_t aFlags) {
bool VectorImage::RequestDecodeWithResult(uint32_t aFlags,
uint32_t aWhichFrame) {
// SVG images are ready to draw when they are loaded
return mIsFullyLoaded;
}
NS_IMETHODIMP
VectorImage::RequestDecodeForSize(const nsIntSize& aSize, uint32_t aFlags) {
VectorImage::RequestDecodeForSize(const nsIntSize& aSize, uint32_t aFlags,
uint32_t aWhichFrame) {
// Nothing to do for SVG images, though in theory we could rasterize to the
// provided size ahead of time if we supported off-main-thread SVG
// rasterization...

View File

@ -467,8 +467,15 @@ interface imgIContainer : nsISupports
*
* @param aFlags Flags of the FLAG_* variety. Only FLAG_ASYNC_NOTIFY
* is accepted; all others are ignored.
* @param aWhichFrame Frame specifier of the FRAME_* variety.
*/
[noscript] void startDecoding(in uint32_t aFlags);
[noscript] void startDecoding(in uint32_t aFlags, in uint32_t aWhichFrame);
%{C++
nsresult StartDecoding(uint32_t aFlags) {
return StartDecoding(aFlags, FRAME_CURRENT);
}
%}
/*
* Exactly like startDecoding above except returns whether the current frame
@ -476,8 +483,15 @@ interface imgIContainer : nsISupports
*
* @param aFlags Flags of the FLAG_* variety. Only FLAG_ASYNC_NOTIFY
* is accepted; all others are ignored.
* @param aWhichFrame Frame specifier of the FRAME_* variety.
*/
[noscript, notxpcom] boolean startDecodingWithResult(in uint32_t aFlags);
[noscript, notxpcom] boolean startDecodingWithResult(in uint32_t aFlags, in uint32_t aWhichFrame);
%{C++
bool StartDecodingWithResult(uint32_t aFlags) {
return StartDecodingWithResult(aFlags, FRAME_CURRENT);
}
%}
/*
* This method triggers decoding for an image, but unlike startDecoding() it
@ -485,10 +499,17 @@ interface imgIContainer : nsISupports
* request.
*
* @param aFlags Flags of the FLAG_* variety.
* @param aWhichFrame Frame specifier of the FRAME_* variety.
* @return True there is a surface that satisfies the request and it is
* fully decoded, else false.
*/
[noscript, notxpcom] boolean requestDecodeWithResult(in uint32_t aFlags);
[noscript, notxpcom] boolean requestDecodeWithResult(in uint32_t aFlags, in uint32_t aWhichFrame);
%{C++
bool RequestDecodeWithResult(uint32_t aFlags) {
return RequestDecodeWithResult(aFlags, FRAME_CURRENT);
}
%}
/*
* This method triggers decoding for an image, but unlike startDecoding() it
@ -499,9 +520,17 @@ interface imgIContainer : nsISupports
* if possible. If the image cannot be scaled to this size while
* being decoded, it will be decoded at its intrinsic size.
* @param aFlags Flags of the FLAG_* variety.
* @param aWhichFrame Frame specifier of the FRAME_* variety.
*/
[noscript] void requestDecodeForSize([const] in nsIntSize aSize,
in uint32_t aFlags);
in uint32_t aFlags,
in uint32_t aWhichFrame);
%{C++
nsresult RequestDecodeForSize(const nsIntSize& aSize, uint32_t aFlags) {
return RequestDecodeForSize(aSize, aFlags, FRAME_CURRENT);
}
%}
/**
* Increments the lock count on the image. An image will not be discarded