| 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" |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 59 SkStream* stream = static_cast<SkStream*>(png_get_io_ptr(png_ptr)); | 59 SkStream* stream = static_cast<SkStream*>(png_get_io_ptr(png_ptr)); |
| 60 const size_t bytes = stream->read(data, length); | 60 const size_t bytes = stream->read(data, length); |
| 61 if (bytes != length) { | 61 if (bytes != length) { |
| 62 // FIXME: We want to report the fact that the stream was truncated. | 62 // FIXME: We want to report the fact that the stream was truncated. |
| 63 // One way to do that might be to pass a enum to longjmp so setjmp can | 63 // One way to do that might be to pass a enum to longjmp so setjmp can |
| 64 // specify the failure. | 64 // specify the failure. |
| 65 png_error(png_ptr, "Read Error!"); | 65 png_error(png_ptr, "Read Error!"); |
| 66 } | 66 } |
| 67 } | 67 } |
| 68 | 68 |
| 69 #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED |
| 70 static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) { |
| 71 SkChunkReader* chunkReader = (SkChunkReader*)png_get_user_chunk_ptr(png_ptr)
; |
| 72 // peek() returning true means continue decoding |
| 73 return chunkReader->readChunk((const char*)chunk->name, chunk->data, chunk->
size) ? 1 : -1; |
| 74 } |
| 75 #endif |
| 76 |
| 69 /////////////////////////////////////////////////////////////////////////////// | 77 /////////////////////////////////////////////////////////////////////////////// |
| 70 // Helpers | 78 // Helpers |
| 71 /////////////////////////////////////////////////////////////////////////////// | 79 /////////////////////////////////////////////////////////////////////////////// |
| 72 | 80 |
| 73 class AutoCleanPng : public SkNoncopyable { | 81 class AutoCleanPng : public SkNoncopyable { |
| 74 public: | 82 public: |
| 75 AutoCleanPng(png_structp png_ptr) | 83 AutoCleanPng(png_structp png_ptr) |
| 76 : fPng_ptr(png_ptr) | 84 : fPng_ptr(png_ptr) |
| 77 , fInfo_ptr(NULL) {} | 85 , fInfo_ptr(NULL) {} |
| 78 | 86 |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 194 char buf[PNG_BYTES_TO_CHECK]; | 202 char buf[PNG_BYTES_TO_CHECK]; |
| 195 if (stream->read(buf, PNG_BYTES_TO_CHECK) != PNG_BYTES_TO_CHECK) { | 203 if (stream->read(buf, PNG_BYTES_TO_CHECK) != PNG_BYTES_TO_CHECK) { |
| 196 return false; | 204 return false; |
| 197 } | 205 } |
| 198 if (png_sig_cmp((png_bytep) buf, (png_size_t)0, PNG_BYTES_TO_CHECK)) { | 206 if (png_sig_cmp((png_bytep) buf, (png_size_t)0, PNG_BYTES_TO_CHECK)) { |
| 199 return false; | 207 return false; |
| 200 } | 208 } |
| 201 return true; | 209 return true; |
| 202 } | 210 } |
| 203 | 211 |
| 204 SkCodec* SkPngCodec::NewFromStream(SkStream* stream) { | 212 SkCodec* SkPngCodec::NewFromStream(SkStream* stream, SkChunkReader* chunkReader)
{ |
| 205 // The image is known to be a PNG. Decode enough to know the SkImageInfo. | 213 // The image is known to be a PNG. Decode enough to know the SkImageInfo. |
| 206 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, | 214 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, |
| 207 sk_error_fn, sk_warning_fn); | 215 sk_error_fn, sk_warning_fn); |
| 208 if (!png_ptr) { | 216 if (!png_ptr) { |
| 209 return NULL; | 217 return NULL; |
| 210 } | 218 } |
| 211 | 219 |
| 212 AutoCleanPng autoClean(png_ptr); | 220 AutoCleanPng autoClean(png_ptr); |
| 213 | 221 |
| 214 png_infop info_ptr = png_create_info_struct(png_ptr); | 222 png_infop info_ptr = png_create_info_struct(png_ptr); |
| 215 if (info_ptr == NULL) { | 223 if (info_ptr == NULL) { |
| 216 return NULL; | 224 return NULL; |
| 217 } | 225 } |
| 218 | 226 |
| 219 autoClean.setInfoPtr(info_ptr); | 227 autoClean.setInfoPtr(info_ptr); |
| 220 | 228 |
| 221 // FIXME: Could we use the return value of setjmp to specify the type of | 229 // FIXME: Could we use the return value of setjmp to specify the type of |
| 222 // error? | 230 // error? |
| 223 if (setjmp(png_jmpbuf(png_ptr))) { | 231 if (setjmp(png_jmpbuf(png_ptr))) { |
| 224 return NULL; | 232 return NULL; |
| 225 } | 233 } |
| 226 | 234 |
| 227 png_set_read_fn(png_ptr, static_cast<void*>(stream), sk_read_fn); | 235 png_set_read_fn(png_ptr, static_cast<void*>(stream), sk_read_fn); |
| 228 | 236 |
| 229 // FIXME: This is where the old code hooks up the Peeker. Does it need to | 237 #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED |
| 230 // be set this early? (i.e. where are the user chunks? early in the stream, | 238 // hookup our chunkReader so we can see any user-chunks the caller may be in
terested in |
| 231 // potentially?) | 239 if (chunkReader) { |
| 232 // If it does, we need to figure out a way to set it here. | 240 png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*
)"", 0); |
| 241 png_set_read_user_chunk_fn(png_ptr, (png_voidp) chunkReader, sk_read_use
r_chunk); |
| 242 } |
| 243 #endif |
| 233 | 244 |
| 234 // The call to png_read_info() gives us all of the information from the | 245 // The call to png_read_info() gives us all of the information from the |
| 235 // PNG file before the first IDAT (image data chunk). | 246 // PNG file before the first IDAT (image data chunk). |
| 236 png_read_info(png_ptr, info_ptr); | 247 png_read_info(png_ptr, info_ptr); |
| 237 png_uint_32 origWidth, origHeight; | 248 png_uint_32 origWidth, origHeight; |
| 238 int bitDepth, colorType; | 249 int bitDepth, colorType; |
| 239 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth, | 250 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth, |
| 240 &colorType, int_p_NULL, int_p_NULL, int_p_NULL); | 251 &colorType, int_p_NULL, int_p_NULL, int_p_NULL); |
| 241 | 252 |
| 242 // sanity check for size | 253 // sanity check for size |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 320 // FIXME: It seems like we could just use RGB as the SrcConfig here. | 331 // FIXME: It seems like we could just use RGB as the SrcConfig here. |
| 321 if (colorType == PNG_COLOR_TYPE_RGB || convertGrayToRGB) { | 332 if (colorType == PNG_COLOR_TYPE_RGB || convertGrayToRGB) { |
| 322 png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); | 333 png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); |
| 323 } | 334 } |
| 324 } | 335 } |
| 325 | 336 |
| 326 // FIXME: Also need to check for sRGB (skbug.com/3471). | 337 // FIXME: Also need to check for sRGB (skbug.com/3471). |
| 327 | 338 |
| 328 SkImageInfo info = SkImageInfo::Make(origWidth, origHeight, skColorType, | 339 SkImageInfo info = SkImageInfo::Make(origWidth, origHeight, skColorType, |
| 329 skAlphaType); | 340 skAlphaType); |
| 330 SkCodec* codec = SkNEW_ARGS(SkPngCodec, (info, stream, png_ptr, info_ptr)); | 341 SkCodec* codec = SkNEW_ARGS(SkPngCodec, (info, stream, chunkReader, png_ptr,
info_ptr)); |
| 331 autoClean.detach(); | 342 autoClean.detach(); |
| 332 return codec; | 343 return codec; |
| 333 } | 344 } |
| 334 | 345 |
| 335 #define INVALID_NUMBER_PASSES -1 | 346 #define INVALID_NUMBER_PASSES -1 |
| 336 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, | 347 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, SkChunkReader*
chunkReader, |
| 337 png_structp png_ptr, png_infop info_ptr) | 348 png_structp png_ptr, png_infop info_ptr) |
| 338 : INHERITED(info, stream) | 349 : INHERITED(info, stream) |
| 350 , fChunkReader(SkSafeRef(chunkReader)) |
| 339 , fPng_ptr(png_ptr) | 351 , fPng_ptr(png_ptr) |
| 340 , fInfo_ptr(info_ptr) | 352 , fInfo_ptr(info_ptr) |
| 341 , fSrcConfig(SkSwizzler::kUnknown) | 353 , fSrcConfig(SkSwizzler::kUnknown) |
| 342 , fNumberPasses(INVALID_NUMBER_PASSES) | 354 , fNumberPasses(INVALID_NUMBER_PASSES) |
| 343 , fReallyHasAlpha(false) | 355 , fReallyHasAlpha(false) |
| 344 {} | 356 {} |
| 345 | 357 |
| 346 SkPngCodec::~SkPngCodec() { | 358 SkPngCodec::~SkPngCodec() { |
| 347 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL); | 359 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL); |
| 348 } | 360 } |
| (...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 572 | 584 |
| 573 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); | 585 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); |
| 574 if (fNumberPasses > 1) { | 586 if (fNumberPasses > 1) { |
| 575 // We cannot efficiently do scanline decoding. | 587 // We cannot efficiently do scanline decoding. |
| 576 return NULL; | 588 return NULL; |
| 577 } | 589 } |
| 578 | 590 |
| 579 return SkNEW_ARGS(SkPngScanlineDecoder, (dstInfo, this)); | 591 return SkNEW_ARGS(SkPngScanlineDecoder, (dstInfo, this)); |
| 580 } | 592 } |
| 581 | 593 |
| OLD | NEW |