IntSize RasterImage::OptimalImageSizeForDest(const gfxSize& aDest, uint32_t aWhichFrame, SamplingFilter aSamplingFilter, uint32_t aFlags) { MOZ_ASSERT(aDest.width >= 0 || ceil(aDest.width) <= INT32_MAX || aDest.height >= 0 || ceil(aDest.height) <= INT32_MAX, "Unexpected destination size"); if (mSize.IsEmpty() || aDest.IsEmpty()) { return IntSize(0, 0); } IntSize destSize = IntSize::Ceil(aDest.width, aDest.height); if (aSamplingFilter == SamplingFilter::GOOD && CanDownscaleDuringDecode(destSize, aFlags)) { return destSize; } // We can't scale to this size. Use our intrinsic size for now. return mSize; }
DrawResult RasterImage::DrawInternal(DrawableSurface&& aSurface, gfxContext* aContext, const IntSize& aSize, const ImageRegion& aRegion, SamplingFilter aSamplingFilter, uint32_t aFlags, float aOpacity) { gfxContextMatrixAutoSaveRestore saveMatrix(aContext); ImageRegion region(aRegion); bool frameIsFinished = aSurface->IsFinished(); // By now we may have a frame with the requested size. If not, we need to // adjust the drawing parameters accordingly. IntSize finalSize = aSurface->GetImageSize(); bool couldRedecodeForBetterFrame = false; if (finalSize != aSize) { gfx::Size scale(double(aSize.width) / finalSize.width, double(aSize.height) / finalSize.height); aContext->Multiply(gfxMatrix::Scaling(scale.width, scale.height)); region.Scale(1.0 / scale.width, 1.0 / scale.height); couldRedecodeForBetterFrame = CanDownscaleDuringDecode(aSize, aFlags); } if (!aSurface->Draw(aContext, region, aSamplingFilter, aFlags, aOpacity)) { RecoverFromInvalidFrames(aSize, aFlags); return DrawResult::TEMPORARY_ERROR; } if (!frameIsFinished) { return DrawResult::INCOMPLETE; } if (couldRedecodeForBetterFrame) { return DrawResult::WRONG_SIZE; } return DrawResult::SUCCESS; }
DrawableSurface RasterImage::LookupFrame(const IntSize& aSize, uint32_t aFlags, PlaybackType aPlaybackType) { MOZ_ASSERT(NS_IsMainThread()); // If we're opaque, we don't need to care about premultiplied alpha, because // that can only matter for frames with transparency. if (IsOpaque()) { aFlags &= ~FLAG_DECODE_NO_PREMULTIPLY_ALPHA; } IntSize requestedSize = CanDownscaleDuringDecode(aSize, aFlags) ? aSize : mSize; if (requestedSize.IsEmpty()) { return DrawableSurface(); // Can't decode to a surface of zero size. } LookupResult result = LookupFrameInternal(requestedSize, aFlags, aPlaybackType); if (!result && !mHasSize) { // We can't request a decode without knowing our intrinsic size. Give up. return DrawableSurface(); } if (result.Type() == MatchType::NOT_FOUND || result.Type() == MatchType::SUBSTITUTE_BECAUSE_NOT_FOUND || ((aFlags & FLAG_SYNC_DECODE) && !result)) { // We don't have a copy of this frame, and there's no decoder working on // one. (Or we're sync decoding and the existing decoder hasn't even started // yet.) Trigger decoding so it'll be available next time. MOZ_ASSERT(aPlaybackType != PlaybackType::eAnimated || !mAnimationState || mAnimationState->KnownFrameCount() < 1, "Animated frames should be locked"); Decode(requestedSize, aFlags, aPlaybackType); // If we can sync decode, we should already have the frame. if (aFlags & FLAG_SYNC_DECODE) { result = LookupFrameInternal(requestedSize, aFlags, aPlaybackType); } } if (!result) { // We still weren't able to get a frame. Give up. return DrawableSurface(); } if (result.Surface()->GetCompositingFailed()) { return DrawableSurface(); } MOZ_ASSERT(!result.Surface()->GetIsPaletted(), "Should not have a paletted frame"); // Sync decoding guarantees that we got the frame, but if it's owned by an // async decoder that's currently running, the contents of the frame may not // be available yet. Make sure we get everything. if (mHasSourceData && (aFlags & FLAG_SYNC_DECODE)) { result.Surface()->WaitUntilFinished(); } // If we could have done some decoding in this function we need to check if // that decoding encountered an error and hence aborted the surface. We want // to avoid calling IsAborted if we weren't passed any sync decode flag because // IsAborted acquires the monitor for the imgFrame. if (aFlags & (FLAG_SYNC_DECODE | FLAG_SYNC_DECODE_IF_FAST) && result.Surface()->IsAborted()) { return DrawableSurface(); } return Move(result.Surface()); }