Exemplo n.º 1
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;
}
Exemplo n.º 2
0
already_AddRefed<gfxDrawable>
VectorImage::LookupCachedSurface(const SVGDrawingParameters& aParams)
{
  // If we're not allowed to use a cached surface, don't attempt a lookup.
  if (aParams.flags & FLAG_BYPASS_SURFACE_CACHE) {
    return nullptr;
  }

  // We don't do any caching if we have animation, so don't bother with a lookup
  // in this case either.
  if (mHaveAnimations) {
    return nullptr;
  }

  LookupResult result =
    SurfaceCache::Lookup(ImageKey(this),
                         VectorSurfaceKey(aParams.size, aParams.svgContext));
  if (!result) {
    return nullptr;  // No matching surface, or the OS freed the volatile buffer.
  }

  RefPtr<SourceSurface> sourceSurface = result.Surface()->GetSourceSurface();
  if (!sourceSurface) {
    // Something went wrong. (Probably a GPU driver crash or device reset.)
    // Attempt to recover.
    RecoverFromLossOfSurfaces();
    return nullptr;
  }

  RefPtr<gfxDrawable> svgDrawable =
    new gfxSurfaceDrawable(sourceSurface, result.Surface()->GetSize());
  return svgDrawable.forget();
}
Exemplo 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;
}
Exemplo n.º 4
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();
}
Exemplo n.º 5
0
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());
}
Exemplo n.º 6
0
TEST_F(ImageDecoders, AnimatedGIFWithExtraImageSubBlocks)
{
  ImageTestCase testCase = ExtraImageSubBlocksAnimatedGIFTestCase();

  // Verify that we can decode this test case and get two frames, even though
  // there are extra image sub blocks between the first and second frame. The
  // extra data shouldn't confuse the decoder or cause the decode to fail.

  // Create an image.
  RefPtr<Image> image =
    ImageFactory::CreateAnonymousImage(nsDependentCString(testCase.mMimeType));
  ASSERT_TRUE(!image->HasError());

  nsCOMPtr<nsIInputStream> inputStream = LoadFile(testCase.mPath);
  ASSERT_TRUE(inputStream);

  // Figure out how much data we have.
  uint64_t length;
  nsresult rv = inputStream->Available(&length);
  ASSERT_TRUE(NS_SUCCEEDED(rv));

  // Write the data into the image.
  rv = image->OnImageDataAvailable(nullptr, nullptr, inputStream, 0,
                                   static_cast<uint32_t>(length));
  ASSERT_TRUE(NS_SUCCEEDED(rv));

  // Let the image know we've sent all the data.
  rv = image->OnImageDataComplete(nullptr, nullptr, NS_OK, true);
  ASSERT_TRUE(NS_SUCCEEDED(rv));

  RefPtr<ProgressTracker> tracker = image->GetProgressTracker();
  tracker->SyncNotifyProgress(FLAG_LOAD_COMPLETE);

  // Use GetFrame() to force a sync decode of the image.
  RefPtr<SourceSurface> surface =
    image->GetFrame(imgIContainer::FRAME_CURRENT,
                    imgIContainer::FLAG_SYNC_DECODE);

  // Ensure that the image's metadata meets our expectations.
  IntSize imageSize(0, 0);
  rv = image->GetWidth(&imageSize.width);
  EXPECT_TRUE(NS_SUCCEEDED(rv));
  rv = image->GetHeight(&imageSize.height);
  EXPECT_TRUE(NS_SUCCEEDED(rv));

  EXPECT_EQ(testCase.mSize.width, imageSize.width);
  EXPECT_EQ(testCase.mSize.height, imageSize.height);

  Progress imageProgress = tracker->GetProgress();

  EXPECT_TRUE(bool(imageProgress & FLAG_HAS_TRANSPARENCY) == false);
  EXPECT_TRUE(bool(imageProgress & FLAG_IS_ANIMATED) == true);

  // Ensure that we decoded both frames of the image.
  LookupResult result =
    SurfaceCache::Lookup(ImageKey(image.get()),
                         RasterSurfaceKey(imageSize,
                                          DefaultSurfaceFlags(),
                                          PlaybackType::eAnimated));
  ASSERT_EQ(MatchType::EXACT, result.Type());

  EXPECT_TRUE(NS_SUCCEEDED(result.Surface().Seek(0)));
  EXPECT_TRUE(bool(result.Surface()));

  EXPECT_TRUE(NS_SUCCEEDED(result.Surface().Seek(1)));
  EXPECT_TRUE(bool(result.Surface()));
}
Exemplo n.º 7
0
TEST_F(ImageDecoders, AnimatedGIFWithFRAME_CURRENT)
{
  ImageTestCase testCase = GreenFirstFrameAnimatedGIFTestCase();

  // Verify that we can decode this test case and retrieve the entire sequence
  // of frames using imgIContainer::FRAME_CURRENT. This ensures that we
  // correctly trigger an animated decode rather than a single-frame decode when
  // imgIContainer::FRAME_CURRENT is requested.

  // Create an image.
  RefPtr<Image> image =
    ImageFactory::CreateAnonymousImage(nsDependentCString(testCase.mMimeType));
  ASSERT_TRUE(!image->HasError());

  nsCOMPtr<nsIInputStream> inputStream = LoadFile(testCase.mPath);
  ASSERT_TRUE(inputStream);

  // Figure out how much data we have.
  uint64_t length;
  nsresult rv = inputStream->Available(&length);
  ASSERT_TRUE(NS_SUCCEEDED(rv));

  // Write the data into the image.
  rv = image->OnImageDataAvailable(nullptr, nullptr, inputStream, 0,
                                   static_cast<uint32_t>(length));
  ASSERT_TRUE(NS_SUCCEEDED(rv));

  // Let the image know we've sent all the data.
  rv = image->OnImageDataComplete(nullptr, nullptr, NS_OK, true);
  ASSERT_TRUE(NS_SUCCEEDED(rv));

  RefPtr<ProgressTracker> tracker = image->GetProgressTracker();
  tracker->SyncNotifyProgress(FLAG_LOAD_COMPLETE);

  // Lock the image so its surfaces don't disappear during the test.
  image->LockImage();

  // Use GetFrame() to force a sync decode of the image, specifying
  // FRAME_CURRENT to ensure we get an animated decode.
  RefPtr<SourceSurface> surface =
    image->GetFrame(imgIContainer::FRAME_CURRENT,
                    imgIContainer::FLAG_SYNC_DECODE);

  // Ensure that the image's metadata meets our expectations.
  IntSize imageSize(0, 0);
  rv = image->GetWidth(&imageSize.width);
  EXPECT_TRUE(NS_SUCCEEDED(rv));
  rv = image->GetHeight(&imageSize.height);
  EXPECT_TRUE(NS_SUCCEEDED(rv));

  EXPECT_EQ(testCase.mSize.width, imageSize.width);
  EXPECT_EQ(testCase.mSize.height, imageSize.height);

  Progress imageProgress = tracker->GetProgress();

  EXPECT_TRUE(bool(imageProgress & FLAG_HAS_TRANSPARENCY) == false);
  EXPECT_TRUE(bool(imageProgress & FLAG_IS_ANIMATED) == true);

  // Ensure that we decoded both frames of the animated version of the image.
  {
    LookupResult result =
      SurfaceCache::Lookup(ImageKey(image.get()),
                           RasterSurfaceKey(imageSize,
                                            DefaultSurfaceFlags(),
                                            PlaybackType::eAnimated));
    ASSERT_EQ(MatchType::EXACT, result.Type());

    EXPECT_TRUE(NS_SUCCEEDED(result.Surface().Seek(0)));
    EXPECT_TRUE(bool(result.Surface()));

    EXPECT_TRUE(NS_SUCCEEDED(result.Surface().Seek(1)));
    EXPECT_TRUE(bool(result.Surface()));
  }

  // Ensure that we didn't decode the static version of the image.
  {
    LookupResult result =
      SurfaceCache::Lookup(ImageKey(image.get()),
                           RasterSurfaceKey(imageSize,
                                            DefaultSurfaceFlags(),
                                            PlaybackType::eStatic));
    ASSERT_EQ(MatchType::NOT_FOUND, result.Type());
  }

  // Use GetFrame() to force a sync decode of the image, this time specifying
  // FRAME_FIRST to ensure that we get a single-frame decode.
  RefPtr<SourceSurface> animatedSurface =
    image->GetFrame(imgIContainer::FRAME_FIRST,
                    imgIContainer::FLAG_SYNC_DECODE);

  // Ensure that we decoded the static version of the image.
  {
    LookupResult result =
      SurfaceCache::Lookup(ImageKey(image.get()),
                           RasterSurfaceKey(imageSize,
                                            DefaultSurfaceFlags(),
                                            PlaybackType::eStatic));
    ASSERT_EQ(MatchType::EXACT, result.Type());
    EXPECT_TRUE(bool(result.Surface()));
  }

  // Ensure that both frames of the animated version are still around.
  {
    LookupResult result =
      SurfaceCache::Lookup(ImageKey(image.get()),
                           RasterSurfaceKey(imageSize,
                                            DefaultSurfaceFlags(),
                                            PlaybackType::eAnimated));
    ASSERT_EQ(MatchType::EXACT, result.Type());

    EXPECT_TRUE(NS_SUCCEEDED(result.Surface().Seek(0)));
    EXPECT_TRUE(bool(result.Surface()));

    EXPECT_TRUE(NS_SUCCEEDED(result.Surface().Seek(1)));
    EXPECT_TRUE(bool(result.Surface()));
  }
}