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 for (int i = 0; i < count; i++) { |
| 513 png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1); |
| 514 fCodec->fSwizzler->setDstRow(dst); |
| 515 fHasAlpha |= !SkSwizzler::IsOpaque(fCodec->fSwizzler->next(fSrcRow))
; |
| 516 dst = SkTAddOffset<void>(dst, rowBytes); |
| 517 } |
| 518 return SkImageGenerator::kSuccess; |
487 } | 519 } |
488 return kSuccess; | 520 |
| 521 SkImageGenerator::Result onSkipScanlines(int count) SK_OVERRIDE { |
| 522 // FIXME: Could we use the return value of setjmp to specify the type of |
| 523 // error? |
| 524 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { |
| 525 SkDebugf("setjmp long jump!\n"); |
| 526 return SkImageGenerator::kInvalidInput; |
| 527 } |
| 528 |
| 529 png_read_rows(fCodec->fPng_ptr, png_bytepp_NULL, png_bytepp_NULL, count)
; |
| 530 return SkImageGenerator::kSuccess; |
| 531 } |
| 532 |
| 533 void onFinish() SK_OVERRIDE { |
| 534 fCodec->finish(); |
| 535 } |
| 536 |
| 537 bool onReallyHasAlpha() const SK_OVERRIDE { return fHasAlpha; } |
| 538 |
| 539 private: |
| 540 SkPngCodec* fCodec; // Unowned. |
| 541 bool fHasAlpha; |
| 542 SkAutoMalloc fStorage; |
| 543 uint8_t* fSrcRow; |
| 544 |
| 545 typedef SkScanlineDecoder INHERITED; |
| 546 }; |
| 547 |
| 548 SkScanlineDecoder* SkPngCodec::onGetScanlineDecoder(const SkImageInfo& dstInfo)
{ |
| 549 // Check to see if scaling was requested. |
| 550 if (dstInfo.dimensions() != this->getInfo().dimensions()) { |
| 551 return NULL; |
| 552 } |
| 553 |
| 554 if (!conversion_possible(dstInfo, this->getInfo())) { |
| 555 SkDebugf("no conversion possible\n"); |
| 556 return NULL; |
| 557 } |
| 558 |
| 559 // Note: We set dst to NULL since we do not know it yet. rowBytes is not nee
ded, |
| 560 // since we'll be manually updating the dstRow, but the SkSwizzler requires
it to |
| 561 // be at least dstInfo.minRowBytes. |
| 562 Options opts; |
| 563 // FIXME: Pass this in to getScanlineDecoder? |
| 564 opts.fZeroInitialized = kNo_ZeroInitialized; |
| 565 if (this->initializeSwizzler(dstInfo, NULL, dstInfo.minRowBytes(), opts) !=
kSuccess) { |
| 566 SkDebugf("failed to initialize the swizzler.\n"); |
| 567 return NULL; |
| 568 } |
| 569 |
| 570 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); |
| 571 if (fNumberPasses > 1) { |
| 572 // We cannot efficiently do scanline decoding. |
| 573 return NULL; |
| 574 } |
| 575 |
| 576 return SkNEW_ARGS(SkPngScanlineDecoder, (dstInfo, this)); |
489 } | 577 } |
| 578 |
OLD | NEW |