Beispiel #1
0
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);
  }
}