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_libgif.h" | 8 #include "SkCodec_libgif.h" |
9 #include "SkCodecPriv.h" | 9 #include "SkCodecPriv.h" |
10 #include "SkColorPriv.h" | 10 #include "SkColorPriv.h" |
(...skipping 512 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
523 | 523 |
524 // Initialize the swizzler | 524 // Initialize the swizzler |
525 if (fFrameIsSubset) { | 525 if (fFrameIsSubset) { |
526 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameDims.width(), fFr ameDims.height()); | 526 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameDims.width(), fFr ameDims.height()); |
527 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia lized)) { | 527 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia lized)) { |
528 return gif_error("Could not initialize swizzler.\n", kUnimplemented) ; | 528 return gif_error("Could not initialize swizzler.\n", kUnimplemented) ; |
529 } | 529 } |
530 | 530 |
531 // Fill the background | 531 // Fill the background |
532 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 532 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); |
533 SkSwizzler::Fill(dst, dstInfo, dstRowBytes, this->getInfo().height(), | 533 SkSwizzler::Fill(dst, dstInfo, dstRowBytes, this->getFillValue(dstInfo), |
534 fFillIndex, colorPtr, opts.fZeroInitialized); | 534 opts.fZeroInitialized); |
535 | 535 |
536 // Modify the dst pointer | 536 // Modify the dst pointer |
537 const int32_t dstBytesPerPixel = SkColorTypeBytesPerPixel(dstInfo.colorT ype()); | 537 const int32_t dstBytesPerPixel = SkColorTypeBytesPerPixel(dstInfo.colorT ype()); |
538 dst = SkTAddOffset<void*>(dst, dstRowBytes * fFrameDims.top() + | 538 dst = SkTAddOffset<void*>(dst, dstRowBytes * fFrameDims.top() + |
539 dstBytesPerPixel * fFrameDims.left()); | 539 dstBytesPerPixel * fFrameDims.left()); |
540 } else { | 540 } else { |
541 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized) ) { | 541 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized) ) { |
542 return gif_error("Could not initialize swizzler.\n", kUnimplemented) ; | 542 return gif_error("Could not initialize swizzler.\n", kUnimplemented) ; |
543 } | 543 } |
544 } | 544 } |
545 | 545 |
546 // Check the interlace flag and iterate over rows of the input | 546 // Check the interlace flag and iterate over rows of the input |
547 uint32_t width = fFrameDims.width(); | 547 uint32_t width = fFrameDims.width(); |
548 uint32_t height = fFrameDims.height(); | 548 uint32_t height = fFrameDims.height(); |
549 if (fGif->Image.Interlace) { | 549 if (fGif->Image.Interlace) { |
550 // In interlace mode, the rows of input are rearranged in | 550 // In interlace mode, the rows of input are rearranged in |
551 // the output image. We a helper function to help us | 551 // the output image. We a helper function to help us |
552 // rearrange the decoded rows. | 552 // rearrange the decoded rows. |
553 for (uint32_t y = 0; y < height; y++) { | 553 for (uint32_t y = 0; y < height; y++) { |
554 if (kSuccess != this->readRow()) { | 554 if (kSuccess != this->readRow()) { |
555 // Recover from error by filling remainder of image | 555 // Incomplete interlaced gifs are a unique case. Rather than, |
556 memset(fSrcBuffer.get(), fFillIndex, width); | 556 // relying on the base class, we will fill the remaining lines |
557 // here. | |
558 const SkImageInfo fillInfo = dstInfo.makeWH(dstInfo.width(), 1); | |
559 const uint32_t fillValue = this->getFillValue(fillInfo); | |
557 for (; y < height; y++) { | 560 for (; y < height; y++) { |
558 void* dstRow = SkTAddOffset<void>(dst, | 561 void* dstRow = SkTAddOffset<void>(dst, |
559 dstRowBytes * get_output_row_interlaced(y, height)); | 562 dstRowBytes * get_output_row_interlaced(y, height)); |
560 fSwizzler->swizzle(dstRow, fSrcBuffer.get()); | 563 SkSwizzler::Fill(dstRow, fillInfo, dstRowBytes, fillValue, |
564 opts.fZeroInitialized); | |
561 } | 565 } |
562 return gif_error("Could not decode line.\n", kIncompleteInput); | 566 return gif_error("Could not decode line.\n", kIncompleteInput); |
563 } | 567 } |
564 void* dstRow = SkTAddOffset<void>(dst, | 568 void* dstRow = SkTAddOffset<void>(dst, |
565 dstRowBytes * get_output_row_interlaced(y, height)); | 569 dstRowBytes * get_output_row_interlaced(y, height)); |
566 fSwizzler->swizzle(dstRow, fSrcBuffer.get()); | 570 fSwizzler->swizzle(dstRow, fSrcBuffer.get()); |
567 } | 571 } |
568 } else { | 572 } else { |
569 // Standard mode | 573 // Standard mode |
570 void* dstRow = dst; | 574 void* dstRow = dst; |
571 for (uint32_t y = 0; y < height; y++) { | 575 for (uint32_t y = 0; y < height; y++) { |
572 if (kSuccess != this->readRow()) { | 576 if (kSuccess != this->readRow()) { |
573 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 577 this->setIncompleteScanlines(height - y); |
574 SkSwizzler::Fill(dstRow, dstInfo, dstRowBytes, | |
575 height - y, fFillIndex, colorPtr, opts.fZeroInitialized) ; | |
576 return gif_error("Could not decode line\n", kIncompleteInput); | 578 return gif_error("Could not decode line\n", kIncompleteInput); |
577 } | 579 } |
578 fSwizzler->swizzle(dstRow, fSrcBuffer.get()); | 580 fSwizzler->swizzle(dstRow, fSrcBuffer.get()); |
579 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); | 581 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); |
580 } | 582 } |
581 } | 583 } |
582 return kSuccess; | 584 return kSuccess; |
583 } | 585 } |
584 | 586 |
587 uint32_t SkGifCodec::onGetFillValue(const SkImageInfo& dstInfo) const { | |
588 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | |
589 return get_color_table_fill_value(dstInfo.colorType(), colorPtr, fFillIndex) ; | |
590 } | |
591 | |
585 // TODO (msarett): skbug.com/3582 | 592 // TODO (msarett): skbug.com/3582 |
586 // Should we implement reallyHasAlpha? Or should we read extens ion blocks in the | 593 // Should we implement reallyHasAlpha? Or should we read extens ion blocks in the |
587 // header? Or should we do both? | 594 // header? Or should we do both? |
588 | 595 |
589 class SkGifScanlineDecoder : public SkScanlineDecoder { | 596 class SkGifScanlineDecoder : public SkScanlineDecoder { |
590 public: | 597 public: |
591 SkGifScanlineDecoder(const SkImageInfo& srcInfo, SkGifCodec* codec) | 598 SkGifScanlineDecoder(SkGifCodec* codec) |
592 : INHERITED(srcInfo) | 599 : INHERITED(codec, codec->getInfo()) |
593 , fCodec(codec) | 600 , fCodec(codec) |
594 {} | 601 {} |
595 | 602 |
596 SkEncodedFormat onGetEncodedFormat() const override { | 603 SkEncodedFormat onGetEncodedFormat() const override { |
597 return kGIF_SkEncodedFormat; | 604 return kGIF_SkEncodedFormat; |
598 } | 605 } |
599 | 606 |
600 SkCodec::Result onStart(const SkImageInfo& dstInfo, const SkCodec::Options& opts, | 607 SkCodec::Result onStart(const SkImageInfo& dstInfo, const SkCodec::Options& opts, |
601 SkPMColor inputColorPtr[], int* inputColorCount) ove rride { | 608 SkPMColor inputColorPtr[], int* inputColorCount) ove rride { |
602 SkCodec::Result result = fCodec->prepareToDecode(dstInfo, inputColorPtr, inputColorCount, | 609 SkCodec::Result result = fCodec->prepareToDecode(dstInfo, inputColorPtr, inputColorCount, |
(...skipping 22 matching lines...) Expand all Loading... | |
625 } | 632 } |
626 } else { | 633 } else { |
627 if (SkCodec::kSuccess != fCodec->initializeSwizzler(dstInfo, opts.fZ eroInitialized)) { | 634 if (SkCodec::kSuccess != fCodec->initializeSwizzler(dstInfo, opts.fZ eroInitialized)) { |
628 return gif_error("Could not initialize swizzler.\n", SkCodec::kU nimplemented); | 635 return gif_error("Could not initialize swizzler.\n", SkCodec::kU nimplemented); |
629 } | 636 } |
630 } | 637 } |
631 | 638 |
632 return SkCodec::kSuccess; | 639 return SkCodec::kSuccess; |
633 } | 640 } |
634 | 641 |
635 SkCodec::Result onGetScanlines(void* dst, int count, size_t rowBytes) overri de { | 642 uint32_t onGetScanlines(void* dst, int count, size_t rowBytes) override { |
636 if (fCodec->fFrameIsSubset) { | 643 if (fCodec->fFrameIsSubset) { |
637 // Fill the requested rows | 644 // Fill the requested rows |
638 const SkPMColor* colorPtr = get_color_ptr(fCodec->fColorTable.get()) ; | 645 SkSwizzler::Fill(dst, this->dstInfo().makeWH(this->dstInfo().width() , count), rowBytes, |
639 SkSwizzler::Fill(dst, this->dstInfo(), rowBytes, count, fCodec->fFil lIndex, | 646 fCodec->onGetFillValue(dstInfo()), this->options().fZeroInit ialized); |
640 colorPtr, this->options().fZeroInitialized); | |
641 | 647 |
642 // Do nothing for rows before the image frame | 648 // Do nothing for rows before the image frame |
643 int rowsBeforeFrame = fCodec->fFrameDims.top() - INHERITED::getY(); | 649 int rowsBeforeFrame = fCodec->fFrameDims.top() - INHERITED::getY(); |
644 if (rowsBeforeFrame > 0) { | 650 if (rowsBeforeFrame > 0) { |
645 count = SkTMin(0, count - rowsBeforeFrame); | 651 count = SkTMin(0, count - rowsBeforeFrame); |
646 dst = SkTAddOffset<void>(dst, rowBytes * rowsBeforeFrame); | 652 dst = SkTAddOffset<void>(dst, rowBytes * rowsBeforeFrame); |
647 } | 653 } |
648 | 654 |
649 // Do nothing for rows after the image frame | 655 // Do nothing for rows after the image frame |
650 int rowsAfterFrame = INHERITED::getY() + count - fCodec->fFrameDims. bottom(); | 656 int rowsAfterFrame = INHERITED::getY() + count - fCodec->fFrameDims. bottom(); |
651 if (rowsAfterFrame > 0) { | 657 if (rowsAfterFrame > 0) { |
652 count = SkTMin(0, count - rowsAfterFrame); | 658 count = SkTMin(0, count - rowsAfterFrame); |
653 } | 659 } |
654 | 660 |
655 // Adjust dst pointer for left offset | 661 // Adjust dst pointer for left offset |
656 dst = SkTAddOffset<void>(dst, SkColorTypeBytesPerPixel( | 662 dst = SkTAddOffset<void>(dst, SkColorTypeBytesPerPixel( |
657 this->dstInfo().colorType()) * fCodec->fFrameDims.left()); | 663 this->dstInfo().colorType()) * fCodec->fFrameDims.left()); |
658 } | 664 } |
659 | 665 |
666 void* dstRow = dst; | |
660 for (int i = 0; i < count; i++) { | 667 for (int i = 0; i < count; i++) { |
661 if (SkCodec::kSuccess != fCodec->readRow()) { | 668 if (SkCodec::kSuccess != fCodec->readRow()) { |
scroggo
2015/09/22 18:02:48
Should readRow just return a boolean?
msarett
2015/09/23 13:22:40
Yes!
| |
662 const SkPMColor* colorPtr = get_color_ptr(fCodec->fColorTable.ge t()); | 669 return i; |
663 SkSwizzler::Fill(dst, this->dstInfo(), rowBytes, | |
664 count - i, fCodec->fFillIndex, colorPtr, | |
665 this->options().fZeroInitialized); | |
666 return gif_error("Could not decode line\n", SkCodec::kIncomplete Input); | |
667 } | 670 } |
668 fCodec->fSwizzler->swizzle(dst, fCodec->fSrcBuffer.get()); | 671 fCodec->fSwizzler->swizzle(dstRow, fCodec->fSrcBuffer.get()); |
669 dst = SkTAddOffset<void>(dst, rowBytes); | 672 dstRow = SkTAddOffset<void>(dstRow, rowBytes); |
670 } | 673 } |
671 return SkCodec::kSuccess; | 674 return count; |
672 } | 675 } |
673 | 676 |
674 SkScanlineOrder onGetScanlineOrder() const override { | 677 SkScanlineOrder onGetScanlineOrder() const override { |
675 if (fCodec->fGif->Image.Interlace) { | 678 if (fCodec->fGif->Image.Interlace) { |
676 return kOutOfOrder_SkScanlineOrder; | 679 return kOutOfOrder_SkScanlineOrder; |
677 } else { | 680 } else { |
678 return kTopDown_SkScanlineOrder; | 681 return kTopDown_SkScanlineOrder; |
679 } | 682 } |
680 } | 683 } |
681 | 684 |
682 int onGetY() const override { | 685 int onGetY(int encodedY) const override { |
683 if (fCodec->fGif->Image.Interlace) { | 686 if (fCodec->fGif->Image.Interlace) { |
684 return get_output_row_interlaced(INHERITED::onGetY(), this->dstInfo( ).height()); | 687 return get_output_row_interlaced(encodedY, this->dstInfo().height()) ; |
685 } else { | 688 } else { |
686 return INHERITED::onGetY(); | 689 return encodedY; |
687 } | 690 } |
688 } | 691 } |
689 | 692 |
690 private: | 693 private: |
691 SkAutoTDelete<SkGifCodec> fCodec; | 694 SkGifCodec* fCodec; // Owned by parent class |
692 | 695 |
693 typedef SkScanlineDecoder INHERITED; | 696 typedef SkScanlineDecoder INHERITED; |
694 }; | 697 }; |
695 | 698 |
696 SkScanlineDecoder* SkGifCodec::NewSDFromStream(SkStream* stream) { | 699 SkScanlineDecoder* SkGifCodec::NewSDFromStream(SkStream* stream) { |
697 SkAutoTDelete<SkGifCodec> codec (static_cast<SkGifCodec*>(SkGifCodec::NewFro mStream(stream))); | 700 SkAutoTDelete<SkGifCodec> codec (static_cast<SkGifCodec*>(SkGifCodec::NewFro mStream(stream))); |
698 if (!codec) { | 701 if (!codec) { |
699 return NULL; | 702 return NULL; |
700 } | 703 } |
701 | 704 |
702 const SkImageInfo& srcInfo = codec->getInfo(); | 705 return SkNEW_ARGS(SkGifScanlineDecoder, (codec.detach())); |
703 | |
704 return SkNEW_ARGS(SkGifScanlineDecoder, (srcInfo, codec.detach())); | |
705 } | 706 } |
OLD | NEW |