Bug 1337111 - Part 5. Add pref to force decoding of full frames, disabled by default. r=tnikkel

This commit is contained in:
Andrew Osmond 2018-09-17 15:06:29 -04:00
parent 8d1ec5a066
commit 8be55f0165
8 changed files with 43 additions and 13 deletions

View File

@ -543,6 +543,7 @@ private:
DECL_GFX_PREF(Live, "image.animated.decode-on-demand.threshold-kb", ImageAnimatedDecodeOnDemandThresholdKB, uint32_t, 20480);
DECL_GFX_PREF(Live, "image.animated.decode-on-demand.batch-size", ImageAnimatedDecodeOnDemandBatchSize, uint32_t, 6);
DECL_GFX_PREF(Live, "image.animated.generate-full-frames", ImageAnimatedGenerateFullFrames, bool, false);
DECL_GFX_PREF(Live, "image.animated.resume-from-last-displayed", ImageAnimatedResumeFromLastDisplayed, bool, false);
DECL_GFX_PREF(Live, "image.cache.factor2.threshold-surfaces", ImageCacheFactor2ThresholdSurfaces, int32_t, -1);
DECL_GFX_PREF(Once, "image.cache.size", ImageCacheSize, int32_t, 5*1024*1024);

View File

@ -32,10 +32,10 @@ AnimationSurfaceProvider::AnimationSurfaceProvider(NotNull<RasterImage*> aImage,
MOZ_ASSERT(!mDecoder->IsFirstFrameDecode(),
"Use DecodedSurfaceProvider for single-frame image decodes");
// We still produce paletted surfaces for GIF which means the frames are
// smaller than one would expect for APNG. This may be removed if/when
// bug 1337111 lands and it is enabled by default.
size_t pixelSize = aDecoder->GetType() == DecoderType::GIF
// We may produce paletted surfaces for GIF which means the frames are smaller
// than one would expect.
size_t pixelSize = !aDecoder->ShouldBlendAnimation() &&
aDecoder->GetType() == DecoderType::GIF
? sizeof(uint8_t) : sizeof(uint32_t);
// Calculate how many frames we need to decode in this animation before we

View File

@ -343,7 +343,7 @@ Decoder::AllocateFrameInternal(const gfx::IntSize& aOutputSize,
bool nonPremult = bool(mSurfaceFlags & SurfaceFlags::NO_PREMULTIPLY_ALPHA);
if (NS_FAILED(frame->InitForDecoder(aOutputSize, aFrameRect, aFormat,
aPaletteDepth, nonPremult,
aAnimParams))) {
aAnimParams, ShouldBlendAnimation()))) {
NS_WARNING("imgFrame::Init should succeed");
return RawAccessFrameRef();
}

View File

