Chromium Code Reviews| 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..09fe111a8136045c864cc48fd328314c418ac5d7 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 is no or only one frame. | 
| 
 
Peter Kasting
2013/05/29 02:02:18
Nit: "...are no frames or only one frame."
 
Xianzhu
2013/05/29 18:37:01
Done.
 
 | 
| + if (m_frameBufferCache.size() <= 1) | 
| + return 0; | 
| + | 
| 
 
Peter Kasting
2013/05/29 02:02:18
In theory, it's technically possible for ICOs to r
 
Xianzhu
2013/05/29 18:37:01
Done.
 
 | 
| + // 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; | 
| 
 
Peter Kasting
2013/05/29 02:02:18
Nit: ; -> .
 
Xianzhu
2013/05/29 18:37:01
Done.
 
 | 
| + // All other frames can be cleared. | 
| + size_t frameToBeRequired = notFound; | 
| 
 
Peter Kasting
2013/05/29 02:02:18
Nit: You can actually make this even simpler by re
 
Xianzhu
2013/05/29 18:37:01
Done.
 
 | 
| + if (clearExceptFrame < m_frameBufferCache.size() && m_frameBufferCache[clearExceptFrame].status() == ImageFrame::FrameEmpty) { | 
| + frameToBeRequired = clearExceptFrame; | 
| + do { | 
| + frameToBeRequired = m_frameBufferCache[frameToBeRequired].requiredPreviousFrameIndex(); | 
| + } while (frameToBeRequired != notFound && m_frameBufferCache[frameToBeRequired].status() == ImageFrame::FrameEmpty); | 
| + } | 
| + | 
| + size_t frameBytesCleared = 0; | 
| + for (size_t i = 0; i < m_frameBufferCache.size(); ++i) { | 
| + if (i != clearExceptFrame && i != frameToBeRequired) { | 
| + 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]; | 
| 
 
Peter Kasting
2013/05/29 02:02:18
Here you should also ASSERT(prevBuffer->m_required
 
Xianzhu
2013/05/29 18:37:01
Done.
 
 | 
| + 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. Otherwise, prevFrame contributes to this frame. | 
| + // However, the first frame always clears even it partially covers. | 
| 
 
Peter Kasting
2013/05/29 02:02:18
We can actually be even smarter here by handling c
 
Xianzhu
2013/05/29 18:37:01
Done. Thanks for the idea.
 
 | 
| + return !prevFrame || prevBuffer->originalFrameRect().contains(IntRect(IntPoint(), size())) ? notFound : prevFrame; | 
| + default: | 
| + ASSERT_NOT_REACHED(); | 
| + return notFound; | 
| + } | 
| +} | 
| + | 
| } // namespace WebCore |