Reset SkWuffsCodec frame-count decoder less often

Previously, every call to SkWuffsCodec::onGetFrameCountInternal would
reset the decoder, as it might have been suspended in a co-routine.
Resetting also meant re-winding the input stream back to the first byte
of source data, to re-parse the image configuration (not just a
per-frame configuration), since e.g. the overall image bounds can affect
(clip) a frame's bounds.

Now that there are two separate decoders (one for pixel data and one
just for the frame-count), the only co-routine that the frame-count
decoder could be suspended in is the call to decode the next frame
configuration. There is no longer a need to (conditionally) reset the
frame-count decoder; we can just resume that co-routine (provided that
the fIOBuffer is positioned where it left off).

After this commit, the Wuffs decoder should use a little less CPU and
I/O when having getFrameCount called multiple times, interleaved with
incrementally decoding an animation.

Bug: skia:8235
Change-Id: I871ead40ed0acd6d101cf12784ee5da45e7de5aa
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/254356
Reviewed-by: Leon Scroggins <scroggo@google.com>
Commit-Queue: Leon Scroggins <scroggo@google.com>
diff --git a/src/codec/SkWuffsCodec.cpp b/src/codec/SkWuffsCodec.cpp
index 45a01d8..a196e60 100644
--- a/src/codec/SkWuffsCodec.cpp
+++ b/src/codec/SkWuffsCodec.cpp
@@ -261,6 +261,7 @@
     size_t   fIncrDecRowBytes;
     bool     fFirstCallToIncrementalDecode;
 
+    uint64_t                  fFrameCountReaderIOPosition;
     uint64_t                  fNumFullyReceivedFrames;
     std::vector<SkWuffsFrame> fFrames;
     bool                      fFramesComplete;
@@ -363,6 +364,7 @@
       fIncrDecReaderIOPosition(0),
       fIncrDecRowBytes(0),
       fFirstCallToIncrementalDecode(false),
+      fFrameCountReaderIOPosition(0),
       fNumFullyReceivedFrames(0),
       fFramesComplete(false),
       fDecoderIsSuspended{
@@ -593,16 +595,15 @@
 }
 
 int SkWuffsCodec::onGetFrameCount() {
-    if (!fFramesComplete) {
+    if (!fFramesComplete && seek_buffer(&fIOBuffer, fStream.get(), fFrameCountReaderIOPosition)) {
         this->onGetFrameCountInternal();
+        fFrameCountReaderIOPosition =
+            fDecoders[WhichDecoder::kFrameCount] ? fIOBuffer.reader_io_position() : 0;
     }
     return fFrames.size();
 }
 
 void SkWuffsCodec::onGetFrameCountInternal() {
-    if (!seek_buffer(&fIOBuffer, fStream.get(), 0)) {
-        return;
-    }
     if (!fDecoders[WhichDecoder::kFrameCount]) {
         void* decoder_raw = sk_malloc_canfail(sizeof__wuffs_gif__decoder());
         if (!decoder_raw) {
@@ -610,20 +611,13 @@
         }
         std::unique_ptr<wuffs_gif__decoder, decltype(&sk_free)> decoder(
             reinterpret_cast<wuffs_gif__decoder*>(decoder_raw), &sk_free);
+        reset_and_decode_image_config(decoder.get(), nullptr, &fIOBuffer, fStream.get());
         fDecoders[WhichDecoder::kFrameCount] = std::move(decoder);
     }
-    reset_and_decode_image_config(fDecoders[WhichDecoder::kFrameCount].get(), nullptr, &fIOBuffer,
-                                  fStream.get());
-
-    size_t n = fFrames.size();
-    int    i = n ? n - 1 : 0;
-    if (this->seekFrame(WhichDecoder::kFrameCount, i) != SkCodec::kSuccess) {
-        return;
-    }
 
     // Iterate through the frames, converting from Wuffs'
     // wuffs_base__frame_config type to Skia's SkWuffsFrame type.
-    for (; i < INT_MAX; i++) {
+    while (true) {
         const char* status = this->decodeFrameConfig(WhichDecoder::kFrameCount);
         if (status == nullptr) {
             // No-op.
@@ -633,7 +627,11 @@
             return;
         }
 
-        if (static_cast<size_t>(i) < fFrames.size()) {
+        uint64_t i = fDecoders[WhichDecoder::kFrameCount]->num_decoded_frame_configs();
+        if (i > INT_MAX) {
+            break;
+        }
+        if ((i == 0) || (static_cast<size_t>(i - 1) != fFrames.size())) {
             continue;
         }
         fFrames.emplace_back(&fFrameConfigs[WhichDecoder::kFrameCount]);