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

Unified Diff: Source/core/platform/image-decoders/ImageDecoder.cpp

Issue 15969015: Reland again "Decode GIF image frames on demand". (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: For landing Created 7 years, 7 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/image-decoders/ImageDecoder.cpp
diff --git a/Source/core/platform/image-decoders/ImageDecoder.cpp b/Source/core/platform/image-decoders/ImageDecoder.cpp
index b98e45a3fa8f93c9a9ccfaba21d6749ce34e02fa..9eb1de3127844150adcd41ad5b4f28dc3183e77d 100644
--- a/Source/core/platform/image-decoders/ImageDecoder.cpp
+++ b/Source/core/platform/image-decoders/ImageDecoder.cpp
@@ -127,7 +127,7 @@ bool ImageDecoder::frameIsCompleteAtIndex(size_t index) const
unsigned ImageDecoder::frameBytesAtIndex(size_t index) const
{
- if (m_frameBufferCache.size() <= index)
+ if (m_frameBufferCache.size() <= index || m_frameBufferCache[index].status() == ImageFrame::FrameEmpty)
return 0;
// FIXME: Use the dimension of the requested frame.
return m_size.area() * sizeof(ImageFrame::PixelData);
@@ -140,4 +140,73 @@ void ImageDecoder::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
info.addMember(m_frameBufferCache, "frameBufferCache");
}
+size_t ImageDecoder::clearCacheExceptFrame(size_t clearExceptFrame)
+{
+ // Don't clear if there are no frames or only one frame.
+ if (m_frameBufferCache.size() <= 1)
+ return 0;
+
+ // We need to preserve frames such that:
+ // 1. We don't clear |clearExceptFrame|;
+ // 2. We don't clear any frame from which a future initFrameBuffer() call
+ // will copy bitmap data.
+ // All other frames can be cleared.
+ while ((clearExceptFrame < m_frameBufferCache.size()) && (m_frameBufferCache[clearExceptFrame].status() == ImageFrame::FrameEmpty))
+ clearExceptFrame = m_frameBufferCache[clearExceptFrame].requiredPreviousFrameIndex();
+
+ size_t frameBytesCleared = 0;
+ for (size_t i = 0; i < m_frameBufferCache.size(); ++i) {
+ if (i != clearExceptFrame) {
+ frameBytesCleared += frameBytesAtIndex(i);
+ clearFrameBuffer(i);
+ }
+ }
+ return frameBytesCleared;
+}
+
+void ImageDecoder::clearFrameBuffer(size_t frameIndex)
+{
+ m_frameBufferCache[frameIndex].clearPixelData();
+}
+
+size_t ImageDecoder::findRequiredPreviousFrame(size_t frameIndex)
+{
+ ASSERT(frameIndex <= m_frameBufferCache.size());
+ if (!frameIndex) {
+ // The first frame doesn't rely on any previous data.
+ return notFound;
+ }
+
+ // The starting state for this frame depends on the previous frame's
+ // disposal method.
+ size_t prevFrame = frameIndex - 1;
+ const ImageFrame* prevBuffer = &m_frameBufferCache[prevFrame];
+ ASSERT(prevBuffer->requiredPreviousFrameIndexValid());
+
+ switch (prevBuffer->disposalMethod()) {
+ case ImageFrame::DisposeNotSpecified:
+ case ImageFrame::DisposeKeep:
+ // prevFrame will be used as the starting state for this frame.
+ // FIXME: Be even smarter by checking the frame sizes and/or alpha-containing regions.
+ return prevFrame;
+ case ImageFrame::DisposeOverwritePrevious:
+ // Frames that use the DisposeOverwritePrevious method are effectively
+ // no-ops in terms of changing the starting state of a frame compared to
+ // the starting state of the previous frame, so skip over them and
+ // return the required previous frame of it.
+ return prevBuffer->requiredPreviousFrameIndex();
+ case ImageFrame::DisposeOverwriteBgcolor:
+ // If the previous frame fills the whole image, then the current frame
+ // can be decoded alone. Likewise, if the previous frame could be
+ // decoded without reference to any prior frame, the starting state for
+ // this frame is a blank frame, so it can again be decoded alone.
+ // Otherwise, the previous frame contributes to this frame.
+ return (prevBuffer->originalFrameRect().contains(IntRect(IntPoint(), size()))
+ || (prevBuffer->requiredPreviousFrameIndex() == notFound)) ? notFound : prevFrame;
+ default:
+ ASSERT_NOT_REACHED();
+ return notFound;
+ }
+}
+
} // namespace WebCore

Powered by Google App Engine
This is Rietveld 408576698