Update Subset benches to support interlacing and fix bugs

Instead of decoding one line at a time, if the ScanlineOrder is kNone,
decode all of the lines in one pass, and then copy the subset into the
output. This will allow us to more realistically test subset decodes
for interlaced png. It also makes running them not take forever.

Do *not* support other modes (besides kTopDown), since they are not
used by the big three we need to replace BitmapRegionDecoder
implementation (skbug.com/4428).

Fix a bug in SubsetTranslateBench and SubsetZoomBench:
When we decode another subset, we need to reset the scanline decode
first. This bug appears to have been present since the introduction of
these tests in crrev.com/1160953002

BUG=skia:4205
BUG=skia:3418

Review URL: https://codereview.chromium.org/1387233002
diff --git a/bench/nanobench.cpp b/bench/nanobench.cpp
index 4ab6ca0..b16fb13 100644
--- a/bench/nanobench.cpp
+++ b/bench/nanobench.cpp
@@ -501,6 +501,27 @@
 }
 
 /*
+ * We only run our subset benches on files that are supported by BitmapRegionDecoder:
+ * i.e. PNG, JPEG, and WEBP. We do *not* test WEBP when using codec, since we do not
+ * have a scanline decoder for WEBP, which is necessary for running the subset bench.
+ * (Another bench must be used to test WEBP, which decodes subsets natively.)
+ */
+static bool run_subset_bench(const SkString& path, bool useCodec) {
+    static const char* const exts[] = {
+        "jpg", "jpeg", "png",
+        "JPG", "JPEG", "PNG",
+    };
+
+    for (uint32_t i = 0; i < SK_ARRAY_COUNT(exts); i++) {
+        if (path.endsWith(exts[i])) {
+            return true;
+        }
+    }
+
+    return !useCodec && (path.endsWith("webp") || path.endsWith("WEBP"));
+}
+
+/*
  * Returns true if set up for a subset decode succeeds, false otherwise
  * If the set-up succeeds, the width and height parameters will be set
  */
