Implement onSkipScanlines() for bmp and wbmp

TBR=reed@google.com
BUG=skia:4270
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1691083002

Review URL: https://codereview.chromium.org/1691083002
diff --git a/include/codec/SkCodec.h b/include/codec/SkCodec.h
index edc8ec3..c3a5873 100644
--- a/include/codec/SkCodec.h
+++ b/include/codec/SkCodec.h
@@ -657,18 +657,7 @@
         return kUnimplemented;
     }
 
-    // Naive default version just calls onGetScanlines on temp memory.
-    virtual bool onSkipScanlines(int countLines) {
-        // FIXME (msarett): Make this a pure virtual and always override this.
-        SkAutoMalloc storage(fDstInfo.minRowBytes());
-
-        // Note that we pass 0 to rowBytes so we continue to use the same memory.
-        // Also note that while getScanlines checks that rowBytes is big enough,
-        // onGetScanlines bypasses that check.
-        // Calling the virtual method also means we do not double count
-        // countLines.
-        return countLines == this->onGetScanlines(storage.get(), countLines, 0);
-    }
+    virtual bool onSkipScanlines(int /*countLines*/) { return false; }
 
     virtual int onGetScanlines(void* /*dst*/, int /*countLines*/, size_t /*rowBytes*/) { return 0; }
 
diff --git a/src/codec/SkBmpCodec.cpp b/src/codec/SkBmpCodec.cpp
index cbba28c..babb17d 100644
--- a/src/codec/SkBmpCodec.cpp
+++ b/src/codec/SkBmpCodec.cpp
@@ -546,6 +546,7 @@
     : INHERITED(info, stream)
     , fBitsPerPixel(bitsPerPixel)
     , fRowOrder(rowOrder)
+    , fSrcRowBytes(SkAlign4(compute_row_bytes(info.width(), fBitsPerPixel)))
 {}
 
 bool SkBmpCodec::onRewind() {
@@ -577,3 +578,12 @@
     // Decode the requested rows
     return this->decodeRows(rowInfo, dst, rowBytes, this->options());
 }
+
+bool SkBmpCodec::skipRows(int count) {
+    const size_t bytesToSkip = count * fSrcRowBytes;
+    return this->stream()->skip(bytesToSkip) == bytesToSkip;
+}
+
+bool SkBmpCodec::onSkipScanlines(int count) {
+    return this->skipRows(count);
+}
diff --git a/src/codec/SkBmpCodec.h b/src/codec/SkBmpCodec.h
index 5d77ca3..a54734f 100644
--- a/src/codec/SkBmpCodec.h
+++ b/src/codec/SkBmpCodec.h
@@ -81,6 +81,7 @@
      */
     uint16_t bitsPerPixel() const { return fBitsPerPixel; }
     SkScanlineOrder onGetScanlineOrder() const override { return fRowOrder; }
