Chromium Code Reviews| Index: src/codec/SkCodec_libpng.cpp |
| diff --git a/src/codec/SkCodec_libpng.cpp b/src/codec/SkCodec_libpng.cpp |
| index 2ba2d5bb9f2bed42209d9c2ca5b0ce4ce127bba0..24c835191ccf4f20855eee460129644c9862c610 100644 |
| --- a/src/codec/SkCodec_libpng.cpp |
| +++ b/src/codec/SkCodec_libpng.cpp |
| @@ -12,7 +12,6 @@ |
| #include "SkBitmap.h" |
| #include "SkMath.h" |
| #include "SkScaledCodec.h" |
| -#include "SkScanlineDecoder.h" |
| #include "SkSize.h" |
| #include "SkStream.h" |
| #include "SkSwizzler.h" |
| @@ -163,7 +162,10 @@ bool SkPngCodec::decodePalette(bool premultiply, int* ctableCount) { |
| palette++; |
| } |
| - fReallyHasAlpha = transLessThanFF < 0; |
| + if (transLessThanFF >= 0) { |
|
scroggo
2015/09/25 16:07:49
If I understand this code correctly, the old code
msarett
2015/09/28 14:48:50
I agree with this interpretation.
In this case, w
scroggo
2015/09/28 16:01:52
Well, swizzle() returns the alpha value, and I don
|
| + // No transparent colors were found. |
| + fAlphaState = kOpaque_AlphaState; |
| + } |
| for (; index < numPalette; index++) { |
| *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette->blue); |
| @@ -216,7 +218,8 @@ bool SkPngCodec::IsPng(SkStream* stream) { |
| // png_destroy_read_struct. If it returns false, the passed in fields (except |
| // stream) are unchanged. |
| static bool read_header(SkStream* stream, png_structp* png_ptrp, |
| - png_infop* info_ptrp, SkImageInfo* imageInfo, int* bitDepthPtr) { |
| + png_infop* info_ptrp, SkImageInfo* imageInfo, |
| + int* bitDepthPtr, int* numberPassesPtr) { |
| // The image is known to be a PNG. Decode enough to know the SkImageInfo. |
| png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, |
| sk_error_fn, sk_warning_fn); |
| @@ -333,6 +336,11 @@ static bool read_header(SkStream* stream, png_structp* png_ptrp, |
| SkASSERT(false); |
| } |
| + int numberPasses = png_set_interlace_handling(png_ptr); |
| + if (numberPassesPtr) { |
| + *numberPassesPtr = numberPasses; |
| + } |
| + |
| // FIXME: Also need to check for sRGB (skbug.com/3471). |
| if (imageInfo) { |
| @@ -349,29 +357,21 @@ static bool read_header(SkStream* stream, png_structp* png_ptrp, |
| return true; |
| } |
| -SkCodec* SkPngCodec::NewFromStream(SkStream* stream) { |
| - SkAutoTDelete<SkStream> streamDeleter(stream); |
| - png_structp png_ptr; |
| - png_infop info_ptr; |
| - SkImageInfo imageInfo; |
| - int bitDepth; |
| - if (read_header(stream, &png_ptr, &info_ptr, &imageInfo, &bitDepth)) { |
| - return new SkPngCodec(imageInfo, streamDeleter.detach(), png_ptr, info_ptr, bitDepth); |
| - } |
| - return nullptr; |
| -} |
| - |
| -#define INVALID_NUMBER_PASSES -1 |
| SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, |
| - png_structp png_ptr, png_infop info_ptr, int bitDepth) |
| + png_structp png_ptr, png_infop info_ptr, int bitDepth, int numberPasses) |
| : INHERITED(info, stream) |
| , fPng_ptr(png_ptr) |
| , fInfo_ptr(info_ptr) |
| , fSrcConfig(SkSwizzler::kUnknown) |
| - , fNumberPasses(INVALID_NUMBER_PASSES) |
| - , fReallyHasAlpha(false) |
| + , fNumberPasses(numberPasses) |
| , fBitDepth(bitDepth) |
| -{} |
| +{ |
| + if (info.alphaType() == kOpaque_SkAlphaType) { |
| + fAlphaState = kOpaque_AlphaState; |
| + } else { |
| + fAlphaState = kUnknown_AlphaState; |
| + } |
| +} |
| SkPngCodec::~SkPngCodec() { |
| this->destroyReadStruct(); |
| @@ -401,13 +401,9 @@ SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo, |
| SkCodecPrintf("setjmp long jump!\n"); |
| return kInvalidInput; |
| } |
| - fNumberPasses = png_set_interlace_handling(fPng_ptr); |
| png_read_update_info(fPng_ptr, fInfo_ptr); |
| - // Set to the default before calling decodePalette, which may change it. |
| - fReallyHasAlpha = false; |
| - |
| - //srcColorType was determined in readHeader() which determined png color type |
| + //srcColorType was determined in read_header() which determined png color type |
| const SkColorType srcColorType = this->getInfo().colorType(); |
| switch (srcColorType) { |
| @@ -459,7 +455,7 @@ bool SkPngCodec::onRewind() { |
| png_structp png_ptr; |
| png_infop info_ptr; |
| - if (!read_header(this->stream(), &png_ptr, &info_ptr, nullptr, nullptr)) { |
| + if (!read_header(this->stream(), &png_ptr, &info_ptr, nullptr, nullptr, nullptr)) { |
| return false; |
| } |
| @@ -498,7 +494,8 @@ SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* |
| return kInvalidInput; |
| } |
| - SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); |
| + bool hasAlpha = false; |
| + // FIXME: We could split these out based on subclass. |
|
msarett
2015/09/28 14:48:50
Yeah it really feels like these should be separate
|
| SkAutoMalloc storage; |
| void* dstRow = dst; |
| if (fNumberPasses > 1) { |
| @@ -522,7 +519,7 @@ SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* |
| // Now swizzle it. |
| uint8_t* srcRow = base; |
| for (int y = 0; y < height; y++) { |
| - fReallyHasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow, srcRow)); |
| + hasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow, srcRow)); |
| dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); |
| srcRow += srcRowBytes; |
| } |
| @@ -531,11 +528,17 @@ SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* |
| uint8_t* srcRow = static_cast<uint8_t*>(storage.get()); |
| for (int y = 0; y < requestedInfo.height(); y++) { |
| png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1); |
| - fReallyHasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow, srcRow)); |
| + hasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow, srcRow)); |
| dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); |
| } |
| } |
| + if (hasAlpha) { |
| + fAlphaState = kHasAlpha_AlphaState; |
| + } else { |
| + fAlphaState = kOpaque_AlphaState; |
| + } |
| + |
| // FIXME: do we need substituteTranspColor? Note that we cannot do it for |
| // scanline decoding, but we could do it here. Alternatively, we could do |
| // it as we go, instead of in post-processing like SkPNGImageDecoder. |
| @@ -547,136 +550,166 @@ SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* |
| // read rest of file, and get additional comment and time chunks in info_ptr |
| png_read_end(fPng_ptr, fInfo_ptr); |
| + |
| return kSuccess; |
| } |
| -class SkPngScanlineDecoder : public SkScanlineDecoder { |
| +bool SkPngCodec::onReallyHasAlpha() const { |
| + switch (fAlphaState) { |
| + case kOpaque_AlphaState: |
| + return false; |
| + case kUnknown_AlphaState: |
| + // Maybe the subclass knows? |
| + return this->alphaInScanlineDecode() == kHasAlpha_AlphaState; |
| + case kHasAlpha_AlphaState: |
| + switch (this->alphaInScanlineDecode()) { |
| + case kUnknown_AlphaState: |
| + // Scanline decoder must not have been used. Return our knowledge. |
| + return true; |
| + case kOpaque_AlphaState: |
| + // Scanline decoder was used, and did not find alpha in its subset. |
| + return false; |
| + case kHasAlpha_AlphaState: |
| + return true; |
| + } |
| + } |
| +} |
| + |
| +// Subclass of SkPngCodec which supports scanline decoding |
| +class SkPngScanlineDecoder : public SkPngCodec { |
| public: |
| - SkPngScanlineDecoder(const SkImageInfo& srcInfo, SkPngCodec* codec) |
| - : INHERITED(srcInfo) |
| - , fCodec(codec) |
| - , fHasAlpha(false) |
| + SkPngScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream, |
| + png_structp png_ptr, png_infop info_ptr, int bitDepth) |
| + : INHERITED(srcInfo, stream, png_ptr, info_ptr, bitDepth, 1) |
| + , fSrcRow(nullptr) |
| + , fAlphaState(kUnknown_AlphaState) |
| {} |
| - SkCodec::Result onStart(const SkImageInfo& dstInfo, |
| - const SkCodec::Options& options, |
| - SkPMColor ctable[], int* ctableCount) override { |
| - if (!fCodec->rewindIfNeeded()) { |
| - return SkCodec::kCouldNotRewind; |
| + Result onStart(const SkImageInfo& dstInfo, const Options& options, |
| + SkPMColor ctable[], int* ctableCount) override { |
| + if (!this->rewindIfNeeded()) { |
| + return kCouldNotRewind; |
| } |
| if (!conversion_possible(dstInfo, this->getInfo())) { |
| - return SkCodec::kInvalidConversion; |
| + return kInvalidConversion; |
| } |
| // Check to see if scaling was requested. |
| if (dstInfo.dimensions() != this->getInfo().dimensions()) { |
| if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) { |
| - return SkCodec::kInvalidScale; |
| + return kInvalidScale; |
| } |
| } |
| - const SkCodec::Result result = fCodec->initializeSwizzler(dstInfo, options, ctable, |
| - ctableCount); |
| - if (result != SkCodec::kSuccess) { |
| + const Result result = this->initializeSwizzler(dstInfo, options, ctable, |
| + ctableCount); |
| + if (result != kSuccess) { |
| return result; |
| } |
| - fHasAlpha = false; |
| - fStorage.reset(this->getInfo().width() * SkSwizzler::BytesPerPixel(fCodec->fSrcConfig)); |
| + fAlphaState = kUnknown_AlphaState; |
| + fStorage.reset(this->getInfo().width() * SkSwizzler::BytesPerPixel(this->srcConfig())); |
| fSrcRow = static_cast<uint8_t*>(fStorage.get()); |
| - return SkCodec::kSuccess; |
| + return kSuccess; |
| } |
| - SkCodec::Result onGetScanlines(void* dst, int count, size_t rowBytes) override { |
| - if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { |
| + Result onGetScanlines(void* dst, int count, size_t rowBytes) override { |
| + if (setjmp(png_jmpbuf(this->png_ptr()))) { |
| SkCodecPrintf("setjmp long jump!\n"); |
| - return SkCodec::kInvalidInput; |
| + return kInvalidInput; |
| } |
| void* dstRow = dst; |
| + bool hasAlpha = false; |
| for (int i = 0; i < count; i++) { |
| - png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1); |
| - fHasAlpha |= !SkSwizzler::IsOpaque(fCodec->fSwizzler->swizzle(dstRow, fSrcRow)); |
| + png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1); |
| + hasAlpha |= !SkSwizzler::IsOpaque(this->swizzler()->swizzle(dstRow, fSrcRow)); |
| dstRow = SkTAddOffset<void>(dstRow, rowBytes); |
| } |
| - return SkCodec::kSuccess; |
| + |
| + if (hasAlpha) { |
| + fAlphaState = kHasAlpha_AlphaState; |
| + } else { |
| + if (kUnknown_AlphaState == fAlphaState) { |
| + fAlphaState = kOpaque_AlphaState; |
| + } |
| + // Otherwise, the AlphaState is unchanged. |
| + } |
| + |
| + return kSuccess; |
| } |
| - SkCodec::Result onSkipScanlines(int count) override { |
| + Result onSkipScanlines(int count) override { |
| // FIXME: Could we use the return value of setjmp to specify the type of |
| // error? |
| - if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { |
| + if (setjmp(png_jmpbuf(this->png_ptr()))) { |
| SkCodecPrintf("setjmp long jump!\n"); |
| - return SkCodec::kInvalidInput; |
| + return kInvalidInput; |
| } |
| //there is a potential tradeoff of memory vs speed created by putting this in a loop. |
| //calling png_read_rows in a loop is insignificantly slower than calling it once with count |
| //as png_read_rows has it's own loop which calls png_read_row count times. |
| for (int i = 0; i < count; i++) { |
| - png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1); |
| + png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1); |
| } |
| return SkCodec::kSuccess; |
| } |
| - bool onReallyHasAlpha() const override { return fHasAlpha; } |
| - |
| - SkEncodedFormat onGetEncodedFormat() const override { |
| - return kPNG_SkEncodedFormat; |
| + AlphaState alphaInScanlineDecode() const override { |
| + return fAlphaState; |
| } |
| - |
| private: |
| - SkAutoTDelete<SkPngCodec> fCodec; |
| - bool fHasAlpha; |
| + AlphaState fAlphaState; |
| SkAutoMalloc fStorage; |
| uint8_t* fSrcRow; |
| - typedef SkScanlineDecoder INHERITED; |
| + typedef SkPngCodec INHERITED; |
| }; |
| -class SkPngInterlacedScanlineDecoder : public SkScanlineDecoder { |
| +class SkPngInterlacedScanlineDecoder : public SkPngCodec { |
| public: |
| - SkPngInterlacedScanlineDecoder(const SkImageInfo& srcInfo, SkPngCodec* codec) |
| - : INHERITED(srcInfo) |
| - , fCodec(codec) |
| - , fHasAlpha(false) |
| - , fCurrentRow(0) |
| - , fHeight(srcInfo.height()) |
| + SkPngInterlacedScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream, |
| + png_structp png_ptr, png_infop info_ptr, int bitDepth, int numberPasses) |
| + : INHERITED(srcInfo, stream, png_ptr, info_ptr, bitDepth, numberPasses) |
| + , fAlphaState(kUnknown_AlphaState) |
| + , fHeight(-1) |
| , fCanSkipRewind(false) |
| - {} |
| + { |
| + SkASSERT(numberPasses != 1); |
| + } |
| - SkCodec::Result onStart(const SkImageInfo& dstInfo, |
| - const SkCodec::Options& options, |
| - SkPMColor ctable[], int* ctableCount) override |
| + Result onStart(const SkImageInfo& dstInfo, const Options& options, |
| + SkPMColor ctable[], int* ctableCount) override |
| { |
| - if (!fCodec->rewindIfNeeded()) { |
| - return SkCodec::kCouldNotRewind; |
| + if (!this->rewindIfNeeded()) { |
| + return kCouldNotRewind; |
| } |
| if (!conversion_possible(dstInfo, this->getInfo())) { |
| - return SkCodec::kInvalidConversion; |
| + return kInvalidConversion; |
| } |
| // Check to see if scaling was requested. |
| if (dstInfo.dimensions() != this->getInfo().dimensions()) { |
| if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) { |
| - return SkCodec::kInvalidScale; |
| + return kInvalidScale; |
| } |
| } |
| - const SkCodec::Result result = fCodec->initializeSwizzler(dstInfo, options, ctable, |
| - ctableCount); |
| - if (result != SkCodec::kSuccess) { |
| + const Result result = this->initializeSwizzler(dstInfo, options, ctable, |
| + ctableCount); |
| + if (result != kSuccess) { |
| return result; |
| } |
| - fHasAlpha = false; |
| - fCurrentRow = 0; |
| + fAlphaState = kUnknown_AlphaState; |
| fHeight = dstInfo.height(); |
| - fSrcRowBytes = this->getInfo().width() * SkSwizzler::BytesPerPixel(fCodec->fSrcConfig); |
| + // FIXME: This need not be called on a second call to onStart. |
| + fSrcRowBytes = this->getInfo().width() * SkSwizzler::BytesPerPixel(this->srcConfig()); |
| fGarbageRow.reset(fSrcRowBytes); |
| fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); |
| fCanSkipRewind = true; |
| @@ -684,73 +717,90 @@ public: |
| return SkCodec::kSuccess; |
| } |
| - SkCodec::Result onGetScanlines(void* dst, int count, size_t dstRowBytes) override { |
| + 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 (fCanSkipRewind) { |
| // We already rewound in onStart, so there is no reason to rewind. |
| // Next time onGetScanlines is called, we will need to rewind. |
| fCanSkipRewind = false; |
| - } else if (!fCodec->rewindIfNeeded()) { |
| - return SkCodec::kCouldNotRewind; |
| + } else { |
| + // rewindIfNeeded resets fCurrScanline, since it assumes that start |
| + // needs to be called again before scanline decoding. PNG scanline |
| + // decoding is the exception, since it needs to rewind between |
| + // calls to getScanlines. Keep track of fCurrScanline, to undo the |
| + // reset. |
| + const int currScanline = this->onGetY(); |
| + // This method would never be called if currScanline is -1 |
| + SkASSERT(currScanline != -1); |
| + |
| + if (!this->rewindIfNeeded()) { |
| + return kCouldNotRewind; |
| + } |
| + this->updateY(currScanline); |
| } |
| - if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { |
| + if (setjmp(png_jmpbuf(this->png_ptr()))) { |
| SkCodecPrintf("setjmp long jump!\n"); |
| - return SkCodec::kInvalidInput; |
| + return 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); |
| + const int startRow = this->onGetY(); |
| + for (int i = 0; i < this->numberPasses(); i++) { |
| + // read rows we planned to skip into garbage row |
| + for (int y = 0; y < startRow; y++){ |
| + png_read_rows(this->png_ptr(), &fGarbageRowPtr, png_bytepp_NULL, 1); |
| } |
| - //read rows we care about into buffer |
| + // 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); |
| + png_read_rows(this->png_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); |
| + // read rows we don't want into garbage buffer |
| + for (int y = 0; y < fHeight - startRow - count; y++) { |
| + png_read_rows(this->png_ptr(), &fGarbageRowPtr, png_bytepp_NULL, 1); |
| } |
| } |
| //swizzle the rows we care about |
| srcRow = storagePtr; |
| void* dstRow = dst; |
| + bool hasAlpha = false; |
| for (int y = 0; y < count; y++) { |
| - fHasAlpha |= !SkSwizzler::IsOpaque(fCodec->fSwizzler->swizzle(dstRow, srcRow)); |
| + hasAlpha |= !SkSwizzler::IsOpaque(this->swizzler()->swizzle(dstRow, srcRow)); |
| dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); |
| srcRow += fSrcRowBytes; |
| } |
| - fCurrentRow += count; |
| - return SkCodec::kSuccess; |
| + |
| + if (hasAlpha) { |
| + fAlphaState = kHasAlpha_AlphaState; |
| + } else { |
| + if (kUnknown_AlphaState == fAlphaState) { |
| + fAlphaState = kOpaque_AlphaState; |
| + } |
| + // Otherwise, the AlphaState is unchanged. |
| + } |
| + |
| + return kSuccess; |
| } |
| SkCodec::Result onSkipScanlines(int count) override { |
| - //when ongetScanlines is called it will skip to fCurrentRow |
| - fCurrentRow += count; |
| + // The non-virtual version will update fCurrScanline. |
| return SkCodec::kSuccess; |
| } |
| - bool onReallyHasAlpha() const override { return fHasAlpha; } |
| + AlphaState alphaInScanlineDecode() const override { |
| + return fAlphaState; |
| + } |
| SkScanlineOrder onGetScanlineOrder() const override { |
| return kNone_SkScanlineOrder; |
| } |
| - SkEncodedFormat onGetEncodedFormat() const override { |
| - return kPNG_SkEncodedFormat; |
| - } |
| - |
| private: |
| - SkAutoTDelete<SkPngCodec> fCodec; |
| - bool fHasAlpha; |
| - int fCurrentRow; |
| + AlphaState fAlphaState; |
| int fHeight; |
| size_t fSrcRowBytes; |
| SkAutoMalloc fGarbageRow; |
| @@ -765,24 +815,27 @@ private: |
| // layer. |
| bool fCanSkipRewind; |
| - typedef SkScanlineDecoder INHERITED; |
| + typedef SkPngCodec INHERITED; |
| }; |
| -SkScanlineDecoder* SkPngCodec::NewSDFromStream(SkStream* stream) { |
| - SkAutoTDelete<SkPngCodec> codec (static_cast<SkPngCodec*>(SkPngCodec::NewFromStream(stream))); |
| - if (!codec) { |
| +SkCodec* SkPngCodec::NewFromStream(SkStream* stream) { |
| + SkAutoTDelete<SkStream> streamDeleter(stream); |
| + png_structp png_ptr; |
| + png_infop info_ptr; |
| + SkImageInfo imageInfo; |
| + int bitDepth; |
| + int numberPasses; |
| + |
| + if (!read_header(stream, &png_ptr, &info_ptr, &imageInfo, &bitDepth, &numberPasses)) { |
| return nullptr; |
| } |
| - codec->fNumberPasses = png_set_interlace_handling(codec->fPng_ptr); |
| - SkASSERT(codec->fNumberPasses != INVALID_NUMBER_PASSES); |
| - |
| - const SkImageInfo& srcInfo = codec->getInfo(); |
| - if (codec->fNumberPasses > 1) { |
| - // interlaced image |
| - return new SkPngInterlacedScanlineDecoder(srcInfo, codec.detach()); |
| + if (1 == numberPasses) { |
| + return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), png_ptr, info_ptr, |
| + bitDepth); |
| } |
| - return new SkPngScanlineDecoder(srcInfo, codec.detach()); |
| + return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(), png_ptr, |
| + info_ptr, bitDepth, numberPasses); |
| } |