Chromium Code Reviews| 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 349 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 360 } | 360 } |
| 361 return nullptr; | 361 return nullptr; |
| 362 } | 362 } |
| 363 | 363 |
| 364 #define INVALID_NUMBER_PASSES -1 | 364 #define INVALID_NUMBER_PASSES -1 |
| 365 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, | 365 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, |
| 366 png_structp png_ptr, png_infop info_ptr, int bitDepth) | 366 png_structp png_ptr, png_infop info_ptr, int bitDepth) |
| 367 : INHERITED(info, stream) | 367 : INHERITED(info, stream) |
| 368 , fPng_ptr(png_ptr) | 368 , fPng_ptr(png_ptr) |
| 369 , fInfo_ptr(info_ptr) | 369 , fInfo_ptr(info_ptr) |
| 370 , fRow(0) | |
| 370 , fSrcConfig(SkSwizzler::kUnknown) | 371 , fSrcConfig(SkSwizzler::kUnknown) |
| 371 , fNumberPasses(INVALID_NUMBER_PASSES) | 372 , fNumberPasses(INVALID_NUMBER_PASSES) |
| 372 , fReallyHasAlpha(false) | 373 , fReallyHasAlpha(false) |
| 373 , fBitDepth(bitDepth) | 374 , fBitDepth(bitDepth) |
| 374 {} | 375 {} |
| 375 | 376 |
| 376 SkPngCodec::~SkPngCodec() { | 377 SkPngCodec::~SkPngCodec() { |
| 377 this->destroyReadStruct(); | 378 this->destroyReadStruct(); |
| 378 } | 379 } |
| 379 | 380 |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 487 | 488 |
| 488 // Note that ctable and ctableCount may be modified if there is a color tabl e | 489 // Note that ctable and ctableCount may be modified if there is a color tabl e |
| 489 const Result result = this->initializeSwizzler(requestedInfo, options, | 490 const Result result = this->initializeSwizzler(requestedInfo, options, |
| 490 ctable, ctableCount); | 491 ctable, ctableCount); |
| 491 if (result != kSuccess) { | 492 if (result != kSuccess) { |
| 492 return result; | 493 return result; |
| 493 } | 494 } |
| 494 // FIXME: Could we use the return value of setjmp to specify the type of | 495 // FIXME: Could we use the return value of setjmp to specify the type of |
| 495 // error? | 496 // error? |
| 496 if (setjmp(png_jmpbuf(fPng_ptr))) { | 497 if (setjmp(png_jmpbuf(fPng_ptr))) { |
| 497 SkCodecPrintf("setjmp long jump!\n"); | 498 // Assume that any error that occurs while reading rows is caused by an incomplete input. |
| 498 return kInvalidInput; | 499 if (fNumberPasses > 1) { |
| 500 // FIXME (msarett): Handle incomplete interlaced pngs. | |
| 501 return kInvalidInput; | |
| 502 } | |
| 503 // FIXME: We do a poor job on incomplete pngs compared to other decoders (ex: Chromium, | |
| 504 // Ubuntu Image Viewer). This is because we use the default buffer size in libpng (8192 | |
| 505 // bytes), and if we can't fill the buffer, we immediately fail. Making our buffer size | |
|
scroggo
2015/09/22 18:02:48
Does this mean, for example, that we try to read 8
msarett
2015/09/23 13:22:40
Yes that is exactly what the problem is.
scroggo
2015/09/25 15:55:05
Could you add that to the description?
msarett
2015/10/01 12:44:51
Done.
| |
| 506 // smaller would help, but what impact would it have on regular decode p erformance? Should | |
| 507 // we investigate using a different API than png_read_row(s). Chromium uses | |
| 508 // png_process_data. | |
| 509 this->setIncompleteScanlines(requestedInfo.height() - fRow); | |
|
scroggo
2015/09/22 18:02:48
I always get confused when dealing with setjmp, so
msarett
2015/09/23 13:22:40
Yes this works! Clever!
scroggo
2015/09/25 15:55:05
Just to make sure, did you test this? Can we add a
msarett
2015/10/01 12:44:51
Yes I tested this. I have been testing by decodin
scroggo
2015/10/01 14:48:31
Possibly - the advantage to including it in CodexT
msarett
2015/10/01 18:14:13
I will add a single incomplete image to resources
| |
| 510 return kIncompleteInput; | |
| 499 } | 511 } |
| 500 | 512 |
| 501 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); | 513 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); |
| 502 SkAutoMalloc storage; | 514 SkAutoMalloc storage; |
| 503 void* dstRow = dst; | 515 void* dstRow = dst; |
| 504 if (fNumberPasses > 1) { | 516 if (fNumberPasses > 1) { |
| 505 const int width = requestedInfo.width(); | 517 const int width = requestedInfo.width(); |
| 506 const int height = requestedInfo.height(); | 518 const int height = requestedInfo.height(); |
| 507 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig); | 519 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig); |
| 508 const size_t srcRowBytes = width * bpp; | 520 const size_t srcRowBytes = width * bpp; |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 522 // Now swizzle it. | 534 // Now swizzle it. |
| 523 uint8_t* srcRow = base; | 535 uint8_t* srcRow = base; |
| 524 for (int y = 0; y < height; y++) { | 536 for (int y = 0; y < height; y++) { |
| 525 fReallyHasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow, srcRow)); | 537 fReallyHasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow, srcRow)); |
| 526 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); | 538 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); |
| 527 srcRow += srcRowBytes; | 539 srcRow += srcRowBytes; |
| 528 } | 540 } |
| 529 } else { | 541 } else { |
| 530 storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConf ig)); | 542 storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConf ig)); |
| 531 uint8_t* srcRow = static_cast<uint8_t*>(storage.get()); | 543 uint8_t* srcRow = static_cast<uint8_t*>(storage.get()); |
| 532 for (int y = 0; y < requestedInfo.height(); y++) { | 544 for (fRow = 0; fRow < requestedInfo.height(); fRow++) { |
| 533 png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1); | 545 png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1); |
| 534 fReallyHasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow, srcRow)); | 546 fReallyHasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow, srcRow)); |
| 535 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); | 547 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); |
| 536 } | 548 } |
| 537 } | 549 } |
| 538 | 550 |
| 539 // FIXME: do we need substituteTranspColor? Note that we cannot do it for | 551 // FIXME: do we need substituteTranspColor? Note that we cannot do it for |
| 540 // scanline decoding, but we could do it here. Alternatively, we could do | 552 // scanline decoding, but we could do it here. Alternatively, we could do |
| 541 // it as we go, instead of in post-processing like SkPNGImageDecoder. | 553 // it as we go, instead of in post-processing like SkPNGImageDecoder. |
| 542 | 554 |
| 543 if (setjmp(png_jmpbuf(fPng_ptr))) { | 555 if (setjmp(png_jmpbuf(fPng_ptr))) { |
| 544 // We've already read all the scanlines. This is a success. | 556 // We've already read all the scanlines. This is a success. |
| 545 return kSuccess; | 557 return kSuccess; |
| 546 } | 558 } |
| 547 | 559 |
| 548 // read rest of file, and get additional comment and time chunks in info_ptr | 560 // read rest of file, and get additional comment and time chunks in info_ptr |
| 549 png_read_end(fPng_ptr, fInfo_ptr); | 561 png_read_end(fPng_ptr, fInfo_ptr); |
| 550 return kSuccess; | 562 return kSuccess; |
| 551 } | 563 } |
| 552 | 564 |
| 565 uint32_t SkPngCodec::onGetFillValue(const SkImageInfo& dstInfo) const { | |
| 566 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | |
| 567 if (colorPtr) { | |
| 568 return get_color_table_fill_value(dstInfo.colorType(), colorPtr, 0); | |
| 569 } | |
| 570 return INHERITED::onGetFillValue(dstInfo); | |
| 571 } | |
| 572 | |
| 553 class SkPngScanlineDecoder : public SkScanlineDecoder { | 573 class SkPngScanlineDecoder : public SkScanlineDecoder { |
| 554 public: | 574 public: |
| 555 SkPngScanlineDecoder(const SkImageInfo& srcInfo, SkPngCodec* codec) | 575 SkPngScanlineDecoder(SkPngCodec* codec) |
| 556 : INHERITED(srcInfo) | 576 : INHERITED(codec, codec->getInfo()) |
| 557 , fCodec(codec) | 577 , fCodec(codec) |
| 558 , fHasAlpha(false) | 578 , fHasAlpha(false) |
| 559 {} | 579 {} |
| 560 | 580 |
| 561 SkCodec::Result onStart(const SkImageInfo& dstInfo, | 581 SkCodec::Result onStart(const SkImageInfo& dstInfo, |
| 562 const SkCodec::Options& options, | 582 const SkCodec::Options& options, |
| 563 SkPMColor ctable[], int* ctableCount) override { | 583 SkPMColor ctable[], int* ctableCount) override { |
| 564 if (!fCodec->rewindIfNeeded()) { | 584 if (!fCodec->rewindIfNeeded()) { |
| 565 return SkCodec::kCouldNotRewind; | 585 return SkCodec::kCouldNotRewind; |
| 566 } | 586 } |
| 567 | 587 |
| 568 if (!conversion_possible(dstInfo, this->getInfo())) { | 588 if (!conversion_possible(dstInfo, this->getInfo())) { |
| 569 return SkCodec::kInvalidConversion; | 589 return SkCodec::kInvalidConversion; |
| 570 } | 590 } |
| 571 | 591 |
| 572 // Check to see if scaling was requested. | 592 // Check to see if scaling was requested. |
| 573 if (dstInfo.dimensions() != this->getInfo().dimensions()) { | 593 if (dstInfo.dimensions() != this->getInfo().dimensions()) { |
| 574 if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) { | 594 if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) { |
| 575 return SkCodec::kInvalidScale; | 595 return SkCodec::kInvalidScale; |
| 576 } | 596 } |
| 577 } | 597 } |
| 578 | 598 |
| 579 const SkCodec::Result result = fCodec->initializeSwizzler(dstInfo, optio ns, ctable, | 599 const SkCodec::Result result = fCodec->initializeSwizzler(dstInfo, optio ns, ctable, |
| 580 ctableCount); | 600 ctableCount); |
| 581 if (result != SkCodec::kSuccess) { | 601 if (result != SkCodec::kSuccess) { |
| 582 return result; | 602 return result; |
| 583 } | 603 } |
| 584 | 604 |
| 585 fHasAlpha = false; | 605 fHasAlpha = false; |
| 586 fStorage.reset(this->getInfo().width() * SkSwizzler::BytesPerPixel(fCode c->fSrcConfig)); | 606 fStorage.reset(this->getInfo().width() * SkSwizzler::BytesPerPixel(fCode c->fSrcConfig)); |
| 587 fSrcRow = static_cast<uint8_t*>(fStorage.get()); | 607 fSrcRow = static_cast<uint8_t*>(fStorage.get()); |
| 588 | 608 |
| 589 return SkCodec::kSuccess; | 609 return SkCodec::kSuccess; |
| 590 } | 610 } |
| 591 | 611 |
| 592 SkCodec::Result onGetScanlines(void* dst, int count, size_t rowBytes) overri de { | 612 uint32_t onGetScanlines(void* dst, int count, size_t rowBytes) override { |
| 613 // Assume that an error in libpng indicates an incomplete input. | |
| 593 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { | 614 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { |
| 594 SkCodecPrintf("setjmp long jump!\n"); | 615 SkCodecPrintf("setjmp long jump!\n"); |
| 595 return SkCodec::kInvalidInput; | 616 return fCodec->fRow; |
| 596 } | 617 } |
| 597 | 618 |
| 598 void* dstRow = dst; | 619 void* dstRow = dst; |
| 599 for (int i = 0; i < count; i++) { | 620 for (fCodec->fRow = 0; fCodec->fRow < count; fCodec->fRow++) { |
| 600 png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1); | 621 png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1); |
| 601 fHasAlpha |= !SkSwizzler::IsOpaque(fCodec->fSwizzler->swizzle(dstRow , fSrcRow)); | 622 fHasAlpha |= !SkSwizzler::IsOpaque(fCodec->fSwizzler->swizzle(dstRow , fSrcRow)); |
| 602 dstRow = SkTAddOffset<void>(dstRow, rowBytes); | 623 dstRow = SkTAddOffset<void>(dstRow, rowBytes); |
| 603 } | 624 } |
| 604 return SkCodec::kSuccess; | 625 return fCodec->fRow; |
| 605 } | 626 } |
| 606 | 627 |
| 607 SkCodec::Result onSkipScanlines(int count) override { | 628 uint32_t onSkipScanlines(int count) override { |
| 608 // FIXME: Could we use the return value of setjmp to specify the type of | 629 // Assume that an error in libpng indicates an incomplete input. |
| 609 // error? | |
| 610 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { | 630 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { |
| 611 SkCodecPrintf("setjmp long jump!\n"); | 631 SkCodecPrintf("setjmp long jump!\n"); |
| 612 return SkCodec::kInvalidInput; | 632 return fCodec->fRow; |
| 613 } | 633 } |
| 614 //there is a potential tradeoff of memory vs speed created by putting th is in a loop. | 634 //there is a potential tradeoff of memory vs speed created by putting th is in a loop. |
| 615 //calling png_read_rows in a loop is insignificantly slower than calling it once with count | 635 //calling png_read_rows in a loop is insignificantly slower than calling it once with count |
| 616 //as png_read_rows has it's own loop which calls png_read_row count time s. | 636 //as png_read_rows has it's own loop which calls png_read_row count time s. |
| 617 for (int i = 0; i < count; i++) { | 637 for (fCodec->fRow = 0; fCodec->fRow < count; fCodec->fRow++) { |
| 618 png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1); | 638 png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1); |
| 619 } | 639 } |
| 620 return SkCodec::kSuccess; | 640 return fCodec->fRow; |
| 621 } | 641 } |
| 622 | 642 |
| 623 bool onReallyHasAlpha() const override { return fHasAlpha; } | 643 bool onReallyHasAlpha() const override { return fHasAlpha; } |
| 624 | 644 |
| 625 SkEncodedFormat onGetEncodedFormat() const override { | 645 SkEncodedFormat onGetEncodedFormat() const override { |
| 626 return kPNG_SkEncodedFormat; | 646 return kPNG_SkEncodedFormat; |
| 627 } | 647 } |
| 628 | 648 |
| 629 | 649 |
| 630 private: | 650 private: |
| 631 SkAutoTDelete<SkPngCodec> fCodec; | 651 SkPngCodec* fCodec; // Owned by parent class |
| 632 bool fHasAlpha; | 652 bool fHasAlpha; |
| 633 SkAutoMalloc fStorage; | 653 SkAutoMalloc fStorage; |
| 634 uint8_t* fSrcRow; | 654 uint8_t* fSrcRow; |
| 635 | 655 |
| 636 typedef SkScanlineDecoder INHERITED; | 656 typedef SkScanlineDecoder INHERITED; |
| 637 }; | 657 }; |
| 638 | 658 |
| 639 | 659 |
| 640 class SkPngInterlacedScanlineDecoder : public SkScanlineDecoder { | 660 class SkPngInterlacedScanlineDecoder : public SkScanlineDecoder { |
| 641 public: | 661 public: |
| 642 SkPngInterlacedScanlineDecoder(const SkImageInfo& srcInfo, SkPngCodec* codec ) | 662 SkPngInterlacedScanlineDecoder(SkPngCodec* codec) |
| 643 : INHERITED(srcInfo) | 663 : INHERITED(codec, codec->getInfo()) |
| 644 , fCodec(codec) | 664 , fCodec(codec) |
| 645 , fHasAlpha(false) | 665 , fHasAlpha(false) |
| 646 , fCurrentRow(0) | 666 , fCurrentRow(0) |
| 647 , fHeight(srcInfo.height()) | 667 , fHeight(codec->getInfo().height()) |
| 648 , fCanSkipRewind(false) | 668 , fCanSkipRewind(false) |
| 649 {} | 669 {} |
| 650 | 670 |
| 651 SkCodec::Result onStart(const SkImageInfo& dstInfo, | 671 SkCodec::Result onStart(const SkImageInfo& dstInfo, |
| 652 const SkCodec::Options& options, | 672 const SkCodec::Options& options, |
| 653 SkPMColor ctable[], int* ctableCount) override | 673 SkPMColor ctable[], int* ctableCount) override |
| 654 { | 674 { |
| 655 if (!fCodec->rewindIfNeeded()) { | 675 if (!fCodec->rewindIfNeeded()) { |
| 656 return SkCodec::kCouldNotRewind; | 676 return SkCodec::kCouldNotRewind; |
| 657 } | 677 } |
| 658 | 678 |
| 659 if (!conversion_possible(dstInfo, this->getInfo())) { | 679 if (!conversion_possible(dstInfo, this->getInfo())) { |
| 660 return SkCodec::kInvalidConversion; | 680 return SkCodec::kInvalidConversion; |
| 661 } | 681 } |
| 662 | 682 |
| 663 // Check to see if scaling was requested. | 683 // Check to see if scaling was requested. |
| 664 if (dstInfo.dimensions() != this->getInfo().dimensions()) { | 684 if (dstInfo.dimensions() != this->getInfo().dimensions()) { |
| 665 if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) { | 685 if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) { |
| 666 return SkCodec::kInvalidScale; | 686 return SkCodec::kInvalidScale; |
| 667 } | 687 } |
| 668 } | 688 } |
| 669 | 689 |
| 670 const SkCodec::Result result = fCodec->initializeSwizzler(dstInfo, optio ns, ctable, | 690 const SkCodec::Result result = fCodec->initializeSwizzler(dstInfo, optio ns, ctable, |
| 671 ctableCount); | 691 ctableCount); |
| 672 if (result != SkCodec::kSuccess) { | 692 if (result != SkCodec::kSuccess) { |
| 673 return result; | 693 return result; |
| 674 } | 694 } |
| 675 | 695 |
| 676 fHasAlpha = false; | 696 fHasAlpha = false; |
| 677 fCurrentRow = 0; | 697 fCurrentRow = 0; |
| 678 fHeight = dstInfo.height(); | 698 fHeight = dstInfo.height(); |
| 679 fSrcRowBytes = this->getInfo().width() * SkSwizzler::BytesPerPixel(fCode c->fSrcConfig); | 699 fSrcRowBytes = this->getInfo().width() * SkSwizzler::BytesPerPixel(fCode c->fSrcConfig); |
| 680 fGarbageRow.reset(fSrcRowBytes); | 700 fGarbageRow.reset(fSrcRowBytes); |
| 681 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); | 701 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); |
| 682 fCanSkipRewind = true; | 702 fCanSkipRewind = true; |
| 683 | 703 |
| 684 return SkCodec::kSuccess; | 704 return SkCodec::kSuccess; |
| 685 } | 705 } |
| 686 | 706 |
| 687 SkCodec::Result onGetScanlines(void* dst, int count, size_t dstRowBytes) ove rride { | 707 uint32_t onGetScanlines(void* dst, int count, size_t dstRowBytes) override { |
| 688 // rewind stream if have previously called onGetScanlines, | 708 // rewind stream if have previously called onGetScanlines, |
| 689 // since we need entire progressive image to get scanlines | 709 // since we need entire progressive image to get scanlines |
| 690 if (fCanSkipRewind) { | 710 if (fCanSkipRewind) { |
| 691 // We already rewound in onStart, so there is no reason to rewind. | 711 // We already rewound in onStart, so there is no reason to rewind. |
| 692 // Next time onGetScanlines is called, we will need to rewind. | 712 // Next time onGetScanlines is called, we will need to rewind. |
| 693 fCanSkipRewind = false; | 713 fCanSkipRewind = false; |
| 694 } else if (!fCodec->rewindIfNeeded()) { | 714 } else if (!fCodec->rewindIfNeeded()) { |
| 695 return SkCodec::kCouldNotRewind; | 715 return 0; |
| 696 } | 716 } |
| 697 | 717 |
| 698 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { | 718 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { |
| 699 SkCodecPrintf("setjmp long jump!\n"); | 719 SkCodecPrintf("setjmp long jump!\n"); |
| 700 return SkCodec::kInvalidInput; | 720 // FIXME (msarett): Returning 0 is pessimistic. If we can complete a single pass, |
| 721 // we may be able to report that all of the memory has been initiali zed. Even if we | |
| 722 // fail on the first pass, we can still report than some scanlines a re initialized. | |
| 723 return 0; | |
| 701 } | 724 } |
| 702 const int number_passes = png_set_interlace_handling(fCodec->fPng_ptr); | 725 const int number_passes = png_set_interlace_handling(fCodec->fPng_ptr); |
| 703 SkAutoMalloc storage(count * fSrcRowBytes); | 726 SkAutoMalloc storage(count * fSrcRowBytes); |
| 704 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get()); | 727 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get()); |
| 705 uint8_t* srcRow; | 728 uint8_t* srcRow; |
| 706 for (int i = 0; i < number_passes; i++) { | 729 for (int i = 0; i < number_passes; i++) { |
| 707 //read rows we planned to skip into garbage row | 730 //read rows we planned to skip into garbage row |
| 708 for (int y = 0; y < fCurrentRow; y++){ | 731 for (int y = 0; y < fCurrentRow; y++){ |
| 709 png_read_rows(fCodec->fPng_ptr, &fGarbageRowPtr, png_bytepp_NULL , 1); | 732 png_read_rows(fCodec->fPng_ptr, &fGarbageRowPtr, png_bytepp_NULL , 1); |
| 710 } | 733 } |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 721 } | 744 } |
| 722 //swizzle the rows we care about | 745 //swizzle the rows we care about |
| 723 srcRow = storagePtr; | 746 srcRow = storagePtr; |
| 724 void* dstRow = dst; | 747 void* dstRow = dst; |
| 725 for (int y = 0; y < count; y++) { | 748 for (int y = 0; y < count; y++) { |
| 726 fHasAlpha |= !SkSwizzler::IsOpaque(fCodec->fSwizzler->swizzle(dstRow , srcRow)); | 749 fHasAlpha |= !SkSwizzler::IsOpaque(fCodec->fSwizzler->swizzle(dstRow , srcRow)); |
| 727 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); | 750 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); |
| 728 srcRow += fSrcRowBytes; | 751 srcRow += fSrcRowBytes; |
| 729 } | 752 } |
| 730 fCurrentRow += count; | 753 fCurrentRow += count; |
| 731 return SkCodec::kSuccess; | 754 return count; |
| 732 } | 755 } |
| 733 | 756 |
| 734 SkCodec::Result onSkipScanlines(int count) override { | 757 uint32_t onSkipScanlines(int count) override { |
| 735 //when ongetScanlines is called it will skip to fCurrentRow | 758 //when ongetScanlines is called it will skip to fCurrentRow |
| 736 fCurrentRow += count; | 759 fCurrentRow += count; |
| 737 return SkCodec::kSuccess; | 760 return count; |
| 738 } | 761 } |
| 739 | 762 |
| 740 bool onReallyHasAlpha() const override { return fHasAlpha; } | 763 bool onReallyHasAlpha() const override { return fHasAlpha; } |
| 741 | 764 |
| 742 SkScanlineOrder onGetScanlineOrder() const override { | 765 SkScanlineOrder onGetScanlineOrder() const override { |
| 743 return kNone_SkScanlineOrder; | 766 return kNone_SkScanlineOrder; |
| 744 } | 767 } |
| 745 | 768 |
| 746 SkEncodedFormat onGetEncodedFormat() const override { | 769 SkEncodedFormat onGetEncodedFormat() const override { |
| 747 return kPNG_SkEncodedFormat; | 770 return kPNG_SkEncodedFormat; |
| 748 } | 771 } |
| 749 | 772 |
| 750 private: | 773 private: |
| 751 SkAutoTDelete<SkPngCodec> fCodec; | 774 SkPngCodec* fCodec; // Owned by parent class |
| 752 bool fHasAlpha; | 775 bool fHasAlpha; |
| 753 int fCurrentRow; | 776 int fCurrentRow; |
| 754 int fHeight; | 777 int fHeight; |
| 755 size_t fSrcRowBytes; | 778 size_t fSrcRowBytes; |
| 756 SkAutoMalloc fGarbageRow; | 779 SkAutoMalloc fGarbageRow; |
| 757 uint8_t* fGarbageRowPtr; | 780 uint8_t* fGarbageRowPtr; |
| 758 // FIXME: This imitates behavior in SkCodec::rewindIfNeeded. That function | 781 // FIXME: This imitates behavior in SkCodec::rewindIfNeeded. That function |
| 759 // is called whenever some action is taken that reads the stream and | 782 // is called whenever some action is taken that reads the stream and |
| 760 // therefore the next call will require a rewind. So it modifies a boolean | 783 // therefore the next call will require a rewind. So it modifies a boolean |
| 761 // to note that the *next* time it is called a rewind is needed. | 784 // to note that the *next* time it is called a rewind is needed. |
| 762 // SkPngInterlacedScanlineDecoder has an extra wrinkle - calling onStart | 785 // SkPngInterlacedScanlineDecoder has an extra wrinkle - calling onStart |
| 763 // followed by onGetScanlines does *not* require a rewind. Since | 786 // followed by onGetScanlines does *not* require a rewind. Since |
| 764 // rewindIfNeeded does not have this flexibility, we need to add another | 787 // rewindIfNeeded does not have this flexibility, we need to add another |
| 765 // layer. | 788 // layer. |
| 766 bool fCanSkipRewind; | 789 bool fCanSkipRewind; |
| 767 | 790 |
| 768 typedef SkScanlineDecoder INHERITED; | 791 typedef SkScanlineDecoder INHERITED; |
| 769 }; | 792 }; |
| 770 | 793 |
| 771 SkScanlineDecoder* SkPngCodec::NewSDFromStream(SkStream* stream) { | 794 SkScanlineDecoder* SkPngCodec::NewSDFromStream(SkStream* stream) { |
| 772 SkAutoTDelete<SkPngCodec> codec (static_cast<SkPngCodec*>(SkPngCodec::NewFro mStream(stream))); | 795 SkAutoTDelete<SkPngCodec> codec (static_cast<SkPngCodec*>(SkPngCodec::NewFro mStream(stream))); |
| 773 if (!codec) { | 796 if (!codec) { |
| 774 return nullptr; | 797 return nullptr; |
| 775 } | 798 } |
| 776 | 799 |
| 777 codec->fNumberPasses = png_set_interlace_handling(codec->fPng_ptr); | 800 codec->fNumberPasses = png_set_interlace_handling(codec->fPng_ptr); |
| 778 SkASSERT(codec->fNumberPasses != INVALID_NUMBER_PASSES); | 801 SkASSERT(codec->fNumberPasses != INVALID_NUMBER_PASSES); |
| 779 | 802 |
| 780 const SkImageInfo& srcInfo = codec->getInfo(); | |
| 781 if (codec->fNumberPasses > 1) { | 803 if (codec->fNumberPasses > 1) { |
| 782 // interlaced image | 804 // interlaced image |
| 783 return new SkPngInterlacedScanlineDecoder(srcInfo, codec.detach()); | 805 return new SkPngInterlacedScanlineDecoder(codec.detach()); |
| 784 } | 806 } |
| 785 | 807 |
| 786 return new SkPngScanlineDecoder(srcInfo, codec.detach()); | 808 return new SkPngScanlineDecoder(codec.detach()); |
| 787 } | 809 } |
| 788 | 810 |
| OLD | NEW |