| 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) { | |
| 99 return (a + b - 1) / b; | |
| 100 } | |
| 101 | |
| 102 /* | |
| 103 * Gets the output row corresponding to the encoded row for interlaced gifs | |
| 104 */ | |
| 105 static uint32_t get_output_row_interlaced(uint32_t encodedRow, uint32_t height)
{ | |
| 106 SkASSERT(encodedRow < height); | |
| 107 // First pass | |
| 108 if (encodedRow * 8 < height) { | |
| 109 return encodedRow * 8; | |
| 110 } | |
| 111 // Second pass | |
| 112 if (encodedRow * 4 < height) { | |
| 113 return 4 + 8 * (encodedRow - ceil_div(height, 8)); | |
| 114 } | |
| 115 // Third pass | |
| 116 if (encodedRow * 2 < height) { | |
| 117 return 2 + 4 * (encodedRow - ceil_div(height, 4)); | |
| 118 } | |
| 119 // Fourth pass | |
| 120 return 1 + 2 * (encodedRow - ceil_div(height, 2)); | |
| 121 } | |
| 122 | |
| 123 /* | 98 /* |
| 124 * This function cleans up the gif object after the decode completes | 99 * This function cleans up the gif object after the decode completes |
| 125 * It is used in a SkAutoTCallIProc template | 100 * It is used in a SkAutoTCallIProc template |
| 126 */ | 101 */ |
| 127 void SkGifCodec::CloseGif(GifFileType* gif) { | 102 void SkGifCodec::CloseGif(GifFileType* gif) { |
| 128 DGifCloseFile(gif, NULL); | 103 DGifCloseFile(gif, NULL); |
| 129 } | 104 } |
| 130 | 105 |
| 131 /* | 106 /* |
| 132 * This function free extension data that has been saved to assist the image | 107 * This function free extension data that has been saved to assist the image |
| (...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 453 ZeroInitialized zeroInit) { | 428 ZeroInitialized zeroInit) { |
| 454 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 429 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); |
| 455 fSwizzler.reset(SkSwizzler::CreateSwizzler(SkSwizzler::kIndex, | 430 fSwizzler.reset(SkSwizzler::CreateSwizzler(SkSwizzler::kIndex, |
| 456 colorPtr, dstInfo, zeroInit)); | 431 colorPtr, dstInfo, zeroInit)); |
| 457 if (nullptr != fSwizzler.get()) { | 432 if (nullptr != fSwizzler.get()) { |
| 458 return kSuccess; | 433 return kSuccess; |
| 459 } | 434 } |
| 460 return kUnimplemented; | 435 return kUnimplemented; |
| 461 } | 436 } |
| 462 | 437 |
| 463 SkCodec::Result SkGifCodec::readRow() { | 438 bool SkGifCodec::readRow() { |
| 464 if (GIF_ERROR == DGifGetLine(fGif, fSrcBuffer.get(), fFrameRect.width())) { | 439 return GIF_ERROR != DGifGetLine(fGif, fSrcBuffer.get(), fFrameRect.width()); |
| 465 return kIncompleteInput; | |
| 466 } | |
| 467 return kSuccess; | |
| 468 } | 440 } |
| 469 | 441 |
| 470 /* | 442 /* |
| 471 * Initiates the gif decode | 443 * Initiates the gif decode |
| 472 */ | 444 */ |
| 473 SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo, | 445 SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo, |
| 474 void* dst, size_t dstRowBytes, | 446 void* dst, size_t dstRowBytes, |
| 475 const Options& opts, | 447 const Options& opts, |
| 476 SkPMColor* inputColorPtr, | 448 SkPMColor* inputColorPtr, |
| 477 int* inputColorCount) { | 449 int* inputColorCount, |
| 450 int* rowsDecoded) { |
| 478 Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCoun
t, opts); | 451 Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCoun
t, opts); |
| 479 if (kSuccess != result) { | 452 if (kSuccess != result) { |
| 480 return result; | 453 return result; |
| 481 } | 454 } |
| 482 | 455 |
| 483 if (dstInfo.dimensions() != this->getInfo().dimensions()) { | 456 if (dstInfo.dimensions() != this->getInfo().dimensions()) { |
| 484 return gif_error("Scaling not supported.\n", kInvalidScale); | 457 return gif_error("Scaling not supported.\n", kInvalidScale); |
| 485 } | 458 } |
| 486 | 459 |
| 487 // Initialize the swizzler | 460 // Initialize the swizzler |
| 488 if (fFrameIsSubset) { | 461 if (fFrameIsSubset) { |
| 489 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameRect.width(), fFr
ameRect.height()); | 462 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameRect.width(), fFr
ameRect.height()); |
| 490 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia
lized)) { | 463 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia
lized)) { |
| 491 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; | 464 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; |
| 492 } | 465 } |
| 493 | 466 |
| 494 // Fill the background | 467 // Fill the background |
| 495 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 468 SkSampler::Fill(dst, dstInfo.colorType(), dstInfo.width(), dstInfo.heigh
t(), dstRowBytes, |
| 496 SkSwizzler::Fill(dst, dstInfo, dstRowBytes, this->getInfo().height(), | 469 this->getFillValue(dstInfo.colorType(), dstInfo.alphaType()), |
| 497 fFillIndex, colorPtr, opts.fZeroInitialized); | 470 opts.fZeroInitialized); |
| 498 | 471 |
| 499 // Modify the dst pointer | 472 // Modify the dst pointer |
| 500 const int32_t dstBytesPerPixel = SkColorTypeBytesPerPixel(dstInfo.colorT
ype()); | 473 const int32_t dstBytesPerPixel = SkColorTypeBytesPerPixel(dstInfo.colorT
ype()); |
| 501 dst = SkTAddOffset<void*>(dst, dstRowBytes * fFrameRect.top() + | 474 dst = SkTAddOffset<void*>(dst, dstRowBytes * fFrameRect.top() + |
| 502 dstBytesPerPixel * fFrameRect.left()); | 475 dstBytesPerPixel * fFrameRect.left()); |
| 503 } else { | 476 } else { |
| 504 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized)
) { | 477 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized)
) { |
| 505 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; | 478 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; |
| 506 } | 479 } |
| 507 } | 480 } |
| 508 | 481 |
| 509 // Check the interlace flag and iterate over rows of the input | 482 // Iterate over rows of the input |
| 510 uint32_t width = fFrameRect.width(); | 483 uint32_t width = fFrameRect.width(); |
| 511 uint32_t height = fFrameRect.height(); | 484 uint32_t height = fFrameRect.height(); |
| 512 if (fGif->Image.Interlace) { | 485 for (uint32_t y = 0; y < height; y++) { |
| 513 // In interlace mode, the rows of input are rearranged in | 486 if (!this->readRow()) { |
| 514 // the output image. We a helper function to help us | 487 *rowsDecoded = y; |
| 515 // rearrange the decoded rows. | 488 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 } | 489 } |
| 531 } else { | 490 void* dstRow = SkTAddOffset<void>(dst, dstRowBytes * this->outputScanlin
e(y)); |
| 532 // Standard mode | 491 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 } | 492 } |
| 545 return kSuccess; | 493 return kSuccess; |
| 546 } | 494 } |
| 547 | 495 |
| 496 uint32_t SkGifCodec::onGetFillValue(SkColorType colorType, SkAlphaType alphaType
) const { |
| 497 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); |
| 498 return get_color_table_fill_value(colorType, colorPtr, fFillIndex); |
| 499 } |
| 500 |
| 548 SkCodec::Result SkGifCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, | 501 SkCodec::Result SkGifCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, |
| 549 const SkCodec::Options& opts, SkPMColor inputColorPtr[], int* inputColor
Count) { | 502 const SkCodec::Options& opts, SkPMColor inputColorPtr[], int* inputColor
Count) { |
| 550 Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCoun
t, | 503 |
| 551 this->options()); | 504 Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCoun
t, this->options()); |
| 552 if (kSuccess != result) { | 505 if (kSuccess != result) { |
| 553 return result; | 506 return result; |
| 554 } | 507 } |
| 555 | 508 |
| 556 // Initialize the swizzler | 509 // Initialize the swizzler |
| 557 if (fFrameIsSubset) { | 510 if (fFrameIsSubset) { |
| 558 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameRect.width(), fFr
ameRect.height()); | 511 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameRect.width(), fFr
ameRect.height()); |
| 559 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia
lized)) { | 512 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia
lized)) { |
| 560 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; | 513 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; |
| 561 } | 514 } |
| 562 } else { | 515 } else { |
| 563 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized)
) { | 516 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized)
) { |
| 564 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; | 517 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; |
| 565 } | 518 } |
| 566 } | 519 } |
| 567 | 520 |
| 568 return kSuccess; | 521 return kSuccess; |
| 569 } | 522 } |
| 570 | 523 |
| 571 SkCodec::Result SkGifCodec::onGetScanlines(void* dst, int count, size_t rowBytes
) { | 524 int SkGifCodec::onGetScanlines(void* dst, int count, size_t rowBytes) { |
| 525 int rowsBeforeFrame = 0; |
| 526 int rowsAfterFrame = 0; |
| 527 int rowsInFrame = count; |
| 572 if (fFrameIsSubset) { | 528 if (fFrameIsSubset) { |
| 573 // Fill the requested rows | 529 // Fill the requested rows |
| 574 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 530 SkSampler::Fill(dst, this->dstInfo().colorType(), this->dstInfo().width(
), count, rowBytes, |
| 575 SkSwizzler::Fill(dst, this->dstInfo(), rowBytes, count, fFillIndex, | 531 this->onGetFillValue(this->dstInfo().colorType(), this->dstInfo(
).alphaType()), |
| 576 colorPtr, this->options().fZeroInitialized); | 532 this->options().fZeroInitialized); |
| 577 | 533 |
| 578 // Do nothing for rows before the image frame | 534 // Do nothing for rows before the image frame |
| 579 int rowsBeforeFrame = SkTMax(0, fFrameRect.top() - this->INHERITED::onNe
xtScanline()); | 535 rowsBeforeFrame = SkTMax(0, fFrameRect.top() - this->INHERITED::nextScan
line()); |
| 580 count = SkTMax(0, count - rowsBeforeFrame); | 536 rowsInFrame = SkTMax(0, rowsInFrame - rowsBeforeFrame); |
| 581 dst = SkTAddOffset<void>(dst, rowBytes * rowsBeforeFrame); | 537 dst = SkTAddOffset<void>(dst, rowBytes * rowsBeforeFrame); |
| 582 | 538 |
| 583 // Do nothing for rows after the image frame | 539 // Do nothing for rows after the image frame |
| 584 int rowsAfterFrame = SkTMax(0, | 540 rowsAfterFrame = SkTMax(0, |
| 585 this->INHERITED::onNextScanline() + count - fFrameRect.bottom())
; | 541 this->INHERITED::nextScanline() + rowsInFrame - fFrameRect.botto
m()); |
| 586 count = SkTMax(0, count - rowsAfterFrame); | 542 rowsInFrame = SkTMax(0, rowsInFrame - rowsAfterFrame); |
| 587 | 543 |
| 588 // Adjust dst pointer for left offset | 544 // Adjust dst pointer for left offset |
| 589 int offset = SkColorTypeBytesPerPixel(this->dstInfo().colorType()) * fFr
ameRect.left(); | 545 int offset = SkColorTypeBytesPerPixel(this->dstInfo().colorType()) * fFr
ameRect.left(); |
| 590 dst = SkTAddOffset<void>(dst, offset); | 546 dst = SkTAddOffset<void>(dst, offset); |
| 591 } | 547 } |
| 592 | 548 |
| 593 for (int i = 0; i < count; i++) { | 549 for (int i = 0; i < rowsInFrame; i++) { |
| 594 if (kSuccess != this->readRow()) { | 550 if (!this->readRow()) { |
| 595 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 551 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 } | 552 } |
| 601 fSwizzler->swizzle(dst, fSrcBuffer.get()); | 553 fSwizzler->swizzle(dst, fSrcBuffer.get()); |
| 602 dst = SkTAddOffset<void>(dst, rowBytes); | 554 dst = SkTAddOffset<void>(dst, rowBytes); |
| 603 } | 555 } |
| 604 return kSuccess; | 556 |
| 557 return count; |
| 605 } | 558 } |
| 606 | 559 |
| 607 SkCodec::SkScanlineOrder SkGifCodec::onGetScanlineOrder() const { | 560 SkCodec::SkScanlineOrder SkGifCodec::onGetScanlineOrder() const { |
| 608 if (fGif->Image.Interlace) { | 561 if (fGif->Image.Interlace) { |
| 609 return kOutOfOrder_SkScanlineOrder; | 562 return kOutOfOrder_SkScanlineOrder; |
| 610 } else { | |
| 611 return kTopDown_SkScanlineOrder; | |
| 612 } | 563 } |
| 564 return kTopDown_SkScanlineOrder; |
| 613 } | 565 } |
| 614 | 566 |
| 615 int SkGifCodec::onNextScanline() const { | 567 int SkGifCodec::onOutputScanline(int inputScanline) const { |
| 616 int nextScanline = this->INHERITED::onNextScanline(); | |
| 617 if (fGif->Image.Interlace) { | 568 if (fGif->Image.Interlace) { |
| 618 if (nextScanline < fFrameRect.top() || nextScanline >= fFrameRect.bottom
()) { | 569 if (inputScanline < fFrameRect.top() || inputScanline >= fFrameRect.bott
om()) { |
| 619 return nextScanline; | 570 return inputScanline; |
| 620 } | 571 } |
| 621 return get_output_row_interlaced(nextScanline - fFrameRect.top(), fFrame
Rect.height()); | 572 return get_output_row_interlaced(inputScanline - fFrameRect.top(), fFram
eRect.height()); |
| 622 } | 573 } |
| 623 return nextScanline; | 574 return inputScanline; |
| 624 } | 575 } |
| 625 | |
| OLD | NEW |