1 /*
2  * Copyright 2017 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "gm.h"
9 #include "Resources.h"
10 #include "SkAnimCodecPlayer.h"
11 #include "SkAnimTimer.h"
12 #include "SkColor.h"
13 #include "SkMakeUnique.h"
14 #include "Skottie.h"
15 #include "SkottieProperty.h"
16 #include "SkottieUtils.h"
17 
18 #include <cmath>
19 #include <vector>
20 
21 using namespace skottie;
22 
23 namespace {
24 
25 static constexpr char kWebFontResource[] = "fonts/Roboto-Regular.ttf";
26 static constexpr char kSkottieResource[] = "skottie/skottie_sample_webfont.json";
27 
28 // Dummy web font loader which serves a single local font (checked in under resources/).
29 class FakeWebFontProvider final : public ResourceProvider {
30 public:
FakeWebFontProvider()31     FakeWebFontProvider() : fFontData(GetResourceAsData(kWebFontResource)) {}
32 
loadFont(const char[],const char[]) const33     sk_sp<SkData> loadFont(const char[], const char[]) const override {
34         return fFontData;
35     }
36 
37 private:
38     sk_sp<SkData> fFontData;
39 
40     using INHERITED = ResourceProvider;
41 };
42 
43 } // namespace
44 
45 class SkottieWebFontGM : public skiagm::GM {
46 public:
47 protected:
onShortName()48     SkString onShortName() override {
49         return SkString("skottie_webfont");
50     }
51 
onISize()52     SkISize onISize() override {
53         return SkISize::Make(kSize, kSize);
54     }
55 
onOnceBeforeDraw()56     void onOnceBeforeDraw() override {
57         if (auto stream = GetResourceAsStream(kSkottieResource)) {
58             fAnimation = Animation::Builder()
59                             .setResourceProvider(sk_make_sp<FakeWebFontProvider>())
60                             .make(stream.get());
61         }
62     }
63 
onDraw(SkCanvas * canvas,SkString * errorMsg)64     DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
65         if (!fAnimation) {
66             *errorMsg = "No animation";
67             return DrawResult::kFail;
68         }
69 
70         auto dest = SkRect::MakeWH(kSize, kSize);
71         fAnimation->render(canvas, &dest);
72         return DrawResult::kOk;
73     }
74 
onAnimate(const SkAnimTimer & timer)75     bool onAnimate(const SkAnimTimer& timer) override {
76         if (!fAnimation) {
77             return false;
78         }
79 
80         const auto duration = fAnimation->duration();
81         fAnimation->seek(std::fmod(timer.secs(), duration) / duration);
82         return true;
83     }
84 
85 private:
86     static constexpr SkScalar kSize = 800;
87 
88     sk_sp<Animation> fAnimation;
89 
90     using INHERITED = skiagm::GM;
91 };
92 
93 DEF_GM(return new SkottieWebFontGM;)
94 
95 using namespace skottie_utils;
96 
97 class SkottieColorizeGM : public skiagm::GM {
98 protected:
onShortName()99     SkString onShortName() override {
100         return SkString("skottie_colorize");
101     }
102 
onISize()103     SkISize onISize() override {
104         return SkISize::Make(kSize, kSize);
105     }
106 
onOnceBeforeDraw()107     void onOnceBeforeDraw() override {
108         if (auto stream = GetResourceAsStream("skottie/skottie_sample_search.json")) {
109             fPropManager = skstd::make_unique<CustomPropertyManager>();
110             fAnimation   = Animation::Builder()
111                               .setPropertyObserver(fPropManager->getPropertyObserver())
112                               .make(stream.get());
113             fColors      = fPropManager->getColorProps();
114         }
115     }
116 
onDraw(SkCanvas * canvas,SkString * errorMsg)117     DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
118         if (!fAnimation) {
119             *errorMsg = "No animation";
120             return DrawResult::kFail;
121         }
122 
123         auto dest = SkRect::MakeWH(kSize, kSize);
124         fAnimation->render(canvas, &dest);
125         return DrawResult::kOk;
126     }
127 
onAnimate(const SkAnimTimer & timer)128     bool onAnimate(const SkAnimTimer& timer) override {
129         if (!fAnimation) {
130             return false;
131         }
132 
133         const auto duration = fAnimation->duration();
134         fAnimation->seek(std::fmod(timer.secs(), duration) / duration);
135         return true;
136     }
137 
onHandleKey(SkUnichar uni)138     bool onHandleKey(SkUnichar uni) override {
139         static constexpr SkColor kColors[] = {
140             SK_ColorBLACK,
141             SK_ColorRED,
142             SK_ColorGREEN,
143             SK_ColorYELLOW,
144             SK_ColorCYAN,
145         };
146 
147         if (uni == 'c') {
148             fColorIndex = (fColorIndex + 1) % SK_ARRAY_COUNT(kColors);
149             for (const auto& prop : fColors) {
150                 fPropManager->setColor(prop, kColors[fColorIndex]);
151             }
152             return true;
153         }
154 
155         return false;
156     }
157 
158 private:
159     static constexpr SkScalar kSize = 800;
160 
161     sk_sp<Animation>                            fAnimation;
162     std::unique_ptr<CustomPropertyManager>      fPropManager;
163     std::vector<CustomPropertyManager::PropKey> fColors;
164     size_t                                      fColorIndex = 0;
165 
166     using INHERITED = skiagm::GM;
167 };
168 
169 DEF_GM(return new SkottieColorizeGM;)
170 
171 class SkottieMultiFrameGM : public skiagm::GM {
172 public:
173 protected:
onShortName()174     SkString onShortName() override {
175         return SkString("skottie_multiframe");
176     }
177 
onISize()178     SkISize onISize() override {
179         return SkISize::Make(kSize, kSize);
180     }
181 
onOnceBeforeDraw()182     void onOnceBeforeDraw() override {
183         if (auto stream = GetResourceAsStream("skottie/skottie_sample_multiframe.json")) {
184             fAnimation = Animation::Builder()
185                             .setResourceProvider(sk_make_sp<MultiFrameResourceProvider>())
186                             .make(stream.get());
187         }
188     }
189 
onDraw(SkCanvas * canvas,SkString * errorMsg)190     DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
191         if (!fAnimation) {
192             *errorMsg = "No animation";
193             return DrawResult::kFail;
194         }
195 
196         auto dest = SkRect::MakeWH(kSize, kSize);
197         fAnimation->render(canvas, &dest);
198         return DrawResult::kOk;
199     }
200 
onAnimate(const SkAnimTimer & timer)201     bool onAnimate(const SkAnimTimer& timer) override {
202         if (!fAnimation) {
203             return false;
204         }
205 
206         const auto duration = fAnimation->duration();
207         fAnimation->seek(std::fmod(timer.secs(), duration) / duration);
208         return true;
209     }
210 
211 private:
212     class MultiFrameResourceProvider final : public skottie::ResourceProvider {
213     public:
loadImageAsset(const char[],const char[]) const214         sk_sp<ImageAsset> loadImageAsset(const char[], const char[]) const override {
215             return skottie_utils::MultiFrameImageAsset::Make(
216                         GetResourceAsData("images/flightAnim.gif"));
217         }
218     };
219 
220     static constexpr SkScalar kSize = 800;
221 
222     sk_sp<Animation> fAnimation;
223 
224     using INHERITED = skiagm::GM;
225 };
226 
227 DEF_GM(return new SkottieMultiFrameGM;)
228