 Chromium Code Reviews
 Chromium Code Reviews Issue 15350006:
  Decode GIF image frames on demand.  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/blink.git@master
    
  
    Issue 15350006:
  Decode GIF image frames on demand.  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/blink.git@master| 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 37cd9327dd39379d68debb4ab690c28d772a5dd3..76cdb4d6d28d31a85bbac6a0e983ed845720100b 100644 | 
| --- a/Source/core/platform/image-decoders/ImageDecoder.cpp | 
| +++ b/Source/core/platform/image-decoders/ImageDecoder.cpp | 
| @@ -227,4 +227,84 @@ int ImageDecoder::scaledY(int origY, int searchStart) | 
| return getScaledValue<Exact>(m_scaledRows, origY, searchStart); | 
| } | 
| +void ImageDecoder::clearFrameBufferCache(size_t clearExceptFrame) | 
| 
Alpha Left Google
2013/05/22 20:18:09
I'm not sure you should move this to the base clas
 
Xianzhu
2013/05/22 23:43:29
I thought as the disposal methods are defined in c
 | 
| +{ | 
| + // Don't clear if there is no or only one frame. | 
| + if (m_frameBufferCache.size() <= 1) | 
| + return; | 
| + | 
| + // 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. | 
| + // 3. We don't clear empty frames or the frame we're currently decoding; | 
| + // All other frames can be cleared. | 
| + size_t frameToBeRequired; | 
| + 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::FrameComplete); | 
| 
Xianzhu
2013/05/22 23:43:29
Changed the above condition to ...== ImageFrame::F
 | 
| + } else { | 
| + // initFrameBuffer() has already been called for this frame. | 
| + frameToBeRequired = notFound; | 
| + } | 
| + | 
| + for (size_t i = 0; i < m_frameBufferCache.size(); ++i) { | 
| + if (i == clearExceptFrame || i == frameToBeRequired) // 1 and 2. | 
| + continue; | 
| + | 
| + ImageFrame& frame = m_frameBufferCache[i]; | 
| + if (frame.status() == ImageFrame::FrameComplete) // 3. | 
| 
Alpha Left Google
2013/05/22 20:18:09
Using this condition you'll hit a corner case wher
 
Xianzhu
2013/05/22 23:43:29
Changed to clear partial frames. However, I'm not
 
Xianzhu
2013/05/23 00:33:49
Never mind this question. I know the answer now :)
 | 
| + frame.clearPixelData(); | 
| + } | 
| +} | 
| + | 
| +size_t ImageDecoder::findRequiredPreviousFrame(size_t frameIndex) | 
| +{ | 
| + 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. | 
| + // | 
| + // 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. (If the | 
| + // first frame specifies this method, it will get treated like | 
| + // DisposeOverwriteBgcolor below and reset to a completely empty image.) | 
| + size_t prevFrame = frameIndex - 1; | 
| + const ImageFrame* prevBuffer = &m_frameBufferCache[prevFrame]; | 
| + ImageFrame::FrameDisposalMethod prevMethod = prevBuffer->disposalMethod(); | 
| + while (prevFrame && (prevMethod == ImageFrame::DisposeOverwritePrevious)) { | 
| + prevBuffer = &m_frameBufferCache[--prevFrame]; | 
| + prevMethod = prevBuffer->disposalMethod(); | 
| + } | 
| + | 
| + if (prevMethod == ImageFrame::DisposeNotSpecified || prevMethod == ImageFrame::DisposeKeep) { | 
| + // prevFrame will be used as the starting state for this frame. | 
| + return prevFrame; | 
| + } | 
| + | 
| + if (!prevFrame) { | 
| + // The first frame whose disposal method is DisposeOverwriteBgColor or | 
| + // DisposeOverritePrevious will be reset to background despite its size. | 
| + return notFound; | 
| + } | 
| + | 
| + ASSERT(prevMethod == ImageFrame::DisposeOverwriteBgcolor); | 
| + const IntRect& prevRect = prevBuffer->originalFrameRect(); | 
| + const IntSize& bufferSize = scaledSize(); | 
| + if (prevRect.contains(IntRect(IntPoint(), scaledSize()))) { | 
| + // prevFrame covering the whole image will be reset to background, | 
| + return notFound; | 
| + } | 
| + | 
| + // prevFrame only clears part of the image to background, so it contributes | 
| + // to the starting state of this frame. | 
| + return prevFrame; | 
| +} | 
| + | 
| } // namespace WebCore |