Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(642)

Side by Side Diff: src/codec/SkPngCodec.cpp

Issue 1643623004: A variety of SkPngCodec clean-ups (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Change comment Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2015 Google Inc. 2 * Copyright 2015 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkCodecPriv.h" 8 #include "SkCodecPriv.h"
9 #include "SkColorPriv.h" 9 #include "SkColorPriv.h"
10 #include "SkColorTable.h" 10 #include "SkColorTable.h"
11 #include "SkBitmap.h" 11 #include "SkBitmap.h"
12 #include "SkMath.h" 12 #include "SkMath.h"
13 #include "SkOpts.h"
13 #include "SkPngCodec.h" 14 #include "SkPngCodec.h"
14 #include "SkPngFilters.h" 15 #include "SkPngFilters.h"
15 #include "SkSize.h" 16 #include "SkSize.h"
16 #include "SkStream.h" 17 #include "SkStream.h"
17 #include "SkSwizzler.h" 18 #include "SkSwizzler.h"
18 #include "SkTemplates.h" 19 #include "SkTemplates.h"
19 20
20 #if defined(__SSE2__) 21 #if defined(__SSE2__)
21 #include "pngstruct.h" 22 #include "pngstruct.h"
22 23
23 extern "C" void sk_png_init_filter_functions_sse2(png_structp png, unsigned int bpp) { 24 extern "C" void sk_png_init_filter_functions_sse2(png_structp png, unsigned int bpp) {
24 if (bpp == 3) { 25 if (bpp == 3) {
25 png->read_filter[PNG_FILTER_VALUE_SUB -1] = sk_sub3_sse2; 26 png->read_filter[PNG_FILTER_VALUE_SUB -1] = sk_sub3_sse2;
26 png->read_filter[PNG_FILTER_VALUE_AVG -1] = sk_avg3_sse2; 27 png->read_filter[PNG_FILTER_VALUE_AVG -1] = sk_avg3_sse2;
27 png->read_filter[PNG_FILTER_VALUE_PAETH-1] = sk_paeth3_sse2; 28 png->read_filter[PNG_FILTER_VALUE_PAETH-1] = sk_paeth3_sse2;
28 } 29 }
29 if (bpp == 4) { 30 if (bpp == 4) {
30 png->read_filter[PNG_FILTER_VALUE_SUB -1] = sk_sub4_sse2; 31 png->read_filter[PNG_FILTER_VALUE_SUB -1] = sk_sub4_sse2;
31 png->read_filter[PNG_FILTER_VALUE_AVG -1] = sk_avg4_sse2; 32 png->read_filter[PNG_FILTER_VALUE_AVG -1] = sk_avg4_sse2;
32 png->read_filter[PNG_FILTER_VALUE_PAETH-1] = sk_paeth4_sse2; 33 png->read_filter[PNG_FILTER_VALUE_PAETH-1] = sk_paeth4_sse2;
33 } 34 }
34 } 35 }
35 #endif 36 #endif
36 37
37 /////////////////////////////////////////////////////////////////////////////// 38 ///////////////////////////////////////////////////////////////////////////////
38 // Helper macros
39 ///////////////////////////////////////////////////////////////////////////////
40
41 #ifndef png_jmpbuf
42 # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
43 #endif
44
45 /* These were dropped in libpng >= 1.4 */
46 #ifndef png_infopp_NULL
47 #define png_infopp_NULL nullptr
48 #endif
49
50 #ifndef png_bytepp_NULL
51 #define png_bytepp_NULL nullptr
52 #endif
53
54 #ifndef int_p_NULL
55 #define int_p_NULL nullptr
56 #endif
57
58 #ifndef png_flush_ptr_NULL
59 #define png_flush_ptr_NULL nullptr
60 #endif
61
62 ///////////////////////////////////////////////////////////////////////////////
63 // Callback functions 39 // Callback functions
64 /////////////////////////////////////////////////////////////////////////////// 40 ///////////////////////////////////////////////////////////////////////////////
65 41
66 static void sk_error_fn(png_structp png_ptr, png_const_charp msg) { 42 static void sk_error_fn(png_structp png_ptr, png_const_charp msg) {
67 SkCodecPrintf("------ png error %s\n", msg); 43 SkCodecPrintf("------ png error %s\n", msg);
68 longjmp(png_jmpbuf(png_ptr), 1); 44 longjmp(png_jmpbuf(png_ptr), 1);
69 } 45 }
70 46
71 void sk_warning_fn(png_structp, png_const_charp msg) { 47 void sk_warning_fn(png_structp, png_const_charp msg) {
72 SkCodecPrintf("----- png warning %s\n", msg); 48 SkCodecPrintf("----- png warning %s\n", msg);
(...skipping 26 matching lines...) Expand all
99 class AutoCleanPng : public SkNoncopyable { 75 class AutoCleanPng : public SkNoncopyable {
100 public: 76 public:
101 AutoCleanPng(png_structp png_ptr) 77 AutoCleanPng(png_structp png_ptr)
102 : fPng_ptr(png_ptr) 78 : fPng_ptr(png_ptr)
103 , fInfo_ptr(nullptr) {} 79 , fInfo_ptr(nullptr) {}
104 80
105 ~AutoCleanPng() { 81 ~AutoCleanPng() {
106 // fInfo_ptr will never be non-nullptr unless fPng_ptr is. 82 // fInfo_ptr will never be non-nullptr unless fPng_ptr is.
107 if (fPng_ptr) { 83 if (fPng_ptr) {
108 png_infopp info_pp = fInfo_ptr ? &fInfo_ptr : nullptr; 84 png_infopp info_pp = fInfo_ptr ? &fInfo_ptr : nullptr;
109 png_destroy_read_struct(&fPng_ptr, info_pp, png_infopp_NULL); 85 png_destroy_read_struct(&fPng_ptr, info_pp, nullptr);
110 } 86 }
111 } 87 }
112 88
113 void setInfoPtr(png_infop info_ptr) { 89 void setInfoPtr(png_infop info_ptr) {
114 SkASSERT(nullptr == fInfo_ptr); 90 SkASSERT(nullptr == fInfo_ptr);
115 fInfo_ptr = info_ptr; 91 fInfo_ptr = info_ptr;
116 } 92 }
117 93
118 void detach() { 94 void detach() {
119 fPng_ptr = nullptr; 95 fPng_ptr = nullptr;
120 fInfo_ptr = nullptr; 96 fInfo_ptr = nullptr;
121 } 97 }
122 98
123 private: 99 private:
124 png_structp fPng_ptr; 100 png_structp fPng_ptr;
125 png_infop fInfo_ptr; 101 png_infop fInfo_ptr;
126 }; 102 };
127 #define AutoCleanPng(...) SK_REQUIRE_LOCAL_VAR(AutoCleanPng) 103 #define AutoCleanPng(...) SK_REQUIRE_LOCAL_VAR(AutoCleanPng)
128 104
129 //checks if there is transparency info in the tRNS chunk
130 //image types which could have data in the tRNS chunk include: Index8, Gray8, RG B
131 static bool has_transparency_in_tRNS(png_structp png_ptr,
132 png_infop info_ptr) {
133 if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
134 return false;
135 }
136
137 png_bytep trans;
138 int num_trans;
139 png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, nullptr);
140 return num_trans > 0;
141 }
142
143 // Method for coverting to either an SkPMColor or a similarly packed 105 // Method for coverting to either an SkPMColor or a similarly packed
144 // unpremultiplied color. 106 // unpremultiplied color.
145 typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b); 107 typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b);
146 108
147 // Note: SkColorTable claims to store SkPMColors, which is not necessarily 109 // Note: SkColorTable claims to store SkPMColors, which is not necessarily
148 // the case here. 110 // the case here.
111 // TODO: If we add support for non-native swizzles, we'll need to handle that he re.
149 bool SkPngCodec::decodePalette(bool premultiply, int* ctableCount) { 112 bool SkPngCodec::decodePalette(bool premultiply, int* ctableCount) {
150 int numPalette;
151 png_colorp palette;
152 png_bytep trans;
153 113
154 if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numPalette)) { 114 int numColors;
115 png_color* palette;
116 if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numColors)) {
155 return false; 117 return false;
156 } 118 }
157 119
158 // Note: These are not necessarily SkPMColors 120 // Note: These are not necessarily SkPMColors.
159 SkPMColor colorStorage[256]; // worst-case storage 121 SkPMColor colorPtr[256];
160 SkPMColor* colorPtr = colorStorage;
161 122
162 int numTrans; 123 png_bytep alphas;
163 if (png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS)) { 124 int numColorsWithAlpha = 0;
164 png_get_tRNS(fPng_ptr, fInfo_ptr, &trans, &numTrans, nullptr); 125 if (png_get_tRNS(fPng_ptr, fInfo_ptr, &alphas, &numColorsWithAlpha, nullptr) ) {
165 } else { 126 // Choose which function to use to create the color table. If the final destination's
166 numTrans = 0; 127 // colortype is unpremultiplied, the color table will store unpremultipl ied colors.
128 PackColorProc proc;
129 if (premultiply) {
130 proc = &SkPremultiplyARGBInline;
131 } else {
132 proc = &SkPackARGB32NoCheck;
133 }
134
135 for (int i = 0; i < numColorsWithAlpha; i++) {
136 // We don't have a function in SkOpts that combines a set of alphas with a set
137 // of RGBs. We could write one, but it's hardly worth it, given tha t this
138 // is such a small fraction of the total decode time.
139 colorPtr[i] = proc(alphas[i], palette->red, palette->green, palette- >blue);
140 palette++;
141 }
167 } 142 }
168 143
169 // check for bad images that might make us crash 144 if (numColorsWithAlpha < numColors) {
170 if (numTrans > numPalette) { 145 // The optimized code depends on a 3-byte png_color struct with the colo rs
171 numTrans = numPalette; 146 // in RGB order. These checks make sure it is safe to use.
147 static_assert(3 == sizeof(png_color), "png_color struct has changed. Op ts are broken.");
148 #ifdef SK_DEBUG
149 SkASSERT(&palette->red < &palette->green);
150 SkASSERT(&palette->green < &palette->blue);
151 #endif
152
153 #ifdef SK_PMCOLOR_IS_RGBA
154 SkOpts::RGB_to_RGB1(colorPtr + numColorsWithAlpha, palette, numColors - numColorsWithAlpha);
155 #else
156 SkOpts::RGB_to_BGR1(colorPtr + numColorsWithAlpha, palette, numColors - numColorsWithAlpha);
157 #endif
172 } 158 }
173 159
174 int index = 0; 160 // Pad the color table with the last color in the table (or black) in the ca se that
175 161 // invalid pixel indices exceed the number of colors in the table.
176 // Choose which function to use to create the color table. If the final dest ination's 162 const int maxColors = 1 << fBitDepth;
177 // colortype is unpremultiplied, the color table will store unpremultiplied colors. 163 if (numColors < maxColors) {
178 PackColorProc proc; 164 SkPMColor lastColor = numColors > 0 ? colorPtr[numColors - 1] : SK_Color BLACK;
179 if (premultiply) { 165 sk_memset32(colorPtr + numColors, lastColor, maxColors - numColors);
180 proc = &SkPreMultiplyARGB;
181 } else {
182 proc = &SkPackARGB32NoCheck;
183 }
184 for (; index < numTrans; index++) {
185 *colorPtr++ = proc(*trans++, palette->red, palette->green, palette->blue );
186 palette++;
187 } 166 }
188 167
189 for (; index < numPalette; index++) { 168 // Set the new color count.
190 *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette-> blue); 169 if (ctableCount != nullptr) {
191 palette++; 170 *ctableCount = maxColors;
192 } 171 }
193 172
194 /* BUGGY IMAGE WORKAROUND 173 fColorTable.reset(new SkColorTable(colorPtr, maxColors));
195 Invalid images could contain pixel values that are greater than the numb er of palette
196 entries. Since we use pixel values as indices into the palette this coul d result in reading
197 beyond the end of the palette which could leak the contents of uninitial ized memory. To
198 ensure this doesn't happen, we grow the colortable to the maximum size t hat can be
199 addressed by the bitdepth of the image and fill it with the last palette color or black if
200 the palette is empty (really broken image).
201 */
202 int colorCount = SkTMax(numPalette, 1 << SkTMin(fBitDepth, 8));
203 SkPMColor lastColor = index > 0 ? colorPtr[-1] : SkPackARGB32(0xFF, 0, 0, 0) ;
204 for (; index < colorCount; index++) {
205 *colorPtr++ = lastColor;
206 }
207
208 // Set the new color count
209 if (ctableCount != nullptr) {
210 *ctableCount = colorCount;
211 }
212
213 fColorTable.reset(new SkColorTable(colorStorage, colorCount));
214 return true; 174 return true;
215 } 175 }
216 176
217 /////////////////////////////////////////////////////////////////////////////// 177 ///////////////////////////////////////////////////////////////////////////////
218 // Creation 178 // Creation
219 /////////////////////////////////////////////////////////////////////////////// 179 ///////////////////////////////////////////////////////////////////////////////
220 180
221 bool SkPngCodec::IsPng(const char* buf, size_t bytesRead) { 181 bool SkPngCodec::IsPng(const char* buf, size_t bytesRead) {
222 return !png_sig_cmp((png_bytep) buf, (png_size_t)0, bytesRead); 182 return !png_sig_cmp((png_bytep) buf, (png_size_t)0, bytesRead);
223 } 183 }
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
276 if (chunkReader) { 236 if (chunkReader) {
277 png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte* )"", 0); 237 png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte* )"", 0);
278 png_set_read_user_chunk_fn(png_ptr, (png_voidp) chunkReader, sk_read_use r_chunk); 238 png_set_read_user_chunk_fn(png_ptr, (png_voidp) chunkReader, sk_read_use r_chunk);
279 } 239 }
280 #endif 240 #endif
281 241
282 // The call to png_read_info() gives us all of the information from the 242 // The call to png_read_info() gives us all of the information from the
283 // PNG file before the first IDAT (image data chunk). 243 // PNG file before the first IDAT (image data chunk).
284 png_read_info(png_ptr, info_ptr); 244 png_read_info(png_ptr, info_ptr);
285 png_uint_32 origWidth, origHeight; 245 png_uint_32 origWidth, origHeight;
286 int bitDepth, colorType; 246 int bitDepth, encodedColorType;
287 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth, 247 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,
288 &colorType, int_p_NULL, int_p_NULL, int_p_NULL); 248 &encodedColorType, nullptr, nullptr, nullptr);
289 249
290 if (bitDepthPtr) { 250 if (bitDepthPtr) {
291 *bitDepthPtr = bitDepth; 251 *bitDepthPtr = bitDepth;
292 } 252 }
293 253
294 // sanity check for size 254 // Tell libpng to strip 16 bit/color files down to 8 bits/color.
295 { 255 // TODO: Should we handle this in SkSwizzler? Could this also benefit
296 int64_t size = sk_64_mul(origWidth, origHeight); 256 // RAW decodes?
297 // now check that if we are 4-bytes per pixel, we also don't overflow 257 if (bitDepth == 16) {
298 if (size < 0 || size > (0x7FFFFFFF >> 2)) { 258 SkASSERT(PNG_COLOR_TYPE_PALETTE != encodedColorType);
299 return false; 259 png_set_strip_16(png_ptr);
300 }
301 } 260 }
302 261
303 // Tell libpng to strip 16 bit/color files down to 8 bits/color 262 // Now determine the default colorType and alphaType and set the required tr ansforms.
304 if (bitDepth == 16) { 263 // Often, we depend on SkSwizzler to perform any transforms that we need. H owever, we
305 png_set_strip_16(png_ptr); 264 // still depend on libpng for many of the rare and PNG-specific cases.
306 } 265 SkColorType colorType = kUnknown_SkColorType;
307 #ifdef PNG_READ_PACK_SUPPORTED 266 SkAlphaType alphaType = kUnknown_SkAlphaType;
308 // Extract multiple pixels with bit depths of 1, 2, and 4 from a single 267 switch (encodedColorType) {
309 // byte into separate bytes (useful for paletted and grayscale images). 268 case PNG_COLOR_TYPE_PALETTE:
310 if (bitDepth < 8) { 269 // Extract multiple pixels with bit depths of 1, 2, and 4 from a sin gle
311 png_set_packing(png_ptr); 270 // byte into separate bytes (useful for paletted and grayscale image s).
312 } 271 if (bitDepth < 8) {
313 #endif 272 // TODO: Should we use SkSwizzler here?
314 // Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel. 273 png_set_packing(png_ptr);
315 if (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8) { 274 }
316 png_set_expand_gray_1_2_4_to_8(png_ptr);
317 }
318 275
319 // Now determine the default SkColorType and SkAlphaType and set required tr ansforms 276 colorType = kIndex_8_SkColorType;
320 SkColorType skColorType = kUnknown_SkColorType; 277 // Set the alpha type depending on if a transparency chunk exists.
321 SkAlphaType skAlphaType = kUnknown_SkAlphaType; 278 alphaType = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) ?
322 switch (colorType) {
323 case PNG_COLOR_TYPE_PALETTE:
324 skColorType = kIndex_8_SkColorType;
325 skAlphaType = has_transparency_in_tRNS(png_ptr, info_ptr) ?
326 kUnpremul_SkAlphaType : kOpaque_SkAlphaType; 279 kUnpremul_SkAlphaType : kOpaque_SkAlphaType;
327 break; 280 break;
328 case PNG_COLOR_TYPE_RGB: 281 case PNG_COLOR_TYPE_RGB:
329 if (has_transparency_in_tRNS(png_ptr, info_ptr)) { 282 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
330 //convert to RGBA with tranparency information in tRNS chunk if it exists 283 // Convert to RGBA if transparency chunk exists.
331 png_set_tRNS_to_alpha(png_ptr); 284 png_set_tRNS_to_alpha(png_ptr);
332 skAlphaType = kUnpremul_SkAlphaType; 285 alphaType = kUnpremul_SkAlphaType;
333 } else { 286 } else {
334 skAlphaType = kOpaque_SkAlphaType; 287 alphaType = kOpaque_SkAlphaType;
335 } 288 }
336 skColorType = kN32_SkColorType; 289 colorType = kN32_SkColorType;
337 break; 290 break;
338 case PNG_COLOR_TYPE_GRAY: 291 case PNG_COLOR_TYPE_GRAY:
339 if (has_transparency_in_tRNS(png_ptr, info_ptr)) { 292 // Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/p ixel.
340 //FIXME: support gray with alpha as a color type 293 if (bitDepth < 8) {
341 //convert to RGBA if there is transparentcy info in the tRNS chu nk 294 // TODO: Should we use SkSwizzler here?
295 png_set_expand_gray_1_2_4_to_8(png_ptr);
296 }
297
298 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
299 // Convert to RGBA if there is a transparency chunk.
342 png_set_tRNS_to_alpha(png_ptr); 300 png_set_tRNS_to_alpha(png_ptr);
343 png_set_gray_to_rgb(png_ptr); 301 png_set_gray_to_rgb(png_ptr);
344 skColorType = kN32_SkColorType; 302 colorType = kN32_SkColorType;
345 skAlphaType = kUnpremul_SkAlphaType; 303 alphaType = kUnpremul_SkAlphaType;
346 } else { 304 } else {
347 skColorType = kGray_8_SkColorType; 305 colorType = kGray_8_SkColorType;
348 skAlphaType = kOpaque_SkAlphaType; 306 alphaType = kOpaque_SkAlphaType;
349 } 307 }
350 break; 308 break;
351 case PNG_COLOR_TYPE_GRAY_ALPHA: 309 case PNG_COLOR_TYPE_GRAY_ALPHA:
352 //FIXME: support gray with alpha as a color type 310 // Convert to RGBA if the image has alpha.
353 //convert to RGBA
354 png_set_gray_to_rgb(png_ptr); 311 png_set_gray_to_rgb(png_ptr);
355 skColorType = kN32_SkColorType; 312 colorType = kN32_SkColorType;
356 skAlphaType = kUnpremul_SkAlphaType; 313 alphaType = kUnpremul_SkAlphaType;
357 break; 314 break;
358 case PNG_COLOR_TYPE_RGBA: 315 case PNG_COLOR_TYPE_RGBA:
359 skColorType = kN32_SkColorType; 316 colorType = kN32_SkColorType;
360 skAlphaType = kUnpremul_SkAlphaType; 317 alphaType = kUnpremul_SkAlphaType;
361 break; 318 break;
362 default: 319 default:
363 //all the color types have been covered above 320 // All the color types have been covered above.
364 SkASSERT(false); 321 SkASSERT(false);
365 } 322 }
366 323
367 int numberPasses = png_set_interlace_handling(png_ptr); 324 int numberPasses = png_set_interlace_handling(png_ptr);
368 if (numberPassesPtr) { 325 if (numberPassesPtr) {
369 *numberPassesPtr = numberPasses; 326 *numberPassesPtr = numberPasses;
370 } 327 }
371 328
372 // FIXME: Also need to check for sRGB ( https://bug.skia.org/3471 ). 329 // FIXME: Also need to check for sRGB ( https://bug.skia.org/3471 ).
373 330
374 if (imageInfo) { 331 if (imageInfo) {
375 *imageInfo = SkImageInfo::Make(origWidth, origHeight, skColorType, skAlp haType); 332 *imageInfo = SkImageInfo::Make(origWidth, origHeight, colorType, alphaTy pe);
376 } 333 }
377 autoClean.detach(); 334 autoClean.detach();
378 if (png_ptrp) { 335 if (png_ptrp) {
379 *png_ptrp = png_ptr; 336 *png_ptrp = png_ptr;
380 } 337 }
381 if (info_ptrp) { 338 if (info_ptrp) {
382 *info_ptrp = info_ptr; 339 *info_ptrp = info_ptr;
383 } 340 }
384 341
385 return true; 342 return true;
(...skipping 11 matching lines...) Expand all
397 {} 354 {}
398 355
399 SkPngCodec::~SkPngCodec() { 356 SkPngCodec::~SkPngCodec() {
400 this->destroyReadStruct(); 357 this->destroyReadStruct();
401 } 358 }
402 359
403 void SkPngCodec::destroyReadStruct() { 360 void SkPngCodec::destroyReadStruct() {
404 if (fPng_ptr) { 361 if (fPng_ptr) {
405 // We will never have a nullptr fInfo_ptr with a non-nullptr fPng_ptr 362 // We will never have a nullptr fInfo_ptr with a non-nullptr fPng_ptr
406 SkASSERT(fInfo_ptr); 363 SkASSERT(fInfo_ptr);
407 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL); 364 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, nullptr);
408 fPng_ptr = nullptr; 365 fPng_ptr = nullptr;
409 fInfo_ptr = nullptr; 366 fInfo_ptr = nullptr;
410 } 367 }
411 } 368 }
412 369
413 /////////////////////////////////////////////////////////////////////////////// 370 ///////////////////////////////////////////////////////////////////////////////
414 // Getting the pixels 371 // Getting the pixels
415 /////////////////////////////////////////////////////////////////////////////// 372 ///////////////////////////////////////////////////////////////////////////////
416 373
417 SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo, 374 SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo,
418 const Options& options, 375 const Options& options,
419 SkPMColor ctable[], 376 SkPMColor ctable[],
420 int* ctableCount) { 377 int* ctableCount) {
421 // FIXME: Could we use the return value of setjmp to specify the type of 378 // FIXME: Could we use the return value of setjmp to specify the type of
422 // error? 379 // error?
423 if (setjmp(png_jmpbuf(fPng_ptr))) { 380 if (setjmp(png_jmpbuf(fPng_ptr))) {
424 SkCodecPrintf("setjmp long jump!\n"); 381 SkCodecPrintf("setjmp long jump!\n");
425 return kInvalidInput; 382 return kInvalidInput;
426 } 383 }
427 png_read_update_info(fPng_ptr, fInfo_ptr); 384 png_read_update_info(fPng_ptr, fInfo_ptr);
428 385
429 //srcColorType was determined in read_header() which determined png color ty pe 386 // srcColorType was determined in read_header() which determined png color t ype
430 const SkColorType srcColorType = this->getInfo().colorType(); 387 const SkColorType srcColorType = this->getInfo().colorType();
431 388
432 switch (srcColorType) { 389 switch (srcColorType) {
433 case kIndex_8_SkColorType: 390 case kIndex_8_SkColorType:
434 //decode palette to Skia format 391 //decode palette to Skia format
435 fSrcConfig = SkSwizzler::kIndex; 392 fSrcConfig = SkSwizzler::kIndex;
436 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaT ype(), 393 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaT ype(),
437 ctableCount)) { 394 ctableCount)) {
438 return kInvalidInput; 395 return kInvalidInput;
439 } 396 }
440 break; 397 break;
441 case kGray_8_SkColorType: 398 case kGray_8_SkColorType:
442 fSrcConfig = SkSwizzler::kGray; 399 fSrcConfig = SkSwizzler::kGray;
443 break; 400 break;
444 case kN32_SkColorType: 401 case kN32_SkColorType:
445 if (this->getInfo().alphaType() == kOpaque_SkAlphaType) { 402 if (this->getInfo().alphaType() == kOpaque_SkAlphaType) {
446 fSrcConfig = SkSwizzler::kRGB; 403 fSrcConfig = SkSwizzler::kRGB;
447 } else { 404 } else {
448 fSrcConfig = SkSwizzler::kRGBA; 405 fSrcConfig = SkSwizzler::kRGBA;
449 } 406 }
450 break; 407 break;
451 default: 408 default:
452 //would have exited before now if the colorType was supported by png 409 // We will always recommend one of the above colorTypes.
453 SkASSERT(false); 410 SkASSERT(false);
454 } 411 }
455 412
456 // Copy the color table to the client if they request kIndex8 mode 413 // Copy the color table to the client if they request kIndex8 mode
457 copy_color_table(requestedInfo, fColorTable, ctable, ctableCount); 414 copy_color_table(requestedInfo, fColorTable, ctable, ctableCount);
458 415
459 // Create the swizzler. SkPngCodec retains ownership of the color table. 416 // Create the swizzler. SkPngCodec retains ownership of the color table.
460 const SkPMColor* colors = get_color_ptr(fColorTable.get()); 417 const SkPMColor* colors = get_color_ptr(fColorTable.get());
461 fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo , options)); 418 fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo , options));
462 if (!fSwizzler) { 419 SkASSERT(fSwizzler);
463 // FIXME: CreateSwizzler could fail for another reason. 420
464 return kUnimplemented;
465 }
466 return kSuccess; 421 return kSuccess;
467 } 422 }
468 423
469 424
470 bool SkPngCodec::onRewind() { 425 bool SkPngCodec::onRewind() {
471 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header 426 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header
472 // succeeds, they will be repopulated, and if it fails, they will 427 // succeeds, they will be repopulated, and if it fails, they will
473 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will 428 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will
474 // come through this function which will rewind and again attempt 429 // come through this function which will rewind and again attempt
475 // to reinitialize them. 430 // to reinitialize them.
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
538 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig); 493 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig);
539 const size_t srcRowBytes = width * bpp; 494 const size_t srcRowBytes = width * bpp;
540 495
541 storage.reset(width * height * bpp); 496 storage.reset(width * height * bpp);
542 uint8_t* const base = storage.get(); 497 uint8_t* const base = storage.get();
543 498
544 for (int i = 0; i < fNumberPasses; i++) { 499 for (int i = 0; i < fNumberPasses; i++) {
545 uint8_t* srcRow = base; 500 uint8_t* srcRow = base;
546 for (int y = 0; y < height; y++) { 501 for (int y = 0; y < height; y++) {
547 uint8_t* bmRow = srcRow; 502 uint8_t* bmRow = srcRow;
548 png_read_rows(fPng_ptr, &bmRow, png_bytepp_NULL, 1); 503 png_read_rows(fPng_ptr, &bmRow, nullptr, 1);
549 srcRow += srcRowBytes; 504 srcRow += srcRowBytes;
550 } 505 }
551 } 506 }
552 507
553 // Now swizzle it. 508 // Now swizzle it.
554 uint8_t* srcRow = base; 509 uint8_t* srcRow = base;
555 for (int y = 0; y < height; y++) { 510 for (int y = 0; y < height; y++) {
556 fSwizzler->swizzle(dstRow, srcRow); 511 fSwizzler->swizzle(dstRow, srcRow);
557 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); 512 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
558 srcRow += srcRowBytes; 513 srcRow += srcRowBytes;
559 } 514 }
560 } else { 515 } else {
561 storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConf ig)); 516 storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConf ig));
562 uint8_t* srcRow = storage.get(); 517 uint8_t* srcRow = storage.get();
563 for (; row < requestedInfo.height(); row++) { 518 for (; row < requestedInfo.height(); row++) {
564 png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1); 519 png_read_rows(fPng_ptr, &srcRow, nullptr, 1);
565 // FIXME: Only call IsOpaque once, outside the loop. Same for onGetS canlines. 520 // FIXME: Only call IsOpaque once, outside the loop. Same for onGetS canlines.
566 fSwizzler->swizzle(dstRow, srcRow); 521 fSwizzler->swizzle(dstRow, srcRow);
567 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); 522 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
568 } 523 }
569 } 524 }
570 525
571 // FIXME: do we need substituteTranspColor? Note that we cannot do it for
572 // scanline decoding, but we could do it here. Alternatively, we could do
573 // it as we go, instead of in post-processing like SkPNGImageDecoder.
574
575 if (setjmp(png_jmpbuf(fPng_ptr))) { 526 if (setjmp(png_jmpbuf(fPng_ptr))) {
576 // We've already read all the scanlines. This is a success. 527 // We've already read all the scanlines. This is a success.
577 return kSuccess; 528 return kSuccess;
578 } 529 }
579 530
580 // read rest of file, and get additional comment and time chunks in info_ptr 531 // read rest of file, and get additional comment and time chunks in info_ptr
581 png_read_end(fPng_ptr, fInfo_ptr); 532 png_read_end(fPng_ptr, fInfo_ptr);
582 533
583 return kSuccess; 534 return kSuccess;
584 } 535 }
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
621 int onGetScanlines(void* dst, int count, size_t rowBytes) override { 572 int onGetScanlines(void* dst, int count, size_t rowBytes) override {
622 // Assume that an error in libpng indicates an incomplete input. 573 // Assume that an error in libpng indicates an incomplete input.
623 int row = 0; 574 int row = 0;
624 if (setjmp(png_jmpbuf(this->png_ptr()))) { 575 if (setjmp(png_jmpbuf(this->png_ptr()))) {
625 SkCodecPrintf("setjmp long jump!\n"); 576 SkCodecPrintf("setjmp long jump!\n");
626 return row; 577 return row;
627 } 578 }
628 579
629 void* dstRow = dst; 580 void* dstRow = dst;
630 for (; row < count; row++) { 581 for (; row < count; row++) {
631 png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1); 582 png_read_rows(this->png_ptr(), &fSrcRow, nullptr, 1);
632 this->swizzler()->swizzle(dstRow, fSrcRow); 583 this->swizzler()->swizzle(dstRow, fSrcRow);
633 dstRow = SkTAddOffset<void>(dstRow, rowBytes); 584 dstRow = SkTAddOffset<void>(dstRow, rowBytes);
634 } 585 }
635 586
636 return row; 587 return row;
637 } 588 }
638 589
639 bool onSkipScanlines(int count) override { 590 bool onSkipScanlines(int count) override {
640 // Assume that an error in libpng indicates an incomplete input. 591 // Assume that an error in libpng indicates an incomplete input.
641 if (setjmp(png_jmpbuf(this->png_ptr()))) { 592 if (setjmp(png_jmpbuf(this->png_ptr()))) {
642 SkCodecPrintf("setjmp long jump!\n"); 593 SkCodecPrintf("setjmp long jump!\n");
643 return false; 594 return false;
644 } 595 }
645 //there is a potential tradeoff of memory vs speed created by putting th is in a loop. 596 //there is a potential tradeoff of memory vs speed created by putting th is in a loop.
646 //calling png_read_rows in a loop is insignificantly slower than calling it once with count 597 //calling png_read_rows in a loop is insignificantly slower than calling it once with count
647 //as png_read_rows has it's own loop which calls png_read_row count time s. 598 //as png_read_rows has it's own loop which calls png_read_row count time s.
648 for (int row = 0; row < count; row++) { 599 for (int row = 0; row < count; row++) {
649 png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1); 600 png_read_rows(this->png_ptr(), &fSrcRow, nullptr, 1);
650 } 601 }
651 return true; 602 return true;
652 } 603 }
653 604
654 private: 605 private:
655 SkAutoTMalloc<uint8_t> fStorage; 606 SkAutoTMalloc<uint8_t> fStorage;
656 uint8_t* fSrcRow; 607 uint8_t* fSrcRow;
657 608
658 typedef SkPngCodec INHERITED; 609 typedef SkPngCodec INHERITED;
659 }; 610 };
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
723 // fail on the first pass, we can still report than some scanlines a re initialized. 674 // fail on the first pass, we can still report than some scanlines a re initialized.
724 return 0; 675 return 0;
725 } 676 }
726 SkAutoTMalloc<uint8_t> storage(count * fSrcRowBytes); 677 SkAutoTMalloc<uint8_t> storage(count * fSrcRowBytes);
727 uint8_t* storagePtr = storage.get(); 678 uint8_t* storagePtr = storage.get();
728 uint8_t* srcRow; 679 uint8_t* srcRow;
729 const int startRow = this->nextScanline(); 680 const int startRow = this->nextScanline();
730 for (int i = 0; i < this->numberPasses(); i++) { 681 for (int i = 0; i < this->numberPasses(); i++) {
731 // read rows we planned to skip into garbage row 682 // read rows we planned to skip into garbage row
732 for (int y = 0; y < startRow; y++){ 683 for (int y = 0; y < startRow; y++){
733 png_read_rows(this->png_ptr(), &fGarbageRowPtr, png_bytepp_NULL, 1); 684 png_read_rows(this->png_ptr(), &fGarbageRowPtr, nullptr, 1);
734 } 685 }
735 // read rows we care about into buffer 686 // read rows we care about into buffer
736 srcRow = storagePtr; 687 srcRow = storagePtr;
737 for (int y = 0; y < count; y++) { 688 for (int y = 0; y < count; y++) {
738 png_read_rows(this->png_ptr(), &srcRow, png_bytepp_NULL, 1); 689 png_read_rows(this->png_ptr(), &srcRow, nullptr, 1);
739 srcRow += fSrcRowBytes; 690 srcRow += fSrcRowBytes;
740 } 691 }
741 // read rows we don't want into garbage buffer 692 // read rows we don't want into garbage buffer
742 for (int y = 0; y < fHeight - startRow - count; y++) { 693 for (int y = 0; y < fHeight - startRow - count; y++) {
743 png_read_rows(this->png_ptr(), &fGarbageRowPtr, png_bytepp_NULL, 1); 694 png_read_rows(this->png_ptr(), &fGarbageRowPtr, nullptr, 1);
744 } 695 }
745 } 696 }
746 //swizzle the rows we care about 697 //swizzle the rows we care about
747 srcRow = storagePtr; 698 srcRow = storagePtr;
748 void* dstRow = dst; 699 void* dstRow = dst;
749 for (int y = 0; y < count; y++) { 700 for (int y = 0; y < count; y++) {
750 this->swizzler()->swizzle(dstRow, srcRow); 701 this->swizzler()->swizzle(dstRow, srcRow);
751 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); 702 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
752 srcRow += fSrcRowBytes; 703 srcRow += fSrcRowBytes;
753 } 704 }
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
796 } 747 }
797 748
798 if (1 == numberPasses) { 749 if (1 == numberPasses) {
799 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), chunk Reader, 750 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), chunk Reader,
800 png_ptr, info_ptr, bitDepth); 751 png_ptr, info_ptr, bitDepth);
801 } 752 }
802 753
803 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(), chunkReader, 754 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(), chunkReader,
804 png_ptr, info_ptr, bitDepth, numbe rPasses); 755 png_ptr, info_ptr, bitDepth, numbe rPasses);
805 } 756 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698