Consolidate decoding frames into SkCodec

Add a new private method to SkCodec that handles Options.fFrameIndex:
- Check to ensure the index is valid
- Call onGetFrameCount to force parsing the stream
- Recursively call getPixels (it should be complete, so no need for
  incremental decoding) to decode the prior frame if necessary
- Zero fill a RestoreBGColor frame

Call the method in getPixels and startIncrementalDecode, and remove
duplicate code from GIF and WEBP.

Remove support for scaling frames beyond the first, which is currently
unused.

Preserve the feature of SkGifCodec that it will only parse to the end
of the first frame if the first frame is asked for. (Also note that
when we continue a partial frame, we won't force parsing the full
stream.) If the client only wants the first frame, parsing the rest
would be unnecessary. But if the client wants the second, we assume
they will want any remaining frames, so we parse the remainder of the
stream. This simplifies the code (so SkCodec does not have to ask its
subclass to parse up to a particular frame).

Update tests that relied on the old behavior:
- Codec_partialAnim now hardcodes the bytes needed. Previously it
  relied on the old behavior that GIF only parsed up to the frame being
  decoded.
- Codec_skipFullParse now only tests the first frame, since that is the
  case where it is important to skip a full parse.

TBR=reed@google.com
No changes to the public API.

Change-Id: Ic2f075452dfeedb4e3e60e6cf4df33ee7bd38495
Reviewed-on: https://skia-review.googlesource.com/19276
Reviewed-by: Leon Scroggins <scroggo@google.com>
Reviewed-by: Matt Sarett <msarett@google.com>
Commit-Queue: Leon Scroggins <scroggo@google.com>
diff --git a/src/codec/SkWebpCodec.cpp b/src/codec/SkWebpCodec.cpp
index 65250a4..68301b9 100644
--- a/src/codec/SkWebpCodec.cpp
+++ b/src/codec/SkWebpCodec.cpp
@@ -381,11 +381,8 @@
 SkCodec::Result SkWebpCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t rowBytes,
                                          const Options& options, SkPMColor*, int*,
                                          int* rowsDecodedPtr) {
-    // Ensure that we have parsed this far.
     const int index = options.fFrameIndex;
-    if (index >= this->onGetFrameCount()) {
-        return kIncompleteInput;
-    }
+    SkASSERT(0 == index || index < fFrameHolder.size());
 
     const auto& srcInfo = this->getInfo();
     {
@@ -401,13 +398,7 @@
         }
     }
 
-    if (index > 0 && (options.fSubset || dstInfo.dimensions() != srcInfo.dimensions())) {
-        // Subsetting and scaling are tricky when asking for frames beyond frame 0. In order to
-        // support it, we'll need to determine the proper rectangle for a
-        // WEBP_MUX_DISPOSE_BACKGROUND required frame before erasing it. (Currently the order
-        // is backwards.) Disable until it becomes clear that supporting it is important.
-        return kUnimplemented;
-    }
+    SkASSERT(0 == index || (!options.fSubset && dstInfo.dimensions() == srcInfo.dimensions()));
 
     WebPDecoderConfig config;
     if (0 == WebPInitDecoderConfig(&config)) {
@@ -424,53 +415,15 @@
     // If this succeeded in onGetFrameCount(), it should succeed again here.
     SkAssertResult(WebPDemuxGetFrame(fDemux, index + 1, &frame));
 
-    const int requiredFrame = index == 0 ? kNone : fFrameHolder.frame(index)->getRequiredFrame();
+    const bool independent = index == 0 ? true :
+            (fFrameHolder.frame(index)->getRequiredFrame() == kNone);
     // Get the frameRect.  libwebp will have already signaled an error if this is not fully
     // contained by the canvas.
     auto frameRect = SkIRect::MakeXYWH(frame.x_offset, frame.y_offset, frame.width, frame.height);
     SkASSERT(srcInfo.bounds().contains(frameRect));
     const bool frameIsSubset = frameRect != srcInfo.bounds();
-    if (kNone == requiredFrame) {
-        if (frameIsSubset) {
-            SkSampler::Fill(dstInfo, dst, rowBytes, 0, options.fZeroInitialized);
-        }
-    } else {
-        // FIXME: Share with GIF
-        if (options.fPriorFrame != kNone) {
-            if (options.fPriorFrame < requiredFrame || options.fPriorFrame >= index) {
-                return kInvalidParameters;
-            }
-        } else {
-            Options prevFrameOpts(options);
-            prevFrameOpts.fFrameIndex = requiredFrame;
-            prevFrameOpts.fPriorFrame = kNone;
-            const auto result = this->getPixels(dstInfo, dst, rowBytes, &prevFrameOpts,
-                                                nullptr, nullptr);
-            switch (result) {
-                case kSuccess:
-                    break;
-                case kIncompleteInput:
-                    return kInvalidInput;
-                default:
-                    return result;
-            }
-        }
-
-        if (options.fPriorFrame == requiredFrame || options.fPriorFrame == kNone) {
-            // Dispose bg color
-            const Frame* priorFrame = fFrameHolder.frame(requiredFrame);
-            if (priorFrame->getDisposalMethod()
-                    == SkCodecAnimation::DisposalMethod::kRestoreBGColor) {
-                // FIXME: If we add support for scaling/subsets, this rectangle needs to be
-                // adjusted.
-                const auto priorRect = priorFrame->frameRect();
-                const auto info = dstInfo.makeWH(priorRect.width(), priorRect.height());
-                const size_t bpp = SkColorTypeBytesPerPixel(dstInfo.colorType());
-                const size_t offset = priorRect.x() * bpp + priorRect.y() * rowBytes;
-                auto* eraseDst = SkTAddOffset<void>(dst, offset);
-                SkSampler::Fill(info, eraseDst, rowBytes, 0, kNo_ZeroInitialized);
-            }
-        }
+    if (independent && frameIsSubset) {
+        SkSampler::Fill(dstInfo, dst, rowBytes, 0, options.fZeroInitialized);
     }
 
     int dstX = frameRect.x();
@@ -540,7 +493,7 @@
         config.options.scaled_height = scaledHeight;
     }
 
-    const bool blendWithPrevFrame = requiredFrame != kNone && frame.blend_method == WEBP_MUX_BLEND
+    const bool blendWithPrevFrame = !independent && frame.blend_method == WEBP_MUX_BLEND
         && frame.has_alpha;
     if (blendWithPrevFrame && options.fPremulBehavior == SkTransferFunctionBehavior::kRespect) {
         // Blending is done with SkRasterPipeline, which requires a color space that is valid for