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 |