Chromium Code Reviews| 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 |