| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2010 Google Inc. All rights reserved. | 2 * Copyright (C) 2010 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * | 7 * |
| 8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 120 Vector<size_t> framesToDecode; | 120 Vector<size_t> framesToDecode; |
| 121 size_t frameToDecode = index; | 121 size_t frameToDecode = index; |
| 122 do { | 122 do { |
| 123 framesToDecode.append(frameToDecode); | 123 framesToDecode.append(frameToDecode); |
| 124 frameToDecode = m_frameBufferCache[frameToDecode].requiredPreviousFr
ameIndex(); | 124 frameToDecode = m_frameBufferCache[frameToDecode].requiredPreviousFr
ameIndex(); |
| 125 } while (frameToDecode != notFound && m_frameBufferCache[frameToDecode].
status() != ImageFrame::FrameComplete); | 125 } while (frameToDecode != notFound && m_frameBufferCache[frameToDecode].
status() != ImageFrame::FrameComplete); |
| 126 | 126 |
| 127 ASSERT(m_demux); | 127 ASSERT(m_demux); |
| 128 for (size_t i = framesToDecode.size(); i > 0; --i) { | 128 for (size_t i = framesToDecode.size(); i > 0; --i) { |
| 129 size_t frameIndex = framesToDecode[i - 1]; | 129 size_t frameIndex = framesToDecode[i - 1]; |
| 130 if ((m_formatFlags & ANIMATION_FLAG) && !initFrameBuffer(frameIndex)
) |
| 131 return 0; |
| 130 WebPIterator webpFrame; | 132 WebPIterator webpFrame; |
| 131 if (!WebPDemuxGetFrame(m_demux, frameIndex + 1, &webpFrame)) | 133 if (!WebPDemuxGetFrame(m_demux, frameIndex + 1, &webpFrame)) |
| 132 return 0; | 134 return 0; |
| 133 if ((m_formatFlags & ANIMATION_FLAG) && !initFrameBuffer(webpFrame,
frameIndex)) { | |
| 134 WebPDemuxReleaseIterator(&webpFrame); | |
| 135 return 0; | |
| 136 } | |
| 137 PlatformInstrumentation::willDecodeImage("WEBP"); | 135 PlatformInstrumentation::willDecodeImage("WEBP"); |
| 138 decode(webpFrame.fragment.bytes, webpFrame.fragment.size, false, fra
meIndex); | 136 decode(webpFrame.fragment.bytes, webpFrame.fragment.size, false, fra
meIndex); |
| 139 PlatformInstrumentation::didDecodeImage(); | 137 PlatformInstrumentation::didDecodeImage(); |
| 140 WebPDemuxReleaseIterator(&webpFrame); | 138 WebPDemuxReleaseIterator(&webpFrame); |
| 141 | 139 |
| 142 // We need more data to continue decoding. | 140 // We need more data to continue decoding. |
| 143 if (m_frameBufferCache[frameIndex].status() != ImageFrame::FrameComp
lete) | 141 if (m_frameBufferCache[frameIndex].status() != ImageFrame::FrameComp
lete) |
| 144 break; | 142 break; |
| 145 } | 143 } |
| 146 | 144 |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 240 if (!hasAnimation) { | 238 if (!hasAnimation) { |
| 241 ASSERT(!i); | 239 ASSERT(!i); |
| 242 m_frameBufferCache[i].setRequiredPreviousFrameIndex(notFound); | 240 m_frameBufferCache[i].setRequiredPreviousFrameIndex(notFound); |
| 243 continue; | 241 continue; |
| 244 } | 242 } |
| 245 WebPIterator animatedFrame; | 243 WebPIterator animatedFrame; |
| 246 WebPDemuxGetFrame(m_demux, i + 1, &animatedFrame); | 244 WebPDemuxGetFrame(m_demux, i + 1, &animatedFrame); |
| 247 ASSERT(animatedFrame.complete == 1); | 245 ASSERT(animatedFrame.complete == 1); |
| 248 m_frameBufferCache[i].setDuration(animatedFrame.duration); | 246 m_frameBufferCache[i].setDuration(animatedFrame.duration); |
| 249 m_frameBufferCache[i].setDisposalMethod(animatedFrame.dispose_method
== WEBP_MUX_DISPOSE_BACKGROUND ? ImageFrame::DisposeOverwriteBgcolor : ImageFra
me::DisposeKeep); | 247 m_frameBufferCache[i].setDisposalMethod(animatedFrame.dispose_method
== WEBP_MUX_DISPOSE_BACKGROUND ? ImageFrame::DisposeOverwriteBgcolor : ImageFra
me::DisposeKeep); |
| 248 m_frameBufferCache[i].setAlphaBlendSource(animatedFrame.blend_method
== WEBP_MUX_BLEND ? ImageFrame::BlendAtopPreviousFrame : ImageFrame::BlendAtopB
gcolor); |
| 249 IntRect frameRect(animatedFrame.x_offset, animatedFrame.y_offset, an
imatedFrame.width, animatedFrame.height); |
| 250 // Make sure the frameRect doesn't extend outside the buffer. |
| 251 if (frameRect.maxX() > size().width()) |
| 252 frameRect.setWidth(size().width() - animatedFrame.x_offset); |
| 253 if (frameRect.maxY() > size().height()) |
| 254 frameRect.setHeight(size().height() - animatedFrame.y_offset); |
| 255 m_frameBufferCache[i].setOriginalFrameRect(frameRect); |
| 256 m_frameBufferCache[i].setRequiredPreviousFrameIndex(findRequiredPrev
iousFrame(i, !animatedFrame.has_alpha)); |
| 250 WebPDemuxReleaseIterator(&animatedFrame); | 257 WebPDemuxReleaseIterator(&animatedFrame); |
| 251 m_frameBufferCache[i].setRequiredPreviousFrameIndex(findRequiredPrev
iousFrame(i)); | |
| 252 } | 258 } |
| 253 } | 259 } |
| 254 | 260 |
| 255 return true; | 261 return true; |
| 256 } | 262 } |
| 257 | 263 |
| 258 bool WEBPImageDecoder::initFrameBuffer(const WebPIterator& frame, size_t frameIn
dex) | 264 bool WEBPImageDecoder::initFrameBuffer(size_t frameIndex) |
| 259 { | 265 { |
| 260 ImageFrame& buffer = m_frameBufferCache[frameIndex]; | 266 ImageFrame& buffer = m_frameBufferCache[frameIndex]; |
| 261 if (buffer.status() != ImageFrame::FrameEmpty) // Already initialized. | 267 if (buffer.status() != ImageFrame::FrameEmpty) // Already initialized. |
| 262 return true; | 268 return true; |
| 263 | 269 |
| 264 // Initialize the frame rect in our buffer. | |
| 265 IntRect frameRect(frame.x_offset, frame.y_offset, frame.width, frame.height)
; | |
| 266 | |
| 267 // Make sure the frameRect doesn't extend outside the buffer. | |
| 268 if (frameRect.maxX() > size().width()) | |
| 269 frameRect.setWidth(size().width() - frame.x_offset); | |
| 270 if (frameRect.maxY() > size().height()) | |
| 271 frameRect.setHeight(size().height() - frame.y_offset); | |
| 272 buffer.setOriginalFrameRect(frameRect); | |
| 273 | |
| 274 const size_t requiredPreviousFrameIndex = buffer.requiredPreviousFrameIndex(
); | 270 const size_t requiredPreviousFrameIndex = buffer.requiredPreviousFrameIndex(
); |
| 275 if (requiredPreviousFrameIndex == notFound) { | 271 if (requiredPreviousFrameIndex == notFound) { |
| 276 // This frame doesn't rely on any previous data. | 272 // This frame doesn't rely on any previous data. |
| 277 if (!buffer.setSize(size().width(), size().height())) | 273 if (!buffer.setSize(size().width(), size().height())) |
| 278 return setFailed(); | 274 return setFailed(); |
| 279 m_frameBackgroundHasAlpha = !frameRect.contains(IntRect(IntPoint(), size
())); | 275 m_frameBackgroundHasAlpha = !buffer.originalFrameRect().contains(IntRect
(IntPoint(), size())); |
| 280 } else { | 276 } else { |
| 281 const ImageFrame& prevBuffer = m_frameBufferCache[requiredPreviousFrameI
ndex]; | 277 const ImageFrame& prevBuffer = m_frameBufferCache[requiredPreviousFrameI
ndex]; |
| 282 ASSERT(prevBuffer.status() == ImageFrame::FrameComplete); | 278 ASSERT(prevBuffer.status() == ImageFrame::FrameComplete); |
| 283 | 279 |
| 284 // Preserve the last frame as the starting state for this frame. | 280 // Preserve the last frame as the starting state for this frame. |
| 285 if (!buffer.copyBitmapData(prevBuffer)) | 281 if (!buffer.copyBitmapData(prevBuffer)) |
| 286 return setFailed(); | 282 return setFailed(); |
| 287 | 283 |
| 288 if (prevBuffer.disposalMethod() == ImageFrame::DisposeOverwriteBgcolor)
{ | 284 if (prevBuffer.disposalMethod() == ImageFrame::DisposeOverwriteBgcolor)
{ |
| 289 // We want to clear the previous frame to transparent, without | 285 // We want to clear the previous frame to transparent, without |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 408 for (int x = 0; x < width; ++x, pixel += 4) { | 404 for (int x = 0; x < width; ++x, pixel += 4) { |
| 409 const int canvasX = left + x; | 405 const int canvasX = left + x; |
| 410 buffer.setRGBA(canvasX, canvasY, pixel[0], pixel[1], pixel[2], p
ixel[3]); | 406 buffer.setRGBA(canvasX, canvasY, pixel[0], pixel[1], pixel[2], p
ixel[3]); |
| 411 } | 407 } |
| 412 } | 408 } |
| 413 } | 409 } |
| 414 #endif // USE(QCMSLIB) | 410 #endif // USE(QCMSLIB) |
| 415 | 411 |
| 416 // During the decoding of current frame, we may have set some pixels to be t
ransparent (i.e. alpha < 255). | 412 // During the decoding of current frame, we may have set some pixels to be t
ransparent (i.e. alpha < 255). |
| 417 // However, the value of each of these pixels should have been determined by
blending it against the value | 413 // However, the value of each of these pixels should have been determined by
blending it against the value |
| 418 // of that pixel in the previous frame. So, we correct these pixels based on
disposal method of the previous | 414 // of that pixel in the previous frame if alpha blend source was 'BlendAtopP
reviousFrame'. So, we correct these |
| 419 // frame and the previous frame buffer. | 415 // pixels based on disposal method of the previous frame and the previous fr
ame buffer. |
| 420 // FIXME: This could be avoided if libwebp decoder had an API that used the
previous required frame | 416 // FIXME: This could be avoided if libwebp decoder had an API that used the
previous required frame |
| 421 // to do the alpha-blending by itself. | 417 // to do the alpha-blending by itself. |
| 422 if ((m_formatFlags & ANIMATION_FLAG) && frameIndex) { | 418 if ((m_formatFlags & ANIMATION_FLAG) && frameIndex && buffer.alphaBlendSourc
e() == ImageFrame::BlendAtopPreviousFrame && buffer.requiredPreviousFrameIndex()
!= notFound) { |
| 423 ImageFrame& prevBuffer = m_frameBufferCache[frameIndex - 1]; | 419 ImageFrame& prevBuffer = m_frameBufferCache[frameIndex - 1]; |
| 424 ImageFrame::FrameDisposalMethod prevMethod = prevBuffer.disposalMethod()
; | 420 ASSERT(prevBuffer.status() == ImageFrame::FrameComplete); |
| 425 if (prevMethod == ImageFrame::DisposeKeep) { // Restore transparent pixe
ls to pixels in previous canvas. | 421 ImageFrame::DisposalMethod prevDisposalMethod = prevBuffer.disposalMetho
d(); |
| 426 ASSERT(prevBuffer.status() == ImageFrame::FrameComplete); | 422 if (prevDisposalMethod == ImageFrame::DisposeKeep) { // Restore transpar
ent pixels to pixels in previous canvas. |
| 427 for (int y = m_decodedHeight; y < decodedHeight; ++y) { | 423 for (int y = m_decodedHeight; y < decodedHeight; ++y) { |
| 428 const int canvasY = top + y; | 424 const int canvasY = top + y; |
| 429 for (int x = 0; x < width; ++x) { | 425 for (int x = 0; x < width; ++x) { |
| 430 const int canvasX = left + x; | 426 const int canvasX = left + x; |
| 431 ImageFrame::PixelData& pixel = *buffer.getAddr(canvasX, canv
asY); | 427 ImageFrame::PixelData& pixel = *buffer.getAddr(canvasX, canv
asY); |
| 432 // FIXME: Use alpha-blending when alpha is between 0 and 255
. | 428 // FIXME: Use alpha-blending when alpha is between 0 and 255
. |
| 433 // Alpha-blending is being implemented in: https://bugs.webk
it.org/show_bug.cgi?id=17022 | 429 // Alpha-blending is being implemented in: https://bugs.webk
it.org/show_bug.cgi?id=17022 |
| 434 if (!((pixel >> SK_A32_SHIFT) & 0xff)) { | 430 if (!((pixel >> SK_A32_SHIFT) & 0xff)) { |
| 435 ImageFrame::PixelData prevPixel = *prevBuffer.getAddr(ca
nvasX, canvasY); | 431 ImageFrame::PixelData prevPixel = *prevBuffer.getAddr(ca
nvasX, canvasY); |
| 436 pixel = prevPixel; | 432 pixel = prevPixel; |
| 437 } | 433 } |
| 438 } | 434 } |
| 439 } | 435 } |
| 440 } else if (prevMethod == ImageFrame::DisposeOverwriteBgcolor && buffer.r
equiredPreviousFrameIndex() != notFound) { | 436 } else if (prevDisposalMethod == ImageFrame::DisposeOverwriteBgcolor) { |
| 441 // Note: if the requiredPreviousFrameIndex is |notFound|, there's no
thing to do. | |
| 442 ASSERT(prevBuffer.status() == ImageFrame::FrameComplete); | |
| 443 const IntRect& prevRect = prevBuffer.originalFrameRect(); | 437 const IntRect& prevRect = prevBuffer.originalFrameRect(); |
| 444 // We need to restore transparent pixels to as they were just after
initFrame() call. That is: | 438 // We need to restore transparent pixels to as they were just after
initFrame() call. That is: |
| 445 // * Transparent if it belongs to prevRect <-- This is a no-op. | 439 // * Transparent if it belongs to prevRect <-- This is a no-op. |
| 446 // * Pixel in the previous canvas otherwise <-- Need to restore. | 440 // * Pixel in the previous canvas otherwise <-- Need to restore. |
| 447 for (int y = m_decodedHeight; y < decodedHeight; ++y) { | 441 for (int y = m_decodedHeight; y < decodedHeight; ++y) { |
| 448 const int canvasY = top + y; | 442 const int canvasY = top + y; |
| 449 for (int x = 0; x < width; ++x) { | 443 for (int x = 0; x < width; ++x) { |
| 450 const int canvasX = left + x; | 444 const int canvasX = left + x; |
| 451 ImageFrame::PixelData& pixel = *buffer.getAddr(canvasX, canv
asY); | 445 ImageFrame::PixelData& pixel = *buffer.getAddr(canvasX, canv
asY); |
| 452 // FIXME: Use alpha-blending when alpha is between 0 and 255
. | 446 // FIXME: Use alpha-blending when alpha is between 0 and 255
. |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 531 case VP8_STATUS_SUSPENDED: | 525 case VP8_STATUS_SUSPENDED: |
| 532 applyPostProcessing(frameIndex); | 526 applyPostProcessing(frameIndex); |
| 533 return false; | 527 return false; |
| 534 default: | 528 default: |
| 535 clear(); | 529 clear(); |
| 536 return setFailed(); | 530 return setFailed(); |
| 537 } | 531 } |
| 538 } | 532 } |
| 539 | 533 |
| 540 } // namespace WebCore | 534 } // namespace WebCore |
| OLD | NEW |