@ -316,10 +316,10 @@ FrameAnimator::AdvanceFrame(AnimationState& aState,
}
if (nextFrameIndex == 0) {
MOZ_ASSERT(nextFrame->IsFullFrame());
ret.mDirtyRect = aState.FirstFrameRefreshArea();
} else {
} else if (!nextFrame->IsFullFrame()) {
MOZ_ASSERT(nextFrameIndex == currentFrameIndex + 1);
// Change frame
if (!DoBlend(aCurrentFrame, nextFrame, nextFrameIndex, &ret.mDirtyRect)) {
// something went wrong, move on to next
@ -336,6 +336,8 @@ FrameAnimator::AdvanceFrame(AnimationState& aState,
}
nextFrame->SetCompositingFailed(false);
} else {
ret.mDirtyRect = nextFrame->GetDirtyRect();
}
aState.mCurrentAnimationFrameTime =
@ -483,8 +485,13 @@ FrameAnimator::RequestRefresh(AnimationState& aState,
}
}
// Advanced to the correct frame, the composited frame is now valid to be drawn.
if (currentFrameEndTime > aTime) {
// We should only mark the composited frame as valid and reset the dirty rect
// if we advanced (meaning the next frame was actually produced somehow), the
// composited frame was previously invalid (so we may need to repaint
// everything) and the frame index is valid (to know we were doing blending
// on the main thread, instead of on the decoder threads in advance).
if (currentFrameEndTime > aTime && aState.mCompositedFrameInvalid &&
mLastCompositedFrameIndex >= 0) {
aState.mCompositedFrameInvalid = false;
ret.mDirtyRect = IntRect(IntPoint(0,0), mSize);
}

View File

@ -1286,6 +1286,10 @@ RasterImage::Decode(const IntSize& aSize,
nsresult rv;
bool animated = mAnimationState && aPlaybackType == PlaybackType::eAnimated;
if (animated) {
if (gfxPrefs::ImageAnimatedGenerateFullFrames()) {
decoderFlags |= DecoderFlags::BLEND_ANIMATION;
}
size_t currentFrame = mAnimationState->GetCurrentAnimationFrameIndex();
rv = DecoderFactory::CreateAnimationDecoder(mDecoderType, WrapNotNull(this),
mSourceBuffer, mSize,

View File

@ -213,6 +213,7 @@ imgFrame::imgFrame()
, mPalettedImageData(nullptr)
, mPaletteDepth(0)
, mNonPremult(false)
, mIsFullFrame(false)
, mCompositingFailed(false)
{
}
@ -235,7 +236,8 @@ imgFrame::InitForDecoder(const nsIntSize& aImageSize,
SurfaceFormat aFormat,
uint8_t aPaletteDepth /* = 0 */,
bool aNonPremult /* = false */,
const Maybe<AnimationParams>& aAnimParams /* = Nothing() */)
const Maybe<AnimationParams>& aAnimParams /* = Nothing() */,
bool aIsFullFrame /* = false */)
{
// Assert for properties that should be verified by decoders,
// warn for properties related to bad content.
@ -258,8 +260,10 @@ imgFrame::InitForDecoder(const nsIntSize& aImageSize,
mTimeout = aAnimParams->mTimeout;
mBlendMethod = aAnimParams->mBlendMethod;
mDisposalMethod = aAnimParams->mDisposalMethod;
mIsFullFrame = aAnimParams->mFrameNum == 0 || aIsFullFrame;
} else {
mBlendRect = aRect;
mIsFullFrame = true;
}
// We only allow a non-trivial frame rect (i.e., a frame rect that doesn't

View File

@ -59,7 +59,8 @@ public:
SurfaceFormat aFormat,
uint8_t aPaletteDepth = 0,
bool aNonPremult = false,
const Maybe<AnimationParams>& aAnimParams = Nothing());
const Maybe<AnimationParams>& aAnimParams = Nothing(),
bool aIsFullFrame = false);
nsresult InitForAnimator(const nsIntSize& aSize,
SurfaceFormat aFormat)
@ -68,8 +69,12 @@ public:
AnimationParams animParams { frameRect, FrameTimeout::Forever(),
/* aFrameNum */ 1, BlendMethod::OVER,
DisposalMethod::NOT_SPECIFIED };
return InitForDecoder(aSize, frameRect,
aFormat, 0, false, Some(animParams));
// We set aIsFullFrame to false because we don't want the compositing frame
// to be allocated into shared memory for WebRender. mIsFullFrame is only
// otherwise used for frames produced by Decoder, so it isn't relevant.
return InitForDecoder(aSize, frameRect, aFormat, /* aPaletteDepth */ 0,
/* aNonPremult */ false, Some(animParams),
/* aIsFullFrame */ false);
}
@ -191,6 +196,8 @@ public:
const IntRect& GetDirtyRect() const { return mDirtyRect; }
void SetDirtyRect(const IntRect& aDirtyRect) { mDirtyRect = aDirtyRect; }
bool IsFullFrame() const { return mIsFullFrame; }
bool GetCompositingFailed() const;
void SetCompositingFailed(bool val);
@ -340,6 +347,9 @@ private: // data
bool mNonPremult;
//! True if the frame has all of the data stored in it, false if it needs to
//! be combined with another frame (e.g. the previous frame) to be complete.
bool mIsFullFrame;
//////////////////////////////////////////////////////////////////////////////
// Main-thread-only mutable data.

View File

@ -4608,6 +4608,10 @@ pref("image.animated.decode-on-demand.threshold-kb", 20480);
// animation's currently displayed frame.
pref("image.animated.decode-on-demand.batch-size", 6);
// Whether we should generate full frames at decode time or partial frames which
// are combined at display time (historical behavior and default).
pref("image.animated.generate-full-frames", false);
// Resume an animated image from the last displayed frame rather than
// advancing when out of view.
pref("image.animated.resume-from-last-displayed", true);