+    size_t srcRowBytes() const { return fSrcRowBytes; }
 
     /*
      * To be overriden by bmp subclasses, which provide unique implementations.
@@ -127,15 +128,18 @@
     virtual int decodeRows(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes,
             const Options& opts) = 0;
 
+    virtual bool skipRows(int count);
+
     Result onStartScanlineDecode(const SkImageInfo& dstInfo, const SkCodec::Options&,
             SkPMColor inputColorPtr[], int* inputColorCount) override;
 
     int onGetScanlines(void* dst, int count, size_t rowBytes) override;
 
-    // TODO(msarett): Override default skipping with something more clever.
+    bool onSkipScanlines(int count) override;
 
     const uint16_t          fBitsPerPixel;
     const SkScanlineOrder   fRowOrder;
+    const size_t            fSrcRowBytes;
 
     typedef SkCodec INHERITED;
 };
diff --git a/src/codec/SkBmpMaskCodec.cpp b/src/codec/SkBmpMaskCodec.cpp
index b173317..b603de9 100644
--- a/src/codec/SkBmpMaskCodec.cpp
+++ b/src/codec/SkBmpMaskCodec.cpp
@@ -18,8 +18,7 @@
     : INHERITED(info, stream, bitsPerPixel, rowOrder)
     , fMasks(masks)
     , fMaskSwizzler(nullptr)
-    , fSrcRowBytes(SkAlign4(compute_row_bytes(this->getInfo().width(), this->bitsPerPixel())))
-    , fSrcBuffer(new uint8_t [fSrcRowBytes])
+    , fSrcBuffer(new uint8_t [this->srcRowBytes()])
 {}
 
 /*
@@ -92,7 +91,7 @@
     const int height = dstInfo.height();
     for (int y = 0; y < height; y++) {
         // Read a row of the input
-        if (this->stream()->read(srcRow, fSrcRowBytes) != fSrcRowBytes) {
+        if (this->stream()->read(srcRow, this->srcRowBytes()) != this->srcRowBytes()) {
             SkCodecPrintf("Warning: incomplete input stream.\n");
             return y;
         }
diff --git a/src/codec/SkBmpMaskCodec.h b/src/codec/SkBmpMaskCodec.h
index 4ec868d..73a8b37 100644
--- a/src/codec/SkBmpMaskCodec.h
+++ b/src/codec/SkBmpMaskCodec.h
@@ -55,7 +55,6 @@
 
     SkAutoTDelete<SkMasks>              fMasks;        // owned
     SkAutoTDelete<SkMaskSwizzler>       fMaskSwizzler;
-    const size_t                        fSrcRowBytes;
     SkAutoTDeleteArray<uint8_t>         fSrcBuffer;
 
     typedef SkBmpCodec INHERITED;
diff --git a/src/codec/SkBmpRLECodec.cpp b/src/codec/SkBmpRLECodec.cpp
index 05691cc..1b95acc 100644
--- a/src/codec/SkBmpRLECodec.cpp
+++ b/src/codec/SkBmpRLECodec.cpp
@@ -201,7 +201,7 @@
 void SkBmpRLECodec::setPixel(void* dst, size_t dstRowBytes,
                              const SkImageInfo& dstInfo, uint32_t x, uint32_t y,
                              uint8_t index) {
-    if (is_coord_necessary(x, fSampleX, dstInfo.width())) {
+    if (dst && is_coord_necessary(x, fSampleX, dstInfo.width())) {
         // Set the row
         uint32_t row = this->getDstRow(y, dstInfo.height());
 
@@ -234,7 +234,7 @@
                                 const SkImageInfo& dstInfo, uint32_t x,
                                 uint32_t y, uint8_t red, uint8_t green,
                                 uint8_t blue) {
-    if (is_coord_necessary(x, fSampleX, dstInfo.width())) {
+    if (dst && is_coord_necessary(x, fSampleX, dstInfo.width())) {
         // Set the row
         uint32_t row = this->getDstRow(y, dstInfo.height());
 
@@ -316,7 +316,9 @@
     // Because of the need for transparent pixels, kN32 is the only color
     // type that makes sense for the destination format.
     SkASSERT(kN32_SkColorType == dstInfo.colorType());
-    SkSampler::Fill(dstInfo, dst, dstRowBytes, SK_ColorTRANSPARENT, opts.fZeroInitialized);
+    if (dst) {
+        SkSampler::Fill(dstInfo, dst, dstRowBytes, SK_ColorTRANSPARENT, opts.fZeroInitialized);
+    }
 
     // Adjust the height and the dst if the previous call to decodeRows() left us
     // with lines that need to be skipped.
@@ -500,6 +502,13 @@
     }
 }
 
+bool SkBmpRLECodec::skipRows(int count) {
+    const SkImageInfo rowInfo = SkImageInfo::Make(this->getInfo().width(), count, kN32_SkColorType,
+            kUnpremul_SkAlphaType);
+
+    return count == this->decodeRows(rowInfo, nullptr, 0, this->options());
+}
+
 // FIXME: Make SkBmpRLECodec have no knowledge of sampling.
 //        Or it should do all sampling natively.
 //        It currently is a hybrid that needs to know what SkScaledCodec is doing.
diff --git a/src/codec/SkBmpRLECodec.h b/src/codec/SkBmpRLECodec.h
index e319a71..2ddf8d8 100644
--- a/src/codec/SkBmpRLECodec.h
+++ b/src/codec/SkBmpRLECodec.h
@@ -84,9 +84,14 @@
                      const SkImageInfo& dstInfo, uint32_t x, uint32_t y,
                      uint8_t red, uint8_t green, uint8_t blue);
 
+    /*
+     * If dst is NULL, this is a signal to skip the rows.
+     */
     int decodeRows(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes,
             const Options& opts) override;
 
