Reland "SkAndroidCodec: Support decoding all frames"

This is a reland of fc4fdc5b25f448dd9c2cd4e445561a840ce8514b

Original change's description:
> SkAndroidCodec: Support decoding all frames
>
> Bug: b/160984428
> Bug: b/163595585
>
> Add support to SkAndroidCodec for decoding all frames with an
> fSampleSize, so that an entire animation can be decoded to a smaller
> size.
>
> dm/:
> - Test scaled + animated decodes
>
> SkAndroidCodec:
> - Make AndroidOptions inherit from SkCodec::Options. This allows
>   SkAndroidCodec to use fFrameIndex. (It also combines the two versions
>   of fSubset, which is now const for both.)
> - Respect fFrameIndex, and call SkCodec::handleFrameIndex to decode
>   the required frame.
> - Disallow decoding with kRespect + fFrameIndex > 0 if there is a
>   non-default orientation. As currently written (except without
>   disabling this combination), SkPixmapPriv::Orient would draw the new
>   portion of the frame on top of uninitialized pixels, instead of the
>   prior frame. This could be fixed by
>   - If SkAndroidCodec needs to decode the required frame, it could do so
>     without applying the orientation, then decode fFrameIndex, and then
>     apply the orientation.
>   - If the client provided the required frame, SkAndroidCodec would need
>     to un-apply the orientation to get the proper starting state, then
>     decode and apply.
>   I think it is simpler to force the client to handle the orientation
>   externally.
>
> SkCodec:
> - Allow SkAndroidCodec to call its private method handleFrameIndex. This
>   method handles decoding a required frame, if necessary. When called by
>   SkAndroidCodec, it now uses the SkAndroidCodec to check for/decode the
>   required frame, so that it will scale properly.
> - Call rewindIfNeeded inside handleFrameIndex. handleFrameIndex calls a
>   virtual method which may set some state (e.g. in SkJpegCodec). Without
>   this change, that state would be reset by rewindIfNeeded.
> - Simplify handling a kRestoreBGColor frame. Whether provided or not,
>   take the same path to calling zero_rect.
> - Updates to zero_rect:
>   - Intersect after scaling, which will also check for empty.
>   - Round out instead of in - this ensures we don't under-erase
>   - Use kFill_ScaleToFit, which better matches the intent.
>
> Change-Id: Ibe1951980a0dca8f5b7b1f20192432d395681683
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/333225
> Commit-Queue: Leon Scroggins <scroggo@google.com>
> Reviewed-by: Derek Sollenberger <djsollen@google.com>

