OLD | NEW |
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 "SkCodec_libpng.h" | 8 #include "SkCodec_libpng.h" |
9 #include "SkCodecPriv.h" | 9 #include "SkCodecPriv.h" |
10 #include "SkColorPriv.h" | 10 #include "SkColorPriv.h" |
11 #include "SkColorTable.h" | 11 #include "SkColorTable.h" |
12 #include "SkBitmap.h" | 12 #include "SkBitmap.h" |
13 #include "SkMath.h" | 13 #include "SkMath.h" |
14 #include "SkScaledCodec.h" | 14 #include "SkScaledCodec.h" |
15 #include "SkScanlineDecoder.h" | 15 #include "SkScanlineDecoder.h" |
16 #include "SkSize.h" | 16 #include "SkSize.h" |
17 #include "SkStream.h" | 17 #include "SkStream.h" |
18 #include "SkSwizzler.h" | 18 #include "SkSwizzler.h" |
19 | 19 |
20 /////////////////////////////////////////////////////////////////////////////// | 20 /////////////////////////////////////////////////////////////////////////////// |
21 // Helper macros | 21 // Helper macros |
22 /////////////////////////////////////////////////////////////////////////////// | 22 /////////////////////////////////////////////////////////////////////////////// |
23 | 23 |
24 #ifndef png_jmpbuf | 24 #ifndef png_jmpbuf |
25 # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) | 25 # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) |
26 #endif | 26 #endif |
27 | 27 |
28 /* These were dropped in libpng >= 1.4 */ | 28 /* These were dropped in libpng >= 1.4 */ |
29 #ifndef png_infopp_NULL | 29 #ifndef png_infopp_NULL |
30 #define png_infopp_NULL NULL | 30 #define png_infopp_NULL nullptr |
31 #endif | 31 #endif |
32 | 32 |
33 #ifndef png_bytepp_NULL | 33 #ifndef png_bytepp_NULL |
34 #define png_bytepp_NULL NULL | 34 #define png_bytepp_NULL nullptr |
35 #endif | 35 #endif |
36 | 36 |
37 #ifndef int_p_NULL | 37 #ifndef int_p_NULL |
38 #define int_p_NULL NULL | 38 #define int_p_NULL nullptr |
39 #endif | 39 #endif |
40 | 40 |
41 #ifndef png_flush_ptr_NULL | 41 #ifndef png_flush_ptr_NULL |
42 #define png_flush_ptr_NULL NULL | 42 #define png_flush_ptr_NULL nullptr |
43 #endif | 43 #endif |
44 | 44 |
45 /////////////////////////////////////////////////////////////////////////////// | 45 /////////////////////////////////////////////////////////////////////////////// |
46 // Callback functions | 46 // Callback functions |
47 /////////////////////////////////////////////////////////////////////////////// | 47 /////////////////////////////////////////////////////////////////////////////// |
48 | 48 |
49 static void sk_error_fn(png_structp png_ptr, png_const_charp msg) { | 49 static void sk_error_fn(png_structp png_ptr, png_const_charp msg) { |
50 SkCodecPrintf("------ png error %s\n", msg); | 50 SkCodecPrintf("------ png error %s\n", msg); |
51 longjmp(png_jmpbuf(png_ptr), 1); | 51 longjmp(png_jmpbuf(png_ptr), 1); |
52 } | 52 } |
(...skipping 15 matching lines...) Expand all Loading... |
68 } | 68 } |
69 | 69 |
70 /////////////////////////////////////////////////////////////////////////////// | 70 /////////////////////////////////////////////////////////////////////////////// |
71 // Helpers | 71 // Helpers |
72 /////////////////////////////////////////////////////////////////////////////// | 72 /////////////////////////////////////////////////////////////////////////////// |
73 | 73 |
74 class AutoCleanPng : public SkNoncopyable { | 74 class AutoCleanPng : public SkNoncopyable { |
75 public: | 75 public: |
76 AutoCleanPng(png_structp png_ptr) | 76 AutoCleanPng(png_structp png_ptr) |
77 : fPng_ptr(png_ptr) | 77 : fPng_ptr(png_ptr) |
78 , fInfo_ptr(NULL) {} | 78 , fInfo_ptr(nullptr) {} |
79 | 79 |
80 ~AutoCleanPng() { | 80 ~AutoCleanPng() { |
81 // fInfo_ptr will never be non-NULL unless fPng_ptr is. | 81 // fInfo_ptr will never be non-nullptr unless fPng_ptr is. |
82 if (fPng_ptr) { | 82 if (fPng_ptr) { |
83 png_infopp info_pp = fInfo_ptr ? &fInfo_ptr : NULL; | 83 png_infopp info_pp = fInfo_ptr ? &fInfo_ptr : nullptr; |
84 png_destroy_read_struct(&fPng_ptr, info_pp, png_infopp_NULL); | 84 png_destroy_read_struct(&fPng_ptr, info_pp, png_infopp_NULL); |
85 } | 85 } |
86 } | 86 } |
87 | 87 |
88 void setInfoPtr(png_infop info_ptr) { | 88 void setInfoPtr(png_infop info_ptr) { |
89 SkASSERT(NULL == fInfo_ptr); | 89 SkASSERT(nullptr == fInfo_ptr); |
90 fInfo_ptr = info_ptr; | 90 fInfo_ptr = info_ptr; |
91 } | 91 } |
92 | 92 |
93 void detach() { | 93 void detach() { |
94 fPng_ptr = NULL; | 94 fPng_ptr = nullptr; |
95 fInfo_ptr = NULL; | 95 fInfo_ptr = nullptr; |
96 } | 96 } |
97 | 97 |
98 private: | 98 private: |
99 png_structp fPng_ptr; | 99 png_structp fPng_ptr; |
100 png_infop fInfo_ptr; | 100 png_infop fInfo_ptr; |
101 }; | 101 }; |
102 #define AutoCleanPng(...) SK_REQUIRE_LOCAL_VAR(AutoCleanPng) | 102 #define AutoCleanPng(...) SK_REQUIRE_LOCAL_VAR(AutoCleanPng) |
103 | 103 |
104 //checks if there is transparency info in the tRNS chunk | 104 //checks if there is transparency info in the tRNS chunk |
105 //image types which could have data in the tRNS chunk include: Index8, Gray8, RG
B | 105 //image types which could have data in the tRNS chunk include: Index8, Gray8, RG
B |
106 static bool has_transparency_in_tRNS(png_structp png_ptr, | 106 static bool has_transparency_in_tRNS(png_structp png_ptr, |
107 png_infop info_ptr) { | 107 png_infop info_ptr) { |
108 if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { | 108 if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { |
109 return false; | 109 return false; |
110 } | 110 } |
111 | 111 |
112 png_bytep trans; | 112 png_bytep trans; |
113 int num_trans; | 113 int num_trans; |
114 png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL); | 114 png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, nullptr); |
115 return num_trans > 0; | 115 return num_trans > 0; |
116 } | 116 } |
117 | 117 |
118 // Method for coverting to either an SkPMColor or a similarly packed | 118 // Method for coverting to either an SkPMColor or a similarly packed |
119 // unpremultiplied color. | 119 // unpremultiplied color. |
120 typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b); | 120 typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b); |
121 | 121 |
122 // Note: SkColorTable claims to store SkPMColors, which is not necessarily | 122 // Note: SkColorTable claims to store SkPMColors, which is not necessarily |
123 // the case here. | 123 // the case here. |
124 bool SkPngCodec::decodePalette(bool premultiply, int* ctableCount) { | 124 bool SkPngCodec::decodePalette(bool premultiply, int* ctableCount) { |
125 int numPalette; | 125 int numPalette; |
126 png_colorp palette; | 126 png_colorp palette; |
127 png_bytep trans; | 127 png_bytep trans; |
128 | 128 |
129 if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numPalette)) { | 129 if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numPalette)) { |
130 return false; | 130 return false; |
131 } | 131 } |
132 | 132 |
133 // Note: These are not necessarily SkPMColors | 133 // Note: These are not necessarily SkPMColors |
134 SkPMColor colorStorage[256]; // worst-case storage | 134 SkPMColor colorStorage[256]; // worst-case storage |
135 SkPMColor* colorPtr = colorStorage; | 135 SkPMColor* colorPtr = colorStorage; |
136 | 136 |
137 int numTrans; | 137 int numTrans; |
138 if (png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS)) { | 138 if (png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS)) { |
139 png_get_tRNS(fPng_ptr, fInfo_ptr, &trans, &numTrans, NULL); | 139 png_get_tRNS(fPng_ptr, fInfo_ptr, &trans, &numTrans, nullptr); |
140 } else { | 140 } else { |
141 numTrans = 0; | 141 numTrans = 0; |
142 } | 142 } |
143 | 143 |
144 // check for bad images that might make us crash | 144 // check for bad images that might make us crash |
145 if (numTrans > numPalette) { | 145 if (numTrans > numPalette) { |
146 numTrans = numPalette; | 146 numTrans = numPalette; |
147 } | 147 } |
148 | 148 |
149 int index = 0; | 149 int index = 0; |
(...skipping 28 matching lines...) Expand all Loading... |
178 addressed by the bitdepth of the image and fill it with the last palette
color or black if | 178 addressed by the bitdepth of the image and fill it with the last palette
color or black if |
179 the palette is empty (really broken image). | 179 the palette is empty (really broken image). |
180 */ | 180 */ |
181 int colorCount = SkTMax(numPalette, 1 << SkTMin(fBitDepth, 8)); | 181 int colorCount = SkTMax(numPalette, 1 << SkTMin(fBitDepth, 8)); |
182 SkPMColor lastColor = index > 0 ? colorPtr[-1] : SkPackARGB32(0xFF, 0, 0, 0)
; | 182 SkPMColor lastColor = index > 0 ? colorPtr[-1] : SkPackARGB32(0xFF, 0, 0, 0)
; |
183 for (; index < colorCount; index++) { | 183 for (; index < colorCount; index++) { |
184 *colorPtr++ = lastColor; | 184 *colorPtr++ = lastColor; |
185 } | 185 } |
186 | 186 |
187 // Set the new color count | 187 // Set the new color count |
188 if (ctableCount != NULL) { | 188 if (ctableCount != nullptr) { |
189 *ctableCount = colorCount; | 189 *ctableCount = colorCount; |
190 } | 190 } |
191 | 191 |
192 fColorTable.reset(new SkColorTable(colorStorage, colorCount)); | 192 fColorTable.reset(new SkColorTable(colorStorage, colorCount)); |
193 return true; | 193 return true; |
194 } | 194 } |
195 | 195 |
196 /////////////////////////////////////////////////////////////////////////////// | 196 /////////////////////////////////////////////////////////////////////////////// |
197 // Creation | 197 // Creation |
198 /////////////////////////////////////////////////////////////////////////////// | 198 /////////////////////////////////////////////////////////////////////////////// |
199 | 199 |
200 #define PNG_BYTES_TO_CHECK 4 | 200 #define PNG_BYTES_TO_CHECK 4 |
201 | 201 |
202 bool SkPngCodec::IsPng(SkStream* stream) { | 202 bool SkPngCodec::IsPng(SkStream* stream) { |
203 char buf[PNG_BYTES_TO_CHECK]; | 203 char buf[PNG_BYTES_TO_CHECK]; |
204 if (stream->read(buf, PNG_BYTES_TO_CHECK) != PNG_BYTES_TO_CHECK) { | 204 if (stream->read(buf, PNG_BYTES_TO_CHECK) != PNG_BYTES_TO_CHECK) { |
205 return false; | 205 return false; |
206 } | 206 } |
207 if (png_sig_cmp((png_bytep) buf, (png_size_t)0, PNG_BYTES_TO_CHECK)) { | 207 if (png_sig_cmp((png_bytep) buf, (png_size_t)0, PNG_BYTES_TO_CHECK)) { |
208 return false; | 208 return false; |
209 } | 209 } |
210 return true; | 210 return true; |
211 } | 211 } |
212 | 212 |
213 // Reads the header, and initializes the passed in fields, if not NULL (except | 213 // Reads the header, and initializes the passed in fields, if not nullptr (excep
t |
214 // stream, which is passed to the read function). | 214 // stream, which is passed to the read function). |
215 // Returns true on success, in which case the caller is responsible for calling | 215 // Returns true on success, in which case the caller is responsible for calling |
216 // png_destroy_read_struct. If it returns false, the passed in fields (except | 216 // png_destroy_read_struct. If it returns false, the passed in fields (except |
217 // stream) are unchanged. | 217 // stream) are unchanged. |
218 static bool read_header(SkStream* stream, png_structp* png_ptrp, | 218 static bool read_header(SkStream* stream, png_structp* png_ptrp, |
219 png_infop* info_ptrp, SkImageInfo* imageInfo, int* bitDe
pthPtr) { | 219 png_infop* info_ptrp, SkImageInfo* imageInfo, int* bitDe
pthPtr) { |
220 // The image is known to be a PNG. Decode enough to know the SkImageInfo. | 220 // The image is known to be a PNG. Decode enough to know the SkImageInfo. |
221 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, | 221 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, |
222 sk_error_fn, sk_warning_fn); | 222 sk_error_fn, sk_warning_fn); |
223 if (!png_ptr) { | 223 if (!png_ptr) { |
224 return false; | 224 return false; |
225 } | 225 } |
226 | 226 |
227 AutoCleanPng autoClean(png_ptr); | 227 AutoCleanPng autoClean(png_ptr); |
228 | 228 |
229 png_infop info_ptr = png_create_info_struct(png_ptr); | 229 png_infop info_ptr = png_create_info_struct(png_ptr); |
230 if (info_ptr == NULL) { | 230 if (info_ptr == nullptr) { |
231 return false; | 231 return false; |
232 } | 232 } |
233 | 233 |
234 autoClean.setInfoPtr(info_ptr); | 234 autoClean.setInfoPtr(info_ptr); |
235 | 235 |
236 // FIXME: Could we use the return value of setjmp to specify the type of | 236 // FIXME: Could we use the return value of setjmp to specify the type of |
237 // error? | 237 // error? |
238 if (setjmp(png_jmpbuf(png_ptr))) { | 238 if (setjmp(png_jmpbuf(png_ptr))) { |
239 return false; | 239 return false; |
240 } | 240 } |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
351 | 351 |
352 SkCodec* SkPngCodec::NewFromStream(SkStream* stream) { | 352 SkCodec* SkPngCodec::NewFromStream(SkStream* stream) { |
353 SkAutoTDelete<SkStream> streamDeleter(stream); | 353 SkAutoTDelete<SkStream> streamDeleter(stream); |
354 png_structp png_ptr; | 354 png_structp png_ptr; |
355 png_infop info_ptr; | 355 png_infop info_ptr; |
356 SkImageInfo imageInfo; | 356 SkImageInfo imageInfo; |
357 int bitDepth; | 357 int bitDepth; |
358 if (read_header(stream, &png_ptr, &info_ptr, &imageInfo, &bitDepth)) { | 358 if (read_header(stream, &png_ptr, &info_ptr, &imageInfo, &bitDepth)) { |
359 return new SkPngCodec(imageInfo, streamDeleter.detach(), png_ptr, info_p
tr, bitDepth); | 359 return new SkPngCodec(imageInfo, streamDeleter.detach(), png_ptr, info_p
tr, bitDepth); |
360 } | 360 } |
361 return NULL; | 361 return nullptr; |
362 } | 362 } |
363 | 363 |
364 #define INVALID_NUMBER_PASSES -1 | 364 #define INVALID_NUMBER_PASSES -1 |
365 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, | 365 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, |
366 png_structp png_ptr, png_infop info_ptr, int bitDepth) | 366 png_structp png_ptr, png_infop info_ptr, int bitDepth) |
367 : INHERITED(info, stream) | 367 : INHERITED(info, stream) |
368 , fPng_ptr(png_ptr) | 368 , fPng_ptr(png_ptr) |
369 , fInfo_ptr(info_ptr) | 369 , fInfo_ptr(info_ptr) |
370 , fSrcConfig(SkSwizzler::kUnknown) | 370 , fSrcConfig(SkSwizzler::kUnknown) |
371 , fNumberPasses(INVALID_NUMBER_PASSES) | 371 , fNumberPasses(INVALID_NUMBER_PASSES) |
372 , fReallyHasAlpha(false) | 372 , fReallyHasAlpha(false) |
373 , fBitDepth(bitDepth) | 373 , fBitDepth(bitDepth) |
374 {} | 374 {} |
375 | 375 |
376 SkPngCodec::~SkPngCodec() { | 376 SkPngCodec::~SkPngCodec() { |
377 this->destroyReadStruct(); | 377 this->destroyReadStruct(); |
378 } | 378 } |
379 | 379 |
380 void SkPngCodec::destroyReadStruct() { | 380 void SkPngCodec::destroyReadStruct() { |
381 if (fPng_ptr) { | 381 if (fPng_ptr) { |
382 // We will never have a NULL fInfo_ptr with a non-NULL fPng_ptr | 382 // We will never have a nullptr fInfo_ptr with a non-nullptr fPng_ptr |
383 SkASSERT(fInfo_ptr); | 383 SkASSERT(fInfo_ptr); |
384 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL); | 384 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL); |
385 fPng_ptr = NULL; | 385 fPng_ptr = nullptr; |
386 fInfo_ptr = NULL; | 386 fInfo_ptr = nullptr; |
387 } | 387 } |
388 } | 388 } |
389 | 389 |
390 /////////////////////////////////////////////////////////////////////////////// | 390 /////////////////////////////////////////////////////////////////////////////// |
391 // Getting the pixels | 391 // Getting the pixels |
392 /////////////////////////////////////////////////////////////////////////////// | 392 /////////////////////////////////////////////////////////////////////////////// |
393 | 393 |
394 SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo, | 394 SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo, |
395 const Options& options, | 395 const Options& options, |
396 SkPMColor ctable[], | 396 SkPMColor ctable[], |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
443 options.fZeroInitialized, this->getInfo())); | 443 options.fZeroInitialized, this->getInfo())); |
444 if (!fSwizzler) { | 444 if (!fSwizzler) { |
445 // FIXME: CreateSwizzler could fail for another reason. | 445 // FIXME: CreateSwizzler could fail for another reason. |
446 return kUnimplemented; | 446 return kUnimplemented; |
447 } | 447 } |
448 return kSuccess; | 448 return kSuccess; |
449 } | 449 } |
450 | 450 |
451 | 451 |
452 bool SkPngCodec::onRewind() { | 452 bool SkPngCodec::onRewind() { |
453 // This sets fPng_ptr and fInfo_ptr to NULL. If read_header | 453 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header |
454 // succeeds, they will be repopulated, and if it fails, they will | 454 // succeeds, they will be repopulated, and if it fails, they will |
455 // remain NULL. Any future accesses to fPng_ptr and fInfo_ptr will | 455 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will |
456 // come through this function which will rewind and again attempt | 456 // come through this function which will rewind and again attempt |
457 // to reinitialize them. | 457 // to reinitialize them. |
458 this->destroyReadStruct(); | 458 this->destroyReadStruct(); |
459 | 459 |
460 png_structp png_ptr; | 460 png_structp png_ptr; |
461 png_infop info_ptr; | 461 png_infop info_ptr; |
462 if (!read_header(this->stream(), &png_ptr, &info_ptr, NULL, NULL)) { | 462 if (!read_header(this->stream(), &png_ptr, &info_ptr, nullptr, nullptr)) { |
463 return false; | 463 return false; |
464 } | 464 } |
465 | 465 |
466 fPng_ptr = png_ptr; | 466 fPng_ptr = png_ptr; |
467 fInfo_ptr = info_ptr; | 467 fInfo_ptr = info_ptr; |
468 return true; | 468 return true; |
469 } | 469 } |
470 | 470 |
471 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void*
dst, | 471 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void*
dst, |
472 size_t dstRowBytes, const Options& optio
ns, | 472 size_t dstRowBytes, const Options& optio
ns, |
(...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
764 // rewindIfNeeded does not have this flexibility, we need to add another | 764 // rewindIfNeeded does not have this flexibility, we need to add another |
765 // layer. | 765 // layer. |
766 bool fCanSkipRewind; | 766 bool fCanSkipRewind; |
767 | 767 |
768 typedef SkScanlineDecoder INHERITED; | 768 typedef SkScanlineDecoder INHERITED; |
769 }; | 769 }; |
770 | 770 |
771 SkScanlineDecoder* SkPngCodec::NewSDFromStream(SkStream* stream) { | 771 SkScanlineDecoder* SkPngCodec::NewSDFromStream(SkStream* stream) { |
772 SkAutoTDelete<SkPngCodec> codec (static_cast<SkPngCodec*>(SkPngCodec::NewFro
mStream(stream))); | 772 SkAutoTDelete<SkPngCodec> codec (static_cast<SkPngCodec*>(SkPngCodec::NewFro
mStream(stream))); |
773 if (!codec) { | 773 if (!codec) { |
774 return NULL; | 774 return nullptr; |
775 } | 775 } |
776 | 776 |
777 codec->fNumberPasses = png_set_interlace_handling(codec->fPng_ptr); | 777 codec->fNumberPasses = png_set_interlace_handling(codec->fPng_ptr); |
778 SkASSERT(codec->fNumberPasses != INVALID_NUMBER_PASSES); | 778 SkASSERT(codec->fNumberPasses != INVALID_NUMBER_PASSES); |
779 | 779 |
780 const SkImageInfo& srcInfo = codec->getInfo(); | 780 const SkImageInfo& srcInfo = codec->getInfo(); |
781 if (codec->fNumberPasses > 1) { | 781 if (codec->fNumberPasses > 1) { |
782 // interlaced image | 782 // interlaced image |
783 return new SkPngInterlacedScanlineDecoder(srcInfo, codec.detach()); | 783 return new SkPngInterlacedScanlineDecoder(srcInfo, codec.detach()); |
784 } | 784 } |
785 | 785 |
786 return new SkPngScanlineDecoder(srcInfo, codec.detach()); | 786 return new SkPngScanlineDecoder(srcInfo, codec.detach()); |
787 } | 787 } |
788 | 788 |
OLD | NEW |