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; }
void RasterImage::NotifyDecodeComplete(const DecoderFinalStatus& aStatus, const ImageMetadata& aMetadata, const DecoderTelemetry& aTelemetry, Progress aProgress, const IntRect& aInvalidRect, const Maybe<uint32_t>& aFrameCount, DecoderFlags aDecoderFlags, SurfaceFlags aSurfaceFlags) { MOZ_ASSERT(NS_IsMainThread()); // If the decoder detected an error, log it to the error console. if (aStatus.mShouldReportError && !aStatus.mWasAborted) { ReportDecoderError(); } // Record all the metadata the decoder gathered about this image. bool metadataOK = SetMetadata(aMetadata, aStatus.mWasMetadataDecode); if (!metadataOK) { // This indicates a serious error that requires us to discard all existing // surfaces and redecode to recover. We'll drop the results from this // decoder on the floor, since they aren't valid. RecoverFromInvalidFrames(mSize, FromSurfaceFlags(aSurfaceFlags)); return; } MOZ_ASSERT(mError || mHasSize || !aMetadata.HasSize(), "SetMetadata should've gotten a size"); if (!aStatus.mWasMetadataDecode && aStatus.mFinished && !aStatus.mWasAborted) { // Flag that we've been decoded before. mHasBeenDecoded = true; } // Send out any final notifications. NotifyProgress(aProgress, aInvalidRect, aFrameCount, aDecoderFlags, aSurfaceFlags); if (!(aDecoderFlags & DecoderFlags::FIRST_FRAME_ONLY) && mHasBeenDecoded && mAnimationState) { // We've finished a full decode of all animation frames and our AnimationState // has been notified about them all, so let it know not to expect anymore. mAnimationState->SetDoneDecoding(true); } if (!aStatus.mWasMetadataDecode && aTelemetry.mChunkCount) { Telemetry::Accumulate(Telemetry::IMAGE_DECODE_CHUNKS, aTelemetry.mChunkCount); } if (aStatus.mFinished) { // Do some telemetry if this isn't a metadata decode. if (!aStatus.mWasMetadataDecode) { Telemetry::Accumulate(Telemetry::IMAGE_DECODE_TIME, int32_t(aTelemetry.mDecodeTime.ToMicroseconds())); if (aTelemetry.mSpeedHistogram) { Telemetry::Accumulate(*aTelemetry.mSpeedHistogram, aTelemetry.Speed()); } } // Detect errors. if (aStatus.mHadError && !aStatus.mWasAborted) { DoError(); } else if (aStatus.mWasMetadataDecode && !mHasSize) { DoError(); } // If we were waiting to fire the load event, go ahead and fire it now. if (mLoadProgress && aStatus.mWasMetadataDecode) { NotifyForLoadEvent(*mLoadProgress); mLoadProgress = Nothing(); NotifyProgress(FLAG_ONLOAD_UNBLOCKED); } } // If we were a metadata decode and a full decode was requested, do it. if (aStatus.mFinished && aStatus.mWasMetadataDecode && mWantFullDecode) { mWantFullDecode = false; RequestDecodeForSize(mSize, DECODE_FLAGS_DEFAULT); } }