xref: /aosp_15_r20/external/skia/modules/skottie/gm/SkottieGM.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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/gm.h"
9 #include "include/codec/SkCodec.h"
10 #include "include/codec/SkGifDecoder.h"
11 #include "include/core/SkColor.h"
12 #include "include/core/SkFontMgr.h"
13 #include "include/core/SkStream.h"
14 #include "modules/skottie/include/Skottie.h"
15 #include "modules/skottie/include/SkottieProperty.h"
16 #include "modules/skottie/utils/SkottieUtils.h"
17 #include "modules/skresources/include/SkResources.h"
18 #include "modules/skshaper/include/SkShaper_factory.h"
19 #include "modules/skshaper/utils/FactoryHelpers.h"
20 #include "tools/Resources.h"
21 #include "tools/fonts/FontToolUtils.h"
22 
23 #include <cmath>
24 #include <vector>
25 
26 namespace {
27 
28 static constexpr char kWebFontResource[] = "fonts/Roboto-Regular.ttf";
29 static constexpr char kSkottieResource[] = "skottie/skottie_sample_webfont.json";
30 
31 // Mock web font loader which serves a single local font (checked in under resources/).
32 class FakeWebFontProvider final : public skresources::ResourceProvider {
33 public:
FakeWebFontProvider()34     FakeWebFontProvider() : fTypeface(ToolUtils::CreateTypefaceFromResource(kWebFontResource)) {}
35 
loadTypeface(const char[],const char[]) const36     sk_sp<SkTypeface> loadTypeface(const char[], const char[]) const override {
37         return fTypeface;
38     }
39 
40 private:
41     sk_sp<SkTypeface> fTypeface;
42 
43     using INHERITED = skresources::ResourceProvider;
44 };
45 
46 } // namespace
47 
48 class SkottieWebFontGM : public skiagm::GM {
49 public:
50 protected:
getName() const51     SkString getName() const override { return SkString("skottie_webfont"); }
52 
getISize()53     SkISize getISize() override { return SkISize::Make(kSize, kSize); }
54 
onOnceBeforeDraw()55     void onOnceBeforeDraw() override {
56         if (auto stream = GetResourceAsStream(kSkottieResource)) {
57             fAnimation = skottie::Animation::Builder()
58                             .setFontManager(ToolUtils::TestFontMgr())
59                             .setResourceProvider(sk_make_sp<FakeWebFontProvider>())
60                             .setTextShapingFactory(SkShapers::BestAvailable())
61                             .make(stream.get());
62         }
63     }
64 
onDraw(SkCanvas * canvas,SkString * errorMsg)65     DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
66         if (!fAnimation) {
67             *errorMsg = "No animation";
68             return DrawResult::kFail;
69         }
70 
71         auto dest = SkRect::MakeWH(kSize, kSize);
72         fAnimation->render(canvas, &dest);
73         return DrawResult::kOk;
74     }
75 
onAnimate(double nanos)76     bool onAnimate(double nanos) override {
77         if (!fAnimation) {
78             return false;
79         }
80 
81         const auto duration = fAnimation->duration();
82         fAnimation->seek(std::fmod(1e-9 * nanos, duration) / duration);
83         return true;
84     }
85 
86 private:
87     inline static constexpr SkScalar kSize = 800;
88 
89     sk_sp<skottie::Animation> fAnimation;
90 
91     using INHERITED = skiagm::GM;
92 };
93 
94 DEF_GM(return new SkottieWebFontGM;)
95 
96 class SkottieColorizeGM : public skiagm::GM {
97 public:
SkottieColorizeGM(const char * name,const char * resource)98     SkottieColorizeGM(const char* name, const char* resource)
99         : fName(name)
100         , fResource(resource)
101     {}
102 
103 protected:
getName() const104     SkString getName() const override { return SkStringPrintf("skottie_colorize_%s", fName); }
105 
getISize()106     SkISize getISize() override { return SkISize::Make(kSize, kSize); }
107 
onOnceBeforeDraw()108     void onOnceBeforeDraw() override {
109         if (auto stream = GetResourceAsStream(fResource)) {
110             fPropManager = std::make_unique<skottie_utils::CustomPropertyManager>();
111             fAnimation   = skottie::Animation::Builder()
112                               .setFontManager(ToolUtils::TestFontMgr())
113                               .setPropertyObserver(fPropManager->getPropertyObserver())
114                               .setTextShapingFactory(SkShapers::BestAvailable())
115                               .make(stream.get());
116             fColorProps  = fPropManager->getColorProps();
117             fTextProps   = fPropManager->getTextProps();
118         }
119     }
120 
onDraw(SkCanvas * canvas,SkString * errorMsg)121     DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
122         if (!fAnimation) {
123             *errorMsg = "No animation";
124             return DrawResult::kFail;
125         }
126 
127         auto dest = SkRect::MakeWH(kSize, kSize);
128         fAnimation->render(canvas, &dest);
129         return DrawResult::kOk;
130     }
131 
onAnimate(double nanos)132     bool onAnimate(double nanos) override {
133         if (!fAnimation) {
134             return false;
135         }
136 
137         const auto duration = fAnimation->duration();
138         fAnimation->seek(std::fmod(1e-9 * nanos, duration) / duration);
139         return true;
140     }
141 
onChar(SkUnichar uni)142     bool onChar(SkUnichar uni) override {
143         static constexpr SkColor kColors[] = {
144             SK_ColorBLACK,
145             SK_ColorRED,
146             SK_ColorGREEN,
147             SK_ColorYELLOW,
148             SK_ColorCYAN,
149         };
150 
151         if (uni == 'c') {
152             fColorIndex = (fColorIndex + 1) % std::size(kColors);
153             for (const auto& prop : fColorProps) {
154                 fPropManager->setColor(prop, kColors[fColorIndex]);
155             }
156             for (const auto& prop : fTextProps) {
157                 auto txtval = fPropManager->getText(prop);
158                 txtval.fFillColor = kColors[fColorIndex];
159                 fPropManager->setText(prop, txtval);
160             }
161             return true;
162         }
163 
164         return false;
165     }
166 
167 private:
168     inline static constexpr SkScalar kSize = 800;
169 
170     const char*                                                fName;
171     const char*                                                fResource;
172 
173     sk_sp<skottie::Animation>                                  fAnimation;
174     std::unique_ptr<skottie_utils::CustomPropertyManager>      fPropManager;
175     std::vector<skottie_utils::CustomPropertyManager::PropKey> fColorProps,
176                                                                fTextProps;
177     size_t                                                     fColorIndex = 0;
178 
179     using INHERITED = skiagm::GM;
180 };
181 
182 DEF_GM(return new SkottieColorizeGM("color", "skottie/skottie_sample_search.json");)
183 DEF_GM(return new SkottieColorizeGM("text" , "skottie/skottie-text-animator-5.json");)
184 
185 class SkottieMultiFrameGM : public skiagm::GM {
186 public:
187 protected:
getName() const188     SkString getName() const override { return SkString("skottie_multiframe"); }
189 
getISize()190     SkISize getISize() override { return SkISize::Make(kSize, kSize); }
191 
onOnceBeforeDraw()192     void onOnceBeforeDraw() override {
193         if (auto stream = GetResourceAsStream("skottie/skottie_sample_multiframe.json")) {
194             fAnimation = skottie::Animation::Builder()
195                             .setResourceProvider(sk_make_sp<MultiFrameResourceProvider>())
196                             .make(stream.get());
197             fAnimation->seek(0);
198         }
199     }
200 
onDraw(SkCanvas * canvas,SkString * errorMsg)201     DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
202         if (!fAnimation) {
203             *errorMsg = "No animation";
204             return DrawResult::kFail;
205         }
206 
207         auto dest = SkRect::MakeWH(kSize, kSize);
208         fAnimation->render(canvas, &dest);
209         return DrawResult::kOk;
210     }
211 
onAnimate(double nanos)212     bool onAnimate(double nanos) override {
213         if (!fAnimation) {
214             return false;
215         }
216 
217         const auto duration = fAnimation->duration();
218         fAnimation->seek(std::fmod(1e-9 * nanos, duration) / duration);
219         return true;
220     }
221 
222 private:
223     class MultiFrameResourceProvider final : public skresources::ResourceProvider {
224     public:
loadImageAsset(const char[],const char[],const char[]) const225         sk_sp<skresources::ImageAsset> loadImageAsset(const char[], const char[],
226                                                       const char[]) const override {
227             sk_sp<SkData> data = GetResourceAsData("images/flightAnim.gif");
228             SkASSERT(data);
229             std::unique_ptr<SkCodec> codec = SkGifDecoder::Decode(data, nullptr);
230             SkASSERT(codec);
231             return skresources::MultiFrameImageAsset::Make(std::move(codec));
232         }
233     };
234 
235     inline static constexpr SkScalar kSize = 800;
236 
237     sk_sp<skottie::Animation> fAnimation;
238 
239     using INHERITED = skiagm::GM;
240 };
241 
242 DEF_GM(return new SkottieMultiFrameGM;)
243