+    bool skipRows(int count) override;
+
     SkSampler* getSampler(bool createIfNecessary) override;
 
     SkAutoTUnref<SkColorTable>          fColorTable;    // owned
diff --git a/src/codec/SkBmpStandardCodec.cpp b/src/codec/SkBmpStandardCodec.cpp
index 66a8c9a..47b1070 100644
--- a/src/codec/SkBmpStandardCodec.cpp
+++ b/src/codec/SkBmpStandardCodec.cpp
@@ -25,8 +25,7 @@
     , fBytesPerColor(bytesPerColor)
     , fOffset(offset)
     , fSwizzler(nullptr)
-    , fSrcRowBytes(SkAlign4(compute_row_bytes(this->getInfo().width(), this->bitsPerPixel())))
-    , fSrcBuffer(new uint8_t [fSrcRowBytes])
+    , fSrcBuffer(new uint8_t [this->srcRowBytes()])
     , fIsOpaque(isOpaque)
     , fInIco(inIco)
     , fAndMaskRowBytes(fInIco ? SkAlign4(compute_row_bytes(this->getInfo().width(), 1)) : 0)
@@ -225,7 +224,7 @@
     const int height = dstInfo.height();
     for (int y = 0; y < height; y++) {
         // Read a row of the input
-        if (this->stream()->read(fSrcBuffer.get(), fSrcRowBytes) != fSrcRowBytes) {
+        if (this->stream()->read(fSrcBuffer.get(), this->srcRowBytes()) != this->srcRowBytes()) {
             SkCodecPrintf("Warning: incomplete input stream.\n");
             return y;
         }
@@ -262,7 +261,7 @@
 
         // Calculate how many bytes we must skip to reach the AND mask.
         const int remainingScanlines = this->getInfo().height() - startScanline - height;
-        const size_t bytesToSkip = remainingScanlines * fSrcRowBytes +
+        const size_t bytesToSkip = remainingScanlines * this->srcRowBytes() +
                 startScanline * fAndMaskRowBytes;
         const size_t subStreamStartPosition = currPosition + bytesToSkip;
         if (subStreamStartPosition >= length) {
diff --git a/src/codec/SkBmpStandardCodec.h b/src/codec/SkBmpStandardCodec.h
index 725b7bb..d3e2ed3 100644
--- a/src/codec/SkBmpStandardCodec.h
+++ b/src/codec/SkBmpStandardCodec.h
@@ -90,7 +90,6 @@
     const uint32_t                      fBytesPerColor;
     const uint32_t                      fOffset;
     SkAutoTDelete<SkSwizzler>           fSwizzler;
-    const size_t                        fSrcRowBytes;
     SkAutoTDeleteArray<uint8_t>         fSrcBuffer;
     const bool                          fIsOpaque;
     const bool                          fInIco;
diff --git a/src/codec/SkWbmpCodec.cpp b/src/codec/SkWbmpCodec.cpp
index 4dd0f25..af1ab46 100644
--- a/src/codec/SkWbmpCodec.cpp
+++ b/src/codec/SkWbmpCodec.cpp
@@ -181,6 +181,11 @@
     return count;
 }
 
+bool SkWbmpCodec::onSkipScanlines(int count) {
+    const size_t bytesToSkip = count * fSrcRowBytes;
+    return this->stream()->skip(bytesToSkip) == bytesToSkip;
+}
+
 SkCodec::Result SkWbmpCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
         const Options& options, SkPMColor inputColorTable[], int* inputColorCount) {
     if (options.fSubset) {
diff --git a/src/codec/SkWbmpCodec.h b/src/codec/SkWbmpCodec.h
index fb062c9..ceeadd4 100644
--- a/src/codec/SkWbmpCodec.h
+++ b/src/codec/SkWbmpCodec.h
@@ -52,8 +52,8 @@
     SkAutoTUnref<SkColorTable>   fColorTable;
     SkAutoTMalloc<uint8_t>       fSrcBuffer;
 
-    // FIXME: Override onSkipScanlines to avoid swizzling.
     int onGetScanlines(void* dst, int count, size_t dstRowBytes) override;
+    bool onSkipScanlines(int count) override;
     Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& options,
             SkPMColor inputColorTable[], int* inputColorCount) override;