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