Chromium Code Reviews| Index: third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp |
| diff --git a/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp b/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp |
| index caff5e4cca0f89744ffc0e7a61b000555e3b248f..a2e1169146b1665bbeff7258203413880fa1ab4f 100644 |
| --- a/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp |
| +++ b/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp |
| @@ -36,20 +36,18 @@ |
| namespace blink { |
| static bool compatibleInfo(const SkImageInfo& src, const SkImageInfo& dst) { |
| - if (src == dst) |
| - return true; |
| + bool compatibleSize = src.dimensions() == dst.dimensions(); |
| + bool compatibleColorType = src.colorType() == dst.colorType(); |
| - // It is legal to write kOpaque_SkAlphaType pixels into a kPremul_SkAlphaType |
| - // buffer. This can happen when DeferredImageDecoder allocates an |
| - // kOpaque_SkAlphaType image generator based on cached frame info, while the |
| - // ImageFrame-allocated dest bitmap stays kPremul_SkAlphaType. |
| - if (src.alphaType() == kOpaque_SkAlphaType && |
| - dst.alphaType() == kPremul_SkAlphaType) { |
| - const SkImageInfo& tmp = src.makeAlphaType(kPremul_SkAlphaType); |
| - return tmp == dst; |
| - } |
| + // We should be lenient with alphaType. Any image can be decoded to kUnpremul |
| + // or kPremul. Opaque images may be marked as kOpaque, but not until they |
| + // are fully decoded. This means that the buffer may be kPremul, but we are |
| + // writing kOpaque pixels. |
| - return false; |
| + // The color spaces also do not need to match. We will perform color space |
| + // conversions when necessary. |
| + |
| + return compatibleSize && compatibleColorType; |
| } |
| // Creates a SkPixelRef such that the memory for pixels is given by an external |
| @@ -103,10 +101,10 @@ static bool updateYUVComponentSizes(ImageDecoder* decoder, |
| return true; |
| } |
| -ImageFrameGenerator::ImageFrameGenerator(const SkISize& fullSize, |
| +ImageFrameGenerator::ImageFrameGenerator(const SkImageInfo& info, |
| bool isMultiFrame, |
| const ColorBehavior& colorBehavior) |
| - : m_fullSize(fullSize), |
| + : m_info(info), |
| m_decoderColorBehavior(colorBehavior), |
| m_isMultiFrame(isMultiFrame), |
| m_decodeFailed(false), |
| @@ -120,7 +118,7 @@ ImageFrameGenerator::~ImageFrameGenerator() { |
| bool ImageFrameGenerator::decodeAndScale(SegmentReader* data, |
| bool allDataReceived, |
| size_t index, |
| - const SkImageInfo& info, |
| + const SkImageInfo& dstInfo, |
| void* pixels, |
| size_t rowBytes) { |
| if (m_decodeFailed) |
| @@ -130,16 +128,16 @@ bool ImageFrameGenerator::decodeAndScale(SegmentReader* data, |
| static_cast<int>(index)); |
| // This implementation does not support scaling so check the requested size. |
| - SkISize scaledSize = SkISize::Make(info.width(), info.height()); |
| - ASSERT(m_fullSize == scaledSize); |
| + SkISize scaledSize = SkISize::Make(dstInfo.width(), dstInfo.height()); |
| + DCHECK(m_info.dimensions() == scaledSize); |
|
scroggo_chromium
2017/04/07 18:06:06
scaledSize looks to be never used again (or it doe
|
| // It is okay to allocate ref-counted ExternalMemoryAllocator on the stack, |
| // because 1) it contains references to memory that will be invalid after |
| // returning (i.e. a pointer to |pixels|) and therefore 2) should not live |
| // longer than the call to the current method. |
| - ExternalMemoryAllocator externalAllocator(info, pixels, rowBytes); |
| + ExternalMemoryAllocator externalAllocator(dstInfo, pixels, rowBytes); |
| SkBitmap bitmap = tryToResumeDecode(data, allDataReceived, index, scaledSize, |
| - &externalAllocator); |
| + &externalAllocator, dstInfo); |
| DCHECK(externalAllocator.unique()); // Verify we have the only ref-count. |
| if (bitmap.isNull()) |
| @@ -151,7 +149,7 @@ bool ImageFrameGenerator::decodeAndScale(SegmentReader* data, |
| ASSERT(bitmap.height() == scaledSize.height()); |
| SkAutoLockPixels bitmapLock(bitmap); |
| if (bitmap.getPixels() != pixels) |
| - return bitmap.copyPixelsTo(pixels, rowBytes * info.height(), rowBytes); |
| + return bitmap.readPixels(bitmap.info(), pixels, rowBytes, 0, 0); |
|
scroggo_chromium
2017/04/07 18:06:06
Might bitmap.info() be different from dstInfo? I'm
|
| return true; |
| } |
| @@ -196,26 +194,38 @@ bool ImageFrameGenerator::decodeToYUV(SegmentReader* data, |
| return false; |
| } |
| -SkBitmap ImageFrameGenerator::tryToResumeDecode( |
| - SegmentReader* data, |
| - bool allDataReceived, |
| - size_t index, |
| - const SkISize& scaledSize, |
| - SkBitmap::Allocator* allocator) { |
| +static inline bool needsColorXform(const SkImageInfo& src, |
| + const SkImageInfo& dst) { |
| + return src.colorSpace() && dst.colorSpace() && |
| + !SkColorSpace::Equals(src.colorSpace(), dst.colorSpace()); |
| +} |
| + |
| +SkBitmap ImageFrameGenerator::tryToResumeDecode(SegmentReader* data, |
| + bool allDataReceived, |
| + size_t index, |
| + const SkISize& scaledSize, |
| + SkBitmap::Allocator* allocator, |
| + const SkImageInfo& dstInfo) { |
| TRACE_EVENT1("blink", "ImageFrameGenerator::tryToResumeDecode", "frame index", |
| static_cast<int>(index)); |
| ImageDecoder* decoder = 0; |
| + const bool needsXform = needsColorXform(m_info, dstInfo); |
| + ImageDecoder::AlphaOption alphaOption = ImageDecoder::AlphaPremultiplied; |
| + if (needsXform && !dstInfo.isOpaque()) { |
|
scroggo_chromium
2017/04/07 18:06:06
It might be worth noting that you check dstInfo be
msarett1
2017/04/10 14:42:46
Acknowledged.
|
| + alphaOption = ImageDecoder::AlphaNotPremultiplied; |
| + } |
| + |
| // Lock the mutex, so only one thread can use the decoder at once. |
| MutexLocker lock(m_decodeMutex); |
| - const bool resumeDecoding = |
| - ImageDecodingStore::instance().lockDecoder(this, m_fullSize, &decoder); |
| + const bool resumeDecoding = ImageDecodingStore::instance().lockDecoder( |
| + this, m_info.dimensions(), alphaOption, &decoder); |
| ASSERT(!resumeDecoding || decoder); |
| SkBitmap fullSizeImage; |
| - bool complete = |
| - decode(data, allDataReceived, index, &decoder, &fullSizeImage, allocator); |
| + bool complete = decode(data, allDataReceived, index, &decoder, &fullSizeImage, |
| + allocator, alphaOption, dstInfo); |
| if (!decoder) |
| return SkBitmap(); |
| @@ -280,10 +290,12 @@ bool ImageFrameGenerator::decode(SegmentReader* data, |
| size_t index, |
| ImageDecoder** decoder, |
| SkBitmap* bitmap, |
| - SkBitmap::Allocator* allocator) { |
| + SkBitmap::Allocator* allocator, |
| + ImageDecoder::AlphaOption alphaOption, |
| + const SkImageInfo& dstInfo) { |
| ASSERT(m_decodeMutex.locked()); |
| - TRACE_EVENT2("blink", "ImageFrameGenerator::decode", "width", |
| - m_fullSize.width(), "height", m_fullSize.height()); |
| + TRACE_EVENT2("blink", "ImageFrameGenerator::decode", "width", m_info.width(), |
| + "height", m_info.height()); |
| // Try to create an ImageDecoder if we are not given one. |
| ASSERT(decoder); |
| @@ -295,8 +307,7 @@ bool ImageFrameGenerator::decode(SegmentReader* data, |
| *decoder = m_imageDecoderFactory->create().release(); |
| if (!*decoder) { |
| - *decoder = ImageDecoder::create(data, allDataReceived, |
| - ImageDecoder::AlphaPremultiplied, |
| + *decoder = ImageDecoder::create(data, allDataReceived, alphaOption, |
| m_decoderColorBehavior) |
| .release(); |
| // The newly created decoder just grabbed the data. No need to reset it. |
| @@ -307,7 +318,6 @@ bool ImageFrameGenerator::decode(SegmentReader* data, |
| return false; |
| } |
| - |
| if (shouldCallSetData) |
| (*decoder)->setData(data, allDataReceived); |
| @@ -350,11 +360,45 @@ bool ImageFrameGenerator::decode(SegmentReader* data, |
| SkBitmap fullSizeBitmap = frame->bitmap(); |
| if (!fullSizeBitmap.isNull()) { |
| - ASSERT(fullSizeBitmap.width() == m_fullSize.width() && |
| - fullSizeBitmap.height() == m_fullSize.height()); |
| + DCHECK(fullSizeBitmap.width() == m_info.width() && |
|
scroggo_chromium
2017/04/07 18:06:06
So long as you're changing this, it could be:
D
msarett1
2017/04/10 14:42:46
Acknowledged.
|
| + fullSizeBitmap.height() == m_info.height()); |
| setHasAlpha(index, !fullSizeBitmap.isOpaque()); |
| } |
| + if (needsColorXform(m_info, dstInfo)) { |
|
scroggo_chromium
2017/04/07 18:06:06
I assume you do not need to do this if fullSizeBit
msarett1
2017/04/10 14:42:46
Acknowledged.
|
| + DCHECK(dstInfo.isOpaque() || |
| + ImageDecoder::AlphaNotPremultiplied == alphaOption); |
| + std::unique_ptr<SkColorSpaceXform> xform = |
| + SkColorSpaceXform::New(m_info.colorSpace(), dstInfo.colorSpace()); |
| + |
| + SkBitmap tmp(fullSizeBitmap); |
|
scroggo_chromium
2017/04/07 18:06:06
IIRC, this will make tmp share fullSizeBitmap's Sk
msarett1
2017/04/10 14:42:46
Acknowledged.
|
| + tmp.lockPixels(); |
| + uint32_t* row = tmp.getAddr32(0, 0); |
| + for (int y = 0; y < dstInfo.height(); y++) { |
|
scroggo_chromium
2017/04/07 18:06:06
This method is called while m_decodeMutex is locke
msarett1
2017/04/10 14:42:45
Acknowledged.
|
| + SkColorSpaceXform::ColorFormat format = |
| + SkColorSpaceXform::kRGBA_8888_ColorFormat; |
| + if (kN32_SkColorType == kBGRA_8888_SkColorType) { |
| + format = SkColorSpaceXform::kBGRA_8888_ColorFormat; |
| + } |
| + SkAlphaType alphaType = |
| + dstInfo.isOpaque() ? kOpaque_SkAlphaType : kUnpremul_SkAlphaType; |
|
scroggo_chromium
2017/04/07 18:06:06
My first thought was that you could use dstInfo.al
msarett1
2017/04/10 14:42:46
Acknowledged.
|
| + bool xformed = |
| + xform->apply(format, row, format, row, dstInfo.width(), alphaType); |
| + DCHECK(xformed); |
| + |
| + // To be compatible with dst space blending, premultiply in the dst space. |
| + if (kPremul_SkAlphaType == dstInfo.alphaType()) { |
| + for (int x = 0; x < dstInfo.width(); x++) { |
| + row[x] = |
| + SkPreMultiplyARGB(SkGetPackedA32(row[x]), SkGetPackedR32(row[x]), |
| + SkGetPackedG32(row[x]), SkGetPackedB32(row[x])); |
| + } |
| + } |
| + |
| + row = (uint32_t*)(((uint8_t*)row) + fullSizeBitmap.rowBytes()); |
|
scroggo_chromium
2017/04/07 18:06:06
I think tmp and fullSizeBitmap are essentially the
msarett1
2017/04/10 14:42:46
Acknowledged.
|
| + } |
| + } |
| + |
| *bitmap = fullSizeBitmap; |
| return isDecodeComplete; |
| } |
| @@ -369,7 +413,7 @@ bool ImageFrameGenerator::hasAlpha(size_t index) { |
| bool ImageFrameGenerator::getYUVComponentSizes(SegmentReader* data, |
| SkYUVSizeInfo* sizeInfo) { |
| TRACE_EVENT2("blink", "ImageFrameGenerator::getYUVComponentSizes", "width", |
| - m_fullSize.width(), "height", m_fullSize.height()); |
| + m_info.width(), "height", m_info.height()); |
| if (m_yuvDecodingFailed) |
| return false; |