skia2/modules/canvaskit/skottie_bindings.cpp
Brian Osman 849f4d6571 Copy SkottieUtils' classes into skresources
For now, we'll have two copies. Once clients are using the skresources
versions exclusively, we can remove the originals from skottie.

Change-Id: I3152f526b0505b8374bdd9b4513a80bddc702ccc
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/256416
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Florin Malita <fmalita@chromium.org>
Reviewed-by: Kevin Lubick <kjlubick@google.com>
2019-11-26 14:25:44 +00:00

256 lines
9.7 KiB
C++

/*
* Copyright 2019 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "include/core/SkCanvas.h"
#include "include/core/SkImage.h"
#include "include/core/SkString.h"
#include "include/core/SkTypes.h"
#include "modules/skottie/include/Skottie.h"
#include "modules/sksg/include/SkSGInvalidationController.h"
#include "src/core/SkMakeUnique.h"
#include <string>
#include <vector>
#include <emscripten.h>
#include <emscripten/bind.h>
#include "modules/canvaskit/WasmAliases.h"
#if SK_INCLUDE_MANAGED_SKOTTIE
#include "modules/skottie/include/SkottieProperty.h"
#include "modules/skottie/utils/SkottieUtils.h"
#include "modules/skresources/include/SkResources.h"
#endif // SK_INCLUDE_MANAGED_SKOTTIE
using namespace emscripten;
#if SK_INCLUDE_MANAGED_SKOTTIE
namespace {
class SkottieAssetProvider : public skottie::ResourceProvider {
public:
~SkottieAssetProvider() override = default;
// Tried using a map, but that gave strange errors like
// https://emscripten.org/docs/porting/guidelines/function_pointer_issues.html
// Not entirely sure why, but perhaps the iterator in the map was
// confusing enscripten.
using AssetVec = std::vector<std::pair<SkString, sk_sp<SkData>>>;
static sk_sp<SkottieAssetProvider> Make(AssetVec assets) {
if (assets.empty()) {
return nullptr;
}
return sk_sp<SkottieAssetProvider>(new SkottieAssetProvider(std::move(assets)));
}
sk_sp<skottie::ImageAsset> loadImageAsset(const char[] /* path */,
const char name[],
const char[] /* id */) const override {
// For CK/Skottie we ignore paths & IDs, and identify images based solely on name.
if (auto data = this->findAsset(name)) {
return skresources::MultiFrameImageAsset::Make(std::move(data));
}
return nullptr;
}
sk_sp<SkData> loadFont(const char name[], const char[] /* url */) const override {
// Same as images paths, we ignore font URLs.
return this->findAsset(name);
}
private:
explicit SkottieAssetProvider(AssetVec assets) : fAssets(std::move(assets)) {}
sk_sp<SkData> findAsset(const char name[]) const {
for (const auto& asset : fAssets) {
if (asset.first.equals(name)) {
return asset.second;
}
}
SkDebugf("Could not find %s\n", name);
return nullptr;
}
const AssetVec fAssets;
};
class ManagedAnimation final : public SkRefCnt {
public:
static sk_sp<ManagedAnimation> Make(const std::string& json,
sk_sp<skottie::ResourceProvider> rp) {
auto mgr = skstd::make_unique<skottie_utils::CustomPropertyManager>();
auto animation = skottie::Animation::Builder()
.setMarkerObserver(mgr->getMarkerObserver())
.setPropertyObserver(mgr->getPropertyObserver())
.setResourceProvider(rp)
.make(json.c_str(), json.size());
return animation
? sk_sp<ManagedAnimation>(new ManagedAnimation(std::move(animation), std::move(mgr)))
: nullptr;
}
~ManagedAnimation() override = default;
// skottie::Animation API
void render(SkCanvas* canvas) const { fAnimation->render(canvas, nullptr); }
void render(SkCanvas* canvas, const SkRect& dst) const { fAnimation->render(canvas, &dst); }
// Returns a damage rect.
SkRect seek(SkScalar t) {
sksg::InvalidationController ic;
fAnimation->seek(t, &ic);
return ic.bounds();
}
// Returns a damage rect.
SkRect seekFrame(double t) {
sksg::InvalidationController ic;
fAnimation->seekFrame(t, &ic);
return ic.bounds();
}
double duration() const { return fAnimation->duration(); }
double fps() const { return fAnimation->fps(); }
const SkSize& size() const { return fAnimation->size(); }
std::string version() const { return std::string(fAnimation->version().c_str()); }
// CustomPropertyManager API
JSArray getColorProps() const {
JSArray props = emscripten::val::array();
for (const auto& cp : fPropMgr->getColorProps()) {
JSObject prop = emscripten::val::object();
prop.set("key", cp);
prop.set("value", fPropMgr->getColor(cp));
props.call<void>("push", prop);
}
return props;
}
JSArray getOpacityProps() const {
JSArray props = emscripten::val::array();
for (const auto& op : fPropMgr->getOpacityProps()) {
JSObject prop = emscripten::val::object();
prop.set("key", op);
prop.set("value", fPropMgr->getOpacity(op));
props.call<void>("push", prop);
}
return props;
}
bool setColor(const std::string& key, SkColor c) {
return fPropMgr->setColor(key, c);
}
bool setOpacity(const std::string& key, float o) {
return fPropMgr->setOpacity(key, o);
}
JSArray getMarkers() const {
JSArray markers = emscripten::val::array();
for (const auto& m : fPropMgr->markers()) {
JSObject marker = emscripten::val::object();
marker.set("name", m.name);
marker.set("t0" , m.t0);
marker.set("t1" , m.t1);
markers.call<void>("push", marker);
}
return markers;
}
private:
ManagedAnimation(sk_sp<skottie::Animation> animation,
std::unique_ptr<skottie_utils::CustomPropertyManager> propMgr)
: fAnimation(std::move(animation))
, fPropMgr(std::move(propMgr)) {}
sk_sp<skottie::Animation> fAnimation;
std::unique_ptr<skottie_utils::CustomPropertyManager> fPropMgr;
};
} // anonymous ns
#endif // SK_INCLUDE_MANAGED_SKOTTIE
EMSCRIPTEN_BINDINGS(Skottie) {
// Animation things (may eventually go in own library)
class_<skottie::Animation>("Animation")
.smart_ptr<sk_sp<skottie::Animation>>("sk_sp<Animation>")
.function("version", optional_override([](skottie::Animation& self)->std::string {
return std::string(self.version().c_str());
}))
.function("size" , &skottie::Animation::size)
.function("duration", &skottie::Animation::duration)
.function("fps" , &skottie::Animation::fps)
.function("seek", optional_override([](skottie::Animation& self, SkScalar t)->void {
self.seek(t);
}))
.function("seekFrame", optional_override([](skottie::Animation& self, double t)->void {
self.seekFrame(t);
}))
.function("render", optional_override([](skottie::Animation& self, SkCanvas* canvas)->void {
self.render(canvas, nullptr);
}), allow_raw_pointers())
.function("render", optional_override([](skottie::Animation& self, SkCanvas* canvas,
const SkRect r)->void {
self.render(canvas, &r);
}), allow_raw_pointers());
function("MakeAnimation", optional_override([](std::string json)->sk_sp<skottie::Animation> {
return skottie::Animation::Make(json.c_str(), json.length());
}));
constant("skottie", true);
#if SK_INCLUDE_MANAGED_SKOTTIE
class_<ManagedAnimation>("ManagedAnimation")
.smart_ptr<sk_sp<ManagedAnimation>>("sk_sp<ManagedAnimation>")
.function("version" , &ManagedAnimation::version)
.function("size" , &ManagedAnimation::size)
.function("duration" , &ManagedAnimation::duration)
.function("fps" , &ManagedAnimation::fps)
.function("seek" , &ManagedAnimation::seek)
.function("seekFrame" , &ManagedAnimation::seekFrame)
.function("render" , select_overload<void(SkCanvas*) const>(&ManagedAnimation::render), allow_raw_pointers())
.function("render" , select_overload<void(SkCanvas*, const SkRect&) const>
(&ManagedAnimation::render), allow_raw_pointers())
.function("setColor" , &ManagedAnimation::setColor)
.function("setOpacity", &ManagedAnimation::setOpacity)
.function("getMarkers", &ManagedAnimation::getMarkers)
.function("getColorProps" , &ManagedAnimation::getColorProps)
.function("getOpacityProps", &ManagedAnimation::getOpacityProps);
function("_MakeManagedAnimation", optional_override([](std::string json,
size_t assetCount,
uintptr_t /* char** */ nptr,
uintptr_t /* uint8_t** */ dptr,
uintptr_t /* size_t* */ sptr)
->sk_sp<ManagedAnimation> {
const auto assetNames = reinterpret_cast<char** >(nptr);
const auto assetDatas = reinterpret_cast<uint8_t**>(dptr);
const auto assetSizes = reinterpret_cast<size_t* >(sptr);
SkottieAssetProvider::AssetVec assets;
assets.reserve(assetCount);
for (size_t i = 0; i < assetCount; i++) {
auto name = SkString(assetNames[i]);
auto bytes = SkData::MakeFromMalloc(assetDatas[i], assetSizes[i]);
assets.push_back(std::make_pair(std::move(name), std::move(bytes)));
}
return ManagedAnimation::Make(json,
skresources::DataURIResourceProviderProxy::Make(
SkottieAssetProvider::Make(std::move(assets))));
}));
constant("managed_skottie", true);
#endif // SK_INCLUDE_MANAGED_SKOTTIE
}