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 |