Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(242)

Side by Side Diff: third_party/WebKit/Source/platform/image-decoders/webp/WEBPImageDecoder.cpp

Issue 2426723005: Use SkColorSpaceXform to handle color conversions in decoders (Closed)
Patch Set: Refactor a bit for clarity Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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 // TODO (msarett):
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698