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 |