# HG changeset patch # User Andrew Osmond # Date 1519842892 18000 # Node ID 88ff3387dd497fb1e9925584399cf4501de4902c # Parent 684a61efff840d915e34fd881f1133681fb84652 Bug 523950 - Part 5. Pass the currently displayed frame of an animation to its decoder. r=tnikkel When we need to recreate an animated image decoder because it was discarded, the animation may have progressed beyond the first frame. Given that later in the patch series we need FrameAnimator to be driving the decoding more actively, it simplifies its role by making it assume the initial state of the decoder matches its initial state. Passing in the currently displayed frame allows the decoder to advance its frame buffer (and potentially discard unnecessary frames), such that when the animation actually wants to advance as it normally would, the decoder state matches what it would have been if it had never been discarded. diff --git a/image/AnimationSurfaceProvider.cpp b/image/AnimationSurfaceProvider.cpp --- a/image/AnimationSurfaceProvider.cpp +++ b/image/AnimationSurfaceProvider.cpp @@ -12,17 +12,18 @@ using namespace mozilla::gfx; namespace mozilla { namespace image { AnimationSurfaceProvider::AnimationSurfaceProvider(NotNull aImage, const SurfaceKey& aSurfaceKey, - NotNull aDecoder) + NotNull aDecoder, + size_t aCurrentFrame) : ISurfaceProvider(ImageKey(aImage.get()), aSurfaceKey, AvailabilityState::StartAsPlaceholder()) , mImage(aImage.get()) , mDecodingMutex("AnimationSurfaceProvider::mDecoder") , mDecoder(aDecoder.get()) , mFramesMutex("AnimationSurfaceProvider::mFrames") { MOZ_ASSERT(!mDecoder->IsMetadataDecode(), diff --git a/image/AnimationSurfaceProvider.h b/image/AnimationSurfaceProvider.h --- a/image/AnimationSurfaceProvider.h +++ b/image/AnimationSurfaceProvider.h @@ -26,17 +26,18 @@ class AnimationSurfaceProvider final : public ISurfaceProvider , public IDecodingTask { public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AnimationSurfaceProvider, override) AnimationSurfaceProvider(NotNull aImage, const SurfaceKey& aSurfaceKey, - NotNull aDecoder); + NotNull aDecoder, + size_t aCurrentFrame); ////////////////////////////////////////////////////////////////////////////// // ISurfaceProvider implementation. ////////////////////////////////////////////////////////////////////////////// public: // We use the ISurfaceProvider constructor of DrawableSurface to indicate that diff --git a/image/DecoderFactory.cpp b/image/DecoderFactory.cpp --- a/image/DecoderFactory.cpp +++ b/image/DecoderFactory.cpp @@ -179,16 +179,17 @@ DecoderFactory::CreateDecoder(DecoderTyp /* static */ nsresult DecoderFactory::CreateAnimationDecoder(DecoderType aType, NotNull aImage, NotNull aSourceBuffer, const IntSize& aIntrinsicSize, DecoderFlags aDecoderFlags, SurfaceFlags aSurfaceFlags, + size_t aCurrentFrame, IDecodingTask** aOutTask) { if (aType == DecoderType::UNKNOWN) { return NS_ERROR_INVALID_ARG; } MOZ_ASSERT(aType == DecoderType::GIF || aType == DecoderType::PNG || aType == DecoderType::WEBP, @@ -210,17 +211,17 @@ DecoderFactory::CreateAnimationDecoder(D return NS_ERROR_FAILURE; } // Create an AnimationSurfaceProvider which will manage the decoding process // and make this decoder's output available in the surface cache. SurfaceKey surfaceKey = RasterSurfaceKey(aIntrinsicSize, aSurfaceFlags, PlaybackType::eAnimated); auto provider = MakeNotNull>( - aImage, surfaceKey, WrapNotNull(decoder)); + aImage, surfaceKey, WrapNotNull(decoder), aCurrentFrame); // Attempt to insert the surface provider into the surface cache right away so // we won't trigger any more decoders with the same parameters. switch (SurfaceCache::Insert(provider)) { case InsertOutcome::SUCCESS: break; case InsertOutcome::FAILURE_ALREADY_PRESENT: return NS_ERROR_ALREADY_INITIALIZED; diff --git a/image/RasterImage.cpp b/image/RasterImage.cpp --- a/image/RasterImage.cpp +++ b/image/RasterImage.cpp @@ -1244,19 +1244,21 @@ RasterImage::Decode(const IntSize& aSize surfaceFlags &= ~SurfaceFlags::NO_PREMULTIPLY_ALPHA; } // Create a decoder. RefPtr task; nsresult rv; bool animated = mAnimationState && aPlaybackType == PlaybackType::eAnimated; if (animated) { + size_t currentFrame = mAnimationState->GetCurrentAnimationFrameIndex(); rv = DecoderFactory::CreateAnimationDecoder(mDecoderType, WrapNotNull(this), mSourceBuffer, mSize, decoderFlags, surfaceFlags, + currentFrame, getter_AddRefs(task)); } else { rv = DecoderFactory::CreateDecoder(mDecoderType, WrapNotNull(this), mSourceBuffer, mSize, aSize, decoderFlags, surfaceFlags, getter_AddRefs(task)); }