skottie_bindings.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. /*
  2. * Copyright 2019 Google LLC
  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. #include "include/core/SkCanvas.h"
  8. #include "include/core/SkImage.h"
  9. #include "include/core/SkString.h"
  10. #include "include/core/SkTypes.h"
  11. #include "modules/skottie/include/Skottie.h"
  12. #include "modules/sksg/include/SkSGInvalidationController.h"
  13. #include "src/core/SkMakeUnique.h"
  14. #include <string>
  15. #include <vector>
  16. #include <emscripten.h>
  17. #include <emscripten/bind.h>
  18. #include "modules/canvaskit/WasmAliases.h"
  19. #if SK_INCLUDE_MANAGED_SKOTTIE
  20. #include "modules/skottie/include/SkottieProperty.h"
  21. #include "modules/skottie/utils/SkottieUtils.h"
  22. #endif // SK_INCLUDE_MANAGED_SKOTTIE
  23. using namespace emscripten;
  24. #if SK_INCLUDE_MANAGED_SKOTTIE
  25. namespace {
  26. class SkottieAssetProvider : public skottie::ResourceProvider {
  27. public:
  28. ~SkottieAssetProvider() override = default;
  29. // Tried using a map, but that gave strange errors like
  30. // https://emscripten.org/docs/porting/guidelines/function_pointer_issues.html
  31. // Not entirely sure why, but perhaps the iterator in the map was
  32. // confusing enscripten.
  33. using AssetVec = std::vector<std::pair<SkString, sk_sp<SkData>>>;
  34. static sk_sp<SkottieAssetProvider> Make(AssetVec assets) {
  35. if (assets.empty()) {
  36. return nullptr;
  37. }
  38. return sk_sp<SkottieAssetProvider>(new SkottieAssetProvider(std::move(assets)));
  39. }
  40. sk_sp<skottie::ImageAsset> loadImageAsset(const char[] /* path */,
  41. const char name[],
  42. const char[] /* id */) const override {
  43. // For CK/Skottie we ignore paths & IDs, and identify images based solely on name.
  44. if (auto data = this->findAsset(name)) {
  45. return skottie_utils::MultiFrameImageAsset::Make(std::move(data), true /* predecode */);
  46. }
  47. return nullptr;
  48. }
  49. sk_sp<SkData> loadFont(const char name[], const char[] /* url */) const override {
  50. // Same as images paths, we ignore font URLs.
  51. return this->findAsset(name);
  52. }
  53. private:
  54. explicit SkottieAssetProvider(AssetVec assets) : fAssets(std::move(assets)) {}
  55. sk_sp<SkData> findAsset(const char name[]) const {
  56. for (const auto& asset : fAssets) {
  57. if (asset.first.equals(name)) {
  58. return asset.second;
  59. }
  60. }
  61. SkDebugf("Could not find %s\n", name);
  62. return nullptr;
  63. }
  64. const AssetVec fAssets;
  65. };
  66. class ManagedAnimation final : public SkRefCnt {
  67. public:
  68. static sk_sp<ManagedAnimation> Make(const std::string& json, sk_sp<SkottieAssetProvider> ap) {
  69. auto mgr = skstd::make_unique<skottie_utils::CustomPropertyManager>();
  70. auto animation = skottie::Animation::Builder()
  71. .setMarkerObserver(mgr->getMarkerObserver())
  72. .setPropertyObserver(mgr->getPropertyObserver())
  73. .setResourceProvider(ap)
  74. .make(json.c_str(), json.size());
  75. return animation
  76. ? sk_sp<ManagedAnimation>(new ManagedAnimation(std::move(animation), std::move(mgr)))
  77. : nullptr;
  78. }
  79. ~ManagedAnimation() override = default;
  80. // skottie::Animation API
  81. void render(SkCanvas* canvas) const { fAnimation->render(canvas, nullptr); }
  82. void render(SkCanvas* canvas, const SkRect& dst) const { fAnimation->render(canvas, &dst); }
  83. // Returns a damage rect.
  84. SkRect seek(SkScalar t) {
  85. sksg::InvalidationController ic;
  86. fAnimation->seek(t, &ic);
  87. return ic.bounds();
  88. }
  89. SkScalar duration() const { return fAnimation->duration(); }
  90. const SkSize& size() const { return fAnimation->size(); }
  91. std::string version() const { return std::string(fAnimation->version().c_str()); }
  92. // CustomPropertyManager API
  93. JSArray getColorProps() const {
  94. JSArray props = emscripten::val::array();
  95. for (const auto& cp : fPropMgr->getColorProps()) {
  96. JSObject prop = emscripten::val::object();
  97. prop.set("key", cp);
  98. prop.set("value", fPropMgr->getColor(cp));
  99. props.call<void>("push", prop);
  100. }
  101. return props;
  102. }
  103. JSArray getOpacityProps() const {
  104. JSArray props = emscripten::val::array();
  105. for (const auto& op : fPropMgr->getOpacityProps()) {
  106. JSObject prop = emscripten::val::object();
  107. prop.set("key", op);
  108. prop.set("value", fPropMgr->getOpacity(op));
  109. props.call<void>("push", prop);
  110. }
  111. return props;
  112. }
  113. bool setColor(const std::string& key, SkColor c) {
  114. return fPropMgr->setColor(key, c);
  115. }
  116. bool setOpacity(const std::string& key, float o) {
  117. return fPropMgr->setOpacity(key, o);
  118. }
  119. JSArray getMarkers() const {
  120. JSArray markers = emscripten::val::array();
  121. for (const auto& m : fPropMgr->markers()) {
  122. JSObject marker = emscripten::val::object();
  123. marker.set("name", m.name);
  124. marker.set("t0" , m.t0);
  125. marker.set("t1" , m.t1);
  126. markers.call<void>("push", marker);
  127. }
  128. return markers;
  129. }
  130. private:
  131. ManagedAnimation(sk_sp<skottie::Animation> animation,
  132. std::unique_ptr<skottie_utils::CustomPropertyManager> propMgr)
  133. : fAnimation(std::move(animation))
  134. , fPropMgr(std::move(propMgr)) {}
  135. sk_sp<skottie::Animation> fAnimation;
  136. std::unique_ptr<skottie_utils::CustomPropertyManager> fPropMgr;
  137. };
  138. } // anonymous ns
  139. #endif // SK_INCLUDE_MANAGED_SKOTTIE
  140. EMSCRIPTEN_BINDINGS(Skottie) {
  141. // Animation things (may eventually go in own library)
  142. class_<skottie::Animation>("Animation")
  143. .smart_ptr<sk_sp<skottie::Animation>>("sk_sp<Animation>")
  144. .function("version", optional_override([](skottie::Animation& self)->std::string {
  145. return std::string(self.version().c_str());
  146. }))
  147. .function("size", &skottie::Animation::size)
  148. .function("duration", &skottie::Animation::duration)
  149. .function("seek", optional_override([](skottie::Animation& self, SkScalar t)->void {
  150. self.seek(t);
  151. }))
  152. .function("render", optional_override([](skottie::Animation& self, SkCanvas* canvas)->void {
  153. self.render(canvas, nullptr);
  154. }), allow_raw_pointers())
  155. .function("render", optional_override([](skottie::Animation& self, SkCanvas* canvas,
  156. const SkRect r)->void {
  157. self.render(canvas, &r);
  158. }), allow_raw_pointers());
  159. function("MakeAnimation", optional_override([](std::string json)->sk_sp<skottie::Animation> {
  160. return skottie::Animation::Make(json.c_str(), json.length());
  161. }));
  162. constant("skottie", true);
  163. #if SK_INCLUDE_MANAGED_SKOTTIE
  164. class_<ManagedAnimation>("ManagedAnimation")
  165. .smart_ptr<sk_sp<ManagedAnimation>>("sk_sp<ManagedAnimation>")
  166. .function("version" , &ManagedAnimation::version)
  167. .function("size" , &ManagedAnimation::size)
  168. .function("duration" , &ManagedAnimation::duration)
  169. .function("seek" , &ManagedAnimation::seek)
  170. .function("render" , select_overload<void(SkCanvas*) const>(&ManagedAnimation::render), allow_raw_pointers())
  171. .function("render" , select_overload<void(SkCanvas*, const SkRect&) const>
  172. (&ManagedAnimation::render), allow_raw_pointers())
  173. .function("setColor" , &ManagedAnimation::setColor)
  174. .function("setOpacity", &ManagedAnimation::setOpacity)
  175. .function("getMarkers", &ManagedAnimation::getMarkers)
  176. .function("getColorProps" , &ManagedAnimation::getColorProps)
  177. .function("getOpacityProps", &ManagedAnimation::getOpacityProps);
  178. function("_MakeManagedAnimation", optional_override([](std::string json,
  179. size_t assetCount,
  180. uintptr_t /* char** */ nptr,
  181. uintptr_t /* uint8_t** */ dptr,
  182. uintptr_t /* size_t* */ sptr)
  183. ->sk_sp<ManagedAnimation> {
  184. const auto assetNames = reinterpret_cast<char** >(nptr);
  185. const auto assetDatas = reinterpret_cast<uint8_t**>(dptr);
  186. const auto assetSizes = reinterpret_cast<size_t* >(sptr);
  187. SkottieAssetProvider::AssetVec assets;
  188. assets.reserve(assetCount);
  189. for (size_t i = 0; i < assetCount; i++) {
  190. auto name = SkString(assetNames[i]);
  191. auto bytes = SkData::MakeFromMalloc(assetDatas[i], assetSizes[i]);
  192. assets.push_back(std::make_pair(std::move(name), std::move(bytes)));
  193. }
  194. return ManagedAnimation::Make(json, SkottieAssetProvider::Make(std::move(assets)));
  195. }));
  196. constant("managed_skottie", true);
  197. #endif // SK_INCLUDE_MANAGED_SKOTTIE
  198. }