Add subsetting to SkScanlineDecoder

This CL allows the SkScanlineDecoder to decode partial
scanlines.

This is a first step in efficiently implementing subsetting
in SkScaledCodec.

BUG=skia:4209

Review URL: https://codereview.chromium.org/1390213002
diff --git a/src/codec/SkBmpCodec.cpp b/src/codec/SkBmpCodec.cpp
index 1aa43f5..0222c8c 100644
--- a/src/codec/SkBmpCodec.cpp
+++ b/src/codec/SkBmpCodec.cpp
@@ -564,10 +564,6 @@
 
 SkCodec::Result SkBmpCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
         const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) {
-    if (options.fSubset) {
-        // Subsets are not supported.
-        return kUnimplemented;
-    }
     if (!conversion_possible(dstInfo, this->getInfo())) {
         SkCodecPrintf("Error: cannot convert input type to output type.\n");
         return kInvalidConversion;
diff --git a/src/codec/SkBmpMaskCodec.cpp b/src/codec/SkBmpMaskCodec.cpp
index 336698d..2bc47b5 100644
--- a/src/codec/SkBmpMaskCodec.cpp
+++ b/src/codec/SkBmpMaskCodec.cpp
@@ -58,10 +58,10 @@
     return kSuccess;
 }
 
-bool SkBmpMaskCodec::initializeSwizzler(const SkImageInfo& dstInfo) {
+bool SkBmpMaskCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options) {
     // Create the swizzler
-    fMaskSwizzler.reset(SkMaskSwizzler::CreateMaskSwizzler(
-            dstInfo, this->getInfo(), fMasks, this->bitsPerPixel()));
+    fMaskSwizzler.reset(SkMaskSwizzler::CreateMaskSwizzler(dstInfo, this->getInfo(), fMasks,
+            this->bitsPerPixel(), options));
 
     if (nullptr == fMaskSwizzler.get()) {
         return false;
@@ -73,7 +73,7 @@
 SkCodec::Result SkBmpMaskCodec::prepareToDecode(const SkImageInfo& dstInfo,
         const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) {
     // Initialize a the mask swizzler
-    if (!this->initializeSwizzler(dstInfo)) {
+    if (!this->initializeSwizzler(dstInfo, options)) {
         SkCodecPrintf("Error: cannot initialize swizzler.\n");
         return SkCodec::kInvalidConversion;
     }
diff --git a/src/codec/SkBmpMaskCodec.h b/src/codec/SkBmpMaskCodec.h
index 1c1d1d8..4ec868d 100644
--- a/src/codec/SkBmpMaskCodec.h
+++ b/src/codec/SkBmpMaskCodec.h
@@ -44,7 +44,7 @@
 
 private:
 
-    bool initializeSwizzler(const SkImageInfo& dstInfo);
+    bool initializeSwizzler(const SkImageInfo& dstInfo, const Options& options);
     SkSampler* getSampler(bool createIfNecessary) override {
         SkASSERT(fMaskSwizzler);
         return fMaskSwizzler;
diff --git a/src/codec/SkBmpRLECodec.cpp b/src/codec/SkBmpRLECodec.cpp
index 37af476..e215095 100644
--- a/src/codec/SkBmpRLECodec.cpp
+++ b/src/codec/SkBmpRLECodec.cpp
@@ -259,6 +259,12 @@
 
 SkCodec::Result SkBmpRLECodec::prepareToDecode(const SkImageInfo& dstInfo,
         const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) {
+    // FIXME: Support subsets for scanline decodes.
+    if (options.fSubset) {
+        // Subsets are not supported.
+        return kUnimplemented;
+    }
+
     // Reset fSampleX. If it needs to be a value other than 1, it will get modified by
     // the sampler.
     fSampleX = 1;
diff --git a/src/codec/SkBmpStandardCodec.cpp b/src/codec/SkBmpStandardCodec.cpp
index 938fe8c..9557609 100644
--- a/src/codec/SkBmpStandardCodec.cpp
+++ b/src/codec/SkBmpStandardCodec.cpp
@@ -161,8 +161,7 @@
     return true;
 }
 
-bool SkBmpStandardCodec::initializeSwizzler(const SkImageInfo& dstInfo,
-                                            const Options& opts) {
+bool SkBmpStandardCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& opts) {
     // Get swizzler configuration
     SkSwizzler::SrcConfig config;
     switch (this->bitsPerPixel()) {
@@ -197,8 +196,7 @@
     const SkPMColor* colorPtr = get_color_ptr(fColorTable.get());
 
     // Create swizzler
-    fSwizzler.reset(SkSwizzler::CreateSwizzler(config,
-            colorPtr, dstInfo, opts.fZeroInitialized));
+    fSwizzler.reset(SkSwizzler::CreateSwizzler(config, colorPtr, dstInfo, opts));
 
     if (nullptr == fSwizzler.get()) {
         return false;
diff --git a/src/codec/SkCodec.cpp b/src/codec/SkCodec.cpp
index 0047d59..56f6a8d 100644
--- a/src/codec/SkCodec.cpp
+++ b/src/codec/SkCodec.cpp
@@ -220,11 +220,15 @@
     if (nullptr == options) {
         options = &optsStorage;
     } else if (options->fSubset) {
-        SkIRect subset(*options->fSubset);
-        if (!this->onGetValidSubset(&subset) || subset != *options->fSubset) {
-            // FIXME: How to differentiate between not supporting subset at all
-            // and not supporting this particular subset?
-            return kUnimplemented;
+        SkIRect size = SkIRect::MakeSize(dstInfo.dimensions());
+        if (!size.contains(*options->fSubset)) {
+            return kInvalidInput;
+        }
+
+        // We only support subsetting in the x-dimension for scanline decoder.
+        // Subsetting in the y-dimension can be accomplished using skipScanlines().
+        if (options->fSubset->top() != 0 || options->fSubset->height() != dstInfo.height()) {
+            return kInvalidInput;
         }
     }
 
diff --git a/src/codec/SkCodec_libgif.cpp b/src/codec/SkCodec_libgif.cpp
index 856f69b..0187891 100644
--- a/src/codec/SkCodec_libgif.cpp
+++ b/src/codec/SkCodec_libgif.cpp
@@ -435,10 +435,6 @@
 SkCodec::Result SkGifCodec::prepareToDecode(const SkImageInfo& dstInfo, SkPMColor* inputColorPtr,
         int* inputColorCount, const Options& opts) {
     // Check for valid input parameters
-    if (opts.fSubset) {
-        // Subsets are not supported.
-        return kUnimplemented;
-    }
     if (!conversion_possible(dstInfo, this->getInfo())) {
         return gif_error("Cannot convert input type to output type.\n",
                 kInvalidConversion);
@@ -449,11 +445,9 @@
     return kSuccess;
 }
 
-SkCodec::Result SkGifCodec::initializeSwizzler(const SkImageInfo& dstInfo,
-        ZeroInitialized zeroInit) {
+SkCodec::Result SkGifCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& opts) {
     const SkPMColor* colorPtr = get_color_ptr(fColorTable.get());
-    fSwizzler.reset(SkSwizzler::CreateSwizzler(SkSwizzler::kIndex,
-            colorPtr, dstInfo, zeroInit));
+    fSwizzler.reset(SkSwizzler::CreateSwizzler(SkSwizzler::kIndex, colorPtr, dstInfo, opts));
     if (nullptr != fSwizzler.get()) {
         return kSuccess;
     }
@@ -485,7 +479,7 @@
     // Initialize the swizzler
     if (fFrameIsSubset) {
         const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameRect.width(), fFrameRect.height());
-        if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitialized)) {
+        if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts)) {
             return gif_error("Could not initialize swizzler.\n", kUnimplemented);
         }
 
@@ -499,7 +493,7 @@
         dst = SkTAddOffset<void*>(dst, dstRowBytes * fFrameRect.top() +
                 dstBytesPerPixel * fFrameRect.left());
     } else {
-        if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized)) {
+        if (kSuccess != this->initializeSwizzler(dstInfo, opts)) {
             return gif_error("Could not initialize swizzler.\n", kUnimplemented);
         }
     }
@@ -535,11 +529,11 @@
     // Initialize the swizzler
     if (fFrameIsSubset) {
         const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameRect.width(), fFrameRect.height());
-        if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitialized)) {
+        if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts)) {
             return gif_error("Could not initialize swizzler.\n", kUnimplemented);
         }
     } else {
-        if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized)) {
+        if (kSuccess != this->initializeSwizzler(dstInfo, opts)) {
             return gif_error("Could not initialize swizzler.\n", kUnimplemented);
         }
     }
diff --git a/src/codec/SkCodec_libgif.h b/src/codec/SkCodec_libgif.h
index 10fdac9..2e0c5a4 100644
--- a/src/codec/SkCodec_libgif.h
+++ b/src/codec/SkCodec_libgif.h
@@ -129,9 +129,11 @@
      * @param dstInfo  Output image information.  Dimensions may have been
      *                 adjusted if the image frame size does not match the size
      *                 indicated in the header.
-     * @param zeroInit Indicates if destination memory is zero initialized.
+     * @param options  Informs the swizzler if destination memory is zero initialized.
+     *                 Contains subset information.
      */
-    Result initializeSwizzler(const SkImageInfo& dstInfo, ZeroInitialized zeroInit);
+    Result initializeSwizzler(const SkImageInfo& dstInfo,
+            const Options& options);
 
     SkSampler* getSampler(bool createIfNecessary) override {
         SkASSERT(fSwizzler);
diff --git a/src/codec/SkCodec_libpng.cpp b/src/codec/SkCodec_libpng.cpp
index e828e24..7d41623 100644
--- a/src/codec/SkCodec_libpng.cpp
+++ b/src/codec/SkCodec_libpng.cpp
@@ -435,8 +435,7 @@
 
     // Create the swizzler.  SkPngCodec retains ownership of the color table.
     const SkPMColor* colors = get_color_ptr(fColorTable.get());
-    fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo,
-                                               options.fZeroInitialized));
+    fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo, options));
     if (!fSwizzler) {
         // FIXME: CreateSwizzler could fail for another reason.
         return kUnimplemented;
@@ -477,8 +476,7 @@
     }
 
     // Note that ctable and ctableCount may be modified if there is a color table
