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 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
147 } else { | 147 } else { |
148 numTrans = 0; | 148 numTrans = 0; |
149 } | 149 } |
150 | 150 |
151 // check for bad images that might make us crash | 151 // check for bad images that might make us crash |
152 if (numTrans > numPalette) { | 152 if (numTrans > numPalette) { |
153 numTrans = numPalette; | 153 numTrans = numPalette; |
154 } | 154 } |
155 | 155 |
156 int index = 0; | 156 int index = 0; |
157 int transLessThanFF = 0; | |
158 | 157 |
159 // Choose which function to use to create the color table. If the final dest ination's | 158 // Choose which function to use to create the color table. If the final dest ination's |
160 // colortype is unpremultiplied, the color table will store unpremultiplied colors. | 159 // colortype is unpremultiplied, the color table will store unpremultiplied colors. |
161 PackColorProc proc; | 160 PackColorProc proc; |
162 if (premultiply) { | 161 if (premultiply) { |
163 proc = &SkPreMultiplyARGB; | 162 proc = &SkPreMultiplyARGB; |
164 } else { | 163 } else { |
165 proc = &SkPackARGB32NoCheck; | 164 proc = &SkPackARGB32NoCheck; |
166 } | 165 } |
167 for (; index < numTrans; index++) { | 166 for (; index < numTrans; index++) { |
168 transLessThanFF |= (int)*trans - 0xFF; | |
169 *colorPtr++ = proc(*trans++, palette->red, palette->green, palette->blue ); | 167 *colorPtr++ = proc(*trans++, palette->red, palette->green, palette->blue ); |
scroggo
2016/01/08 20:08:45
Can your other CL update this to use the SIMD vers
msarett
2016/01/08 20:10:29
Yes! Good point.
| |
170 palette++; | 168 palette++; |
171 } | 169 } |
172 | 170 |
173 if (transLessThanFF >= 0) { | |
174 // No transparent colors were found. | |
175 fAlphaState = kOpaque_AlphaState; | |
176 } | |
177 | |
178 for (; index < numPalette; index++) { | 171 for (; index < numPalette; index++) { |
179 *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette-> blue); | 172 *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette-> blue); |
180 palette++; | 173 palette++; |
181 } | 174 } |
182 | 175 |
183 /* BUGGY IMAGE WORKAROUND | 176 /* BUGGY IMAGE WORKAROUND |
184 Invalid images could contain pixel values that are greater than the numb er of palette | 177 Invalid images could contain pixel values that are greater than the numb er of palette |
185 entries. Since we use pixel values as indices into the palette this coul d result in reading | 178 entries. Since we use pixel values as indices into the palette this coul d result in reading |
186 beyond the end of the palette which could leak the contents of uninitial ized memory. To | 179 beyond the end of the palette which could leak the contents of uninitial ized memory. To |
187 ensure this doesn't happen, we grow the colortable to the maximum size t hat can be | 180 ensure this doesn't happen, we grow the colortable to the maximum size t hat can be |
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
377 | 370 |
378 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, SkPngChunkRead er* chunkReader, | 371 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, SkPngChunkRead er* chunkReader, |
379 png_structp png_ptr, png_infop info_ptr, int bitDepth, in t numberPasses) | 372 png_structp png_ptr, png_infop info_ptr, int bitDepth, in t numberPasses) |
380 : INHERITED(info, stream) | 373 : INHERITED(info, stream) |
381 , fPngChunkReader(SkSafeRef(chunkReader)) | 374 , fPngChunkReader(SkSafeRef(chunkReader)) |
382 , fPng_ptr(png_ptr) | 375 , fPng_ptr(png_ptr) |
383 , fInfo_ptr(info_ptr) | 376 , fInfo_ptr(info_ptr) |
384 , fSrcConfig(SkSwizzler::kUnknown) | 377 , fSrcConfig(SkSwizzler::kUnknown) |
385 , fNumberPasses(numberPasses) | 378 , fNumberPasses(numberPasses) |
386 , fBitDepth(bitDepth) | 379 , fBitDepth(bitDepth) |
387 { | 380 {} |
388 if (info.alphaType() == kOpaque_SkAlphaType) { | |
389 fAlphaState = kOpaque_AlphaState; | |
390 } else { | |
391 fAlphaState = kUnknown_AlphaState; | |
392 } | |
393 } | |
394 | 381 |
395 SkPngCodec::~SkPngCodec() { | 382 SkPngCodec::~SkPngCodec() { |
396 this->destroyReadStruct(); | 383 this->destroyReadStruct(); |
397 } | 384 } |
398 | 385 |
399 void SkPngCodec::destroyReadStruct() { | 386 void SkPngCodec::destroyReadStruct() { |
400 if (fPng_ptr) { | 387 if (fPng_ptr) { |
401 // We will never have a nullptr fInfo_ptr with a non-nullptr fPng_ptr | 388 // We will never have a nullptr fInfo_ptr with a non-nullptr fPng_ptr |
402 SkASSERT(fInfo_ptr); | 389 SkASSERT(fInfo_ptr); |
403 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL); | 390 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL); |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
519 // when we could have decoded a few more lines and then failed. | 506 // when we could have decoded a few more lines and then failed. |
520 // The read function that we provide for libpng has no way of indicating that we have | 507 // The read function that we provide for libpng has no way of indicating that we have |
521 // made a partial read. | 508 // made a partial read. |
522 // Making our buffer size smaller improves our incomplete decodes, but w hat impact does | 509 // Making our buffer size smaller improves our incomplete decodes, but w hat impact does |
523 // it have on regular decode performance? Should we investigate using a different API | 510 // it have on regular decode performance? Should we investigate using a different API |
524 // instead of png_read_row(s)? Chromium uses png_process_data. | 511 // instead of png_read_row(s)? Chromium uses png_process_data. |
525 *rowsDecoded = row; | 512 *rowsDecoded = row; |
526 return kIncompleteInput; | 513 return kIncompleteInput; |
527 } | 514 } |
528 | 515 |
529 bool hasAlpha = false; | |
530 // FIXME: We could split these out based on subclass. | 516 // FIXME: We could split these out based on subclass. |
531 void* dstRow = dst; | 517 void* dstRow = dst; |
532 if (fNumberPasses > 1) { | 518 if (fNumberPasses > 1) { |
533 const int width = requestedInfo.width(); | 519 const int width = requestedInfo.width(); |
534 const int height = requestedInfo.height(); | 520 const int height = requestedInfo.height(); |
535 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig); | 521 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig); |
536 const size_t srcRowBytes = width * bpp; | 522 const size_t srcRowBytes = width * bpp; |
537 | 523 |
538 storage.reset(width * height * bpp); | 524 storage.reset(width * height * bpp); |
539 uint8_t* const base = storage.get(); | 525 uint8_t* const base = storage.get(); |
540 | 526 |
541 for (int i = 0; i < fNumberPasses; i++) { | 527 for (int i = 0; i < fNumberPasses; i++) { |
542 uint8_t* srcRow = base; | 528 uint8_t* srcRow = base; |
543 for (int y = 0; y < height; y++) { | 529 for (int y = 0; y < height; y++) { |
544 uint8_t* bmRow = srcRow; | 530 uint8_t* bmRow = srcRow; |
545 png_read_rows(fPng_ptr, &bmRow, png_bytepp_NULL, 1); | 531 png_read_rows(fPng_ptr, &bmRow, png_bytepp_NULL, 1); |
546 srcRow += srcRowBytes; | 532 srcRow += srcRowBytes; |
547 } | 533 } |
548 } | 534 } |
549 | 535 |
550 // Now swizzle it. | 536 // Now swizzle it. |
551 uint8_t* srcRow = base; | 537 uint8_t* srcRow = base; |
552 for (int y = 0; y < height; y++) { | 538 for (int y = 0; y < height; y++) { |
553 hasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow, srcRow) ); | 539 fSwizzler->swizzle(dstRow, srcRow); |
554 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); | 540 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); |
555 srcRow += srcRowBytes; | 541 srcRow += srcRowBytes; |
556 } | 542 } |
557 } else { | 543 } else { |
558 storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConf ig)); | 544 storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConf ig)); |
559 uint8_t* srcRow = storage.get(); | 545 uint8_t* srcRow = storage.get(); |
560 for (; row < requestedInfo.height(); row++) { | 546 for (; row < requestedInfo.height(); row++) { |
561 png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1); | 547 png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1); |
562 // FIXME: Only call IsOpaque once, outside the loop. Same for onGetS canlines. | 548 // FIXME: Only call IsOpaque once, outside the loop. Same for onGetS canlines. |
563 hasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow, srcRow) ); | 549 fSwizzler->swizzle(dstRow, srcRow); |
564 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); | 550 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); |
565 } | 551 } |
566 } | 552 } |
567 | 553 |
568 if (hasAlpha) { | |
569 fAlphaState = kHasAlpha_AlphaState; | |
570 } else { | |
571 fAlphaState = kOpaque_AlphaState; | |
572 } | |
573 | |
574 // FIXME: do we need substituteTranspColor? Note that we cannot do it for | 554 // FIXME: do we need substituteTranspColor? Note that we cannot do it for |
575 // scanline decoding, but we could do it here. Alternatively, we could do | 555 // scanline decoding, but we could do it here. Alternatively, we could do |
576 // it as we go, instead of in post-processing like SkPNGImageDecoder. | 556 // it as we go, instead of in post-processing like SkPNGImageDecoder. |
577 | 557 |
578 if (setjmp(png_jmpbuf(fPng_ptr))) { | 558 if (setjmp(png_jmpbuf(fPng_ptr))) { |
579 // We've already read all the scanlines. This is a success. | 559 // We've already read all the scanlines. This is a success. |
580 return kSuccess; | 560 return kSuccess; |
581 } | 561 } |
582 | 562 |
583 // read rest of file, and get additional comment and time chunks in info_ptr | 563 // read rest of file, and get additional comment and time chunks in info_ptr |
584 png_read_end(fPng_ptr, fInfo_ptr); | 564 png_read_end(fPng_ptr, fInfo_ptr); |
585 | 565 |
586 return kSuccess; | 566 return kSuccess; |
587 } | 567 } |
588 | 568 |
589 uint32_t SkPngCodec::onGetFillValue(SkColorType colorType, SkAlphaType alphaType ) const { | 569 uint32_t SkPngCodec::onGetFillValue(SkColorType colorType, SkAlphaType alphaType ) const { |
590 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 570 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); |
591 if (colorPtr) { | 571 if (colorPtr) { |
592 return get_color_table_fill_value(colorType, colorPtr, 0); | 572 return get_color_table_fill_value(colorType, colorPtr, 0); |
593 } | 573 } |
594 return INHERITED::onGetFillValue(colorType, alphaType); | 574 return INHERITED::onGetFillValue(colorType, alphaType); |
595 } | 575 } |
596 | 576 |
597 bool SkPngCodec::onReallyHasAlpha() const { | |
598 switch (fAlphaState) { | |
599 case kOpaque_AlphaState: | |
600 return false; | |
601 case kUnknown_AlphaState: | |
602 // Maybe the subclass knows? | |
603 return this->alphaInScanlineDecode() == kHasAlpha_AlphaState; | |
604 case kHasAlpha_AlphaState: | |
605 switch (this->alphaInScanlineDecode()) { | |
606 case kUnknown_AlphaState: | |
607 // Scanline decoder must not have been used. Return our know ledge. | |
608 return true; | |
609 case kOpaque_AlphaState: | |
610 // Scanline decoder was used, and did not find alpha in its subset. | |
611 return false; | |
612 case kHasAlpha_AlphaState: | |
613 return true; | |
614 } | |
615 } | |
616 | |
617 // All valid AlphaStates have been covered, so this should not be reached. | |
618 SkASSERT(false); | |
619 return true; | |
620 } | |
621 | |
622 // Subclass of SkPngCodec which supports scanline decoding | 577 // Subclass of SkPngCodec which supports scanline decoding |
623 class SkPngScanlineDecoder : public SkPngCodec { | 578 class SkPngScanlineDecoder : public SkPngCodec { |
624 public: | 579 public: |
625 SkPngScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream, | 580 SkPngScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream, |
626 SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_p tr, int bitDepth) | 581 SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_p tr, int bitDepth) |
627 : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, 1 ) | 582 : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, 1 ) |
628 , fAlphaState(kUnknown_AlphaState) | |
629 , fSrcRow(nullptr) | 583 , fSrcRow(nullptr) |
630 {} | 584 {} |
631 | 585 |
632 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti ons, | 586 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti ons, |
633 SkPMColor ctable[], int* ctableCount) override { | 587 SkPMColor ctable[], int* ctableCount) override { |
634 if (!conversion_possible(dstInfo, this->getInfo())) { | 588 if (!conversion_possible(dstInfo, this->getInfo())) { |
635 return kInvalidConversion; | 589 return kInvalidConversion; |
636 } | 590 } |
637 | 591 |
638 const Result result = this->initializeSwizzler(dstInfo, options, ctable, | 592 const Result result = this->initializeSwizzler(dstInfo, options, ctable, |
639 ctableCount); | 593 ctableCount); |
640 if (result != kSuccess) { | 594 if (result != kSuccess) { |
641 return result; | 595 return result; |
642 } | 596 } |
643 | 597 |
644 fAlphaState = kUnknown_AlphaState; | |
645 fStorage.reset(this->getInfo().width() * SkSwizzler::BytesPerPixel(this- >srcConfig())); | 598 fStorage.reset(this->getInfo().width() * SkSwizzler::BytesPerPixel(this- >srcConfig())); |
646 fSrcRow = fStorage.get(); | 599 fSrcRow = fStorage.get(); |
647 | 600 |
648 return kSuccess; | 601 return kSuccess; |
649 } | 602 } |
650 | 603 |
651 int onGetScanlines(void* dst, int count, size_t rowBytes) override { | 604 int onGetScanlines(void* dst, int count, size_t rowBytes) override { |
652 // Assume that an error in libpng indicates an incomplete input. | 605 // Assume that an error in libpng indicates an incomplete input. |
653 int row = 0; | 606 int row = 0; |
654 if (setjmp(png_jmpbuf(this->png_ptr()))) { | 607 if (setjmp(png_jmpbuf(this->png_ptr()))) { |
655 SkCodecPrintf("setjmp long jump!\n"); | 608 SkCodecPrintf("setjmp long jump!\n"); |
656 return row; | 609 return row; |
657 } | 610 } |
658 | 611 |
659 void* dstRow = dst; | 612 void* dstRow = dst; |
660 bool hasAlpha = false; | |
661 for (; row < count; row++) { | 613 for (; row < count; row++) { |
662 png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1); | 614 png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1); |
663 hasAlpha |= !SkSwizzler::IsOpaque(this->swizzler()->swizzle(dstRow, fSrcRow)); | 615 this->swizzler()->swizzle(dstRow, fSrcRow); |
664 dstRow = SkTAddOffset<void>(dstRow, rowBytes); | 616 dstRow = SkTAddOffset<void>(dstRow, rowBytes); |
665 } | 617 } |
666 | 618 |
667 if (hasAlpha) { | |
668 fAlphaState = kHasAlpha_AlphaState; | |
669 } else { | |
670 if (kUnknown_AlphaState == fAlphaState) { | |
671 fAlphaState = kOpaque_AlphaState; | |
672 } | |
673 // Otherwise, the AlphaState is unchanged. | |
674 } | |
675 | |
676 return row; | 619 return row; |
677 } | 620 } |
678 | 621 |
679 bool onSkipScanlines(int count) override { | 622 bool onSkipScanlines(int count) override { |
680 // Assume that an error in libpng indicates an incomplete input. | 623 // Assume that an error in libpng indicates an incomplete input. |
681 if (setjmp(png_jmpbuf(this->png_ptr()))) { | 624 if (setjmp(png_jmpbuf(this->png_ptr()))) { |
682 SkCodecPrintf("setjmp long jump!\n"); | 625 SkCodecPrintf("setjmp long jump!\n"); |
683 return false; | 626 return false; |
684 } | 627 } |
685 //there is a potential tradeoff of memory vs speed created by putting th is in a loop. | 628 //there is a potential tradeoff of memory vs speed created by putting th is in a loop. |
686 //calling png_read_rows in a loop is insignificantly slower than calling it once with count | 629 //calling png_read_rows in a loop is insignificantly slower than calling it once with count |
687 //as png_read_rows has it's own loop which calls png_read_row count time s. | 630 //as png_read_rows has it's own loop which calls png_read_row count time s. |
688 for (int row = 0; row < count; row++) { | 631 for (int row = 0; row < count; row++) { |
689 png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1); | 632 png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1); |
690 } | 633 } |
691 return true; | 634 return true; |
692 } | 635 } |
693 | 636 |
694 AlphaState alphaInScanlineDecode() const override { | |
695 return fAlphaState; | |
696 } | |
697 | |
698 private: | 637 private: |
699 AlphaState fAlphaState; | |
700 SkAutoTMalloc<uint8_t> fStorage; | 638 SkAutoTMalloc<uint8_t> fStorage; |
701 uint8_t* fSrcRow; | 639 uint8_t* fSrcRow; |
702 | 640 |
703 typedef SkPngCodec INHERITED; | 641 typedef SkPngCodec INHERITED; |
704 }; | 642 }; |
705 | 643 |
706 | 644 |
707 class SkPngInterlacedScanlineDecoder : public SkPngCodec { | 645 class SkPngInterlacedScanlineDecoder : public SkPngCodec { |
708 public: | 646 public: |
709 SkPngInterlacedScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream, | 647 SkPngInterlacedScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream, |
710 SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_p tr, | 648 SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_p tr, |
711 int bitDepth, int numberPasses) | 649 int bitDepth, int numberPasses) |
712 : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, n umberPasses) | 650 : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, n umberPasses) |
713 , fAlphaState(kUnknown_AlphaState) | |
714 , fHeight(-1) | 651 , fHeight(-1) |
715 , fCanSkipRewind(false) | 652 , fCanSkipRewind(false) |
716 { | 653 { |
717 SkASSERT(numberPasses != 1); | 654 SkASSERT(numberPasses != 1); |
718 } | 655 } |
719 | 656 |
720 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti ons, | 657 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti ons, |
721 SkPMColor ctable[], int* ctableCount) override { | 658 SkPMColor ctable[], int* ctableCount) override { |
722 if (!conversion_possible(dstInfo, this->getInfo())) { | 659 if (!conversion_possible(dstInfo, this->getInfo())) { |
723 return kInvalidConversion; | 660 return kInvalidConversion; |
724 } | 661 } |
725 | 662 |
726 const Result result = this->initializeSwizzler(dstInfo, options, ctable, | 663 const Result result = this->initializeSwizzler(dstInfo, options, ctable, |
727 ctableCount); | 664 ctableCount); |
728 if (result != kSuccess) { | 665 if (result != kSuccess) { |
729 return result; | 666 return result; |
730 } | 667 } |
731 | 668 |
732 fAlphaState = kUnknown_AlphaState; | |
733 fHeight = dstInfo.height(); | 669 fHeight = dstInfo.height(); |
734 // FIXME: This need not be called on a second call to onStartScanlineDec ode. | 670 // FIXME: This need not be called on a second call to onStartScanlineDec ode. |
735 fSrcRowBytes = this->getInfo().width() * SkSwizzler::BytesPerPixel(this- >srcConfig()); | 671 fSrcRowBytes = this->getInfo().width() * SkSwizzler::BytesPerPixel(this- >srcConfig()); |
736 fGarbageRow.reset(fSrcRowBytes); | 672 fGarbageRow.reset(fSrcRowBytes); |
737 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); | 673 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); |
738 fCanSkipRewind = true; | 674 fCanSkipRewind = true; |
739 | 675 |
740 return SkCodec::kSuccess; | 676 return SkCodec::kSuccess; |
741 } | 677 } |
742 | 678 |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
786 srcRow += fSrcRowBytes; | 722 srcRow += fSrcRowBytes; |
787 } | 723 } |
788 // read rows we don't want into garbage buffer | 724 // read rows we don't want into garbage buffer |
789 for (int y = 0; y < fHeight - startRow - count; y++) { | 725 for (int y = 0; y < fHeight - startRow - count; y++) { |
790 png_read_rows(this->png_ptr(), &fGarbageRowPtr, png_bytepp_NULL, 1); | 726 png_read_rows(this->png_ptr(), &fGarbageRowPtr, png_bytepp_NULL, 1); |
791 } | 727 } |
792 } | 728 } |
793 //swizzle the rows we care about | 729 //swizzle the rows we care about |
794 srcRow = storagePtr; | 730 srcRow = storagePtr; |
795 void* dstRow = dst; | 731 void* dstRow = dst; |
796 bool hasAlpha = false; | |
797 for (int y = 0; y < count; y++) { | 732 for (int y = 0; y < count; y++) { |
798 hasAlpha |= !SkSwizzler::IsOpaque(this->swizzler()->swizzle(dstRow, srcRow)); | 733 this->swizzler()->swizzle(dstRow, srcRow); |
799 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); | 734 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); |
800 srcRow += fSrcRowBytes; | 735 srcRow += fSrcRowBytes; |
801 } | 736 } |
802 | 737 |
803 if (hasAlpha) { | |
804 fAlphaState = kHasAlpha_AlphaState; | |
805 } else { | |
806 if (kUnknown_AlphaState == fAlphaState) { | |
807 fAlphaState = kOpaque_AlphaState; | |
808 } | |
809 // Otherwise, the AlphaState is unchanged. | |
810 } | |
811 | |
812 return count; | 738 return count; |
813 } | 739 } |
814 | 740 |
815 bool onSkipScanlines(int count) override { | 741 bool onSkipScanlines(int count) override { |
816 // The non-virtual version will update fCurrScanline. | 742 // The non-virtual version will update fCurrScanline. |
817 return true; | 743 return true; |
818 } | 744 } |
819 | 745 |
820 AlphaState alphaInScanlineDecode() const override { | |
821 return fAlphaState; | |
822 } | |
823 | |
824 SkScanlineOrder onGetScanlineOrder() const override { | 746 SkScanlineOrder onGetScanlineOrder() const override { |
825 return kNone_SkScanlineOrder; | 747 return kNone_SkScanlineOrder; |
826 } | 748 } |
827 | 749 |
828 private: | 750 private: |
829 AlphaState fAlphaState; | |
830 int fHeight; | 751 int fHeight; |
831 size_t fSrcRowBytes; | 752 size_t fSrcRowBytes; |
832 SkAutoMalloc fGarbageRow; | 753 SkAutoMalloc fGarbageRow; |
833 uint8_t* fGarbageRowPtr; | 754 uint8_t* fGarbageRowPtr; |
834 // FIXME: This imitates behavior in SkCodec::rewindIfNeeded. That function | 755 // FIXME: This imitates behavior in SkCodec::rewindIfNeeded. That function |
835 // is called whenever some action is taken that reads the stream and | 756 // is called whenever some action is taken that reads the stream and |
836 // therefore the next call will require a rewind. So it modifies a boolean | 757 // therefore the next call will require a rewind. So it modifies a boolean |
837 // to note that the *next* time it is called a rewind is needed. | 758 // to note that the *next* time it is called a rewind is needed. |
838 // SkPngInterlacedScanlineDecoder has an extra wrinkle - calling | 759 // SkPngInterlacedScanlineDecoder has an extra wrinkle - calling |
839 // onStartScanlineDecode followed by onGetScanlines does *not* require a | 760 // onStartScanlineDecode followed by onGetScanlines does *not* require a |
(...skipping 18 matching lines...) Expand all Loading... | |
858 } | 779 } |
859 | 780 |
860 if (1 == numberPasses) { | 781 if (1 == numberPasses) { |
861 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), chunk Reader, | 782 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), chunk Reader, |
862 png_ptr, info_ptr, bitDepth); | 783 png_ptr, info_ptr, bitDepth); |
863 } | 784 } |
864 | 785 |
865 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(), chunkReader, | 786 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(), chunkReader, |
866 png_ptr, info_ptr, bitDepth, numbe rPasses); | 787 png_ptr, info_ptr, bitDepth, numbe rPasses); |
867 } | 788 } |
OLD | NEW |