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 #if USE(SKCOLORXFORM) |
371 if (qcms_transform* transform = colorTransform()) { | 367 // FIXME: |
scroggo_chromium
2016/10/20 12:45:04
nit: TODO (msarett):
msarett
2016/10/20 13:20:52
Done.
| |
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; | |
372 for (int y = m_decodedHeight; y < decodedHeight; ++y) { | 379 for (int y = m_decodedHeight; y < decodedHeight; ++y) { |
373 const int canvasY = top + y; | 380 const int canvasY = top + y; |
374 uint8_t* row = reinterpret_cast<uint8_t*>(buffer.getAddr(left, canvasY)); | 381 uint8_t* row = reinterpret_cast<uint8_t*>(buffer.getAddr(left, canvasY)); |
375 qcms_transform_data_type(transform, row, row, width, QCMS_OUTPUT_RGBX); | 382 xform->apply(dstFormat, row, srcFormat, row, width, |
383 kUnpremul_SkAlphaType); | |
384 | |
376 uint8_t* pixel = row; | 385 uint8_t* pixel = row; |
377 for (int x = 0; x < width; ++x, pixel += 4) { | 386 for (int x = 0; x < width; ++x, pixel += 4) { |
378 const int canvasX = left + x; | 387 const int canvasX = left + x; |
379 buffer.setRGBA(canvasX, canvasY, pixel[0], pixel[1], pixel[2], | 388 buffer.setRGBA(canvasX, canvasY, pixel[0], pixel[1], pixel[2], |
380 pixel[3]); | 389 pixel[3]); |
381 } | 390 } |
382 } | 391 } |
383 } | 392 } |
384 #endif // USE(QCMSLIB) | 393 #endif // USE(SKCOLORXFORM) |
385 | 394 |
386 // During the decoding of the current frame, we may have set some pixels to be | 395 // 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 | 396 // transparent (i.e. alpha < 255). If the alpha blend source was |
388 // 'BlendAtopPreviousFrame', the values of these pixels should be determined | 397 // 'BlendAtopPreviousFrame', the values of these pixels should be determined |
389 // by blending them against the pixels of the corresponding previous frame. | 398 // by blending them against the pixels of the corresponding previous frame. |
390 // Compute the correct opaque values now. | 399 // Compute the correct opaque values now. |
391 // FIXME: This could be avoided if libwebp decoder had an API that used the | 400 // 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. | 401 // previous required frame to do the alpha-blending by itself. |
393 if ((m_formatFlags & ANIMATION_FLAG) && frameIndex && | 402 if ((m_formatFlags & ANIMATION_FLAG) && frameIndex && |
394 buffer.getAlphaBlendSource() == ImageFrame::BlendAtopPreviousFrame && | 403 buffer.getAlphaBlendSource() == ImageFrame::BlendAtopPreviousFrame && |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
524 // fully decoded. | 533 // fully decoded. |
525 buffer.setHasAlpha(true); | 534 buffer.setHasAlpha(true); |
526 buffer.setOriginalFrameRect(IntRect(IntPoint(), size())); | 535 buffer.setOriginalFrameRect(IntRect(IntPoint(), size())); |
527 } | 536 } |
528 | 537 |
529 const IntRect& frameRect = buffer.originalFrameRect(); | 538 const IntRect& frameRect = buffer.originalFrameRect(); |
530 if (!m_decoder) { | 539 if (!m_decoder) { |
531 WEBP_CSP_MODE mode = outputMode(m_formatFlags & ALPHA_FLAG); | 540 WEBP_CSP_MODE mode = outputMode(m_formatFlags & ALPHA_FLAG); |
532 if (!m_premultiplyAlpha) | 541 if (!m_premultiplyAlpha) |
533 mode = outputMode(false); | 542 mode = outputMode(false); |
534 #if USE(QCMSLIB) | 543 #if USE(SKCOLORXFORM) |
535 if (colorTransform()) | 544 if (colorTransform()) { |
536 mode = MODE_RGBA; // Decode to RGBA for input to libqcms. | 545 // Swizzling between RGBA and BGRA is zero cost in a color transform. |
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 } | |
537 #endif | 554 #endif |
538 WebPInitDecBuffer(&m_decoderBuffer); | 555 WebPInitDecBuffer(&m_decoderBuffer); |
539 m_decoderBuffer.colorspace = mode; | 556 m_decoderBuffer.colorspace = mode; |
540 m_decoderBuffer.u.RGBA.stride = | 557 m_decoderBuffer.u.RGBA.stride = |
541 size().width() * sizeof(ImageFrame::PixelData); | 558 size().width() * sizeof(ImageFrame::PixelData); |
542 m_decoderBuffer.u.RGBA.size = | 559 m_decoderBuffer.u.RGBA.size = |
543 m_decoderBuffer.u.RGBA.stride * frameRect.height(); | 560 m_decoderBuffer.u.RGBA.stride * frameRect.height(); |
544 m_decoderBuffer.is_external_memory = 1; | 561 m_decoderBuffer.is_external_memory = 1; |
545 m_decoder = WebPINewDecoder(&m_decoderBuffer); | 562 m_decoder = WebPINewDecoder(&m_decoderBuffer); |
546 if (!m_decoder) | 563 if (!m_decoder) |
(...skipping 17 matching lines...) Expand all Loading... | |
564 return false; | 581 return false; |
565 } | 582 } |
566 // FALLTHROUGH | 583 // FALLTHROUGH |
567 default: | 584 default: |
568 clear(); | 585 clear(); |
569 return setFailed(); | 586 return setFailed(); |
570 } | 587 } |
571 } | 588 } |
572 | 589 |
573 } // namespace blink | 590 } // namespace blink |
OLD | NEW |