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