Handle static/single frame images in SkAnimCodecPlayer

Bug: skia:
Change-Id: I9fae9b56133e7de877021e846dbc431c69477113
Reviewed-on: https://skia-review.googlesource.com/c/168900
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Florin Malita <fmalita@chromium.org>
diff --git a/src/codec/SkCodecImageGenerator.cpp b/src/codec/SkCodecImageGenerator.cpp
index b26fe71..8341df8 100644
--- a/src/codec/SkCodecImageGenerator.cpp
+++ b/src/codec/SkCodecImageGenerator.cpp
@@ -19,6 +19,13 @@
     return std::unique_ptr<SkImageGenerator>(new SkCodecImageGenerator(std::move(codec), data));
 }
 
+std::unique_ptr<SkImageGenerator>
+SkCodecImageGenerator::MakeFromCodec(std::unique_ptr<SkCodec> codec) {
+    return codec
+        ? std::unique_ptr<SkImageGenerator>(new SkCodecImageGenerator(std::move(codec), nullptr))
+        : nullptr;
+}
+
 static SkImageInfo adjust_info(SkCodec* codec) {
     SkImageInfo info = codec->getInfo();
     if (kUnpremul_SkAlphaType == info.alphaType()) {
diff --git a/src/codec/SkCodecImageGenerator.h b/src/codec/SkCodecImageGenerator.h
index de6cf93..afd0b99 100644
--- a/src/codec/SkCodecImageGenerator.h
+++ b/src/codec/SkCodecImageGenerator.h
@@ -19,6 +19,8 @@
      */
     static std::unique_ptr<SkImageGenerator> MakeFromEncodedCodec(sk_sp<SkData>);
 
+    static std::unique_ptr<SkImageGenerator> MakeFromCodec(std::unique_ptr<SkCodec>);
+
 protected:
     sk_sp<SkData> onRefEncodedData() override;
 
diff --git a/src/utils/SkAnimCodecPlayer.cpp b/src/utils/SkAnimCodecPlayer.cpp
index 0a9bbc0..d2fcdab 100644
--- a/src/utils/SkAnimCodecPlayer.cpp
+++ b/src/utils/SkAnimCodecPlayer.cpp
@@ -7,6 +7,7 @@
 
 #include "SkAnimCodecPlayer.h"
 #include "SkCodec.h"
+#include "SkCodecImageGenerator.h"
 #include "SkData.h"
 #include "SkImage.h"
 #include <algorithm>
@@ -23,6 +24,14 @@
         f.fDuration = dur;
     }
     fTotalDuration = dur;
+
+    if (!fTotalDuration) {
+        // Static image -- may or may not have returned a single frame info.
+        fFrameInfos.clear();
+        fImages.clear();
+        fImages.push_back(SkImage::MakeFromGenerator(
+                              SkCodecImageGenerator::MakeFromCodec(std::move(fCodec))));
+    }
 }
 
 SkAnimCodecPlayer::~SkAnimCodecPlayer() {}
@@ -61,10 +70,18 @@
 }
 
 sk_sp<SkImage> SkAnimCodecPlayer::getFrame() {
-    return this->getFrameAt(fCurrIndex);
+    SkASSERT(fTotalDuration > 0 || fImages.size() == 1);
+
+    return fTotalDuration > 0
+        ? this->getFrameAt(fCurrIndex)
+        : fImages.front();
 }
 
 bool SkAnimCodecPlayer::seek(uint32_t msec) {
+    if (!fTotalDuration) {
+        return false;
+    }
+
     msec %= fTotalDuration;
 
     auto lower = std::lower_bound(fFrameInfos.begin(), fFrameInfos.end(), msec,
diff --git a/tests/CodecAnimTest.cpp b/tests/CodecAnimTest.cpp
index 99ed876..d3f385e 100644
--- a/tests/CodecAnimTest.cpp
+++ b/tests/CodecAnimTest.cpp
@@ -8,11 +8,13 @@
 #include "CodecPriv.h"
 #include "Resources.h"
 #include "SkAndroidCodec.h"
+#include "SkAnimCodecPlayer.h"
 #include "SkBitmap.h"
 #include "SkCodec.h"
 #include "SkCodecAnimation.h"
 #include "SkData.h"
 #include "SkImageInfo.h"
+#include "SkMakeUnique.h"
 #include "SkRefCnt.h"
 #include "SkSize.h"
 #include "SkString.h"
@@ -449,3 +451,36 @@
         }
     }
 }
+
+DEF_TEST(AnimCodecPlayer, r) {
+    static constexpr struct {
+        const char* fFile;
+        uint32_t    fDuration;
+        SkISize     fSize;
+    } gTests[] = {
+        { "images/alphabetAnim.gif", 1300, {100, 100} },
+        { "images/randPixels.gif"  ,    0, {  8,   8} },
+        { "images/randPixels.jpg"  ,    0, {  8,   8} },
+        { "images/randPixels.png"  ,    0, {  8,   8} },
+    };
+
+    for (const auto& test : gTests) {
+        auto codec = SkCodec::MakeFromData(GetResourceAsData(test.fFile));
+        REPORTER_ASSERT(r, codec);
+
+        auto player = skstd::make_unique<SkAnimCodecPlayer>(std::move(codec));
+        if (player->duration() != test.fDuration) {
+            printf("*** %d vs %d\n", player->duration(), test.fDuration);
+        }
+        REPORTER_ASSERT(r, player->duration() == test.fDuration);
+
+        auto f0 = player->getFrame();
+        REPORTER_ASSERT(r, f0);
+        REPORTER_ASSERT(r, f0->bounds().size() == test.fSize);
+
+        player->seek(500);
+        auto f1 = player->getFrame();
+        REPORTER_ASSERT(r, f1);
+        REPORTER_ASSERT(r, f1->bounds().size() == test.fSize);
+    }
+}