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 |