@@ -872,8 +893,12 @@
             fSourceType = "image";
             fBenchType = useCodec ? "skcodec" : "skimagedecoder";
             while (fCurrentSubsetImage < fImages.count()) {
+                const SkString& path = fImages[fCurrentSubsetImage];
+                if (!run_subset_bench(path, useCodec)) {
+                    fCurrentSubsetImage++;
+                    continue;
+                }
                 while (fCurrentColorType < fColorTypes.count()) {
-                    const SkString& path = fImages[fCurrentSubsetImage];
                     SkColorType colorType = fColorTypes[fCurrentColorType];
                     while (fCurrentSubsetType <= kLast_SubsetType) {
                         int width = 0;
diff --git a/bench/subset/SubsetSingleBench.cpp b/bench/subset/SubsetSingleBench.cpp
index 232c159..735effa 100644
--- a/bench/subset/SubsetSingleBench.cpp
+++ b/bench/subset/SubsetSingleBench.cpp
@@ -66,30 +66,65 @@
         for (int count = 0; count < n; count++) {
             SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(fStream->duplicate()));
             const SkImageInfo info = codec->getInfo().makeColorType(fColorType);
-            SkAutoTDeleteArray<uint8_t> row(new uint8_t[info.minRowBytes()]);
+
+            SkDEBUGCODE(SkCodec::Result result =)
             codec->startScanlineDecode(info, nullptr, colors, &colorCount);
+            SkASSERT(result == SkCodec::kSuccess);
 
             SkBitmap bitmap;
             SkImageInfo subsetInfo = info.makeWH(fSubsetWidth, fSubsetHeight);
             alloc_pixels(&bitmap, subsetInfo, colors, colorCount);
 
-            codec->skipScanlines(fOffsetTop);
-            uint32_t bpp = info.bytesPerPixel();
-            for (uint32_t y = 0; y < fSubsetHeight; y++) {
-                codec->getScanlines(row.get(), 1, 0);
-                memcpy(bitmap.getAddr(0, y), row.get() + fOffsetLeft * bpp,
-                        fSubsetWidth * bpp);
+            SkDEBUGCODE(result = ) codec->skipScanlines(fOffsetTop);
+            SkASSERT(result == SkCodec::kSuccess);
+
+            const uint32_t bpp = info.bytesPerPixel();
+
+            switch (codec->getScanlineOrder()) {
+                case SkCodec::kTopDown_SkScanlineOrder: {
+                    SkAutoTDeleteArray<uint8_t> row(new uint8_t[info.minRowBytes()]);
+                    for (uint32_t y = 0; y < fSubsetHeight; y++) {
+                        SkDEBUGCODE(result = ) codec->getScanlines(row.get(), 1, 0);
+                        SkASSERT(result == SkCodec::kSuccess);
+
+                        memcpy(bitmap.getAddr(0, y), row.get() + fOffsetLeft * bpp,
+                                fSubsetWidth * bpp);
+                    }
+                    break;
+                }
+                case SkCodec::kNone_SkScanlineOrder: {
+                    // decode all scanlines that intersect the subset, and copy the subset
+                    // into the output.
+                    SkImageInfo stripeInfo = info.makeWH(info.width(), fSubsetHeight);
+                    SkBitmap stripeBm;
+                    alloc_pixels(&stripeBm, stripeInfo, colors, colorCount);
+
+                    SkDEBUGCODE(result = ) codec->getScanlines(stripeBm.getPixels(), fSubsetHeight,
+                                                               stripeBm.rowBytes());
+                    SkASSERT(result == SkCodec::kSuccess);
+
+                    for (uint32_t y = 0; y < fSubsetHeight; y++) {
+                        memcpy(bitmap.getAddr(0, y), stripeBm.getAddr(fOffsetLeft, y),
+                                fSubsetWidth * bpp);
+                    }
+                    break;
+                }
+                default:
+                    // We currently are only testing kTopDown and kNone, which are the only
+                    // two used by the subsets we care about. skbug.com/4428
+                    SkASSERT(false);
+
             }
         }
     } else {
         for (int count = 0; count < n; count++) {
             SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(fStream));
             int width, height;
-            decoder->buildTileIndex(fStream->duplicate(), &width, &height);
+            SkAssertResult(decoder->buildTileIndex(fStream->duplicate(), &width, &height));
             SkBitmap bitmap;
             SkIRect rect = SkIRect::MakeXYWH(fOffsetLeft, fOffsetTop, fSubsetWidth,
                     fSubsetHeight);
-            decoder->decodeSubset(&bitmap, rect, fColorType);
+            SkAssertResult(decoder->decodeSubset(&bitmap, rect, fColorType));
         }
     }
 }
diff --git a/bench/subset/SubsetTranslateBench.cpp b/bench/subset/SubsetTranslateBench.cpp
index 8f29ba8..d13f31a 100644
--- a/bench/subset/SubsetTranslateBench.cpp
+++ b/bench/subset/SubsetTranslateBench.cpp
@@ -53,17 +53,29 @@
     return kNonRendering_Backend == backend;
 }
 