Bug: b/160984428
Bug: b/163595585
Change-Id: I7c1e79e0f92c75b4840eef65c8fc2b8497189e81
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/334842
Auto-Submit: Leon Scroggins <scroggo@google.com>
Commit-Queue: Derek Sollenberger <djsollen@google.com>
Reviewed-by: Derek Sollenberger <djsollen@google.com>
diff --git a/src/codec/SkSampledCodec.cpp b/src/codec/SkSampledCodec.cpp
index b7ac0eb..4371e69 100644
--- a/src/codec/SkSampledCodec.cpp
+++ b/src/codec/SkSampledCodec.cpp
@@ -73,14 +73,10 @@
 
 SkCodec::Result SkSampledCodec::onGetAndroidPixels(const SkImageInfo& info, void* pixels,
         size_t rowBytes, const AndroidOptions& options) {
-    // Create an Options struct for the codec.
-    SkCodec::Options codecOptions;
-    codecOptions.fZeroInitialized = options.fZeroInitialized;
-
-    SkIRect* subset = options.fSubset;
+    const SkIRect* subset = options.fSubset;
     if (!subset || subset->size() == this->codec()->dimensions()) {
         if (this->codec()->dimensionsSupported(info.dimensions())) {
-            return this->codec()->getPixels(info, pixels, rowBytes, &codecOptions);
+            return this->codec()->getPixels(info, pixels, rowBytes, &options);
         }
 
         // If the native codec does not support the requested scale, scale by sampling.
@@ -103,15 +99,17 @@
 
     const SkImageInfo scaledInfo = info.makeDimensions(scaledSize);
 
+    // Copy so we can use a different fSubset.
+    AndroidOptions subsetOptions = options;
     {
         // Although startScanlineDecode expects the bottom and top to match the
         // SkImageInfo, startIncrementalDecode uses them to determine which rows to
         // decode.
         SkIRect incrementalSubset = SkIRect::MakeXYWH(scaledSubsetX, scaledSubsetY,
                                                       scaledSubsetWidth, scaledSubsetHeight);
-        codecOptions.fSubset = &incrementalSubset;
+        subsetOptions.fSubset = &incrementalSubset;
         const SkCodec::Result startResult = this->codec()->startIncrementalDecode(
-                scaledInfo, pixels, rowBytes, &codecOptions);
+                scaledInfo, pixels, rowBytes, &subsetOptions);
         if (SkCodec::kSuccess == startResult) {
             int rowsDecoded = 0;
             const SkCodec::Result incResult = this->codec()->incrementalDecode(&rowsDecoded);
@@ -128,17 +126,17 @@
             return startResult;
         }
         // Otherwise fall down to use the old scanline decoder.
-        // codecOptions.fSubset will be reset below, so it will not continue to
+        // subsetOptions.fSubset will be reset below, so it will not continue to
         // point to the object that is no longer on the stack.
     }
 
     // Start the scanline decode.
     SkIRect scanlineSubset = SkIRect::MakeXYWH(scaledSubsetX, 0, scaledSubsetWidth,
             scaledSize.height());
-    codecOptions.fSubset = &scanlineSubset;
+    subsetOptions.fSubset = &scanlineSubset;
 
     SkCodec::Result result = this->codec()->startScanlineDecode(scaledInfo,
-            &codecOptions);
+            &subsetOptions);
     if (SkCodec::kSuccess != result) {
         return result;
     }
@@ -167,10 +165,6 @@
     // We should only call this function when sampling.
     SkASSERT(options.fSampleSize > 1);
 
-    // Create options struct for the codec.
-    SkCodec::Options sampledOptions;
-    sampledOptions.fZeroInitialized = options.fZeroInitialized;
-
     // FIXME: This was already called by onGetAndroidPixels. Can we reduce that?
     int sampleSize = options.fSampleSize;
     int nativeSampleSize;
@@ -198,7 +192,6 @@
 
         // The scanline decoder only needs to be aware of subsetting in the x-dimension.
         subset.setXYWH(subsetX, 0, subsetWidth, nativeSize.height());
-        sampledOptions.fSubset = &subset;
     }
 
     // Since we guarantee that output dimensions are always at least one (even if the sampleSize
@@ -217,13 +210,13 @@
         // Although startScanlineDecode expects the bottom and top to match the
         // SkImageInfo, startIncrementalDecode uses them to determine which rows to
         // decode.
-        SkCodec::Options incrementalOptions = sampledOptions;
+        AndroidOptions incrementalOptions = options;
         SkIRect incrementalSubset;
-        if (sampledOptions.fSubset) {
-            incrementalSubset.fTop = subsetY;
-            incrementalSubset.fBottom = subsetY + subsetHeight;
-            incrementalSubset.fLeft = sampledOptions.fSubset->fLeft;
-            incrementalSubset.fRight = sampledOptions.fSubset->fRight;
+        if (options.fSubset) {
+            incrementalSubset.fTop     = subsetY;
+            incrementalSubset.fBottom  = subsetY + subsetHeight;
+            incrementalSubset.fLeft    = subset.fLeft;
+            incrementalSubset.fRight   = subset.fRight;
             incrementalOptions.fSubset = &incrementalSubset;
         }
         const SkCodec::Result startResult = this->codec()->startIncrementalDecode(nativeInfo,
@@ -263,6 +256,10 @@
     }
 
     // Start the scanline decode.
+    AndroidOptions sampledOptions = options;
+    if (options.fSubset) {
+        sampledOptions.fSubset = &subset;
+    }
     SkCodec::Result result = this->codec()->startScanlineDecode(nativeInfo,
             &sampledOptions);
     if (SkCodec::kIncompleteInput == result || SkCodec::kErrorInInput == result) {