| Index: src/codec/SkPngCodec.cpp | 
| diff --git a/src/codec/SkPngCodec.cpp b/src/codec/SkPngCodec.cpp | 
| index 1344a7e773c6ad52c738a47aa62253f9cdce499f..5e364553a3ce6bdc3afc6f094041b73e538a1b04 100644 | 
| --- a/src/codec/SkPngCodec.cpp | 
| +++ b/src/codec/SkPngCodec.cpp | 
| @@ -515,6 +515,7 @@ public: | 
| SkPngChunkReader* reader, png_structp png_ptr, png_infop info_ptr, int bitDepth) | 
| : INHERITED(info, imageInfo, stream, reader, png_ptr, info_ptr, bitDepth) | 
| , fLinesDecoded(0) | 
| +        , fRowsWrittenToOutput(0) | 
| , fDst(nullptr) | 
| , fRowBytes(0) | 
| , fFirstRow(0) | 
| @@ -536,7 +537,13 @@ public: | 
| #endif | 
|  | 
| private: | 
| -    int                         fLinesDecoded; // FIXME: Move to baseclass? | 
| +    // This represents the number of lines reported by libpng, minus any we skipped at the | 
| +    // beginning. Only used when we are skipping lines (i.e. not in decodeAllRows). | 
| +    int                         fLinesDecoded; | 
| +    // While fLinesDecoded include lines that we skipped, this only includes lines written to the | 
| +    // output so we can report it to the caller for filling. | 
| +    // FIXME: Can we remove fLinesDecoded and just rely on fRowsWrittenToOutput? | 
| +    int                         fRowsWrittenToOutput; | 
| void*                       fDst; | 
| size_t                      fRowBytes; | 
|  | 
| @@ -560,26 +567,26 @@ private: | 
| fDst = dst; | 
| fRowBytes = rowBytes; | 
|  | 
| -        fLinesDecoded = 0; | 
| +        fRowsWrittenToOutput = 0; | 
| fFirstRow = 0; | 
| fLastRow = height - 1; | 
|  | 
| this->processData(); | 
|  | 
| -        if (fLinesDecoded == height) { | 
| +        if (fRowsWrittenToOutput == height) { | 
| return SkCodec::kSuccess; | 
| } | 
|  | 
| if (rowsDecoded) { | 
| -            *rowsDecoded = fLinesDecoded; | 
| +            *rowsDecoded = fRowsWrittenToOutput; | 
| } | 
|  | 
| return SkCodec::kIncompleteInput; | 
| } | 
|  | 
| void allRowsCallback(png_bytep row, int rowNum) { | 
| -        SkASSERT(rowNum == fLinesDecoded); | 
| -        fLinesDecoded++; | 
| +        SkASSERT(rowNum == fRowsWrittenToOutput); | 
| +        fRowsWrittenToOutput++; | 
| this->applyXformRow(fDst, row); | 
| fDst = SkTAddOffset<void>(fDst, fRowBytes); | 
| } | 
| @@ -595,6 +602,7 @@ private: | 
| fDst = dst; | 
| fRowBytes = rowBytes; | 
| fLinesDecoded = 0; | 
| +        fRowsWrittenToOutput = 0; | 
| } | 
|  | 
| SkCodec::Result decode(int* rowsDecoded) override { | 
| @@ -605,7 +613,7 @@ private: | 
| } | 
|  | 
| if (rowsDecoded) { | 
| -            *rowsDecoded = fLinesDecoded; | 
| +            *rowsDecoded = fRowsWrittenToOutput; | 
| } | 
|  | 
| return SkCodec::kIncompleteInput; | 
| @@ -623,6 +631,7 @@ private: | 
| if (!this->swizzler() || this->swizzler()->rowNeeded(fLinesDecoded)) { | 
| this->applyXformRow(fDst, row); | 
| fDst = SkTAddOffset<void>(fDst, fRowBytes); | 
| +            fRowsWrittenToOutput++; | 
| } | 
|  | 
| fLinesDecoded++; | 
| @@ -772,6 +781,8 @@ private: | 
| const int lastRow = fLinesDecoded + fFirstRow - 1; | 
| SkASSERT(lastRow <= fLastRow); | 
|  | 
| +        int rowsWrittenToOutput = 0; | 
| + | 
| // FIXME: For resuming interlace, we may swizzle a row that hasn't changed. But it | 
| // may be too tricky/expensive to handle that correctly. | 
| png_bytep srcRow = fInterlaceBuffer.get(); | 
| @@ -781,6 +792,7 @@ private: | 
| this->applyXformRow(dst, srcRow); | 
| dst = SkTAddOffset<void>(dst, fRowBytes); | 
| srcRow = SkTAddOffset<png_byte>(srcRow, fPng_rowbytes * sampleY); | 
| +            rowsWrittenToOutput++; | 
| } | 
|  | 
| if (fInterlacedComplete) { | 
| @@ -788,7 +800,7 @@ private: | 
| } | 
|  | 
| if (rowsDecoded) { | 
| -            *rowsDecoded = fLinesDecoded; | 
| +            *rowsDecoded = rowsWrittenToOutput; | 
| } | 
| return SkCodec::kIncompleteInput; | 
| } | 
|  |