TEST_F(BitmapImageTest, destroyDecodedData) { loadImage("/LayoutTests/fast/images/resources/animated-10color.gif"); size_t totalSize = decodedSize(); EXPECT_GT(totalSize, 0u); destroyDecodedData(); EXPECT_EQ(-static_cast<int>(totalSize), lastDecodedSizeChange()); EXPECT_EQ(0u, decodedSize()); }
void CachedImage::decodedSizeChanged(const Image* image, long long delta) { if (!image || image != m_image) return; ASSERT(delta >= 0 || decodedSize() + delta >= 0); setDecodedSize(static_cast<unsigned>(decodedSize() + delta)); }
TEST_F(BitmapImageTest, destroyAllDecodedData) { loadImage("/tests/fast/images/resources/animated-10color.gif"); size_t totalSize = decodedSize(); EXPECT_GT(totalSize, 0u); destroyDecodedData(true); EXPECT_EQ(-static_cast<int>(totalSize), m_imageObserver.m_lastDecodedSizeChangedDelta); EXPECT_EQ(0u, decodedSize()); }
TEST_F(BitmapImageTest, webpHasColorProfile) { loadImage("/LayoutTests/fast/images/resources/webp-color-profile-lossy.webp"); EXPECT_EQ(1u, decodedFramesCount()); EXPECT_EQ(2560000u, decodedSize()); EXPECT_TRUE(m_image->hasColorProfile()); destroyDecodedData(true); resetDecoder(); loadImage("/LayoutTests/fast/images/resources/test.webp"); EXPECT_EQ(1u, decodedFramesCount()); EXPECT_EQ(65536u, decodedSize()); EXPECT_FALSE(m_image->hasColorProfile()); }
TEST_F(BitmapImageTest, jpegHasColorProfile) { loadImage("/tests/fast/images/resources/icc-v2-gbr.jpg"); EXPECT_EQ(1u, decodedFramesCount()); EXPECT_EQ(227700u, decodedSize()); EXPECT_TRUE(m_image->hasColorProfile()); resetDecoder(); destroyDecodedData(true); loadImage("/tests/fast/images/resources/green.jpg"); EXPECT_EQ(1u, decodedFramesCount()); EXPECT_EQ(1024u, decodedSize()); EXPECT_FALSE(m_image->hasColorProfile()); }
TEST_F(BitmapImageTest, pngHasColorProfile) { loadImage("/tests/fast/images/resources/palatted-color-png-gamma-one-color-profile.png"); EXPECT_EQ(1u, decodedFramesCount()); EXPECT_EQ(65536u, decodedSize()); EXPECT_TRUE(m_image->hasColorProfile()); resetDecoder(); destroyDecodedData(true); loadImage("/tests/fast/images/resources/green.jpg"); EXPECT_EQ(1u, decodedFramesCount()); EXPECT_EQ(1024u, decodedSize()); EXPECT_FALSE(m_image->hasColorProfile()); }
void CachedImage::decodedSizeChanged(const Image* image, int delta) { if (image != m_image) return; setDecodedSize(decodedSize() + delta); }
void ImageResource::decodedSizeChanged(const blink::Image* image, int delta) { if (!image || image != m_image) return; setDecodedSize(decodedSize() + delta); }
TEST_F(BitmapImageTest, noColorProfile) { loadImage("/LayoutTests/fast/images/resources/green.jpg"); EXPECT_EQ(1u, decodedFramesCount()); EXPECT_EQ(1024u, decodedSize()); EXPECT_FALSE(m_image->hasColorProfile()); }
TEST_F(BitmapImageTest, jpegHasColorProfile) { loadImage("/LayoutTests/fast/images/resources/icc-v2-gbr.jpg"); EXPECT_EQ(1u, decodedFramesCount()); EXPECT_EQ(227700u, decodedSize()); EXPECT_TRUE(m_image->hasColorProfile()); }
TEST_F(BitmapImageTest, pngHasColorProfile) { loadImage("/LayoutTests/fast/images/resources/palatted-color-png-gamma-one-color-profile.png"); EXPECT_EQ(1u, decodedFramesCount()); EXPECT_EQ(65536u, decodedSize()); EXPECT_TRUE(m_image->hasColorProfile()); }
void ImageDecoder::updateAggressivePurging(size_t index) { if (m_purgeAggressively) return; // We don't want to cache so much that we cause a memory issue. // // If we used a LRU cache we would fill it and then on next animation loop // we would need to decode all the frames again -- the LRU would give no // benefit and would consume more memory. // So instead, simply purge unused frames if caching all of the frames of // the image would use more memory than the image decoder is allowed // (m_maxDecodedBytes) or would overflow 32 bits.. // // As we decode we will learn the total number of frames, and thus total // possible image memory used. const uint64_t frameArea = decodedSize().area(); const uint64_t frameMemoryUsage = frameArea * 4; // 4 bytes per pixel if (frameMemoryUsage / 4 != frameArea) { // overflow occurred m_purgeAggressively = true; return; } const uint64_t totalMemoryUsage = frameMemoryUsage * index; if (totalMemoryUsage / frameMemoryUsage != index) { // overflow occurred m_purgeAggressively = true; return; } if (totalMemoryUsage > m_maxDecodedBytes) { m_purgeAggressively = true; } }
TEST_F(BitmapImageTest, webpHasColorProfile) { loadImage("/LayoutTests/fast/images/resources/webp-color-profile-lossy.webp"); EXPECT_EQ(1u, decodedFramesCount()); EXPECT_EQ(2560000u, decodedSize()); EXPECT_TRUE(m_image->hasColorProfile()); }
void ImageResource::didDraw(const blink::Image* image) { if (!image || image != m_image) return; // decodedSize() == 0 indicates that the image is decoded into DiscardableMemory, // not in MemoryCache. So we don't need to call Resource::didAccessDecodedData() // to update MemoryCache. if (decodedSize() != 0) Resource::didAccessDecodedData(); }
TEST_F(BitmapImageTest, destroyDecodedDataExceptCurrentFrame) { loadImage("/tests/fast/images/resources/animated-10color.gif"); size_t totalSize = decodedSize(); size_t frame = frameCount() / 2; setCurrentFrame(frame); size_t size = frameDecodedSize(frame); destroyDecodedData(false); EXPECT_LT(m_imageObserver.m_lastDecodedSizeChangedDelta, 0); EXPECT_GE(m_imageObserver.m_lastDecodedSizeChangedDelta, -static_cast<int>(totalSize - size)); }
void loadImage(const char* fileName) { RefPtr<SharedBuffer> imageData = readFile("/LayoutTests/fast/images/resources/animated-10color.gif"); ASSERT_TRUE(imageData.get()); m_image->setData(imageData, true); EXPECT_EQ(0u, decodedSize()); size_t frameCount = m_image->frameCount(); for (size_t i = 0; i < frameCount; ++i) m_image->frameAtIndex(i); }
void loadImage(const char* fileName) { RefPtr<SharedBuffer> imageData = readFile(fileName); ASSERT_TRUE(imageData.get()); m_image->setData(imageData, true); EXPECT_EQ(0u, decodedSize()); size_t frameCount = m_image->frameCount(); for (size_t i = 0; i < frameCount; ++i) m_image->frameAtIndex(i); }
void GIFImageDecoder::updateAggressivePurging(size_t index) { if (m_purgeAggressively) return; // We don't want to cache so much that we cause a memory issue. // // If we used a LRU cache we would fill it and then on next animation loop // we would need to decode all the frames again -- the LRU would give no // benefit and would consume more memory. // So instead, simply purge unused frames if caching all of the frames of // the image would use more memory than the image decoder is allowed // (m_maxDecodedBytes) or would overflow 32 bits.. // // As we decode we will learn the total number of frames, and thus total // possible image memory used. const uint64_t frameArea = decodedSize().area(); // We are about to multiply by 4, which may require an extra bit of storage bool wouldOverflow = frameArea > (UINT64_C(1) << 62); if (wouldOverflow) { m_purgeAggressively = true; return; } const uint64_t frameMemoryUsage = frameArea * 4; // 4 bytes per pixel // We are about to multiply by a size_t, which does not have a fixed // size. // To simplify things, let's make sure our per-frame memory usage and // index can be stored in 32 bits and store the multiplicand in a 64-bit // number. wouldOverflow = (frameMemoryUsage > (UINT32_C(1) << 31)) || (index > (UINT32_C(1) << 31)); if (wouldOverflow) { m_purgeAggressively = true; return; } const uint64_t totalMemoryUsage = frameMemoryUsage * index; if (totalMemoryUsage > m_maxDecodedBytes) { m_purgeAggressively = true; } }
void ImageFrameCache::replaceFrameNativeImageAtIndex(NativeImagePtr&& nativeImage, size_t index, SubsamplingLevel subsamplingLevel) { ASSERT(index < m_frames.size()); ImageFrame& frame = m_frames[index]; if (!frame.hasValidNativeImage(subsamplingLevel)) { // Clear the current image frame and update the observer with this clearance. unsigned decodedSize = frame.clear(); decodedSizeDecreased(decodedSize); } // Do not cache the NativeImage if adding its frameByes to the MemoryCache will cause numerical overflow. size_t frameBytes = size().unclampedArea() * sizeof(RGBA32); if (!WTF::isInBounds<unsigned>(frameBytes + decodedSize())) return; // Copy the new image to the cache. setFrameNativeImageAtIndex(WTFMove(nativeImage), index, subsamplingLevel); // Update the observer with the new image frame bytes. decodedSizeIncreased(frame.frameBytes()); }
void CachedScript::sourceProviderCacheSizeChanged(int delta) { setDecodedSize(decodedSize() + delta); }