| 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_libpng.h" | 8 #include "SkCodec_libpng.h" |
| 9 #include "SkCodecPriv.h" | 9 #include "SkCodecPriv.h" |
| 10 #include "SkColorPriv.h" | 10 #include "SkColorPriv.h" |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 147 } else { | 147 } else { |
| 148 numTrans = 0; | 148 numTrans = 0; |
| 149 } | 149 } |
| 150 | 150 |
| 151 // check for bad images that might make us crash | 151 // check for bad images that might make us crash |
| 152 if (numTrans > numPalette) { | 152 if (numTrans > numPalette) { |
| 153 numTrans = numPalette; | 153 numTrans = numPalette; |
| 154 } | 154 } |
| 155 | 155 |
| 156 int index = 0; | 156 int index = 0; |
| 157 int transLessThanFF = 0; | |
| 158 | 157 |
| 159 // Choose which function to use to create the color table. If the final dest
ination's | 158 // Choose which function to use to create the color table. If the final dest
ination's |
| 160 // colortype is unpremultiplied, the color table will store unpremultiplied
colors. | 159 // colortype is unpremultiplied, the color table will store unpremultiplied
colors. |
| 161 PackColorProc proc; | 160 PackColorProc proc; |
| 162 if (premultiply) { | 161 if (premultiply) { |
| 163 proc = &SkPreMultiplyARGB; | 162 proc = &SkPreMultiplyARGB; |
| 164 } else { | 163 } else { |
| 165 proc = &SkPackARGB32NoCheck; | 164 proc = &SkPackARGB32NoCheck; |
| 166 } | 165 } |
| 167 for (; index < numTrans; index++) { | 166 for (; index < numTrans; index++) { |
| 168 transLessThanFF |= (int)*trans - 0xFF; | |
| 169 *colorPtr++ = proc(*trans++, palette->red, palette->green, palette->blue
); | 167 *colorPtr++ = proc(*trans++, palette->red, palette->green, palette->blue
); |
| 170 palette++; | 168 palette++; |
| 171 } | 169 } |
| 172 | 170 |
| 173 if (transLessThanFF >= 0) { | |
| 174 // No transparent colors were found. | |
| 175 fAlphaState = kOpaque_AlphaState; | |
| 176 } | |
| 177 | |
| 178 for (; index < numPalette; index++) { | 171 for (; index < numPalette; index++) { |
| 179 *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette->
blue); | 172 *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette->
blue); |
| 180 palette++; | 173 palette++; |
| 181 } | 174 } |
| 182 | 175 |
| 183 /* BUGGY IMAGE WORKAROUND | 176 /* BUGGY IMAGE WORKAROUND |
| 184 Invalid images could contain pixel values that are greater than the numb
er of palette | 177 Invalid images could contain pixel values that are greater than the numb
er of palette |
| 185 entries. Since we use pixel values as indices into the palette this coul
d result in reading | 178 entries. Since we use pixel values as indices into the palette this coul
d result in reading |
| 186 beyond the end of the palette which could leak the contents of uninitial
ized memory. To | 179 beyond the end of the palette which could leak the contents of uninitial
ized memory. To |
| 187 ensure this doesn't happen, we grow the colortable to the maximum size t
hat can be | 180 ensure this doesn't happen, we grow the colortable to the maximum size t
hat can be |
| (...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 378 | 371 |
| 379 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, SkPngChunkRead
er* chunkReader, | 372 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, SkPngChunkRead
er* chunkReader, |
| 380 png_structp png_ptr, png_infop info_ptr, int bitDepth, in
t numberPasses) | 373 png_structp png_ptr, png_infop info_ptr, int bitDepth, in
t numberPasses) |
| 381 : INHERITED(info, stream) | 374 : INHERITED(info, stream) |
| 382 , fPngChunkReader(SkSafeRef(chunkReader)) | 375 , fPngChunkReader(SkSafeRef(chunkReader)) |
| 383 , fPng_ptr(png_ptr) | 376 , fPng_ptr(png_ptr) |
| 384 , fInfo_ptr(info_ptr) | 377 , fInfo_ptr(info_ptr) |
| 385 , fSrcConfig(SkSwizzler::kUnknown) | 378 , fSrcConfig(SkSwizzler::kUnknown) |
| 386 , fNumberPasses(numberPasses) | 379 , fNumberPasses(numberPasses) |
| 387 , fBitDepth(bitDepth) | 380 , fBitDepth(bitDepth) |
| 388 { | 381 {} |
| 389 if (info.alphaType() == kOpaque_SkAlphaType) { | |
| 390 fAlphaState = kOpaque_AlphaState; | |
| 391 } else { | |
| 392 fAlphaState = kUnknown_AlphaState; | |
| 393 } | |
| 394 } | |
| 395 | 382 |
| 396 SkPngCodec::~SkPngCodec() { | 383 SkPngCodec::~SkPngCodec() { |
| 397 this->destroyReadStruct(); | 384 this->destroyReadStruct(); |
| 398 } | 385 } |
| 399 | 386 |
| 400 void SkPngCodec::destroyReadStruct() { | 387 void SkPngCodec::destroyReadStruct() { |
| 401 if (fPng_ptr) { | 388 if (fPng_ptr) { |
| 402 // We will never have a nullptr fInfo_ptr with a non-nullptr fPng_ptr | 389 // We will never have a nullptr fInfo_ptr with a non-nullptr fPng_ptr |
| 403 SkASSERT(fInfo_ptr); | 390 SkASSERT(fInfo_ptr); |
| 404 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL); | 391 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL); |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 520 // when we could have decoded a few more lines and then failed. | 507 // when we could have decoded a few more lines and then failed. |
| 521 // The read function that we provide for libpng has no way of indicating
that we have | 508 // The read function that we provide for libpng has no way of indicating
that we have |
| 522 // made a partial read. | 509 // made a partial read. |
| 523 // Making our buffer size smaller improves our incomplete decodes, but w
hat impact does | 510 // Making our buffer size smaller improves our incomplete decodes, but w
hat impact does |
| 524 // it have on regular decode performance? Should we investigate using a
different API | 511 // it have on regular decode performance? Should we investigate using a
different API |
| 525 // instead of png_read_row(s)? Chromium uses png_process_data. | 512 // instead of png_read_row(s)? Chromium uses png_process_data. |
| 526 *rowsDecoded = row; | 513 *rowsDecoded = row; |
| 527 return kIncompleteInput; | 514 return kIncompleteInput; |
| 528 } | 515 } |
| 529 | 516 |
| 530 bool hasAlpha = false; | |
| 531 // FIXME: We could split these out based on subclass. | 517 // FIXME: We could split these out based on subclass. |
| 532 void* dstRow = dst; | 518 void* dstRow = dst; |
| 533 if (fNumberPasses > 1) { | 519 if (fNumberPasses > 1) { |
| 534 const int width = requestedInfo.width(); | 520 const int width = requestedInfo.width(); |
| 535 const int height = requestedInfo.height(); | 521 const int height = requestedInfo.height(); |
| 536 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig); | 522 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig); |
| 537 const size_t srcRowBytes = width * bpp; | 523 const size_t srcRowBytes = width * bpp; |
| 538 | 524 |
| 539 storage.reset(width * height * bpp); | 525 storage.reset(width * height * bpp); |
| 540 uint8_t* const base = storage.get(); | 526 uint8_t* const base = storage.get(); |
| 541 | 527 |
| 542 for (int i = 0; i < fNumberPasses; i++) { | 528 for (int i = 0; i < fNumberPasses; i++) { |
| 543 uint8_t* srcRow = base; | 529 uint8_t* srcRow = base; |
| 544 for (int y = 0; y < height; y++) { | 530 for (int y = 0; y < height; y++) { |
| 545 uint8_t* bmRow = srcRow; | 531 uint8_t* bmRow = srcRow; |
| 546 png_read_rows(fPng_ptr, &bmRow, png_bytepp_NULL, 1); | 532 png_read_rows(fPng_ptr, &bmRow, png_bytepp_NULL, 1); |
| 547 srcRow += srcRowBytes; | 533 srcRow += srcRowBytes; |
| 548 } | 534 } |
| 549 } | 535 } |
| 550 | 536 |
| 551 // Now swizzle it. | 537 // Now swizzle it. |
| 552 uint8_t* srcRow = base; | 538 uint8_t* srcRow = base; |
| 553 for (int y = 0; y < height; y++) { | 539 for (int y = 0; y < height; y++) { |
| 554 hasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow, srcRow)
); | 540 fSwizzler->swizzle(dstRow, srcRow); |
| 555 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); | 541 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); |
| 556 srcRow += srcRowBytes; | 542 srcRow += srcRowBytes; |
| 557 } | 543 } |
| 558 } else { | 544 } else { |
| 559 storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConf
ig)); | 545 storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConf
ig)); |
| 560 uint8_t* srcRow = storage.get(); | 546 uint8_t* srcRow = storage.get(); |
| 561 for (; row < requestedInfo.height(); row++) { | 547 for (; row < requestedInfo.height(); row++) { |
| 562 png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1); | 548 png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1); |
| 563 // FIXME: Only call IsOpaque once, outside the loop. Same for onGetS
canlines. | 549 // FIXME: Only call IsOpaque once, outside the loop. Same for onGetS
canlines. |
| 564 hasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow, srcRow)
); | 550 fSwizzler->swizzle(dstRow, srcRow); |
| 565 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); | 551 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); |
| 566 } | 552 } |
| 567 } | 553 } |
| 568 | 554 |
| 569 if (hasAlpha) { | |
| 570 fAlphaState = kHasAlpha_AlphaState; | |
| 571 } else { | |
| 572 fAlphaState = kOpaque_AlphaState; | |
| 573 } | |
| 574 | |
| 575 // FIXME: do we need substituteTranspColor? Note that we cannot do it for | 555 // FIXME: do we need substituteTranspColor? Note that we cannot do it for |
| 576 // scanline decoding, but we could do it here. Alternatively, we could do | 556 // scanline decoding, but we could do it here. Alternatively, we could do |
| 577 // it as we go, instead of in post-processing like SkPNGImageDecoder. | 557 // it as we go, instead of in post-processing like SkPNGImageDecoder. |
| 578 | 558 |
| 579 if (setjmp(png_jmpbuf(fPng_ptr))) { | 559 if (setjmp(png_jmpbuf(fPng_ptr))) { |
| 580 // We've already read all the scanlines. This is a success. | 560 // We've already read all the scanlines. This is a success. |
| 581 return kSuccess; | 561 return kSuccess; |
| 582 } | 562 } |
| 583 | 563 |
| 584 // read rest of file, and get additional comment and time chunks in info_ptr | 564 // read rest of file, and get additional comment and time chunks in info_ptr |
| 585 png_read_end(fPng_ptr, fInfo_ptr); | 565 png_read_end(fPng_ptr, fInfo_ptr); |
| 586 | 566 |
| 587 return kSuccess; | 567 return kSuccess; |
| 588 } | 568 } |
| 589 | 569 |
| 590 uint32_t SkPngCodec::onGetFillValue(SkColorType colorType, SkAlphaType alphaType
) const { | 570 uint32_t SkPngCodec::onGetFillValue(SkColorType colorType, SkAlphaType alphaType
) const { |
| 591 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 571 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); |
| 592 if (colorPtr) { | 572 if (colorPtr) { |
| 593 return get_color_table_fill_value(colorType, colorPtr, 0); | 573 return get_color_table_fill_value(colorType, colorPtr, 0); |
| 594 } | 574 } |
| 595 return INHERITED::onGetFillValue(colorType, alphaType); | 575 return INHERITED::onGetFillValue(colorType, alphaType); |
| 596 } | 576 } |
| 597 | 577 |
| 598 bool SkPngCodec::onReallyHasAlpha() const { | |
| 599 switch (fAlphaState) { | |
| 600 case kOpaque_AlphaState: | |
| 601 return false; | |
| 602 case kUnknown_AlphaState: | |
| 603 // Maybe the subclass knows? | |
| 604 return this->alphaInScanlineDecode() == kHasAlpha_AlphaState; | |
| 605 case kHasAlpha_AlphaState: | |
| 606 switch (this->alphaInScanlineDecode()) { | |
| 607 case kUnknown_AlphaState: | |
| 608 // Scanline decoder must not have been used. Return our know
ledge. | |
| 609 return true; | |
| 610 case kOpaque_AlphaState: | |
| 611 // Scanline decoder was used, and did not find alpha in its
subset. | |
| 612 return false; | |
| 613 case kHasAlpha_AlphaState: | |
| 614 return true; | |
| 615 } | |
| 616 } | |
| 617 | |
| 618 // All valid AlphaStates have been covered, so this should not be reached. | |
| 619 SkASSERT(false); | |
| 620 return true; | |
| 621 } | |
| 622 | |
| 623 // Subclass of SkPngCodec which supports scanline decoding | 578 // Subclass of SkPngCodec which supports scanline decoding |
| 624 class SkPngScanlineDecoder : public SkPngCodec { | 579 class SkPngScanlineDecoder : public SkPngCodec { |
| 625 public: | 580 public: |
| 626 SkPngScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream, | 581 SkPngScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream, |
| 627 SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_p
tr, int bitDepth) | 582 SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_p
tr, int bitDepth) |
| 628 : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, 1
) | 583 : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, 1
) |
| 629 , fAlphaState(kUnknown_AlphaState) | |
| 630 , fSrcRow(nullptr) | 584 , fSrcRow(nullptr) |
| 631 {} | 585 {} |
| 632 | 586 |
| 633 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti
ons, | 587 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti
ons, |
| 634 SkPMColor ctable[], int* ctableCount) override { | 588 SkPMColor ctable[], int* ctableCount) override { |
| 635 if (!conversion_possible(dstInfo, this->getInfo())) { | 589 if (!conversion_possible(dstInfo, this->getInfo())) { |
| 636 return kInvalidConversion; | 590 return kInvalidConversion; |
| 637 } | 591 } |
| 638 | 592 |
| 639 const Result result = this->initializeSwizzler(dstInfo, options, ctable, | 593 const Result result = this->initializeSwizzler(dstInfo, options, ctable, |
| 640 ctableCount); | 594 ctableCount); |
| 641 if (result != kSuccess) { | 595 if (result != kSuccess) { |
| 642 return result; | 596 return result; |
| 643 } | 597 } |
| 644 | 598 |
| 645 fAlphaState = kUnknown_AlphaState; | |
| 646 fStorage.reset(this->getInfo().width() * SkSwizzler::BytesPerPixel(this-
>srcConfig())); | 599 fStorage.reset(this->getInfo().width() * SkSwizzler::BytesPerPixel(this-
>srcConfig())); |
| 647 fSrcRow = fStorage.get(); | 600 fSrcRow = fStorage.get(); |
| 648 | 601 |
| 649 return kSuccess; | 602 return kSuccess; |
| 650 } | 603 } |
| 651 | 604 |
| 652 int onGetScanlines(void* dst, int count, size_t rowBytes) override { | 605 int onGetScanlines(void* dst, int count, size_t rowBytes) override { |
| 653 // Assume that an error in libpng indicates an incomplete input. | 606 // Assume that an error in libpng indicates an incomplete input. |
| 654 int row = 0; | 607 int row = 0; |
| 655 if (setjmp(png_jmpbuf(this->png_ptr()))) { | 608 if (setjmp(png_jmpbuf(this->png_ptr()))) { |
| 656 SkCodecPrintf("setjmp long jump!\n"); | 609 SkCodecPrintf("setjmp long jump!\n"); |
| 657 return row; | 610 return row; |
| 658 } | 611 } |
| 659 | 612 |
| 660 void* dstRow = dst; | 613 void* dstRow = dst; |
| 661 bool hasAlpha = false; | |
| 662 for (; row < count; row++) { | 614 for (; row < count; row++) { |
| 663 png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1); | 615 png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1); |
| 664 hasAlpha |= !SkSwizzler::IsOpaque(this->swizzler()->swizzle(dstRow,
fSrcRow)); | 616 this->swizzler()->swizzle(dstRow, fSrcRow); |
| 665 dstRow = SkTAddOffset<void>(dstRow, rowBytes); | 617 dstRow = SkTAddOffset<void>(dstRow, rowBytes); |
| 666 } | 618 } |
| 667 | 619 |
| 668 if (hasAlpha) { | |
| 669 fAlphaState = kHasAlpha_AlphaState; | |
| 670 } else { | |
| 671 if (kUnknown_AlphaState == fAlphaState) { | |
| 672 fAlphaState = kOpaque_AlphaState; | |
| 673 } | |
| 674 // Otherwise, the AlphaState is unchanged. | |
| 675 } | |
| 676 | |
| 677 return row; | 620 return row; |
| 678 } | 621 } |
| 679 | 622 |
| 680 bool onSkipScanlines(int count) override { | 623 bool onSkipScanlines(int count) override { |
| 681 // Assume that an error in libpng indicates an incomplete input. | 624 // Assume that an error in libpng indicates an incomplete input. |
| 682 if (setjmp(png_jmpbuf(this->png_ptr()))) { | 625 if (setjmp(png_jmpbuf(this->png_ptr()))) { |
| 683 SkCodecPrintf("setjmp long jump!\n"); | 626 SkCodecPrintf("setjmp long jump!\n"); |
| 684 return false; | 627 return false; |
| 685 } | 628 } |
| 686 //there is a potential tradeoff of memory vs speed created by putting th
is in a loop. | 629 //there is a potential tradeoff of memory vs speed created by putting th
is in a loop. |
| 687 //calling png_read_rows in a loop is insignificantly slower than calling
it once with count | 630 //calling png_read_rows in a loop is insignificantly slower than calling
it once with count |
| 688 //as png_read_rows has it's own loop which calls png_read_row count time
s. | 631 //as png_read_rows has it's own loop which calls png_read_row count time
s. |
| 689 for (int row = 0; row < count; row++) { | 632 for (int row = 0; row < count; row++) { |
| 690 png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1); | 633 png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1); |
| 691 } | 634 } |
| 692 return true; | 635 return true; |
| 693 } | 636 } |
| 694 | 637 |
| 695 AlphaState alphaInScanlineDecode() const override { | |
| 696 return fAlphaState; | |
| 697 } | |
| 698 | |
| 699 private: | 638 private: |
| 700 AlphaState fAlphaState; | |
| 701 SkAutoTMalloc<uint8_t> fStorage; | 639 SkAutoTMalloc<uint8_t> fStorage; |
| 702 uint8_t* fSrcRow; | 640 uint8_t* fSrcRow; |
| 703 | 641 |
| 704 typedef SkPngCodec INHERITED; | 642 typedef SkPngCodec INHERITED; |
| 705 }; | 643 }; |
| 706 | 644 |
| 707 | 645 |
| 708 class SkPngInterlacedScanlineDecoder : public SkPngCodec { | 646 class SkPngInterlacedScanlineDecoder : public SkPngCodec { |
| 709 public: | 647 public: |
| 710 SkPngInterlacedScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream, | 648 SkPngInterlacedScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream, |
| 711 SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_p
tr, | 649 SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_p
tr, |
| 712 int bitDepth, int numberPasses) | 650 int bitDepth, int numberPasses) |
| 713 : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, n
umberPasses) | 651 : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, n
umberPasses) |
| 714 , fAlphaState(kUnknown_AlphaState) | |
| 715 , fHeight(-1) | 652 , fHeight(-1) |
| 716 , fCanSkipRewind(false) | 653 , fCanSkipRewind(false) |
| 717 { | 654 { |
| 718 SkASSERT(numberPasses != 1); | 655 SkASSERT(numberPasses != 1); |
| 719 } | 656 } |
| 720 | 657 |
| 721 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti
ons, | 658 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti
ons, |
| 722 SkPMColor ctable[], int* ctableCount) override { | 659 SkPMColor ctable[], int* ctableCount) override { |
| 723 if (!conversion_possible(dstInfo, this->getInfo())) { | 660 if (!conversion_possible(dstInfo, this->getInfo())) { |
| 724 return kInvalidConversion; | 661 return kInvalidConversion; |
| 725 } | 662 } |
| 726 | 663 |
| 727 const Result result = this->initializeSwizzler(dstInfo, options, ctable, | 664 const Result result = this->initializeSwizzler(dstInfo, options, ctable, |
| 728 ctableCount); | 665 ctableCount); |
| 729 if (result != kSuccess) { | 666 if (result != kSuccess) { |
| 730 return result; | 667 return result; |
| 731 } | 668 } |
| 732 | 669 |
| 733 fAlphaState = kUnknown_AlphaState; | |
| 734 fHeight = dstInfo.height(); | 670 fHeight = dstInfo.height(); |
| 735 // FIXME: This need not be called on a second call to onStartScanlineDec
ode. | 671 // FIXME: This need not be called on a second call to onStartScanlineDec
ode. |
| 736 fSrcRowBytes = this->getInfo().width() * SkSwizzler::BytesPerPixel(this-
>srcConfig()); | 672 fSrcRowBytes = this->getInfo().width() * SkSwizzler::BytesPerPixel(this-
>srcConfig()); |
| 737 fGarbageRow.reset(fSrcRowBytes); | 673 fGarbageRow.reset(fSrcRowBytes); |
| 738 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); | 674 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); |
| 739 fCanSkipRewind = true; | 675 fCanSkipRewind = true; |
| 740 | 676 |
| 741 return SkCodec::kSuccess; | 677 return SkCodec::kSuccess; |
| 742 } | 678 } |
| 743 | 679 |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 787 srcRow += fSrcRowBytes; | 723 srcRow += fSrcRowBytes; |
| 788 } | 724 } |
| 789 // read rows we don't want into garbage buffer | 725 // read rows we don't want into garbage buffer |
| 790 for (int y = 0; y < fHeight - startRow - count; y++) { | 726 for (int y = 0; y < fHeight - startRow - count; y++) { |
| 791 png_read_rows(this->png_ptr(), &fGarbageRowPtr, png_bytepp_NULL,
1); | 727 png_read_rows(this->png_ptr(), &fGarbageRowPtr, png_bytepp_NULL,
1); |
| 792 } | 728 } |
| 793 } | 729 } |
| 794 //swizzle the rows we care about | 730 //swizzle the rows we care about |
| 795 srcRow = storagePtr; | 731 srcRow = storagePtr; |
| 796 void* dstRow = dst; | 732 void* dstRow = dst; |
| 797 bool hasAlpha = false; | |
| 798 for (int y = 0; y < count; y++) { | 733 for (int y = 0; y < count; y++) { |
| 799 hasAlpha |= !SkSwizzler::IsOpaque(this->swizzler()->swizzle(dstRow,
srcRow)); | 734 this->swizzler()->swizzle(dstRow, srcRow); |
| 800 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); | 735 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); |
| 801 srcRow += fSrcRowBytes; | 736 srcRow += fSrcRowBytes; |
| 802 } | 737 } |
| 803 | 738 |
| 804 if (hasAlpha) { | |
| 805 fAlphaState = kHasAlpha_AlphaState; | |
| 806 } else { | |
| 807 if (kUnknown_AlphaState == fAlphaState) { | |
| 808 fAlphaState = kOpaque_AlphaState; | |
| 809 } | |
| 810 // Otherwise, the AlphaState is unchanged. | |
| 811 } | |
| 812 | |
| 813 return count; | 739 return count; |
| 814 } | 740 } |
| 815 | 741 |
| 816 bool onSkipScanlines(int count) override { | 742 bool onSkipScanlines(int count) override { |
| 817 // The non-virtual version will update fCurrScanline. | 743 // The non-virtual version will update fCurrScanline. |
| 818 return true; | 744 return true; |
| 819 } | 745 } |
| 820 | 746 |
| 821 AlphaState alphaInScanlineDecode() const override { | |
| 822 return fAlphaState; | |
| 823 } | |
| 824 | |
| 825 SkScanlineOrder onGetScanlineOrder() const override { | 747 SkScanlineOrder onGetScanlineOrder() const override { |
| 826 return kNone_SkScanlineOrder; | 748 return kNone_SkScanlineOrder; |
| 827 } | 749 } |
| 828 | 750 |
| 829 private: | 751 private: |
| 830 AlphaState fAlphaState; | |
| 831 int fHeight; | 752 int fHeight; |
| 832 size_t fSrcRowBytes; | 753 size_t fSrcRowBytes; |
| 833 SkAutoMalloc fGarbageRow; | 754 SkAutoMalloc fGarbageRow; |
| 834 uint8_t* fGarbageRowPtr; | 755 uint8_t* fGarbageRowPtr; |
| 835 // FIXME: This imitates behavior in SkCodec::rewindIfNeeded. That function | 756 // FIXME: This imitates behavior in SkCodec::rewindIfNeeded. That function |
| 836 // is called whenever some action is taken that reads the stream and | 757 // is called whenever some action is taken that reads the stream and |
| 837 // therefore the next call will require a rewind. So it modifies a boolean | 758 // therefore the next call will require a rewind. So it modifies a boolean |
| 838 // to note that the *next* time it is called a rewind is needed. | 759 // to note that the *next* time it is called a rewind is needed. |
| 839 // SkPngInterlacedScanlineDecoder has an extra wrinkle - calling | 760 // SkPngInterlacedScanlineDecoder has an extra wrinkle - calling |
| 840 // onStartScanlineDecode followed by onGetScanlines does *not* require a | 761 // onStartScanlineDecode followed by onGetScanlines does *not* require a |
| (...skipping 18 matching lines...) Expand all Loading... |
| 859 } | 780 } |
| 860 | 781 |
| 861 if (1 == numberPasses) { | 782 if (1 == numberPasses) { |
| 862 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), chunk
Reader, | 783 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), chunk
Reader, |
| 863 png_ptr, info_ptr, bitDepth); | 784 png_ptr, info_ptr, bitDepth); |
| 864 } | 785 } |
| 865 | 786 |
| 866 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(),
chunkReader, | 787 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(),
chunkReader, |
| 867 png_ptr, info_ptr, bitDepth, numbe
rPasses); | 788 png_ptr, info_ptr, bitDepth, numbe
rPasses); |
| 868 } | 789 } |
| OLD | NEW |