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 |