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

Unified Diff: third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp

Issue 2787053004: Respect colorSpace in DecodingImageGenerator::onGetPixels() (Closed)
Patch Set: Response to comments Created 3 years, 8 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 side-by-side diff with in-line comments
Download patch
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;

Powered by Google App Engine
This is Rietveld 408576698