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: 31 FakeWebFontProvider() : fFontData(GetResourceAsData(kWebFontResource)) {} 32 33 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: 48 SkString onShortName() override { 49 return SkString("skottie_webfont"); 50 } 51 52 SkISize onISize() override { 53 return SkISize::Make(kSize, kSize); 54 } 55 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 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 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: 99 SkString onShortName() override { 100 return SkString("skottie_colorize"); 101 } 102 103 SkISize onISize() override { 104 return SkISize::Make(kSize, kSize); 105 } 106 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 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 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 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: 174 SkString onShortName() override { 175 return SkString("skottie_multiframe"); 176 } 177 178 SkISize onISize() override { 179 return SkISize::Make(kSize, kSize); 180 } 181 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 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 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: 214 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