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