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. | |
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 if (png_get_valid(png, info, PNG_INFO_tRNS)) |
142 int trnsCount = 0; | |
143 if (png_get_valid(png, info, PNG_INFO_tRNS)) { | |
144 png_get_tRNS(png, info, &trns, &trnsCount, 0); | |
145 png_set_expand(png); | 142 png_set_expand(png); |
146 } | |
147 | 143 |
148 if (bitDepth == 16) | 144 if (bitDepth == 16) |
149 png_set_strip_16(png); | 145 png_set_strip_16(png); |
150 | 146 |
151 if (colorType == PNG_COLOR_TYPE_GRAY || | 147 if (colorType == PNG_COLOR_TYPE_GRAY || |
152 colorType == PNG_COLOR_TYPE_GRAY_ALPHA) | 148 colorType == PNG_COLOR_TYPE_GRAY_ALPHA) |
153 png_set_gray_to_rgb(png); | 149 png_set_gray_to_rgb(png); |
154 | 150 |
155 if ((colorType & PNG_COLOR_MASK_COLOR) && !ignoresColorSpace()) { | 151 if ((colorType & PNG_COLOR_MASK_COLOR) && !ignoresColorSpace()) { |
156 // We only support color profiles for color PALETTE and RGB[A] PNG. | 152 // We only support color profiles for color PALETTE and RGB[A] PNG. |
157 // Supporting color profiles for gray-scale images is slightly tricky, at | 153 // TODO(msarret): Add GRAY profile support, block CYMK? |
158 // least using the CoreGraphics ICC library, because we expand gray-scale | 154 if (sk_sp<SkColorSpace> colorSpace = readColorSpace(png, info)) |
159 // images to RGB but we do not similarly transform the color profile. We'd | 155 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 } | 156 } |
167 | 157 |
168 if (!hasEmbeddedColorSpace()) { | 158 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. | |
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. | |
178 const double inverseGamma = 0.45455; | 159 const double inverseGamma = 0.45455; |
179 const double defaultGamma = 2.2; | 160 const double defaultGamma = 2.2; |
180 double gamma; | 161 double gamma; |
181 if (!ignoresColorSpace() && png_get_gAMA(png, info, &gamma)) { | 162 if (!ignoresColorSpace() && png_get_gAMA(png, info, &gamma)) { |
182 const double maxGamma = 21474.83; | 163 const double maxGamma = 21474.83; |
183 if ((gamma <= 0.0) || (gamma > maxGamma)) { | 164 if ((gamma <= 0.0) || (gamma > maxGamma)) { |
184 gamma = inverseGamma; | 165 gamma = inverseGamma; |
185 png_set_gAMA(png, info, gamma); | 166 png_set_gAMA(png, info, gamma); |
186 } | 167 } |
187 png_set_gamma(png, defaultGamma, gamma); | 168 png_set_gamma(png, defaultGamma, gamma); |
188 } else { | 169 } else { |
189 png_set_gamma(png, defaultGamma, inverseGamma); | 170 png_set_gamma(png, defaultGamma, inverseGamma); |
190 } | 171 } |
191 } | 172 } |
192 | 173 |
193 // Tell libpng to send us rows for interlaced pngs. | 174 // Tell libpng to send us rows for interlaced pngs. |
194 if (interlaceType == PNG_INTERLACE_ADAM7) | 175 if (interlaceType == PNG_INTERLACE_ADAM7) |
195 png_set_interlace_handling(png); | 176 png_set_interlace_handling(png); |
196 | 177 |
197 // Update our info now. | 178 // Update our info now (so we can get color channel info). |
198 png_read_update_info(png, info); | 179 png_read_update_info(png, info); |
199 channels = png_get_channels(png, info); | |
200 ASSERT(channels == 3 || channels == 4); | |
201 | 180 |
| 181 int channels = png_get_channels(png, info); |
| 182 DCHECK(channels == 3 || channels == 4); |
202 m_reader->setHasAlpha(channels == 4); | 183 m_reader->setHasAlpha(channels == 4); |
203 | 184 |
204 if (m_reader->decodingSizeOnly()) { | 185 if (m_reader->decodingSizeOnly()) { |
205 // If we only needed the size, halt the reader. | 186 // If we only needed the size, halt the reader. |
206 #if PNG_LIBPNG_VER_MAJOR > 1 || \ | 187 #if PNG_LIBPNG_VER_MAJOR > 1 || \ |
207 (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 5) | 188 (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 5) |
208 // Passing '0' tells png_process_data_pause() not to cache unprocessed data. | 189 // Passing '0' tells png_process_data_pause() not to cache unprocessed data. |
209 m_reader->setReadOffset(m_reader->currentBufferSize() - | 190 m_reader->setReadOffset(m_reader->currentBufferSize() - |
210 png_process_data_pause(png, 0)); | 191 png_process_data_pause(png, 0)); |
211 #else | 192 #else |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
243 } | 224 } |
244 | 225 |
245 buffer.setStatus(ImageFrame::FramePartial); | 226 buffer.setStatus(ImageFrame::FramePartial); |
246 buffer.setHasAlpha(false); | 227 buffer.setHasAlpha(false); |
247 | 228 |
248 // For PNGs, the frame always fills the entire image. | 229 // For PNGs, the frame always fills the entire image. |
249 buffer.setOriginalFrameRect(IntRect(IntPoint(), size())); | 230 buffer.setOriginalFrameRect(IntRect(IntPoint(), size())); |
250 } | 231 } |
251 | 232 |
252 /* libpng comments (here to explain what follows). | 233 /* libpng comments (here to explain what follows). |
253 * | 234 * |
254 * this function is called for every row in the image. If the | 235 * this function is called for every row in the image. If the |
255 * image is interlacing, and you turned on the interlace handler, | 236 * image is interlacing, and you turned on the interlace handler, |
256 * this function will be called for every row in every pass. | 237 * this function will be called for every row in every pass. |
257 * Some of these rows will not be changed from the previous pass. | 238 * 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. | 239 * 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 | 240 * 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 | 241 * need the row_num and pass, but I'm supplying them because it |
261 * may make your life easier. | 242 * may make your life easier. |
262 */ | 243 */ |
263 | 244 |
264 // Nothing to do if the row is unchanged, or the row is outside | 245 // 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 | 246 // the image bounds: libpng may send extra rows, ignore them to |
266 // make our lives easier. | 247 // make our lives easier. |
267 if (!rowBuffer) | 248 if (!rowBuffer) |
268 return; | 249 return; |
269 int y = rowIndex; | 250 int y = rowIndex; |
270 if (y < 0 || y >= size().height()) | 251 if (y < 0 || y >= size().height()) |
271 return; | 252 return; |
272 | 253 |
273 /* libpng comments (continued). | 254 /* libpng comments (continued). |
274 * | 255 * |
275 * For the non-NULL rows of interlaced images, you must call | 256 * For the non-NULL rows of interlaced images, you must call |
276 * png_progressive_combine_row() passing in the row and the | 257 * png_progressive_combine_row() passing in the row and the |
277 * old row. You can call this function for NULL rows (it will | 258 * old row. You can call this function for NULL rows (it will |
278 * just return) and for non-interlaced images (it just does the | 259 * just return) and for non-interlaced images (it just does the |
279 * memcpy for you) if it will make the code easier. Thus, you | 260 * memcpy for you) if it will make the code easier. Thus, you |
280 * can just do this for all cases: | 261 * can just do this for all cases: |
281 * | 262 * |
282 * png_progressive_combine_row(png_ptr, old_row, new_row); | 263 * png_progressive_combine_row(png_ptr, old_row, new_row); |
283 * | 264 * |
284 * where old_row is what was displayed for previous rows. Note | 265 * where old_row is what was displayed for previous rows. Note |
285 * that the first pass (pass == 0 really) will completely cover | 266 * that the first pass (pass == 0 really) will completely cover |
286 * the old row, so the rows do not have to be initialized. After | 267 * 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 | 268 * the first pass (and only for interlaced images), you will have |
288 * to pass the current row, and the function will combine the | 269 * to pass the current row, and the function will combine the |
289 * old row and the new row. | 270 * old row and the new row. |
290 */ | 271 */ |
291 | 272 |
292 bool hasAlpha = m_reader->hasAlpha(); | 273 bool hasAlpha = m_reader->hasAlpha(); |
293 png_bytep row = rowBuffer; | 274 png_bytep row = rowBuffer; |
294 | 275 |
295 if (png_bytep interlaceBuffer = m_reader->interlaceBuffer()) { | 276 if (png_bytep interlaceBuffer = m_reader->interlaceBuffer()) { |
296 unsigned colorChannels = hasAlpha ? 4 : 3; | 277 unsigned colorChannels = hasAlpha ? 4 : 3; |
297 row = interlaceBuffer + (rowIndex * colorChannels * size().width()); | 278 row = interlaceBuffer + (rowIndex * colorChannels * size().width()); |
298 png_progressive_combine_row(m_reader->pngPtr(), row, rowBuffer); | 279 png_progressive_combine_row(m_reader->pngPtr(), row, rowBuffer); |
299 } | 280 } |
300 | 281 |
301 // Write the decoded row pixels to the frame buffer. The repetitive | 282 // Write the decoded row pixels to the frame buffer. The repetitive |
302 // form of the row write loops is for speed. | 283 // form of the row write loops is for speed. |
303 ImageFrame::PixelData* const dstRow = buffer.getAddr(0, y); | 284 ImageFrame::PixelData* const dstRow = buffer.getAddr(0, y); |
304 unsigned alphaMask = 255; | |
305 int width = size().width(); | 285 int width = size().width(); |
306 | 286 |
307 png_bytep srcPtr = row; | 287 png_bytep srcPtr = row; |
308 if (hasAlpha) { | 288 if (hasAlpha) { |
309 // Here we apply the color space transformation to the dst space. | 289 // Here we apply the color space transformation to the dst space. |
310 // It does not really make sense to transform to a gamma-encoded | 290 // It does not really make sense to transform to a gamma-encoded |
311 // space and then immediately after, perform a linear premultiply. | 291 // space and then immediately after, perform a linear premultiply. |
312 // Ideally we would pass kPremul_SkAlphaType to xform->apply(), | 292 // Ideally we would pass kPremul_SkAlphaType to xform->apply(), |
313 // instructing SkColorSpaceXform to perform the linear premultiply | 293 // instructing SkColorSpaceXform to perform the linear premultiply |
314 // while the pixels are a linear space. | 294 // while the pixels are a linear space. |
315 // We cannot do this because when we apply the gamma encoding after | 295 // We cannot do this because when we apply the gamma encoding after |
316 // the premultiply, we will very likely end up with valid pixels | 296 // 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 | 297 // where R, G, and/or B are greater than A. The legacy drawing |
318 // pipeline does not know how to handle this. | 298 // pipeline does not know how to handle this. |
319 if (SkColorSpaceXform* xform = colorTransform()) { | 299 if (SkColorSpaceXform* xform = colorTransform()) { |
320 SkColorSpaceXform::ColorFormat colorFormat = | 300 SkColorSpaceXform::ColorFormat colorFormat = |
321 SkColorSpaceXform::kRGBA_8888_ColorFormat; | 301 SkColorSpaceXform::kRGBA_8888_ColorFormat; |
322 xform->apply(colorFormat, dstRow, colorFormat, srcPtr, size().width(), | 302 xform->apply(colorFormat, dstRow, colorFormat, srcPtr, size().width(), |
323 kUnpremul_SkAlphaType); | 303 kUnpremul_SkAlphaType); |
324 srcPtr = (png_bytep)dstRow; | 304 srcPtr = png_bytep(dstRow); |
325 } | 305 } |
326 | 306 |
| 307 unsigned alphaMask = 255; |
327 if (buffer.premultiplyAlpha()) { | 308 if (buffer.premultiplyAlpha()) { |
328 for (auto *dstPixel = dstRow; dstPixel < dstRow + width; | 309 for (auto *dstPixel = dstRow; dstPixel < dstRow + width; |
329 dstPixel++, srcPtr += 4) { | 310 srcPtr += 4, ++dstPixel) { |
330 buffer.setRGBAPremultiply(dstPixel, srcPtr[0], srcPtr[1], srcPtr[2], | 311 buffer.setRGBAPremultiply(dstPixel, srcPtr[0], srcPtr[1], srcPtr[2], |
331 srcPtr[3]); | 312 srcPtr[3]); |
332 alphaMask &= srcPtr[3]; | 313 alphaMask &= srcPtr[3]; |
333 } | 314 } |
334 } else { | 315 } else { |
335 for (auto *dstPixel = dstRow; dstPixel < dstRow + width; | 316 for (auto *dstPixel = dstRow; dstPixel < dstRow + width; |
336 dstPixel++, srcPtr += 4) { | 317 srcPtr += 4, ++dstPixel) { |
337 buffer.setRGBARaw(dstPixel, srcPtr[0], srcPtr[1], srcPtr[2], srcPtr[3]); | 318 buffer.setRGBARaw(dstPixel, srcPtr[0], srcPtr[1], srcPtr[2], srcPtr[3]); |
338 alphaMask &= srcPtr[3]; | 319 alphaMask &= srcPtr[3]; |
339 } | 320 } |
340 } | 321 } |
| 322 |
| 323 if (alphaMask != 255 && !buffer.hasAlpha()) |
| 324 buffer.setHasAlpha(true); |
| 325 |
341 } else { | 326 } else { |
342 for (auto *dstPixel = dstRow; dstPixel < dstRow + width; | 327 for (auto *dstPixel = dstRow; dstPixel < dstRow + width; |
343 dstPixel++, srcPtr += 3) { | 328 srcPtr += 3, ++dstPixel) { |
344 buffer.setRGBARaw(dstPixel, srcPtr[0], srcPtr[1], srcPtr[2], 255); | 329 buffer.setRGBARaw(dstPixel, srcPtr[0], srcPtr[1], srcPtr[2], 255); |
345 } | 330 } |
346 | 331 |
347 // We'll apply the color space xform to opaque pixels after they have been | 332 // We'll apply the color space xform to opaque pixels after they have been |
348 // written to the ImageFrame, purely because SkColorSpaceXform supports | 333 // written to the ImageFrame, purely because SkColorSpaceXform supports |
349 // RGBA (and not RGB). | 334 // RGBA (and not RGB). |
350 if (SkColorSpaceXform* xform = colorTransform()) { | 335 if (SkColorSpaceXform* xform = colorTransform()) { |
351 xform->apply(xformColorFormat(), dstRow, xformColorFormat(), dstRow, | 336 xform->apply(xformColorFormat(), dstRow, xformColorFormat(), dstRow, |
352 size().width(), kOpaque_SkAlphaType); | 337 size().width(), kOpaque_SkAlphaType); |
353 } | 338 } |
354 } | 339 } |
355 | 340 |
356 if (alphaMask != 255 && !buffer.hasAlpha()) | |
357 buffer.setHasAlpha(true); | |
358 | |
359 buffer.setPixelsChanged(true); | 341 buffer.setPixelsChanged(true); |
360 } | 342 } |
361 | 343 |
362 void PNGImageDecoder::complete() { | 344 void PNGImageDecoder::complete() { |
363 if (m_frameBufferCache.isEmpty()) | 345 if (m_frameBufferCache.isEmpty()) |
364 return; | 346 return; |
365 | 347 |
366 m_frameBufferCache[0].setStatus(ImageFrame::FrameComplete); | 348 m_frameBufferCache[0].setStatus(ImageFrame::FrameComplete); |
367 } | 349 } |
368 | 350 |
(...skipping 12 matching lines...) Expand all Loading... |
381 // has failed. | 363 // has failed. |
382 if (!m_reader->decode(*m_data, onlySize) && isAllDataReceived()) | 364 if (!m_reader->decode(*m_data, onlySize) && isAllDataReceived()) |
383 setFailed(); | 365 setFailed(); |
384 | 366 |
385 // If decoding is done or failed, we don't need the PNGImageReader anymore. | 367 // If decoding is done or failed, we don't need the PNGImageReader anymore. |
386 if (isComplete(this) || failed()) | 368 if (isComplete(this) || failed()) |
387 m_reader.reset(); | 369 m_reader.reset(); |
388 } | 370 } |
389 | 371 |
390 } // namespace blink | 372 } // namespace blink |
OLD | NEW |