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, 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 { | |
scroggo
2015/10/08 13:50:30
It looks like there are three classes with similar
msarett
2015/10/08 15:33:25
It won't quite work because gif may have an fFillI
| |
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().makeWH(this->dstInfo().width(), cou nt), rowBytes, |
scroggo
2015/10/08 13:50:30
nit: some local variables would probably make this
msarett
2015/10/08 15:33:25
Done.
| |
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 |