xref: /aosp_15_r20/external/skia/modules/canvaskit/skottie_bindings.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2019 Google LLC
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "include/codec/SkCodec.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFontMgr.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImage.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkStream.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkOnce.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "modules/canvaskit/WasmCommon.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skottie/include/Skottie.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skottie/include/SkottieProperty.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skottie/include/SlotManager.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skottie/utils/SkottieUtils.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skottie/utils/TextEditor.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skparagraph/include/Paragraph.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skresources/include/SkResources.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "modules/sksg/include/SkSGInvalidationController.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skshaper/utils/FactoryHelpers.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skunicode/include/SkUnicode.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkUTF.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "src/ports/SkTypeface_FreeType.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "tools/skui/InputState.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "tools/skui/ModifierKey.h"
31*c8dee2aaSAndroid Build Coastguard Worker 
32*c8dee2aaSAndroid Build Coastguard Worker #include <string>
33*c8dee2aaSAndroid Build Coastguard Worker #include <vector>
34*c8dee2aaSAndroid Build Coastguard Worker #include <emscripten.h>
35*c8dee2aaSAndroid Build Coastguard Worker #include <emscripten/bind.h>
36*c8dee2aaSAndroid Build Coastguard Worker 
37*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_CODEC_DECODES_GIF)
38*c8dee2aaSAndroid Build Coastguard Worker #include "include/codec/SkGifDecoder.h"
39*c8dee2aaSAndroid Build Coastguard Worker #endif
40*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_CODEC_DECODES_JPEG)
41*c8dee2aaSAndroid Build Coastguard Worker #include "include/codec/SkJpegDecoder.h"
42*c8dee2aaSAndroid Build Coastguard Worker #endif
43*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_CODEC_DECODES_PNG)
44*c8dee2aaSAndroid Build Coastguard Worker #include "include/codec/SkPngDecoder.h"
45*c8dee2aaSAndroid Build Coastguard Worker #endif
46*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_CODEC_DECODES_WEBP)
47*c8dee2aaSAndroid Build Coastguard Worker #include "include/codec/SkWebpDecoder.h"
48*c8dee2aaSAndroid Build Coastguard Worker #endif
49*c8dee2aaSAndroid Build Coastguard Worker 
50*c8dee2aaSAndroid Build Coastguard Worker #if !defined(CK_NO_FONTS)
51*c8dee2aaSAndroid Build Coastguard Worker #include "include/ports/SkFontMgr_empty.h"
52*c8dee2aaSAndroid Build Coastguard Worker #endif
53*c8dee2aaSAndroid Build Coastguard Worker 
54*c8dee2aaSAndroid Build Coastguard Worker using namespace emscripten;
55*c8dee2aaSAndroid Build Coastguard Worker namespace para = skia::textlayout;
56*c8dee2aaSAndroid Build Coastguard Worker namespace {
57*c8dee2aaSAndroid Build Coastguard Worker 
58*c8dee2aaSAndroid Build Coastguard Worker struct SimpleSlottableTextProperty {
59*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkTypeface> typeface;
60*c8dee2aaSAndroid Build Coastguard Worker     std::string text;
61*c8dee2aaSAndroid Build Coastguard Worker 
62*c8dee2aaSAndroid Build Coastguard Worker     float textSize;
63*c8dee2aaSAndroid Build Coastguard Worker     float minTextSize;
64*c8dee2aaSAndroid Build Coastguard Worker     float maxTextSize;
65*c8dee2aaSAndroid Build Coastguard Worker     float strokeWidth;
66*c8dee2aaSAndroid Build Coastguard Worker     float lineHeight;
67*c8dee2aaSAndroid Build Coastguard Worker     float lineShift;
68*c8dee2aaSAndroid Build Coastguard Worker     float ascent;
69*c8dee2aaSAndroid Build Coastguard Worker     float maxLines;
70*c8dee2aaSAndroid Build Coastguard Worker 
71*c8dee2aaSAndroid Build Coastguard Worker     para::TextAlign horizAlign;
72*c8dee2aaSAndroid Build Coastguard Worker     skottie::Shaper::VAlign vertAlign;
73*c8dee2aaSAndroid Build Coastguard Worker     skottie::Shaper::ResizePolicy resize;
74*c8dee2aaSAndroid Build Coastguard Worker     SkUnicode::LineBreakType lineBreak;
75*c8dee2aaSAndroid Build Coastguard Worker     para::TextDirection direction;
76*c8dee2aaSAndroid Build Coastguard Worker     SkPaint::Join strokeJoin;
77*c8dee2aaSAndroid Build Coastguard Worker 
78*c8dee2aaSAndroid Build Coastguard Worker     WASMPointerF32 boundingBoxPtr;
79*c8dee2aaSAndroid Build Coastguard Worker     WASMPointerF32 fillColorPtr;
80*c8dee2aaSAndroid Build Coastguard Worker     WASMPointerF32 strokeColorPtr;
81*c8dee2aaSAndroid Build Coastguard Worker 
operator skottie::TextPropertyValue__anonaf201dba0111::SimpleSlottableTextProperty82*c8dee2aaSAndroid Build Coastguard Worker     operator skottie::TextPropertyValue() const {
83*c8dee2aaSAndroid Build Coastguard Worker         skottie::TextPropertyValue textProperty;
84*c8dee2aaSAndroid Build Coastguard Worker 
85*c8dee2aaSAndroid Build Coastguard Worker         textProperty.fTypeface = this->typeface;
86*c8dee2aaSAndroid Build Coastguard Worker         textProperty.fText = SkString(this->text);
87*c8dee2aaSAndroid Build Coastguard Worker         textProperty.fTextSize = this->textSize;
88*c8dee2aaSAndroid Build Coastguard Worker         textProperty.fMinTextSize = this->minTextSize;
89*c8dee2aaSAndroid Build Coastguard Worker         textProperty.fMaxTextSize = this->maxTextSize;
90*c8dee2aaSAndroid Build Coastguard Worker         textProperty.fStrokeWidth = this->strokeWidth;
91*c8dee2aaSAndroid Build Coastguard Worker         textProperty.fLineHeight = this->lineHeight;
92*c8dee2aaSAndroid Build Coastguard Worker         textProperty.fLineShift = this->lineShift;
93*c8dee2aaSAndroid Build Coastguard Worker         textProperty.fAscent = this->ascent;
94*c8dee2aaSAndroid Build Coastguard Worker         textProperty.fMaxLines = this->maxLines;
95*c8dee2aaSAndroid Build Coastguard Worker 
96*c8dee2aaSAndroid Build Coastguard Worker         switch (this->horizAlign) {
97*c8dee2aaSAndroid Build Coastguard Worker         case para::TextAlign::kLeft:
98*c8dee2aaSAndroid Build Coastguard Worker             textProperty.fHAlign = SkTextUtils::Align::kLeft_Align;
99*c8dee2aaSAndroid Build Coastguard Worker             break;
100*c8dee2aaSAndroid Build Coastguard Worker         case para::TextAlign::kCenter:
101*c8dee2aaSAndroid Build Coastguard Worker             textProperty.fHAlign = SkTextUtils::Align::kCenter_Align;
102*c8dee2aaSAndroid Build Coastguard Worker             break;
103*c8dee2aaSAndroid Build Coastguard Worker         case para::TextAlign::kRight:
104*c8dee2aaSAndroid Build Coastguard Worker             textProperty.fHAlign = SkTextUtils::Align::kRight_Align;
105*c8dee2aaSAndroid Build Coastguard Worker             break;
106*c8dee2aaSAndroid Build Coastguard Worker         default:
107*c8dee2aaSAndroid Build Coastguard Worker             textProperty.fHAlign = SkTextUtils::Align::kLeft_Align;
108*c8dee2aaSAndroid Build Coastguard Worker             break;
109*c8dee2aaSAndroid Build Coastguard Worker         }
110*c8dee2aaSAndroid Build Coastguard Worker 
111*c8dee2aaSAndroid Build Coastguard Worker         textProperty.fVAlign = this->vertAlign;
112*c8dee2aaSAndroid Build Coastguard Worker         textProperty.fResize = this->resize;
113*c8dee2aaSAndroid Build Coastguard Worker 
114*c8dee2aaSAndroid Build Coastguard Worker         if (this->lineBreak == SkUnicode::LineBreakType::kSoftLineBreak) {
115*c8dee2aaSAndroid Build Coastguard Worker             textProperty.fLineBreak = skottie::Shaper::LinebreakPolicy::kParagraph;
116*c8dee2aaSAndroid Build Coastguard Worker         } else {
117*c8dee2aaSAndroid Build Coastguard Worker             textProperty.fLineBreak = skottie::Shaper::LinebreakPolicy::kExplicit;
118*c8dee2aaSAndroid Build Coastguard Worker         }
119*c8dee2aaSAndroid Build Coastguard Worker 
120*c8dee2aaSAndroid Build Coastguard Worker         if (this->direction == para::TextDirection::kRtl) {
121*c8dee2aaSAndroid Build Coastguard Worker             textProperty.fDirection = skottie::Shaper::Direction::kRTL;
122*c8dee2aaSAndroid Build Coastguard Worker         } else {
123*c8dee2aaSAndroid Build Coastguard Worker             textProperty.fDirection = skottie::Shaper::Direction::kLTR;
124*c8dee2aaSAndroid Build Coastguard Worker         }
125*c8dee2aaSAndroid Build Coastguard Worker 
126*c8dee2aaSAndroid Build Coastguard Worker         textProperty.fStrokeJoin = this->strokeJoin;
127*c8dee2aaSAndroid Build Coastguard Worker 
128*c8dee2aaSAndroid Build Coastguard Worker         textProperty.fBox = reinterpret_cast<SkRect*>(this->boundingBoxPtr)[0];
129*c8dee2aaSAndroid Build Coastguard Worker         textProperty.fFillColor = ptrToSkColor4f(this->fillColorPtr).toSkColor();
130*c8dee2aaSAndroid Build Coastguard Worker         textProperty.fStrokeColor = ptrToSkColor4f(this->strokeColorPtr).toSkColor();
131*c8dee2aaSAndroid Build Coastguard Worker 
132*c8dee2aaSAndroid Build Coastguard Worker         return textProperty;
133*c8dee2aaSAndroid Build Coastguard Worker     }
134*c8dee2aaSAndroid Build Coastguard Worker };
135*c8dee2aaSAndroid Build Coastguard Worker 
136*c8dee2aaSAndroid Build Coastguard Worker // WebTrack wraps a JS object that has a 'seek' method.
137*c8dee2aaSAndroid Build Coastguard Worker // Playback logic is kept there.
138*c8dee2aaSAndroid Build Coastguard Worker class WebTrack final : public skresources::ExternalTrackAsset {
139*c8dee2aaSAndroid Build Coastguard Worker public:
WebTrack(emscripten::val player)140*c8dee2aaSAndroid Build Coastguard Worker     explicit WebTrack(emscripten::val player) : fPlayer(std::move(player)) {}
141*c8dee2aaSAndroid Build Coastguard Worker 
142*c8dee2aaSAndroid Build Coastguard Worker private:
seek(float t)143*c8dee2aaSAndroid Build Coastguard Worker     void seek(float t) override {
144*c8dee2aaSAndroid Build Coastguard Worker         fPlayer.call<void>("seek", val(t));
145*c8dee2aaSAndroid Build Coastguard Worker     }
146*c8dee2aaSAndroid Build Coastguard Worker 
147*c8dee2aaSAndroid Build Coastguard Worker     const emscripten::val fPlayer;
148*c8dee2aaSAndroid Build Coastguard Worker };
149*c8dee2aaSAndroid Build Coastguard Worker 
150*c8dee2aaSAndroid Build Coastguard Worker class SkottieAssetProvider : public skottie::ResourceProvider {
151*c8dee2aaSAndroid Build Coastguard Worker public:
152*c8dee2aaSAndroid Build Coastguard Worker     ~SkottieAssetProvider() override = default;
153*c8dee2aaSAndroid Build Coastguard Worker 
154*c8dee2aaSAndroid Build Coastguard Worker     // Tried using a map, but that gave strange errors like
155*c8dee2aaSAndroid Build Coastguard Worker     // https://emscripten.org/docs/porting/guidelines/function_pointer_issues.html
156*c8dee2aaSAndroid Build Coastguard Worker     // Not entirely sure why, but perhaps the iterator in the map was
157*c8dee2aaSAndroid Build Coastguard Worker     // confusing enscripten.
158*c8dee2aaSAndroid Build Coastguard Worker     using AssetVec = std::vector<std::pair<SkString, sk_sp<SkData>>>;
159*c8dee2aaSAndroid Build Coastguard Worker 
Make(AssetVec assets,emscripten::val soundMap)160*c8dee2aaSAndroid Build Coastguard Worker     static sk_sp<SkottieAssetProvider> Make(AssetVec assets, emscripten::val soundMap) {
161*c8dee2aaSAndroid Build Coastguard Worker         return sk_sp<SkottieAssetProvider>(new SkottieAssetProvider(std::move(assets),
162*c8dee2aaSAndroid Build Coastguard Worker                                                                     std::move(soundMap)));
163*c8dee2aaSAndroid Build Coastguard Worker     }
164*c8dee2aaSAndroid Build Coastguard Worker 
loadImageAsset(const char[],const char name[],const char[]) const165*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<skottie::ImageAsset> loadImageAsset(const char[] /* path */,
166*c8dee2aaSAndroid Build Coastguard Worker                                               const char name[],
167*c8dee2aaSAndroid Build Coastguard Worker                                               const char[] /* id */) const override {
168*c8dee2aaSAndroid Build Coastguard Worker         // For CK/Skottie we ignore paths & IDs, and identify images based solely on name.
169*c8dee2aaSAndroid Build Coastguard Worker         if (auto data = this->findAsset(name)) {
170*c8dee2aaSAndroid Build Coastguard Worker             auto codec = DecodeImageData(data);
171*c8dee2aaSAndroid Build Coastguard Worker             if (!codec) {
172*c8dee2aaSAndroid Build Coastguard Worker                 return nullptr;
173*c8dee2aaSAndroid Build Coastguard Worker             }
174*c8dee2aaSAndroid Build Coastguard Worker             return skresources::MultiFrameImageAsset::Make(std::move(codec));
175*c8dee2aaSAndroid Build Coastguard Worker         }
176*c8dee2aaSAndroid Build Coastguard Worker 
177*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
178*c8dee2aaSAndroid Build Coastguard Worker     }
179*c8dee2aaSAndroid Build Coastguard Worker 
loadAudioAsset(const char[],const char[],const char id[])180*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<skresources::ExternalTrackAsset> loadAudioAsset(const char[] /* path */,
181*c8dee2aaSAndroid Build Coastguard Worker                                                           const char[] /* name */,
182*c8dee2aaSAndroid Build Coastguard Worker                                                           const char id[]) override {
183*c8dee2aaSAndroid Build Coastguard Worker         emscripten::val player = this->findSoundAsset(id);
184*c8dee2aaSAndroid Build Coastguard Worker         if (player.as<bool>()) {
185*c8dee2aaSAndroid Build Coastguard Worker             return sk_make_sp<WebTrack>(std::move(player));
186*c8dee2aaSAndroid Build Coastguard Worker         }
187*c8dee2aaSAndroid Build Coastguard Worker 
188*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
189*c8dee2aaSAndroid Build Coastguard Worker     }
190*c8dee2aaSAndroid Build Coastguard Worker 
loadTypeface(const char name[],const char[]) const191*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkTypeface> loadTypeface(const char name[], const char[] /* url */) const override {
192*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<SkData> faceData = this->findAsset(name);
193*c8dee2aaSAndroid Build Coastguard Worker         if (!faceData) {
194*c8dee2aaSAndroid Build Coastguard Worker             return nullptr;
195*c8dee2aaSAndroid Build Coastguard Worker         }
196*c8dee2aaSAndroid Build Coastguard Worker         auto stream = std::make_unique<SkMemoryStream>(faceData);
197*c8dee2aaSAndroid Build Coastguard Worker         return SkTypeface_FreeType::MakeFromStream(std::move(stream), SkFontArguments());
198*c8dee2aaSAndroid Build Coastguard Worker     }
199*c8dee2aaSAndroid Build Coastguard Worker 
load(const char[],const char name[]) const200*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkData> load(const char[]/*path*/, const char name[]) const override {
201*c8dee2aaSAndroid Build Coastguard Worker         // Ignore paths.
202*c8dee2aaSAndroid Build Coastguard Worker         return this->findAsset(name);
203*c8dee2aaSAndroid Build Coastguard Worker     }
204*c8dee2aaSAndroid Build Coastguard Worker 
205*c8dee2aaSAndroid Build Coastguard Worker private:
SkottieAssetProvider(AssetVec assets,emscripten::val soundMap)206*c8dee2aaSAndroid Build Coastguard Worker     explicit SkottieAssetProvider(AssetVec assets, emscripten::val soundMap)
207*c8dee2aaSAndroid Build Coastguard Worker     : fAssets(std::move(assets))
208*c8dee2aaSAndroid Build Coastguard Worker     , fSoundMap(std::move(soundMap)) {}
209*c8dee2aaSAndroid Build Coastguard Worker 
findAsset(const char name[]) const210*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkData> findAsset(const char name[]) const {
211*c8dee2aaSAndroid Build Coastguard Worker         for (const auto& asset : fAssets) {
212*c8dee2aaSAndroid Build Coastguard Worker             if (asset.first.equals(name)) {
213*c8dee2aaSAndroid Build Coastguard Worker                 return asset.second;
214*c8dee2aaSAndroid Build Coastguard Worker             }
215*c8dee2aaSAndroid Build Coastguard Worker         }
216*c8dee2aaSAndroid Build Coastguard Worker 
217*c8dee2aaSAndroid Build Coastguard Worker         SkDebugf("Could not find %s\n", name);
218*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
219*c8dee2aaSAndroid Build Coastguard Worker     }
220*c8dee2aaSAndroid Build Coastguard Worker 
findSoundAsset(const char name[]) const221*c8dee2aaSAndroid Build Coastguard Worker     emscripten::val findSoundAsset(const char name[]) const {
222*c8dee2aaSAndroid Build Coastguard Worker         if (fSoundMap.as<bool>() && fSoundMap.hasOwnProperty("getPlayer")) {
223*c8dee2aaSAndroid Build Coastguard Worker             emscripten::val player = fSoundMap.call<emscripten::val>("getPlayer", val(name));
224*c8dee2aaSAndroid Build Coastguard Worker             if (player.as<bool>() && player.hasOwnProperty("seek")) {
225*c8dee2aaSAndroid Build Coastguard Worker                 return player;
226*c8dee2aaSAndroid Build Coastguard Worker             }
227*c8dee2aaSAndroid Build Coastguard Worker         }
228*c8dee2aaSAndroid Build Coastguard Worker         return emscripten::val::null();
229*c8dee2aaSAndroid Build Coastguard Worker     }
230*c8dee2aaSAndroid Build Coastguard Worker 
231*c8dee2aaSAndroid Build Coastguard Worker     const AssetVec fAssets;
232*c8dee2aaSAndroid Build Coastguard Worker     const emscripten::val fSoundMap;
233*c8dee2aaSAndroid Build Coastguard Worker };
234*c8dee2aaSAndroid Build Coastguard Worker 
235*c8dee2aaSAndroid Build Coastguard Worker // Wraps a JS object with 'onError' and 'onWarning' methods.
236*c8dee2aaSAndroid Build Coastguard Worker class JSLogger final : public skottie::Logger {
237*c8dee2aaSAndroid Build Coastguard Worker public:
Make(emscripten::val logger)238*c8dee2aaSAndroid Build Coastguard Worker     static sk_sp<JSLogger> Make(emscripten::val logger) {
239*c8dee2aaSAndroid Build Coastguard Worker         return logger.as<bool>()
240*c8dee2aaSAndroid Build Coastguard Worker             && logger.hasOwnProperty(kWrnFunc)
241*c8dee2aaSAndroid Build Coastguard Worker             && logger.hasOwnProperty(kErrFunc)
242*c8dee2aaSAndroid Build Coastguard Worker                 ? sk_sp<JSLogger>(new JSLogger(std::move(logger)))
243*c8dee2aaSAndroid Build Coastguard Worker                 : nullptr;
244*c8dee2aaSAndroid Build Coastguard Worker     }
245*c8dee2aaSAndroid Build Coastguard Worker 
246*c8dee2aaSAndroid Build Coastguard Worker private:
JSLogger(emscripten::val logger)247*c8dee2aaSAndroid Build Coastguard Worker     explicit JSLogger(emscripten::val logger) : fLogger(std::move(logger)) {}
248*c8dee2aaSAndroid Build Coastguard Worker 
log(Level lvl,const char msg[],const char * json)249*c8dee2aaSAndroid Build Coastguard Worker     void log(Level lvl, const char msg[], const char* json) override {
250*c8dee2aaSAndroid Build Coastguard Worker         const auto* func = lvl == Level::kError ? kErrFunc : kWrnFunc;
251*c8dee2aaSAndroid Build Coastguard Worker         fLogger.call<void>(func, std::string(msg), std::string(json));
252*c8dee2aaSAndroid Build Coastguard Worker     }
253*c8dee2aaSAndroid Build Coastguard Worker 
254*c8dee2aaSAndroid Build Coastguard Worker     inline static constexpr char kWrnFunc[] = "onWarning",
255*c8dee2aaSAndroid Build Coastguard Worker                                  kErrFunc[] = "onError";
256*c8dee2aaSAndroid Build Coastguard Worker 
257*c8dee2aaSAndroid Build Coastguard Worker     const emscripten::val fLogger;
258*c8dee2aaSAndroid Build Coastguard Worker };
259*c8dee2aaSAndroid Build Coastguard Worker 
260*c8dee2aaSAndroid Build Coastguard Worker class ManagedAnimation final : public SkRefCnt {
261*c8dee2aaSAndroid Build Coastguard Worker public:
Make(const std::string & json,sk_sp<skottie::ResourceProvider> rp,std::string prop_prefix,emscripten::val logger)262*c8dee2aaSAndroid Build Coastguard Worker     static sk_sp<ManagedAnimation> Make(const std::string& json,
263*c8dee2aaSAndroid Build Coastguard Worker                                         sk_sp<skottie::ResourceProvider> rp,
264*c8dee2aaSAndroid Build Coastguard Worker                                         std::string prop_prefix,
265*c8dee2aaSAndroid Build Coastguard Worker                                         emscripten::val logger) {
266*c8dee2aaSAndroid Build Coastguard Worker         auto mgr = std::make_unique<skottie_utils::CustomPropertyManager>(
267*c8dee2aaSAndroid Build Coastguard Worker                         skottie_utils::CustomPropertyManager::Mode::kCollapseProperties,
268*c8dee2aaSAndroid Build Coastguard Worker                         prop_prefix.c_str());
269*c8dee2aaSAndroid Build Coastguard Worker         static constexpr char kInterceptPrefix[] = "__";
270*c8dee2aaSAndroid Build Coastguard Worker         auto pinterceptor =
271*c8dee2aaSAndroid Build Coastguard Worker             sk_make_sp<skottie_utils::ExternalAnimationPrecompInterceptor>(rp, kInterceptPrefix);
272*c8dee2aaSAndroid Build Coastguard Worker         skottie::Animation::Builder builder;
273*c8dee2aaSAndroid Build Coastguard Worker         builder.setMarkerObserver(mgr->getMarkerObserver())
274*c8dee2aaSAndroid Build Coastguard Worker                .setPropertyObserver(mgr->getPropertyObserver())
275*c8dee2aaSAndroid Build Coastguard Worker                .setResourceProvider(rp)
276*c8dee2aaSAndroid Build Coastguard Worker                .setPrecompInterceptor(std::move(pinterceptor))
277*c8dee2aaSAndroid Build Coastguard Worker                .setTextShapingFactory(SkShapers::BestAvailable())
278*c8dee2aaSAndroid Build Coastguard Worker                .setLogger(JSLogger::Make(std::move(logger)));
279*c8dee2aaSAndroid Build Coastguard Worker         auto animation = builder.make(json.c_str(), json.size());
280*c8dee2aaSAndroid Build Coastguard Worker         auto slotManager = builder.getSlotManager();
281*c8dee2aaSAndroid Build Coastguard Worker 
282*c8dee2aaSAndroid Build Coastguard Worker         return animation
283*c8dee2aaSAndroid Build Coastguard Worker             ? sk_sp<ManagedAnimation>(new ManagedAnimation(std::move(animation), std::move(mgr),
284*c8dee2aaSAndroid Build Coastguard Worker                                                            std::move(slotManager), std::move(rp)))
285*c8dee2aaSAndroid Build Coastguard Worker             : nullptr;
286*c8dee2aaSAndroid Build Coastguard Worker     }
287*c8dee2aaSAndroid Build Coastguard Worker 
288*c8dee2aaSAndroid Build Coastguard Worker     ~ManagedAnimation() override = default;
289*c8dee2aaSAndroid Build Coastguard Worker 
290*c8dee2aaSAndroid Build Coastguard Worker     // skottie::Animation API
render(SkCanvas * canvas,const SkRect * dst) const291*c8dee2aaSAndroid Build Coastguard Worker     void render(SkCanvas* canvas, const SkRect* dst) const { fAnimation->render(canvas, dst); }
292*c8dee2aaSAndroid Build Coastguard Worker     // Returns a damage rect.
seek(SkScalar t)293*c8dee2aaSAndroid Build Coastguard Worker     SkRect seek(SkScalar t) {
294*c8dee2aaSAndroid Build Coastguard Worker         sksg::InvalidationController ic;
295*c8dee2aaSAndroid Build Coastguard Worker         fAnimation->seek(t, &ic);
296*c8dee2aaSAndroid Build Coastguard Worker         return ic.bounds();
297*c8dee2aaSAndroid Build Coastguard Worker     }
298*c8dee2aaSAndroid Build Coastguard Worker     // Returns a damage rect.
seekFrame(double t)299*c8dee2aaSAndroid Build Coastguard Worker     SkRect seekFrame(double t) {
300*c8dee2aaSAndroid Build Coastguard Worker         sksg::InvalidationController ic;
301*c8dee2aaSAndroid Build Coastguard Worker         fAnimation->seekFrame(t, &ic);
302*c8dee2aaSAndroid Build Coastguard Worker         return ic.bounds();
303*c8dee2aaSAndroid Build Coastguard Worker     }
duration() const304*c8dee2aaSAndroid Build Coastguard Worker     double duration() const { return fAnimation->duration(); }
fps() const305*c8dee2aaSAndroid Build Coastguard Worker     double fps() const { return fAnimation->fps(); }
size() const306*c8dee2aaSAndroid Build Coastguard Worker     const SkSize& size() const { return fAnimation->size(); }
version() const307*c8dee2aaSAndroid Build Coastguard Worker     std::string version() const { return std::string(fAnimation->version().c_str()); }
308*c8dee2aaSAndroid Build Coastguard Worker 
309*c8dee2aaSAndroid Build Coastguard Worker     // CustomPropertyManager API
getColorProps() const310*c8dee2aaSAndroid Build Coastguard Worker     JSArray getColorProps() const {
311*c8dee2aaSAndroid Build Coastguard Worker         JSArray props = emscripten::val::array();
312*c8dee2aaSAndroid Build Coastguard Worker 
313*c8dee2aaSAndroid Build Coastguard Worker         for (const auto& cp : fPropMgr->getColorProps()) {
314*c8dee2aaSAndroid Build Coastguard Worker             JSObject prop = emscripten::val::object();
315*c8dee2aaSAndroid Build Coastguard Worker             prop.set("key", cp);
316*c8dee2aaSAndroid Build Coastguard Worker             prop.set("value", fPropMgr->getColor(cp));
317*c8dee2aaSAndroid Build Coastguard Worker             props.call<void>("push", prop);
318*c8dee2aaSAndroid Build Coastguard Worker         }
319*c8dee2aaSAndroid Build Coastguard Worker 
320*c8dee2aaSAndroid Build Coastguard Worker         return props;
321*c8dee2aaSAndroid Build Coastguard Worker     }
322*c8dee2aaSAndroid Build Coastguard Worker 
getOpacityProps() const323*c8dee2aaSAndroid Build Coastguard Worker     JSArray getOpacityProps() const {
324*c8dee2aaSAndroid Build Coastguard Worker         JSArray props = emscripten::val::array();
325*c8dee2aaSAndroid Build Coastguard Worker 
326*c8dee2aaSAndroid Build Coastguard Worker         for (const auto& op : fPropMgr->getOpacityProps()) {
327*c8dee2aaSAndroid Build Coastguard Worker             JSObject prop = emscripten::val::object();
328*c8dee2aaSAndroid Build Coastguard Worker             prop.set("key", op);
329*c8dee2aaSAndroid Build Coastguard Worker             prop.set("value", fPropMgr->getOpacity(op));
330*c8dee2aaSAndroid Build Coastguard Worker             props.call<void>("push", prop);
331*c8dee2aaSAndroid Build Coastguard Worker         }
332*c8dee2aaSAndroid Build Coastguard Worker 
333*c8dee2aaSAndroid Build Coastguard Worker         return props;
334*c8dee2aaSAndroid Build Coastguard Worker     }
335*c8dee2aaSAndroid Build Coastguard Worker 
getTextProps() const336*c8dee2aaSAndroid Build Coastguard Worker     JSArray getTextProps() const {
337*c8dee2aaSAndroid Build Coastguard Worker         JSArray props = emscripten::val::array();
338*c8dee2aaSAndroid Build Coastguard Worker 
339*c8dee2aaSAndroid Build Coastguard Worker         for (const auto& key : fPropMgr->getTextProps()) {
340*c8dee2aaSAndroid Build Coastguard Worker             const auto txt = fPropMgr->getText(key);
341*c8dee2aaSAndroid Build Coastguard Worker             JSObject txt_val = emscripten::val::object();
342*c8dee2aaSAndroid Build Coastguard Worker             txt_val.set("text", txt.fText.c_str());
343*c8dee2aaSAndroid Build Coastguard Worker             txt_val.set("size", txt.fTextSize);
344*c8dee2aaSAndroid Build Coastguard Worker 
345*c8dee2aaSAndroid Build Coastguard Worker             JSObject prop = emscripten::val::object();
346*c8dee2aaSAndroid Build Coastguard Worker             prop.set("key", key);
347*c8dee2aaSAndroid Build Coastguard Worker             prop.set("value", std::move(txt_val));
348*c8dee2aaSAndroid Build Coastguard Worker 
349*c8dee2aaSAndroid Build Coastguard Worker             props.call<void>("push", prop);
350*c8dee2aaSAndroid Build Coastguard Worker         }
351*c8dee2aaSAndroid Build Coastguard Worker 
352*c8dee2aaSAndroid Build Coastguard Worker         return props;
353*c8dee2aaSAndroid Build Coastguard Worker     }
354*c8dee2aaSAndroid Build Coastguard Worker 
getTransformProps() const355*c8dee2aaSAndroid Build Coastguard Worker     JSArray getTransformProps() const {
356*c8dee2aaSAndroid Build Coastguard Worker         JSArray props = emscripten::val::array();
357*c8dee2aaSAndroid Build Coastguard Worker 
358*c8dee2aaSAndroid Build Coastguard Worker         for (const auto& key : fPropMgr->getTransformProps()) {
359*c8dee2aaSAndroid Build Coastguard Worker             const auto transform = fPropMgr->getTransform(key);
360*c8dee2aaSAndroid Build Coastguard Worker             JSObject trans_val = emscripten::val::object();
361*c8dee2aaSAndroid Build Coastguard Worker             const float anchor[] = {transform.fAnchorPoint.fX, transform.fAnchorPoint.fY};
362*c8dee2aaSAndroid Build Coastguard Worker             const float position[] = {transform.fPosition.fX, transform.fPosition.fY};
363*c8dee2aaSAndroid Build Coastguard Worker             const float scale[] = {transform.fScale.fX, transform.fScale.fY};
364*c8dee2aaSAndroid Build Coastguard Worker             trans_val.set("anchor", MakeTypedArray(2, anchor));
365*c8dee2aaSAndroid Build Coastguard Worker             trans_val.set("position", MakeTypedArray(2, position));
366*c8dee2aaSAndroid Build Coastguard Worker             trans_val.set("scale", MakeTypedArray(2, scale));
367*c8dee2aaSAndroid Build Coastguard Worker             trans_val.set("rotation", transform.fRotation);
368*c8dee2aaSAndroid Build Coastguard Worker             trans_val.set("skew", transform.fSkew);
369*c8dee2aaSAndroid Build Coastguard Worker             trans_val.set("skew_axis", transform.fSkewAxis);
370*c8dee2aaSAndroid Build Coastguard Worker 
371*c8dee2aaSAndroid Build Coastguard Worker             JSObject prop = emscripten::val::object();
372*c8dee2aaSAndroid Build Coastguard Worker             prop.set("key", key);
373*c8dee2aaSAndroid Build Coastguard Worker             prop.set("value", trans_val);
374*c8dee2aaSAndroid Build Coastguard Worker             props.call<void>("push", prop);
375*c8dee2aaSAndroid Build Coastguard Worker         }
376*c8dee2aaSAndroid Build Coastguard Worker 
377*c8dee2aaSAndroid Build Coastguard Worker         return props;
378*c8dee2aaSAndroid Build Coastguard Worker     }
379*c8dee2aaSAndroid Build Coastguard Worker 
setColor(const std::string & key,SkColor c)380*c8dee2aaSAndroid Build Coastguard Worker     bool setColor(const std::string& key, SkColor c) {
381*c8dee2aaSAndroid Build Coastguard Worker         return fPropMgr->setColor(key, c);
382*c8dee2aaSAndroid Build Coastguard Worker     }
383*c8dee2aaSAndroid Build Coastguard Worker 
setOpacity(const std::string & key,float o)384*c8dee2aaSAndroid Build Coastguard Worker     bool setOpacity(const std::string& key, float o) {
385*c8dee2aaSAndroid Build Coastguard Worker         return fPropMgr->setOpacity(key, o);
386*c8dee2aaSAndroid Build Coastguard Worker     }
387*c8dee2aaSAndroid Build Coastguard Worker 
setText(const std::string & key,std::string text,float size)388*c8dee2aaSAndroid Build Coastguard Worker     bool setText(const std::string& key, std::string text, float size) {
389*c8dee2aaSAndroid Build Coastguard Worker         // preserve all other text fields
390*c8dee2aaSAndroid Build Coastguard Worker         auto t = fPropMgr->getText(key);
391*c8dee2aaSAndroid Build Coastguard Worker 
392*c8dee2aaSAndroid Build Coastguard Worker         t.fText     = SkString(text);
393*c8dee2aaSAndroid Build Coastguard Worker         t.fTextSize = size;
394*c8dee2aaSAndroid Build Coastguard Worker 
395*c8dee2aaSAndroid Build Coastguard Worker         return fPropMgr->setText(key, t);
396*c8dee2aaSAndroid Build Coastguard Worker     }
397*c8dee2aaSAndroid Build Coastguard Worker 
setTransform(const std::string & key,SkScalar anchorX,SkScalar anchorY,SkScalar posX,SkScalar posY,SkScalar scaleX,SkScalar scaleY,SkScalar rotation,SkScalar skew,SkScalar skewAxis)398*c8dee2aaSAndroid Build Coastguard Worker     bool setTransform(const std::string& key, SkScalar anchorX, SkScalar anchorY,
399*c8dee2aaSAndroid Build Coastguard Worker                                               SkScalar posX, SkScalar posY,
400*c8dee2aaSAndroid Build Coastguard Worker                                               SkScalar scaleX, SkScalar scaleY,
401*c8dee2aaSAndroid Build Coastguard Worker                                               SkScalar rotation, SkScalar skew, SkScalar skewAxis) {
402*c8dee2aaSAndroid Build Coastguard Worker         skottie::TransformPropertyValue transform;
403*c8dee2aaSAndroid Build Coastguard Worker         transform.fAnchorPoint = {anchorX, anchorY};
404*c8dee2aaSAndroid Build Coastguard Worker         transform.fPosition = {posX, posY};
405*c8dee2aaSAndroid Build Coastguard Worker         transform.fScale = {scaleX, scaleY};
406*c8dee2aaSAndroid Build Coastguard Worker         transform.fRotation = rotation;
407*c8dee2aaSAndroid Build Coastguard Worker         transform.fSkew = skew;
408*c8dee2aaSAndroid Build Coastguard Worker         transform.fSkewAxis = skewAxis;
409*c8dee2aaSAndroid Build Coastguard Worker         return fPropMgr->setTransform(key, transform);
410*c8dee2aaSAndroid Build Coastguard Worker     }
411*c8dee2aaSAndroid Build Coastguard Worker 
getMarkers() const412*c8dee2aaSAndroid Build Coastguard Worker     JSArray getMarkers() const {
413*c8dee2aaSAndroid Build Coastguard Worker         JSArray markers = emscripten::val::array();
414*c8dee2aaSAndroid Build Coastguard Worker         for (const auto& m : fPropMgr->markers()) {
415*c8dee2aaSAndroid Build Coastguard Worker             JSObject marker = emscripten::val::object();
416*c8dee2aaSAndroid Build Coastguard Worker             marker.set("name", m.name);
417*c8dee2aaSAndroid Build Coastguard Worker             marker.set("t0"  , m.t0);
418*c8dee2aaSAndroid Build Coastguard Worker             marker.set("t1"  , m.t1);
419*c8dee2aaSAndroid Build Coastguard Worker             markers.call<void>("push", marker);
420*c8dee2aaSAndroid Build Coastguard Worker         }
421*c8dee2aaSAndroid Build Coastguard Worker         return markers;
422*c8dee2aaSAndroid Build Coastguard Worker     }
423*c8dee2aaSAndroid Build Coastguard Worker 
copyStringArrayToJSArray(skia_private::TArray<SkString> slotIDs) const424*c8dee2aaSAndroid Build Coastguard Worker     JSArray copyStringArrayToJSArray(skia_private::TArray<SkString> slotIDs) const {
425*c8dee2aaSAndroid Build Coastguard Worker         JSArray retVal = emscripten::val::array();
426*c8dee2aaSAndroid Build Coastguard Worker         for (auto slotID : slotIDs) {
427*c8dee2aaSAndroid Build Coastguard Worker             retVal.call<void>("push", emscripten::val(slotID.c_str()));
428*c8dee2aaSAndroid Build Coastguard Worker         }
429*c8dee2aaSAndroid Build Coastguard Worker         return retVal;
430*c8dee2aaSAndroid Build Coastguard Worker     }
431*c8dee2aaSAndroid Build Coastguard Worker 
432*c8dee2aaSAndroid Build Coastguard Worker     // Slot Manager API
getSlotInfo() const433*c8dee2aaSAndroid Build Coastguard Worker     JSObject getSlotInfo() const {
434*c8dee2aaSAndroid Build Coastguard Worker         JSObject slotInfoJS = emscripten::val::object();
435*c8dee2aaSAndroid Build Coastguard Worker         auto slotInfo = fSlotMgr->getSlotInfo();
436*c8dee2aaSAndroid Build Coastguard Worker 
437*c8dee2aaSAndroid Build Coastguard Worker         slotInfoJS.set("colorSlotIDs", copyStringArrayToJSArray(slotInfo.fColorSlotIDs));
438*c8dee2aaSAndroid Build Coastguard Worker         slotInfoJS.set("scalarSlotIDs", copyStringArrayToJSArray(slotInfo.fScalarSlotIDs));
439*c8dee2aaSAndroid Build Coastguard Worker         slotInfoJS.set("vec2SlotIDs", copyStringArrayToJSArray(slotInfo.fVec2SlotIDs));
440*c8dee2aaSAndroid Build Coastguard Worker         slotInfoJS.set("imageSlotIDs", copyStringArrayToJSArray(slotInfo.fImageSlotIDs));
441*c8dee2aaSAndroid Build Coastguard Worker         slotInfoJS.set("textSlotIDs", copyStringArrayToJSArray(slotInfo.fTextSlotIDs));
442*c8dee2aaSAndroid Build Coastguard Worker 
443*c8dee2aaSAndroid Build Coastguard Worker         return slotInfoJS;
444*c8dee2aaSAndroid Build Coastguard Worker     }
445*c8dee2aaSAndroid Build Coastguard Worker 
getColorSlot(const std::string & slotID,WASMPointerF32 outPtr)446*c8dee2aaSAndroid Build Coastguard Worker     void getColorSlot(const std::string& slotID, WASMPointerF32 outPtr) {
447*c8dee2aaSAndroid Build Coastguard Worker         SkColor4f c4f;
448*c8dee2aaSAndroid Build Coastguard Worker         if (auto c = fSlotMgr->getColorSlot(SkString(slotID))) {
449*c8dee2aaSAndroid Build Coastguard Worker             c4f = SkColor4f::FromColor(*c);
450*c8dee2aaSAndroid Build Coastguard Worker         } else {
451*c8dee2aaSAndroid Build Coastguard Worker             c4f = {-1, -1, -1, -1};
452*c8dee2aaSAndroid Build Coastguard Worker         }
453*c8dee2aaSAndroid Build Coastguard Worker         memcpy(reinterpret_cast<float*>(outPtr), &c4f, 4 * sizeof(float));
454*c8dee2aaSAndroid Build Coastguard Worker     }
455*c8dee2aaSAndroid Build Coastguard Worker 
getScalarSlot(const std::string & slotID)456*c8dee2aaSAndroid Build Coastguard Worker     emscripten::val getScalarSlot(const std::string& slotID) {
457*c8dee2aaSAndroid Build Coastguard Worker         if (auto s = fSlotMgr->getScalarSlot(SkString(slotID))) {
458*c8dee2aaSAndroid Build Coastguard Worker            return emscripten::val(*s);
459*c8dee2aaSAndroid Build Coastguard Worker         }
460*c8dee2aaSAndroid Build Coastguard Worker         return emscripten::val::null();
461*c8dee2aaSAndroid Build Coastguard Worker     }
462*c8dee2aaSAndroid Build Coastguard Worker 
getVec2Slot(const std::string & slotID,WASMPointerF32 outPtr)463*c8dee2aaSAndroid Build Coastguard Worker     void getVec2Slot(const std::string& slotID, WASMPointerF32 outPtr) {
464*c8dee2aaSAndroid Build Coastguard Worker         // [x, y, sentinel]
465*c8dee2aaSAndroid Build Coastguard Worker         SkV3 vec3;
466*c8dee2aaSAndroid Build Coastguard Worker         if (auto v = fSlotMgr->getVec2Slot(SkString(slotID))) {
467*c8dee2aaSAndroid Build Coastguard Worker             vec3 = {v->x, v->y, 1};
468*c8dee2aaSAndroid Build Coastguard Worker         } else {
469*c8dee2aaSAndroid Build Coastguard Worker             vec3 = {0, 0, -1};
470*c8dee2aaSAndroid Build Coastguard Worker         }
471*c8dee2aaSAndroid Build Coastguard Worker         memcpy(reinterpret_cast<float*>(outPtr), vec3.ptr(), 3 * sizeof(float));
472*c8dee2aaSAndroid Build Coastguard Worker     }
473*c8dee2aaSAndroid Build Coastguard Worker 
getTextSlot(const std::string & slotID) const474*c8dee2aaSAndroid Build Coastguard Worker     JSObject getTextSlot(const std::string& slotID) const {
475*c8dee2aaSAndroid Build Coastguard Worker         if (auto textProp = fSlotMgr->getTextSlot(SkString(slotID))){
476*c8dee2aaSAndroid Build Coastguard Worker             JSObject text_val = emscripten::val::object();
477*c8dee2aaSAndroid Build Coastguard Worker 
478*c8dee2aaSAndroid Build Coastguard Worker             text_val.set("typeface", textProp->fTypeface);
479*c8dee2aaSAndroid Build Coastguard Worker             text_val.set("text", emscripten::val(textProp->fText.c_str()));
480*c8dee2aaSAndroid Build Coastguard Worker             text_val.set("textSize", textProp->fTextSize);
481*c8dee2aaSAndroid Build Coastguard Worker             text_val.set("minTextSize", textProp->fMinTextSize);
482*c8dee2aaSAndroid Build Coastguard Worker             text_val.set("maxTextSize", textProp->fMaxTextSize);
483*c8dee2aaSAndroid Build Coastguard Worker             text_val.set("strokeWidth", textProp->fStrokeWidth);
484*c8dee2aaSAndroid Build Coastguard Worker             text_val.set("lineHeight", textProp->fLineHeight);
485*c8dee2aaSAndroid Build Coastguard Worker             text_val.set("lineShift", textProp->fLineShift);
486*c8dee2aaSAndroid Build Coastguard Worker             text_val.set("ascent", textProp->fAscent);
487*c8dee2aaSAndroid Build Coastguard Worker             text_val.set("maxLines", textProp->fMaxLines);
488*c8dee2aaSAndroid Build Coastguard Worker 
489*c8dee2aaSAndroid Build Coastguard Worker             switch (textProp->fHAlign) {
490*c8dee2aaSAndroid Build Coastguard Worker             case SkTextUtils::Align::kLeft_Align:
491*c8dee2aaSAndroid Build Coastguard Worker                 text_val.set("horizAlign", para::TextAlign::kLeft);
492*c8dee2aaSAndroid Build Coastguard Worker                 break;
493*c8dee2aaSAndroid Build Coastguard Worker             case SkTextUtils::Align::kRight_Align:
494*c8dee2aaSAndroid Build Coastguard Worker                 text_val.set("horizAlign", para::TextAlign::kRight);
495*c8dee2aaSAndroid Build Coastguard Worker                 break;
496*c8dee2aaSAndroid Build Coastguard Worker             case SkTextUtils::Align::kCenter_Align:
497*c8dee2aaSAndroid Build Coastguard Worker                 text_val.set("horizAlign", para::TextAlign::kCenter);
498*c8dee2aaSAndroid Build Coastguard Worker                 break;
499*c8dee2aaSAndroid Build Coastguard Worker             default:
500*c8dee2aaSAndroid Build Coastguard Worker                 text_val.set("horizAlign", para::TextAlign::kLeft);
501*c8dee2aaSAndroid Build Coastguard Worker                 break;
502*c8dee2aaSAndroid Build Coastguard Worker             }
503*c8dee2aaSAndroid Build Coastguard Worker 
504*c8dee2aaSAndroid Build Coastguard Worker             text_val.set("vertAlign", textProp->fVAlign);
505*c8dee2aaSAndroid Build Coastguard Worker             text_val.set("resize", textProp->fResize);
506*c8dee2aaSAndroid Build Coastguard Worker 
507*c8dee2aaSAndroid Build Coastguard Worker             if (textProp->fLineBreak == skottie::Shaper::LinebreakPolicy::kParagraph) {
508*c8dee2aaSAndroid Build Coastguard Worker                 text_val.set("linebreak", SkUnicode::LineBreakType::kSoftLineBreak);
509*c8dee2aaSAndroid Build Coastguard Worker             } else {
510*c8dee2aaSAndroid Build Coastguard Worker                 text_val.set("linebreak", SkUnicode::LineBreakType::kHardLineBreak);
511*c8dee2aaSAndroid Build Coastguard Worker             }
512*c8dee2aaSAndroid Build Coastguard Worker 
513*c8dee2aaSAndroid Build Coastguard Worker             if (textProp->fDirection == skottie::Shaper::Direction::kLTR) {
514*c8dee2aaSAndroid Build Coastguard Worker                 text_val.set("direction", para::TextDirection::kLtr);
515*c8dee2aaSAndroid Build Coastguard Worker             } else {
516*c8dee2aaSAndroid Build Coastguard Worker                 text_val.set("direction", para::TextDirection::kRtl);
517*c8dee2aaSAndroid Build Coastguard Worker             }
518*c8dee2aaSAndroid Build Coastguard Worker             text_val.set("strokeJoin", textProp->fStrokeJoin);
519*c8dee2aaSAndroid Build Coastguard Worker 
520*c8dee2aaSAndroid Build Coastguard Worker             text_val.set("fillColor", MakeTypedArray(4, SkColor4f::FromColor(textProp->fFillColor)
521*c8dee2aaSAndroid Build Coastguard Worker                                                             .vec()));
522*c8dee2aaSAndroid Build Coastguard Worker 
523*c8dee2aaSAndroid Build Coastguard Worker             text_val.set("strokeColor", MakeTypedArray(4, SkColor4f::FromColor(textProp->fStrokeColor)
524*c8dee2aaSAndroid Build Coastguard Worker                                                             .vec()));
525*c8dee2aaSAndroid Build Coastguard Worker 
526*c8dee2aaSAndroid Build Coastguard Worker             const float box[] = {textProp->fBox.fLeft, textProp->fBox.fTop,
527*c8dee2aaSAndroid Build Coastguard Worker                                  textProp->fBox.fRight, textProp->fBox.fBottom};
528*c8dee2aaSAndroid Build Coastguard Worker             text_val.set("boundingBox", MakeTypedArray(4, box));
529*c8dee2aaSAndroid Build Coastguard Worker             return text_val;
530*c8dee2aaSAndroid Build Coastguard Worker         }
531*c8dee2aaSAndroid Build Coastguard Worker         return emscripten::val::null();
532*c8dee2aaSAndroid Build Coastguard Worker     }
533*c8dee2aaSAndroid Build Coastguard Worker 
setImageSlot(const std::string & slotID,const std::string & assetName)534*c8dee2aaSAndroid Build Coastguard Worker     bool setImageSlot(const std::string& slotID, const std::string& assetName) {
535*c8dee2aaSAndroid Build Coastguard Worker         // look for resource in preloaded SkottieAssetProvider
536*c8dee2aaSAndroid Build Coastguard Worker         return fSlotMgr->setImageSlot(SkString(slotID), fResourceProvider->loadImageAsset(nullptr,
537*c8dee2aaSAndroid Build Coastguard Worker                                                                             assetName.data(),
538*c8dee2aaSAndroid Build Coastguard Worker                                                                             nullptr));
539*c8dee2aaSAndroid Build Coastguard Worker     }
540*c8dee2aaSAndroid Build Coastguard Worker 
setColorSlot(const std::string & slotID,SkColor c)541*c8dee2aaSAndroid Build Coastguard Worker     bool setColorSlot(const std::string& slotID, SkColor c) {
542*c8dee2aaSAndroid Build Coastguard Worker         return fSlotMgr->setColorSlot(SkString(slotID), c);
543*c8dee2aaSAndroid Build Coastguard Worker     }
544*c8dee2aaSAndroid Build Coastguard Worker 
setScalarSlot(const std::string & slotID,float s)545*c8dee2aaSAndroid Build Coastguard Worker     bool setScalarSlot(const std::string& slotID, float s) {
546*c8dee2aaSAndroid Build Coastguard Worker         return fSlotMgr->setScalarSlot(SkString(slotID), s);
547*c8dee2aaSAndroid Build Coastguard Worker     }
548*c8dee2aaSAndroid Build Coastguard Worker 
setVec2Slot(const std::string & slotID,SkV2 v)549*c8dee2aaSAndroid Build Coastguard Worker     bool setVec2Slot(const std::string& slotID, SkV2 v) {
550*c8dee2aaSAndroid Build Coastguard Worker         return fSlotMgr->setVec2Slot(SkString(slotID), v);
551*c8dee2aaSAndroid Build Coastguard Worker     }
552*c8dee2aaSAndroid Build Coastguard Worker 
attachEditor(const std::string & layerID,size_t layerIndex)553*c8dee2aaSAndroid Build Coastguard Worker     bool attachEditor(const std::string& layerID, size_t layerIndex) {
554*c8dee2aaSAndroid Build Coastguard Worker         if (fTextEditor) {
555*c8dee2aaSAndroid Build Coastguard Worker             fTextEditor->setEnabled(false);
556*c8dee2aaSAndroid Build Coastguard Worker             fTextEditor = nullptr;
557*c8dee2aaSAndroid Build Coastguard Worker         }
558*c8dee2aaSAndroid Build Coastguard Worker 
559*c8dee2aaSAndroid Build Coastguard Worker         if (layerID.empty()) {
560*c8dee2aaSAndroid Build Coastguard Worker             return true;
561*c8dee2aaSAndroid Build Coastguard Worker         }
562*c8dee2aaSAndroid Build Coastguard Worker 
563*c8dee2aaSAndroid Build Coastguard Worker         auto txt_handle = fPropMgr->getTextHandle(layerID, layerIndex);
564*c8dee2aaSAndroid Build Coastguard Worker         if (!txt_handle) {
565*c8dee2aaSAndroid Build Coastguard Worker             return false;
566*c8dee2aaSAndroid Build Coastguard Worker         }
567*c8dee2aaSAndroid Build Coastguard Worker 
568*c8dee2aaSAndroid Build Coastguard Worker         std::vector<std::unique_ptr<skottie::TextPropertyHandle>> deps;
569*c8dee2aaSAndroid Build Coastguard Worker         for (size_t i = 0; ; ++i) {
570*c8dee2aaSAndroid Build Coastguard Worker             if (i == layerIndex) {
571*c8dee2aaSAndroid Build Coastguard Worker                 continue;
572*c8dee2aaSAndroid Build Coastguard Worker             }
573*c8dee2aaSAndroid Build Coastguard Worker 
574*c8dee2aaSAndroid Build Coastguard Worker             auto dep_handle = fPropMgr->getTextHandle(layerID, i);
575*c8dee2aaSAndroid Build Coastguard Worker             if (!dep_handle) {
576*c8dee2aaSAndroid Build Coastguard Worker                 break;
577*c8dee2aaSAndroid Build Coastguard Worker             }
578*c8dee2aaSAndroid Build Coastguard Worker             deps.push_back(std::move(dep_handle));
579*c8dee2aaSAndroid Build Coastguard Worker         }
580*c8dee2aaSAndroid Build Coastguard Worker 
581*c8dee2aaSAndroid Build Coastguard Worker         fTextEditor = sk_make_sp<skottie_utils::TextEditor>(std::move(txt_handle),
582*c8dee2aaSAndroid Build Coastguard Worker                                                             std::move(deps));
583*c8dee2aaSAndroid Build Coastguard Worker         return true;
584*c8dee2aaSAndroid Build Coastguard Worker     }
585*c8dee2aaSAndroid Build Coastguard Worker 
enableEditor(bool enable)586*c8dee2aaSAndroid Build Coastguard Worker     void enableEditor(bool enable) {
587*c8dee2aaSAndroid Build Coastguard Worker         if (fTextEditor) {
588*c8dee2aaSAndroid Build Coastguard Worker             fTextEditor->setEnabled(enable);
589*c8dee2aaSAndroid Build Coastguard Worker         }
590*c8dee2aaSAndroid Build Coastguard Worker     }
591*c8dee2aaSAndroid Build Coastguard Worker 
dispatchEditorKey(const std::string & key)592*c8dee2aaSAndroid Build Coastguard Worker     bool dispatchEditorKey(const std::string& key) {
593*c8dee2aaSAndroid Build Coastguard Worker         // Map some useful keys to the current (odd) text editor bindings.
594*c8dee2aaSAndroid Build Coastguard Worker         // TODO: Add support for custom bindings in the editor.
595*c8dee2aaSAndroid Build Coastguard Worker         auto key2char = [](const std::string& key) -> SkUnichar {
596*c8dee2aaSAndroid Build Coastguard Worker             // Special keys.
597*c8dee2aaSAndroid Build Coastguard Worker             if (key == "ArrowLeft")  return '[';
598*c8dee2aaSAndroid Build Coastguard Worker             if (key == "ArrowRight") return ']';
599*c8dee2aaSAndroid Build Coastguard Worker             if (key == "Backspace")  return '\\';
600*c8dee2aaSAndroid Build Coastguard Worker 
601*c8dee2aaSAndroid Build Coastguard Worker             const char* str = key.c_str();
602*c8dee2aaSAndroid Build Coastguard Worker             const char* end = str + key.size();
603*c8dee2aaSAndroid Build Coastguard Worker             const SkUnichar uch = SkUTF::NextUTF8(&str, end);
604*c8dee2aaSAndroid Build Coastguard Worker 
605*c8dee2aaSAndroid Build Coastguard Worker             // Pass through single code points, ignore everything else.
606*c8dee2aaSAndroid Build Coastguard Worker             return str == end ? uch : -1;
607*c8dee2aaSAndroid Build Coastguard Worker         };
608*c8dee2aaSAndroid Build Coastguard Worker 
609*c8dee2aaSAndroid Build Coastguard Worker         if (fTextEditor) {
610*c8dee2aaSAndroid Build Coastguard Worker             const auto uch = key2char(key);
611*c8dee2aaSAndroid Build Coastguard Worker             if (uch != -1) {
612*c8dee2aaSAndroid Build Coastguard Worker                 return fTextEditor->onCharInput(uch);
613*c8dee2aaSAndroid Build Coastguard Worker             }
614*c8dee2aaSAndroid Build Coastguard Worker         }
615*c8dee2aaSAndroid Build Coastguard Worker 
616*c8dee2aaSAndroid Build Coastguard Worker         return false;
617*c8dee2aaSAndroid Build Coastguard Worker     }
618*c8dee2aaSAndroid Build Coastguard Worker 
dispatchEditorPointer(float x,float y,skui::InputState state,skui::ModifierKey mod)619*c8dee2aaSAndroid Build Coastguard Worker     bool dispatchEditorPointer(float x, float y, skui::InputState state, skui::ModifierKey mod) {
620*c8dee2aaSAndroid Build Coastguard Worker         return fTextEditor
621*c8dee2aaSAndroid Build Coastguard Worker                 ? fTextEditor->onMouseInput(x, y, state, mod)
622*c8dee2aaSAndroid Build Coastguard Worker                 : false;
623*c8dee2aaSAndroid Build Coastguard Worker     }
624*c8dee2aaSAndroid Build Coastguard Worker 
setEditorCursorWeight(float w)625*c8dee2aaSAndroid Build Coastguard Worker     void setEditorCursorWeight(float w) {
626*c8dee2aaSAndroid Build Coastguard Worker         if (fTextEditor) {
627*c8dee2aaSAndroid Build Coastguard Worker             fTextEditor->setCursorWeight(w);
628*c8dee2aaSAndroid Build Coastguard Worker         }
629*c8dee2aaSAndroid Build Coastguard Worker     }
630*c8dee2aaSAndroid Build Coastguard Worker 
setTextSlot(const std::string & slotID,SimpleSlottableTextProperty t)631*c8dee2aaSAndroid Build Coastguard Worker     bool setTextSlot(const std::string& slotID, SimpleSlottableTextProperty t) {
632*c8dee2aaSAndroid Build Coastguard Worker         return fSlotMgr->setTextSlot(SkString(slotID), t);
633*c8dee2aaSAndroid Build Coastguard Worker     }
634*c8dee2aaSAndroid Build Coastguard Worker 
635*c8dee2aaSAndroid Build Coastguard Worker private:
ManagedAnimation(sk_sp<skottie::Animation> animation,std::unique_ptr<skottie_utils::CustomPropertyManager> propMgr,sk_sp<skottie::SlotManager> slotMgr,sk_sp<skresources::ResourceProvider> rp)636*c8dee2aaSAndroid Build Coastguard Worker     ManagedAnimation(sk_sp<skottie::Animation> animation,
637*c8dee2aaSAndroid Build Coastguard Worker                      std::unique_ptr<skottie_utils::CustomPropertyManager> propMgr,
638*c8dee2aaSAndroid Build Coastguard Worker                      sk_sp<skottie::SlotManager> slotMgr,
639*c8dee2aaSAndroid Build Coastguard Worker                      sk_sp<skresources::ResourceProvider> rp)
640*c8dee2aaSAndroid Build Coastguard Worker         : fAnimation(std::move(animation))
641*c8dee2aaSAndroid Build Coastguard Worker         , fPropMgr(std::move(propMgr))
642*c8dee2aaSAndroid Build Coastguard Worker         , fSlotMgr(std::move(slotMgr))
643*c8dee2aaSAndroid Build Coastguard Worker         , fResourceProvider(std::move(rp))
644*c8dee2aaSAndroid Build Coastguard Worker     {}
645*c8dee2aaSAndroid Build Coastguard Worker 
646*c8dee2aaSAndroid Build Coastguard Worker     const sk_sp<skottie::Animation>                             fAnimation;
647*c8dee2aaSAndroid Build Coastguard Worker     const std::unique_ptr<skottie_utils::CustomPropertyManager> fPropMgr;
648*c8dee2aaSAndroid Build Coastguard Worker     const sk_sp<skottie::SlotManager>                           fSlotMgr;
649*c8dee2aaSAndroid Build Coastguard Worker     const sk_sp<skresources::ResourceProvider>                  fResourceProvider;
650*c8dee2aaSAndroid Build Coastguard Worker 
651*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<skottie_utils::TextEditor>                            fTextEditor;
652*c8dee2aaSAndroid Build Coastguard Worker };
653*c8dee2aaSAndroid Build Coastguard Worker 
654*c8dee2aaSAndroid Build Coastguard Worker } // anonymous ns
655*c8dee2aaSAndroid Build Coastguard Worker 
EMSCRIPTEN_BINDINGS(Skottie)656*c8dee2aaSAndroid Build Coastguard Worker EMSCRIPTEN_BINDINGS(Skottie) {
657*c8dee2aaSAndroid Build Coastguard Worker     // Animation things (may eventually go in own library)
658*c8dee2aaSAndroid Build Coastguard Worker     class_<skottie::Animation>("Animation")
659*c8dee2aaSAndroid Build Coastguard Worker         .smart_ptr<sk_sp<skottie::Animation>>("sk_sp<Animation>")
660*c8dee2aaSAndroid Build Coastguard Worker         .function("version", optional_override([](skottie::Animation& self)->std::string {
661*c8dee2aaSAndroid Build Coastguard Worker             return std::string(self.version().c_str());
662*c8dee2aaSAndroid Build Coastguard Worker         }))
663*c8dee2aaSAndroid Build Coastguard Worker         .function("_size", optional_override([](skottie::Animation& self,
664*c8dee2aaSAndroid Build Coastguard Worker                                                 WASMPointerF32 oPtr)->void {
665*c8dee2aaSAndroid Build Coastguard Worker             SkSize* output = reinterpret_cast<SkSize*>(oPtr);
666*c8dee2aaSAndroid Build Coastguard Worker             *output = self.size();
667*c8dee2aaSAndroid Build Coastguard Worker         }))
668*c8dee2aaSAndroid Build Coastguard Worker         .function("duration", &skottie::Animation::duration)
669*c8dee2aaSAndroid Build Coastguard Worker         .function("fps"     , &skottie::Animation::fps)
670*c8dee2aaSAndroid Build Coastguard Worker         .function("seek", optional_override([](skottie::Animation& self, SkScalar t)->void {
671*c8dee2aaSAndroid Build Coastguard Worker             self.seek(t);
672*c8dee2aaSAndroid Build Coastguard Worker         }))
673*c8dee2aaSAndroid Build Coastguard Worker         .function("seekFrame", optional_override([](skottie::Animation& self, double t)->void {
674*c8dee2aaSAndroid Build Coastguard Worker             self.seekFrame(t);
675*c8dee2aaSAndroid Build Coastguard Worker         }))
676*c8dee2aaSAndroid Build Coastguard Worker         .function("_render", optional_override([](skottie::Animation& self, SkCanvas* canvas,
677*c8dee2aaSAndroid Build Coastguard Worker                                                   WASMPointerF32 fPtr)->void {
678*c8dee2aaSAndroid Build Coastguard Worker             const SkRect* dst = reinterpret_cast<const SkRect*>(fPtr);
679*c8dee2aaSAndroid Build Coastguard Worker             self.render(canvas, dst);
680*c8dee2aaSAndroid Build Coastguard Worker         }), allow_raw_pointers());
681*c8dee2aaSAndroid Build Coastguard Worker 
682*c8dee2aaSAndroid Build Coastguard Worker     function("MakeAnimation", optional_override([](std::string json)->sk_sp<skottie::Animation> {
683*c8dee2aaSAndroid Build Coastguard Worker         return skottie::Animation::Make(json.c_str(), json.length());
684*c8dee2aaSAndroid Build Coastguard Worker     }));
685*c8dee2aaSAndroid Build Coastguard Worker     constant("skottie", true);
686*c8dee2aaSAndroid Build Coastguard Worker 
687*c8dee2aaSAndroid Build Coastguard Worker     class_<ManagedAnimation>("ManagedAnimation")
688*c8dee2aaSAndroid Build Coastguard Worker         .smart_ptr<sk_sp<ManagedAnimation>>("sk_sp<ManagedAnimation>")
689*c8dee2aaSAndroid Build Coastguard Worker         .function("version"   , &ManagedAnimation::version)
690*c8dee2aaSAndroid Build Coastguard Worker         .function("_size", optional_override([](ManagedAnimation& self,
691*c8dee2aaSAndroid Build Coastguard Worker                                                 WASMPointerF32 oPtr)->void {
692*c8dee2aaSAndroid Build Coastguard Worker             SkSize* output = reinterpret_cast<SkSize*>(oPtr);
693*c8dee2aaSAndroid Build Coastguard Worker             *output = self.size();
694*c8dee2aaSAndroid Build Coastguard Worker         }))
695*c8dee2aaSAndroid Build Coastguard Worker         .function("duration"  , &ManagedAnimation::duration)
696*c8dee2aaSAndroid Build Coastguard Worker         .function("fps"       , &ManagedAnimation::fps)
697*c8dee2aaSAndroid Build Coastguard Worker         .function("_render", optional_override([](ManagedAnimation& self, SkCanvas* canvas,
698*c8dee2aaSAndroid Build Coastguard Worker                                                   WASMPointerF32 fPtr)->void {
699*c8dee2aaSAndroid Build Coastguard Worker             const SkRect* dst = reinterpret_cast<const SkRect*>(fPtr);
700*c8dee2aaSAndroid Build Coastguard Worker             self.render(canvas, dst);
701*c8dee2aaSAndroid Build Coastguard Worker         }), allow_raw_pointers())
702*c8dee2aaSAndroid Build Coastguard Worker         .function("_seek", optional_override([](ManagedAnimation& self, SkScalar t,
703*c8dee2aaSAndroid Build Coastguard Worker                                                 WASMPointerF32 fPtr) {
704*c8dee2aaSAndroid Build Coastguard Worker             SkRect* damageRect = reinterpret_cast<SkRect*>(fPtr);
705*c8dee2aaSAndroid Build Coastguard Worker             damageRect[0] = self.seek(t);
706*c8dee2aaSAndroid Build Coastguard Worker         }))
707*c8dee2aaSAndroid Build Coastguard Worker         .function("_seekFrame", optional_override([](ManagedAnimation& self, double frame,
708*c8dee2aaSAndroid Build Coastguard Worker                                                      WASMPointerF32 fPtr) {
709*c8dee2aaSAndroid Build Coastguard Worker             SkRect* damageRect = reinterpret_cast<SkRect*>(fPtr);
710*c8dee2aaSAndroid Build Coastguard Worker             damageRect[0] = self.seekFrame(frame);
711*c8dee2aaSAndroid Build Coastguard Worker         }))
712*c8dee2aaSAndroid Build Coastguard Worker         .function("seekFrame" , &ManagedAnimation::seekFrame)
713*c8dee2aaSAndroid Build Coastguard Worker         .function("_setColor"  , optional_override([](ManagedAnimation& self, const std::string& key, WASMPointerF32 cPtr) {
714*c8dee2aaSAndroid Build Coastguard Worker             float* fourFloats = reinterpret_cast<float*>(cPtr);
715*c8dee2aaSAndroid Build Coastguard Worker             SkColor4f color = { fourFloats[0], fourFloats[1], fourFloats[2], fourFloats[3] };
716*c8dee2aaSAndroid Build Coastguard Worker             return self.setColor(key, color.toSkColor());
717*c8dee2aaSAndroid Build Coastguard Worker         }))
718*c8dee2aaSAndroid Build Coastguard Worker         .function("_setTransform"  , optional_override([](ManagedAnimation& self,
719*c8dee2aaSAndroid Build Coastguard Worker                                                           const std::string& key,
720*c8dee2aaSAndroid Build Coastguard Worker                                                           WASMPointerF32 transformData) {
721*c8dee2aaSAndroid Build Coastguard Worker             // transform value info is passed in as an array of 9 scalars in the following order:
722*c8dee2aaSAndroid Build Coastguard Worker             // anchor xy, position xy, scalexy, rotation, skew, skew axis
723*c8dee2aaSAndroid Build Coastguard Worker             auto transform = reinterpret_cast<SkScalar*>(transformData);
724*c8dee2aaSAndroid Build Coastguard Worker             return self.setTransform(key, transform[0], transform[1], transform[2], transform[3],
725*c8dee2aaSAndroid Build Coastguard Worker                                      transform[4], transform[5], transform[6], transform[7], transform[8]);
726*c8dee2aaSAndroid Build Coastguard Worker                                                           }))
727*c8dee2aaSAndroid Build Coastguard Worker         .function("getMarkers"       , &ManagedAnimation::getMarkers)
728*c8dee2aaSAndroid Build Coastguard Worker         .function("getColorProps"    , &ManagedAnimation::getColorProps)
729*c8dee2aaSAndroid Build Coastguard Worker         .function("getOpacityProps"  , &ManagedAnimation::getOpacityProps)
730*c8dee2aaSAndroid Build Coastguard Worker         .function("setOpacity"       , &ManagedAnimation::setOpacity)
731*c8dee2aaSAndroid Build Coastguard Worker         .function("getTextProps"     , &ManagedAnimation::getTextProps)
732*c8dee2aaSAndroid Build Coastguard Worker         .function("setText"          , &ManagedAnimation::setText)
733*c8dee2aaSAndroid Build Coastguard Worker         .function("getTransformProps", &ManagedAnimation::getTransformProps)
734*c8dee2aaSAndroid Build Coastguard Worker         .function("getSlotInfo"      , &ManagedAnimation::getSlotInfo)
735*c8dee2aaSAndroid Build Coastguard Worker         .function("_getColorSlot"    , &ManagedAnimation::getColorSlot)
736*c8dee2aaSAndroid Build Coastguard Worker         .function("_setColorSlot"    , optional_override([](ManagedAnimation& self, const std::string& key, WASMPointerF32 cPtr) {
737*c8dee2aaSAndroid Build Coastguard Worker             SkColor4f color = ptrToSkColor4f(cPtr);
738*c8dee2aaSAndroid Build Coastguard Worker             return self.setColorSlot(key, color.toSkColor());
739*c8dee2aaSAndroid Build Coastguard Worker         }))
740*c8dee2aaSAndroid Build Coastguard Worker         .function("_getVec2Slot"    , &ManagedAnimation::getVec2Slot)
741*c8dee2aaSAndroid Build Coastguard Worker         .function("_setVec2Slot"    , optional_override([](ManagedAnimation& self, const std::string& key, WASMPointerF32 vPtr) {
742*c8dee2aaSAndroid Build Coastguard Worker             float* twoFloats = reinterpret_cast<float*>(vPtr);
743*c8dee2aaSAndroid Build Coastguard Worker             SkV2 vec2 = {twoFloats[0], twoFloats[1]};
744*c8dee2aaSAndroid Build Coastguard Worker             return self.setVec2Slot(key, vec2);
745*c8dee2aaSAndroid Build Coastguard Worker         }))
746*c8dee2aaSAndroid Build Coastguard Worker         .function("getScalarSlot"    , &ManagedAnimation::getScalarSlot)
747*c8dee2aaSAndroid Build Coastguard Worker         .function("setScalarSlot"    , &ManagedAnimation::setScalarSlot)
748*c8dee2aaSAndroid Build Coastguard Worker         .function("attachEditor"         , &ManagedAnimation::attachEditor)
749*c8dee2aaSAndroid Build Coastguard Worker         .function("enableEditor"         , &ManagedAnimation::enableEditor)
750*c8dee2aaSAndroid Build Coastguard Worker         .function("dispatchEditorKey"    , &ManagedAnimation::dispatchEditorKey)
751*c8dee2aaSAndroid Build Coastguard Worker         .function("dispatchEditorPointer", &ManagedAnimation::dispatchEditorPointer)
752*c8dee2aaSAndroid Build Coastguard Worker         .function("setEditorCursorWeight", &ManagedAnimation::setEditorCursorWeight)
753*c8dee2aaSAndroid Build Coastguard Worker         .function("getTextSlot"      , &ManagedAnimation::getTextSlot)
754*c8dee2aaSAndroid Build Coastguard Worker         .function("_setTextSlot"     , &ManagedAnimation::setTextSlot)
755*c8dee2aaSAndroid Build Coastguard Worker         .function("setImageSlot"     , &ManagedAnimation::setImageSlot);
756*c8dee2aaSAndroid Build Coastguard Worker 
757*c8dee2aaSAndroid Build Coastguard Worker     function("_MakeManagedAnimation", optional_override([](std::string json,
758*c8dee2aaSAndroid Build Coastguard Worker                                                            size_t assetCount,
759*c8dee2aaSAndroid Build Coastguard Worker                                                            WASMPointerU32 nptr,
760*c8dee2aaSAndroid Build Coastguard Worker                                                            WASMPointerU32 dptr,
761*c8dee2aaSAndroid Build Coastguard Worker                                                            WASMPointerU32 sptr,
762*c8dee2aaSAndroid Build Coastguard Worker                                                            std::string prop_prefix,
763*c8dee2aaSAndroid Build Coastguard Worker                                                            emscripten::val soundMap,
764*c8dee2aaSAndroid Build Coastguard Worker                                                            emscripten::val logger)
765*c8dee2aaSAndroid Build Coastguard Worker                                                         ->sk_sp<ManagedAnimation> {
766*c8dee2aaSAndroid Build Coastguard Worker         const auto assetNames = reinterpret_cast<char**   >(nptr);
767*c8dee2aaSAndroid Build Coastguard Worker         const auto assetDatas = reinterpret_cast<uint8_t**>(dptr);
768*c8dee2aaSAndroid Build Coastguard Worker         const auto assetSizes = reinterpret_cast<size_t*  >(sptr);
769*c8dee2aaSAndroid Build Coastguard Worker 
770*c8dee2aaSAndroid Build Coastguard Worker         SkottieAssetProvider::AssetVec assets;
771*c8dee2aaSAndroid Build Coastguard Worker         assets.reserve(assetCount);
772*c8dee2aaSAndroid Build Coastguard Worker 
773*c8dee2aaSAndroid Build Coastguard Worker         for (size_t i = 0; i < assetCount; i++) {
774*c8dee2aaSAndroid Build Coastguard Worker             auto name  = SkString(assetNames[i]);
775*c8dee2aaSAndroid Build Coastguard Worker             auto bytes = SkData::MakeFromMalloc(assetDatas[i], assetSizes[i]);
776*c8dee2aaSAndroid Build Coastguard Worker             assets.push_back(std::make_pair(std::move(name), std::move(bytes)));
777*c8dee2aaSAndroid Build Coastguard Worker         }
778*c8dee2aaSAndroid Build Coastguard Worker 
779*c8dee2aaSAndroid Build Coastguard Worker         // DataURIResourceProviderProxy needs codecs registered to try to process Base64 encoded
780*c8dee2aaSAndroid Build Coastguard Worker         // images.
781*c8dee2aaSAndroid Build Coastguard Worker         static SkOnce once;
782*c8dee2aaSAndroid Build Coastguard Worker         once([] {
783*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_CODEC_DECODES_PNG)
784*c8dee2aaSAndroid Build Coastguard Worker             SkCodecs::Register(SkPngDecoder::Decoder());
785*c8dee2aaSAndroid Build Coastguard Worker #endif
786*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_CODEC_DECODES_JPEG)
787*c8dee2aaSAndroid Build Coastguard Worker             SkCodecs::Register(SkJpegDecoder::Decoder());
788*c8dee2aaSAndroid Build Coastguard Worker #endif
789*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_CODEC_DECODES_GIF)
790*c8dee2aaSAndroid Build Coastguard Worker             SkCodecs::Register(SkGifDecoder::Decoder());
791*c8dee2aaSAndroid Build Coastguard Worker #endif
792*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_CODEC_DECODES_WEBP)
793*c8dee2aaSAndroid Build Coastguard Worker             SkCodecs::Register(SkWebpDecoder::Decoder());
794*c8dee2aaSAndroid Build Coastguard Worker #endif
795*c8dee2aaSAndroid Build Coastguard Worker         });
796*c8dee2aaSAndroid Build Coastguard Worker 
797*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<SkFontMgr> fontmgr;
798*c8dee2aaSAndroid Build Coastguard Worker #if !defined(CK_NO_FONTS)
799*c8dee2aaSAndroid Build Coastguard Worker         fontmgr = SkFontMgr_New_Custom_Empty();
800*c8dee2aaSAndroid Build Coastguard Worker #endif
801*c8dee2aaSAndroid Build Coastguard Worker 
802*c8dee2aaSAndroid Build Coastguard Worker         return ManagedAnimation::Make(json,
803*c8dee2aaSAndroid Build Coastguard Worker                                       skresources::DataURIResourceProviderProxy::Make(
804*c8dee2aaSAndroid Build Coastguard Worker                                           SkottieAssetProvider::Make(std::move(assets),
805*c8dee2aaSAndroid Build Coastguard Worker                                                                      std::move(soundMap)),
806*c8dee2aaSAndroid Build Coastguard Worker                                           skresources::ImageDecodeStrategy::kPreDecode,
807*c8dee2aaSAndroid Build Coastguard Worker                                           std::move(fontmgr)),
808*c8dee2aaSAndroid Build Coastguard Worker                                       prop_prefix, std::move(logger));
809*c8dee2aaSAndroid Build Coastguard Worker     }));
810*c8dee2aaSAndroid Build Coastguard Worker 
811*c8dee2aaSAndroid Build Coastguard Worker     enum_<skui::InputState>("InputState")
812*c8dee2aaSAndroid Build Coastguard Worker         .value("Down",  skui::InputState::kDown)
813*c8dee2aaSAndroid Build Coastguard Worker         .value("Up",    skui::InputState::kUp)
814*c8dee2aaSAndroid Build Coastguard Worker         .value("Move",  skui::InputState::kMove)
815*c8dee2aaSAndroid Build Coastguard Worker         .value("Right", skui::InputState::kRight)
816*c8dee2aaSAndroid Build Coastguard Worker         .value("Left",  skui::InputState::kLeft);
817*c8dee2aaSAndroid Build Coastguard Worker 
818*c8dee2aaSAndroid Build Coastguard Worker     enum_<skui::ModifierKey>("ModifierKey")
819*c8dee2aaSAndroid Build Coastguard Worker         .value("None",       skui::ModifierKey::kNone)
820*c8dee2aaSAndroid Build Coastguard Worker         .value("Shift",      skui::ModifierKey::kShift)
821*c8dee2aaSAndroid Build Coastguard Worker         .value("Control",    skui::ModifierKey::kControl)
822*c8dee2aaSAndroid Build Coastguard Worker         .value("Option",     skui::ModifierKey::kOption)
823*c8dee2aaSAndroid Build Coastguard Worker         .value("Command",    skui::ModifierKey::kCommand)
824*c8dee2aaSAndroid Build Coastguard Worker         .value("FirstPress", skui::ModifierKey::kFirstPress);
825*c8dee2aaSAndroid Build Coastguard Worker 
826*c8dee2aaSAndroid Build Coastguard Worker     enum_<skottie::Shaper::VAlign>("VerticalTextAlign")
827*c8dee2aaSAndroid Build Coastguard Worker         .value("Top",          skottie::Shaper::VAlign::kTop)
828*c8dee2aaSAndroid Build Coastguard Worker         .value("TopBaseline",  skottie::Shaper::VAlign::kTopBaseline)
829*c8dee2aaSAndroid Build Coastguard Worker         .value("VisualTop",    skottie::Shaper::VAlign::kVisualTop)
830*c8dee2aaSAndroid Build Coastguard Worker         .value("VisualCenter", skottie::Shaper::VAlign::kVisualCenter)
831*c8dee2aaSAndroid Build Coastguard Worker         .value("VisualBottom", skottie::Shaper::VAlign::kVisualBottom);
832*c8dee2aaSAndroid Build Coastguard Worker 
833*c8dee2aaSAndroid Build Coastguard Worker     enum_<skottie::Shaper::ResizePolicy>("ResizePolicy")
834*c8dee2aaSAndroid Build Coastguard Worker         .value("None",           skottie::Shaper::ResizePolicy::kNone)
835*c8dee2aaSAndroid Build Coastguard Worker         .value("ScaleToFit",     skottie::Shaper::ResizePolicy::kScaleToFit)
836*c8dee2aaSAndroid Build Coastguard Worker         .value("DownscaleToFit", skottie::Shaper::ResizePolicy::kDownscaleToFit);
837*c8dee2aaSAndroid Build Coastguard Worker 
838*c8dee2aaSAndroid Build Coastguard Worker     value_object<SimpleSlottableTextProperty>("SlottableTextProperty")
839*c8dee2aaSAndroid Build Coastguard Worker         .field("typeface",          &SimpleSlottableTextProperty::typeface)
840*c8dee2aaSAndroid Build Coastguard Worker         .field("text",              &SimpleSlottableTextProperty::text)
841*c8dee2aaSAndroid Build Coastguard Worker         .field("textSize",          &SimpleSlottableTextProperty::textSize)
842*c8dee2aaSAndroid Build Coastguard Worker         .field("minTextSize",       &SimpleSlottableTextProperty::minTextSize)
843*c8dee2aaSAndroid Build Coastguard Worker         .field("maxTextSize",       &SimpleSlottableTextProperty::maxTextSize)
844*c8dee2aaSAndroid Build Coastguard Worker         .field("strokeWidth",       &SimpleSlottableTextProperty::strokeWidth)
845*c8dee2aaSAndroid Build Coastguard Worker         .field("lineHeight",        &SimpleSlottableTextProperty::lineHeight)
846*c8dee2aaSAndroid Build Coastguard Worker         .field("lineShift",         &SimpleSlottableTextProperty::lineShift)
847*c8dee2aaSAndroid Build Coastguard Worker         .field("ascent",            &SimpleSlottableTextProperty::ascent)
848*c8dee2aaSAndroid Build Coastguard Worker         .field("maxLines",          &SimpleSlottableTextProperty::maxLines)
849*c8dee2aaSAndroid Build Coastguard Worker         .field("horizAlign",        &SimpleSlottableTextProperty::horizAlign)
850*c8dee2aaSAndroid Build Coastguard Worker         .field("vertAlign",         &SimpleSlottableTextProperty::vertAlign)
851*c8dee2aaSAndroid Build Coastguard Worker         .field("strokeJoin",        &SimpleSlottableTextProperty::strokeJoin)
852*c8dee2aaSAndroid Build Coastguard Worker         .field("direction",         &SimpleSlottableTextProperty::direction)
853*c8dee2aaSAndroid Build Coastguard Worker         .field("linebreak",         &SimpleSlottableTextProperty::lineBreak)
854*c8dee2aaSAndroid Build Coastguard Worker         .field("resize",            &SimpleSlottableTextProperty::resize)
855*c8dee2aaSAndroid Build Coastguard Worker         .field("_fillColorPtr",     &SimpleSlottableTextProperty::fillColorPtr)
856*c8dee2aaSAndroid Build Coastguard Worker         .field("_strokeColorPtr",   &SimpleSlottableTextProperty::strokeColorPtr)
857*c8dee2aaSAndroid Build Coastguard Worker         .field("_boundingBoxPtr",   &SimpleSlottableTextProperty::boundingBoxPtr);
858*c8dee2aaSAndroid Build Coastguard Worker 
859*c8dee2aaSAndroid Build Coastguard Worker     constant("managed_skottie", true);
860*c8dee2aaSAndroid Build Coastguard Worker }
861