| Index: src/codec/SkCodec_libpng.cpp
|
| diff --git a/src/codec/SkCodec_libpng.cpp b/src/codec/SkCodec_libpng.cpp
|
| index 9f9c110cc68bcc06ed9d38c7c272cdecea42341a..d29ca8a2a300bbc2635a93c05b6b8c33d1fca220 100644
|
| --- a/src/codec/SkCodec_libpng.cpp
|
| +++ b/src/codec/SkCodec_libpng.cpp
|
| @@ -594,13 +594,40 @@ SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void*
|
|
|
| class SkPngScanlineDecoder : public SkScanlineDecoder {
|
| public:
|
| - SkPngScanlineDecoder(const SkImageInfo& dstInfo, SkPngCodec* codec)
|
| - : INHERITED(dstInfo)
|
| + SkPngScanlineDecoder(const SkImageInfo& srcInfo, SkPngCodec* codec)
|
| + : INHERITED(srcInfo)
|
| , fCodec(codec)
|
| , fHasAlpha(false)
|
| + {}
|
| +
|
| + SkCodec::Result onStart(const SkImageInfo& dstInfo,
|
| + const SkCodec::Options& options,
|
| + SkPMColor ctable[], int* ctableCount) override
|
| {
|
| + if (!fCodec->handleRewind()) {
|
| + return SkCodec::kCouldNotRewind;
|
| + }
|
| +
|
| + if (!conversion_possible(dstInfo, this->getInfo())) {
|
| + return SkCodec::kInvalidConversion;
|
| + }
|
| +
|
| + // Check to see if scaling was requested.
|
| + if (dstInfo.dimensions() != this->getInfo().dimensions()) {
|
| + return SkCodec::kInvalidScale;
|
| + }
|
| +
|
| + const SkCodec::Result result = fCodec->initializeSwizzler(dstInfo, options, ctable,
|
| + ctableCount);
|
| + if (result != SkCodec::kSuccess) {
|
| + return result;
|
| + }
|
| +
|
| + fHasAlpha = false;
|
| fStorage.reset(dstInfo.width() * SkSwizzler::BytesPerPixel(fCodec->fSrcConfig));
|
| fSrcRow = static_cast<uint8_t*>(fStorage.get());
|
| +
|
| + return SkCodec::kSuccess;
|
| }
|
|
|
| SkCodec::Result onGetScanlines(void* dst, int count, size_t rowBytes) override {
|
| @@ -648,24 +675,60 @@ private:
|
|
|
| class SkPngInterlacedScanlineDecoder : public SkScanlineDecoder {
|
| public:
|
| - SkPngInterlacedScanlineDecoder(const SkImageInfo& dstInfo, SkPngCodec* codec)
|
| - : INHERITED(dstInfo)
|
| + SkPngInterlacedScanlineDecoder(const SkImageInfo& srcInfo, SkPngCodec* codec)
|
| + : INHERITED(srcInfo)
|
| , fCodec(codec)
|
| , fHasAlpha(false)
|
| , fCurrentRow(0)
|
| - , fHeight(dstInfo.height())
|
| + , fHeight(srcInfo.height())
|
| + , fCanSkipRewind(false)
|
| + {}
|
| +
|
| + SkCodec::Result onStart(const SkImageInfo& dstInfo,
|
| + const SkCodec::Options& options,
|
| + SkPMColor ctable[], int* ctableCount) override
|
| {
|
| + if (!fCodec->handleRewind()) {
|
| + return SkCodec::kCouldNotRewind;
|
| + }
|
| +
|
| + if (!conversion_possible(dstInfo, this->getInfo())) {
|
| + return SkCodec::kInvalidConversion;
|
| + }
|
| +
|
| + // Check to see if scaling was requested.
|
| + if (dstInfo.dimensions() != this->getInfo().dimensions()) {
|
| + return SkCodec::kInvalidScale;
|
| + }
|
| +
|
| + const SkCodec::Result result = fCodec->initializeSwizzler(dstInfo, options, ctable,
|
| + ctableCount);
|
| + if (result != SkCodec::kSuccess) {
|
| + return result;
|
| + }
|
| +
|
| + fHasAlpha = false;
|
| + fCurrentRow = 0;
|
| + fHeight = dstInfo.height();
|
| fSrcRowBytes = dstInfo.width() * SkSwizzler::BytesPerPixel(fCodec->fSrcConfig);
|
| fGarbageRow.reset(fSrcRowBytes);
|
| fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get());
|
| + fCanSkipRewind = true;
|
| +
|
| + return SkCodec::kSuccess;
|
| }
|
|
|
| SkCodec::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 (!fCodec->handleRewind()) {
|
| + // 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->handleRewind()) {
|
| return SkCodec::kCouldNotRewind;
|
| }
|
| +
|
| if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) {
|
| SkCodecPrintf("setjmp long jump!\n");
|
| return SkCodec::kInvalidInput;
|
| @@ -718,42 +781,34 @@ private:
|
| size_t fSrcRowBytes;
|
| SkAutoMalloc fGarbageRow;
|
| uint8_t* fGarbageRowPtr;
|
| + // FIXME: This imitates behavior in SkCodec::rewindIfNeeded. That function
|
| + // is called whenever some action is taken that reads the stream and
|
| + // therefore the next call will require a rewind. So it modifies a boolean
|
| + // to note that the *next* time it is called a rewind is needed.
|
| + // SkPngInterlacedScanlineDecoder has an extra wrinkle - calling onStart
|
| + // followed by onGetScanlines does *not* require a rewind. Since
|
| + // rewindIfNeeded does not have this flexibility, we need to add another
|
| + // layer.
|
| + bool fCanSkipRewind;
|
|
|
| typedef SkScanlineDecoder INHERITED;
|
| };
|
|
|
| -
|
| -SkScanlineDecoder* SkPngCodec::onGetScanlineDecoder(const SkImageInfo& dstInfo,
|
| - const Options& options, SkPMColor ctable[], int* ctableCount) {
|
| - if (!conversion_possible(dstInfo, this->getInfo())) {
|
| - SkCodecPrintf("no conversion possible\n");
|
| - return NULL;
|
| - }
|
| - // Check to see if scaling was requested.
|
| - if (dstInfo.dimensions() != this->getInfo().dimensions()) {
|
| - return NULL;
|
| - }
|
| - // Create a new SkPngCodec, to be owned by the scanline decoder.
|
| - SkStream* stream = this->stream()->duplicate();
|
| - if (!stream) {
|
| - return NULL;
|
| - }
|
| +SkScanlineDecoder* SkPngCodec::NewSDFromStream(SkStream* stream) {
|
| SkAutoTDelete<SkPngCodec> codec (static_cast<SkPngCodec*>(SkPngCodec::NewFromStream(stream)));
|
| if (!codec) {
|
| return NULL;
|
| }
|
|
|
| - if (codec->initializeSwizzler(dstInfo, options, ctable, ctableCount) != kSuccess) {
|
| - SkCodecPrintf("failed to initialize the swizzler.\n");
|
| - return NULL;
|
| - }
|
| -
|
| + 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 SkNEW_ARGS(SkPngInterlacedScanlineDecoder, (dstInfo, codec.detach()));
|
| + return SkNEW_ARGS(SkPngInterlacedScanlineDecoder, (srcInfo, codec.detach()));
|
| }
|
|
|
| - return SkNEW_ARGS(SkPngScanlineDecoder, (dstInfo, codec.detach()));
|
| + return SkNEW_ARGS(SkPngScanlineDecoder, (srcInfo, codec.detach()));
|
| }
|
|
|
|
|