Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2006 Apple Computer, Inc. | 2 * Copyright (C) 2006 Apple Computer, Inc. |
| 3 * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. | 3 * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. |
| 4 * | 4 * |
| 5 * Portions are Copyright (C) 2001 mozilla.org | 5 * Portions are Copyright (C) 2001 mozilla.org |
| 6 * | 6 * |
| 7 * Other contributors: | 7 * Other contributors: |
| 8 * Stuart Parmenter <stuart@mozilla.com> | 8 * Stuart Parmenter <stuart@mozilla.com> |
| 9 * | 9 * |
| 10 * This library is free software; you can redistribute it and/or | 10 * This library is free software; you can redistribute it and/or |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 47 | 47 |
| 48 PNGImageDecoder::PNGImageDecoder(AlphaOption alphaOption, | 48 PNGImageDecoder::PNGImageDecoder(AlphaOption alphaOption, |
| 49 const ColorBehavior& colorBehavior, | 49 const ColorBehavior& colorBehavior, |
| 50 size_t maxDecodedBytes, | 50 size_t maxDecodedBytes, |
| 51 size_t offset) | 51 size_t offset) |
| 52 : ImageDecoder(alphaOption, colorBehavior, maxDecodedBytes), | 52 : ImageDecoder(alphaOption, colorBehavior, maxDecodedBytes), |
| 53 m_offset(offset) {} | 53 m_offset(offset) {} |
| 54 | 54 |
| 55 PNGImageDecoder::~PNGImageDecoder() {} | 55 PNGImageDecoder::~PNGImageDecoder() {} |
| 56 | 56 |
| 57 inline float pngFixedToFloat(png_fixed_point x) { | 57 inline sk_sp<SkColorSpace> readColorSpace(png_structp png, png_infop info) { |
| 58 return ((float)x) * 0.00001f; | 58 if (png_get_valid(png, info, PNG_INFO_sRGB)) |
| 59 } | 59 return SkColorSpace::MakeSRGB(); |
| 60 | 60 |
| 61 inline sk_sp<SkColorSpace> readColorSpace(png_structp png, png_infop info) { | 61 png_charp name; |
| 62 if (png_get_valid(png, info, PNG_INFO_sRGB)) { | 62 int compression; |
| 63 return SkColorSpace::MakeSRGB(); | 63 png_bytep profile; |
| 64 } | 64 png_uint_32 length; |
| 65 | 65 if (png_get_iCCP(png, info, &name, &compression, &profile, &length)) |
| 66 png_charp name = nullptr; | |
| 67 int compression = 0; | |
| 68 png_bytep profile = nullptr; | |
| 69 png_uint_32 length = 0; | |
| 70 if (png_get_iCCP(png, info, &name, &compression, &profile, &length)) { | |
| 71 return SkColorSpace::MakeICC(profile, length); | 66 return SkColorSpace::MakeICC(profile, length); |
| 72 } | |
| 73 | 67 |
| 74 png_fixed_point chrm[8]; | 68 png_fixed_point chrm[8]; |
| 75 if (png_get_cHRM_fixed(png, info, &chrm[0], &chrm[1], &chrm[2], &chrm[3], | 69 if (!png_get_cHRM_fixed(png, info, &chrm[0], &chrm[1], &chrm[2], &chrm[3], |
| 76 &chrm[4], &chrm[5], &chrm[6], &chrm[7])) { | 70 &chrm[4], &chrm[5], &chrm[6], &chrm[7])) |
| 77 SkColorSpacePrimaries primaries; | 71 return nullptr; |
| 78 primaries.fRX = pngFixedToFloat(chrm[2]); | |
| 79 primaries.fRY = pngFixedToFloat(chrm[3]); | |
| 80 primaries.fGX = pngFixedToFloat(chrm[4]); | |
| 81 primaries.fGY = pngFixedToFloat(chrm[5]); | |
| 82 primaries.fBX = pngFixedToFloat(chrm[6]); | |
| 83 primaries.fBY = pngFixedToFloat(chrm[7]); | |
| 84 primaries.fWX = pngFixedToFloat(chrm[0]); | |
| 85 primaries.fWY = pngFixedToFloat(chrm[1]); | |
| 86 | 72 |
| 87 SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor); | 73 png_fixed_point inverseGamma; |
| 88 if (primaries.toXYZD50(&toXYZD50)) { | 74 if (!png_get_gAMA_fixed(png, info, &inverseGamma)) |
| 89 png_fixed_point gammaFixed; | 75 return nullptr; |
| 90 if (PNG_INFO_gAMA == png_get_gAMA_fixed(png, info, &gammaFixed)) { | |
| 91 SkColorSpaceTransferFn fn; | |
| 92 fn.fA = 1.0f; | |
| 93 fn.fB = fn.fC = fn.fD = fn.fE = fn.fF = 0.0f; | |
| 94 // This is necessary because the gAMA chunk actually stores 1/gamma. | |
| 95 fn.fG = 1.0f / pngFixedToFloat(gammaFixed); | |
| 96 return SkColorSpace::MakeRGB(fn, toXYZD50); | |
| 97 } | |
| 98 | 76 |
| 99 // Note that we only use the cHRM tag when gAMA is present. The | 77 // cHRM and gAMA tags are both present. The PNG spec states that cHRM is |
| 100 // specification states that the cHRM is valid even without a gAMA | 78 // valid even without gAMA but we cannot apply the cHRM without guessing |
| 101 // tag, but we cannot apply the cHRM without guessing a transfer | 79 // a gAMA. Color correction is not a guessing game: match the behavior |
| 102 // function. It's possible that we should guess sRGB transfer | 80 // of Safari and Firefox instead (compat). |
| 103 // function, given that unmarked PNGs should be treated as sRGB. | |
| 104 // However, the current behavior matches Safari and Firefox. | |
|
Noel Gordon
2017/02/23 10:53:41
"... that unmarked PNGs should be treated as sRGB"
msarett1
2017/02/23 14:07:03
I don't completely agree. It is widely accepted t
Noel Gordon
2017/02/23 18:06:47
Not sure you understood this point, but the crux i
| |
| 105 } | |
| 106 } | |
| 107 | 81 |
| 108 return nullptr; | 82 struct pngFixedToFloat { |
| 83 explicit pngFixedToFloat(png_fixed_point value) | |
| 84 : floatValue(.00001f * value) {} | |
| 85 operator float() { return floatValue; } | |
| 86 float floatValue; | |
| 87 }; | |
| 88 | |
| 89 SkColorSpacePrimaries primaries; | |
| 90 primaries.fRX = pngFixedToFloat(chrm[2]); | |
| 91 primaries.fRY = pngFixedToFloat(chrm[3]); | |
| 92 primaries.fGX = pngFixedToFloat(chrm[4]); | |
| 93 primaries.fGY = pngFixedToFloat(chrm[5]); | |
| 94 primaries.fBX = pngFixedToFloat(chrm[6]); | |
| 95 primaries.fBY = pngFixedToFloat(chrm[7]); | |
| 96 primaries.fWX = pngFixedToFloat(chrm[0]); | |
| 97 primaries.fWY = pngFixedToFloat(chrm[1]); | |
| 98 | |
| 99 SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor); | |
| 100 if (!primaries.toXYZD50(&toXYZD50)) | |
| 101 return nullptr; | |
| 102 | |
| 103 SkColorSpaceTransferFn fn; | |
| 104 fn.fG = 1.0f / pngFixedToFloat(inverseGamma); | |
| 105 fn.fA = 1.0f; | |
| 106 fn.fB = fn.fC = fn.fD = fn.fE = fn.fF = 0.0f; | |
| 107 | |
| 108 return SkColorSpace::MakeRGB(fn, toXYZD50); | |
| 109 } | 109 } |
| 110 | 110 |
| 111 void PNGImageDecoder::headerAvailable() { | 111 void PNGImageDecoder::headerAvailable() { |
| 112 png_structp png = m_reader->pngPtr(); | 112 png_structp png = m_reader->pngPtr(); |
| 113 png_infop info = m_reader->infoPtr(); | 113 png_infop info = m_reader->infoPtr(); |
| 114 png_uint_32 width = png_get_image_width(png, info); | 114 png_uint_32 width = png_get_image_width(png, info); |
| 115 png_uint_32 height = png_get_image_height(png, info); | 115 png_uint_32 height = png_get_image_height(png, info); |
| 116 | 116 |
| 117 // Protect against large PNGs. See http://bugzil.la/251381 for more details. | 117 // Protect against large PNGs. See http://bugzil.la/251381 for more details. |
| 118 const unsigned long maxPNGSize = 1000000UL; | 118 const unsigned long maxPNGSize = 1000000UL; |
| 119 if (width > maxPNGSize || height > maxPNGSize) { | 119 if (width > maxPNGSize || height > maxPNGSize) { |
| 120 longjmp(JMPBUF(png), 1); | 120 longjmp(JMPBUF(png), 1); |
| 121 return; | 121 return; |
| 122 } | 122 } |
| 123 | 123 |
| 124 // Set the image size now that the image header is available. | 124 // Set the image size now that the image header is available. |
| 125 if (!setSize(width, height)) { | 125 if (!setSize(width, height)) { |
| 126 longjmp(JMPBUF(png), 1); | 126 longjmp(JMPBUF(png), 1); |
| 127 return; | 127 return; |
| 128 } | 128 } |
| 129 | 129 |
| 130 int bitDepth, colorType, interlaceType, compressionType, filterType, channels; | 130 int bitDepth, colorType, interlaceType, compressionType; |
| 131 png_get_IHDR(png, info, &width, &height, &bitDepth, &colorType, | 131 png_get_IHDR(png, info, &width, &height, &bitDepth, &colorType, |
| 132 &interlaceType, &compressionType, &filterType); | 132 &interlaceType, &compressionType, nullptr); |
| 133 | 133 |
| 134 // The options we set here match what Mozilla does. | 134 // The options we set here match what Mozilla does. |
| 135 | 135 |
| 136 // Expand to ensure we use 24-bit for RGB and 32-bit for RGBA. | 136 // Expand to ensure we use 24-bit for RGB and 32-bit for RGBA. |
| 137 if (colorType == PNG_COLOR_TYPE_PALETTE || | 137 if (colorType == PNG_COLOR_TYPE_PALETTE || |
| 138 (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8)) | 138 (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8)) |
| 139 png_set_expand(png); | 139 png_set_expand(png); |
| 140 | 140 |
| 141 png_bytep trns = 0; | 141 png_bytep trns = 0; |
| 142 int trnsCount = 0; | 142 int trnsCount = 0; |
| 143 if (png_get_valid(png, info, PNG_INFO_tRNS)) { | 143 if (png_get_valid(png, info, PNG_INFO_tRNS)) { |
| 144 png_get_tRNS(png, info, &trns, &trnsCount, 0); | 144 png_get_tRNS(png, info, &trns, &trnsCount, 0); |
|
scroggo_chromium
2017/02/23 15:11:51
Another issue you brought up in the APNG patch - t
Noel Gordon
2017/02/23 16:49:05
Ah yes, that's orthogonal to your APNG patch too.
| |
| 145 png_set_expand(png); | 145 png_set_expand(png); |
| 146 } | 146 } |
| 147 | 147 |
| 148 if (bitDepth == 16) | 148 if (bitDepth == 16) |
| 149 png_set_strip_16(png); | 149 png_set_strip_16(png); |
| 150 | 150 |
| 151 if (colorType == PNG_COLOR_TYPE_GRAY || | 151 if (colorType == PNG_COLOR_TYPE_GRAY || |
| 152 colorType == PNG_COLOR_TYPE_GRAY_ALPHA) | 152 colorType == PNG_COLOR_TYPE_GRAY_ALPHA) |
| 153 png_set_gray_to_rgb(png); | 153 png_set_gray_to_rgb(png); |
| 154 | 154 |
| 155 if ((colorType & PNG_COLOR_MASK_COLOR) && !ignoresColorSpace()) { | 155 if ((colorType & PNG_COLOR_MASK_COLOR) && !ignoresColorSpace()) { |
| 156 // We only support color profiles for color PALETTE and RGB[A] PNG. | 156 // We only support color profiles for color PALETTE and RGB[A] PNG. |
| 157 // Supporting color profiles for gray-scale images is slightly tricky, at | 157 // TODO(msarret): Add GRAY, CMYK profile support? |
|
msarett1
2017/02/23 14:07:03
nit: msarett
nit: CMYK doesn't seem relevant here
Noel Gordon
2017/02/23 16:49:05
Yes but reading SkColorSpace::MakeICC, it seems to
| |
| 158 // least using the CoreGraphics ICC library, because we expand gray-scale | 158 if (sk_sp<SkColorSpace> colorSpace = readColorSpace(png, info)) |
| 159 // images to RGB but we do not similarly transform the color profile. We'd | 159 setEmbeddedColorSpace(std::move(colorSpace)); |
| 160 // either need to transform the color profile or we'd need to decode into a | |
| 161 // gray-scale image buffer and hand that to CoreGraphics. | |
| 162 sk_sp<SkColorSpace> colorSpace = readColorSpace(png, info); | |
| 163 if (colorSpace) { | |
| 164 setEmbeddedColorSpace(colorSpace); | |
| 165 } | |
| 166 } | 160 } |
| 167 | 161 |
| 168 if (!hasEmbeddedColorSpace()) { | 162 if (!hasEmbeddedColorSpace()) { |
| 169 // TODO (msarett): | |
| 170 // Applying the transfer function (gamma) should be handled by | |
| 171 // SkColorSpaceXform. Here we always convert to a transfer function that | |
| 172 // is a 2.2 exponential. This is a little strange given that the dst | |
| 173 // transfer function is not necessarily a 2.2 exponential. | |
|
Noel Gordon
2017/02/23 10:43:56
Here be dragons for reference. The sad story of PN
msarett1
2017/02/23 14:07:03
This comment seems valid to me?
[1] seems to poin
Noel Gordon
2017/02/23 18:06:47
I don't think the lone gAMA tag is a problem worth
| |
| 174 // TODO (msarett): | |
| 175 // Often, PNGs that specify their transfer function with the gAMA tag will | |
| 176 // also specify their gamut with the cHRM tag. We should read this tag | |
| 177 // and do a full color space transformation if it is present. | |
|
Noel Gordon
2017/02/23 10:43:56
Fixed a while back. Though the Android pixels resu
msarett1
2017/02/23 14:07:03
Yes this comment is out of date, thanks for removi
msarett1
2017/02/23 14:09:34
Oops, I see the bug now. Thanks.
Noel Gordon
2017/02/23 16:49:05
K.
| |
| 178 const double inverseGamma = 0.45455; | 163 const double inverseGamma = 0.45455; |
| 179 const double defaultGamma = 2.2; | 164 const double defaultGamma = 2.2; |
| 180 double gamma; | 165 double gamma; |
| 181 if (!ignoresColorSpace() && png_get_gAMA(png, info, &gamma)) { | 166 if (!ignoresColorSpace() && png_get_gAMA(png, info, &gamma)) { |
| 182 const double maxGamma = 21474.83; | 167 const double maxGamma = 21474.83; |
| 183 if ((gamma <= 0.0) || (gamma > maxGamma)) { | 168 if ((gamma <= 0.0) || (gamma > maxGamma)) { |
| 184 gamma = inverseGamma; | 169 gamma = inverseGamma; |
| 185 png_set_gAMA(png, info, gamma); | 170 png_set_gAMA(png, info, gamma); |
| 186 } | 171 } |
| 187 png_set_gamma(png, defaultGamma, gamma); | 172 png_set_gamma(png, defaultGamma, gamma); |
| 188 } else { | 173 } else { |
| 189 png_set_gamma(png, defaultGamma, inverseGamma); | 174 png_set_gamma(png, defaultGamma, inverseGamma); |
| 190 } | 175 } |
| 191 } | 176 } |
| 192 | 177 |
| 193 // Tell libpng to send us rows for interlaced pngs. | 178 // Tell libpng to send us rows for interlaced pngs. |
| 194 if (interlaceType == PNG_INTERLACE_ADAM7) | 179 if (interlaceType == PNG_INTERLACE_ADAM7) |
| 195 png_set_interlace_handling(png); | 180 png_set_interlace_handling(png); |
| 196 | 181 |
| 197 // Update our info now. | 182 // Update our info now (so we can read color channel info). |
| 198 png_read_update_info(png, info); | 183 png_read_update_info(png, info); |
| 199 channels = png_get_channels(png, info); | |
| 200 ASSERT(channels == 3 || channels == 4); | |
| 201 | 184 |
| 185 int channels = png_get_channels(png, info); | |
| 186 DCHECK(channels == 3 || channels == 4); | |
| 202 m_reader->setHasAlpha(channels == 4); | 187 m_reader->setHasAlpha(channels == 4); |
| 203 | 188 |
| 204 if (m_reader->decodingSizeOnly()) { | 189 if (m_reader->decodingSizeOnly()) { |
| 205 // If we only needed the size, halt the reader. | 190 // If we only needed the size, halt the reader. |
| 206 #if PNG_LIBPNG_VER_MAJOR > 1 || \ | 191 #if PNG_LIBPNG_VER_MAJOR > 1 || \ |
| 207 (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 5) | 192 (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 5) |
| 208 // Passing '0' tells png_process_data_pause() not to cache unprocessed data. | 193 // Passing '0' tells png_process_data_pause() not to cache unprocessed data. |
| 209 m_reader->setReadOffset(m_reader->currentBufferSize() - | 194 m_reader->setReadOffset(m_reader->currentBufferSize() - |
| 210 png_process_data_pause(png, 0)); | 195 png_process_data_pause(png, 0)); |
| 211 #else | 196 #else |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 243 } | 228 } |
| 244 | 229 |
| 245 buffer.setStatus(ImageFrame::FramePartial); | 230 buffer.setStatus(ImageFrame::FramePartial); |
| 246 buffer.setHasAlpha(false); | 231 buffer.setHasAlpha(false); |
| 247 | 232 |
| 248 // For PNGs, the frame always fills the entire image. | 233 // For PNGs, the frame always fills the entire image. |
| 249 buffer.setOriginalFrameRect(IntRect(IntPoint(), size())); | 234 buffer.setOriginalFrameRect(IntRect(IntPoint(), size())); |
| 250 } | 235 } |
| 251 | 236 |
| 252 /* libpng comments (here to explain what follows). | 237 /* libpng comments (here to explain what follows). |
| 253 * | 238 * |
| 254 * this function is called for every row in the image. If the | 239 * this function is called for every row in the image. If the |
| 255 * image is interlacing, and you turned on the interlace handler, | 240 * image is interlacing, and you turned on the interlace handler, |
| 256 * this function will be called for every row in every pass. | 241 * this function will be called for every row in every pass. |
| 257 * Some of these rows will not be changed from the previous pass. | 242 * Some of these rows will not be changed from the previous pass. |
| 258 * When the row is not changed, the new_row variable will be NULL. | 243 * When the row is not changed, the new_row variable will be NULL. |
| 259 * The rows and passes are called in order, so you don't really | 244 * The rows and passes are called in order, so you don't really |
| 260 * need the row_num and pass, but I'm supplying them because it | 245 * need the row_num and pass, but I'm supplying them because it |
| 261 * may make your life easier. | 246 * may make your life easier. |
| 262 */ | 247 */ |
| 263 | 248 |
| 264 // Nothing to do if the row is unchanged, or the row is outside | 249 // Nothing to do if the row is unchanged, or the row is outside |
| 265 // the image bounds: libpng may send extra rows, ignore them to | 250 // the image bounds: libpng may send extra rows, ignore them to |
| 266 // make our lives easier. | 251 // make our lives easier. |
| 267 if (!rowBuffer) | 252 if (!rowBuffer) |
| 268 return; | 253 return; |
| 269 int y = rowIndex; | 254 int y = rowIndex; |
| 270 if (y < 0 || y >= size().height()) | 255 if (y < 0 || y >= size().height()) |
| 271 return; | 256 return; |
| 272 | 257 |
| 273 /* libpng comments (continued). | 258 /* libpng comments (continued). |
| 274 * | 259 * |
| 275 * For the non-NULL rows of interlaced images, you must call | 260 * For the non-NULL rows of interlaced images, you must call |
| 276 * png_progressive_combine_row() passing in the row and the | 261 * png_progressive_combine_row() passing in the row and the |
| 277 * old row. You can call this function for NULL rows (it will | 262 * old row. You can call this function for NULL rows (it will |
| 278 * just return) and for non-interlaced images (it just does the | 263 * just return) and for non-interlaced images (it just does the |
| 279 * memcpy for you) if it will make the code easier. Thus, you | 264 * memcpy for you) if it will make the code easier. Thus, you |
| 280 * can just do this for all cases: | 265 * can just do this for all cases: |
| 281 * | 266 * |
| 282 * png_progressive_combine_row(png_ptr, old_row, new_row); | 267 * png_progressive_combine_row(png_ptr, old_row, new_row); |
| 283 * | 268 * |
| 284 * where old_row is what was displayed for previous rows. Note | 269 * where old_row is what was displayed for previous rows. Note |
| 285 * that the first pass (pass == 0 really) will completely cover | 270 * that the first pass (pass == 0 really) will completely cover |
| 286 * the old row, so the rows do not have to be initialized. After | 271 * the old row, so the rows do not have to be initialized. After |
| 287 * the first pass (and only for interlaced images), you will have | 272 * the first pass (and only for interlaced images), you will have |
| 288 * to pass the current row, and the function will combine the | 273 * to pass the current row, and the function will combine the |
| 289 * old row and the new row. | 274 * old row and the new row. |
| 290 */ | 275 */ |
| 291 | 276 |
| 292 bool hasAlpha = m_reader->hasAlpha(); | 277 bool hasAlpha = m_reader->hasAlpha(); |
| 293 png_bytep row = rowBuffer; | 278 png_bytep row = rowBuffer; |
| 294 | 279 |
| 295 if (png_bytep interlaceBuffer = m_reader->interlaceBuffer()) { | 280 if (png_bytep interlaceBuffer = m_reader->interlaceBuffer()) { |
| 296 unsigned colorChannels = hasAlpha ? 4 : 3; | 281 unsigned colorChannels = hasAlpha ? 4 : 3; |
| 297 row = interlaceBuffer + (rowIndex * colorChannels * size().width()); | 282 row = interlaceBuffer + (rowIndex * colorChannels * size().width()); |
| 298 png_progressive_combine_row(m_reader->pngPtr(), row, rowBuffer); | 283 png_progressive_combine_row(m_reader->pngPtr(), row, rowBuffer); |
| 299 } | 284 } |
| 300 | 285 |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 314 // while the pixels are a linear space. | 299 // while the pixels are a linear space. |
| 315 // We cannot do this because when we apply the gamma encoding after | 300 // We cannot do this because when we apply the gamma encoding after |
| 316 // the premultiply, we will very likely end up with valid pixels | 301 // the premultiply, we will very likely end up with valid pixels |
| 317 // where R, G, and/or B are greater than A. The legacy drawing | 302 // where R, G, and/or B are greater than A. The legacy drawing |
| 318 // pipeline does not know how to handle this. | 303 // pipeline does not know how to handle this. |
| 319 if (SkColorSpaceXform* xform = colorTransform()) { | 304 if (SkColorSpaceXform* xform = colorTransform()) { |
| 320 SkColorSpaceXform::ColorFormat colorFormat = | 305 SkColorSpaceXform::ColorFormat colorFormat = |
| 321 SkColorSpaceXform::kRGBA_8888_ColorFormat; | 306 SkColorSpaceXform::kRGBA_8888_ColorFormat; |
| 322 xform->apply(colorFormat, dstRow, colorFormat, srcPtr, size().width(), | 307 xform->apply(colorFormat, dstRow, colorFormat, srcPtr, size().width(), |
| 323 kUnpremul_SkAlphaType); | 308 kUnpremul_SkAlphaType); |
| 324 srcPtr = (png_bytep)dstRow; | 309 srcPtr = png_bytep(dstRow); |
| 325 } | 310 } |
| 326 | 311 |
|
scroggo_chromium
2017/02/23 15:11:51
As long as you're moving where alphaMask is refere
Noel Gordon
2017/02/23 16:49:05
Done.
| |
| 327 if (buffer.premultiplyAlpha()) { | 312 if (buffer.premultiplyAlpha()) { |
| 328 for (auto *dstPixel = dstRow; dstPixel < dstRow + width; | 313 for (auto *dstPixel = dstRow; dstPixel < dstRow + width; |
| 329 dstPixel++, srcPtr += 4) { | 314 srcPtr += 4, ++dstPixel) { |
| 330 buffer.setRGBAPremultiply(dstPixel, srcPtr[0], srcPtr[1], srcPtr[2], | 315 buffer.setRGBAPremultiply(dstPixel, srcPtr[0], srcPtr[1], srcPtr[2], |
| 331 srcPtr[3]); | 316 srcPtr[3]); |
| 332 alphaMask &= srcPtr[3]; | 317 alphaMask &= srcPtr[3]; |
| 333 } | 318 } |
| 334 } else { | 319 } else { |
| 335 for (auto *dstPixel = dstRow; dstPixel < dstRow + width; | 320 for (auto *dstPixel = dstRow; dstPixel < dstRow + width; |
| 336 dstPixel++, srcPtr += 4) { | 321 srcPtr += 4, ++dstPixel) { |
| 337 buffer.setRGBARaw(dstPixel, srcPtr[0], srcPtr[1], srcPtr[2], srcPtr[3]); | 322 buffer.setRGBARaw(dstPixel, srcPtr[0], srcPtr[1], srcPtr[2], srcPtr[3]); |
| 338 alphaMask &= srcPtr[3]; | 323 alphaMask &= srcPtr[3]; |
| 339 } | 324 } |
| 340 } | 325 } |
| 326 | |
| 327 if (alphaMask != 255 && !buffer.hasAlpha()) | |
| 328 buffer.setHasAlpha(true); | |
| 329 | |
| 341 } else { | 330 } else { |
| 342 for (auto *dstPixel = dstRow; dstPixel < dstRow + width; | 331 for (auto *dstPixel = dstRow; dstPixel < dstRow + width; |
| 343 dstPixel++, srcPtr += 3) { | 332 srcPtr += 3, ++dstPixel) { |
| 344 buffer.setRGBARaw(dstPixel, srcPtr[0], srcPtr[1], srcPtr[2], 255); | 333 buffer.setRGBARaw(dstPixel, srcPtr[0], srcPtr[1], srcPtr[2], 255); |
| 345 } | 334 } |
| 346 | 335 |
| 347 // We'll apply the color space xform to opaque pixels after they have been | 336 // We'll apply the color space xform to opaque pixels after they have been |
| 348 // written to the ImageFrame, purely because SkColorSpaceXform supports | 337 // written to the ImageFrame, purely because SkColorSpaceXform supports |
| 349 // RGBA (and not RGB). | 338 // RGBA (and not RGB). |
| 350 if (SkColorSpaceXform* xform = colorTransform()) { | 339 if (SkColorSpaceXform* xform = colorTransform()) { |
| 351 xform->apply(xformColorFormat(), dstRow, xformColorFormat(), dstRow, | 340 xform->apply(xformColorFormat(), dstRow, xformColorFormat(), dstRow, |
| 352 size().width(), kOpaque_SkAlphaType); | 341 size().width(), kOpaque_SkAlphaType); |
| 353 } | 342 } |
| 354 } | 343 } |
| 355 | 344 |
| 356 if (alphaMask != 255 && !buffer.hasAlpha()) | |
| 357 buffer.setHasAlpha(true); | |
| 358 | |
| 359 buffer.setPixelsChanged(true); | 345 buffer.setPixelsChanged(true); |
| 360 } | 346 } |
| 361 | 347 |
| 362 void PNGImageDecoder::complete() { | 348 void PNGImageDecoder::complete() { |
| 363 if (m_frameBufferCache.isEmpty()) | 349 if (m_frameBufferCache.isEmpty()) |
| 364 return; | 350 return; |
| 365 | 351 |
| 366 m_frameBufferCache[0].setStatus(ImageFrame::FrameComplete); | 352 m_frameBufferCache[0].setStatus(ImageFrame::FrameComplete); |
| 367 } | 353 } |
| 368 | 354 |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 381 // has failed. | 367 // has failed. |
| 382 if (!m_reader->decode(*m_data, onlySize) && isAllDataReceived()) | 368 if (!m_reader->decode(*m_data, onlySize) && isAllDataReceived()) |
| 383 setFailed(); | 369 setFailed(); |
| 384 | 370 |
| 385 // If decoding is done or failed, we don't need the PNGImageReader anymore. | 371 // If decoding is done or failed, we don't need the PNGImageReader anymore. |
| 386 if (isComplete(this) || failed()) | 372 if (isComplete(this) || failed()) |
| 387 m_reader.reset(); | 373 m_reader.reset(); |
| 388 } | 374 } |
| 389 | 375 |
| 390 } // namespace blink | 376 } // namespace blink |
| OLD | NEW |