-    const Result result = this->initializeSwizzler(requestedInfo, options,
-                                                   ctable, ctableCount);
+    const Result result = this->initializeSwizzler(requestedInfo, options, ctable, ctableCount);
     if (result != kSuccess) {
         return result;
     }
@@ -699,15 +697,14 @@
     }
 
     Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& options,
-            SkPMColor ctable[], int* ctableCount) override
-    {
+            SkPMColor ctable[], int* ctableCount) override {
         if (!conversion_possible(dstInfo, this->getInfo())) {
             return kInvalidConversion;    
         }
 
-        const SkCodec::Result result = this->initializeSwizzler(dstInfo, options, ctable,
-                                                                ctableCount);
-        if (result != SkCodec::kSuccess) {
+        const Result result = this->initializeSwizzler(dstInfo, options, ctable,
+                                                       ctableCount);
+        if (result != kSuccess) {
             return result;
         }
 
diff --git a/src/codec/SkCodec_libpng.h b/src/codec/SkCodec_libpng.h
index 6bdf580..f003cbd 100644
--- a/src/codec/SkCodec_libpng.h
+++ b/src/codec/SkCodec_libpng.h
@@ -18,7 +18,6 @@
 #endif
 #include "png.h"
 
-class SkScanlineDecoder;
 class SkStream;
 
 class SkPngCodec : public SkCodec {
@@ -27,7 +26,6 @@
 
     // Assume IsPng was called and returned true.
     static SkCodec* NewFromStream(SkStream*);
-    static SkScanlineDecoder* NewSDFromStream(SkStream*);
 
     virtual ~SkPngCodec();
 
@@ -78,7 +76,6 @@
     SkSwizzler::SrcConfig       fSrcConfig;
     const int                   fNumberPasses;
     int                         fBitDepth;
-
     AlphaState                  fAlphaState;
 
     bool decodePalette(bool premultiply, int* ctableCount);
diff --git a/src/codec/SkCodec_wbmp.cpp b/src/codec/SkCodec_wbmp.cpp
index 14b7209..19ae4ea 100644
--- a/src/codec/SkCodec_wbmp.cpp
+++ b/src/codec/SkCodec_wbmp.cpp
@@ -70,8 +70,8 @@
     return read_header(this->stream(), nullptr);
 }
 
-SkSwizzler* SkWbmpCodec::initializeSwizzler(const SkImageInfo& info,
-        const SkPMColor* ctable, const Options& opts) {
+SkSwizzler* SkWbmpCodec::initializeSwizzler(const SkImageInfo& info, const SkPMColor* ctable,
+        const Options& opts) {
     // Create the swizzler based on the desired color type
     switch (info.colorType()) {
         case kIndex_8_SkColorType:
@@ -82,8 +82,7 @@
         default:
             return nullptr;
     }
-    return SkSwizzler::CreateSwizzler(SkSwizzler::kBit, ctable, info,
-                                      opts.fZeroInitialized);
+    return SkSwizzler::CreateSwizzler(SkSwizzler::kBit, ctable, info, opts);
 }
 
 bool SkWbmpCodec::readRow(uint8_t* row) {
@@ -188,8 +187,7 @@
     }
 
     // Initialize the swizzler
-    fSwizzler.reset(this->initializeSwizzler(dstInfo,
-            get_color_ptr(fColorTable.get()), options));
+    fSwizzler.reset(this->initializeSwizzler(dstInfo, get_color_ptr(fColorTable.get()), options));
     if (nullptr == fSwizzler.get()) {
         return kInvalidConversion;
     }
diff --git a/src/codec/SkJpegCodec.cpp b/src/codec/SkJpegCodec.cpp
index 196543b..d0d11b1 100644
--- a/src/codec/SkJpegCodec.cpp
+++ b/src/codec/SkJpegCodec.cpp
@@ -177,19 +177,19 @@
     // support these as well
     unsigned int num;
     unsigned int denom = 8;
-    if (desiredScale > 0.875f) {
+    if (desiredScale >= 0.9375) {
         num = 8;
-    } else if (desiredScale > 0.75f) {
+    } else if (desiredScale >= 0.8125) {
         num = 7;
-    } else if (desiredScale > 0.625f) {
+    } else if (desiredScale >= 0.6875f) {
         num = 6;
-    } else if (desiredScale > 0.5f) {
+    } else if (desiredScale >= 0.5625f) {
         num = 5;
-    } else if (desiredScale > 0.375f) {
+    } else if (desiredScale >= 0.4375f) {
         num = 4;
-    } else if (desiredScale > 0.25f) {
+    } else if (desiredScale >= 0.3125f) {
         num = 3;
-    } else if (desiredScale > 0.125f) {
+    } else if (desiredScale >= 0.1875f) {
         num = 2;
     } else {
         num = 1;
@@ -380,15 +380,9 @@
     return kSuccess;
 }
 
-SkSampler* SkJpegCodec::getSampler(bool createIfNecessary) {
-    if (!createIfNecessary || fSwizzler) {
-        SkASSERT(!fSwizzler || (fSrcRow && static_cast<uint8_t*>(fStorage.get()) == fSrcRow));
-        return fSwizzler;
-    }
-
-    const SkImageInfo& info = this->dstInfo();
+void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options) {
     SkSwizzler::SrcConfig srcConfig;
-    switch (info.colorType()) {
+    switch (dstInfo.colorType()) {
         case kGray_8_SkColorType:
             srcConfig = SkSwizzler::kGray;
             break;
@@ -406,14 +400,18 @@
             SkASSERT(false);
     }
 
-    fSwizzler.reset(SkSwizzler::CreateSwizzler(srcConfig, nullptr, info,
-                                               this->options().fZeroInitialized));
-    if (!fSwizzler) {
-        return nullptr;
-    }
-
+    fSwizzler.reset(SkSwizzler::CreateSwizzler(srcConfig, nullptr, dstInfo, options));
     fStorage.reset(get_row_bytes(fDecoderMgr->dinfo()));
     fSrcRow = static_cast<uint8_t*>(fStorage.get());
+}
+
+SkSampler* SkJpegCodec::getSampler(bool createIfNecessary) {
+    if (!createIfNecessary || fSwizzler) {
+        SkASSERT(!fSwizzler || (fSrcRow && static_cast<uint8_t*>(fStorage.get()) == fSrcRow));
+        return fSwizzler;
+    }
+
+    this->initializeSwizzler(this->dstInfo(), this->options());
     return fSwizzler;
 }
 
@@ -441,6 +439,11 @@
         return kInvalidInput;
     }
 
+    // We will need a swizzler if we are performing a subset decode
+    if (options.fSubset) {
+        this->initializeSwizzler(dstInfo, options);
+    }
+
     return kSuccess;
 }
 
@@ -452,7 +455,7 @@
     // Read rows one at a time
     JSAMPLE* dstRow;
     if (fSwizzler) {
-        // write data to storage row, then sample using swizzler         
+        // write data to storage row, then sample using swizzler
         dstRow = fSrcRow;
     } else {
         // write data directly to dst
diff --git a/src/codec/SkJpegCodec.h b/src/codec/SkJpegCodec.h
index 67680d6..687cf4b 100644
--- a/src/codec/SkJpegCodec.h
+++ b/src/codec/SkJpegCodec.h
@@ -103,9 +103,10 @@
     bool setOutputColorSpace(const SkImageInfo& dst);
 
     // scanline decoding
+    void initializeSwizzler(const SkImageInfo& dstInfo, const Options& options);
     SkSampler* getSampler(bool createIfNecessary) override;
     Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& options,
-                   SkPMColor ctable[], int* ctableCount) override;
+            SkPMColor ctable[], int* ctableCount) override;
     int onGetScanlines(void* dst, int count, size_t rowBytes) override;
     bool onSkipScanlines(int count) override;
 
diff --git a/src/codec/SkMaskSwizzler.cpp b/src/codec/SkMaskSwizzler.cpp
index 9772d87..72dca28 100644
--- a/src/codec/SkMaskSwizzler.cpp
+++ b/src/codec/SkMaskSwizzler.cpp
@@ -250,9 +250,9 @@
  * Create a new mask swizzler
  *
  */
-SkMaskSwizzler* SkMaskSwizzler::CreateMaskSwizzler(
-        const SkImageInfo& dstInfo, const SkImageInfo& srcInfo, SkMasks* masks,
-        uint32_t bitsPerPixel) {
+SkMaskSwizzler* SkMaskSwizzler::CreateMaskSwizzler(const SkImageInfo& dstInfo,
+        const SkImageInfo& srcInfo, SkMasks* masks, uint32_t bitsPerPixel,
+        const SkCodec::Options& options) {
 
     // Choose the appropriate row procedure
     RowProc proc = nullptr;
@@ -352,7 +352,14 @@
             return nullptr;
     }
 
-    return new SkMaskSwizzler(dstInfo.width(), masks, proc);
+    int srcOffset = 0;
+    int srcWidth = dstInfo.width();
+    if (options.fSubset) {
+        srcOffset = options.fSubset->left();
+        srcWidth = options.fSubset->width();
+    }
+
+    return new SkMaskSwizzler(masks, proc, srcOffset, srcWidth);
 }
 
 /*
@@ -360,13 +367,14 @@
  * Constructor for mask swizzler
  *
  */
-SkMaskSwizzler::SkMaskSwizzler(int width, SkMasks* masks, RowProc proc)
+SkMaskSwizzler::SkMaskSwizzler(SkMasks* masks, RowProc proc, int srcOffset, int srcWidth)
     : fMasks(masks)
     , fRowProc(proc)
-    , fSrcWidth(width)
-    , fDstWidth(width)
+    , fSrcWidth(srcWidth)
+    , fDstWidth(srcWidth)
     , fSampleX(1)
-    , fX0(0)
+    , fSrcOffset(srcOffset)
+    , fX0(srcOffset)
 {}
 
 int SkMaskSwizzler::onSetSampleX(int sampleX) {
@@ -374,7 +382,7 @@
     SkASSERT(sampleX > 0); // Surely there is an upper limit? Should there be
                            // way to report failure?
     fSampleX = sampleX;
-    fX0 = get_start_coord(sampleX);
+    fX0 = get_start_coord(sampleX) + fSrcOffset;
     fDstWidth = get_scaled_dimension(fSrcWidth, sampleX);
 
     // check that fX0 is less than original width
diff --git a/src/codec/SkMaskSwizzler.h b/src/codec/SkMaskSwizzler.h
index 0513d83..9aea5d8 100644
--- a/src/codec/SkMaskSwizzler.h
+++ b/src/codec/SkMaskSwizzler.h
@@ -28,7 +28,8 @@
     static SkMaskSwizzler* CreateMaskSwizzler(const SkImageInfo& dstInfo,
                                               const SkImageInfo& srcInfo,
                                               SkMasks* masks,
-                                              uint32_t bitsPerPixel);
+                                              uint32_t bitsPerPixel,
+                                              const SkCodec::Options& options);
 
     /*
      * Swizzle a row
@@ -49,14 +50,10 @@
     /*
      * Row procedure used for swizzle
      */
-    typedef SkSwizzler::ResultAlpha (*RowProc)(
-            void* dstRow, const uint8_t* srcRow, int width,
+    typedef SkSwizzler::ResultAlpha (*RowProc)(void* dstRow, const uint8_t* srcRow, int width,
             SkMasks* masks, uint32_t startX, uint32_t sampleX);
 
-    /*
-     * Constructor for mask swizzler
-     */
-    SkMaskSwizzler(int width, SkMasks* masks, RowProc proc);
+    SkMaskSwizzler(SkMasks* masks, RowProc proc, int srcWidth, int srcOffset);
 
     int onSetSampleX(int) override;
 
@@ -67,6 +64,7 @@
     const int       fSrcWidth;        // Width of the source - i.e. before any sampling.
     int             fDstWidth;        // Width of dst, which may differ with sampling.
     int             fSampleX;
+    int             fSrcOffset;
     int             fX0;
 };
 
diff --git a/src/codec/SkSwizzler.cpp b/src/codec/SkSwizzler.cpp
index 8d13e56..95ed1d7 100644
--- a/src/codec/SkSwizzler.cpp
+++ b/src/codec/SkSwizzler.cpp
@@ -230,9 +230,6 @@
     //                 SkScaledBitmap sampler just guesses that it is opaque.  This is dangerous
     //                 and probably wrong since gif and bmp (rarely) may have alpha.
     if (1 == deltaSrc) {
-        // A non-zero offset is only used when sampling, meaning that deltaSrc will be
-        // greater than 1. The below loop relies on the fact that src remains unchanged.
-        SkASSERT(0 == offset);
         memcpy(dst, src, dstWidth);
         for (int x = 0; x < dstWidth; x++) {
             UPDATE_RESULT_ALPHA(ctable[src[x]] >> SK_A32_SHIFT);
@@ -514,8 +511,8 @@
 
 SkSwizzler* SkSwizzler::CreateSwizzler(SkSwizzler::SrcConfig sc,
                                        const SkPMColor* ctable,
-                                       const SkImageInfo& dstInfo, 
-                                       SkCodec::ZeroInitialized zeroInit) {
+                                       const SkImageInfo& dstInfo,
+                                       const SkCodec::Options& options) {
     if (dstInfo.colorType() == kUnknown_SkColorType || kUnknown == sc) {
         return nullptr;
     }
@@ -524,7 +521,7 @@
         return nullptr;
     }
     RowProc proc = nullptr;
-
+    SkCodec::ZeroInitialized zeroInit = options.fZeroInitialized;
     switch (sc) {
         case kBit:
             switch (dstInfo.colorType()) {
@@ -683,28 +680,35 @@
         return nullptr;
     }
 
-    // Store deltaSrc in bytes if it is an even multiple, otherwise use bits
-    int deltaSrc = SkIsAlign8(BitsPerPixel(sc)) ? BytesPerPixel(sc) : BitsPerPixel(sc);
+    // Store bpp in bytes if it is an even multiple, otherwise use bits
+    int bpp = SkIsAlign8(BitsPerPixel(sc)) ? BytesPerPixel(sc) : BitsPerPixel(sc);
+    
+    int srcOffset = 0;
+    int srcWidth = dstInfo.width();
+    if (options.fSubset) {
+        srcOffset = options.fSubset->left();
+        srcWidth = options.fSubset->width();
+    }
 
-    return new SkSwizzler(proc, ctable, deltaSrc, dstInfo.width());
+    return new SkSwizzler(proc, ctable, srcOffset, srcWidth, bpp);
 }
 
-SkSwizzler::SkSwizzler(RowProc proc, const SkPMColor* ctable,
-                       int deltaSrc, int srcWidth)
+SkSwizzler::SkSwizzler(RowProc proc, const SkPMColor* ctable, int srcOffset, int srcWidth, int bpp)
     : fRowProc(proc)
     , fColorTable(ctable)
-    , fDeltaSrc(deltaSrc)
+    , fSrcOffset(srcOffset)
+    , fX0(srcOffset)
     , fSrcWidth(srcWidth)
     , fDstWidth(srcWidth)
+    , fBPP(bpp)
     , fSampleX(1)
-    , fX0(0)
 {}
 
 int SkSwizzler::onSetSampleX(int sampleX) {
     SkASSERT(sampleX > 0); // Surely there is an upper limit? Should there be
                            // way to report failure?
     fSampleX = sampleX;
-    fX0 = get_start_coord(sampleX);
+    fX0 = get_start_coord(sampleX) + fSrcOffset;
     fDstWidth = get_scaled_dimension(fSrcWidth, sampleX);
 
     // check that fX0 is less than original width
@@ -714,6 +718,5 @@
 
 SkSwizzler::ResultAlpha SkSwizzler::swizzle(void* dst, const uint8_t* SK_RESTRICT src) {
     SkASSERT(nullptr != dst && nullptr != src);
-    return fRowProc(dst, src, fDstWidth, fDeltaSrc, fSampleX * fDeltaSrc,
-            fX0 * fDeltaSrc, fColorTable);
+    return fRowProc(dst, src, fDstWidth, fBPP, fSampleX * fBPP, fX0 * fBPP, fColorTable);
 }
diff --git a/src/codec/SkSwizzler.h b/src/codec/SkSwizzler.h
index d7f6337..058044e 100644
--- a/src/codec/SkSwizzler.h
+++ b/src/codec/SkSwizzler.h
@@ -121,13 +121,14 @@
      *  @param ctable Unowned pointer to an array of up to 256 colors for an
      *                index source.
      *  @param dstInfo Describes the destination.
-     *  @param ZeroInitialized Whether dst is zero-initialized. The
+     *  @param options Indicates if dst is zero-initialized. The
      *                         implementation may choose to skip writing zeroes
      *                         if set to kYes_ZeroInitialized.
+     *                 Contains subset information.
      *  @return A new SkSwizzler or nullptr on failure.
      */
     static SkSwizzler* CreateSwizzler(SrcConfig, const SkPMColor* ctable,
-                                      const SkImageInfo& dstInfo, SkCodec::ZeroInitialized);
+                                      const SkImageInfo& dstInfo, const SkCodec::Options&);
 
     /**
      *  Swizzle a line. Generally this will be called height times, once
@@ -173,16 +174,19 @@
 
     const RowProc       fRowProc;
     const SkPMColor*    fColorTable;      // Unowned pointer
-    const int           fDeltaSrc;        // if bitsPerPixel % 8 == 0
-                                          //     deltaSrc is bytesPerPixel
-                                          // else
-                                          //     deltaSrc is bitsPerPixel
+    const int           fSrcOffset;       // Offset of the src in pixels, allows for partial
+                                          // scanline decodes.
+    int                 fX0;              // Start coordinate for the src, may be different than
+                                          // fSrcOffset if we are sampling.
     const int           fSrcWidth;        // Width of the source - i.e. before any sampling.
     int                 fDstWidth;        // Width of dst, which may differ with sampling.
-    int                 fX0;              // first X coord to sample
     int                 fSampleX;         // step between X samples
+    const int           fBPP;             // if bitsPerPixel % 8 == 0
+                                          //     fBPP is bytesPerPixel
+                                          // else
+                                          //     fBPP is bitsPerPixel
 
-    SkSwizzler(RowProc proc, const SkPMColor* ctable, int deltaSrc, int srcWidth);
+    SkSwizzler(RowProc proc, const SkPMColor* ctable, int srcOffset, int srcWidth, int bpp);
 
     int onSetSampleX(int) override;
 
diff --git a/src/codec/SkWebpCodec.cpp b/src/codec/SkWebpCodec.cpp
index a0fab0a..3c61b93 100644
--- a/src/codec/SkWebpCodec.cpp
+++ b/src/codec/SkWebpCodec.cpp
@@ -144,8 +144,8 @@
         return false;
     }
 
-    SkIRect bounds = SkIRect::MakeSize(this->getInfo().dimensions());
-    if (!desiredSubset->intersect(bounds)) {
+    SkIRect dimensions  = SkIRect::MakeSize(this->getInfo().dimensions());
+    if (!dimensions.contains(*desiredSubset)) {
         return false;
     }