Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(84)

Side by Side Diff: src/codec/SkCodec_libpng.cpp

Issue 1230033004: Allow creating multiple scanline decoders. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Cleanups Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/codec/SkCodec_libpng.h ('k') | src/codec/SkJpegCodec.h » ('j') | src/codec/SkJpegCodec.cpp » ('J')

Powered by Google App Engine
This is Rietveld 408576698