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

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

Powered by Google App Engine
This is Rietveld 408576698