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 |