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

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: Forgot to add SkSampler.cpp Created 5 years, 2 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 448 matching lines...) Expand 10 before | Expand all | Expand 10 after
459 return false; 459 return false;
460 } 460 }
461 461
462 fPng_ptr = png_ptr; 462 fPng_ptr = png_ptr;
463 fInfo_ptr = info_ptr; 463 fInfo_ptr = info_ptr;
464 return true; 464 return true;
465 } 465 }
466 466
467 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst, 467 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst,
468 size_t dstRowBytes, const Options& optio ns, 468 size_t dstRowBytes, const Options& optio ns,
469 SkPMColor ctable[], int* ctableCount) { 469 SkPMColor ctable[], int* ctableCount,
470 int* rowsDecoded) {
470 if (!conversion_possible(requestedInfo, this->getInfo())) { 471 if (!conversion_possible(requestedInfo, this->getInfo())) {
471 return kInvalidConversion; 472 return kInvalidConversion;
472 } 473 }
473 if (options.fSubset) { 474 if (options.fSubset) {
474 // Subsets are not supported. 475 // Subsets are not supported.
475 return kUnimplemented; 476 return kUnimplemented;
476 } 477 }
477 478
478 // Note that ctable and ctableCount may be modified if there is a color tabl e 479 // Note that ctable and ctableCount may be modified if there is a color tabl e
479 const Result result = this->initializeSwizzler(requestedInfo, options, 480 const Result result = this->initializeSwizzler(requestedInfo, options,
480 ctable, ctableCount); 481 ctable, ctableCount);
481 if (result != kSuccess) { 482 if (result != kSuccess) {
482 return result; 483 return result;
483 } 484 }
484 // FIXME: Could we use the return value of setjmp to specify the type of 485 // FIXME: Could we use the return value of setjmp to specify the type of
485 // error? 486 // error?
487 int row = 0;
486 if (setjmp(png_jmpbuf(fPng_ptr))) { 488 if (setjmp(png_jmpbuf(fPng_ptr))) {
487 SkCodecPrintf("setjmp long jump!\n"); 489 // Assume that any error that occurs while reading rows is caused by an incomplete input.
488 return kInvalidInput; 490 if (fNumberPasses > 1) {
491 // FIXME (msarett): Handle incomplete interlaced pngs.
492 return kInvalidInput;
493 }
494 // FIXME: We do a poor job on incomplete pngs compared to other decoders (ex: Chromium,
495 // Ubuntu Image Viewer). This is because we use the default buffer size in libpng (8192
496 // bytes), and if we can't fill the buffer, we immediately fail.
497 // For example, if we try to read 8192 bytes, and the image (incorrectly ) only contains
498 // half that, which may have been enough to contain a non-zero number of lines, we fail
499 // when we could have decoded a few more lines and then failed.
500 // The read function that we provide for libpng has no way of indicating that we have
501 // made a partial read.
502 // Making our buffer size smaller improves our incomplete decodes, but w hat impact does
503 // it have on regular decode performance? Should we investigate using a different API
504 // instead of png_read_row(s)? Chromium uses png_process_data.
505 *rowsDecoded = row;
506 return kIncompleteInput;
489 } 507 }
490 508
491 bool hasAlpha = false; 509 bool hasAlpha = false;
492 // FIXME: We could split these out based on subclass. 510 // FIXME: We could split these out based on subclass.
493 SkAutoMalloc storage; 511 SkAutoMalloc storage;
494 void* dstRow = dst; 512 void* dstRow = dst;
495 if (fNumberPasses > 1) { 513 if (fNumberPasses > 1) {
496 const int width = requestedInfo.width(); 514 const int width = requestedInfo.width();
497 const int height = requestedInfo.height(); 515 const int height = requestedInfo.height();
498 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig); 516 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig);
(...skipping 14 matching lines...) Expand all
513 // Now swizzle it. 531 // Now swizzle it.
514 uint8_t* srcRow = base; 532 uint8_t* srcRow = base;
515 for (int y = 0; y < height; y++) { 533 for (int y = 0; y < height; y++) {
516 hasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow, srcRow) ); 534 hasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow, srcRow) );
517 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); 535 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
518 srcRow += srcRowBytes; 536 srcRow += srcRowBytes;
519 } 537 }
520 } else { 538 } else {
521 storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConf ig)); 539 storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConf ig));
522 uint8_t* srcRow = static_cast<uint8_t*>(storage.get()); 540 uint8_t* srcRow = static_cast<uint8_t*>(storage.get());
523 for (int y = 0; y < requestedInfo.height(); y++) { 541 for (; row < requestedInfo.height(); row++) {
524 png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1); 542 png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1);
525 // FIXME: Only call IsOpaque once, outside the loop. Same for onGetS canlines. 543 // FIXME: Only call IsOpaque once, outside the loop. Same for onGetS canlines.
526 hasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow, srcRow) ); 544 hasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow, srcRow) );
527 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); 545 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
528 } 546 }
529 } 547 }
530 548
531 if (hasAlpha) { 549 if (hasAlpha) {
532 fAlphaState = kHasAlpha_AlphaState; 550 fAlphaState = kHasAlpha_AlphaState;
533 } else { 551 } else {
534 fAlphaState = kOpaque_AlphaState; 552 fAlphaState = kOpaque_AlphaState;
535 } 553 }
536 554
537 // 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
538 // 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
539 // it as we go, instead of in post-processing like SkPNGImageDecoder. 557 // it as we go, instead of in post-processing like SkPNGImageDecoder.
540 558
541 if (setjmp(png_jmpbuf(fPng_ptr))) { 559 if (setjmp(png_jmpbuf(fPng_ptr))) {
542 // We've already read all the scanlines. This is a success. 560 // We've already read all the scanlines. This is a success.
543 return kSuccess; 561 return kSuccess;
544 } 562 }
545 563
546 // 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
547 png_read_end(fPng_ptr, fInfo_ptr); 565 png_read_end(fPng_ptr, fInfo_ptr);
548 566
549 return kSuccess; 567 return kSuccess;
550 } 568 }
551 569
570 uint32_t SkPngCodec::onGetFillValue(SkColorType colorType, SkAlphaType alphaType ) const {
571 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get());
572 if (colorPtr) {
573 return get_color_table_fill_value(colorType, colorPtr, 0);
574 }
575 return INHERITED::onGetFillValue(colorType, alphaType);
576 }
577
552 bool SkPngCodec::onReallyHasAlpha() const { 578 bool SkPngCodec::onReallyHasAlpha() const {
553 switch (fAlphaState) { 579 switch (fAlphaState) {
554 case kOpaque_AlphaState: 580 case kOpaque_AlphaState:
555 return false; 581 return false;
556 case kUnknown_AlphaState: 582 case kUnknown_AlphaState:
557 // Maybe the subclass knows? 583 // Maybe the subclass knows?
558 return this->alphaInScanlineDecode() == kHasAlpha_AlphaState; 584 return this->alphaInScanlineDecode() == kHasAlpha_AlphaState;
559 case kHasAlpha_AlphaState: 585 case kHasAlpha_AlphaState:
560 switch (this->alphaInScanlineDecode()) { 586 switch (this->alphaInScanlineDecode()) {
561 case kUnknown_AlphaState: 587 case kUnknown_AlphaState:
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
596 return result; 622 return result;
597 } 623 }
598 624
599 fAlphaState = kUnknown_AlphaState; 625 fAlphaState = kUnknown_AlphaState;
600 fStorage.reset(this->getInfo().width() * SkSwizzler::BytesPerPixel(this- >srcConfig())); 626 fStorage.reset(this->getInfo().width() * SkSwizzler::BytesPerPixel(this- >srcConfig()));
601 fSrcRow = static_cast<uint8_t*>(fStorage.get()); 627 fSrcRow = static_cast<uint8_t*>(fStorage.get());
602 628
603 return kSuccess; 629 return kSuccess;
604 } 630 }
605 631
606 Result onGetScanlines(void* dst, int count, size_t rowBytes) override { 632 int onGetScanlines(void* dst, int count, size_t rowBytes) override {
633 // Assume that an error in libpng indicates an incomplete input.
634 int row = 0;
607 if (setjmp(png_jmpbuf(this->png_ptr()))) { 635 if (setjmp(png_jmpbuf(this->png_ptr()))) {
608 SkCodecPrintf("setjmp long jump!\n"); 636 SkCodecPrintf("setjmp long jump!\n");
609 return kInvalidInput; 637 return row;
610 } 638 }
611 639
612 void* dstRow = dst; 640 void* dstRow = dst;
613 bool hasAlpha = false; 641 bool hasAlpha = false;
614 for (int i = 0; i < count; i++) { 642 for (; row < count; row++) {
615 png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1); 643 png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1);
616 hasAlpha |= !SkSwizzler::IsOpaque(this->swizzler()->swizzle(dstRow, fSrcRow)); 644 hasAlpha |= !SkSwizzler::IsOpaque(this->swizzler()->swizzle(dstRow, fSrcRow));
617 dstRow = SkTAddOffset<void>(dstRow, rowBytes); 645 dstRow = SkTAddOffset<void>(dstRow, rowBytes);
618 } 646 }
619 647
620 if (hasAlpha) { 648 if (hasAlpha) {
621 fAlphaState = kHasAlpha_AlphaState; 649 fAlphaState = kHasAlpha_AlphaState;
622 } else { 650 } else {
623 if (kUnknown_AlphaState == fAlphaState) { 651 if (kUnknown_AlphaState == fAlphaState) {
624 fAlphaState = kOpaque_AlphaState; 652 fAlphaState = kOpaque_AlphaState;
625 } 653 }
626 // Otherwise, the AlphaState is unchanged. 654 // Otherwise, the AlphaState is unchanged.
627 } 655 }
628 656
629 return kSuccess; 657 return row;
630 } 658 }
631 659
632 Result onSkipScanlines(int count) override { 660 bool onSkipScanlines(int count) override {
633 // FIXME: Could we use the return value of setjmp to specify the type of 661 // Assume that an error in libpng indicates an incomplete input.
634 // error?
635 if (setjmp(png_jmpbuf(this->png_ptr()))) { 662 if (setjmp(png_jmpbuf(this->png_ptr()))) {
636 SkCodecPrintf("setjmp long jump!\n"); 663 SkCodecPrintf("setjmp long jump!\n");
637 return kInvalidInput; 664 return false;
638 } 665 }
639 //there is a potential tradeoff of memory vs speed created by putting th is in a loop. 666 //there is a potential tradeoff of memory vs speed created by putting th is in a loop.
640 //calling png_read_rows in a loop is insignificantly slower than calling it once with count 667 //calling png_read_rows in a loop is insignificantly slower than calling it once with count
641 //as png_read_rows has it's own loop which calls png_read_row count time s. 668 //as png_read_rows has it's own loop which calls png_read_row count time s.
642 for (int i = 0; i < count; i++) { 669 for (int row = 0; row < count; row++) {
643 png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1); 670 png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1);
644 } 671 }
645 return SkCodec::kSuccess; 672 return true;
646 } 673 }
647 674
648 AlphaState alphaInScanlineDecode() const override { 675 AlphaState alphaInScanlineDecode() const override {
649 return fAlphaState; 676 return fAlphaState;
650 } 677 }
651 678
652 private: 679 private:
653 AlphaState fAlphaState; 680 AlphaState fAlphaState;
654 SkAutoMalloc fStorage; 681 SkAutoMalloc fStorage;
655 uint8_t* fSrcRow; 682 uint8_t* fSrcRow;
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
687 fHeight = dstInfo.height(); 714 fHeight = dstInfo.height();
688 // FIXME: This need not be called on a second call to onStartScanlineDec ode. 715 // FIXME: This need not be called on a second call to onStartScanlineDec ode.
689 fSrcRowBytes = this->getInfo().width() * SkSwizzler::BytesPerPixel(this- >srcConfig()); 716 fSrcRowBytes = this->getInfo().width() * SkSwizzler::BytesPerPixel(this- >srcConfig());
690 fGarbageRow.reset(fSrcRowBytes); 717 fGarbageRow.reset(fSrcRowBytes);
691 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); 718 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get());
692 fCanSkipRewind = true; 719 fCanSkipRewind = true;
693 720
694 return SkCodec::kSuccess; 721 return SkCodec::kSuccess;
695 } 722 }
696 723
697 Result onGetScanlines(void* dst, int count, size_t dstRowBytes) override { 724 int onGetScanlines(void* dst, int count, size_t dstRowBytes) override {
698 // rewind stream if have previously called onGetScanlines, 725 // rewind stream if have previously called onGetScanlines,
699 // since we need entire progressive image to get scanlines 726 // since we need entire progressive image to get scanlines
700 if (fCanSkipRewind) { 727 if (fCanSkipRewind) {
701 // We already rewound in onStartScanlineDecode, so there is no reaso n to rewind. 728 // We already rewound in onStartScanlineDecode, so there is no reaso n to rewind.
702 // Next time onGetScanlines is called, we will need to rewind. 729 // Next time onGetScanlines is called, we will need to rewind.
703 fCanSkipRewind = false; 730 fCanSkipRewind = false;
704 } else { 731 } else {
705 // rewindIfNeeded resets fCurrScanline, since it assumes that start 732 // rewindIfNeeded resets fCurrScanline, since it assumes that start
706 // needs to be called again before scanline decoding. PNG scanline 733 // needs to be called again before scanline decoding. PNG scanline
707 // decoding is the exception, since it needs to rewind between 734 // decoding is the exception, since it needs to rewind between
708 // calls to getScanlines. Keep track of fCurrScanline, to undo the 735 // calls to getScanlines. Keep track of fCurrScanline, to undo the
709 // reset. 736 // reset.
710 const int currScanline = this->onNextScanline(); 737 const int currScanline = this->nextScanline();
711 // This method would never be called if currScanline is -1 738 // This method would never be called if currScanline is -1
712 SkASSERT(currScanline != -1); 739 SkASSERT(currScanline != -1);
713 740
714 if (!this->rewindIfNeeded()) { 741 if (!this->rewindIfNeeded()) {
715 return kCouldNotRewind; 742 return kCouldNotRewind;
716 } 743 }
717 this->updateNextScanline(currScanline); 744 this->updateNextScanline(currScanline);
718 } 745 }
719 746
720 if (setjmp(png_jmpbuf(this->png_ptr()))) { 747 if (setjmp(png_jmpbuf(this->png_ptr()))) {
721 SkCodecPrintf("setjmp long jump!\n"); 748 SkCodecPrintf("setjmp long jump!\n");
722 return kInvalidInput; 749 // FIXME (msarett): Returning 0 is pessimistic. If we can complete a single pass,
750 // we may be able to report that all of the memory has been initiali zed. Even if we
751 // fail on the first pass, we can still report than some scanlines a re initialized.
752 return 0;
723 } 753 }
724 SkAutoMalloc storage(count * fSrcRowBytes); 754 SkAutoMalloc storage(count * fSrcRowBytes);
725 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get()); 755 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get());
726 uint8_t* srcRow; 756 uint8_t* srcRow;
727 const int startRow = this->onNextScanline(); 757 const int startRow = this->nextScanline();
728 for (int i = 0; i < this->numberPasses(); i++) { 758 for (int i = 0; i < this->numberPasses(); i++) {
729 // read rows we planned to skip into garbage row 759 // read rows we planned to skip into garbage row
730 for (int y = 0; y < startRow; y++){ 760 for (int y = 0; y < startRow; y++){
731 png_read_rows(this->png_ptr(), &fGarbageRowPtr, png_bytepp_NULL, 1); 761 png_read_rows(this->png_ptr(), &fGarbageRowPtr, png_bytepp_NULL, 1);
732 } 762 }
733 // read rows we care about into buffer 763 // read rows we care about into buffer
734 srcRow = storagePtr; 764 srcRow = storagePtr;
735 for (int y = 0; y < count; y++) { 765 for (int y = 0; y < count; y++) {
736 png_read_rows(this->png_ptr(), &srcRow, png_bytepp_NULL, 1); 766 png_read_rows(this->png_ptr(), &srcRow, png_bytepp_NULL, 1);
737 srcRow += fSrcRowBytes; 767 srcRow += fSrcRowBytes;
(...skipping 15 matching lines...) Expand all
753 783
754 if (hasAlpha) { 784 if (hasAlpha) {
755 fAlphaState = kHasAlpha_AlphaState; 785 fAlphaState = kHasAlpha_AlphaState;
756 } else { 786 } else {
757 if (kUnknown_AlphaState == fAlphaState) { 787 if (kUnknown_AlphaState == fAlphaState) {
758 fAlphaState = kOpaque_AlphaState; 788 fAlphaState = kOpaque_AlphaState;
759 } 789 }
760 // Otherwise, the AlphaState is unchanged. 790 // Otherwise, the AlphaState is unchanged.
761 } 791 }
762 792
763 return kSuccess; 793 return count;
764 } 794 }
765 795
766 SkCodec::Result onSkipScanlines(int count) override { 796 bool onSkipScanlines(int count) override {
767 // The non-virtual version will update fCurrScanline. 797 // The non-virtual version will update fCurrScanline.
768 return SkCodec::kSuccess; 798 return true;
769 } 799 }
770 800
771 AlphaState alphaInScanlineDecode() const override { 801 AlphaState alphaInScanlineDecode() const override {
772 return fAlphaState; 802 return fAlphaState;
773 } 803 }
774 804
775 SkScanlineOrder onGetScanlineOrder() const override { 805 SkScanlineOrder onGetScanlineOrder() const override {
776 return kNone_SkScanlineOrder; 806 return kNone_SkScanlineOrder;
777 } 807 }
778 808
(...skipping 30 matching lines...) Expand all
809 839
810 if (1 == numberPasses) { 840 if (1 == numberPasses) {
811 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), png_p tr, info_ptr, 841 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), png_p tr, info_ptr,
812 bitDepth); 842 bitDepth);
813 } 843 }
814 844
815 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(), png_ptr, 845 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(), png_ptr,
816 info_ptr, bitDepth, numberPasses); 846 info_ptr, bitDepth, numberPasses);
817 } 847 }
818 848
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698