| 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 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 243 #endif | 243 #endif |
| 244 } | 244 } |
| 245 | 245 |
| 246 ASSERT(isDecodedSizeAvailable()); | 246 ASSERT(isDecodedSizeAvailable()); |
| 247 return true; | 247 return true; |
| 248 } | 248 } |
| 249 | 249 |
| 250 bool WEBPImageDecoder::initFrameBuffer(size_t frameIndex) | 250 bool WEBPImageDecoder::initFrameBuffer(size_t frameIndex) |
| 251 { | 251 { |
| 252 ImageFrame& buffer = m_frameBufferCache[frameIndex]; | 252 ImageFrame& buffer = m_frameBufferCache[frameIndex]; |
| 253 if (buffer.status() != ImageFrame::FrameEmpty) // Already initialized. | 253 if (buffer.getStatus() != ImageFrame::FrameEmpty) // Already initialized. |
| 254 return true; | 254 return true; |
| 255 | 255 |
| 256 const size_t requiredPreviousFrameIndex = buffer.requiredPreviousFrameIndex(
); | 256 const size_t requiredPreviousFrameIndex = buffer.requiredPreviousFrameIndex(
); |
| 257 if (requiredPreviousFrameIndex == kNotFound) { | 257 if (requiredPreviousFrameIndex == kNotFound) { |
| 258 // This frame doesn't rely on any previous data. | 258 // This frame doesn't rely on any previous data. |
| 259 if (!buffer.setSize(size().width(), size().height())) | 259 if (!buffer.setSize(size().width(), size().height())) |
| 260 return setFailed(); | 260 return setFailed(); |
| 261 m_frameBackgroundHasAlpha = !buffer.originalFrameRect().contains(IntRect
(IntPoint(), size())); | 261 m_frameBackgroundHasAlpha = !buffer.originalFrameRect().contains(IntRect
(IntPoint(), size())); |
| 262 } else { | 262 } else { |
| 263 const ImageFrame& prevBuffer = m_frameBufferCache[requiredPreviousFrameI
ndex]; | 263 const ImageFrame& prevBuffer = m_frameBufferCache[requiredPreviousFrameI
ndex]; |
| 264 ASSERT(prevBuffer.status() == ImageFrame::FrameComplete); | 264 ASSERT(prevBuffer.getStatus() == ImageFrame::FrameComplete); |
| 265 | 265 |
| 266 // Preserve the last frame as the starting state for this frame. | 266 // Preserve the last frame as the starting state for this frame. |
| 267 if (!buffer.copyBitmapData(prevBuffer)) | 267 if (!buffer.copyBitmapData(prevBuffer)) |
| 268 return setFailed(); | 268 return setFailed(); |
| 269 | 269 |
| 270 if (prevBuffer.disposalMethod() == ImageFrame::DisposeOverwriteBgcolor)
{ | 270 if (prevBuffer.getDisposalMethod() == ImageFrame::DisposeOverwriteBgcolo
r) { |
| 271 // We want to clear the previous frame to transparent, without | 271 // We want to clear the previous frame to transparent, without |
| 272 // affecting pixels in the image outside of the frame. | 272 // affecting pixels in the image outside of the frame. |
| 273 const IntRect& prevRect = prevBuffer.originalFrameRect(); | 273 const IntRect& prevRect = prevBuffer.originalFrameRect(); |
| 274 ASSERT(!prevRect.contains(IntRect(IntPoint(), size()))); | 274 ASSERT(!prevRect.contains(IntRect(IntPoint(), size()))); |
| 275 buffer.zeroFillFrameRect(prevRect); | 275 buffer.zeroFillFrameRect(prevRect); |
| 276 } | 276 } |
| 277 | 277 |
| 278 m_frameBackgroundHasAlpha = prevBuffer.hasAlpha() || (prevBuffer.disposa
lMethod() == ImageFrame::DisposeOverwriteBgcolor); | 278 m_frameBackgroundHasAlpha = prevBuffer.hasAlpha() || (prevBuffer.getDisp
osalMethod() == ImageFrame::DisposeOverwriteBgcolor); |
| 279 } | 279 } |
| 280 | 280 |
| 281 buffer.setStatus(ImageFrame::FramePartial); | 281 buffer.setStatus(ImageFrame::FramePartial); |
| 282 // The buffer is transparent outside the decoded area while the image is loa
ding. | 282 // The buffer is transparent outside the decoded area while the image is loa
ding. |
| 283 // The correct value of 'hasAlpha' for the frame will be set when it is full
y decoded. | 283 // The correct value of 'hasAlpha' for the frame will be set when it is full
y decoded. |
| 284 buffer.setHasAlpha(true); | 284 buffer.setHasAlpha(true); |
| 285 return true; | 285 return true; |
| 286 } | 286 } |
| 287 | 287 |
| 288 size_t WEBPImageDecoder::clearCacheExceptFrame(size_t clearExceptFrame) | 288 size_t WEBPImageDecoder::clearCacheExceptFrame(size_t clearExceptFrame) |
| 289 { | 289 { |
| 290 // If |clearExceptFrame| has status FrameComplete, we preserve that frame. | 290 // If |clearExceptFrame| has status FrameComplete, we preserve that frame. |
| 291 // Otherwise, we preserve a previous frame with status FrameComplete whose d
ata is required | 291 // Otherwise, we preserve a previous frame with status FrameComplete whose d
ata is required |
| 292 // to decode |clearExceptFrame|, either in initFrameBuffer() or ApplyPostPro
cessing(). | 292 // to decode |clearExceptFrame|, either in initFrameBuffer() or ApplyPostPro
cessing(). |
| 293 // All other frames can be cleared. | 293 // All other frames can be cleared. |
| 294 while ((clearExceptFrame < m_frameBufferCache.size()) && (m_frameBufferCache
[clearExceptFrame].status() != ImageFrame::FrameComplete)) | 294 while ((clearExceptFrame < m_frameBufferCache.size()) && (m_frameBufferCache
[clearExceptFrame].getStatus() != ImageFrame::FrameComplete)) |
| 295 clearExceptFrame = m_frameBufferCache[clearExceptFrame].requiredPrevious
FrameIndex(); | 295 clearExceptFrame = m_frameBufferCache[clearExceptFrame].requiredPrevious
FrameIndex(); |
| 296 | 296 |
| 297 return ImageDecoder::clearCacheExceptFrame(clearExceptFrame); | 297 return ImageDecoder::clearCacheExceptFrame(clearExceptFrame); |
| 298 } | 298 } |
| 299 | 299 |
| 300 void WEBPImageDecoder::clearFrameBuffer(size_t frameIndex) | 300 void WEBPImageDecoder::clearFrameBuffer(size_t frameIndex) |
| 301 { | 301 { |
| 302 if (m_demux && m_demuxState >= WEBP_DEMUX_PARSED_HEADER && m_frameBufferCach
e[frameIndex].status() == ImageFrame::FramePartial) { | 302 if (m_demux && m_demuxState >= WEBP_DEMUX_PARSED_HEADER && m_frameBufferCach
e[frameIndex].getStatus() == ImageFrame::FramePartial) { |
| 303 // Clear the decoder state so that this partial frame can be decoded aga
in when requested. | 303 // Clear the decoder state so that this partial frame can be decoded aga
in when requested. |
| 304 clearDecoder(); | 304 clearDecoder(); |
| 305 } | 305 } |
| 306 ImageDecoder::clearFrameBuffer(frameIndex); | 306 ImageDecoder::clearFrameBuffer(frameIndex); |
| 307 } | 307 } |
| 308 | 308 |
| 309 #if USE(QCMSLIB) | 309 #if USE(QCMSLIB) |
| 310 | 310 |
| 311 void WEBPImageDecoder::clearColorTransform() | 311 void WEBPImageDecoder::clearColorTransform() |
| 312 { | 312 { |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 401 } | 401 } |
| 402 } | 402 } |
| 403 #endif // USE(QCMSLIB) | 403 #endif // USE(QCMSLIB) |
| 404 | 404 |
| 405 // During the decoding of current frame, we may have set some pixels to be t
ransparent (i.e. alpha < 255). | 405 // During the decoding of current frame, we may have set some pixels to be t
ransparent (i.e. alpha < 255). |
| 406 // However, the value of each of these pixels should have been determined by
blending it against the value | 406 // However, the value of each of these pixels should have been determined by
blending it against the value |
| 407 // of that pixel in the previous frame if alpha blend source was 'BlendAtopP
reviousFrame'. So, we correct these | 407 // of that pixel in the previous frame if alpha blend source was 'BlendAtopP
reviousFrame'. So, we correct these |
| 408 // pixels based on disposal method of the previous frame and the previous fr
ame buffer. | 408 // pixels based on disposal method of the previous frame and the previous fr
ame buffer. |
| 409 // FIXME: This could be avoided if libwebp decoder had an API that used the
previous required frame | 409 // FIXME: This could be avoided if libwebp decoder had an API that used the
previous required frame |
| 410 // to do the alpha-blending by itself. | 410 // to do the alpha-blending by itself. |
| 411 if ((m_formatFlags & ANIMATION_FLAG) && frameIndex && buffer.alphaBlendSourc
e() == ImageFrame::BlendAtopPreviousFrame && buffer.requiredPreviousFrameIndex()
!= kNotFound) { | 411 if ((m_formatFlags & ANIMATION_FLAG) && frameIndex && buffer.getAlphaBlendSo
urce() == ImageFrame::BlendAtopPreviousFrame && buffer.requiredPreviousFrameInde
x() != kNotFound) { |
| 412 ImageFrame& prevBuffer = m_frameBufferCache[frameIndex - 1]; | 412 ImageFrame& prevBuffer = m_frameBufferCache[frameIndex - 1]; |
| 413 ASSERT(prevBuffer.status() == ImageFrame::FrameComplete); | 413 ASSERT(prevBuffer.getStatus() == ImageFrame::FrameComplete); |
| 414 ImageFrame::DisposalMethod prevDisposalMethod = prevBuffer.disposalMetho
d(); | 414 ImageFrame::DisposalMethod prevDisposalMethod = prevBuffer.getDisposalMe
thod(); |
| 415 if (prevDisposalMethod == ImageFrame::DisposeKeep) { // Blend transparen
t pixels with pixels in previous canvas. | 415 if (prevDisposalMethod == ImageFrame::DisposeKeep) { // Blend transparen
t pixels with pixels in previous canvas. |
| 416 for (int y = m_decodedHeight; y < decodedHeight; ++y) { | 416 for (int y = m_decodedHeight; y < decodedHeight; ++y) { |
| 417 m_blendFunction(buffer, prevBuffer, top + y, left, width); | 417 m_blendFunction(buffer, prevBuffer, top + y, left, width); |
| 418 } | 418 } |
| 419 } else if (prevDisposalMethod == ImageFrame::DisposeOverwriteBgcolor) { | 419 } else if (prevDisposalMethod == ImageFrame::DisposeOverwriteBgcolor) { |
| 420 const IntRect& prevRect = prevBuffer.originalFrameRect(); | 420 const IntRect& prevRect = prevBuffer.originalFrameRect(); |
| 421 // We need to blend a transparent pixel with its value just after in
itFrame() call. That is: | 421 // We need to blend a transparent pixel with its value just after in
itFrame() call. That is: |
| 422 // * Blend with fully transparent pixel if it belongs to prevRect
<-- This is a no-op. | 422 // * Blend with fully transparent pixel if it belongs to prevRect
<-- This is a no-op. |
| 423 // * Blend with the pixel in the previous canvas otherwise <-- Nee
ds alpha-blending. | 423 // * Blend with the pixel in the previous canvas otherwise <-- Nee
ds alpha-blending. |
| 424 for (int y = m_decodedHeight; y < decodedHeight; ++y) { | 424 for (int y = m_decodedHeight; y < decodedHeight; ++y) { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 467 void WEBPImageDecoder::decode(size_t index) | 467 void WEBPImageDecoder::decode(size_t index) |
| 468 { | 468 { |
| 469 if (failed()) | 469 if (failed()) |
| 470 return; | 470 return; |
| 471 | 471 |
| 472 Vector<size_t> framesToDecode; | 472 Vector<size_t> framesToDecode; |
| 473 size_t frameToDecode = index; | 473 size_t frameToDecode = index; |
| 474 do { | 474 do { |
| 475 framesToDecode.append(frameToDecode); | 475 framesToDecode.append(frameToDecode); |
| 476 frameToDecode = m_frameBufferCache[frameToDecode].requiredPreviousFrameI
ndex(); | 476 frameToDecode = m_frameBufferCache[frameToDecode].requiredPreviousFrameI
ndex(); |
| 477 } while (frameToDecode != kNotFound && m_frameBufferCache[frameToDecode].sta
tus() != ImageFrame::FrameComplete); | 477 } while (frameToDecode != kNotFound && m_frameBufferCache[frameToDecode].get
Status() != ImageFrame::FrameComplete); |
| 478 | 478 |
| 479 ASSERT(m_demux); | 479 ASSERT(m_demux); |
| 480 for (auto i = framesToDecode.rbegin(); i != framesToDecode.rend(); ++i) { | 480 for (auto i = framesToDecode.rbegin(); i != framesToDecode.rend(); ++i) { |
| 481 if ((m_formatFlags & ANIMATION_FLAG) && !initFrameBuffer(*i)) | 481 if ((m_formatFlags & ANIMATION_FLAG) && !initFrameBuffer(*i)) |
| 482 return; | 482 return; |
| 483 WebPIterator webpFrame; | 483 WebPIterator webpFrame; |
| 484 if (!WebPDemuxGetFrame(m_demux, *i + 1, &webpFrame)) { | 484 if (!WebPDemuxGetFrame(m_demux, *i + 1, &webpFrame)) { |
| 485 setFailed(); | 485 setFailed(); |
| 486 } else { | 486 } else { |
| 487 decodeSingleFrame(webpFrame.fragment.bytes, webpFrame.fragment.size,
*i); | 487 decodeSingleFrame(webpFrame.fragment.bytes, webpFrame.fragment.size,
*i); |
| 488 WebPDemuxReleaseIterator(&webpFrame); | 488 WebPDemuxReleaseIterator(&webpFrame); |
| 489 } | 489 } |
| 490 if (failed()) | 490 if (failed()) |
| 491 return; | 491 return; |
| 492 | 492 |
| 493 // We need more data to continue decoding. | 493 // We need more data to continue decoding. |
| 494 if (m_frameBufferCache[*i].status() != ImageFrame::FrameComplete) | 494 if (m_frameBufferCache[*i].getStatus() != ImageFrame::FrameComplete) |
| 495 break; | 495 break; |
| 496 } | 496 } |
| 497 | 497 |
| 498 // It is also a fatal error if all data is received and we have decoded all | 498 // It is also a fatal error if all data is received and we have decoded all |
| 499 // frames available but the file is truncated. | 499 // frames available but the file is truncated. |
| 500 if (index >= m_frameBufferCache.size() - 1 && isAllDataReceived() && m_demux
&& m_demuxState != WEBP_DEMUX_DONE) | 500 if (index >= m_frameBufferCache.size() - 1 && isAllDataReceived() && m_demux
&& m_demuxState != WEBP_DEMUX_DONE) |
| 501 setFailed(); | 501 setFailed(); |
| 502 } | 502 } |
| 503 | 503 |
| 504 bool WEBPImageDecoder::decodeSingleFrame(const uint8_t* dataBytes, size_t dataSi
ze, size_t frameIndex) | 504 bool WEBPImageDecoder::decodeSingleFrame(const uint8_t* dataBytes, size_t dataSi
ze, size_t frameIndex) |
| 505 { | 505 { |
| 506 if (failed()) | 506 if (failed()) |
| 507 return false; | 507 return false; |
| 508 | 508 |
| 509 ASSERT(isDecodedSizeAvailable()); | 509 ASSERT(isDecodedSizeAvailable()); |
| 510 | 510 |
| 511 ASSERT(m_frameBufferCache.size() > frameIndex); | 511 ASSERT(m_frameBufferCache.size() > frameIndex); |
| 512 ImageFrame& buffer = m_frameBufferCache[frameIndex]; | 512 ImageFrame& buffer = m_frameBufferCache[frameIndex]; |
| 513 ASSERT(buffer.status() != ImageFrame::FrameComplete); | 513 ASSERT(buffer.getStatus() != ImageFrame::FrameComplete); |
| 514 | 514 |
| 515 if (buffer.status() == ImageFrame::FrameEmpty) { | 515 if (buffer.getStatus() == ImageFrame::FrameEmpty) { |
| 516 if (!buffer.setSize(size().width(), size().height())) | 516 if (!buffer.setSize(size().width(), size().height())) |
| 517 return setFailed(); | 517 return setFailed(); |
| 518 buffer.setStatus(ImageFrame::FramePartial); | 518 buffer.setStatus(ImageFrame::FramePartial); |
| 519 // The buffer is transparent outside the decoded area while the image is
loading. | 519 // The buffer is transparent outside the decoded area while the image is
loading. |
| 520 // The correct value of 'hasAlpha' for the frame will be set when it is
fully decoded. | 520 // The correct value of 'hasAlpha' for the frame will be set when it is
fully decoded. |
| 521 buffer.setHasAlpha(true); | 521 buffer.setHasAlpha(true); |
| 522 buffer.setOriginalFrameRect(IntRect(IntPoint(), size())); | 522 buffer.setOriginalFrameRect(IntRect(IntPoint(), size())); |
| 523 } | 523 } |
| 524 | 524 |
| 525 const IntRect& frameRect = buffer.originalFrameRect(); | 525 const IntRect& frameRect = buffer.originalFrameRect(); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 556 return false; | 556 return false; |
| 557 } | 557 } |
| 558 // FALLTHROUGH | 558 // FALLTHROUGH |
| 559 default: | 559 default: |
| 560 clear(); | 560 clear(); |
| 561 return setFailed(); | 561 return setFailed(); |
| 562 } | 562 } |
| 563 } | 563 } |
| 564 | 564 |
| 565 } // namespace blink | 565 } // namespace blink |
| OLD | NEW |