// Tests for a crash that used to happen for a specific file with specific // sequence of method calls. TEST(AnimatedWebPTests, reproCrash) { std::unique_ptr<ImageDecoder> decoder = createDecoder(); RefPtr<SharedBuffer> fullData = readFile("/LayoutTests/images/resources/invalid_vp8_vp8x.webp"); ASSERT_TRUE(fullData.get()); // Parse partial data up to which error in bitstream is not detected. const size_t partialSize = 32768; ASSERT_GT(fullData->size(), partialSize); RefPtr<SharedBuffer> data = SharedBuffer::create(fullData->data(), partialSize); decoder->setData(data.get(), false); EXPECT_EQ(1u, decoder->frameCount()); ImageFrame* frame = decoder->frameBufferAtIndex(0); ASSERT_TRUE(frame); EXPECT_EQ(ImageFrame::FramePartial, frame->getStatus()); EXPECT_FALSE(decoder->failed()); // Parse full data now. The error in bitstream should now be detected. decoder->setData(fullData.get(), true); EXPECT_EQ(1u, decoder->frameCount()); frame = decoder->frameBufferAtIndex(0); ASSERT_TRUE(frame); EXPECT_EQ(ImageFrame::FramePartial, frame->getStatus()); EXPECT_EQ(cAnimationLoopOnce, decoder->repetitionCount()); EXPECT_TRUE(decoder->failed()); }
sk_sp<SkImage> DeferredImageDecoder::createFrameAtIndex(size_t index) { if (m_frameGenerator && m_frameGenerator->decodeFailed()) return nullptr; prepareLazyDecodedFrames(); if (index < m_frameData.size()) { DeferredFrameData* frameData = &m_frameData[index]; if (m_actualDecoder) frameData->m_frameBytes = m_actualDecoder->frameBytesAtIndex(index); else frameData->m_frameBytes = m_size.area() * sizeof(ImageFrame::PixelData); // ImageFrameGenerator has the latest known alpha state. There will be a // performance boost if this frame is opaque. DCHECK(m_frameGenerator); return createFrameImageAtIndex(index, !m_frameGenerator->hasAlpha(index)); } if (!m_actualDecoder || m_actualDecoder->failed()) return nullptr; ImageFrame* frame = m_actualDecoder->frameBufferAtIndex(index); if (!frame || frame->getStatus() == ImageFrame::FrameEmpty) return nullptr; return (frame->getStatus() == ImageFrame::FrameComplete) ? frame->finalizePixelsAndGetImage() : SkImage::MakeFromBitmap(frame->bitmap()); }
TEST(AnimatedWebPTests, truncatedInBetweenFrame) { std::unique_ptr<ImageDecoder> decoder = createDecoder(); RefPtr<SharedBuffer> fullData = readFile("/LayoutTests/images/resources/invalid-animated-webp4.webp"); ASSERT_TRUE(fullData.get()); RefPtr<SharedBuffer> data = SharedBuffer::create(fullData->data(), fullData->size() - 1); decoder->setData(data.get(), false); ImageFrame* frame = decoder->frameBufferAtIndex(1); ASSERT_TRUE(frame); EXPECT_EQ(ImageFrame::FrameComplete, frame->getStatus()); frame = decoder->frameBufferAtIndex(2); ASSERT_TRUE(frame); EXPECT_EQ(ImageFrame::FramePartial, frame->getStatus()); EXPECT_TRUE(decoder->failed()); }
TEST(AnimatedWebPTests, truncatedLastFrame) { std::unique_ptr<ImageDecoder> decoder = createDecoder(); RefPtr<SharedBuffer> data = readFile("/LayoutTests/images/resources/invalid-animated-webp2.webp"); ASSERT_TRUE(data.get()); decoder->setData(data.get(), true); size_t frameCount = 8; EXPECT_EQ(frameCount, decoder->frameCount()); ImageFrame* frame = decoder->frameBufferAtIndex(0); ASSERT_TRUE(frame); EXPECT_EQ(ImageFrame::FrameComplete, frame->getStatus()); EXPECT_FALSE(decoder->failed()); frame = decoder->frameBufferAtIndex(frameCount - 1); ASSERT_TRUE(frame); EXPECT_EQ(ImageFrame::FramePartial, frame->getStatus()); EXPECT_TRUE(decoder->failed()); frame = decoder->frameBufferAtIndex(0); ASSERT_TRUE(frame); EXPECT_EQ(ImageFrame::FrameComplete, frame->getStatus()); }
ImageFrame* ImageDecoder::frameBufferAtIndex(size_t index) { if (index >= frameCount()) return 0; ImageFrame* frame = &m_frameBufferCache[index]; if (frame->getStatus() != ImageFrame::FrameComplete) { PlatformInstrumentation::willDecodeImage(filenameExtension()); decode(index); PlatformInstrumentation::didDecodeImage(); } if (!m_hasHistogrammedColorSpace) { BitmapImageMetrics::countImageGamma(m_embeddedColorSpace.get()); m_hasHistogrammedColorSpace = true; } frame->notifyBitmapIfPixelsChanged(); return frame; }