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 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
485 ZeroInitialized zeroInit) { | 460 ZeroInitialized zeroInit) { |
486 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 461 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); |
487 fSwizzler.reset(SkSwizzler::CreateSwizzler(SkSwizzler::kIndex, | 462 fSwizzler.reset(SkSwizzler::CreateSwizzler(SkSwizzler::kIndex, |
488 colorPtr, dstInfo, zeroInit, this->getInfo())); | 463 colorPtr, dstInfo, zeroInit, this->getInfo())); |
489 if (nullptr != fSwizzler.get()) { | 464 if (nullptr != fSwizzler.get()) { |
490 return kSuccess; | 465 return kSuccess; |
491 } | 466 } |
492 return kUnimplemented; | 467 return kUnimplemented; |
493 } | 468 } |
494 | 469 |
495 SkCodec::Result SkGifCodec::readRow() { | 470 bool SkGifCodec::readRow() { |
496 if (GIF_ERROR == DGifGetLine(fGif, fSrcBuffer.get(), fFrameDims.width())) { | 471 return GIF_ERROR != DGifGetLine(fGif, fSrcBuffer.get(), fFrameDims.width()); |
497 return kIncompleteInput; | |
498 } | |
499 return kSuccess; | |
500 } | 472 } |
501 | 473 |
502 /* | 474 /* |
503 * Initiates the gif decode | 475 * Initiates the gif decode |
504 */ | 476 */ |
505 SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo, | 477 SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo, |
506 void* dst, size_t dstRowBytes, | 478 void* dst, size_t dstRowBytes, |
507 const Options& opts, | 479 const Options& opts, |
508 SkPMColor* inputColorPtr, | 480 SkPMColor* inputColorPtr, |
509 int* inputColorCount) { | 481 int* inputColorCount, |
| 482 int* rowsDecoded) { |
510 Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCoun
t, opts); | 483 Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCoun
t, opts); |
511 if (kSuccess != result) { | 484 if (kSuccess != result) { |
512 return result; | 485 return result; |
513 } | 486 } |
514 | 487 |
515 if (dstInfo.dimensions() != this->getInfo().dimensions()) { | 488 if (dstInfo.dimensions() != this->getInfo().dimensions()) { |
516 return gif_error("Scaling not supported.\n", kInvalidScale); | 489 return gif_error("Scaling not supported.\n", kInvalidScale); |
517 } | 490 } |
518 | 491 |
519 // Initialize the swizzler | 492 // Initialize the swizzler |
520 if (fFrameIsSubset) { | 493 if (fFrameIsSubset) { |
521 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameDims.width(), fFr
ameDims.height()); | 494 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameDims.width(), fFr
ameDims.height()); |
522 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia
lized)) { | 495 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia
lized)) { |
523 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; | 496 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; |
524 } | 497 } |
525 | 498 |
526 // Fill the background | 499 // Fill the background |
527 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 500 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); |
528 SkSwizzler::Fill(dst, dstInfo, dstRowBytes, this->getInfo().height(), | 501 SkSwizzler::Fill(dst, dstInfo, dstRowBytes, this->getFillValue(dstInfo.c
olorType(), |
529 fFillIndex, colorPtr, opts.fZeroInitialized); | 502 dstInfo.alphaType()), opts.fZeroInitialized); |
530 | 503 |
531 // Modify the dst pointer | 504 // Modify the dst pointer |
532 const int32_t dstBytesPerPixel = SkColorTypeBytesPerPixel(dstInfo.colorT
ype()); | 505 const int32_t dstBytesPerPixel = SkColorTypeBytesPerPixel(dstInfo.colorT
ype()); |
533 dst = SkTAddOffset<void*>(dst, dstRowBytes * fFrameDims.top() + | 506 dst = SkTAddOffset<void*>(dst, dstRowBytes * fFrameDims.top() + |
534 dstBytesPerPixel * fFrameDims.left()); | 507 dstBytesPerPixel * fFrameDims.left()); |
535 } else { | 508 } else { |
536 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized)
) { | 509 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized)
) { |
537 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; | 510 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; |
538 } | 511 } |
539 } | 512 } |
540 | 513 |
541 // Check the interlace flag and iterate over rows of the input | 514 // Iterate over rows of the input |
542 uint32_t width = fFrameDims.width(); | 515 uint32_t width = fFrameDims.width(); |
543 uint32_t height = fFrameDims.height(); | 516 uint32_t height = fFrameDims.height(); |
544 if (fGif->Image.Interlace) { | 517 for (uint32_t y = 0; y < height; y++) { |
545 // In interlace mode, the rows of input are rearranged in | 518 if (!this->readRow()) { |
546 // the output image. We a helper function to help us | 519 *rowsDecoded = y; |
547 // rearrange the decoded rows. | 520 return gif_error("Could not decode line.\n", kIncompleteInput); |
548 for (uint32_t y = 0; y < height; y++) { | |
549 if (kSuccess != this->readRow()) { | |
550 // Recover from error by filling remainder of image | |
551 memset(fSrcBuffer.get(), fFillIndex, width); | |
552 for (; y < height; y++) { | |
553 void* dstRow = SkTAddOffset<void>(dst, | |
554 dstRowBytes * get_output_row_interlaced(y, height)); | |
555 fSwizzler->swizzle(dstRow, fSrcBuffer.get()); | |
556 } | |
557 return gif_error("Could not decode line.\n", kIncompleteInput); | |
558 } | |
559 void* dstRow = SkTAddOffset<void>(dst, | |
560 dstRowBytes * get_output_row_interlaced(y, height)); | |
561 fSwizzler->swizzle(dstRow, fSrcBuffer.get()); | |
562 } | 521 } |
563 } else { | 522 void* dstRow = SkTAddOffset<void>(dst, dstRowBytes * this->nextScanline(
y)); |
564 // Standard mode | 523 fSwizzler->swizzle(dstRow, fSrcBuffer.get()); |
565 void* dstRow = dst; | |
566 for (uint32_t y = 0; y < height; y++) { | |
567 if (kSuccess != this->readRow()) { | |
568 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | |
569 SkSwizzler::Fill(dstRow, dstInfo, dstRowBytes, | |
570 height - y, fFillIndex, colorPtr, opts.fZeroInitialized)
; | |
571 return gif_error("Could not decode line\n", kIncompleteInput); | |
572 } | |
573 fSwizzler->swizzle(dstRow, fSrcBuffer.get()); | |
574 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); | |
575 } | |
576 } | 524 } |
577 return kSuccess; | 525 return kSuccess; |
578 } | 526 } |
579 | 527 |
| 528 uint32_t SkGifCodec::onGetFillValue(SkColorType colorType, SkAlphaType alphaType
) const { |
| 529 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); |
| 530 return get_color_table_fill_value(colorType, colorPtr, fFillIndex); |
| 531 } |
| 532 |
580 SkCodec::Result SkGifCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, | 533 SkCodec::Result SkGifCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, |
581 const SkCodec::Options& opts, SkPMColor inputColorPtr[], int* inputColor
Count) { | 534 const SkCodec::Options& opts, SkPMColor inputColorPtr[], int* inputColor
Count) { |
582 Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCoun
t, | 535 |
583 this->options()); | 536 Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCoun
t, this->options()); |
584 if (kSuccess != result) { | 537 if (kSuccess != result) { |
585 return result; | 538 return result; |
586 } | 539 } |
587 | 540 |
588 // Check to see if scaling was requested. | 541 // Check to see if scaling was requested. |
589 if (dstInfo.dimensions() != this->getInfo().dimensions()) { | 542 if (dstInfo.dimensions() != this->getInfo().dimensions()) { |
590 if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstI
nfo)) { | 543 if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstI
nfo)) { |
591 return gif_error("Scaling not supported.\n", SkCodec::kInvalidScale)
; | 544 return gif_error("Scaling not supported.\n", SkCodec::kInvalidScale)
; |
592 } | 545 } |
593 } | 546 } |
(...skipping 10 matching lines...) Expand all Loading... |
604 } | 557 } |
605 } else { | 558 } else { |
606 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized)
) { | 559 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized)
) { |
607 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; | 560 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; |
608 } | 561 } |
609 } | 562 } |
610 | 563 |
611 return kSuccess; | 564 return kSuccess; |
612 } | 565 } |
613 | 566 |
614 SkCodec::Result SkGifCodec::onGetScanlines(void* dst, int count, size_t rowBytes
) { | 567 uint32_t SkGifCodec::onGetScanlines(void* dst, int count, size_t rowBytes) { |
| 568 int rowsBeforeFrame = 0; |
| 569 int rowsAfterFrame = 0; |
615 if (fFrameIsSubset) { | 570 if (fFrameIsSubset) { |
616 // Fill the requested rows | 571 // Fill the requested rows |
617 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 572 SkSwizzler::Fill(dst, this->dstInfo().makeWH(this->dstInfo().width(), co
unt), rowBytes, |
618 SkSwizzler::Fill(dst, this->dstInfo(), rowBytes, count, fFillIndex, | 573 this->onGetFillValue(this->dstInfo().colorType(), this->dstInfo(
).alphaType()), |
619 colorPtr, this->options().fZeroInitialized); | 574 this->options().fZeroInitialized); |
620 | 575 |
621 // Do nothing for rows before the image frame | 576 // Do nothing for rows before the image frame |
622 // FIXME: nextScanline is not virtual, so using "INHERITED" does not cha
nge | 577 // FIXME: Do we handle fFrameIsSubset properly for interlaced images? |
623 // behavior. Was the intent to call this->INHERITED::onNextScanline()? S
ame | 578 rowsBeforeFrame = SkTMax(0, fFrameDims.top() - this->nextScanline()); |
624 // for the next call down below. | 579 count = SkTMax(0, count - rowsBeforeFrame); |
625 int rowsBeforeFrame = fFrameDims.top() - this->INHERITED::nextScanline()
; | 580 dst = SkTAddOffset<void>(dst, rowBytes * rowsBeforeFrame); |
626 if (rowsBeforeFrame > 0) { | |
627 count = SkTMin(0, count - rowsBeforeFrame); | |
628 dst = SkTAddOffset<void>(dst, rowBytes * rowsBeforeFrame); | |
629 } | |
630 | 581 |
631 // Do nothing for rows after the image frame | 582 // Do nothing for rows after the image frame |
632 int rowsAfterFrame = this->INHERITED::nextScanline() + count - fFrameDim
s.bottom(); | 583 rowsAfterFrame = SkTMax(0, this->nextScanline() + count - fFrameDims.bot
tom()); |
633 if (rowsAfterFrame > 0) { | 584 count = SkTMax(0, count - rowsAfterFrame); |
634 count = SkTMin(0, count - rowsAfterFrame); | |
635 } | |
636 | 585 |
637 // Adjust dst pointer for left offset | 586 // Adjust dst pointer for left offset |
638 int bpp = SkColorTypeBytesPerPixel(this->dstInfo().colorType()) * fFrame
Dims.left(); | 587 int bpp = SkColorTypeBytesPerPixel(this->dstInfo().colorType()) * fFrame
Dims.left(); |
639 dst = SkTAddOffset<void>(dst, bpp); | 588 dst = SkTAddOffset<void>(dst, bpp); |
640 } | 589 } |
641 | 590 |
642 for (int i = 0; i < count; i++) { | 591 for (int i = 0; i < count; i++) { |
643 if (kSuccess != this->readRow()) { | 592 if (!this->readRow()) { |
644 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 593 return i + rowsBeforeFrame; |
645 SkSwizzler::Fill(dst, this->dstInfo(), rowBytes, count - i, fFillInd
ex, colorPtr, | |
646 this->options().fZeroInitialized); | |
647 return gif_error("Could not decode line\n", SkCodec::kIncompleteInpu
t); | |
648 } | 594 } |
649 fSwizzler->swizzle(dst, fSrcBuffer.get()); | 595 fSwizzler->swizzle(dst, fSrcBuffer.get()); |
650 dst = SkTAddOffset<void>(dst, rowBytes); | 596 dst = SkTAddOffset<void>(dst, rowBytes); |
651 } | 597 } |
652 return SkCodec::kSuccess; | 598 return count + rowsBeforeFrame + rowsAfterFrame; |
653 } | 599 } |
654 | 600 |
655 SkCodec::SkScanlineOrder SkGifCodec::onGetScanlineOrder() const { | 601 SkCodec::SkScanlineOrder SkGifCodec::onGetScanlineOrder() const { |
656 if (fGif->Image.Interlace) { | 602 if (fGif->Image.Interlace) { |
657 return kOutOfOrder_SkScanlineOrder; | 603 return kOutOfOrder_SkScanlineOrder; |
658 } else { | |
659 return kTopDown_SkScanlineOrder; | |
660 } | 604 } |
| 605 return kTopDown_SkScanlineOrder; |
661 } | 606 } |
662 | |
663 int SkGifCodec::onNextScanline() const { | |
664 if (fGif->Image.Interlace) { | |
665 return get_output_row_interlaced(this->INHERITED::onNextScanline(), this
->dstInfo().height()); | |
666 } else { | |
667 return this->INHERITED::onNextScanline(); | |
668 } | |
669 } | |
670 | |
OLD | NEW |