Bug 523950 - Part 4. Expose new surface provider APIs that will help drive animation decoding. r=tnikkel

Note that AnimationSurfaceProvider will override these methods to give a
proper implementation in a later patch in this series. For now, they are
mostly stubbed, using the default implementation from ISurfaceProvider.

They focus on the main operations we perform on an animation:

1) Progressing through the animation, e.g. advancing a frame. If we
don't decode the whole animation up front, we need to know at the
decoder level where we are in the display of the animation.

2) Restarting an animation from the beginning. This is a specialized
case of the above, where we want to skip explicitly advancing through
the remaining frames and instead restart at the beginning. The decoder
may have already discarded the earliest frames and must start redecoding
them.

3) Knowing whether or not the decoder is still active, e.g. can we be
missing frames.
This commit is contained in:
Andrew Osmond 2018-02-28 13:34:52 -05:00
Родитель 2088409e88
Коммит 646219b1e7
4 изменённых файлов: 75 добавлений и 9 удалений

Просмотреть файл

@ -71,12 +71,7 @@ AnimationState::UpdateStateInternal(LookupResult& aResult,
if (mHasBeenDecoded) {
Maybe<uint32_t> frameCount = FrameCount();
MOZ_ASSERT(frameCount.isSome());
if (NS_SUCCEEDED(aResult.Surface().Seek(*frameCount - 1)) &&
aResult.Surface()->IsFinished()) {
mIsCurrentlyDecoded = true;
} else {
mIsCurrentlyDecoded = false;
}
mIsCurrentlyDecoded = aResult.Surface().IsFullyDecoded();
}
}
@ -303,8 +298,12 @@ FrameAnimator::AdvanceFrame(AnimationState& aState,
// failure) we would have discarded all the old frames and may not yet have
// the new ones.
if (!nextFrame || !nextFrame->IsFinished()) {
// Uh oh, the frame we want to show is currently being decoded (partial)
// Wait until the next refresh driver tick and try again
// Uh oh, the frame we want to show is currently being decoded (partial).
// Similar to the above case, we could be blocked by network or decoding,
// and so we should advance our current time rather than risk jumping
// through the animation. We will wait until the next refresh driver tick
// and try again.
aState.mCurrentAnimationFrameTime = aTime;
return ret;
}
@ -330,6 +329,7 @@ FrameAnimator::AdvanceFrame(AnimationState& aState,
MOZ_ASSERT(currentFrameEndTime.isSome());
aState.mCurrentAnimationFrameTime = *currentFrameEndTime;
aState.mCurrentAnimationFrameIndex = nextFrameIndex;
aFrames.Advance(nextFrameIndex);
return ret;
}
@ -375,6 +375,7 @@ FrameAnimator::AdvanceFrame(AnimationState& aState,
// Set currentAnimationFrameIndex at the last possible moment
aState.mCurrentAnimationFrameIndex = nextFrameIndex;
aFrames.Advance(nextFrameIndex);
// If we're here, we successfully advanced the frame.
ret.mFrameAdvanced = true;
@ -382,6 +383,25 @@ FrameAnimator::AdvanceFrame(AnimationState& aState,
return ret;
}
void
FrameAnimator::ResetAnimation(AnimationState& aState)
{
aState.ResetAnimation();
// Our surface provider is synchronized to our state, so we need to reset its
// state as well, if we still have one.
LookupResult result =
SurfaceCache::Lookup(ImageKey(mImage),
RasterSurfaceKey(mSize,
DefaultSurfaceFlags(),
PlaybackType::eAnimated));
if (!result) {
return;
}
result.Surface().Reset();
}
RefreshResult
FrameAnimator::RequestRefresh(AnimationState& aState,
const TimeStamp& aTime,

Просмотреть файл

@ -289,6 +289,12 @@ public:
MOZ_COUNT_DTOR(FrameAnimator);
}
/**
* Call when you need to re-start animating. Ensures we start from the first
* frame.
*/
void ResetAnimation(AnimationState& aState);
/**
* Re-evaluate what frame we're supposed to be on, and do whatever blending
* is necessary to get us to that frame.

Просмотреть файл

@ -53,6 +53,12 @@ public:
/// @return true if DrawableRef() will return a completely decoded surface.
virtual bool IsFinished() const = 0;
/// @return true if the underlying decoder is currently fully decoded. For
/// animated images, this means that at least every frame has been decoded
/// at least once. It does not guarantee that all of the frames are present,
/// as the surface provider has the option to discard as it deems necessary.
virtual bool IsFullyDecoded() const { return IsFinished(); }
/// @return the number of bytes of memory this ISurfaceProvider is expected to
/// require. Optimizations may result in lower real memory usage. Trivial
/// overhead is ignored. Because this value is used in bookkeeping, it's
@ -76,6 +82,9 @@ public:
aNonHeapSizeOut, aExtHandlesOut);
}
virtual void Reset() { }
virtual void Advance(size_t aFrame) { }
/// @return the availability state of this ISurfaceProvider, which indicates
/// whether DrawableRef() could successfully return a surface. Should only be
/// called from SurfaceCache code as it relies on SurfaceCache for
@ -190,6 +199,36 @@ public:
return mDrawableRef ? NS_OK : NS_ERROR_FAILURE;
}
void Reset()
{
if (!mProvider) {
MOZ_ASSERT_UNREACHABLE("Trying to reset a static DrawableSurface?");
return;
}
mProvider->Reset();
}
void Advance(size_t aFrame)
{
if (!mProvider) {
MOZ_ASSERT_UNREACHABLE("Trying to advance a static DrawableSurface?");
return;
}
mProvider->Advance(aFrame);
}
bool IsFullyDecoded() const
{
if (!mProvider) {
MOZ_ASSERT_UNREACHABLE("Trying to check decoding state of a static DrawableSurface?");
return false;
}
return mProvider->IsFullyDecoded();
}
explicit operator bool() const { return mHaveSurface; }
imgFrame* operator->() { return DrawableRef().get(); }

Просмотреть файл

@ -869,7 +869,8 @@ RasterImage::ResetAnimation()
}
MOZ_ASSERT(mAnimationState, "Should have AnimationState");
mAnimationState->ResetAnimation();
MOZ_ASSERT(mFrameAnimator, "Should have FrameAnimator");
mFrameAnimator->ResetAnimation(*mAnimationState);
NotifyProgress(NoProgress, mAnimationState->FirstFrameRefreshArea());