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

Side by Side Diff: src/codec/SkCodec_libgif.cpp

Issue 1332053002: Fill incomplete images in SkCodec parent class (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Response to comments 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_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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698