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 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 112 png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL); | 112 png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL); |
| 113 return num_trans > 0; | 113 return num_trans > 0; |
| 114 } | 114 } |
| 115 | 115 |
| 116 // Method for coverting to either an SkPMColor or a similarly packed | 116 // Method for coverting to either an SkPMColor or a similarly packed |
| 117 // unpremultiplied color. | 117 // unpremultiplied color. |
| 118 typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b); | 118 typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b); |
| 119 | 119 |
| 120 // Note: SkColorTable claims to store SkPMColors, which is not necessarily | 120 // Note: SkColorTable claims to store SkPMColors, which is not necessarily |
| 121 // the case here. | 121 // the case here. |
| 122 bool SkPngCodec::decodePalette(bool premultiply, int bitDepth, int* ctableCount) { | 122 bool SkPngCodec::decodePalette(bool premultiply, int* ctableCount) { |
| 123 int numPalette; | 123 int numPalette; |
| 124 png_colorp palette; | 124 png_colorp palette; |
| 125 png_bytep trans; | 125 png_bytep trans; |
| 126 | 126 |
| 127 if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numPalette)) { | 127 if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numPalette)) { |
| 128 return false; | 128 return false; |
| 129 } | 129 } |
| 130 | 130 |
| 131 // Note: These are not necessarily SkPMColors | 131 // Note: These are not necessarily SkPMColors |
| 132 SkPMColor colorStorage[256]; // worst-case storage | 132 SkPMColor colorStorage[256]; // worst-case storage |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 169 } | 169 } |
| 170 | 170 |
| 171 /* BUGGY IMAGE WORKAROUND | 171 /* BUGGY IMAGE WORKAROUND |
| 172 Invalid images could contain pixel values that are greater than the numb er of palette | 172 Invalid images could contain pixel values that are greater than the numb er of palette |
| 173 entries. Since we use pixel values as indices into the palette this coul d result in reading | 173 entries. Since we use pixel values as indices into the palette this coul d result in reading |
| 174 beyond the end of the palette which could leak the contents of uninitial ized memory. To | 174 beyond the end of the palette which could leak the contents of uninitial ized memory. To |
| 175 ensure this doesn't happen, we grow the colortable to the maximum size t hat can be | 175 ensure this doesn't happen, we grow the colortable to the maximum size t hat can be |
| 176 addressed by the bitdepth of the image and fill it with the last palette color or black if | 176 addressed by the bitdepth of the image and fill it with the last palette color or black if |
| 177 the palette is empty (really broken image). | 177 the palette is empty (really broken image). |
| 178 */ | 178 */ |
| 179 int colorCount = SkTMax(numPalette, 1 << SkTMin(bitDepth, 8)); | 179 int colorCount = SkTMax(numPalette, 1 << SkTMin(fBitDepth, 8)); |
| 180 SkPMColor lastColor = index > 0 ? colorPtr[-1] : SkPackARGB32(0xFF, 0, 0, 0) ; | 180 SkPMColor lastColor = index > 0 ? colorPtr[-1] : SkPackARGB32(0xFF, 0, 0, 0) ; |
| 181 for (; index < colorCount; index++) { | 181 for (; index < colorCount; index++) { |
| 182 *colorPtr++ = lastColor; | 182 *colorPtr++ = lastColor; |
| 183 } | 183 } |
| 184 | 184 |
| 185 // Set the new color count | 185 // Set the new color count |
| 186 if (ctableCount != NULL) { | 186 if (ctableCount != NULL) { |
| 187 *ctableCount = colorCount; | 187 *ctableCount = colorCount; |
| 188 } | 188 } |
| 189 | 189 |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 366 : INHERITED(info, stream) | 366 : INHERITED(info, stream) |
| 367 , fPng_ptr(png_ptr) | 367 , fPng_ptr(png_ptr) |
| 368 , fInfo_ptr(info_ptr) | 368 , fInfo_ptr(info_ptr) |
| 369 , fSrcConfig(SkSwizzler::kUnknown) | 369 , fSrcConfig(SkSwizzler::kUnknown) |
| 370 , fNumberPasses(INVALID_NUMBER_PASSES) | 370 , fNumberPasses(INVALID_NUMBER_PASSES) |
| 371 , fReallyHasAlpha(false) | 371 , fReallyHasAlpha(false) |
| 372 , fBitDepth(bitDepth) | 372 , fBitDepth(bitDepth) |
| 373 {} | 373 {} |
| 374 | 374 |
| 375 SkPngCodec::~SkPngCodec() { | 375 SkPngCodec::~SkPngCodec() { |
| 376 // First, ensure that the scanline decoder is left in a finished state. | |
| 377 SkAutoTDelete<SkScanlineDecoder> decoder(this->detachScanlineDecoder()); | |
| 378 if (NULL != decoder) { | |
| 379 this->finish(); | |
| 380 } | |
| 381 | |
| 382 this->destroyReadStruct(); | 376 this->destroyReadStruct(); |
| 383 } | 377 } |
| 384 | 378 |
| 385 void SkPngCodec::destroyReadStruct() { | 379 void SkPngCodec::destroyReadStruct() { |
| 386 if (fPng_ptr) { | 380 if (fPng_ptr) { |
| 387 // We will never have a NULL fInfo_ptr with a non-NULL fPng_ptr | 381 // We will never have a NULL fInfo_ptr with a non-NULL fPng_ptr |
| 388 SkASSERT(fInfo_ptr); | 382 SkASSERT(fInfo_ptr); |
| 389 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL); | 383 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL); |
| 390 fPng_ptr = NULL; | 384 fPng_ptr = NULL; |
| 391 fInfo_ptr = NULL; | 385 fInfo_ptr = NULL; |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 446 // Set to the default before calling decodePalette, which may change it. | 440 // Set to the default before calling decodePalette, which may change it. |
| 447 fReallyHasAlpha = false; | 441 fReallyHasAlpha = false; |
| 448 | 442 |
| 449 //srcColorType was determined in readHeader() which determined png color typ e | 443 //srcColorType was determined in readHeader() which determined png color typ e |
| 450 const SkColorType srcColorType = this->getInfo().colorType(); | 444 const SkColorType srcColorType = this->getInfo().colorType(); |
| 451 | 445 |
| 452 switch (srcColorType) { | 446 switch (srcColorType) { |
| 453 case kIndex_8_SkColorType: | 447 case kIndex_8_SkColorType: |
| 454 //decode palette to Skia format | 448 //decode palette to Skia format |
| 455 fSrcConfig = SkSwizzler::kIndex; | 449 fSrcConfig = SkSwizzler::kIndex; |
| 456 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaT ype(), fBitDepth, | 450 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaT ype(), |
| 457 ctableCount)) { | 451 ctableCount)) { |
| 458 return kInvalidInput; | 452 return kInvalidInput; |
| 459 } | 453 } |
| 460 break; | 454 break; |
| 461 case kGray_8_SkColorType: | 455 case kGray_8_SkColorType: |
| 462 fSrcConfig = SkSwizzler::kGray; | 456 fSrcConfig = SkSwizzler::kGray; |
| 463 break; | 457 break; |
| 464 case kN32_SkColorType: | 458 case kN32_SkColorType: |
| 465 if (this->getInfo().alphaType() == kOpaque_SkAlphaType) { | 459 if (this->getInfo().alphaType() == kOpaque_SkAlphaType) { |
| 466 fSrcConfig = SkSwizzler::kRGBX; | 460 fSrcConfig = SkSwizzler::kRGBX; |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 515 return false; | 509 return false; |
| 516 } | 510 } |
| 517 } | 511 } |
| 518 | 512 |
| 519 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst, | 513 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst, |
| 520 size_t rowBytes, const Options& options, | 514 size_t rowBytes, const Options& options, |
| 521 SkPMColor ctable[], int* ctableCount) { | 515 SkPMColor ctable[], int* ctableCount) { |
| 522 if (!conversion_possible(requestedInfo, this->getInfo())) { | 516 if (!conversion_possible(requestedInfo, this->getInfo())) { |
| 523 return kInvalidConversion; | 517 return kInvalidConversion; |
| 524 } | 518 } |
| 525 // Do not allow a regular decode if the caller has asked for a scanline deco der | |
| 526 if (NULL != this->scanlineDecoder()) { | |
| 527 SkCodecPrintf("cannot getPixels() if a scanline decoder has been created \n"); | |
| 528 return kInvalidParameters; | |
| 529 } | |
| 530 if (requestedInfo.dimensions() != this->getInfo().dimensions()) { | 519 if (requestedInfo.dimensions() != this->getInfo().dimensions()) { |
| 531 return kInvalidScale; | 520 return kInvalidScale; |
| 532 } | 521 } |
| 533 if (!this->handleRewind()) { | 522 if (!this->handleRewind()) { |
| 534 return kCouldNotRewind; | 523 return kCouldNotRewind; |
| 535 } | 524 } |
| 536 | 525 |
| 537 // Note that ctable and ctableCount may be modified if there is a color tabl e | 526 // Note that ctable and ctableCount may be modified if there is a color tabl e |
| 538 const Result result = this->initializeSwizzler(requestedInfo, dst, rowBytes, | 527 const Result result = this->initializeSwizzler(requestedInfo, dst, rowBytes, |
| 539 options, ctable, ctableCount) ; | 528 options, ctable, ctableCount) ; |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 588 | 577 |
| 589 this->finish(); | 578 this->finish(); |
| 590 return kSuccess; | 579 return kSuccess; |
| 591 } | 580 } |
| 592 | 581 |
| 593 void SkPngCodec::finish() { | 582 void SkPngCodec::finish() { |
| 594 if (setjmp(png_jmpbuf(fPng_ptr))) { | 583 if (setjmp(png_jmpbuf(fPng_ptr))) { |
| 595 // We've already read all the scanlines. This is a success. | 584 // We've already read all the scanlines. This is a success. |
| 596 return; | 585 return; |
| 597 } | 586 } |
| 587 // FIXME: Is this necessary? | |
|
scroggo
2015/07/09 20:52:31
I copied the below comment from SkImageDecoder_lib
| |
| 598 /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ | 588 /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ |
| 599 png_read_end(fPng_ptr, fInfo_ptr); | 589 png_read_end(fPng_ptr, fInfo_ptr); |
| 600 } | 590 } |
| 601 | 591 |
| 602 class SkPngScanlineDecoder : public SkScanlineDecoder { | 592 class SkPngScanlineDecoder : public SkScanlineDecoder { |
| 603 public: | 593 public: |
| 604 SkPngScanlineDecoder(const SkImageInfo& dstInfo, SkPngCodec* codec) | 594 SkPngScanlineDecoder(const SkImageInfo& dstInfo, SkPngCodec* codec) |
| 605 : INHERITED(dstInfo) | 595 : INHERITED(dstInfo) |
| 606 , fCodec(codec) | 596 , fCodec(codec) |
| 607 , fHasAlpha(false) | 597 , fHasAlpha(false) |
| 608 { | 598 { |
| 609 fStorage.reset(dstInfo.width() * SkSwizzler::BytesPerPixel(fCodec->fSrcC onfig)); | 599 fStorage.reset(dstInfo.width() * SkSwizzler::BytesPerPixel(fCodec->fSrcC onfig)); |
| 610 fSrcRow = static_cast<uint8_t*>(fStorage.get()); | 600 fSrcRow = static_cast<uint8_t*>(fStorage.get()); |
| 611 } | 601 } |
| 612 | 602 |
| 603 ~SkPngScanlineDecoder() { | |
| 604 fCodec->finish(); | |
| 605 } | |
| 606 | |
| 613 SkCodec::Result onGetScanlines(void* dst, int count, size_t rowBytes) overri de { | 607 SkCodec::Result onGetScanlines(void* dst, int count, size_t rowBytes) overri de { |
| 614 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { | 608 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { |
| 615 SkCodecPrintf("setjmp long jump!\n"); | 609 SkCodecPrintf("setjmp long jump!\n"); |
| 616 return SkCodec::kInvalidInput; | 610 return SkCodec::kInvalidInput; |
| 617 } | 611 } |
| 618 | 612 |
| 619 for (int i = 0; i < count; i++) { | 613 for (int i = 0; i < count; i++) { |
| 620 png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1); | 614 png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1); |
| 621 fCodec->fSwizzler->setDstRow(dst); | 615 fCodec->fSwizzler->setDstRow(dst); |
| 622 fHasAlpha |= !SkSwizzler::IsOpaque(fCodec->fSwizzler->next(fSrcRow)) ; | 616 fHasAlpha |= !SkSwizzler::IsOpaque(fCodec->fSwizzler->next(fSrcRow)) ; |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 637 //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. |
| 638 for (int i = 0; i < count; i++) { | 632 for (int i = 0; i < count; i++) { |
| 639 png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1); | 633 png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1); |
| 640 } | 634 } |
| 641 return SkCodec::kSuccess; | 635 return SkCodec::kSuccess; |
| 642 } | 636 } |
| 643 | 637 |
| 644 bool onReallyHasAlpha() const override { return fHasAlpha; } | 638 bool onReallyHasAlpha() const override { return fHasAlpha; } |
| 645 | 639 |
| 646 private: | 640 private: |
| 647 SkPngCodec* fCodec; // Unowned. | 641 SkAutoTDelete<SkPngCodec> fCodec; |
| 648 bool fHasAlpha; | 642 bool fHasAlpha; |
| 649 SkAutoMalloc fStorage; | 643 SkAutoMalloc fStorage; |
| 650 uint8_t* fSrcRow; | 644 uint8_t* fSrcRow; |
| 651 | 645 |
| 652 typedef SkScanlineDecoder INHERITED; | 646 typedef SkScanlineDecoder INHERITED; |
| 653 }; | 647 }; |
| 654 | 648 |
| 655 | 649 |
| 656 class SkPngInterlacedScanlineDecoder : public SkScanlineDecoder { | 650 class SkPngInterlacedScanlineDecoder : public SkScanlineDecoder { |
| 657 public: | 651 public: |
| 658 SkPngInterlacedScanlineDecoder(const SkImageInfo& dstInfo, SkPngCodec* codec ) | 652 SkPngInterlacedScanlineDecoder(const SkImageInfo& dstInfo, SkPngCodec* codec ) |
| 659 : INHERITED(dstInfo) | 653 : INHERITED(dstInfo) |
| 660 , fCodec(codec) | 654 , fCodec(codec) |
| 661 , fHasAlpha(false) | 655 , fHasAlpha(false) |
| 662 , fCurrentRow(0) | 656 , fCurrentRow(0) |
| 663 , fHeight(dstInfo.height()) | 657 , fHeight(dstInfo.height()) |
| 664 , fRewindNeeded(false) | 658 , fRewindNeeded(false) |
| 665 { | 659 { |
| 666 fSrcRowBytes = dstInfo.width() * SkSwizzler::BytesPerPixel(fCodec->fSrcC onfig); | 660 fSrcRowBytes = dstInfo.width() * SkSwizzler::BytesPerPixel(fCodec->fSrcC onfig); |
| 667 fGarbageRow.reset(fSrcRowBytes); | 661 fGarbageRow.reset(fSrcRowBytes); |
| 668 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); | 662 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); |
| 669 } | 663 } |
| 670 | 664 |
| 665 ~SkPngInterlacedScanlineDecoder() { | |
| 666 fCodec->finish(); | |
| 667 } | |
| 668 | |
| 671 SkCodec::Result onGetScanlines(void* dst, int count, size_t dstRowBytes) ove rride { | 669 SkCodec::Result onGetScanlines(void* dst, int count, size_t dstRowBytes) ove rride { |
| 672 //rewind stream if have previously called onGetScanlines, | 670 //rewind stream if have previously called onGetScanlines, |
| 673 //since we need entire progressive image to get scanlines | 671 //since we need entire progressive image to get scanlines |
| 674 if (fRewindNeeded) { | 672 if (fRewindNeeded) { |
| 675 if(false == fCodec->handleRewind()) { | 673 if(false == fCodec->handleRewind()) { |
| 676 return SkCodec::kCouldNotRewind; | 674 return SkCodec::kCouldNotRewind; |
| 677 } | 675 } |
| 678 } else { | 676 } else { |
| 679 fRewindNeeded = true; | 677 fRewindNeeded = true; |
| 680 } | 678 } |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 716 | 714 |
| 717 SkCodec::Result onSkipScanlines(int count) override { | 715 SkCodec::Result onSkipScanlines(int count) override { |
| 718 //when ongetScanlines is called it will skip to fCurrentRow | 716 //when ongetScanlines is called it will skip to fCurrentRow |
| 719 fCurrentRow += count; | 717 fCurrentRow += count; |
| 720 return SkCodec::kSuccess; | 718 return SkCodec::kSuccess; |
| 721 } | 719 } |
| 722 | 720 |
| 723 bool onReallyHasAlpha() const override { return fHasAlpha; } | 721 bool onReallyHasAlpha() const override { return fHasAlpha; } |
| 724 | 722 |
| 725 private: | 723 private: |
| 726 SkPngCodec* fCodec; // Unowned. | 724 SkAutoTDelete<SkPngCodec> fCodec; |
| 727 bool fHasAlpha; | 725 bool fHasAlpha; |
| 728 int fCurrentRow; | 726 int fCurrentRow; |
| 729 int fHeight; | 727 int fHeight; |
| 730 size_t fSrcRowBytes; | 728 size_t fSrcRowBytes; |
| 731 bool fRewindNeeded; | 729 bool fRewindNeeded; |
| 732 SkAutoMalloc fGarbageRow; | 730 SkAutoMalloc fGarbageRow; |
| 733 uint8_t* fGarbageRowPtr; | 731 uint8_t* fGarbageRowPtr; |
| 734 | 732 |
| 735 typedef SkScanlineDecoder INHERITED; | 733 typedef SkScanlineDecoder INHERITED; |
| 736 }; | 734 }; |
| 737 | 735 |
| 738 | 736 |
| 739 SkScanlineDecoder* SkPngCodec::onGetScanlineDecoder(const SkImageInfo& dstInfo, | 737 SkScanlineDecoder* SkPngCodec::onGetScanlineDecoder(const SkImageInfo& dstInfo, |
| 740 const Options& options, SkPMColor ctable[], int* ctableCount) { | 738 const Options& options, SkPMColor ctable[], int* ctableCount) { |
| 741 if (!conversion_possible(dstInfo, this->getInfo())) { | 739 if (!conversion_possible(dstInfo, this->getInfo())) { |
| 742 SkCodecPrintf("no conversion possible\n"); | 740 SkCodecPrintf("no conversion possible\n"); |
| 743 return NULL; | 741 return NULL; |
| 744 } | 742 } |
| 745 // Check to see if scaling was requested. | 743 // Check to see if scaling was requested. |
| 746 if (dstInfo.dimensions() != this->getInfo().dimensions()) { | 744 if (dstInfo.dimensions() != this->getInfo().dimensions()) { |
| 747 return NULL; | 745 return NULL; |
| 748 } | 746 } |
| 749 if (!this->handleRewind()) { | 747 // Create a new SkPngCodec, to be owned by the scanline decoder. |
| 748 SkStream* stream = this->stream()->duplicate(); | |
| 749 if (!stream) { | |
| 750 return NULL; | |
| 751 } | |
| 752 SkAutoTDelete<SkPngCodec> codec (static_cast<SkPngCodec*>(SkPngCodec::NewFro mStream(stream))); | |
| 753 if (!codec) { | |
| 750 return NULL; | 754 return NULL; |
| 751 } | 755 } |
| 752 | 756 |
| 753 // Note: We set dst to NULL since we do not know it yet. rowBytes is not nee ded, | 757 // Note: We set dst to NULL since we do not know it yet. rowBytes is not nee ded, |
| 754 // since we'll be manually updating the dstRow, but the SkSwizzler requires it to | 758 // since we'll be manually updating the dstRow, but the SkSwizzler requires it to |
| 755 // be at least dstInfo.minRowBytes. | 759 // be at least dstInfo.minRowBytes. |
| 756 if (this->initializeSwizzler(dstInfo, NULL, dstInfo.minRowBytes(), options, ctable, | 760 if (codec->initializeSwizzler(dstInfo, NULL, dstInfo.minRowBytes(), options, ctable, |
| 757 ctableCount) != kSuccess) { | 761 ctableCount) != kSuccess) { |
| 758 SkCodecPrintf("failed to initialize the swizzler.\n"); | 762 SkCodecPrintf("failed to initialize the swizzler.\n"); |
| 759 return NULL; | 763 return NULL; |
| 760 } | 764 } |
| 761 | 765 |
| 762 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); | 766 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); |
| 763 if (fNumberPasses > 1) { | 767 if (fNumberPasses > 1) { |
| 764 // interlaced image | 768 // interlaced image |
| 765 return SkNEW_ARGS(SkPngInterlacedScanlineDecoder, (dstInfo, this)); | 769 return SkNEW_ARGS(SkPngInterlacedScanlineDecoder, (dstInfo, codec.detach ())); |
| 766 } | 770 } |
| 767 | 771 |
| 768 return SkNEW_ARGS(SkPngScanlineDecoder, (dstInfo, this)); | 772 return SkNEW_ARGS(SkPngScanlineDecoder, (dstInfo, codec.detach())); |
| 769 } | 773 } |
| 770 | 774 |
| OLD | NEW |