Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2297)

Side by Side Diff: src/codec/SkCodec_libpng.cpp

Issue 1332053002: Fill incomplete images in SkCodec parent class (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 349 matching lines...) Expand 10 before | Expand all | Expand 10 after
360 } 360 }
361 return nullptr; 361 return nullptr;
362 } 362 }
363 363
364 #define INVALID_NUMBER_PASSES -1 364 #define INVALID_NUMBER_PASSES -1
365 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, 365 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream,
366 png_structp png_ptr, png_infop info_ptr, int bitDepth) 366 png_structp png_ptr, png_infop info_ptr, int bitDepth)
367 : INHERITED(info, stream) 367 : INHERITED(info, stream)
368 , fPng_ptr(png_ptr) 368 , fPng_ptr(png_ptr)
369 , fInfo_ptr(info_ptr) 369 , fInfo_ptr(info_ptr)
370 , fRow(0)
370 , fSrcConfig(SkSwizzler::kUnknown) 371 , fSrcConfig(SkSwizzler::kUnknown)
371 , fNumberPasses(INVALID_NUMBER_PASSES) 372 , fNumberPasses(INVALID_NUMBER_PASSES)
372 , fReallyHasAlpha(false) 373 , fReallyHasAlpha(false)
373 , fBitDepth(bitDepth) 374 , fBitDepth(bitDepth)
374 {} 375 {}
375 376
376 SkPngCodec::~SkPngCodec() { 377 SkPngCodec::~SkPngCodec() {
377 this->destroyReadStruct(); 378 this->destroyReadStruct();
378 } 379 }
379 380
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
487 488
488 // Note that ctable and ctableCount may be modified if there is a color tabl e 489 // Note that ctable and ctableCount may be modified if there is a color tabl e
489 const Result result = this->initializeSwizzler(requestedInfo, options, 490 const Result result = this->initializeSwizzler(requestedInfo, options,
490 ctable, ctableCount); 491 ctable, ctableCount);
491 if (result != kSuccess) { 492 if (result != kSuccess) {
492 return result; 493 return result;
493 } 494 }
494 // FIXME: Could we use the return value of setjmp to specify the type of 495 // FIXME: Could we use the return value of setjmp to specify the type of
495 // error? 496 // error?
496 if (setjmp(png_jmpbuf(fPng_ptr))) { 497 if (setjmp(png_jmpbuf(fPng_ptr))) {
497 SkCodecPrintf("setjmp long jump!\n"); 498 // Assume that any error that occurs while reading rows is caused by an incomplete input.
498 return kInvalidInput; 499 if (fNumberPasses > 1) {
500 // FIXME (msarett): Handle incomplete interlaced pngs.
501 return kInvalidInput;
502 }
503 // FIXME: We do a poor job on incomplete pngs compared to other decoders (ex: Chromium,
504 // Ubuntu Image Viewer). This is because we use the default buffer size in libpng (8192
505 // bytes), and if we can't fill the buffer, we immediately fail. Making our buffer size
scroggo 2015/09/22 18:02:48 Does this mean, for example, that we try to read 8
msarett 2015/09/23 13:22:40 Yes that is exactly what the problem is.
scroggo 2015/09/25 15:55:05 Could you add that to the description?
msarett 2015/10/01 12:44:51 Done.
506 // smaller would help, but what impact would it have on regular decode p erformance? Should
507 // we investigate using a different API than png_read_row(s). Chromium uses
508 // png_process_data.
509 this->setIncompleteScanlines(requestedInfo.height() - fRow);
scroggo 2015/09/22 18:02:48 I always get confused when dealing with setjmp, so
msarett 2015/09/23 13:22:40 Yes this works! Clever!
scroggo 2015/09/25 15:55:05 Just to make sure, did you test this? Can we add a
msarett 2015/10/01 12:44:51 Yes I tested this. I have been testing by decodin
scroggo 2015/10/01 14:48:31 Possibly - the advantage to including it in CodexT
msarett 2015/10/01 18:14:13 I will add a single incomplete image to resources
510 return kIncompleteInput;
499 } 511 }
500 512
501 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); 513 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES);
502 SkAutoMalloc storage; 514 SkAutoMalloc storage;
503 void* dstRow = dst; 515 void* dstRow = dst;
504 if (fNumberPasses > 1) { 516 if (fNumberPasses > 1) {
505 const int width = requestedInfo.width(); 517 const int width = requestedInfo.width();
506 const int height = requestedInfo.height(); 518 const int height = requestedInfo.height();
507 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig); 519 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig);
508 const size_t srcRowBytes = width * bpp; 520 const size_t srcRowBytes = width * bpp;
(...skipping 13 matching lines...) Expand all
522 // Now swizzle it. 534 // Now swizzle it.
523 uint8_t* srcRow = base; 535 uint8_t* srcRow = base;
524 for (int y = 0; y < height; y++) { 536 for (int y = 0; y < height; y++) {
525 fReallyHasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow, srcRow)); 537 fReallyHasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow, srcRow));
526 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); 538 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
527 srcRow += srcRowBytes; 539 srcRow += srcRowBytes;
528 } 540 }
529 } else { 541 } else {
530 storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConf ig)); 542 storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConf ig));
531 uint8_t* srcRow = static_cast<uint8_t*>(storage.get()); 543 uint8_t* srcRow = static_cast<uint8_t*>(storage.get());
532 for (int y = 0; y < requestedInfo.height(); y++) { 544 for (fRow = 0; fRow < requestedInfo.height(); fRow++) {
533 png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1); 545 png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1);
534 fReallyHasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow, srcRow)); 546 fReallyHasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow, srcRow));
535 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); 547 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
536 } 548 }
537 } 549 }
538 550
539 // FIXME: do we need substituteTranspColor? Note that we cannot do it for 551 // 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 552 // scanline decoding, but we could do it here. Alternatively, we could do
541 // it as we go, instead of in post-processing like SkPNGImageDecoder. 553 // it as we go, instead of in post-processing like SkPNGImageDecoder.
542 554
543 if (setjmp(png_jmpbuf(fPng_ptr))) { 555 if (setjmp(png_jmpbuf(fPng_ptr))) {
544 // We've already read all the scanlines. This is a success. 556 // We've already read all the scanlines. This is a success.
545 return kSuccess; 557 return kSuccess;
546 } 558 }
547 559
548 // read rest of file, and get additional comment and time chunks in info_ptr 560 // read rest of file, and get additional comment and time chunks in info_ptr
549 png_read_end(fPng_ptr, fInfo_ptr); 561 png_read_end(fPng_ptr, fInfo_ptr);
550 return kSuccess; 562 return kSuccess;
551 } 563 }
552 564
565 uint32_t SkPngCodec::onGetFillValue(const SkImageInfo& dstInfo) const {
566 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get());
567 if (colorPtr) {
568 return get_color_table_fill_value(dstInfo.colorType(), colorPtr, 0);
569 }
570 return INHERITED::onGetFillValue(dstInfo);
571 }
572
553 class SkPngScanlineDecoder : public SkScanlineDecoder { 573 class SkPngScanlineDecoder : public SkScanlineDecoder {
554 public: 574 public:
555 SkPngScanlineDecoder(const SkImageInfo& srcInfo, SkPngCodec* codec) 575 SkPngScanlineDecoder(SkPngCodec* codec)
556 : INHERITED(srcInfo) 576 : INHERITED(codec, codec->getInfo())
557 , fCodec(codec) 577 , fCodec(codec)
558 , fHasAlpha(false) 578 , fHasAlpha(false)
559 {} 579 {}
560 580
561 SkCodec::Result onStart(const SkImageInfo& dstInfo, 581 SkCodec::Result onStart(const SkImageInfo& dstInfo,
562 const SkCodec::Options& options, 582 const SkCodec::Options& options,
563 SkPMColor ctable[], int* ctableCount) override { 583 SkPMColor ctable[], int* ctableCount) override {
564 if (!fCodec->rewindIfNeeded()) { 584 if (!fCodec->rewindIfNeeded()) {
565 return SkCodec::kCouldNotRewind; 585 return SkCodec::kCouldNotRewind;
566 } 586 }
567 587
568 if (!conversion_possible(dstInfo, this->getInfo())) { 588 if (!conversion_possible(dstInfo, this->getInfo())) {
569 return SkCodec::kInvalidConversion; 589 return SkCodec::kInvalidConversion;
570 } 590 }
571 591
572 // Check to see if scaling was requested. 592 // Check to see if scaling was requested.
573 if (dstInfo.dimensions() != this->getInfo().dimensions()) { 593 if (dstInfo.dimensions() != this->getInfo().dimensions()) {
574 if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) { 594 if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) {
575 return SkCodec::kInvalidScale; 595 return SkCodec::kInvalidScale;
576 } 596 }
577 } 597 }
578 598
579 const SkCodec::Result result = fCodec->initializeSwizzler(dstInfo, optio ns, ctable, 599 const SkCodec::Result result = fCodec->initializeSwizzler(dstInfo, optio ns, ctable,
580 ctableCount); 600 ctableCount);
581 if (result != SkCodec::kSuccess) { 601 if (result != SkCodec::kSuccess) {
582 return result; 602 return result;
583 } 603 }
584 604
585 fHasAlpha = false; 605 fHasAlpha = false;
586 fStorage.reset(this->getInfo().width() * SkSwizzler::BytesPerPixel(fCode c->fSrcConfig)); 606 fStorage.reset(this->getInfo().width() * SkSwizzler::BytesPerPixel(fCode c->fSrcConfig));
587 fSrcRow = static_cast<uint8_t*>(fStorage.get()); 607 fSrcRow = static_cast<uint8_t*>(fStorage.get());
588 608
589 return SkCodec::kSuccess; 609 return SkCodec::kSuccess;
590 } 610 }
591 611
592 SkCodec::Result onGetScanlines(void* dst, int count, size_t rowBytes) overri de { 612 uint32_t onGetScanlines(void* dst, int count, size_t rowBytes) override {
613 // Assume that an error in libpng indicates an incomplete input.
593 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { 614 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) {
594 SkCodecPrintf("setjmp long jump!\n"); 615 SkCodecPrintf("setjmp long jump!\n");
595 return SkCodec::kInvalidInput; 616 return fCodec->fRow;
596 } 617 }
597 618
598 void* dstRow = dst; 619 void* dstRow = dst;
599 for (int i = 0; i < count; i++) { 620 for (fCodec->fRow = 0; fCodec->fRow < count; fCodec->fRow++) {
600 png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1); 621 png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1);
601 fHasAlpha |= !SkSwizzler::IsOpaque(fCodec->fSwizzler->swizzle(dstRow , fSrcRow)); 622 fHasAlpha |= !SkSwizzler::IsOpaque(fCodec->fSwizzler->swizzle(dstRow , fSrcRow));
602 dstRow = SkTAddOffset<void>(dstRow, rowBytes); 623 dstRow = SkTAddOffset<void>(dstRow, rowBytes);
603 } 624 }
604 return SkCodec::kSuccess; 625 return fCodec->fRow;
605 } 626 }
606 627
607 SkCodec::Result onSkipScanlines(int count) override { 628 uint32_t onSkipScanlines(int count) override {
608 // FIXME: Could we use the return value of setjmp to specify the type of 629 // Assume that an error in libpng indicates an incomplete input.
609 // error?
610 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { 630 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) {
611 SkCodecPrintf("setjmp long jump!\n"); 631 SkCodecPrintf("setjmp long jump!\n");
612 return SkCodec::kInvalidInput; 632 return fCodec->fRow;
613 } 633 }
614 //there is a potential tradeoff of memory vs speed created by putting th is in a loop. 634 //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 635 //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. 636 //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++) { 637 for (fCodec->fRow = 0; fCodec->fRow < count; fCodec->fRow++) {
618 png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1); 638 png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1);
619 } 639 }
620 return SkCodec::kSuccess; 640 return fCodec->fRow;
621 } 641 }
622 642
623 bool onReallyHasAlpha() const override { return fHasAlpha; } 643 bool onReallyHasAlpha() const override { return fHasAlpha; }
624 644
625 SkEncodedFormat onGetEncodedFormat() const override { 645 SkEncodedFormat onGetEncodedFormat() const override {
626 return kPNG_SkEncodedFormat; 646 return kPNG_SkEncodedFormat;
627 } 647 }
628 648
629 649
630 private: 650 private:
631 SkAutoTDelete<SkPngCodec> fCodec; 651 SkPngCodec* fCodec; // Owned by parent class
632 bool fHasAlpha; 652 bool fHasAlpha;
633 SkAutoMalloc fStorage; 653 SkAutoMalloc fStorage;
634 uint8_t* fSrcRow; 654 uint8_t* fSrcRow;
635 655
636 typedef SkScanlineDecoder INHERITED; 656 typedef SkScanlineDecoder INHERITED;
637 }; 657 };
638 658
639 659
640 class SkPngInterlacedScanlineDecoder : public SkScanlineDecoder { 660 class SkPngInterlacedScanlineDecoder : public SkScanlineDecoder {
641 public: 661 public:
642 SkPngInterlacedScanlineDecoder(const SkImageInfo& srcInfo, SkPngCodec* codec ) 662 SkPngInterlacedScanlineDecoder(SkPngCodec* codec)
643 : INHERITED(srcInfo) 663 : INHERITED(codec, codec->getInfo())
644 , fCodec(codec) 664 , fCodec(codec)
645 , fHasAlpha(false) 665 , fHasAlpha(false)
646 , fCurrentRow(0) 666 , fCurrentRow(0)
647 , fHeight(srcInfo.height()) 667 , fHeight(codec->getInfo().height())
648 , fCanSkipRewind(false) 668 , fCanSkipRewind(false)
649 {} 669 {}
650 670
651 SkCodec::Result onStart(const SkImageInfo& dstInfo, 671 SkCodec::Result onStart(const SkImageInfo& dstInfo,
652 const SkCodec::Options& options, 672 const SkCodec::Options& options,
653 SkPMColor ctable[], int* ctableCount) override 673 SkPMColor ctable[], int* ctableCount) override
654 { 674 {
655 if (!fCodec->rewindIfNeeded()) { 675 if (!fCodec->rewindIfNeeded()) {
656 return SkCodec::kCouldNotRewind; 676 return SkCodec::kCouldNotRewind;
657 } 677 }
658 678
659 if (!conversion_possible(dstInfo, this->getInfo())) { 679 if (!conversion_possible(dstInfo, this->getInfo())) {
660 return SkCodec::kInvalidConversion; 680 return SkCodec::kInvalidConversion;
661 } 681 }
662 682
663 // Check to see if scaling was requested. 683 // Check to see if scaling was requested.
664 if (dstInfo.dimensions() != this->getInfo().dimensions()) { 684 if (dstInfo.dimensions() != this->getInfo().dimensions()) {
665 if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) { 685 if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) {
666 return SkCodec::kInvalidScale; 686 return SkCodec::kInvalidScale;
667 } 687 }
668 } 688 }
669 689
670 const SkCodec::Result result = fCodec->initializeSwizzler(dstInfo, optio ns, ctable, 690 const SkCodec::Result result = fCodec->initializeSwizzler(dstInfo, optio ns, ctable,
671 ctableCount); 691 ctableCount);
672 if (result != SkCodec::kSuccess) { 692 if (result != SkCodec::kSuccess) {
673 return result; 693 return result;
674 } 694 }
675 695
676 fHasAlpha = false; 696 fHasAlpha = false;
677 fCurrentRow = 0; 697 fCurrentRow = 0;
678 fHeight = dstInfo.height(); 698 fHeight = dstInfo.height();
679 fSrcRowBytes = this->getInfo().width() * SkSwizzler::BytesPerPixel(fCode c->fSrcConfig); 699 fSrcRowBytes = this->getInfo().width() * SkSwizzler::BytesPerPixel(fCode c->fSrcConfig);
680 fGarbageRow.reset(fSrcRowBytes); 700 fGarbageRow.reset(fSrcRowBytes);
681 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); 701 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get());
682 fCanSkipRewind = true; 702 fCanSkipRewind = true;
683 703
684 return SkCodec::kSuccess; 704 return SkCodec::kSuccess;
685 } 705 }
686 706
687 SkCodec::Result onGetScanlines(void* dst, int count, size_t dstRowBytes) ove rride { 707 uint32_t onGetScanlines(void* dst, int count, size_t dstRowBytes) override {
688 // rewind stream if have previously called onGetScanlines, 708 // rewind stream if have previously called onGetScanlines,
689 // since we need entire progressive image to get scanlines 709 // since we need entire progressive image to get scanlines
690 if (fCanSkipRewind) { 710 if (fCanSkipRewind) {
691 // We already rewound in onStart, so there is no reason to rewind. 711 // We already rewound in onStart, so there is no reason to rewind.
692 // Next time onGetScanlines is called, we will need to rewind. 712 // Next time onGetScanlines is called, we will need to rewind.
693 fCanSkipRewind = false; 713 fCanSkipRewind = false;
694 } else if (!fCodec->rewindIfNeeded()) { 714 } else if (!fCodec->rewindIfNeeded()) {
695 return SkCodec::kCouldNotRewind; 715 return 0;
696 } 716 }
697 717
698 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { 718 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) {
699 SkCodecPrintf("setjmp long jump!\n"); 719 SkCodecPrintf("setjmp long jump!\n");
700 return SkCodec::kInvalidInput; 720 // FIXME (msarett): Returning 0 is pessimistic. If we can complete a single pass,
721 // we may be able to report that all of the memory has been initiali zed. Even if we
722 // fail on the first pass, we can still report than some scanlines a re initialized.
723 return 0;
701 } 724 }
702 const int number_passes = png_set_interlace_handling(fCodec->fPng_ptr); 725 const int number_passes = png_set_interlace_handling(fCodec->fPng_ptr);
703 SkAutoMalloc storage(count * fSrcRowBytes); 726 SkAutoMalloc storage(count * fSrcRowBytes);
704 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get()); 727 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get());
705 uint8_t* srcRow; 728 uint8_t* srcRow;
706 for (int i = 0; i < number_passes; i++) { 729 for (int i = 0; i < number_passes; i++) {
707 //read rows we planned to skip into garbage row 730 //read rows we planned to skip into garbage row
708 for (int y = 0; y < fCurrentRow; y++){ 731 for (int y = 0; y < fCurrentRow; y++){
709 png_read_rows(fCodec->fPng_ptr, &fGarbageRowPtr, png_bytepp_NULL , 1); 732 png_read_rows(fCodec->fPng_ptr, &fGarbageRowPtr, png_bytepp_NULL , 1);
710 } 733 }
(...skipping 10 matching lines...) Expand all
721 } 744 }
722 //swizzle the rows we care about 745 //swizzle the rows we care about
723 srcRow = storagePtr; 746 srcRow = storagePtr;
724 void* dstRow = dst; 747 void* dstRow = dst;
725 for (int y = 0; y < count; y++) { 748 for (int y = 0; y < count; y++) {
726 fHasAlpha |= !SkSwizzler::IsOpaque(fCodec->fSwizzler->swizzle(dstRow , srcRow)); 749 fHasAlpha |= !SkSwizzler::IsOpaque(fCodec->fSwizzler->swizzle(dstRow , srcRow));
727 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); 750 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
728 srcRow += fSrcRowBytes; 751 srcRow += fSrcRowBytes;
729 } 752 }
730 fCurrentRow += count; 753 fCurrentRow += count;
731 return SkCodec::kSuccess; 754 return count;
732 } 755 }
733 756
734 SkCodec::Result onSkipScanlines(int count) override { 757 uint32_t onSkipScanlines(int count) override {
735 //when ongetScanlines is called it will skip to fCurrentRow 758 //when ongetScanlines is called it will skip to fCurrentRow
736 fCurrentRow += count; 759 fCurrentRow += count;
737 return SkCodec::kSuccess; 760 return count;
738 } 761 }
739 762
740 bool onReallyHasAlpha() const override { return fHasAlpha; } 763 bool onReallyHasAlpha() const override { return fHasAlpha; }
741 764
742 SkScanlineOrder onGetScanlineOrder() const override { 765 SkScanlineOrder onGetScanlineOrder() const override {
743 return kNone_SkScanlineOrder; 766 return kNone_SkScanlineOrder;
744 } 767 }
745 768
746 SkEncodedFormat onGetEncodedFormat() const override { 769 SkEncodedFormat onGetEncodedFormat() const override {
747 return kPNG_SkEncodedFormat; 770 return kPNG_SkEncodedFormat;
748 } 771 }
749 772
750 private: 773 private:
751 SkAutoTDelete<SkPngCodec> fCodec; 774 SkPngCodec* fCodec; // Owned by parent class
752 bool fHasAlpha; 775 bool fHasAlpha;
753 int fCurrentRow; 776 int fCurrentRow;
754 int fHeight; 777 int fHeight;
755 size_t fSrcRowBytes; 778 size_t fSrcRowBytes;
756 SkAutoMalloc fGarbageRow; 779 SkAutoMalloc fGarbageRow;
757 uint8_t* fGarbageRowPtr; 780 uint8_t* fGarbageRowPtr;
758 // FIXME: This imitates behavior in SkCodec::rewindIfNeeded. That function 781 // FIXME: This imitates behavior in SkCodec::rewindIfNeeded. That function
759 // is called whenever some action is taken that reads the stream and 782 // 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 783 // 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. 784 // to note that the *next* time it is called a rewind is needed.
762 // SkPngInterlacedScanlineDecoder has an extra wrinkle - calling onStart 785 // SkPngInterlacedScanlineDecoder has an extra wrinkle - calling onStart
763 // followed by onGetScanlines does *not* require a rewind. Since 786 // followed by onGetScanlines does *not* require a rewind. Since
764 // rewindIfNeeded does not have this flexibility, we need to add another 787 // rewindIfNeeded does not have this flexibility, we need to add another
765 // layer. 788 // layer.
766 bool fCanSkipRewind; 789 bool fCanSkipRewind;
767 790
768 typedef SkScanlineDecoder INHERITED; 791 typedef SkScanlineDecoder INHERITED;
769 }; 792 };
770 793
771 SkScanlineDecoder* SkPngCodec::NewSDFromStream(SkStream* stream) { 794 SkScanlineDecoder* SkPngCodec::NewSDFromStream(SkStream* stream) {
772 SkAutoTDelete<SkPngCodec> codec (static_cast<SkPngCodec*>(SkPngCodec::NewFro mStream(stream))); 795 SkAutoTDelete<SkPngCodec> codec (static_cast<SkPngCodec*>(SkPngCodec::NewFro mStream(stream)));
773 if (!codec) { 796 if (!codec) {
774 return nullptr; 797 return nullptr;
775 } 798 }
776 799
777 codec->fNumberPasses = png_set_interlace_handling(codec->fPng_ptr); 800 codec->fNumberPasses = png_set_interlace_handling(codec->fPng_ptr);
778 SkASSERT(codec->fNumberPasses != INVALID_NUMBER_PASSES); 801 SkASSERT(codec->fNumberPasses != INVALID_NUMBER_PASSES);
779 802
780 const SkImageInfo& srcInfo = codec->getInfo();
781 if (codec->fNumberPasses > 1) { 803 if (codec->fNumberPasses > 1) {
782 // interlaced image 804 // interlaced image
783 return new SkPngInterlacedScanlineDecoder(srcInfo, codec.detach()); 805 return new SkPngInterlacedScanlineDecoder(codec.detach());
784 } 806 }
785 807
786 return new SkPngScanlineDecoder(srcInfo, codec.detach()); 808 return new SkPngScanlineDecoder(codec.detach());
787 } 809 }
788 810
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698