| 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 |