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