Index: Source/core/platform/image-decoders/webp/WEBPImageDecoder.cpp |
diff --git a/Source/core/platform/image-decoders/webp/WEBPImageDecoder.cpp b/Source/core/platform/image-decoders/webp/WEBPImageDecoder.cpp |
index 12c15e1c113a74e61b92076dc565d6f1d7b1958d..3c3ec9c44c489be9a00bc4142038e95b177ead60 100644 |
--- a/Source/core/platform/image-decoders/webp/WEBPImageDecoder.cpp |
+++ b/Source/core/platform/image-decoders/webp/WEBPImageDecoder.cpp |
@@ -127,13 +127,11 @@ ImageFrame* WEBPImageDecoder::frameBufferAtIndex(size_t index) |
ASSERT(m_demux); |
for (size_t i = framesToDecode.size(); i > 0; --i) { |
size_t frameIndex = framesToDecode[i - 1]; |
+ if ((m_formatFlags & ANIMATION_FLAG) && !initFrameBuffer(frameIndex)) |
+ return 0; |
WebPIterator webpFrame; |
if (!WebPDemuxGetFrame(m_demux, frameIndex + 1, &webpFrame)) |
return 0; |
- if ((m_formatFlags & ANIMATION_FLAG) && !initFrameBuffer(webpFrame, frameIndex)) { |
- WebPDemuxReleaseIterator(&webpFrame); |
- return 0; |
- } |
PlatformInstrumentation::willDecodeImage("WEBP"); |
decode(webpFrame.fragment.bytes, webpFrame.fragment.size, false, frameIndex); |
PlatformInstrumentation::didDecodeImage(); |
@@ -247,36 +245,34 @@ bool WEBPImageDecoder::updateDemuxer() |
ASSERT(animatedFrame.complete == 1); |
m_frameBufferCache[i].setDuration(animatedFrame.duration); |
m_frameBufferCache[i].setDisposalMethod(animatedFrame.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND ? ImageFrame::DisposeOverwriteBgcolor : ImageFrame::DisposeKeep); |
+ m_frameBufferCache[i].setAlphaBlendSource(animatedFrame.blend_method == WEBP_MUX_BLEND ? ImageFrame::BlendAtopPreviousFrame : ImageFrame::BlendAtopBgcolor); |
+ IntRect frameRect(animatedFrame.x_offset, animatedFrame.y_offset, animatedFrame.width, animatedFrame.height); |
+ // Make sure the frameRect doesn't extend outside the buffer. |
+ if (frameRect.maxX() > size().width()) |
+ frameRect.setWidth(size().width() - animatedFrame.x_offset); |
+ if (frameRect.maxY() > size().height()) |
+ frameRect.setHeight(size().height() - animatedFrame.y_offset); |
+ m_frameBufferCache[i].setOriginalFrameRect(frameRect); |
+ m_frameBufferCache[i].setRequiredPreviousFrameIndex(findRequiredPreviousFrame(i, !animatedFrame.has_alpha)); |
WebPDemuxReleaseIterator(&animatedFrame); |
- m_frameBufferCache[i].setRequiredPreviousFrameIndex(findRequiredPreviousFrame(i)); |
} |
} |
return true; |
} |
-bool WEBPImageDecoder::initFrameBuffer(const WebPIterator& frame, size_t frameIndex) |
+bool WEBPImageDecoder::initFrameBuffer(size_t frameIndex) |
{ |
ImageFrame& buffer = m_frameBufferCache[frameIndex]; |
if (buffer.status() != ImageFrame::FrameEmpty) // Already initialized. |
return true; |
- // Initialize the frame rect in our buffer. |
- IntRect frameRect(frame.x_offset, frame.y_offset, frame.width, frame.height); |
- |
- // Make sure the frameRect doesn't extend outside the buffer. |
- if (frameRect.maxX() > size().width()) |
- frameRect.setWidth(size().width() - frame.x_offset); |
- if (frameRect.maxY() > size().height()) |
- frameRect.setHeight(size().height() - frame.y_offset); |
- buffer.setOriginalFrameRect(frameRect); |
- |
const size_t requiredPreviousFrameIndex = buffer.requiredPreviousFrameIndex(); |
if (requiredPreviousFrameIndex == notFound) { |
// This frame doesn't rely on any previous data. |
if (!buffer.setSize(size().width(), size().height())) |
return setFailed(); |
- m_frameBackgroundHasAlpha = !frameRect.contains(IntRect(IntPoint(), size())); |
+ m_frameBackgroundHasAlpha = !buffer.originalFrameRect().contains(IntRect(IntPoint(), size())); |
} else { |
const ImageFrame& prevBuffer = m_frameBufferCache[requiredPreviousFrameIndex]; |
ASSERT(prevBuffer.status() == ImageFrame::FrameComplete); |
@@ -415,15 +411,15 @@ void WEBPImageDecoder::applyPostProcessing(size_t frameIndex) |
// During the decoding of current frame, we may have set some pixels to be transparent (i.e. alpha < 255). |
// However, the value of each of these pixels should have been determined by blending it against the value |
- // of that pixel in the previous frame. So, we correct these pixels based on disposal method of the previous |
- // frame and the previous frame buffer. |
+ // of that pixel in the previous frame if alpha blend source was 'BlendAtopPreviousFrame'. So, we correct these |
+ // pixels based on disposal method of the previous frame and the previous frame buffer. |
// FIXME: This could be avoided if libwebp decoder had an API that used the previous required frame |
// to do the alpha-blending by itself. |
- if ((m_formatFlags & ANIMATION_FLAG) && frameIndex) { |
+ if ((m_formatFlags & ANIMATION_FLAG) && frameIndex && buffer.alphaBlendSource() == ImageFrame::BlendAtopPreviousFrame && buffer.requiredPreviousFrameIndex() != notFound) { |
ImageFrame& prevBuffer = m_frameBufferCache[frameIndex - 1]; |
- ImageFrame::FrameDisposalMethod prevMethod = prevBuffer.disposalMethod(); |
- if (prevMethod == ImageFrame::DisposeKeep) { // Restore transparent pixels to pixels in previous canvas. |
- ASSERT(prevBuffer.status() == ImageFrame::FrameComplete); |
+ ASSERT(prevBuffer.status() == ImageFrame::FrameComplete); |
+ ImageFrame::DisposalMethod prevDisposalMethod = prevBuffer.disposalMethod(); |
+ if (prevDisposalMethod == ImageFrame::DisposeKeep) { // Restore transparent pixels to pixels in previous canvas. |
for (int y = m_decodedHeight; y < decodedHeight; ++y) { |
const int canvasY = top + y; |
for (int x = 0; x < width; ++x) { |
@@ -437,9 +433,7 @@ void WEBPImageDecoder::applyPostProcessing(size_t frameIndex) |
} |
} |
} |
- } else if (prevMethod == ImageFrame::DisposeOverwriteBgcolor && buffer.requiredPreviousFrameIndex() != notFound) { |
- // Note: if the requiredPreviousFrameIndex is |notFound|, there's nothing to do. |
- ASSERT(prevBuffer.status() == ImageFrame::FrameComplete); |
+ } else if (prevDisposalMethod == ImageFrame::DisposeOverwriteBgcolor) { |
const IntRect& prevRect = prevBuffer.originalFrameRect(); |
// We need to restore transparent pixels to as they were just after initFrame() call. That is: |
// * Transparent if it belongs to prevRect <-- This is a no-op. |