Chromium Code Reviews| Index: src/codec/SkCodec_libpng.cpp |
| diff --git a/src/codec/SkCodec_libpng.cpp b/src/codec/SkCodec_libpng.cpp |
| index c2a032e84ea8d98017998bdf5e6f9e12bf059685..15a837ff69cc3d177686e78b70d805c837551b8b 100644 |
| --- a/src/codec/SkCodec_libpng.cpp |
| +++ b/src/codec/SkCodec_libpng.cpp |
| @@ -648,6 +648,98 @@ private: |
| typedef SkScanlineDecoder INHERITED; |
| }; |
| + |
| +class SkPngInterlacedScanlineDecoder : public SkScanlineDecoder { |
| +public: |
| + SkPngInterlacedScanlineDecoder(const SkImageInfo& dstInfo, SkPngCodec* codec) |
| + : INHERITED(dstInfo) |
| + , fCodec(codec) |
| + , fHasAlpha(false) |
| + , fCurrentRow(0) |
| + , fHeight(dstInfo.height()) |
| + , fSrcRowBytes(dstInfo.minRowBytes()) |
| + , fRewindNeeded(false) |
| + { |
| + fGarbageRow.reset(fSrcRowBytes); |
| + fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); |
| + } |
| + |
| + SkImageGenerator::Result onGetScanlines(void* dst, int count, size_t dstRowBytes) override { |
| + //rewind stream if have previously called onGetScanlines, |
| + //since we need entire progressive image to get scanlines |
| + if (fRewindNeeded) { |
| + if(false == fCodec->handleRewind()) { |
| + return SkImageGenerator::kCouldNotRewind; |
| + } |
| + } else { |
| + fRewindNeeded = true; |
|
scroggo
2015/06/22 14:46:25
You'll still need to set this to rewind next time
scroggo
2015/06/22 15:02:17
Nvm. As discussed in person, this should work as i
|
| + } |
| + if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { |
| + SkCodecPrintf("setjmp long jump!\n"); |
| + return SkImageGenerator::kInvalidInput; |
| + } |
| + const int number_passes = png_set_interlace_handling(fCodec->fPng_ptr); |
| + SkAutoMalloc storage(count * fSrcRowBytes); |
| + uint8_t* storagePtr = static_cast<uint8_t*>(storage.get()); |
| + uint8_t* srcRow; |
| + for (int i = 0; i < number_passes; i++) { |
| + //read rows we planned to skip into garbage row |
| + for (int y = 0; y < fCurrentRow; y++){ |
| + png_read_rows(fCodec->fPng_ptr, &fGarbageRowPtr, png_bytepp_NULL, 1); |
| + } |
| + //read rows we care about into buffer |
| + srcRow = storagePtr; |
| + for (int y = 0; y < count; y++) { |
| + png_read_rows(fCodec->fPng_ptr, &srcRow, png_bytepp_NULL, 1); |
| + srcRow += fSrcRowBytes; |
| + } |
| + //read rows we don't want into garbage buffer |
| + for (int y = 0; y < fHeight - fCurrentRow - count; y++) { |
| + png_read_rows(fCodec->fPng_ptr, &fGarbageRowPtr, png_bytepp_NULL, 1); |
| + } |
| + } |
| + //swizzle the rows we care about |
| + srcRow = storagePtr; |
| + for (int y = 0; y < count; y++) { |
| + fCodec->fSwizzler->setDstRow(dst); |
| + fHasAlpha |= !SkSwizzler::IsOpaque(fCodec->fSwizzler->next(srcRow)); |
| + dst = SkTAddOffset<void>(dst, dstRowBytes); |
| + srcRow += fSrcRowBytes; |
| + } |
| + fCurrentRow += count; |
| + return SkImageGenerator::kSuccess; |
| + } |
| + |
| + SkImageGenerator::Result onSkipScanlines(int count) override { |
| + //when ongetScanlines is called it will skip to fCurrentRow |
| + fCurrentRow += count; |
| + return SkImageGenerator::kSuccess; |
| + } |
| + |
| + void onFinish() override { |
| + fCodec->finish(); |
| + } |
| + |
| + bool onReallyHasAlpha() const override { return fHasAlpha; } |
| + |
| +private: |
| + SkPngCodec* fCodec; // Unowned. |
| + bool fHasAlpha; |
| + int fCurrentRow; |
| + int fHeight; |
| + int fSrcRowBytes; |
| + bool fRewindNeeded; |
| + SkAutoMalloc fGarbageRow; |
| + uint8_t* fGarbageRowPtr; |
| + |
| + |
| + |
| + |
| + |
| + typedef SkScanlineDecoder INHERITED; |
| +}; |
| + |
| + |
| SkScanlineDecoder* SkPngCodec::onGetScanlineDecoder(const SkImageInfo& dstInfo, |
| const Options& options, SkPMColor ctable[], int* ctableCount) { |
| if (!this->handleRewind()) { |
| @@ -675,8 +767,8 @@ SkScanlineDecoder* SkPngCodec::onGetScanlineDecoder(const SkImageInfo& dstInfo, |
| SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); |
| if (fNumberPasses > 1) { |
| - // We cannot efficiently do scanline decoding. |
| - return NULL; |
| + // interlaced image |
| + return SkNEW_ARGS(SkPngInterlacedScanlineDecoder, (dstInfo, this)); |
| } |
| return SkNEW_ARGS(SkPngScanlineDecoder, (dstInfo, this)); |