Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1107)

Unified Diff: Source/core/platform/graphics/chromium/ImageFrameGenerator.cpp

Issue 19838002: Reland change to enable deferred image decoding for animated GIFs (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: merved Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: Source/core/platform/graphics/chromium/ImageFrameGenerator.cpp
diff --git a/Source/core/platform/graphics/chromium/ImageFrameGenerator.cpp b/Source/core/platform/graphics/chromium/ImageFrameGenerator.cpp
index e5027cb88b144ce945766d9ea5830e5382a23364..5c32e1277476cb69804860f58d4085279187970c 100644
--- a/Source/core/platform/graphics/chromium/ImageFrameGenerator.cpp
+++ b/Source/core/platform/graphics/chromium/ImageFrameGenerator.cpp
@@ -47,10 +47,10 @@ skia::ImageOperations::ResizeMethod resizeMethod()
} // namespace
-ImageFrameGenerator::ImageFrameGenerator(const SkISize& fullSize, PassRefPtr<SharedBuffer> data, bool allDataReceived)
+ImageFrameGenerator::ImageFrameGenerator(const SkISize& fullSize, PassRefPtr<SharedBuffer> data, bool allDataReceived, bool isMultiFrame)
: m_fullSize(fullSize)
+ , m_isMultiFrame(isMultiFrame)
, m_decodeFailedAndEmpty(false)
- , m_hasAlpha(true)
, m_decodeCount(ScaledImageFragment::FirstPartialImage)
{
setData(data.get(), allDataReceived);
@@ -78,7 +78,7 @@ void ImageFrameGenerator::copyData(RefPtr<SharedBuffer>* data, bool* allDataRece
*data = buffer->copy();
}
-const ScaledImageFragment* ImageFrameGenerator::decodeAndScale(const SkISize& scaledSize)
+const ScaledImageFragment* ImageFrameGenerator::decodeAndScale(const SkISize& scaledSize, size_t index)
{
// Prevents concurrent decode or scale operations on the same image data.
// Multiple LazyDecodingPixelRefs can call this method at the same time.
@@ -88,35 +88,35 @@ const ScaledImageFragment* ImageFrameGenerator::decodeAndScale(const SkISize& sc
const ScaledImageFragment* cachedImage = 0;
- cachedImage = tryToLockCompleteCache(scaledSize);
+ cachedImage = tryToLockCompleteCache(scaledSize, index);
if (cachedImage)
return cachedImage;
TRACE_EVENT2("webkit", "ImageFrameGenerator::decodeAndScale", "generator", this, "decodeCount", static_cast<int>(m_decodeCount));
- cachedImage = tryToScale(0, scaledSize);
+ cachedImage = tryToScale(0, scaledSize, index);
if (cachedImage)
return cachedImage;
- cachedImage = tryToResumeDecodeAndScale(scaledSize);
+ cachedImage = tryToResumeDecodeAndScale(scaledSize, index);
if (cachedImage)
return cachedImage;
- cachedImage = tryToDecodeAndScale(scaledSize);
+ cachedImage = tryToDecodeAndScale(scaledSize, index);
if (cachedImage)
return cachedImage;
return 0;
}
-const ScaledImageFragment* ImageFrameGenerator::tryToLockCompleteCache(const SkISize& scaledSize)
+const ScaledImageFragment* ImageFrameGenerator::tryToLockCompleteCache(const SkISize& scaledSize, size_t index)
{
const ScaledImageFragment* cachedImage = 0;
- if (ImageDecodingStore::instance()->lockCache(this, scaledSize, 0, &cachedImage))
+ if (ImageDecodingStore::instance()->lockCache(this, scaledSize, index, &cachedImage))
return cachedImage;
return 0;
}
-const ScaledImageFragment* ImageFrameGenerator::tryToScale(const ScaledImageFragment* fullSizeImage, const SkISize& scaledSize)
+const ScaledImageFragment* ImageFrameGenerator::tryToScale(const ScaledImageFragment* fullSizeImage, const SkISize& scaledSize, size_t index)
{
TRACE_EVENT0("webkit", "ImageFrameGenerator::tryToScale");
@@ -125,7 +125,7 @@ const ScaledImageFragment* ImageFrameGenerator::tryToScale(const ScaledImageFrag
if (scaledSize == m_fullSize)
return 0;
- if (!fullSizeImage && !ImageDecodingStore::instance()->lockCache(this, m_fullSize, 0, &fullSizeImage))
+ if (!fullSizeImage && !ImageDecodingStore::instance()->lockCache(this, m_fullSize, index, &fullSizeImage))
return 0;
// This call allocates the DiscardablePixelRef and lock/unlocks it
@@ -143,9 +143,9 @@ const ScaledImageFragment* ImageFrameGenerator::tryToScale(const ScaledImageFrag
return ImageDecodingStore::instance()->insertAndLockCache(this, scaledImage.release());
}
-const ScaledImageFragment* ImageFrameGenerator::tryToResumeDecodeAndScale(const SkISize& scaledSize)
+const ScaledImageFragment* ImageFrameGenerator::tryToResumeDecodeAndScale(const SkISize& scaledSize, size_t index)
{
- TRACE_EVENT0("webkit", "ImageFrameGenerator::tryToResumeDecodeAndScale");
+ TRACE_EVENT1("webkit", "ImageFrameGenerator::tryToResumeDecodeAndScale", "index", static_cast<int>(index));
ImageDecoder* cachedDecoder = 0;
@@ -154,27 +154,37 @@ const ScaledImageFragment* ImageFrameGenerator::tryToResumeDecodeAndScale(const
ASSERT(cachedDecoder);
// Always generate a new image and insert it into cache.
- OwnPtr<ScaledImageFragment> fullSizeImage = decode(&cachedDecoder);
+ OwnPtr<ScaledImageFragment> fullSizeImage = decode(index, &cachedDecoder);
+
+ if (!fullSizeImage) {
+ // If decode has failed and resulted an empty image we can save work
+ // in the future by returning early.
+ m_decodeFailedAndEmpty = !m_isMultiFrame && cachedDecoder->failed();
+ ImageDecodingStore::instance()->unlockDecoder(this, cachedDecoder);
+ return 0;
+ }
+
const ScaledImageFragment* cachedImage = ImageDecodingStore::instance()->insertAndLockCache(this, fullSizeImage.release());
// If the image generated is complete then there is no need to keep
- // the decoder.
- if (cachedImage->isComplete())
+ // the decoder. The exception is multi-frame decoder which can generate
+ // multiple complete frames.
+ if (cachedImage->isComplete() && !m_isMultiFrame)
ImageDecodingStore::instance()->removeDecoder(this, cachedDecoder);
else
ImageDecodingStore::instance()->unlockDecoder(this, cachedDecoder);
if (m_fullSize == scaledSize)
return cachedImage;
- return tryToScale(cachedImage, scaledSize);
+ return tryToScale(cachedImage, scaledSize, index);
}
-const ScaledImageFragment* ImageFrameGenerator::tryToDecodeAndScale(const SkISize& scaledSize)
+const ScaledImageFragment* ImageFrameGenerator::tryToDecodeAndScale(const SkISize& scaledSize, size_t index)
{
- TRACE_EVENT0("webkit", "ImageFrameGenerator::tryToDecodeAndScale");
+ TRACE_EVENT1("webkit", "ImageFrameGenerator::tryToDecodeAndScale", "index", static_cast<int>(index));
ImageDecoder* decoder = 0;
- OwnPtr<ScaledImageFragment> fullSizeImage = decode(&decoder);
+ OwnPtr<ScaledImageFragment> fullSizeImage = decode(index, &decoder);
if (!decoder)
return 0;
@@ -182,25 +192,26 @@ const ScaledImageFragment* ImageFrameGenerator::tryToDecodeAndScale(const SkISiz
OwnPtr<ImageDecoder> decoderContainer = adoptPtr(decoder);
if (!fullSizeImage) {
- // If decode has failed and resulted an empty image we need to make
- // sure we don't do wasted work in the future.
- m_decodeFailedAndEmpty = decoderContainer->failed();
+ // If decode has failed and resulted an empty image we can save work
+ // in the future by returning early.
+ m_decodeFailedAndEmpty = !m_isMultiFrame && decoderContainer->failed();
return 0;
}
const ScaledImageFragment* cachedImage = ImageDecodingStore::instance()->insertAndLockCache(this, fullSizeImage.release());
// If image is complete then decoder is not needed in the future.
- // Otherwise save the decoder for later use.
- if (!cachedImage->isComplete())
+ // Otherwise save the decoder for later use. The exception is
+ // multi-frame decoder which can generate multiple complete frames.
+ if (!cachedImage->isComplete() || m_isMultiFrame)
ImageDecodingStore::instance()->insertDecoder(this, decoderContainer.release(), DiscardablePixelRef::isDiscardable(cachedImage->bitmap().pixelRef()));
if (m_fullSize == scaledSize)
return cachedImage;
- return tryToScale(cachedImage, scaledSize);
+ return tryToScale(cachedImage, scaledSize, index);
}
-PassOwnPtr<ScaledImageFragment> ImageFrameGenerator::decode(ImageDecoder** decoder)
+PassOwnPtr<ScaledImageFragment> ImageFrameGenerator::decode(size_t index, ImageDecoder** decoder)
{
TRACE_EVENT2("webkit", "ImageFrameGenerator::decode", "width", m_fullSize.width(), "height", m_fullSize.height());
@@ -222,15 +233,17 @@ PassOwnPtr<ScaledImageFragment> ImageFrameGenerator::decode(ImageDecoder** decod
// TODO: this is very ugly. We need to refactor the way how we can pass a
// memory allocator to image decoders.
- (*decoder)->setMemoryAllocator(&m_allocator);
+ if (!m_isMultiFrame)
+ (*decoder)->setMemoryAllocator(&m_allocator);
(*decoder)->setData(data, allDataReceived);
// If this call returns a newly allocated DiscardablePixelRef, then
// ImageFrame::m_bitmap and the contained DiscardablePixelRef are locked.
// They will be unlocked when ImageDecoder is destroyed since ImageDecoder
// owns the ImageFrame. Partially decoded SkBitmap is thus inserted into the
// ImageDecodingStore while locked.
- ImageFrame* frame = (*decoder)->frameBufferAtIndex(0);
+ ImageFrame* frame = (*decoder)->frameBufferAtIndex(index);
(*decoder)->setData(0, false); // Unref SharedBuffer from ImageDecoder.
+ (*decoder)->clearCacheExceptFrame(index);
if (!frame || frame->status() == ImageFrame::FrameEmpty)
return nullptr;
@@ -239,24 +252,32 @@ PassOwnPtr<ScaledImageFragment> ImageFrameGenerator::decode(ImageDecoder** decod
SkBitmap fullSizeBitmap = frame->getSkBitmap();
{
MutexLocker lock(m_alphaMutex);
- m_hasAlpha = !fullSizeBitmap.isOpaque();
+ if (index >= m_hasAlpha.size()) {
+ const size_t oldSize = m_hasAlpha.size();
+ m_hasAlpha.resize(index + 1);
+ for (size_t i = oldSize; i < m_hasAlpha.size(); ++i)
+ m_hasAlpha[i] = true;
+ }
+ m_hasAlpha[index] = !fullSizeBitmap.isOpaque();
}
ASSERT(fullSizeBitmap.width() == m_fullSize.width() && fullSizeBitmap.height() == m_fullSize.height());
if (isComplete)
- return ScaledImageFragment::createComplete(m_fullSize, 0, fullSizeBitmap);
+ return ScaledImageFragment::createComplete(m_fullSize, index, fullSizeBitmap);
// If the image is partial we need to return a copy. This is to avoid future
// decode operations writing to the same bitmap.
SkBitmap copyBitmap;
fullSizeBitmap.copyTo(&copyBitmap, fullSizeBitmap.config(), &m_allocator);
- return ScaledImageFragment::createPartial(m_fullSize, 0, nextGenerationId(), copyBitmap);
+ return ScaledImageFragment::createPartial(m_fullSize, index, nextGenerationId(), copyBitmap);
}
-bool ImageFrameGenerator::hasAlpha()
+bool ImageFrameGenerator::hasAlpha(size_t index)
{
MutexLocker lock(m_alphaMutex);
- return m_hasAlpha;
+ if (index < m_hasAlpha.size())
+ return m_hasAlpha[index];
+ return true;
}
} // namespace WebCore

Powered by Google App Engine
This is Rietveld 408576698