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" | |
16 #include "SkSize.h" | 15 #include "SkSize.h" |
17 #include "SkStream.h" | 16 #include "SkStream.h" |
18 #include "SkSwizzler.h" | 17 #include "SkSwizzler.h" |
19 | 18 |
20 /////////////////////////////////////////////////////////////////////////////// | 19 /////////////////////////////////////////////////////////////////////////////// |
21 // Helper macros | 20 // Helper macros |
22 /////////////////////////////////////////////////////////////////////////////// | 21 /////////////////////////////////////////////////////////////////////////////// |
23 | 22 |
24 #ifndef png_jmpbuf | 23 #ifndef png_jmpbuf |
25 # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) | 24 # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
156 proc = &SkPreMultiplyARGB; | 155 proc = &SkPreMultiplyARGB; |
157 } else { | 156 } else { |
158 proc = &SkPackARGB32NoCheck; | 157 proc = &SkPackARGB32NoCheck; |
159 } | 158 } |
160 for (; index < numTrans; index++) { | 159 for (; index < numTrans; index++) { |
161 transLessThanFF |= (int)*trans - 0xFF; | 160 transLessThanFF |= (int)*trans - 0xFF; |
162 *colorPtr++ = proc(*trans++, palette->red, palette->green, palette->blue
); | 161 *colorPtr++ = proc(*trans++, palette->red, palette->green, palette->blue
); |
163 palette++; | 162 palette++; |
164 } | 163 } |
165 | 164 |
166 fReallyHasAlpha = transLessThanFF < 0; | 165 if (transLessThanFF >= 0) { |
| 166 // No transparent colors were found. |
| 167 fAlphaState = kOpaque_AlphaState; |
| 168 } |
167 | 169 |
168 for (; index < numPalette; index++) { | 170 for (; index < numPalette; index++) { |
169 *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette->
blue); | 171 *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette->
blue); |
170 palette++; | 172 palette++; |
171 } | 173 } |
172 | 174 |
173 /* BUGGY IMAGE WORKAROUND | 175 /* BUGGY IMAGE WORKAROUND |
174 Invalid images could contain pixel values that are greater than the numb
er of palette | 176 Invalid images could contain pixel values that are greater than the numb
er of palette |
175 entries. Since we use pixel values as indices into the palette this coul
d result in reading | 177 entries. Since we use pixel values as indices into the palette this coul
d result in reading |
176 beyond the end of the palette which could leak the contents of uninitial
ized memory. To | 178 beyond the end of the palette which could leak the contents of uninitial
ized memory. To |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
209 } | 211 } |
210 return true; | 212 return true; |
211 } | 213 } |
212 | 214 |
213 // Reads the header, and initializes the passed in fields, if not nullptr (excep
t | 215 // Reads the header, and initializes the passed in fields, if not nullptr (excep
t |
214 // stream, which is passed to the read function). | 216 // stream, which is passed to the read function). |
215 // Returns true on success, in which case the caller is responsible for calling | 217 // 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 | 218 // png_destroy_read_struct. If it returns false, the passed in fields (except |
217 // stream) are unchanged. | 219 // stream) are unchanged. |
218 static bool read_header(SkStream* stream, png_structp* png_ptrp, | 220 static bool read_header(SkStream* stream, png_structp* png_ptrp, |
219 png_infop* info_ptrp, SkImageInfo* imageInfo, int* bitDe
pthPtr) { | 221 png_infop* info_ptrp, SkImageInfo* imageInfo, |
| 222 int* bitDepthPtr, int* numberPassesPtr) { |
220 // The image is known to be a PNG. Decode enough to know the SkImageInfo. | 223 // 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, nullptr, | 224 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, |
222 sk_error_fn, sk_warning_fn); | 225 sk_error_fn, sk_warning_fn); |
223 if (!png_ptr) { | 226 if (!png_ptr) { |
224 return false; | 227 return false; |
225 } | 228 } |
226 | 229 |
227 AutoCleanPng autoClean(png_ptr); | 230 AutoCleanPng autoClean(png_ptr); |
228 | 231 |
229 png_infop info_ptr = png_create_info_struct(png_ptr); | 232 png_infop info_ptr = png_create_info_struct(png_ptr); |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
326 break; | 329 break; |
327 case PNG_COLOR_TYPE_RGBA: | 330 case PNG_COLOR_TYPE_RGBA: |
328 skColorType = kN32_SkColorType; | 331 skColorType = kN32_SkColorType; |
329 skAlphaType = kUnpremul_SkAlphaType; | 332 skAlphaType = kUnpremul_SkAlphaType; |
330 break; | 333 break; |
331 default: | 334 default: |
332 //all the color types have been covered above | 335 //all the color types have been covered above |
333 SkASSERT(false); | 336 SkASSERT(false); |
334 } | 337 } |
335 | 338 |
| 339 int numberPasses = png_set_interlace_handling(png_ptr); |
| 340 if (numberPassesPtr) { |
| 341 *numberPassesPtr = numberPasses; |
| 342 } |
| 343 |
336 // FIXME: Also need to check for sRGB (skbug.com/3471). | 344 // FIXME: Also need to check for sRGB (skbug.com/3471). |
337 | 345 |
338 if (imageInfo) { | 346 if (imageInfo) { |
339 *imageInfo = SkImageInfo::Make(origWidth, origHeight, skColorType, skAlp
haType); | 347 *imageInfo = SkImageInfo::Make(origWidth, origHeight, skColorType, skAlp
haType); |
340 } | 348 } |
341 autoClean.detach(); | 349 autoClean.detach(); |
342 if (png_ptrp) { | 350 if (png_ptrp) { |
343 *png_ptrp = png_ptr; | 351 *png_ptrp = png_ptr; |
344 } | 352 } |
345 if (info_ptrp) { | 353 if (info_ptrp) { |
346 *info_ptrp = info_ptr; | 354 *info_ptrp = info_ptr; |
347 } | 355 } |
348 | 356 |
349 return true; | 357 return true; |
350 } | 358 } |
351 | 359 |
352 SkCodec* SkPngCodec::NewFromStream(SkStream* stream) { | |
353 SkAutoTDelete<SkStream> streamDeleter(stream); | |
354 png_structp png_ptr; | |
355 png_infop info_ptr; | |
356 SkImageInfo imageInfo; | |
357 int 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); | |
360 } | |
361 return nullptr; | |
362 } | |
363 | |
364 #define INVALID_NUMBER_PASSES -1 | |
365 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, | 360 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, |
366 png_structp png_ptr, png_infop info_ptr, int bitDepth) | 361 png_structp png_ptr, png_infop info_ptr, int bitDepth, in
t numberPasses) |
367 : INHERITED(info, stream) | 362 : INHERITED(info, stream) |
368 , fPng_ptr(png_ptr) | 363 , fPng_ptr(png_ptr) |
369 , fInfo_ptr(info_ptr) | 364 , fInfo_ptr(info_ptr) |
370 , fSrcConfig(SkSwizzler::kUnknown) | 365 , fSrcConfig(SkSwizzler::kUnknown) |
371 , fNumberPasses(INVALID_NUMBER_PASSES) | 366 , fNumberPasses(numberPasses) |
372 , fReallyHasAlpha(false) | |
373 , fBitDepth(bitDepth) | 367 , fBitDepth(bitDepth) |
374 {} | 368 { |
| 369 if (info.alphaType() == kOpaque_SkAlphaType) { |
| 370 fAlphaState = kOpaque_AlphaState; |
| 371 } else { |
| 372 fAlphaState = kUnknown_AlphaState; |
| 373 } |
| 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 nullptr fInfo_ptr with a non-nullptr 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 = nullptr; | 385 fPng_ptr = nullptr; |
386 fInfo_ptr = nullptr; | 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[], |
397 int* ctableCount) { | 397 int* ctableCount) { |
398 // FIXME: Could we use the return value of setjmp to specify the type of | 398 // FIXME: Could we use the return value of setjmp to specify the type of |
399 // error? | 399 // error? |
400 if (setjmp(png_jmpbuf(fPng_ptr))) { | 400 if (setjmp(png_jmpbuf(fPng_ptr))) { |
401 SkCodecPrintf("setjmp long jump!\n"); | 401 SkCodecPrintf("setjmp long jump!\n"); |
402 return kInvalidInput; | 402 return kInvalidInput; |
403 } | 403 } |
404 fNumberPasses = png_set_interlace_handling(fPng_ptr); | |
405 png_read_update_info(fPng_ptr, fInfo_ptr); | 404 png_read_update_info(fPng_ptr, fInfo_ptr); |
406 | 405 |
407 // Set to the default before calling decodePalette, which may change it. | 406 //srcColorType was determined in read_header() which determined png color ty
pe |
408 fReallyHasAlpha = false; | |
409 | |
410 //srcColorType was determined in readHeader() which determined png color typ
e | |
411 const SkColorType srcColorType = this->getInfo().colorType(); | 407 const SkColorType srcColorType = this->getInfo().colorType(); |
412 | 408 |
413 switch (srcColorType) { | 409 switch (srcColorType) { |
414 case kIndex_8_SkColorType: | 410 case kIndex_8_SkColorType: |
415 //decode palette to Skia format | 411 //decode palette to Skia format |
416 fSrcConfig = SkSwizzler::kIndex; | 412 fSrcConfig = SkSwizzler::kIndex; |
417 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaT
ype(), | 413 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaT
ype(), |
418 ctableCount)) { | 414 ctableCount)) { |
419 return kInvalidInput; | 415 return kInvalidInput; |
420 } | 416 } |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
452 bool SkPngCodec::onRewind() { | 448 bool SkPngCodec::onRewind() { |
453 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header | 449 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header |
454 // succeeds, they will be repopulated, and if it fails, they will | 450 // succeeds, they will be repopulated, and if it fails, they will |
455 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will | 451 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will |
456 // come through this function which will rewind and again attempt | 452 // come through this function which will rewind and again attempt |
457 // to reinitialize them. | 453 // to reinitialize them. |
458 this->destroyReadStruct(); | 454 this->destroyReadStruct(); |
459 | 455 |
460 png_structp png_ptr; | 456 png_structp png_ptr; |
461 png_infop info_ptr; | 457 png_infop info_ptr; |
462 if (!read_header(this->stream(), &png_ptr, &info_ptr, nullptr, nullptr)) { | 458 if (!read_header(this->stream(), &png_ptr, &info_ptr, nullptr, nullptr, null
ptr)) { |
463 return false; | 459 return false; |
464 } | 460 } |
465 | 461 |
466 fPng_ptr = png_ptr; | 462 fPng_ptr = png_ptr; |
467 fInfo_ptr = info_ptr; | 463 fInfo_ptr = info_ptr; |
468 return true; | 464 return true; |
469 } | 465 } |
470 | 466 |
471 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void*
dst, | 467 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void*
dst, |
472 size_t dstRowBytes, const Options& optio
ns, | 468 size_t dstRowBytes, const Options& optio
ns, |
(...skipping 18 matching lines...) Expand all Loading... |
491 if (result != kSuccess) { | 487 if (result != kSuccess) { |
492 return result; | 488 return result; |
493 } | 489 } |
494 // FIXME: Could we use the return value of setjmp to specify the type of | 490 // FIXME: Could we use the return value of setjmp to specify the type of |
495 // error? | 491 // error? |
496 if (setjmp(png_jmpbuf(fPng_ptr))) { | 492 if (setjmp(png_jmpbuf(fPng_ptr))) { |
497 SkCodecPrintf("setjmp long jump!\n"); | 493 SkCodecPrintf("setjmp long jump!\n"); |
498 return kInvalidInput; | 494 return kInvalidInput; |
499 } | 495 } |
500 | 496 |
501 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); | 497 bool hasAlpha = false; |
| 498 // FIXME: We could split these out based on subclass. |
502 SkAutoMalloc storage; | 499 SkAutoMalloc storage; |
503 void* dstRow = dst; | 500 void* dstRow = dst; |
504 if (fNumberPasses > 1) { | 501 if (fNumberPasses > 1) { |
505 const int width = requestedInfo.width(); | 502 const int width = requestedInfo.width(); |
506 const int height = requestedInfo.height(); | 503 const int height = requestedInfo.height(); |
507 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig); | 504 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig); |
508 const size_t srcRowBytes = width * bpp; | 505 const size_t srcRowBytes = width * bpp; |
509 | 506 |
510 storage.reset(width * height * bpp); | 507 storage.reset(width * height * bpp); |
511 uint8_t* const base = static_cast<uint8_t*>(storage.get()); | 508 uint8_t* const base = static_cast<uint8_t*>(storage.get()); |
512 | 509 |
513 for (int i = 0; i < fNumberPasses; i++) { | 510 for (int i = 0; i < fNumberPasses; i++) { |
514 uint8_t* srcRow = base; | 511 uint8_t* srcRow = base; |
515 for (int y = 0; y < height; y++) { | 512 for (int y = 0; y < height; y++) { |
516 uint8_t* bmRow = srcRow; | 513 uint8_t* bmRow = srcRow; |
517 png_read_rows(fPng_ptr, &bmRow, png_bytepp_NULL, 1); | 514 png_read_rows(fPng_ptr, &bmRow, png_bytepp_NULL, 1); |
518 srcRow += srcRowBytes; | 515 srcRow += srcRowBytes; |
519 } | 516 } |
520 } | 517 } |
521 | 518 |
522 // Now swizzle it. | 519 // Now swizzle it. |
523 uint8_t* srcRow = base; | 520 uint8_t* srcRow = base; |
524 for (int y = 0; y < height; y++) { | 521 for (int y = 0; y < height; y++) { |
525 fReallyHasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow,
srcRow)); | 522 hasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow, srcRow)
); |
526 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); | 523 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); |
527 srcRow += srcRowBytes; | 524 srcRow += srcRowBytes; |
528 } | 525 } |
529 } else { | 526 } else { |
530 storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConf
ig)); | 527 storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConf
ig)); |
531 uint8_t* srcRow = static_cast<uint8_t*>(storage.get()); | 528 uint8_t* srcRow = static_cast<uint8_t*>(storage.get()); |
532 for (int y = 0; y < requestedInfo.height(); y++) { | 529 for (int y = 0; y < requestedInfo.height(); y++) { |
533 png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1); | 530 png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1); |
534 fReallyHasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow,
srcRow)); | 531 // FIXME: Only call IsOpaque once, outside the loop. Same for onGetS
canlines. |
| 532 hasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow, srcRow)
); |
535 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); | 533 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); |
536 } | 534 } |
537 } | 535 } |
538 | 536 |
| 537 if (hasAlpha) { |
| 538 fAlphaState = kHasAlpha_AlphaState; |
| 539 } else { |
| 540 fAlphaState = kOpaque_AlphaState; |
| 541 } |
| 542 |
539 // FIXME: do we need substituteTranspColor? Note that we cannot do it for | 543 // FIXME: do we need substituteTranspColor? Note that we cannot do it for |
540 // scanline decoding, but we could do it here. Alternatively, we could do | 544 // scanline decoding, but we could do it here. Alternatively, we could do |
541 // it as we go, instead of in post-processing like SkPNGImageDecoder. | 545 // it as we go, instead of in post-processing like SkPNGImageDecoder. |
542 | 546 |
543 if (setjmp(png_jmpbuf(fPng_ptr))) { | 547 if (setjmp(png_jmpbuf(fPng_ptr))) { |
544 // We've already read all the scanlines. This is a success. | 548 // We've already read all the scanlines. This is a success. |
545 return kSuccess; | 549 return kSuccess; |
546 } | 550 } |
547 | 551 |
548 // read rest of file, and get additional comment and time chunks in info_ptr | 552 // read rest of file, and get additional comment and time chunks in info_ptr |
549 png_read_end(fPng_ptr, fInfo_ptr); | 553 png_read_end(fPng_ptr, fInfo_ptr); |
| 554 |
550 return kSuccess; | 555 return kSuccess; |
551 } | 556 } |
552 | 557 |
553 class SkPngScanlineDecoder : public SkScanlineDecoder { | 558 bool SkPngCodec::onReallyHasAlpha() const { |
| 559 switch (fAlphaState) { |
| 560 case kOpaque_AlphaState: |
| 561 return false; |
| 562 case kUnknown_AlphaState: |
| 563 // Maybe the subclass knows? |
| 564 return this->alphaInScanlineDecode() == kHasAlpha_AlphaState; |
| 565 case kHasAlpha_AlphaState: |
| 566 switch (this->alphaInScanlineDecode()) { |
| 567 case kUnknown_AlphaState: |
| 568 // Scanline decoder must not have been used. Return our know
ledge. |
| 569 return true; |
| 570 case kOpaque_AlphaState: |
| 571 // Scanline decoder was used, and did not find alpha in its
subset. |
| 572 return false; |
| 573 case kHasAlpha_AlphaState: |
| 574 return true; |
| 575 } |
| 576 } |
| 577 |
| 578 // All valid AlphaStates have been covered, so this should not be reached. |
| 579 SkASSERT(false); |
| 580 return true; |
| 581 } |
| 582 |
| 583 // Subclass of SkPngCodec which supports scanline decoding |
| 584 class SkPngScanlineDecoder : public SkPngCodec { |
554 public: | 585 public: |
555 SkPngScanlineDecoder(const SkImageInfo& srcInfo, SkPngCodec* codec) | 586 SkPngScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream, |
556 : INHERITED(srcInfo) | 587 png_structp png_ptr, png_infop info_ptr, int bitDepth) |
557 , fCodec(codec) | 588 : INHERITED(srcInfo, stream, png_ptr, info_ptr, bitDepth, 1) |
558 , fHasAlpha(false) | 589 , fSrcRow(nullptr) |
| 590 , fAlphaState(kUnknown_AlphaState) |
559 {} | 591 {} |
560 | 592 |
561 SkCodec::Result onStart(const SkImageInfo& dstInfo, | 593 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti
ons, |
562 const SkCodec::Options& options, | 594 SkPMColor ctable[], int* ctableCount) override { |
563 SkPMColor ctable[], int* ctableCount) override { | 595 if (!this->rewindIfNeeded()) { |
564 if (!fCodec->rewindIfNeeded()) { | 596 return kCouldNotRewind; |
565 return SkCodec::kCouldNotRewind; | |
566 } | 597 } |
567 | 598 |
568 if (!conversion_possible(dstInfo, this->getInfo())) { | 599 if (!conversion_possible(dstInfo, this->getInfo())) { |
569 return SkCodec::kInvalidConversion; | 600 return kInvalidConversion; |
570 } | 601 } |
571 | 602 |
572 // Check to see if scaling was requested. | 603 // Check to see if scaling was requested. |
573 if (dstInfo.dimensions() != this->getInfo().dimensions()) { | 604 if (dstInfo.dimensions() != this->getInfo().dimensions()) { |
574 if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(),
dstInfo)) { | 605 if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(),
dstInfo)) { |
575 return SkCodec::kInvalidScale; | 606 return kInvalidScale; |
576 } | 607 } |
577 } | 608 } |
578 | 609 |
579 const SkCodec::Result result = fCodec->initializeSwizzler(dstInfo, optio
ns, ctable, | 610 const Result result = this->initializeSwizzler(dstInfo, options, ctable, |
580 ctableCount); | 611 ctableCount); |
581 if (result != SkCodec::kSuccess) { | 612 if (result != kSuccess) { |
582 return result; | 613 return result; |
583 } | 614 } |
584 | 615 |
585 fHasAlpha = false; | 616 fAlphaState = kUnknown_AlphaState; |
586 fStorage.reset(this->getInfo().width() * SkSwizzler::BytesPerPixel(fCode
c->fSrcConfig)); | 617 fStorage.reset(this->getInfo().width() * SkSwizzler::BytesPerPixel(this-
>srcConfig())); |
587 fSrcRow = static_cast<uint8_t*>(fStorage.get()); | 618 fSrcRow = static_cast<uint8_t*>(fStorage.get()); |
588 | 619 |
589 return SkCodec::kSuccess; | 620 return kSuccess; |
590 } | 621 } |
591 | 622 |
592 SkCodec::Result onGetScanlines(void* dst, int count, size_t rowBytes) overri
de { | 623 Result onGetScanlines(void* dst, int count, size_t rowBytes) override { |
593 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { | 624 if (setjmp(png_jmpbuf(this->png_ptr()))) { |
594 SkCodecPrintf("setjmp long jump!\n"); | 625 SkCodecPrintf("setjmp long jump!\n"); |
595 return SkCodec::kInvalidInput; | 626 return kInvalidInput; |
596 } | 627 } |
597 | 628 |
598 void* dstRow = dst; | 629 void* dstRow = dst; |
| 630 bool hasAlpha = false; |
599 for (int i = 0; i < count; i++) { | 631 for (int i = 0; i < count; i++) { |
600 png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1); | 632 png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1); |
601 fHasAlpha |= !SkSwizzler::IsOpaque(fCodec->fSwizzler->swizzle(dstRow
, fSrcRow)); | 633 hasAlpha |= !SkSwizzler::IsOpaque(this->swizzler()->swizzle(dstRow,
fSrcRow)); |
602 dstRow = SkTAddOffset<void>(dstRow, rowBytes); | 634 dstRow = SkTAddOffset<void>(dstRow, rowBytes); |
603 } | 635 } |
604 return SkCodec::kSuccess; | 636 |
| 637 if (hasAlpha) { |
| 638 fAlphaState = kHasAlpha_AlphaState; |
| 639 } else { |
| 640 if (kUnknown_AlphaState == fAlphaState) { |
| 641 fAlphaState = kOpaque_AlphaState; |
| 642 } |
| 643 // Otherwise, the AlphaState is unchanged. |
| 644 } |
| 645 |
| 646 return kSuccess; |
605 } | 647 } |
606 | 648 |
607 SkCodec::Result onSkipScanlines(int count) override { | 649 Result onSkipScanlines(int count) override { |
608 // FIXME: Could we use the return value of setjmp to specify the type of | 650 // FIXME: Could we use the return value of setjmp to specify the type of |
609 // error? | 651 // error? |
610 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { | 652 if (setjmp(png_jmpbuf(this->png_ptr()))) { |
611 SkCodecPrintf("setjmp long jump!\n"); | 653 SkCodecPrintf("setjmp long jump!\n"); |
612 return SkCodec::kInvalidInput; | 654 return kInvalidInput; |
613 } | 655 } |
614 //there is a potential tradeoff of memory vs speed created by putting th
is in a loop. | 656 //there is a potential tradeoff of memory vs speed created by putting th
is in a loop. |
615 //calling png_read_rows in a loop is insignificantly slower than calling
it once with count | 657 //calling png_read_rows in a loop is insignificantly slower than calling
it once with count |
616 //as png_read_rows has it's own loop which calls png_read_row count time
s. | 658 //as png_read_rows has it's own loop which calls png_read_row count time
s. |
617 for (int i = 0; i < count; i++) { | 659 for (int i = 0; i < count; i++) { |
618 png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1); | 660 png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1); |
619 } | 661 } |
620 return SkCodec::kSuccess; | 662 return SkCodec::kSuccess; |
621 } | 663 } |
622 | 664 |
623 bool onReallyHasAlpha() const override { return fHasAlpha; } | 665 AlphaState alphaInScanlineDecode() const override { |
624 | 666 return fAlphaState; |
625 SkEncodedFormat onGetEncodedFormat() const override { | |
626 return kPNG_SkEncodedFormat; | |
627 } | 667 } |
628 | 668 |
629 | |
630 private: | 669 private: |
631 SkAutoTDelete<SkPngCodec> fCodec; | 670 AlphaState fAlphaState; |
632 bool fHasAlpha; | |
633 SkAutoMalloc fStorage; | 671 SkAutoMalloc fStorage; |
634 uint8_t* fSrcRow; | 672 uint8_t* fSrcRow; |
635 | 673 |
636 typedef SkScanlineDecoder INHERITED; | 674 typedef SkPngCodec INHERITED; |
637 }; | 675 }; |
638 | 676 |
639 | 677 |
640 class SkPngInterlacedScanlineDecoder : public SkScanlineDecoder { | 678 class SkPngInterlacedScanlineDecoder : public SkPngCodec { |
641 public: | 679 public: |
642 SkPngInterlacedScanlineDecoder(const SkImageInfo& srcInfo, SkPngCodec* codec
) | 680 SkPngInterlacedScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream, |
643 : INHERITED(srcInfo) | 681 png_structp png_ptr, png_infop info_ptr, int bitDepth, int numberPas
ses) |
644 , fCodec(codec) | 682 : INHERITED(srcInfo, stream, png_ptr, info_ptr, bitDepth, numberPasses) |
645 , fHasAlpha(false) | 683 , fAlphaState(kUnknown_AlphaState) |
646 , fCurrentRow(0) | 684 , fHeight(-1) |
647 , fHeight(srcInfo.height()) | |
648 , fCanSkipRewind(false) | 685 , fCanSkipRewind(false) |
649 {} | 686 { |
| 687 SkASSERT(numberPasses != 1); |
| 688 } |
650 | 689 |
651 SkCodec::Result onStart(const SkImageInfo& dstInfo, | 690 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti
ons, |
652 const SkCodec::Options& options, | 691 SkPMColor ctable[], int* ctableCount) override |
653 SkPMColor ctable[], int* ctableCount) override | |
654 { | 692 { |
655 if (!fCodec->rewindIfNeeded()) { | 693 if (!this->rewindIfNeeded()) { |
656 return SkCodec::kCouldNotRewind; | 694 return kCouldNotRewind; |
657 } | 695 } |
658 | 696 |
659 if (!conversion_possible(dstInfo, this->getInfo())) { | 697 if (!conversion_possible(dstInfo, this->getInfo())) { |
660 return SkCodec::kInvalidConversion; | 698 return kInvalidConversion; |
661 } | 699 } |
662 | 700 |
663 // Check to see if scaling was requested. | 701 // Check to see if scaling was requested. |
664 if (dstInfo.dimensions() != this->getInfo().dimensions()) { | 702 if (dstInfo.dimensions() != this->getInfo().dimensions()) { |
665 if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(),
dstInfo)) { | 703 if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(),
dstInfo)) { |
666 return SkCodec::kInvalidScale; | 704 return kInvalidScale; |
667 } | 705 } |
668 } | 706 } |
669 | 707 |
670 const SkCodec::Result result = fCodec->initializeSwizzler(dstInfo, optio
ns, ctable, | 708 const Result result = this->initializeSwizzler(dstInfo, options, ctable, |
671 ctableCount); | 709 ctableCount); |
672 if (result != SkCodec::kSuccess) { | 710 if (result != kSuccess) { |
673 return result; | 711 return result; |
674 } | 712 } |
675 | 713 |
676 fHasAlpha = false; | 714 fAlphaState = kUnknown_AlphaState; |
677 fCurrentRow = 0; | |
678 fHeight = dstInfo.height(); | 715 fHeight = dstInfo.height(); |
679 fSrcRowBytes = this->getInfo().width() * SkSwizzler::BytesPerPixel(fCode
c->fSrcConfig); | 716 // FIXME: This need not be called on a second call to onStartScanlineDec
ode. |
| 717 fSrcRowBytes = this->getInfo().width() * SkSwizzler::BytesPerPixel(this-
>srcConfig()); |
680 fGarbageRow.reset(fSrcRowBytes); | 718 fGarbageRow.reset(fSrcRowBytes); |
681 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); | 719 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); |
682 fCanSkipRewind = true; | 720 fCanSkipRewind = true; |
683 | 721 |
684 return SkCodec::kSuccess; | 722 return SkCodec::kSuccess; |
685 } | 723 } |
686 | 724 |
687 SkCodec::Result onGetScanlines(void* dst, int count, size_t dstRowBytes) ove
rride { | 725 Result onGetScanlines(void* dst, int count, size_t dstRowBytes) override { |
688 // rewind stream if have previously called onGetScanlines, | 726 // rewind stream if have previously called onGetScanlines, |
689 // since we need entire progressive image to get scanlines | 727 // since we need entire progressive image to get scanlines |
690 if (fCanSkipRewind) { | 728 if (fCanSkipRewind) { |
691 // We already rewound in onStart, so there is no reason to rewind. | 729 // We already rewound in onStartScanlineDecode, so there is no reaso
n to rewind. |
692 // Next time onGetScanlines is called, we will need to rewind. | 730 // Next time onGetScanlines is called, we will need to rewind. |
693 fCanSkipRewind = false; | 731 fCanSkipRewind = false; |
694 } else if (!fCodec->rewindIfNeeded()) { | 732 } else { |
695 return SkCodec::kCouldNotRewind; | 733 // rewindIfNeeded resets fCurrScanline, since it assumes that start |
| 734 // needs to be called again before scanline decoding. PNG scanline |
| 735 // decoding is the exception, since it needs to rewind between |
| 736 // calls to getScanlines. Keep track of fCurrScanline, to undo the |
| 737 // reset. |
| 738 const int currScanline = this->onNextScanline(); |
| 739 // This method would never be called if currScanline is -1 |
| 740 SkASSERT(currScanline != -1); |
| 741 |
| 742 if (!this->rewindIfNeeded()) { |
| 743 return kCouldNotRewind; |
| 744 } |
| 745 this->updateNextScanline(currScanline); |
696 } | 746 } |
697 | 747 |
698 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { | 748 if (setjmp(png_jmpbuf(this->png_ptr()))) { |
699 SkCodecPrintf("setjmp long jump!\n"); | 749 SkCodecPrintf("setjmp long jump!\n"); |
700 return SkCodec::kInvalidInput; | 750 return kInvalidInput; |
701 } | 751 } |
702 const int number_passes = png_set_interlace_handling(fCodec->fPng_ptr); | |
703 SkAutoMalloc storage(count * fSrcRowBytes); | 752 SkAutoMalloc storage(count * fSrcRowBytes); |
704 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get()); | 753 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get()); |
705 uint8_t* srcRow; | 754 uint8_t* srcRow; |
706 for (int i = 0; i < number_passes; i++) { | 755 const int startRow = this->onNextScanline(); |
707 //read rows we planned to skip into garbage row | 756 for (int i = 0; i < this->numberPasses(); i++) { |
708 for (int y = 0; y < fCurrentRow; y++){ | 757 // read rows we planned to skip into garbage row |
709 png_read_rows(fCodec->fPng_ptr, &fGarbageRowPtr, png_bytepp_NULL
, 1); | 758 for (int y = 0; y < startRow; y++){ |
| 759 png_read_rows(this->png_ptr(), &fGarbageRowPtr, png_bytepp_NULL,
1); |
710 } | 760 } |
711 //read rows we care about into buffer | 761 // read rows we care about into buffer |
712 srcRow = storagePtr; | 762 srcRow = storagePtr; |
713 for (int y = 0; y < count; y++) { | 763 for (int y = 0; y < count; y++) { |
714 png_read_rows(fCodec->fPng_ptr, &srcRow, png_bytepp_NULL, 1); | 764 png_read_rows(this->png_ptr(), &srcRow, png_bytepp_NULL, 1); |
715 srcRow += fSrcRowBytes; | 765 srcRow += fSrcRowBytes; |
716 } | 766 } |
717 //read rows we don't want into garbage buffer | 767 // read rows we don't want into garbage buffer |
718 for (int y = 0; y < fHeight - fCurrentRow - count; y++) { | 768 for (int y = 0; y < fHeight - startRow - count; y++) { |
719 png_read_rows(fCodec->fPng_ptr, &fGarbageRowPtr, png_bytepp_NULL
, 1); | 769 png_read_rows(this->png_ptr(), &fGarbageRowPtr, png_bytepp_NULL,
1); |
720 } | 770 } |
721 } | 771 } |
722 //swizzle the rows we care about | 772 //swizzle the rows we care about |
723 srcRow = storagePtr; | 773 srcRow = storagePtr; |
724 void* dstRow = dst; | 774 void* dstRow = dst; |
| 775 bool hasAlpha = false; |
725 for (int y = 0; y < count; y++) { | 776 for (int y = 0; y < count; y++) { |
726 fHasAlpha |= !SkSwizzler::IsOpaque(fCodec->fSwizzler->swizzle(dstRow
, srcRow)); | 777 hasAlpha |= !SkSwizzler::IsOpaque(this->swizzler()->swizzle(dstRow,
srcRow)); |
727 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); | 778 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); |
728 srcRow += fSrcRowBytes; | 779 srcRow += fSrcRowBytes; |
729 } | 780 } |
730 fCurrentRow += count; | 781 |
| 782 if (hasAlpha) { |
| 783 fAlphaState = kHasAlpha_AlphaState; |
| 784 } else { |
| 785 if (kUnknown_AlphaState == fAlphaState) { |
| 786 fAlphaState = kOpaque_AlphaState; |
| 787 } |
| 788 // Otherwise, the AlphaState is unchanged. |
| 789 } |
| 790 |
| 791 return kSuccess; |
| 792 } |
| 793 |
| 794 SkCodec::Result onSkipScanlines(int count) override { |
| 795 // The non-virtual version will update fCurrScanline. |
731 return SkCodec::kSuccess; | 796 return SkCodec::kSuccess; |
732 } | 797 } |
733 | 798 |
734 SkCodec::Result onSkipScanlines(int count) override { | 799 AlphaState alphaInScanlineDecode() const override { |
735 //when ongetScanlines is called it will skip to fCurrentRow | 800 return fAlphaState; |
736 fCurrentRow += count; | |
737 return SkCodec::kSuccess; | |
738 } | 801 } |
739 | 802 |
740 bool onReallyHasAlpha() const override { return fHasAlpha; } | |
741 | |
742 SkScanlineOrder onGetScanlineOrder() const override { | 803 SkScanlineOrder onGetScanlineOrder() const override { |
743 return kNone_SkScanlineOrder; | 804 return kNone_SkScanlineOrder; |
744 } | 805 } |
745 | 806 |
746 SkEncodedFormat onGetEncodedFormat() const override { | |
747 return kPNG_SkEncodedFormat; | |
748 } | |
749 | |
750 private: | 807 private: |
751 SkAutoTDelete<SkPngCodec> fCodec; | 808 AlphaState fAlphaState; |
752 bool fHasAlpha; | |
753 int fCurrentRow; | |
754 int fHeight; | 809 int fHeight; |
755 size_t fSrcRowBytes; | 810 size_t fSrcRowBytes; |
756 SkAutoMalloc fGarbageRow; | 811 SkAutoMalloc fGarbageRow; |
757 uint8_t* fGarbageRowPtr; | 812 uint8_t* fGarbageRowPtr; |
758 // FIXME: This imitates behavior in SkCodec::rewindIfNeeded. That function | 813 // FIXME: This imitates behavior in SkCodec::rewindIfNeeded. That function |
759 // is called whenever some action is taken that reads the stream and | 814 // is called whenever some action is taken that reads the stream and |
760 // therefore the next call will require a rewind. So it modifies a boolean | 815 // therefore the next call will require a rewind. So it modifies a boolean |
761 // to note that the *next* time it is called a rewind is needed. | 816 // to note that the *next* time it is called a rewind is needed. |
762 // SkPngInterlacedScanlineDecoder has an extra wrinkle - calling onStart | 817 // SkPngInterlacedScanlineDecoder has an extra wrinkle - calling |
763 // followed by onGetScanlines does *not* require a rewind. Since | 818 // onStartScanlineDecode followed by onGetScanlines does *not* require a |
764 // rewindIfNeeded does not have this flexibility, we need to add another | 819 // rewind. Since rewindIfNeeded does not have this flexibility, we need to |
765 // layer. | 820 // add another layer. |
766 bool fCanSkipRewind; | 821 bool fCanSkipRewind; |
767 | 822 |
768 typedef SkScanlineDecoder INHERITED; | 823 typedef SkPngCodec INHERITED; |
769 }; | 824 }; |
770 | 825 |
771 SkScanlineDecoder* SkPngCodec::NewSDFromStream(SkStream* stream) { | 826 SkCodec* SkPngCodec::NewFromStream(SkStream* stream) { |
772 SkAutoTDelete<SkPngCodec> codec (static_cast<SkPngCodec*>(SkPngCodec::NewFro
mStream(stream))); | 827 SkAutoTDelete<SkStream> streamDeleter(stream); |
773 if (!codec) { | 828 png_structp png_ptr; |
| 829 png_infop info_ptr; |
| 830 SkImageInfo imageInfo; |
| 831 int bitDepth; |
| 832 int numberPasses; |
| 833 |
| 834 if (!read_header(stream, &png_ptr, &info_ptr, &imageInfo, &bitDepth, &number
Passes)) { |
774 return nullptr; | 835 return nullptr; |
775 } | 836 } |
776 | 837 |
777 codec->fNumberPasses = png_set_interlace_handling(codec->fPng_ptr); | 838 if (1 == numberPasses) { |
778 SkASSERT(codec->fNumberPasses != INVALID_NUMBER_PASSES); | 839 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), png_p
tr, info_ptr, |
779 | 840 bitDepth); |
780 const SkImageInfo& srcInfo = codec->getInfo(); | |
781 if (codec->fNumberPasses > 1) { | |
782 // interlaced image | |
783 return new SkPngInterlacedScanlineDecoder(srcInfo, codec.detach()); | |
784 } | 841 } |
785 | 842 |
786 return new SkPngScanlineDecoder(srcInfo, codec.detach()); | 843 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(),
png_ptr, |
| 844 info_ptr, bitDepth, numberPasses); |
787 } | 845 } |
788 | 846 |
OLD | NEW |