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
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;
}
Esempio n. 3
0
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;
}
Esempio n. 4
0
RawAccessFrameRef
FrameAnimator::GetRawFrame(uint32_t aFrameNum) const
{
  LookupResult result =
    SurfaceCache::Lookup(ImageKey(mImage),
                         RasterSurfaceKey(mSize,
                                          DefaultSurfaceFlags(),
                                          aFrameNum));
  return result ? result.DrawableRef()->RawAccessRef()
                : RawAccessFrameRef();
}
Esempio n. 5
0
/* static */ already_AddRefed<IDecodingTask>
DecoderFactory::CreateDecoder(DecoderType aType,
                              NotNull<RasterImage*> aImage,
                              NotNull<SourceBuffer*> aSourceBuffer,
                              const IntSize& aIntrinsicSize,
                              const IntSize& aOutputSize,
                              DecoderFlags aDecoderFlags,
                              SurfaceFlags aSurfaceFlags)
{
  if (aType == DecoderType::UNKNOWN) {
    return nullptr;
  }

  // Create an anonymous decoder. Interaction with the SurfaceCache and the
  // owning RasterImage will be mediated by DecodedSurfaceProvider.
  RefPtr<Decoder> decoder =
    GetDecoder(aType, nullptr, bool(aDecoderFlags & DecoderFlags::IS_REDECODE));
  MOZ_ASSERT(decoder, "Should have a decoder now");

  // Initialize the decoder.
  decoder->SetMetadataDecode(false);
  decoder->SetIterator(aSourceBuffer->Iterator());
  decoder->SetOutputSize(aOutputSize);
  decoder->SetDecoderFlags(aDecoderFlags | DecoderFlags::FIRST_FRAME_ONLY);
  decoder->SetSurfaceFlags(aSurfaceFlags);

  if (NS_FAILED(decoder->Init())) {
    return nullptr;
  }

  // Create a DecodedSurfaceProvider which will manage the decoding process and
  // make this decoder's output available in the surface cache.
  SurfaceKey surfaceKey =
    RasterSurfaceKey(aOutputSize, aSurfaceFlags, PlaybackType::eStatic);
  auto provider = MakeNotNull<RefPtr<DecodedSurfaceProvider>>(
    aImage, surfaceKey, WrapNotNull(decoder));
  if (aDecoderFlags & DecoderFlags::CANNOT_SUBSTITUTE) {
    provider->Availability().SetCannotSubstitute();
  }

  // Attempt to insert the surface provider into the surface cache right away so
  // we won't trigger any more decoders with the same parameters.
  if (SurfaceCache::Insert(provider) != InsertOutcome::SUCCESS) {
    return nullptr;
  }

  // Return the surface provider in its IDecodingTask guise.
  RefPtr<IDecodingTask> task = provider.get();
  return task.forget();
}
Esempio n. 6
0
/* static */ already_AddRefed<IDecodingTask>
DecoderFactory::CreateAnimationDecoder(DecoderType aType,
                                       NotNull<RasterImage*> aImage,
                                       NotNull<SourceBuffer*> aSourceBuffer,
                                       const IntSize& aIntrinsicSize,
                                       DecoderFlags aDecoderFlags,
                                       SurfaceFlags aSurfaceFlags)
{
  if (aType == DecoderType::UNKNOWN) {
    return nullptr;
  }

  MOZ_ASSERT(aType == DecoderType::GIF || aType == DecoderType::PNG,
             "Calling CreateAnimationDecoder for non-animating DecoderType");

  // Create an anonymous decoder. Interaction with the SurfaceCache and the
  // owning RasterImage will be mediated by AnimationSurfaceProvider.
  RefPtr<Decoder> decoder = GetDecoder(aType, nullptr, /* aIsRedecode = */ true);
  MOZ_ASSERT(decoder, "Should have a decoder now");

  // Initialize the decoder.
  decoder->SetMetadataDecode(false);
  decoder->SetIterator(aSourceBuffer->Iterator());
  decoder->SetDecoderFlags(aDecoderFlags | DecoderFlags::IS_REDECODE);
  decoder->SetSurfaceFlags(aSurfaceFlags);

  if (NS_FAILED(decoder->Init())) {
    return nullptr;
  }

  // Create an AnimationSurfaceProvider which will manage the decoding process
  // and make this decoder's output available in the surface cache.
  SurfaceKey surfaceKey =
    RasterSurfaceKey(aIntrinsicSize, aSurfaceFlags, PlaybackType::eAnimated);
  auto provider = MakeNotNull<RefPtr<AnimationSurfaceProvider>>(
    aImage, surfaceKey, WrapNotNull(decoder));

  // Attempt to insert the surface provider into the surface cache right away so
  // we won't trigger any more decoders with the same parameters.
  if (SurfaceCache::Insert(provider) != InsertOutcome::SUCCESS) {
    return nullptr;
  }

  // Return the surface provider in its IDecodingTask guise.
  RefPtr<IDecodingTask> task = provider.get();
  return task.forget();
}
Esempio n. 7
0
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();
}
Esempio n. 8
0
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;
}
Esempio n. 9
0
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);
}
Esempio n. 10
0
RawAccessFrameRef
Decoder::AllocateFrameInternal(uint32_t aFrameNum,
                               const nsIntSize& aTargetSize,
                               const nsIntRect& aFrameRect,
                               SurfaceFormat aFormat,
                               uint8_t aPaletteDepth,
                               imgFrame* aPreviousFrame)
{
  if (mDataError || NS_FAILED(mFailCode)) {
    return RawAccessFrameRef();
  }

  if (aFrameNum != mFrameCount) {
    MOZ_ASSERT_UNREACHABLE("Allocating frames out of order");
    return RawAccessFrameRef();
  }

  if (aTargetSize.width <= 0 || aTargetSize.height <= 0 ||
      aFrameRect.width <= 0 || aFrameRect.height <= 0) {
    NS_WARNING("Trying to add frame with zero or negative size");
    return RawAccessFrameRef();
  }

  const uint32_t bytesPerPixel = aPaletteDepth == 0 ? 4 : 1;
  if (ShouldUseSurfaceCache() &&
      !SurfaceCache::CanHold(aFrameRect.Size(), bytesPerPixel)) {
    NS_WARNING("Trying to add frame that's too large for the SurfaceCache");
    return RawAccessFrameRef();
  }

  RefPtr<imgFrame> frame = new imgFrame();
  bool nonPremult = bool(mSurfaceFlags & SurfaceFlags::NO_PREMULTIPLY_ALPHA);
  if (NS_FAILED(frame->InitForDecoder(aTargetSize, aFrameRect, aFormat,
                                      aPaletteDepth, nonPremult))) {
    NS_WARNING("imgFrame::Init should succeed");
    return RawAccessFrameRef();
  }

  RawAccessFrameRef ref = frame->RawAccessRef();
  if (!ref) {
    frame->Abort();
    return RawAccessFrameRef();
  }

  if (ShouldUseSurfaceCache()) {
    InsertOutcome outcome =
      SurfaceCache::Insert(frame, ImageKey(mImage.get()),
                           RasterSurfaceKey(aTargetSize,
                                            mSurfaceFlags,
                                            aFrameNum));
    if (outcome == InsertOutcome::FAILURE) {
      // We couldn't insert the surface, almost certainly due to low memory. We
      // treat this as a permanent error to help the system recover; otherwise,
      // we might just end up attempting to decode this image again immediately.
      ref->Abort();
      return RawAccessFrameRef();
    } else if (outcome == InsertOutcome::FAILURE_ALREADY_PRESENT) {
      // Another decoder beat us to decoding this frame. We abort this decoder
      // rather than treat this as a real error.
      mDecodeAborted = true;
      ref->Abort();
      return RawAccessFrameRef();
    }
  }

  nsIntRect refreshArea;

  if (aFrameNum == 1) {
    MOZ_ASSERT(aPreviousFrame, "Must provide a previous frame when animated");
    aPreviousFrame->SetRawAccessOnly();

    // If we dispose of the first frame by clearing it, then the first frame's
    // refresh area is all of itself.
    // RESTORE_PREVIOUS is invalid (assumed to be DISPOSE_CLEAR).
    AnimationData previousFrameData = aPreviousFrame->GetAnimationData();
    if (previousFrameData.mDisposalMethod == DisposalMethod::CLEAR ||
        previousFrameData.mDisposalMethod == DisposalMethod::CLEAR_ALL ||
        previousFrameData.mDisposalMethod == DisposalMethod::RESTORE_PREVIOUS) {
      refreshArea = previousFrameData.mRect;
    }
  }

  if (aFrameNum > 0) {
    ref->SetRawAccessOnly();

    // Some GIFs are huge but only have a small area that they animate. We only
    // need to refresh that small area when frame 0 comes around again.
    refreshArea.UnionRect(refreshArea, frame->GetRect());
  }

  mFrameCount++;

  if (mImage) {
    mImage->OnAddedFrame(mFrameCount, refreshArea);
  }

  return ref;
}