| Index: src/codec/SkCodec_libpng.cpp
|
| diff --git a/src/codec/SkCodec_libpng.cpp b/src/codec/SkCodec_libpng.cpp
|
| index c2a032e84ea8d98017998bdf5e6f9e12bf059685..444e2ad87e0ae14a3bfd95746fd991f592c7ceca 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;
|
| + }
|
| + 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;
|
| + size_t 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));
|
|
|