+// Allows allocating the bitmap first, and then writing to them later (in startScanlineDecode)
+static SkPMColor* get_colors(SkBitmap* bm) {
+    SkColorTable* ct = bm->getColorTable();
+    if (!ct) {
+        return nullptr;
+    }
+
+    return const_cast<SkPMColor*>(ct->readColors());
+}
+
 void SubsetTranslateBench::onDraw(int n, SkCanvas* canvas) {
     // When the color type is kIndex8, we will need to store the color table.  If it is
     // used, it will be initialized by the codec.
-    int colorCount;
+    int colorCount = 256;
     SkPMColor colors[256];
     if (fUseCodec) {
         for (int count = 0; count < n; count++) {
             SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(fStream->duplicate()));
             const SkImageInfo info = codec->getInfo().makeColorType(fColorType);
-            SkAutoTDeleteArray<uint8_t> row(new uint8_t[info.minRowBytes()]);
-            codec->startScanlineDecode(info, nullptr, colors, &colorCount);
+            SkAutoTDeleteArray<uint8_t> row(nullptr);
+            if (codec->getScanlineOrder() == SkCodec::kTopDown_SkScanlineOrder) {
+                row.reset(new uint8_t[info.minRowBytes()]);
+            }
 
             SkBitmap bitmap;
             // Note that we use the same bitmap for all of the subsets.
@@ -71,20 +83,55 @@
             SkImageInfo subsetInfo = info.makeWH(fSubsetWidth, fSubsetHeight);
             alloc_pixels(&bitmap, subsetInfo, colors, colorCount);
 
+            const uint32_t bpp = info.bytesPerPixel();
+
             for (int x = 0; x < info.width(); x += fSubsetWidth) {
                 for (int y = 0; y < info.height(); y += fSubsetHeight) {
-                    codec->skipScanlines(y);
+                    SkDEBUGCODE(SkCodec::Result result =)
+                    codec->startScanlineDecode(info, nullptr, get_colors(&bitmap), &colorCount);
+                    SkASSERT(SkCodec::kSuccess == result);
+
+                    SkDEBUGCODE(result =) codec->skipScanlines(y);
+                    SkASSERT(SkCodec::kSuccess == result);
+
                     const uint32_t currSubsetWidth =
                             x + (int) fSubsetWidth > info.width() ?
                             info.width() - x : fSubsetWidth;
                     const uint32_t currSubsetHeight =
                             y + (int) fSubsetHeight > info.height() ?
                             info.height() - y : fSubsetHeight;
-                    const uint32_t bpp = info.bytesPerPixel();
-                    for (uint32_t y = 0; y < currSubsetHeight; y++) {
-                        codec->getScanlines(row.get(), 1, 0);
-                        memcpy(bitmap.getAddr(0, y), row.get() + x * bpp,
-                                currSubsetWidth * bpp);
+
+                    switch (codec->getScanlineOrder()) {
+                        case SkCodec::kTopDown_SkScanlineOrder:
+                            for (uint32_t y = 0; y < currSubsetHeight; y++) {
+                                SkDEBUGCODE(result =) codec->getScanlines(row.get(), 1, 0);
+                                SkASSERT(SkCodec::kSuccess == result);
+
+                                memcpy(bitmap.getAddr(0, y), row.get() + x * bpp,
+                                        currSubsetWidth * bpp);
+                            }
+                            break;
+                        case SkCodec::kNone_SkScanlineOrder: {
+                            // decode all scanlines that intersect the subset, and copy the subset
+                            // into the output.
+                            SkImageInfo stripeInfo = info.makeWH(info.width(), currSubsetHeight);
+                            SkBitmap stripeBm;
+                            alloc_pixels(&stripeBm, stripeInfo, colors, colorCount);
+
+                            SkDEBUGCODE(result =) codec->getScanlines(stripeBm.getPixels(),
+                                    currSubsetHeight, stripeBm.rowBytes());
+                            SkASSERT(SkCodec::kSuccess == result);
+
+                            for (uint32_t subsetY = 0; subsetY < currSubsetHeight; subsetY++) {
+                                memcpy(bitmap.getAddr(0, subsetY), stripeBm.getAddr(x, subsetY),
+                                        currSubsetWidth * bpp);
+                            }
+                            break;
+                        }
+                        default:
+                            // We currently are only testing kTopDown and kNone, which are the only
+                            // two used by the subsets we care about. skbug.com/4428
+                            SkASSERT(false);
                     }
                 }
             }
@@ -97,7 +144,7 @@
         for (int count = 0; count < n; count++) {
             int width, height;
             SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(fStream));
-            decoder->buildTileIndex(fStream->duplicate(), &width, &height);
+            SkAssertResult(decoder->buildTileIndex(fStream->duplicate(), &width, &height));
             SkBitmap bitmap;
             // Note that we use the same bitmap for all of the subsets.
             // It might be larger than necessary for the end subsets.
@@ -117,7 +164,7 @@
                             height - y : fSubsetHeight;
                     SkIRect rect = SkIRect::MakeXYWH(x, y, currSubsetWidth,
                             currSubsetHeight);
-                    decoder->decodeSubset(&bitmap, rect, fColorType);
+                    SkAssertResult(decoder->decodeSubset(&bitmap, rect, fColorType));
                 }
             }
         }
diff --git a/bench/subset/SubsetZoomBench.cpp b/bench/subset/SubsetZoomBench.cpp
index ffd8670..901fbb6 100644
--- a/bench/subset/SubsetZoomBench.cpp
+++ b/bench/subset/SubsetZoomBench.cpp
@@ -62,14 +62,20 @@
         for (int count = 0; count < n; count++) {
             SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(fStream->duplicate()));
             const SkImageInfo info = codec->getInfo().makeColorType(fColorType);
