Index: third_party/WebKit/Source/platform/image-decoders/png/PNGImageDecoder.cpp |
diff --git a/third_party/WebKit/Source/platform/image-decoders/png/PNGImageDecoder.cpp b/third_party/WebKit/Source/platform/image-decoders/png/PNGImageDecoder.cpp |
index f440d851ddf13892d4b3dbe152e747f6c18d2051..1f3b61204919d0f42fdf57b1ff9190d783a962f4 100644 |
--- a/third_party/WebKit/Source/platform/image-decoders/png/PNGImageDecoder.cpp |
+++ b/third_party/WebKit/Source/platform/image-decoders/png/PNGImageDecoder.cpp |
@@ -45,6 +45,9 @@ |
#if !defined(PNG_LIBPNG_VER_MAJOR) || !defined(PNG_LIBPNG_VER_MINOR) |
#error version error: compile against a versioned libpng. |
#endif |
+#if USE(QCMSLIB) |
+#include "qcms.h" |
+#endif |
#if PNG_LIBPNG_VER_MAJOR > 1 || \ |
(PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 4) |
@@ -93,6 +96,10 @@ |
m_currentBufferSize(0), |
m_decodingSizeOnly(false), |
m_hasAlpha(false) |
+#if USE(QCMSLIB) |
+ , |
+ m_rowBuffer() |
+#endif |
{ |
m_png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, pngFailed, 0); |
m_info = png_create_info_struct(m_png); |
@@ -143,6 +150,12 @@ |
void createInterlaceBuffer(int size) { |
m_interlaceBuffer = wrapArrayUnique(new png_byte[size]); |
} |
+#if USE(QCMSLIB) |
+ png_bytep rowBuffer() const { return m_rowBuffer.get(); } |
+ void createRowBuffer(int size) { |
+ m_rowBuffer = wrapArrayUnique(new png_byte[size]); |
+ } |
+#endif |
private: |
png_structp m_png; |
@@ -153,6 +166,9 @@ |
bool m_decodingSizeOnly; |
bool m_hasAlpha; |
std::unique_ptr<png_byte[]> m_interlaceBuffer; |
+#if USE(QCMSLIB) |
+ std::unique_ptr<png_byte[]> m_rowBuffer; |
+#endif |
}; |
PNGImageDecoder::PNGImageDecoder(AlphaOption alphaOption, |
@@ -215,9 +231,11 @@ |
// images to RGB but we do not similarly transform the color profile. We'd |
// either need to transform the color profile or we'd need to decode into a |
// gray-scale image buffer and hand that to CoreGraphics. |
+ bool imageHasAlpha = (colorType & PNG_COLOR_MASK_ALPHA) || trnsCount; |
#ifdef PNG_iCCP_SUPPORTED |
if (png_get_valid(png, info, PNG_INFO_sRGB)) { |
- setColorSpaceAndComputeTransform(nullptr, 0, true /* useSRGB */); |
+ setColorProfileAndComputeTransform(nullptr, 0, imageHasAlpha, |
+ true /* useSRGB */); |
} else { |
char* profileName = nullptr; |
int compressionType = 0; |
@@ -229,23 +247,16 @@ |
png_uint_32 profileLength = 0; |
if (png_get_iCCP(png, info, &profileName, &compressionType, &profile, |
&profileLength)) { |
- setColorSpaceAndComputeTransform(reinterpret_cast<char*>(profile), |
- profileLength, false /* useSRGB */); |
+ setColorProfileAndComputeTransform(reinterpret_cast<char*>(profile), |
+ profileLength, imageHasAlpha, |
+ false /* useSRGB */); |
} |
} |
#endif // PNG_iCCP_SUPPORTED |
} |
if (!hasColorProfile()) { |
- // TODO (msarett): |
- // Applying the transfer function (gamma) should be handled by |
- // SkColorSpaceXform. Here we always convert to a transfer function that |
- // is a 2.2 exponential. This is a little strange given that the dst |
- // transfer function is not necessarily a 2.2 exponential. |
- // TODO (msarett): |
- // Often, PNGs that specify their transfer function with the gAMA tag will |
- // also specify their gamut with the cHRM tag. We should read this tag |
- // and do a full color space transformation if it is present. |
+ // Deal with gamma and keep it under our control. |
const double inverseGamma = 0.45455; |
const double defaultGamma = 2.2; |
double gamma; |
@@ -313,6 +324,15 @@ |
} |
} |
+#if USE(QCMSLIB) |
+ if (colorTransform()) { |
+ m_reader->createRowBuffer(colorChannels * size().width()); |
+ if (!m_reader->rowBuffer()) { |
+ longjmp(JMPBUF(png), 1); |
+ return; |
+ } |
+ } |
+#endif |
buffer.setStatus(ImageFrame::FramePartial); |
buffer.setHasAlpha(false); |
@@ -369,63 +389,37 @@ |
png_progressive_combine_row(m_reader->pngPtr(), row, rowBuffer); |
} |
+#if USE(QCMSLIB) |
+ if (qcms_transform* transform = colorTransform()) { |
+ qcms_transform_data(transform, row, m_reader->rowBuffer(), size().width()); |
+ row = m_reader->rowBuffer(); |
+ } |
+#endif |
+ |
// Write the decoded row pixels to the frame buffer. The repetitive |
// form of the row write loops is for speed. |
- ImageFrame::PixelData* const dstRow = buffer.getAddr(0, y); |
+ ImageFrame::PixelData* address = buffer.getAddr(0, y); |
unsigned alphaMask = 255; |
int width = size().width(); |
- png_bytep srcPtr = row; |
+ png_bytep pixel = row; |
if (hasAlpha) { |
-#if USE(SKCOLORXFORM) |
- // Here we apply the color space transformation to the dst space. |
- // It does not really make sense to transform to a gamma-encoded |
- // space and then immediately after, perform a linear premultiply. |
- // Ideally we would pass kPremul_SkAlphaType to xform->apply(), |
- // instructing SkColorSpaceXform to perform the linear premultiply |
- // while the pixels are a linear space. |
- // We cannot do this because when we apply the gamma encoding after |
- // the premultiply, we will very likely end up with valid pixels |
- // where R, G, and/or B are greater than A. The legacy drawing |
- // pipeline does not know how to handle this. |
- if (SkColorSpaceXform* xform = colorTransform()) { |
- SkColorSpaceXform::ColorFormat colorFormat = |
- SkColorSpaceXform::kRGBA_8888_ColorFormat; |
- xform->apply(colorFormat, dstRow, colorFormat, srcPtr, size().width(), |
- kUnpremul_SkAlphaType); |
- srcPtr = (png_bytep)dstRow; |
- } |
-#endif |
- |
if (buffer.premultiplyAlpha()) { |
- for (auto *dstPixel = dstRow; dstPixel < dstRow + width; |
- dstPixel++, srcPtr += 4) { |
- buffer.setRGBAPremultiply(dstPixel, srcPtr[0], srcPtr[1], srcPtr[2], |
- srcPtr[3]); |
- alphaMask &= srcPtr[3]; |
+ for (int x = 0; x < width; ++x, pixel += 4) { |
+ buffer.setRGBAPremultiply(address++, pixel[0], pixel[1], pixel[2], |
+ pixel[3]); |
+ alphaMask &= pixel[3]; |
} |
} else { |
- for (auto *dstPixel = dstRow; dstPixel < dstRow + width; |
- dstPixel++, srcPtr += 4) { |
- buffer.setRGBARaw(dstPixel, srcPtr[0], srcPtr[1], srcPtr[2], srcPtr[3]); |
- alphaMask &= srcPtr[3]; |
+ for (int x = 0; x < width; ++x, pixel += 4) { |
+ buffer.setRGBARaw(address++, pixel[0], pixel[1], pixel[2], pixel[3]); |
+ alphaMask &= pixel[3]; |
} |
} |
} else { |
- for (auto *dstPixel = dstRow; dstPixel < dstRow + width; |
- dstPixel++, srcPtr += 3) { |
- buffer.setRGBARaw(dstPixel, srcPtr[0], srcPtr[1], srcPtr[2], 255); |
- } |
- |
-#if USE(SKCOLORXFORM) |
- // We'll apply the color space xform to opaque pixels after they have been |
- // written to the ImageFrame, purely because SkColorSpaceXform supports |
- // RGBA (and not RGB). |
- if (SkColorSpaceXform* xform = colorTransform()) { |
- xform->apply(xformColorFormat(), dstRow, xformColorFormat(), dstRow, |
- size().width(), kOpaque_SkAlphaType); |
- } |
-#endif |
+ for (int x = 0; x < width; ++x, pixel += 3) { |
+ buffer.setRGBARaw(address++, pixel[0], pixel[1], pixel[2], 255); |
+ } |
} |
if (alphaMask != 255 && !buffer.hasAlpha()) |