LookupResult FrameAnimator::GetCompositedFrame(AnimationState& aState) { // If we have a composited version of this frame, return that. if (mLastCompositedFrameIndex >= 0 && (uint32_t(mLastCompositedFrameIndex) == aState.mCurrentAnimationFrameIndex)) { return LookupResult(DrawableSurface(mCompositingFrame->DrawableRef()), MatchType::EXACT); } // Otherwise return the raw frame. DoBlend is required to ensure that we only // hit this case if the frame is not paletted and doesn't require compositing. LookupResult result = SurfaceCache::Lookup(ImageKey(mImage), RasterSurfaceKey(mSize, DefaultSurfaceFlags(), PlaybackType::eAnimated)); if (!result) { return result; } // Seek to the appropriate frame. If seeking fails, it means that we couldn't // get the frame we're looking for; treat this as if the lookup failed. if (NS_FAILED(result.Surface().Seek(aState.mCurrentAnimationFrameIndex))) { return LookupResult(MatchType::NOT_FOUND); } MOZ_ASSERT(!result.Surface()->GetIsPaletted(), "About to return a paletted frame"); return result; }
LookupResult RasterImage::LookupFrameInternal(const IntSize& aSize, uint32_t aFlags, PlaybackType aPlaybackType) { if (mAnimationState && aPlaybackType == PlaybackType::eAnimated) { MOZ_ASSERT(mFrameAnimator); MOZ_ASSERT(ToSurfaceFlags(aFlags) == DefaultSurfaceFlags(), "Can't composite frames with non-default surface flags"); const size_t index = mAnimationState->GetCurrentAnimationFrameIndex(); return mFrameAnimator->GetCompositedFrame(index); } SurfaceFlags surfaceFlags = ToSurfaceFlags(aFlags); // We don't want any substitution for sync decodes, and substitution would be // illegal when high quality downscaling is disabled, so we use // SurfaceCache::Lookup in this case. if ((aFlags & FLAG_SYNC_DECODE) || !(aFlags & FLAG_HIGH_QUALITY_SCALING)) { return SurfaceCache::Lookup(ImageKey(this), RasterSurfaceKey(aSize, surfaceFlags, PlaybackType::eStatic)); } // We'll return the best match we can find to the requested frame. return SurfaceCache::LookupBestMatch(ImageKey(this), RasterSurfaceKey(aSize, surfaceFlags, PlaybackType::eStatic)); }
RasterImage::WillDrawOpaqueNow() { if (!IsOpaque()) { return false; } if (mAnimationState) { // We never discard frames of animated images. return true; } // If we are not locked our decoded data could get discard at any time (ie // between the call to this function and when we are asked to draw), so we // have to return false if we are unlocked. if (IsUnlocked()) { return false; } LookupResult result = SurfaceCache::LookupBestMatch(ImageKey(this), RasterSurfaceKey(mSize, DefaultSurfaceFlags(), PlaybackType::eStatic)); MatchType matchType = result.Type(); if (matchType == MatchType::NOT_FOUND || matchType == MatchType::PENDING || !result.Surface()->IsFinished()) { return false; } return true; }
RawAccessFrameRef FrameAnimator::GetRawFrame(uint32_t aFrameNum) const { LookupResult result = SurfaceCache::Lookup(ImageKey(mImage), RasterSurfaceKey(mSize, DefaultSurfaceFlags(), aFrameNum)); return result ? result.DrawableRef()->RawAccessRef() : RawAccessFrameRef(); }
RawAccessFrameRef FrameAnimator::GetRawFrame(uint32_t aFrameNum) const { LookupResult result = SurfaceCache::Lookup(ImageKey(mImage), RasterSurfaceKey(mSize, DefaultSurfaceFlags(), PlaybackType::eAnimated)); if (!result) { return RawAccessFrameRef(); } // Seek to the frame we want. If seeking fails, it means we couldn't get the // frame we're looking for, so we bail here to avoid returning the wrong frame // to the caller. if (NS_FAILED(result.Surface().Seek(aFrameNum))) { return RawAccessFrameRef(); // Not available yet. } return result.Surface()->RawAccessRef(); }
LookupResult FrameAnimator::GetCompositedFrame(uint32_t aFrameNum) { MOZ_ASSERT(aFrameNum != 0, "First frame is never composited"); // If we have a composited version of this frame, return that. if (mLastCompositedFrameIndex == int32_t(aFrameNum)) { return LookupResult(mCompositingFrame->DrawableRef(), MatchType::EXACT); } // Otherwise return the raw frame. DoBlend is required to ensure that we only // hit this case if the frame is not paletted and doesn't require compositing. LookupResult result = SurfaceCache::Lookup(ImageKey(mImage), RasterSurfaceKey(mSize, DefaultSurfaceFlags(), aFrameNum)); MOZ_ASSERT(!result || !result.DrawableRef()->GetIsPaletted(), "About to return a paletted frame"); return result; }
Decoder::Decoder(RasterImage* aImage) : mImageData(nullptr) , mImageDataLength(0) , mColormap(nullptr) , mColormapSize(0) , mImage(aImage) , mProgress(NoProgress) , mFrameCount(0) , mFailCode(NS_OK) , mChunkCount(0) , mDecoderFlags(DefaultDecoderFlags()) , mSurfaceFlags(DefaultSurfaceFlags()) , mBytesDecoded(0) , mInitialized(false) , mMetadataDecode(false) , mInFrame(false) , mDataDone(false) , mDecodeDone(false) , mDataError(false) , mDecodeAborted(false) , mShouldReportError(false) { }
void RasterImage::NotifyProgress(Progress aProgress, const IntRect& aInvalidRect /* = IntRect() */, const Maybe<uint32_t>& aFrameCount /* = Nothing() */, DecoderFlags aDecoderFlags /* = DefaultDecoderFlags() */, SurfaceFlags aSurfaceFlags /* = DefaultSurfaceFlags() */) { MOZ_ASSERT(NS_IsMainThread()); // Ensure that we stay alive long enough to finish notifying. RefPtr<RasterImage> image = this; const bool wasDefaultFlags = aSurfaceFlags == DefaultSurfaceFlags(); if (!aInvalidRect.IsEmpty() && wasDefaultFlags) { // Update our image container since we're invalidating. UpdateImageContainer(); } if (!(aDecoderFlags & DecoderFlags::FIRST_FRAME_ONLY)) { // We may have decoded new animation frames; update our animation state. MOZ_ASSERT_IF(aFrameCount && *aFrameCount > 1, mAnimationState || mError); if (mAnimationState && aFrameCount) { mAnimationState->UpdateKnownFrameCount(*aFrameCount); } // If we should start animating right now, do so. if (mAnimationState && aFrameCount == Some(1u) && mPendingAnimation && ShouldAnimate()) { StartAnimation(); } } // Tell the observers what happened. image->mProgressTracker->SyncNotifyProgress(aProgress, aInvalidRect); }
static void DoCollectSizeOfCompositingSurfaces(const RawAccessFrameRef& aSurface, SurfaceMemoryCounterType aType, nsTArray<SurfaceMemoryCounter>& aCounters, MallocSizeOf aMallocSizeOf) { // Concoct a SurfaceKey for this surface. SurfaceKey key = RasterSurfaceKey(aSurface->GetImageSize(), DefaultSurfaceFlags(), PlaybackType::eStatic); // Create a counter for this surface. SurfaceMemoryCounter counter(key, /* aIsLocked = */ true, aType); // Extract the surface's memory usage information. size_t heap = 0, nonHeap = 0; aSurface->AddSizeOfExcludingThis(aMallocSizeOf, heap, nonHeap); counter.Values().SetDecodedHeap(heap); counter.Values().SetDecodedNonHeap(nonHeap); // Record it. aCounters.AppendElement(counter); }
RasterImage::Draw(gfxContext* aContext, const IntSize& aSize, const ImageRegion& aRegion, uint32_t aWhichFrame, SamplingFilter aSamplingFilter, const Maybe<SVGImageContext>& /*aSVGContext - ignored*/, uint32_t aFlags) { if (aWhichFrame > FRAME_MAX_VALUE) { return DrawResult::BAD_ARGS; } if (mError) { return DrawResult::BAD_IMAGE; } // Illegal -- you can't draw with non-default decode flags. // (Disabling colorspace conversion might make sense to allow, but // we don't currently.) if (ToSurfaceFlags(aFlags) != DefaultSurfaceFlags()) { return DrawResult::BAD_ARGS; } if (!aContext) { return DrawResult::BAD_ARGS; } if (IsUnlocked() && mProgressTracker) { mProgressTracker->OnUnlockedDraw(); } // If we're not using SamplingFilter::GOOD, we shouldn't high-quality scale or // downscale during decode. uint32_t flags = aSamplingFilter == SamplingFilter::GOOD ? aFlags : aFlags & ~FLAG_HIGH_QUALITY_SCALING; DrawableSurface surface = LookupFrame(aSize, flags, ToPlaybackType(aWhichFrame)); if (!surface) { // Getting the frame (above) touches the image and kicks off decoding. if (mDrawStartTime.IsNull()) { mDrawStartTime = TimeStamp::Now(); } return DrawResult::NOT_READY; } bool shouldRecordTelemetry = !mDrawStartTime.IsNull() && surface->IsFinished(); auto result = DrawInternal(Move(surface), aContext, aSize, aRegion, aSamplingFilter, flags); if (shouldRecordTelemetry) { TimeDuration drawLatency = TimeStamp::Now() - mDrawStartTime; Telemetry::Accumulate(Telemetry::IMAGE_DECODE_ON_DRAW_LATENCY, int32_t(drawLatency.ToMicroseconds())); mDrawStartTime = TimeStamp(); } return result; }