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