Incremental decode: only use subset for subsetting

In the initial patch, we modified the subset passed to incremental
decoding to account for sampling in Y. This allowed SkSampledCodec to
use a tighter bounds. But it also means that the implementation cannot
distinguish between lines that are excluded due to subsetting and those
excluded at the beginning and end due to sampling. This becomes
problematic in GIF (crrev.com/2045293002), which may need to fill,
requiring it to reconstruct the actual destination. In truth,
SkGifCodec does not need to support subsets, but cannot distinguish
between the tighter bounds and a true subset.

Fix this by passing the scaled subset to incremental decode, without
using the tighter bounds.

Make SkSampler::rowNeeded take the starting coordinate into account.

In SkPngCodec, compute the number of rows needed in the output, and use
that as a signal to stop.
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2420843003

Review-Url: https://codereview.chromium.org/2420843003
diff --git a/src/codec/SkPngCodec.cpp b/src/codec/SkPngCodec.cpp
index 9f8722f..7083137 100644
--- a/src/codec/SkPngCodec.cpp
+++ b/src/codec/SkPngCodec.cpp
@@ -458,7 +458,6 @@
     SkPngNormalDecoder(const SkEncodedInfo& info, const SkImageInfo& imageInfo, SkStream* stream,
             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)
@@ -481,12 +480,6 @@
 #endif
 
 private:
-    // 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;
@@ -494,6 +487,7 @@
     // Variables for partial decode
     int                         fFirstRow;  // FIXME: Move to baseclass?
     int                         fLastRow;
+    int                         fRowsNeeded;
 
     typedef SkPngCodec INHERITED;
 
@@ -545,14 +539,18 @@
         fLastRow = lastRow;
         fDst = dst;
         fRowBytes = rowBytes;
-        fLinesDecoded = 0;
         fRowsWrittenToOutput = 0;
+        fRowsNeeded = fLastRow - fFirstRow + 1;
     }
 
     SkCodec::Result decode(int* rowsDecoded) override {
+        if (this->swizzler()) {
+            const int sampleY = this->swizzler()->sampleY();
+            fRowsNeeded = get_scaled_dimension(fLastRow - fFirstRow + 1, sampleY);
+        }
         this->processData();
 
-        if (fLinesDecoded == fLastRow - fFirstRow + 1) {
+        if (fRowsWrittenToOutput == fRowsNeeded) {
             return SkCodec::kSuccess;
         }
 
@@ -570,17 +568,16 @@
         }
 
         SkASSERT(rowNum <= fLastRow);
+        SkASSERT(fRowsWrittenToOutput < fRowsNeeded);
 
         // If there is no swizzler, all rows are needed.
-        if (!this->swizzler() || this->swizzler()->rowNeeded(fLinesDecoded)) {
+        if (!this->swizzler() || this->swizzler()->rowNeeded(rowNum - fFirstRow)) {
             this->applyXformRow(fDst, row);
             fDst = SkTAddOffset<void>(fDst, fRowBytes);
             fRowsWrittenToOutput++;
         }
 
-        fLinesDecoded++;
-
-        if (rowNum == fLastRow) {
+        if (fRowsWrittenToOutput == fRowsNeeded) {
             // Fake error to stop decoding scanlines.
             longjmp(PNG_JMPBUF(this->png_ptr()), kStopDecoding);
         }
@@ -722,17 +719,17 @@
             }
             return SkCodec::kIncompleteInput;
         }
-        const int lastRow = fLinesDecoded + fFirstRow - 1;
-        SkASSERT(lastRow <= fLastRow);
 
+        const int sampleY = this->swizzler() ? this->swizzler()->sampleY() : 1;
+        const int rowsNeeded = get_scaled_dimension(fLastRow - fFirstRow + 1, sampleY);
         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();
-        const int sampleY = this->swizzler() ? this->swizzler()->sampleY() : 1;
         void* dst = fDst;
-        for (int rowNum = fFirstRow; rowNum <= lastRow; rowNum += sampleY) {
+        for (int rowNum = fFirstRow + get_start_coord(sampleY); rowsWrittenToOutput < rowsNeeded;
+                rowNum += sampleY) {
             this->applyXformRow(dst, srcRow);
             dst = SkTAddOffset<void>(dst, fRowBytes);
             srcRow = SkTAddOffset<png_byte>(srcRow, fPng_rowbytes * sampleY);