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