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 "SkScanlineDecoder.h" | |
14 #include "SkSize.h" | 15 #include "SkSize.h" |
15 #include "SkStream.h" | 16 #include "SkStream.h" |
16 #include "SkSwizzler.h" | 17 #include "SkSwizzler.h" |
17 | 18 |
18 /////////////////////////////////////////////////////////////////////////////// | 19 /////////////////////////////////////////////////////////////////////////////// |
19 // Helper macros | 20 // Helper macros |
20 /////////////////////////////////////////////////////////////////////////////// | 21 /////////////////////////////////////////////////////////////////////////////// |
21 | 22 |
22 #ifndef png_jmpbuf | 23 #ifndef png_jmpbuf |
23 # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) | 24 # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
107 png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL); | 108 png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL); |
108 return num_trans > 0; | 109 return num_trans > 0; |
109 } | 110 } |
110 | 111 |
111 // Method for coverting to either an SkPMColor or a similarly packed | 112 // Method for coverting to either an SkPMColor or a similarly packed |
112 // unpremultiplied color. | 113 // unpremultiplied color. |
113 typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b); | 114 typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b); |
114 | 115 |
115 // Note: SkColorTable claims to store SkPMColors, which is not necessarily | 116 // Note: SkColorTable claims to store SkPMColors, which is not necessarily |
116 // the case here. | 117 // the case here. |
117 SkColorTable* decode_palette(png_structp png_ptr, png_infop info_ptr, | 118 bool SkPngCodec::decodePalette(bool premultiply) { |
118 bool premultiply, SkAlphaType* outAlphaType) { | |
119 SkASSERT(outAlphaType != NULL); | |
120 int numPalette; | 119 int numPalette; |
121 png_colorp palette; | 120 png_colorp palette; |
122 png_bytep trans; | 121 png_bytep trans; |
123 | 122 |
124 if (!png_get_PLTE(png_ptr, info_ptr, &palette, &numPalette)) { | 123 if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numPalette)) { |
125 return NULL; | 124 return false; |
126 } | 125 } |
127 | 126 |
128 /* BUGGY IMAGE WORKAROUND | 127 /* BUGGY IMAGE WORKAROUND |
129 | 128 |
130 We hit some images (e.g. fruit_.png) who contain bytes that are == color table_count | 129 We hit some images (e.g. fruit_.png) who contain bytes that are == color table_count |
131 which is a problem since we use the byte as an index. To work around thi s we grow | 130 which is a problem since we use the byte as an index. To work around thi s we grow |
132 the colortable by 1 (if its < 256) and duplicate the last color into tha t slot. | 131 the colortable by 1 (if its < 256) and duplicate the last color into tha t slot. |
133 */ | 132 */ |
134 const int colorCount = numPalette + (numPalette < 256); | 133 const int colorCount = numPalette + (numPalette < 256); |
135 // Note: These are not necessarily SkPMColors. | 134 // Note: These are not necessarily SkPMColors. |
136 SkPMColor colorStorage[256]; // worst-case storage | 135 SkPMColor colorStorage[256]; // worst-case storage |
137 SkPMColor* colorPtr = colorStorage; | 136 SkPMColor* colorPtr = colorStorage; |
138 | 137 |
139 int numTrans; | 138 int numTrans; |
140 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { | 139 if (png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS)) { |
141 png_get_tRNS(png_ptr, info_ptr, &trans, &numTrans, NULL); | 140 png_get_tRNS(fPng_ptr, fInfo_ptr, &trans, &numTrans, NULL); |
142 } else { | 141 } else { |
143 numTrans = 0; | 142 numTrans = 0; |
144 } | 143 } |
145 | 144 |
146 // check for bad images that might make us crash | 145 // check for bad images that might make us crash |
147 if (numTrans > numPalette) { | 146 if (numTrans > numPalette) { |
148 numTrans = numPalette; | 147 numTrans = numPalette; |
149 } | 148 } |
150 | 149 |
151 int index = 0; | 150 int index = 0; |
152 int transLessThanFF = 0; | 151 int transLessThanFF = 0; |
153 | 152 |
154 // Choose which function to use to create the color table. If the final dest ination's | 153 // Choose which function to use to create the color table. If the final dest ination's |
155 // colortype is unpremultiplied, the color table will store unpremultiplied colors. | 154 // colortype is unpremultiplied, the color table will store unpremultiplied colors. |
156 PackColorProc proc; | 155 PackColorProc proc; |
157 if (premultiply) { | 156 if (premultiply) { |
158 proc = &SkPreMultiplyARGB; | 157 proc = &SkPreMultiplyARGB; |
159 } else { | 158 } else { |
160 proc = &SkPackARGB32NoCheck; | 159 proc = &SkPackARGB32NoCheck; |
161 } | 160 } |
162 for (; index < numTrans; index++) { | 161 for (; index < numTrans; index++) { |
163 transLessThanFF |= (int)*trans - 0xFF; | 162 transLessThanFF |= (int)*trans - 0xFF; |
164 *colorPtr++ = proc(*trans++, palette->red, palette->green, palette->blue ); | 163 *colorPtr++ = proc(*trans++, palette->red, palette->green, palette->blue ); |
165 palette++; | 164 palette++; |
166 } | 165 } |
167 | 166 |
168 if (transLessThanFF < 0) { | 167 fReallyHasAlpha = transLessThanFF < 0; |
169 *outAlphaType = premultiply ? kPremul_SkAlphaType : kUnpremul_SkAlphaTyp e; | |
170 } else { | |
171 *outAlphaType = kOpaque_SkAlphaType; | |
172 } | |
173 | 168 |
174 for (; index < numPalette; index++) { | 169 for (; index < numPalette; index++) { |
175 *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette-> blue); | 170 *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette-> blue); |
176 palette++; | 171 palette++; |
177 } | 172 } |
178 | 173 |
179 // see BUGGY IMAGE WORKAROUND comment above | 174 // see BUGGY IMAGE WORKAROUND comment above |
180 if (numPalette < 256) { | 175 if (numPalette < 256) { |
181 *colorPtr = colorPtr[-1]; | 176 *colorPtr = colorPtr[-1]; |
182 } | 177 } |
183 | 178 |
184 return SkNEW_ARGS(SkColorTable, (colorStorage, colorCount)); | 179 fColorTable.reset(SkNEW_ARGS(SkColorTable, (colorStorage, colorCount))); |
180 return true; | |
185 } | 181 } |
186 | 182 |
187 /////////////////////////////////////////////////////////////////////////////// | 183 /////////////////////////////////////////////////////////////////////////////// |
188 // Creation | 184 // Creation |
189 /////////////////////////////////////////////////////////////////////////////// | 185 /////////////////////////////////////////////////////////////////////////////// |
190 | 186 |
191 #define PNG_BYTES_TO_CHECK 4 | 187 #define PNG_BYTES_TO_CHECK 4 |
192 | 188 |
193 bool SkPngCodec::IsPng(SkStream* stream) { | 189 bool SkPngCodec::IsPng(SkStream* stream) { |
194 char buf[PNG_BYTES_TO_CHECK]; | 190 char buf[PNG_BYTES_TO_CHECK]; |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
326 | 322 |
327 // FIXME: Also need to check for sRGB (skbug.com/3471). | 323 // FIXME: Also need to check for sRGB (skbug.com/3471). |
328 | 324 |
329 SkImageInfo info = SkImageInfo::Make(origWidth, origHeight, skColorType, | 325 SkImageInfo info = SkImageInfo::Make(origWidth, origHeight, skColorType, |
330 skAlphaType); | 326 skAlphaType); |
331 SkCodec* codec = SkNEW_ARGS(SkPngCodec, (info, stream, png_ptr, info_ptr)); | 327 SkCodec* codec = SkNEW_ARGS(SkPngCodec, (info, stream, png_ptr, info_ptr)); |
332 autoClean.detach(); | 328 autoClean.detach(); |
333 return codec; | 329 return codec; |
334 } | 330 } |
335 | 331 |
332 #define INVALID_NUMBER_PASSES -1 | |
336 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, | 333 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, |
337 png_structp png_ptr, png_infop info_ptr) | 334 png_structp png_ptr, png_infop info_ptr) |
338 : INHERITED(info, stream) | 335 : INHERITED(info, stream) |
339 , fPng_ptr(png_ptr) | 336 , fPng_ptr(png_ptr) |
340 , fInfo_ptr(info_ptr) {} | 337 , fInfo_ptr(info_ptr) |
338 , fSrcConfig(SkSwizzler::kUnknown) | |
339 , fNumberPasses(INVALID_NUMBER_PASSES) | |
340 , fReallyHasAlpha(false) | |
341 {} | |
341 | 342 |
342 SkPngCodec::~SkPngCodec() { | 343 SkPngCodec::~SkPngCodec() { |
343 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL); | 344 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL); |
344 } | 345 } |
345 | 346 |
346 /////////////////////////////////////////////////////////////////////////////// | 347 /////////////////////////////////////////////////////////////////////////////// |
347 // Getting the pixels | 348 // Getting the pixels |
348 /////////////////////////////////////////////////////////////////////////////// | 349 /////////////////////////////////////////////////////////////////////////////// |
349 | 350 |
350 static bool conversion_possible(const SkImageInfo& dst, const SkImageInfo& src) { | 351 static bool conversion_possible(const SkImageInfo& dst, const SkImageInfo& src) { |
351 // TODO: Support other conversions | 352 // TODO: Support other conversions |
352 if (dst.colorType() != src.colorType()) { | 353 if (dst.colorType() != src.colorType()) { |
353 return false; | 354 return false; |
354 } | 355 } |
355 if (dst.profileType() != src.profileType()) { | 356 if (dst.profileType() != src.profileType()) { |
356 return false; | 357 return false; |
357 } | 358 } |
358 if (dst.alphaType() == src.alphaType()) { | 359 if (dst.alphaType() == src.alphaType()) { |
359 return true; | 360 return true; |
360 } | 361 } |
361 return kPremul_SkAlphaType == dst.alphaType() && | 362 return kPremul_SkAlphaType == dst.alphaType() && |
362 kUnpremul_SkAlphaType == src.alphaType(); | 363 kUnpremul_SkAlphaType == src.alphaType(); |
363 } | 364 } |
364 | 365 |
365 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst, | 366 SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo, |
366 size_t rowBytes, const Options& options, | 367 void* dst, size_t rowBytes, |
367 SkPMColor ctable[], int* ctableCount) { | 368 const Options& options) { |
368 if (!this->rewindIfNeeded()) { | |
369 return kCouldNotRewind; | |
370 } | |
371 if (requestedInfo.dimensions() != this->getInfo().dimensions()) { | |
372 return kInvalidScale; | |
373 } | |
374 if (!conversion_possible(requestedInfo, this->getInfo())) { | |
375 return kInvalidConversion; | |
376 } | |
377 | |
378 SkBitmap decodedBitmap; | |
379 // If installPixels would have failed, getPixels should have failed before | |
380 // calling onGetPixels. | |
381 SkAssertResult(decodedBitmap.installPixels(requestedInfo, dst, rowBytes)); | |
382 | |
383 // Initialize all non-trivial objects before setjmp. | |
384 SkAutoTUnref<SkColorTable> colorTable; | |
385 SkAutoTDelete<SkSwizzler> swizzler; | |
386 SkAutoMalloc storage; // Scratch memory for pre-swizzled r ows. | |
387 | |
388 // FIXME: Could we use the return value of setjmp to specify the type of | 369 // FIXME: Could we use the return value of setjmp to specify the type of |
389 // error? | 370 // error? |
390 if (setjmp(png_jmpbuf(fPng_ptr))) { | 371 if (setjmp(png_jmpbuf(fPng_ptr))) { |
391 SkDebugf("setjmp long jump!\n"); | 372 SkDebugf("setjmp long jump!\n"); |
392 return kInvalidInput; | 373 return kInvalidInput; |
393 } | 374 } |
394 | 375 |
395 // FIXME: We already retrieved this information. Store it in SkPngCodec? | 376 // FIXME: We already retrieved this information. Store it in SkPngCodec? |
396 png_uint_32 origWidth, origHeight; | 377 png_uint_32 origWidth, origHeight; |
397 int bitDepth, pngColorType, interlaceType; | 378 int bitDepth, pngColorType, interlaceType; |
398 png_get_IHDR(fPng_ptr, fInfo_ptr, &origWidth, &origHeight, &bitDepth, | 379 png_get_IHDR(fPng_ptr, fInfo_ptr, &origWidth, &origHeight, &bitDepth, |
399 &pngColorType, &interlaceType, int_p_NULL, int_p_NULL); | 380 &pngColorType, &interlaceType, int_p_NULL, int_p_NULL); |
400 | 381 |
401 const int numberPasses = (interlaceType != PNG_INTERLACE_NONE) ? | 382 fNumberPasses = (interlaceType != PNG_INTERLACE_NONE) ? |
402 png_set_interlace_handling(fPng_ptr) : 1; | 383 png_set_interlace_handling(fPng_ptr) : 1; |
403 | 384 |
404 SkSwizzler::SrcConfig sc; | 385 // Set to the default before calling decodePalette, which may change it. |
405 bool reallyHasAlpha = false; | 386 fReallyHasAlpha = false; |
406 if (PNG_COLOR_TYPE_PALETTE == pngColorType) { | 387 if (PNG_COLOR_TYPE_PALETTE == pngColorType) { |
407 sc = SkSwizzler::kIndex; | 388 fSrcConfig = SkSwizzler::kIndex; |
408 SkAlphaType at = requestedInfo.alphaType(); | 389 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaType( ))) { |
409 colorTable.reset(decode_palette(fPng_ptr, fInfo_ptr, | |
410 kPremul_SkAlphaType == at, | |
411 &at)); | |
412 if (!colorTable) { | |
413 return kInvalidInput; | 390 return kInvalidInput; |
414 } | 391 } |
415 | |
416 reallyHasAlpha = (at != kOpaque_SkAlphaType); | |
417 | |
418 if (at != requestedInfo.alphaType()) { | |
419 // It turns out the image is opaque. | |
420 SkASSERT(kOpaque_SkAlphaType == at); | |
421 } | |
422 } else if (kAlpha_8_SkColorType == requestedInfo.colorType()) { | 392 } else if (kAlpha_8_SkColorType == requestedInfo.colorType()) { |
423 // Note: we check the destination, since otherwise we would have | 393 // Note: we check the destination, since otherwise we would have |
424 // told png to upscale. | 394 // told png to upscale. |
425 SkASSERT(PNG_COLOR_TYPE_GRAY == pngColorType); | 395 SkASSERT(PNG_COLOR_TYPE_GRAY == pngColorType); |
426 sc = SkSwizzler::kGray; | 396 fSrcConfig = SkSwizzler::kGray; |
427 } else if (this->getInfo().alphaType() == kOpaque_SkAlphaType) { | 397 } else if (this->getInfo().alphaType() == kOpaque_SkAlphaType) { |
428 sc = SkSwizzler::kRGBX; | 398 fSrcConfig = SkSwizzler::kRGBX; |
429 } else { | 399 } else { |
430 sc = SkSwizzler::kRGBA; | 400 fSrcConfig = SkSwizzler::kRGBA; |
431 } | 401 } |
432 const SkPMColor* colors = colorTable ? colorTable->readColors() : NULL; | 402 const SkPMColor* colors = fColorTable ? fColorTable->readColors() : NULL; |
433 swizzler.reset(SkSwizzler::CreateSwizzler(sc, colors, requestedInfo, | 403 fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo , |
434 dst, rowBytes, | 404 dst, rowBytes, options.fZeroInitialized)); |
435 options.fZeroInitialized)); | 405 if (!fSwizzler) { |
436 if (!swizzler) { | |
437 // FIXME: CreateSwizzler could fail for another reason. | 406 // FIXME: CreateSwizzler could fail for another reason. |
438 return kUnimplemented; | 407 return kUnimplemented; |
439 } | 408 } |
440 | 409 |
441 // FIXME: Here is where we should likely insert some of the modifications | 410 // FIXME: Here is where we should likely insert some of the modifications |
442 // made in the factory. | 411 // made in the factory. |
443 png_read_update_info(fPng_ptr, fInfo_ptr); | 412 png_read_update_info(fPng_ptr, fInfo_ptr); |
444 | 413 |
445 if (numberPasses > 1) { | 414 return kSuccess; |
415 } | |
416 | |
417 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst, | |
418 size_t rowBytes, const Options& options, | |
419 SkPMColor ctable[], int* ctableCount) { | |
420 if (!this->rewindIfNeeded()) { | |
421 return kCouldNotRewind; | |
422 } | |
423 if (requestedInfo.dimensions() != this->getInfo().dimensions()) { | |
424 return kInvalidScale; | |
425 } | |
426 if (!conversion_possible(requestedInfo, this->getInfo())) { | |
427 return kInvalidConversion; | |
428 } | |
429 | |
430 const Result result = this->initializeSwizzler(requestedInfo, dst, rowBytes, | |
431 options); | |
432 if (result != kSuccess) { | |
433 return result; | |
434 } | |
435 | |
436 // FIXME: Could we use the return value of setjmp to specify the type of | |
437 // error? | |
438 if (setjmp(png_jmpbuf(fPng_ptr))) { | |
439 SkDebugf("setjmp long jump!\n"); | |
440 return kInvalidInput; | |
441 } | |
442 | |
443 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); | |
444 SkAutoMalloc storage; | |
445 if (fNumberPasses > 1) { | |
446 const int width = requestedInfo.width(); | 446 const int width = requestedInfo.width(); |
447 const int height = requestedInfo.height(); | 447 const int height = requestedInfo.height(); |
448 const int bpp = SkSwizzler::BytesPerPixel(sc); | 448 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig); |
449 const size_t rowBytes = width * bpp; | 449 const size_t rowBytes = width * bpp; |
450 | 450 |
451 storage.reset(width * height * bpp); | 451 storage.reset(width * height * bpp); |
452 uint8_t* const base = static_cast<uint8_t*>(storage.get()); | 452 uint8_t* const base = static_cast<uint8_t*>(storage.get()); |
453 | 453 |
454 for (int i = 0; i < numberPasses; i++) { | 454 for (int i = 0; i < fNumberPasses; i++) { |
455 uint8_t* row = base; | 455 uint8_t* row = base; |
456 for (int y = 0; y < height; y++) { | 456 for (int y = 0; y < height; y++) { |
457 uint8_t* bmRow = row; | 457 uint8_t* bmRow = row; |
458 png_read_rows(fPng_ptr, &bmRow, png_bytepp_NULL, 1); | 458 png_read_rows(fPng_ptr, &bmRow, png_bytepp_NULL, 1); |
459 row += rowBytes; | 459 row += rowBytes; |
460 } | 460 } |
461 } | 461 } |
462 | 462 |
463 // Now swizzle it. | 463 // Now swizzle it. |
464 uint8_t* row = base; | 464 uint8_t* row = base; |
465 for (int y = 0; y < height; y++) { | 465 for (int y = 0; y < height; y++) { |
466 reallyHasAlpha |= !SkSwizzler::IsOpaque(swizzler->next(row)); | 466 fReallyHasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->next(row)); |
467 row += rowBytes; | 467 row += rowBytes; |
468 } | 468 } |
469 } else { | 469 } else { |
470 storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(sc)); | 470 storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConf ig)); |
471 uint8_t* srcRow = static_cast<uint8_t*>(storage.get()); | 471 uint8_t* srcRow = static_cast<uint8_t*>(storage.get()); |
472 for (int y = 0; y < requestedInfo.height(); y++) { | 472 for (int y = 0; y < requestedInfo.height(); y++) { |
473 png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1); | 473 png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1); |
474 reallyHasAlpha |= !SkSwizzler::IsOpaque(swizzler->next(srcRow)); | 474 fReallyHasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->next(srcRow)); |
475 } | 475 } |
476 } | 476 } |
477 | 477 |
478 // FIXME: do we need substituteTranspColor? Note that we cannot do it for | |
479 // scanline decoding, but we could do it here. Alternatively, we could do | |
480 // it as we go, instead of in post-processing like SkPNGImageDecoder. | |
481 | |
482 this->finish(); | |
483 return kSuccess; | |
484 } | |
485 | |
486 void SkPngCodec::finish() { | |
487 if (setjmp(png_jmpbuf(fPng_ptr))) { | |
488 // We've already read all the scanlines. This is a success. | |
489 return; | |
490 } | |
478 /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ | 491 /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ |
479 png_read_end(fPng_ptr, fInfo_ptr); | 492 png_read_end(fPng_ptr, fInfo_ptr); |
493 } | |
480 | 494 |
481 // FIXME: do we need substituteTranspColor? | 495 class SkPngScanlineDecoder : public SkScanlineDecoder { |
496 public: | |
497 SkPngScanlineDecoder(const SkImageInfo& dstInfo, SkPngCodec* codec) | |
498 : INHERITED(dstInfo) | |
499 , fCodec(codec) | |
500 , fHasAlpha(false) | |
501 { | |
502 fStorage.reset(dstInfo.width() * SkSwizzler::BytesPerPixel(fCodec->fSrcC onfig)); | |
503 fSrcRow = static_cast<uint8_t*>(fStorage.get()); | |
504 } | |
482 | 505 |
483 if (reallyHasAlpha && requestedInfo.alphaType() != kOpaque_SkAlphaType) { | 506 SkImageGenerator::Result onGetScanlines(void* dst, int count, size_t rowByte s) SK_OVERRIDE { |
484 // FIXME: We want to alert the caller. Is this the right way? | 507 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { |
485 SkImageInfo* modInfo = const_cast<SkImageInfo*>(&requestedInfo); | 508 SkDebugf("setjmp long jump!\n"); |
486 *modInfo = requestedInfo.makeAlphaType(kOpaque_SkAlphaType); | 509 return SkImageGenerator::kInvalidInput; |
510 } | |
511 | |
512 // Using this local variable will prevent the clobber error. | |
scroggo
2015/03/25 15:55:45
I think?
| |
513 void* localDst = dst; | |
514 for (int i = 0; i < count; i++) { | |
515 png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1); | |
516 fCodec->fSwizzler->setDstRow(localDst); | |
517 fHasAlpha |= !SkSwizzler::IsOpaque(fCodec->fSwizzler->next(fSrcRow)) ; | |
518 localDst = SkTAddOffset<void>(localDst, rowBytes); | |
519 } | |
520 return SkImageGenerator::kSuccess; | |
487 } | 521 } |
488 return kSuccess; | 522 |
523 SkImageGenerator::Result onSkipScanlines(int count) SK_OVERRIDE { | |
524 // FIXME: Could we use the return value of setjmp to specify the type of | |
525 // error? | |
526 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { | |
527 SkDebugf("setjmp long jump!\n"); | |
528 return SkImageGenerator::kInvalidInput; | |
529 } | |
530 | |
531 png_read_rows(fCodec->fPng_ptr, png_bytepp_NULL, png_bytepp_NULL, count) ; | |
532 return SkImageGenerator::kSuccess; | |
533 } | |
534 | |
535 void onFinish() SK_OVERRIDE { | |
536 fCodec->finish(); | |
537 } | |
538 | |
539 bool onReallyHasAlpha() const SK_OVERRIDE { return fHasAlpha; } | |
540 | |
541 private: | |
542 SkPngCodec* fCodec; // Unowned. | |
543 bool fHasAlpha; | |
544 SkAutoMalloc fStorage; | |
545 uint8_t* fSrcRow; | |
546 | |
547 typedef SkScanlineDecoder INHERITED; | |
548 }; | |
549 | |
550 SkScanlineDecoder* SkPngCodec::onGetScanlineDecoder(const SkImageInfo& dstInfo) { | |
551 // Check to see if scaling was requested. | |
552 if (dstInfo.dimensions() != this->getInfo().dimensions()) { | |
553 return NULL; | |
554 } | |
555 | |
556 if (!conversion_possible(dstInfo, this->getInfo())) { | |
557 SkDebugf("no conversion possible\n"); | |
558 return NULL; | |
559 } | |
560 | |
561 // Note: We set dst to NULL since we do not know it yet. rowBytes is not nee ded, | |
562 // since we'll be manually updating the dstRow, but the SkSwizzler requires it to | |
563 // be at least dstInfo.minRowBytes. | |
564 Options opts; | |
565 // FIXME: Pass this in to getScanlineDecoder? | |
566 opts.fZeroInitialized = kNo_ZeroInitialized; | |
567 if (this->initializeSwizzler(dstInfo, NULL, dstInfo.minRowBytes(), opts) != kSuccess) { | |
568 SkDebugf("failed to initialize the swizzler.\n"); | |
569 return NULL; | |
570 } | |
571 | |
572 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); | |
573 if (fNumberPasses > 1) { | |
574 // We cannot efficiently do scanline decoding. | |
575 return NULL; | |
576 } | |
577 | |
578 return SkNEW_ARGS(SkPngScanlineDecoder, (dstInfo, this)); | |
489 } | 579 } |
580 | |
OLD | NEW |