From 008cb2a2d83d218fb8c81cb901dbdfd422cb3d7f Mon Sep 17 00:00:00 2001 From: Andrew Osmond Date: Tue, 11 Jun 2019 10:54:11 -0400 Subject: [PATCH] Bug 1555934 - Partially backout bug 1255106 part 3 to fix decoders with transparency. r=aosmond --- image/decoders/nsPNGDecoder.cpp | 88 ++++++++++++++++++++------------ image/decoders/nsPNGDecoder.h | 1 - image/decoders/nsWebPDecoder.cpp | 13 +++-- 3 files changed, 62 insertions(+), 40 deletions(-) diff --git a/image/decoders/nsPNGDecoder.cpp b/image/decoders/nsPNGDecoder.cpp index df9dddafe82f..0e46bc2d666f 100644 --- a/image/decoders/nsPNGDecoder.cpp +++ b/image/decoders/nsPNGDecoder.cpp @@ -116,7 +116,6 @@ nsPNGDecoder::nsPNGDecoder(RasterImage* aImage) mFrameIsHidden(false), mDisablePremultipliedAlpha(false), mGotInfoCallback(false), - mUsePipeTransform(false), mNumFrames(0) {} nsPNGDecoder::~nsPNGDecoder() { @@ -213,10 +212,9 @@ nsresult nsPNGDecoder::CreateFrame(const FrameInfo& aFrameInfo) { pipeFlags |= SurfacePipeFlags::PROGRESSIVE_DISPLAY; } - qcms_transform* pipeTransform = mUsePipeTransform ? mTransform : nullptr; Maybe pipe = SurfacePipeFactory::CreateSurfacePipe( this, Size(), OutputSize(), aFrameInfo.mFrameRect, mFormat, animParams, - pipeTransform, pipeFlags); + /*aTransform*/ nullptr, pipeFlags); if (!pipe) { mPipe = SurfacePipe(); @@ -415,7 +413,8 @@ static void PNGDoGammaCorrection(png_structp png_ptr, png_infop info_ptr) { // Adapted from http://www.littlecms.com/pngchrm.c example code static qcms_profile* PNGGetColorProfile(png_structp png_ptr, png_infop info_ptr, - int color_type, uint32_t* intent) { + int color_type, qcms_data_type* inType, + uint32_t* intent) { qcms_profile* profile = nullptr; *intent = QCMS_INTENT_PERCEPTUAL; // Our default @@ -493,6 +492,24 @@ static qcms_profile* PNGGetColorProfile(png_structp png_ptr, png_infop info_ptr, } } + if (profile) { + uint32_t profileSpace = qcms_profile_get_color_space(profile); + if (profileSpace == icSigGrayData) { + if (color_type & PNG_COLOR_MASK_ALPHA) { + *inType = QCMS_DATA_GRAYA_8; + } else { + *inType = QCMS_DATA_GRAY_8; + } + } else { + if (color_type & PNG_COLOR_MASK_ALPHA || + png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { + *inType = QCMS_DATA_RGBA_8; + } else { + *inType = QCMS_DATA_RGB_8; + } + } + } + return profile; } @@ -570,41 +587,25 @@ void nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr) { png_set_scale_16(png_ptr); } - // Let libpng expand interlaced images. - const bool isInterlaced = interlace_type == PNG_INTERLACE_ADAM7; - if (isInterlaced) { - png_set_interlace_handling(png_ptr); - } - + qcms_data_type inType = QCMS_DATA_RGBA_8; uint32_t intent = -1; uint32_t pIntent; if (decoder->mCMSMode != eCMSMode_Off) { intent = gfxPlatform::GetRenderingIntent(); decoder->mInProfile = - PNGGetColorProfile(png_ptr, info_ptr, color_type, &pIntent); + PNGGetColorProfile(png_ptr, info_ptr, color_type, &inType, &pIntent); // If we're not mandating an intent, use the one from the image. if (intent == uint32_t(-1)) { intent = pIntent; } } if (decoder->mInProfile && gfxPlatform::GetCMSOutputProfile()) { - qcms_data_type inType; qcms_data_type outType; - uint32_t profileSpace = qcms_profile_get_color_space(decoder->mInProfile); - decoder->mUsePipeTransform = profileSpace != icSigGrayData; - if (decoder->mUsePipeTransform) { - // If the transform happens with SurfacePipe, it will always be in BGRA. - inType = QCMS_DATA_BGRA_8; - outType = QCMS_DATA_BGRA_8; + if (color_type & PNG_COLOR_MASK_ALPHA || num_trans) { + outType = QCMS_DATA_RGBA_8; } else { - if (color_type & PNG_COLOR_MASK_ALPHA) { - inType = QCMS_DATA_GRAYA_8; - outType = QCMS_DATA_RGBA_8; - } else { - inType = QCMS_DATA_GRAY_8; - outType = QCMS_DATA_RGB_8; - } + outType = QCMS_DATA_RGB_8; } decoder->mTransform = qcms_transform_create( @@ -619,11 +620,20 @@ void nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr) { } if (decoder->mCMSMode == eCMSMode_All) { - decoder->mTransform = gfxPlatform::GetCMSBGRATransform(); - decoder->mUsePipeTransform = true; + if (color_type & PNG_COLOR_MASK_ALPHA || num_trans) { + decoder->mTransform = gfxPlatform::GetCMSRGBATransform(); + } else { + decoder->mTransform = gfxPlatform::GetCMSRGBTransform(); + } } } + // Let libpng expand interlaced images. + const bool isInterlaced = interlace_type == PNG_INTERLACE_ADAM7; + if (isInterlaced) { + png_set_interlace_handling(png_ptr); + } + // now all of those things we set above are used to update various struct // members and whatnot, after which we can get channels, rowbytes, etc. png_read_update_info(png_ptr, info_ptr); @@ -688,8 +698,8 @@ void nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr) { } #endif - if (decoder->mTransform && !decoder->mUsePipeTransform) { - uint32_t bpp[] = {0, 3, 4}; + if (decoder->mTransform && (channels <= 2 || isInterlaced)) { + uint32_t bpp[] = {0, 3, 4, 3, 4}; decoder->mCMSLine = static_cast(malloc(bpp[channels] * frameRect.Width())); if (!decoder->mCMSLine) { @@ -830,11 +840,21 @@ void nsPNGDecoder::WriteRow(uint8_t* aRow) { uint32_t width = uint32_t(mFrameRect.Width()); // Apply color management to the row, if necessary, before writing it out. - // This is only needed for grayscale images. - if (mTransform && !mUsePipeTransform) { - MOZ_ASSERT(mCMSLine); - qcms_transform_data(mTransform, rowToWrite, mCMSLine, width); - rowToWrite = mCMSLine; + if (mTransform) { + if (mCMSLine) { + qcms_transform_data(mTransform, rowToWrite, mCMSLine, width); + + // Copy alpha over. + if (HasAlphaChannel()) { + for (uint32_t i = 0; i < width; ++i) { + mCMSLine[4 * i + 3] = rowToWrite[mChannels * i + mChannels - 1]; + } + } + + rowToWrite = mCMSLine; + } else { + qcms_transform_data(mTransform, rowToWrite, rowToWrite, width); + } } // Write this row to the SurfacePipe. diff --git a/image/decoders/nsPNGDecoder.h b/image/decoders/nsPNGDecoder.h index ea2326694a82..4ed454fea2b3 100644 --- a/image/decoders/nsPNGDecoder.h +++ b/image/decoders/nsPNGDecoder.h @@ -101,7 +101,6 @@ class nsPNGDecoder : public Decoder { bool mFrameIsHidden; bool mDisablePremultipliedAlpha; bool mGotInfoCallback; - bool mUsePipeTransform; struct AnimFrameInfo { AnimFrameInfo(); diff --git a/image/decoders/nsWebPDecoder.cpp b/image/decoders/nsWebPDecoder.cpp index f2c5bcdb721c..9fbbad654c04 100644 --- a/image/decoders/nsWebPDecoder.cpp +++ b/image/decoders/nsWebPDecoder.cpp @@ -228,8 +228,8 @@ nsresult nsWebPDecoder::CreateFrame(const nsIntRect& aFrameRect) { } Maybe pipe = SurfacePipeFactory::CreateSurfacePipe( - this, Size(), OutputSize(), aFrameRect, mFormat, animParams, mTransform, - pipeFlags); + this, Size(), OutputSize(), aFrameRect, mFormat, animParams, + /*aTransform*/ nullptr, pipeFlags); if (!pipe) { MOZ_LOG(sWebPLog, LogLevel::Error, ("[this=%p] nsWebPDecoder::CreateFrame -- no pipe\n", this)); @@ -281,7 +281,7 @@ void nsWebPDecoder::ApplyColorProfile(const char* aProfile, size_t aLength) { ("[this=%p] nsWebPDecoder::ApplyColorProfile -- not tagged, use " "sRGB transform\n", this)); - mTransform = gfxPlatform::GetCMSBGRATransform(); + mTransform = gfxPlatform::GetCMSRGBATransform(); return; } @@ -311,9 +311,9 @@ void nsWebPDecoder::ApplyColorProfile(const char* aProfile, size_t aLength) { } // Create the color management transform. - mTransform = qcms_transform_create(mInProfile, QCMS_DATA_BGRA_8, + mTransform = qcms_transform_create(mInProfile, QCMS_DATA_RGBA_8, gfxPlatform::GetCMSOutputProfile(), - QCMS_DATA_BGRA_8, (qcms_intent)intent); + QCMS_DATA_RGBA_8, (qcms_intent)intent); MOZ_LOG(sWebPLog, LogLevel::Debug, ("[this=%p] nsWebPDecoder::ApplyColorProfile -- use tagged " "transform\n", @@ -463,6 +463,9 @@ LexerResult nsWebPDecoder::ReadSingle(const uint8_t* aData, size_t aLength, for (int row = mLastRow; row < lastRow; row++) { uint8_t* src = rowStart + row * stride; + if (mTransform) { + qcms_transform_data(mTransform, src, src, width); + } WriteState result; if (mFormat == SurfaceFormat::B8G8R8A8) {