Esempio n. 1
0
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));
}
Esempio n. 2
0
/* static */ already_AddRefed<gfx::SourceSurface>
ImageOps::DecodeToSurface(nsIInputStream* aInputStream,
                          const nsACString& aMimeType,
                          uint32_t aFlags)
{
  MOZ_ASSERT(aInputStream);

  nsresult rv;

  // Prepare the input stream.
  nsCOMPtr<nsIInputStream> inputStream = aInputStream;
  if (!NS_InputStreamIsBuffered(aInputStream)) {
    nsCOMPtr<nsIInputStream> bufStream;
    rv = NS_NewBufferedInputStream(getter_AddRefs(bufStream),
                                   aInputStream, 1024);
    if (NS_SUCCEEDED(rv)) {
      inputStream = bufStream;
    }
  }

  // Figure out how much data we've been passed.
  uint64_t length;
  rv = inputStream->Available(&length);
  if (NS_FAILED(rv) || length > UINT32_MAX) {
    return nullptr;
  }

  // Write the data into a SourceBuffer.
  RefPtr<SourceBuffer> sourceBuffer = new SourceBuffer();
  sourceBuffer->ExpectLength(length);
  rv = sourceBuffer->AppendFromInputStream(inputStream, length);
  if (NS_FAILED(rv)) {
    return nullptr;
  }
  sourceBuffer->Complete(NS_OK);

  // Create a decoder.
  DecoderType decoderType =
    DecoderFactory::GetDecoderType(PromiseFlatCString(aMimeType).get());
  RefPtr<Decoder> decoder =
    DecoderFactory::CreateAnonymousDecoder(decoderType,
                                           sourceBuffer,
                                           ToSurfaceFlags(aFlags));
  if (!decoder) {
    return nullptr;
  }

  // Run the decoder synchronously.
  decoder->Decode();
  if (!decoder->GetDecodeDone() || decoder->HasError()) {
    return nullptr;
  }

  // Pull out the surface.
  RawAccessFrameRef frame = decoder->GetCurrentFrameRef();
  if (!frame) {
    return nullptr;
  }

  RefPtr<SourceSurface> surface = frame->GetSurface();
  if (!surface) {
    return nullptr;
  }

  return surface.forget();
}
Esempio n. 3
0
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;
}
Esempio n. 4
0
NS_IMETHODIMP
RasterImage::Decode(const IntSize& aSize,
                    uint32_t aFlags,
                    PlaybackType aPlaybackType)
{
  MOZ_ASSERT(NS_IsMainThread());

  if (mError) {
    return NS_ERROR_FAILURE;
  }

  // If we don't have a size yet, we can't do any other decoding.
  if (!mHasSize) {
    mWantFullDecode = true;
    return NS_OK;
  }

  // We're about to decode again, which may mean that some of the previous sizes
  // we've decoded at aren't useful anymore. We can allow them to expire from
  // the cache by unlocking them here. When the decode finishes, it will send an
  // invalidation that will cause all instances of this image to redraw. If this
  // image is locked, any surfaces that are still useful will become locked
  // again when LookupFrame touches them, and the remainder will eventually
  // expire.
  SurfaceCache::UnlockEntries(ImageKey(this));

  // Determine which flags we need to decode this image with.
  DecoderFlags decoderFlags = DefaultDecoderFlags();
  if (aFlags & FLAG_ASYNC_NOTIFY) {
    decoderFlags |= DecoderFlags::ASYNC_NOTIFY;
  }
  if (mTransient) {
    decoderFlags |= DecoderFlags::IMAGE_IS_TRANSIENT;
  }
  if (mHasBeenDecoded) {
    decoderFlags |= DecoderFlags::IS_REDECODE;
  }

  SurfaceFlags surfaceFlags = ToSurfaceFlags(aFlags);
  if (IsOpaque()) {
    // If there's no transparency, it doesn't matter whether we premultiply
    // alpha or not.
    surfaceFlags &= ~SurfaceFlags::NO_PREMULTIPLY_ALPHA;
  }

  // Create a decoder.
  RefPtr<IDecodingTask> task;
  if (mAnimationState && aPlaybackType == PlaybackType::eAnimated) {
    task = DecoderFactory::CreateAnimationDecoder(mDecoderType, WrapNotNull(this),
                                                  mSourceBuffer, mSize,
                                                  decoderFlags, surfaceFlags);
  } else {
    task = DecoderFactory::CreateDecoder(mDecoderType, WrapNotNull(this),
                                         mSourceBuffer, mSize, aSize,
                                         decoderFlags, surfaceFlags,
                                         mRequestedSampleSize);
  }

  // Make sure DecoderFactory was able to create a decoder successfully.
  if (!task) {
    return NS_ERROR_FAILURE;
  }

  mDecodeCount++;

  // We're ready to decode; start the decoder.
  LaunchDecodingTask(task, this, aFlags, mHasSourceData);
  return NS_OK;
}