| 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 10 matching lines...) Expand all Loading... |
| 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 */ | 27 */ |
| 28 | 28 |
| 29 #include "platform/image-decoders/webp/WEBPImageDecoder.h" | 29 #include "platform/image-decoders/webp/WEBPImageDecoder.h" |
| 30 | 30 |
| 31 #if USE(QCMSLIB) | |
| 32 #include "qcms.h" | |
| 33 #endif | |
| 34 | |
| 35 #if CPU(BIG_ENDIAN) || CPU(MIDDLE_ENDIAN) | 31 #if CPU(BIG_ENDIAN) || CPU(MIDDLE_ENDIAN) |
| 36 #error Blink assumes a little-endian target. | 32 #error Blink assumes a little-endian target. |
| 37 #endif | 33 #endif |
| 38 | 34 |
| 39 #if SK_B32_SHIFT // Output little-endian RGBA pixels (Android). | 35 #if SK_B32_SHIFT // Output little-endian RGBA pixels (Android). |
| 40 inline WEBP_CSP_MODE outputMode(bool hasAlpha) { | 36 inline WEBP_CSP_MODE outputMode(bool hasAlpha) { |
| 41 return hasAlpha ? MODE_rgbA : MODE_RGBA; | 37 return hasAlpha ? MODE_rgbA : MODE_RGBA; |
| 42 } | 38 } |
| 43 #else // Output little-endian BGRA pixels. | 39 #else // Output little-endian BGRA pixels. |
| 44 inline WEBP_CSP_MODE outputMode(bool hasAlpha) { | 40 inline WEBP_CSP_MODE outputMode(bool hasAlpha) { |
| (...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 339 WebPChunkIterator chunkIterator; | 335 WebPChunkIterator chunkIterator; |
| 340 if (!WebPDemuxGetChunk(m_demux, "ICCP", 1, &chunkIterator)) { | 336 if (!WebPDemuxGetChunk(m_demux, "ICCP", 1, &chunkIterator)) { |
| 341 WebPDemuxReleaseChunkIterator(&chunkIterator); | 337 WebPDemuxReleaseChunkIterator(&chunkIterator); |
| 342 return; | 338 return; |
| 343 } | 339 } |
| 344 | 340 |
| 345 const char* profileData = | 341 const char* profileData = |
| 346 reinterpret_cast<const char*>(chunkIterator.chunk.bytes); | 342 reinterpret_cast<const char*>(chunkIterator.chunk.bytes); |
| 347 size_t profileSize = chunkIterator.chunk.size; | 343 size_t profileSize = chunkIterator.chunk.size; |
| 348 | 344 |
| 349 setColorProfileAndComputeTransform(profileData, profileSize, | 345 setColorSpaceAndComputeTransform(profileData, profileSize, |
| 350 true /* hasAlpha */, false /* useSRGB */); | 346 false /* useSRGB */); |
| 351 | 347 |
| 352 WebPDemuxReleaseChunkIterator(&chunkIterator); | 348 WebPDemuxReleaseChunkIterator(&chunkIterator); |
| 353 } | 349 } |
| 354 | 350 |
| 355 void WEBPImageDecoder::applyPostProcessing(size_t frameIndex) { | 351 void WEBPImageDecoder::applyPostProcessing(size_t frameIndex) { |
| 356 ImageFrame& buffer = m_frameBufferCache[frameIndex]; | 352 ImageFrame& buffer = m_frameBufferCache[frameIndex]; |
| 357 int width; | 353 int width; |
| 358 int decodedHeight; | 354 int decodedHeight; |
| 359 if (!WebPIDecGetRGB(m_decoder, &decodedHeight, &width, 0, 0)) | 355 if (!WebPIDecGetRGB(m_decoder, &decodedHeight, &width, 0, 0)) |
| 360 return; // See also https://bugs.webkit.org/show_bug.cgi?id=74062 | 356 return; // See also https://bugs.webkit.org/show_bug.cgi?id=74062 |
| 361 if (decodedHeight <= 0) | 357 if (decodedHeight <= 0) |
| 362 return; | 358 return; |
| 363 | 359 |
| 364 const IntRect& frameRect = buffer.originalFrameRect(); | 360 const IntRect& frameRect = buffer.originalFrameRect(); |
| 365 ASSERT_WITH_SECURITY_IMPLICATION(width == frameRect.width()); | 361 ASSERT_WITH_SECURITY_IMPLICATION(width == frameRect.width()); |
| 366 ASSERT_WITH_SECURITY_IMPLICATION(decodedHeight <= frameRect.height()); | 362 ASSERT_WITH_SECURITY_IMPLICATION(decodedHeight <= frameRect.height()); |
| 367 const int left = frameRect.x(); | 363 const int left = frameRect.x(); |
| 368 const int top = frameRect.y(); | 364 const int top = frameRect.y(); |
| 369 | 365 |
| 370 #if USE(QCMSLIB) | 366 // FIXME: |
| 371 if (qcms_transform* transform = colorTransform()) { | 367 // Here we apply the color space transformation to the dst space. |
| 368 // It does not really make sense to transform to a gamma-encoded |
| 369 // space and then immediately after, perform a linear premultiply |
| 370 // and linear blending. Can we find a way to perform the |
| 371 // premultiplication and blending in a linear space? |
| 372 SkColorSpaceXform* xform = colorTransform(); |
| 373 if (xform) { |
| 374 const SkColorSpaceXform::ColorFormat srcFormat = |
| 375 SkColorSpaceXform::kBGRA_8888_ColorFormat; |
| 376 const SkColorSpaceXform::ColorFormat dstFormat = |
| 377 SkColorSpaceXform::kRGBA_8888_ColorFormat; |
| 372 for (int y = m_decodedHeight; y < decodedHeight; ++y) { | 378 for (int y = m_decodedHeight; y < decodedHeight; ++y) { |
| 373 const int canvasY = top + y; | 379 const int canvasY = top + y; |
| 374 uint8_t* row = reinterpret_cast<uint8_t*>(buffer.getAddr(left, canvasY)); | 380 uint8_t* row = reinterpret_cast<uint8_t*>(buffer.getAddr(left, canvasY)); |
| 375 qcms_transform_data_type(transform, row, row, width, QCMS_OUTPUT_RGBX); | 381 xform->apply(dstFormat, row, srcFormat, row, width, |
| 382 kUnpremul_SkAlphaType); |
| 383 |
| 376 uint8_t* pixel = row; | 384 uint8_t* pixel = row; |
| 377 for (int x = 0; x < width; ++x, pixel += 4) { | 385 for (int x = 0; x < width; ++x, pixel += 4) { |
| 378 const int canvasX = left + x; | 386 const int canvasX = left + x; |
| 379 buffer.setRGBA(canvasX, canvasY, pixel[0], pixel[1], pixel[2], | 387 buffer.setRGBA(canvasX, canvasY, pixel[0], pixel[1], pixel[2], |
| 380 pixel[3]); | 388 pixel[3]); |
| 381 } | 389 } |
| 382 } | 390 } |
| 383 } | 391 } |
| 384 #endif // USE(QCMSLIB) | |
| 385 | 392 |
| 386 // During the decoding of the current frame, we may have set some pixels to be | 393 // During the decoding of the current frame, we may have set some pixels to be |
| 387 // transparent (i.e. alpha < 255). If the alpha blend source was | 394 // transparent (i.e. alpha < 255). If the alpha blend source was |
| 388 // 'BlendAtopPreviousFrame', the values of these pixels should be determined | 395 // 'BlendAtopPreviousFrame', the values of these pixels should be determined |
| 389 // by blending them against the pixels of the corresponding previous frame. | 396 // by blending them against the pixels of the corresponding previous frame. |
| 390 // Compute the correct opaque values now. | 397 // Compute the correct opaque values now. |
| 391 // FIXME: This could be avoided if libwebp decoder had an API that used the | 398 // FIXME: This could be avoided if libwebp decoder had an API that used the |
| 392 // previous required frame to do the alpha-blending by itself. | 399 // previous required frame to do the alpha-blending by itself. |
| 393 if ((m_formatFlags & ANIMATION_FLAG) && frameIndex && | 400 if ((m_formatFlags & ANIMATION_FLAG) && frameIndex && |
| 394 buffer.getAlphaBlendSource() == ImageFrame::BlendAtopPreviousFrame && | 401 buffer.getAlphaBlendSource() == ImageFrame::BlendAtopPreviousFrame && |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 524 // fully decoded. | 531 // fully decoded. |
| 525 buffer.setHasAlpha(true); | 532 buffer.setHasAlpha(true); |
| 526 buffer.setOriginalFrameRect(IntRect(IntPoint(), size())); | 533 buffer.setOriginalFrameRect(IntRect(IntPoint(), size())); |
| 527 } | 534 } |
| 528 | 535 |
| 529 const IntRect& frameRect = buffer.originalFrameRect(); | 536 const IntRect& frameRect = buffer.originalFrameRect(); |
| 530 if (!m_decoder) { | 537 if (!m_decoder) { |
| 531 WEBP_CSP_MODE mode = outputMode(m_formatFlags & ALPHA_FLAG); | 538 WEBP_CSP_MODE mode = outputMode(m_formatFlags & ALPHA_FLAG); |
| 532 if (!m_premultiplyAlpha) | 539 if (!m_premultiplyAlpha) |
| 533 mode = outputMode(false); | 540 mode = outputMode(false); |
| 534 #if USE(QCMSLIB) | 541 if (colorTransform()) { |
| 535 if (colorTransform()) | 542 // Swizzling between RGBA and BGRA is zero cost in a color transform. |
| 536 mode = MODE_RGBA; // Decode to RGBA for input to libqcms. | 543 // So when we have a color transform, we should decode to whatever is |
| 537 #endif | 544 // easiest for libwebp, and then let the color transform swizzle if |
| 545 // necessary. |
| 546 // Lossy webp is encoded as YUV (so RGBA and BGRA are the same cost). |
| 547 // Lossless webp is encoded as BGRA. This means decoding to BGRA is |
| 548 // either faster or the same cost as RGBA. |
| 549 mode = MODE_BGRA; |
| 550 } |
| 538 WebPInitDecBuffer(&m_decoderBuffer); | 551 WebPInitDecBuffer(&m_decoderBuffer); |
| 539 m_decoderBuffer.colorspace = mode; | 552 m_decoderBuffer.colorspace = mode; |
| 540 m_decoderBuffer.u.RGBA.stride = | 553 m_decoderBuffer.u.RGBA.stride = |
| 541 size().width() * sizeof(ImageFrame::PixelData); | 554 size().width() * sizeof(ImageFrame::PixelData); |
| 542 m_decoderBuffer.u.RGBA.size = | 555 m_decoderBuffer.u.RGBA.size = |
| 543 m_decoderBuffer.u.RGBA.stride * frameRect.height(); | 556 m_decoderBuffer.u.RGBA.stride * frameRect.height(); |
| 544 m_decoderBuffer.is_external_memory = 1; | 557 m_decoderBuffer.is_external_memory = 1; |
| 545 m_decoder = WebPINewDecoder(&m_decoderBuffer); | 558 m_decoder = WebPINewDecoder(&m_decoderBuffer); |
| 546 if (!m_decoder) | 559 if (!m_decoder) |
| 547 return setFailed(); | 560 return setFailed(); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 564 return false; | 577 return false; |
| 565 } | 578 } |
| 566 // FALLTHROUGH | 579 // FALLTHROUGH |
| 567 default: | 580 default: |
| 568 clear(); | 581 clear(); |
| 569 return setFailed(); | 582 return setFailed(); |
| 570 } | 583 } |
| 571 } | 584 } |
| 572 | 585 |
| 573 } // namespace blink | 586 } // namespace blink |
| OLD | NEW |