| 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 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 88 // There should only be one graphics control extension for the image
frame | 88 // There should only be one graphics control extension for the image
frame |
| 89 break; | 89 break; |
| 90 } | 90 } |
| 91 } | 91 } |
| 92 | 92 |
| 93 // Use maximum unsigned int (surely an invalid index) to indicate that a val
id | 93 // Use maximum unsigned int (surely an invalid index) to indicate that a val
id |
| 94 // index was not found. | 94 // index was not found. |
| 95 return SK_MaxU32; | 95 return SK_MaxU32; |
| 96 } | 96 } |
| 97 | 97 |
| 98 static inline uint32_t ceil_div(uint32_t a, uint32_t b) { | 98 inline uint32_t ceil_div(uint32_t a, uint32_t b) { |
| 99 return (a + b - 1) / b; | 99 return (a + b - 1) / b; |
| 100 } | 100 } |
| 101 | 101 |
| 102 /* | 102 /* |
| 103 * Gets the output row corresponding to the encoded row for interlaced gifs | 103 * Gets the output row corresponding to the encoded row for interlaced gifs |
| 104 */ | 104 */ |
| 105 static uint32_t get_output_row_interlaced(uint32_t encodedRow, uint32_t height)
{ | 105 inline uint32_t get_output_row_interlaced(uint32_t encodedRow, uint32_t height)
{ |
| 106 SkASSERT(encodedRow < height); | 106 SkASSERT(encodedRow < height); |
| 107 // First pass | 107 // First pass |
| 108 if (encodedRow * 8 < height) { | 108 if (encodedRow * 8 < height) { |
| 109 return encodedRow * 8; | 109 return encodedRow * 8; |
| 110 } | 110 } |
| 111 // Second pass | 111 // Second pass |
| 112 if (encodedRow * 4 < height) { | 112 if (encodedRow * 4 < height) { |
| 113 return 4 + 8 * (encodedRow - ceil_div(height, 8)); | 113 return 4 + 8 * (encodedRow - ceil_div(height, 8)); |
| 114 } | 114 } |
| 115 // Third pass | 115 // Third pass |
| (...skipping 337 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 453 ZeroInitialized zeroInit) { | 453 ZeroInitialized zeroInit) { |
| 454 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 454 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); |
| 455 fSwizzler.reset(SkSwizzler::CreateSwizzler(SkSwizzler::kIndex, | 455 fSwizzler.reset(SkSwizzler::CreateSwizzler(SkSwizzler::kIndex, |
| 456 colorPtr, dstInfo, zeroInit)); | 456 colorPtr, dstInfo, zeroInit)); |
| 457 if (nullptr != fSwizzler.get()) { | 457 if (nullptr != fSwizzler.get()) { |
| 458 return kSuccess; | 458 return kSuccess; |
| 459 } | 459 } |
| 460 return kUnimplemented; | 460 return kUnimplemented; |
| 461 } | 461 } |
| 462 | 462 |
| 463 SkCodec::Result SkGifCodec::readRow() { | 463 bool SkGifCodec::readRow() { |
| 464 if (GIF_ERROR == DGifGetLine(fGif, fSrcBuffer.get(), fFrameRect.width())) { | 464 return GIF_ERROR != DGifGetLine(fGif, fSrcBuffer.get(), fFrameRect.width()); |
| 465 return kIncompleteInput; | |
| 466 } | |
| 467 return kSuccess; | |
| 468 } | 465 } |
| 469 | 466 |
| 470 /* | 467 /* |
| 471 * Initiates the gif decode | 468 * Initiates the gif decode |
| 472 */ | 469 */ |
| 473 SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo, | 470 SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo, |
| 474 void* dst, size_t dstRowBytes, | 471 void* dst, size_t dstRowBytes, |
| 475 const Options& opts, | 472 const Options& opts, |
| 476 SkPMColor* inputColorPtr, | 473 SkPMColor* inputColorPtr, |
| 477 int* inputColorCount) { | 474 int* inputColorCount, |
| 475 int* rowsDecoded) { |
| 478 Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCoun
t, opts); | 476 Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCoun
t, opts); |
| 479 if (kSuccess != result) { | 477 if (kSuccess != result) { |
| 480 return result; | 478 return result; |
| 481 } | 479 } |
| 482 | 480 |
| 483 if (dstInfo.dimensions() != this->getInfo().dimensions()) { | 481 if (dstInfo.dimensions() != this->getInfo().dimensions()) { |
| 484 return gif_error("Scaling not supported.\n", kInvalidScale); | 482 return gif_error("Scaling not supported.\n", kInvalidScale); |
| 485 } | 483 } |
| 486 | 484 |
| 487 // Initialize the swizzler | 485 // Initialize the swizzler |
| 488 if (fFrameIsSubset) { | 486 if (fFrameIsSubset) { |
| 489 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameRect.width(), fFr
ameRect.height()); | 487 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameRect.width(), fFr
ameRect.height()); |
| 490 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia
lized)) { | 488 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia
lized)) { |
| 491 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; | 489 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; |
| 492 } | 490 } |
| 493 | 491 |
| 494 // Fill the background | 492 // Fill the background |
| 495 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 493 SkSampler::Fill(dstInfo, dst, dstRowBytes, |
| 496 SkSwizzler::Fill(dst, dstInfo, dstRowBytes, this->getInfo().height(), | 494 this->getFillValue(dstInfo.colorType(), dstInfo.alphaType()), |
| 497 fFillIndex, colorPtr, opts.fZeroInitialized); | 495 opts.fZeroInitialized); |
| 498 | 496 |
| 499 // Modify the dst pointer | 497 // Modify the dst pointer |
| 500 const int32_t dstBytesPerPixel = SkColorTypeBytesPerPixel(dstInfo.colorT
ype()); | 498 const int32_t dstBytesPerPixel = SkColorTypeBytesPerPixel(dstInfo.colorT
ype()); |
| 501 dst = SkTAddOffset<void*>(dst, dstRowBytes * fFrameRect.top() + | 499 dst = SkTAddOffset<void*>(dst, dstRowBytes * fFrameRect.top() + |
| 502 dstBytesPerPixel * fFrameRect.left()); | 500 dstBytesPerPixel * fFrameRect.left()); |
| 503 } else { | 501 } else { |
| 504 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized)
) { | 502 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized)
) { |
| 505 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; | 503 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; |
| 506 } | 504 } |
| 507 } | 505 } |
| 508 | 506 |
| 509 // Check the interlace flag and iterate over rows of the input | 507 // Iterate over rows of the input |
| 510 uint32_t width = fFrameRect.width(); | |
| 511 uint32_t height = fFrameRect.height(); | 508 uint32_t height = fFrameRect.height(); |
| 512 if (fGif->Image.Interlace) { | 509 for (uint32_t y = 0; y < height; y++) { |
| 513 // In interlace mode, the rows of input are rearranged in | 510 if (!this->readRow()) { |
| 514 // the output image. We a helper function to help us | 511 *rowsDecoded = y; |
| 515 // rearrange the decoded rows. | 512 return gif_error("Could not decode line.\n", kIncompleteInput); |
| 516 for (uint32_t y = 0; y < height; y++) { | |
| 517 if (kSuccess != this->readRow()) { | |
| 518 // Recover from error by filling remainder of image | |
| 519 memset(fSrcBuffer.get(), fFillIndex, width); | |
| 520 for (; y < height; y++) { | |
| 521 void* dstRow = SkTAddOffset<void>(dst, | |
| 522 dstRowBytes * get_output_row_interlaced(y, height)); | |
| 523 fSwizzler->swizzle(dstRow, fSrcBuffer.get()); | |
| 524 } | |
| 525 return gif_error("Could not decode line.\n", kIncompleteInput); | |
| 526 } | |
| 527 void* dstRow = SkTAddOffset<void>(dst, | |
| 528 dstRowBytes * get_output_row_interlaced(y, height)); | |
| 529 fSwizzler->swizzle(dstRow, fSrcBuffer.get()); | |
| 530 } | 513 } |
| 531 } else { | 514 void* dstRow = SkTAddOffset<void>(dst, dstRowBytes * this->outputScanlin
e(y)); |
| 532 // Standard mode | 515 fSwizzler->swizzle(dstRow, fSrcBuffer.get()); |
| 533 void* dstRow = dst; | |
| 534 for (uint32_t y = 0; y < height; y++) { | |
| 535 if (kSuccess != this->readRow()) { | |
| 536 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | |
| 537 SkSwizzler::Fill(dstRow, dstInfo, dstRowBytes, | |
| 538 height - y, fFillIndex, colorPtr, opts.fZeroInitialized)
; | |
| 539 return gif_error("Could not decode line\n", kIncompleteInput); | |
| 540 } | |
| 541 fSwizzler->swizzle(dstRow, fSrcBuffer.get()); | |
| 542 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); | |
| 543 } | |
| 544 } | 516 } |
| 545 return kSuccess; | 517 return kSuccess; |
| 546 } | 518 } |
| 547 | 519 |
| 520 // FIXME: This is similar to the implementation for bmp and png. Can we share m
ore code or |
| 521 // possibly make this non-virtual? |
| 522 uint32_t SkGifCodec::onGetFillValue(SkColorType colorType, SkAlphaType alphaType
) const { |
| 523 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); |
| 524 return get_color_table_fill_value(colorType, colorPtr, fFillIndex); |
| 525 } |
| 526 |
| 548 SkCodec::Result SkGifCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, | 527 SkCodec::Result SkGifCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, |
| 549 const SkCodec::Options& opts, SkPMColor inputColorPtr[], int* inputColor
Count) { | 528 const SkCodec::Options& opts, SkPMColor inputColorPtr[], int* inputColor
Count) { |
| 550 Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCoun
t, | 529 |
| 551 this->options()); | 530 Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCoun
t, this->options()); |
| 552 if (kSuccess != result) { | 531 if (kSuccess != result) { |
| 553 return result; | 532 return result; |
| 554 } | 533 } |
| 555 | 534 |
| 556 // Initialize the swizzler | 535 // Initialize the swizzler |
| 557 if (fFrameIsSubset) { | 536 if (fFrameIsSubset) { |
| 558 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameRect.width(), fFr
ameRect.height()); | 537 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameRect.width(), fFr
ameRect.height()); |
| 559 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia
lized)) { | 538 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia
lized)) { |
| 560 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; | 539 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; |
| 561 } | 540 } |
| 562 } else { | 541 } else { |
| 563 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized)
) { | 542 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized)
) { |
| 564 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; | 543 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; |
| 565 } | 544 } |
| 566 } | 545 } |
| 567 | 546 |
| 568 return kSuccess; | 547 return kSuccess; |
| 569 } | 548 } |
| 570 | 549 |
| 571 SkCodec::Result SkGifCodec::onGetScanlines(void* dst, int count, size_t rowBytes
) { | 550 int SkGifCodec::onGetScanlines(void* dst, int count, size_t rowBytes) { |
| 551 int rowsBeforeFrame = 0; |
| 552 int rowsAfterFrame = 0; |
| 553 int rowsInFrame = count; |
| 572 if (fFrameIsSubset) { | 554 if (fFrameIsSubset) { |
| 573 // Fill the requested rows | 555 // Fill the requested rows |
| 574 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 556 SkImageInfo fillInfo = this->dstInfo().makeWH(this->dstInfo().width(), c
ount); |
| 575 SkSwizzler::Fill(dst, this->dstInfo(), rowBytes, count, fFillIndex, | 557 uint32_t fillValue = this->onGetFillValue(this->dstInfo().colorType(), |
| 576 colorPtr, this->options().fZeroInitialized); | 558 this->dstInfo().alphaType()); |
| 559 SkSampler::Fill(fillInfo, dst, rowBytes, fillValue, this->options().fZer
oInitialized); |
| 577 | 560 |
| 578 // Do nothing for rows before the image frame | 561 // Do nothing for rows before the image frame |
| 579 int rowsBeforeFrame = SkTMax(0, fFrameRect.top() - this->INHERITED::onNe
xtScanline()); | 562 rowsBeforeFrame = SkTMax(0, fFrameRect.top() - this->INHERITED::nextScan
line()); |
| 580 count = SkTMax(0, count - rowsBeforeFrame); | 563 rowsInFrame = SkTMax(0, rowsInFrame - rowsBeforeFrame); |
| 581 dst = SkTAddOffset<void>(dst, rowBytes * rowsBeforeFrame); | 564 dst = SkTAddOffset<void>(dst, rowBytes * rowsBeforeFrame); |
| 582 | 565 |
| 583 // Do nothing for rows after the image frame | 566 // Do nothing for rows after the image frame |
| 584 int rowsAfterFrame = SkTMax(0, | 567 rowsAfterFrame = SkTMax(0, |
| 585 this->INHERITED::onNextScanline() + count - fFrameRect.bottom())
; | 568 this->INHERITED::nextScanline() + rowsInFrame - fFrameRect.botto
m()); |
| 586 count = SkTMax(0, count - rowsAfterFrame); | 569 rowsInFrame = SkTMax(0, rowsInFrame - rowsAfterFrame); |
| 587 | 570 |
| 588 // Adjust dst pointer for left offset | 571 // Adjust dst pointer for left offset |
| 589 int offset = SkColorTypeBytesPerPixel(this->dstInfo().colorType()) * fFr
ameRect.left(); | 572 int offset = SkColorTypeBytesPerPixel(this->dstInfo().colorType()) * fFr
ameRect.left(); |
| 590 dst = SkTAddOffset<void>(dst, offset); | 573 dst = SkTAddOffset<void>(dst, offset); |
| 591 } | 574 } |
| 592 | 575 |
| 593 for (int i = 0; i < count; i++) { | 576 for (int i = 0; i < rowsInFrame; i++) { |
| 594 if (kSuccess != this->readRow()) { | 577 if (!this->readRow()) { |
| 595 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 578 return i + rowsBeforeFrame; |
| 596 SkSwizzler::Fill(dst, this->dstInfo().makeWH(fFrameRect.width(), | |
| 597 this->dstInfo().height()), rowBytes, count - i, fFillIndex,
colorPtr, | |
| 598 this->options().fZeroInitialized); | |
| 599 return kIncompleteInput; | |
| 600 } | 579 } |
| 601 fSwizzler->swizzle(dst, fSrcBuffer.get()); | 580 fSwizzler->swizzle(dst, fSrcBuffer.get()); |
| 602 dst = SkTAddOffset<void>(dst, rowBytes); | 581 dst = SkTAddOffset<void>(dst, rowBytes); |
| 603 } | 582 } |
| 604 return kSuccess; | 583 |
| 584 return count; |
| 605 } | 585 } |
| 606 | 586 |
| 607 SkCodec::SkScanlineOrder SkGifCodec::onGetScanlineOrder() const { | 587 SkCodec::SkScanlineOrder SkGifCodec::onGetScanlineOrder() const { |
| 608 if (fGif->Image.Interlace) { | 588 if (fGif->Image.Interlace) { |
| 609 return kOutOfOrder_SkScanlineOrder; | 589 return kOutOfOrder_SkScanlineOrder; |
| 610 } else { | |
| 611 return kTopDown_SkScanlineOrder; | |
| 612 } | 590 } |
| 591 return kTopDown_SkScanlineOrder; |
| 613 } | 592 } |
| 614 | 593 |
| 615 int SkGifCodec::onNextScanline() const { | 594 int SkGifCodec::onOutputScanline(int inputScanline) const { |
| 616 int nextScanline = this->INHERITED::onNextScanline(); | |
| 617 if (fGif->Image.Interlace) { | 595 if (fGif->Image.Interlace) { |
| 618 if (nextScanline < fFrameRect.top() || nextScanline >= fFrameRect.bottom
()) { | 596 if (inputScanline < fFrameRect.top() || inputScanline >= fFrameRect.bott
om()) { |
| 619 return nextScanline; | 597 return inputScanline; |
| 620 } | 598 } |
| 621 return get_output_row_interlaced(nextScanline - fFrameRect.top(), fFrame
Rect.height()); | 599 return get_output_row_interlaced(inputScanline - fFrameRect.top(), fFram
eRect.height()); |
| 622 } | 600 } |
| 623 return nextScanline; | 601 return inputScanline; |
| 624 } | 602 } |
| 625 | |
| OLD | NEW |