-            SkAutoTDeleteArray<uint8_t> row(new uint8_t[info.minRowBytes()]);
-            codec->startScanlineDecode(info, nullptr, colors, &colorCount);
+            SkAutoTDeleteArray<uint8_t> row(nullptr);
+            if (codec->getScanlineOrder() == SkCodec::kTopDown_SkScanlineOrder) {
+                row.reset(new uint8_t[info.minRowBytes()]);
+            }
 
             const int centerX = info.width() / 2;
             const int centerY = info.height() / 2;
             int w = fSubsetWidth;
             int h = fSubsetHeight;
             do {
+                SkDEBUGCODE(SkCodec::Result result = )
+                codec->startScanlineDecode(info, nullptr, colors, &colorCount);
+                SkASSERT(SkCodec::kSuccess == result);
+
                 const int subsetStartX = SkTMax(0, centerX - w / 2);
                 const int subsetStartY = SkTMax(0, centerY - h / 2);
                 const int subsetWidth = SkTMin(w, info.width() - subsetStartX);
@@ -81,12 +87,44 @@
                 alloc_pixels(&bitmap, subsetInfo, colors, colorCount);
 
                 uint32_t bpp = info.bytesPerPixel();
-                codec->skipScanlines(subsetStartY);
-                for (int y = 0; y < subsetHeight; y++) {
-                    codec->getScanlines(row.get(), 1, 0);
-                    memcpy(bitmap.getAddr(0, y), row.get() + subsetStartX * bpp,
-                            subsetWidth * bpp);
+
+                SkDEBUGCODE(result = ) codec->skipScanlines(subsetStartY);
+                SkASSERT(SkCodec::kSuccess == result);
+
+                switch (codec->getScanlineOrder()) {
+                    case SkCodec::kTopDown_SkScanlineOrder:
+                        for (int y = 0; y < subsetHeight; y++) {
+                            SkDEBUGCODE(result = ) codec->getScanlines(row.get(), 1, 0);
+                            SkASSERT(SkCodec::kSuccess == result);
+
+                            memcpy(bitmap.getAddr(0, y), row.get() + subsetStartX * bpp,
+                                    subsetWidth * bpp);
+                        }
+                        break;
+                    case SkCodec::kNone_SkScanlineOrder: {
+                        // decode all scanlines that intersect the subset, and copy the subset
+                        // into the output.
+                        SkImageInfo stripeInfo = info.makeWH(info.width(), subsetHeight);
+                        SkBitmap stripeBm;
+                        alloc_pixels(&stripeBm, stripeInfo, colors, colorCount);
+
+                        SkDEBUGCODE(result = ) codec->getScanlines(stripeBm.getPixels(),
+                                subsetHeight, stripeBm.rowBytes());
+                        SkASSERT(SkCodec::kSuccess == result);
+
+                        for (int y = 0; y < subsetHeight; y++) {
+                            memcpy(bitmap.getAddr(0, y),
+                                   stripeBm.getAddr(subsetStartX, y),
+                                   subsetWidth * bpp);
+                        }
+                        break;
+                    }
+                    default:
+                        // We currently are only testing kTopDown and kNone, which are the only
+                        // two used by the subsets we care about. skbug.com/4428
+                        SkASSERT(false);
                 }
+
                 w <<= 1;
                 h <<= 1;
             } while (w < 2 * info.width() || h < 2 * info.height());
@@ -95,7 +133,7 @@
         for (int count = 0; count < n; count++) {
             int width, height;
             SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(fStream));
-            decoder->buildTileIndex(fStream->duplicate(), &width, &height);
+            SkAssertResult(decoder->buildTileIndex(fStream->duplicate(), &width, &height));
 
             const int centerX = width / 2;
             const int centerY = height / 2;
@@ -109,7 +147,7 @@
                 SkBitmap bitmap;
                 SkIRect rect = SkIRect::MakeXYWH(subsetStartX, subsetStartY, subsetWidth,
                         subsetHeight);
-                decoder->decodeSubset(&bitmap, rect, fColorType);
+                SkAssertResult(decoder->decodeSubset(&bitmap, rect, fColorType));
                 w <<= 1;
                 h <<= 1;
             } while (w < 2 * width || h < 2 * height);