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 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
89 // There should only be one graphics control extension for the image frame | 89 // There should only be one graphics control extension for the image frame |
90 break; | 90 break; |
91 } | 91 } |
92 } | 92 } |
93 | 93 |
94 // Use maximum unsigned int (surely an invalid index) to indicate that a val id | 94 // Use maximum unsigned int (surely an invalid index) to indicate that a val id |
95 // index was not found. | 95 // index was not found. |
96 return SK_MaxU32; | 96 return SK_MaxU32; |
97 } | 97 } |
98 | 98 |
99 static inline uint32_t ceil_div(uint32_t a, uint32_t b) { | |
100 return (a + b - 1) / b; | |
101 } | |
102 | |
103 /* | |
104 * Gets the output row corresponding to the encoded row for interlaced gifs | |
105 */ | |
106 static uint32_t get_output_row_interlaced(uint32_t encodedRow, uint32_t height) { | |
107 SkASSERT(encodedRow < height); | |
108 // First pass | |
109 if (encodedRow * 8 < height) { | |
110 return encodedRow * 8; | |
111 } | |
112 // Second pass | |
113 if (encodedRow * 4 < height) { | |
114 return 4 + 8 * (encodedRow - ceil_div(height, 8)); | |
115 } | |
116 // Third pass | |
117 if (encodedRow * 2 < height) { | |
118 return 2 + 4 * (encodedRow - ceil_div(height, 4)); | |
119 } | |
120 // Fourth pass | |
121 return 1 + 2 * (encodedRow - ceil_div(height, 2)); | |
122 } | |
123 | |
124 /* | 99 /* |
125 * This function cleans up the gif object after the decode completes | 100 * This function cleans up the gif object after the decode completes |
126 * It is used in a SkAutoTCallIProc template | 101 * It is used in a SkAutoTCallIProc template |
127 */ | 102 */ |
128 void SkGifCodec::CloseGif(GifFileType* gif) { | 103 void SkGifCodec::CloseGif(GifFileType* gif) { |
129 DGifCloseFile(gif, NULL); | 104 DGifCloseFile(gif, NULL); |
130 } | 105 } |
131 | 106 |
132 /* | 107 /* |
133 * This function free extension data that has been saved to assist the image | 108 * This function free extension data that has been saved to assist the image |
(...skipping 356 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
490 ZeroInitialized zeroInit) { | 465 ZeroInitialized zeroInit) { |
491 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 466 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); |
492 fSwizzler.reset(SkSwizzler::CreateSwizzler(SkSwizzler::kIndex, | 467 fSwizzler.reset(SkSwizzler::CreateSwizzler(SkSwizzler::kIndex, |
493 colorPtr, dstInfo, zeroInit, this->getInfo())); | 468 colorPtr, dstInfo, zeroInit, this->getInfo())); |
494 if (nullptr != fSwizzler.get()) { | 469 if (nullptr != fSwizzler.get()) { |
495 return kSuccess; | 470 return kSuccess; |
496 } | 471 } |
497 return kUnimplemented; | 472 return kUnimplemented; |
498 } | 473 } |
499 | 474 |
500 SkCodec::Result SkGifCodec::readRow() { | 475 bool SkGifCodec::readRow() { |
501 if (GIF_ERROR == DGifGetLine(fGif, fSrcBuffer.get(), fFrameDims.width())) { | 476 if (GIF_ERROR == DGifGetLine(fGif, fSrcBuffer.get(), fFrameDims.width())) { |
scroggo
2015/09/25 15:55:06
nit: This can be one line:
return GIF_ERROR != DG
msarett
2015/10/01 12:44:52
Done.
| |
502 return kIncompleteInput; | 477 return false; |
503 } | 478 } |
504 return kSuccess; | 479 return true; |
505 } | 480 } |
506 | 481 |
507 /* | 482 /* |
508 * Initiates the gif decode | 483 * Initiates the gif decode |
509 */ | 484 */ |
510 SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo, | 485 SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo, |
511 void* dst, size_t dstRowBytes, | 486 void* dst, size_t dstRowBytes, |
512 const Options& opts, | 487 const Options& opts, |
513 SkPMColor* inputColorPtr, | 488 SkPMColor* inputColorPtr, |
514 int* inputColorCount) { | 489 int* inputColorCount, |
490 int* incompleteScanlines) { | |
515 Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCoun t, opts); | 491 Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCoun t, opts); |
516 if (kSuccess != result) { | 492 if (kSuccess != result) { |
517 return result; | 493 return result; |
518 } | 494 } |
519 | 495 |
520 if (dstInfo.dimensions() != this->getInfo().dimensions()) { | 496 if (dstInfo.dimensions() != this->getInfo().dimensions()) { |
521 return gif_error("Scaling not supported.\n", kInvalidScale); | 497 return gif_error("Scaling not supported.\n", kInvalidScale); |
522 } | 498 } |
523 | 499 |
524 // Initialize the swizzler | 500 // Initialize the swizzler |
525 if (fFrameIsSubset) { | 501 if (fFrameIsSubset) { |
526 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameDims.width(), fFr ameDims.height()); | 502 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameDims.width(), fFr ameDims.height()); |
527 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia lized)) { | 503 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia lized)) { |
528 return gif_error("Could not initialize swizzler.\n", kUnimplemented) ; | 504 return gif_error("Could not initialize swizzler.\n", kUnimplemented) ; |
529 } | 505 } |
530 | 506 |
531 // Fill the background | 507 // Fill the background |
532 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 508 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); |
533 SkSwizzler::Fill(dst, dstInfo, dstRowBytes, this->getInfo().height(), | 509 SkSwizzler::Fill(dst, dstInfo, dstRowBytes, this->getFillValue(dstInfo), |
534 fFillIndex, colorPtr, opts.fZeroInitialized); | 510 opts.fZeroInitialized); |
535 | 511 |
536 // Modify the dst pointer | 512 // Modify the dst pointer |
537 const int32_t dstBytesPerPixel = SkColorTypeBytesPerPixel(dstInfo.colorT ype()); | 513 const int32_t dstBytesPerPixel = SkColorTypeBytesPerPixel(dstInfo.colorT ype()); |
538 dst = SkTAddOffset<void*>(dst, dstRowBytes * fFrameDims.top() + | 514 dst = SkTAddOffset<void*>(dst, dstRowBytes * fFrameDims.top() + |
539 dstBytesPerPixel * fFrameDims.left()); | 515 dstBytesPerPixel * fFrameDims.left()); |
540 } else { | 516 } else { |
541 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized) ) { | 517 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized) ) { |
542 return gif_error("Could not initialize swizzler.\n", kUnimplemented) ; | 518 return gif_error("Could not initialize swizzler.\n", kUnimplemented) ; |
543 } | 519 } |
544 } | 520 } |
545 | 521 |
546 // Check the interlace flag and iterate over rows of the input | 522 // Check the interlace flag and iterate over rows of the input |
547 uint32_t width = fFrameDims.width(); | 523 uint32_t width = fFrameDims.width(); |
548 uint32_t height = fFrameDims.height(); | 524 uint32_t height = fFrameDims.height(); |
549 if (fGif->Image.Interlace) { | 525 if (fGif->Image.Interlace) { |
550 // In interlace mode, the rows of input are rearranged in | 526 // In interlace mode, the rows of input are rearranged in |
551 // the output image. We a helper function to help us | 527 // the output image. We a helper function to help us |
552 // rearrange the decoded rows. | 528 // rearrange the decoded rows. |
553 for (uint32_t y = 0; y < height; y++) { | 529 for (uint32_t y = 0; y < height; y++) { |
554 if (kSuccess != this->readRow()) { | 530 if (!this->readRow()) { |
555 // Recover from error by filling remainder of image | 531 // Incomplete interlaced gifs are a unique case. Rather than, |
556 memset(fSrcBuffer.get(), fFillIndex, width); | 532 // relying on the base class, we will fill the remaining lines |
533 // here. | |
534 const SkImageInfo fillInfo = dstInfo.makeWH(dstInfo.width(), 1); | |
535 const uint32_t fillValue = this->getFillValue(fillInfo); | |
557 for (; y < height; y++) { | 536 for (; y < height; y++) { |
558 void* dstRow = SkTAddOffset<void>(dst, | 537 void* dstRow = SkTAddOffset<void>(dst, |
559 dstRowBytes * get_output_row_interlaced(y, height)); | 538 dstRowBytes * get_output_row_interlaced(y, height)); |
560 fSwizzler->swizzle(dstRow, fSrcBuffer.get()); | 539 SkSwizzler::Fill(dstRow, fillInfo, dstRowBytes, fillValue, |
540 opts.fZeroInitialized); | |
561 } | 541 } |
562 return gif_error("Could not decode line.\n", kIncompleteInput); | 542 return gif_error("Could not decode line.\n", kIncompleteInput); |
563 } | 543 } |
564 void* dstRow = SkTAddOffset<void>(dst, | 544 void* dstRow = SkTAddOffset<void>(dst, |
565 dstRowBytes * get_output_row_interlaced(y, height)); | 545 dstRowBytes * get_output_row_interlaced(y, height)); |
566 fSwizzler->swizzle(dstRow, fSrcBuffer.get()); | 546 fSwizzler->swizzle(dstRow, fSrcBuffer.get()); |
567 } | 547 } |
568 } else { | 548 } else { |
569 // Standard mode | 549 // Standard mode |
570 void* dstRow = dst; | 550 void* dstRow = dst; |
571 for (uint32_t y = 0; y < height; y++) { | 551 for (uint32_t y = 0; y < height; y++) { |
572 if (kSuccess != this->readRow()) { | 552 if (!this->readRow()) { |
573 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 553 *incompleteScanlines = 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); | 554 return gif_error("Could not decode line\n", kIncompleteInput); |
577 } | 555 } |
578 fSwizzler->swizzle(dstRow, fSrcBuffer.get()); | 556 fSwizzler->swizzle(dstRow, fSrcBuffer.get()); |
579 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); | 557 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); |
580 } | 558 } |
581 } | 559 } |
582 return kSuccess; | 560 return kSuccess; |
583 } | 561 } |
584 | 562 |
563 uint32_t SkGifCodec::onGetFillValue(const SkImageInfo& dstInfo) const { | |
564 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | |
565 return get_color_table_fill_value(dstInfo.colorType(), colorPtr, fFillIndex) ; | |
566 } | |
567 | |
585 // TODO (msarett): skbug.com/3582 | 568 // TODO (msarett): skbug.com/3582 |
586 // Should we implement reallyHasAlpha? Or should we read extens ion blocks in the | 569 // Should we implement reallyHasAlpha? Or should we read extens ion blocks in the |
587 // header? Or should we do both? | 570 // header? Or should we do both? |
588 | 571 |
589 class SkGifScanlineDecoder : public SkScanlineDecoder { | 572 class SkGifScanlineDecoder : public SkScanlineDecoder { |
590 public: | 573 public: |
591 SkGifScanlineDecoder(const SkImageInfo& srcInfo, SkGifCodec* codec) | 574 SkGifScanlineDecoder(SkGifCodec* codec) |
592 : INHERITED(srcInfo) | 575 : INHERITED(codec, codec->getInfo()) |
593 , fCodec(codec) | 576 , fCodec(codec) |
594 {} | 577 {} |
595 | 578 |
596 SkEncodedFormat onGetEncodedFormat() const override { | 579 SkEncodedFormat onGetEncodedFormat() const override { |
597 return kGIF_SkEncodedFormat; | 580 return kGIF_SkEncodedFormat; |
598 } | 581 } |
599 | 582 |
600 SkCodec::Result onStart(const SkImageInfo& dstInfo, const SkCodec::Options& opts, | 583 SkCodec::Result onStart(const SkImageInfo& dstInfo, const SkCodec::Options& opts, |
601 SkPMColor inputColorPtr[], int* inputColorCount) ove rride { | 584 SkPMColor inputColorPtr[], int* inputColorCount) ove rride { |
602 SkCodec::Result result = fCodec->prepareToDecode(dstInfo, inputColorPtr, inputColorCount, | 585 SkCodec::Result result = fCodec->prepareToDecode(dstInfo, inputColorPtr, inputColorCount, |
(...skipping 22 matching lines...) Expand all Loading... | |
625 } | 608 } |
626 } else { | 609 } else { |
627 if (SkCodec::kSuccess != fCodec->initializeSwizzler(dstInfo, opts.fZ eroInitialized)) { | 610 if (SkCodec::kSuccess != fCodec->initializeSwizzler(dstInfo, opts.fZ eroInitialized)) { |
628 return gif_error("Could not initialize swizzler.\n", SkCodec::kU nimplemented); | 611 return gif_error("Could not initialize swizzler.\n", SkCodec::kU nimplemented); |
629 } | 612 } |
630 } | 613 } |
631 | 614 |
632 return SkCodec::kSuccess; | 615 return SkCodec::kSuccess; |
633 } | 616 } |
634 | 617 |
635 SkCodec::Result onGetScanlines(void* dst, int count, size_t rowBytes) overri de { | 618 uint32_t onGetScanlines(void* dst, int count, size_t rowBytes) override { |
636 if (fCodec->fFrameIsSubset) { | 619 if (fCodec->fFrameIsSubset) { |
637 // Fill the requested rows | 620 // Fill the requested rows |
638 const SkPMColor* colorPtr = get_color_ptr(fCodec->fColorTable.get()) ; | 621 SkSwizzler::Fill(dst, this->dstInfo().makeWH(this->dstInfo().width() , count), rowBytes, |
639 SkSwizzler::Fill(dst, this->dstInfo(), rowBytes, count, fCodec->fFil lIndex, | 622 fCodec->onGetFillValue(dstInfo()), this->options().fZeroInit ialized); |
640 colorPtr, this->options().fZeroInitialized); | |
641 | 623 |
642 // Do nothing for rows before the image frame | 624 // Do nothing for rows before the image frame |
643 int rowsBeforeFrame = fCodec->fFrameDims.top() - INHERITED::getY(); | 625 int rowsBeforeFrame = fCodec->fFrameDims.top() - INHERITED::getY(); |
644 if (rowsBeforeFrame > 0) { | 626 if (rowsBeforeFrame > 0) { |
645 count = SkTMin(0, count - rowsBeforeFrame); | 627 count = SkTMin(0, count - rowsBeforeFrame); |
646 dst = SkTAddOffset<void>(dst, rowBytes * rowsBeforeFrame); | 628 dst = SkTAddOffset<void>(dst, rowBytes * rowsBeforeFrame); |
647 } | 629 } |
648 | 630 |
649 // Do nothing for rows after the image frame | 631 // Do nothing for rows after the image frame |
650 int rowsAfterFrame = INHERITED::getY() + count - fCodec->fFrameDims. bottom(); | 632 int rowsAfterFrame = INHERITED::getY() + count - fCodec->fFrameDims. bottom(); |
651 if (rowsAfterFrame > 0) { | 633 if (rowsAfterFrame > 0) { |
652 count = SkTMin(0, count - rowsAfterFrame); | 634 count = SkTMin(0, count - rowsAfterFrame); |
653 } | 635 } |
654 | 636 |
655 // Adjust dst pointer for left offset | 637 // Adjust dst pointer for left offset |
656 dst = SkTAddOffset<void>(dst, SkColorTypeBytesPerPixel( | 638 dst = SkTAddOffset<void>(dst, SkColorTypeBytesPerPixel( |
657 this->dstInfo().colorType()) * fCodec->fFrameDims.left()); | 639 this->dstInfo().colorType()) * fCodec->fFrameDims.left()); |
658 } | 640 } |
659 | 641 |
642 void* dstRow = dst; | |
660 for (int i = 0; i < count; i++) { | 643 for (int i = 0; i < count; i++) { |
661 if (SkCodec::kSuccess != fCodec->readRow()) { | 644 if (!fCodec->readRow()) { |
662 const SkPMColor* colorPtr = get_color_ptr(fCodec->fColorTable.ge t()); | 645 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 } | 646 } |
668 fCodec->fSwizzler->swizzle(dst, fCodec->fSrcBuffer.get()); | 647 fCodec->fSwizzler->swizzle(dstRow, fCodec->fSrcBuffer.get()); |
669 dst = SkTAddOffset<void>(dst, rowBytes); | 648 dstRow = SkTAddOffset<void>(dstRow, rowBytes); |
670 } | 649 } |
671 return SkCodec::kSuccess; | 650 return count; |
672 } | 651 } |
673 | 652 |
674 SkScanlineOrder onGetScanlineOrder() const override { | 653 SkScanlineOrder onGetScanlineOrder() const override { |
675 if (fCodec->fGif->Image.Interlace) { | 654 if (fCodec->fGif->Image.Interlace) { |
676 return kOutOfOrder_SkScanlineOrder; | 655 return kOutOfOrder_SkScanlineOrder; |
677 } else { | 656 } else { |
678 return kTopDown_SkScanlineOrder; | 657 return kTopDown_SkScanlineOrder; |
679 } | 658 } |
680 } | 659 } |
681 | 660 |
682 int onGetY() const override { | |
683 if (fCodec->fGif->Image.Interlace) { | |
684 return get_output_row_interlaced(INHERITED::onGetY(), this->dstInfo( ).height()); | |
685 } else { | |
686 return INHERITED::onGetY(); | |
687 } | |
688 } | |
689 | |
690 private: | 661 private: |
691 SkAutoTDelete<SkGifCodec> fCodec; | 662 SkGifCodec* fCodec; // Owned by parent class |
692 | 663 |
693 typedef SkScanlineDecoder INHERITED; | 664 typedef SkScanlineDecoder INHERITED; |
694 }; | 665 }; |
695 | 666 |
696 SkScanlineDecoder* SkGifCodec::NewSDFromStream(SkStream* stream) { | 667 SkScanlineDecoder* SkGifCodec::NewSDFromStream(SkStream* stream) { |
697 SkAutoTDelete<SkGifCodec> codec (static_cast<SkGifCodec*>(SkGifCodec::NewFro mStream(stream))); | 668 SkAutoTDelete<SkGifCodec> codec (static_cast<SkGifCodec*>(SkGifCodec::NewFro mStream(stream))); |
698 if (!codec) { | 669 if (!codec) { |
699 return NULL; | 670 return NULL; |
700 } | 671 } |
701 | 672 |
702 const SkImageInfo& srcInfo = codec->getInfo(); | 673 return SkNEW_ARGS(SkGifScanlineDecoder, (codec.detach())); |
703 | |
704 return SkNEW_ARGS(SkGifScanlineDecoder, (srcInfo, codec.detach())); | |
705 } | 674 } |
OLD | NEW |