[skottie] Custom prop manager updates

Currently we use a hard-coded name prefix ('$') and the properties are
"namespaced" (the tree hierarchy is part of the key name).

This doesn't work well for most clients looking to test property
manipulation, as they would rather handle similarly named props in
bulk.

E.g. instead of

  precomp1.layer1.Group1.COLOR_01
  precomp1.layer1.Group1.COLOR_02
  precomp1.layer2.Group1.COLOR_01
  precomp1.layer2.Group2.COLOR_02

the UI should simply present

  COLOR_01
  COLOR_02

To support this, introduce a new operation mode for
CustomPropertyManager (kCollapseProperties), and keep the old behavior
around as kNamespacedProperties.

Also drop filtering for markers as anyone interested in markers would
want to see all of them.

Plumb these options all the way into CK (to be added to the player
later).

Change-Id: I57ec78c669f3870939d48fbfc492b97f63ea600d
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/312301
Reviewed-by: Kevin Lubick <kjlubick@google.com>
Commit-Queue: Florin Malita <fmalita@google.com>
This commit is contained in:
Florin Malita 2020-08-20 14:51:41 -04:00 committed by Skia Commit-Bot
parent d279cee2f2
commit 3f45e4b322
4 changed files with 70 additions and 42 deletions

View File

@ -4,12 +4,18 @@
// assets is a dictionary of named blobs: { key: ArrayBuffer, ... }
// The keys should be well-behaved strings - they're turned into null-terminated
// strings for the native side.
CanvasKit.MakeManagedAnimation = function(json, assets) {
// prop_filter_prefix is an optional string acting as a name filter for selecting
// "interesting" Lottie properties (surfaced in the embedded player controls)
CanvasKit.MakeManagedAnimation = function(json, assets, prop_filter_prefix) {
if (!CanvasKit._MakeManagedAnimation) {
throw 'Not compiled with MakeManagedAnimation';
}
if (!prop_filter_prefix) {
prop_filter_prefix = '';
}
if (!assets) {
return CanvasKit._MakeManagedAnimation(json, 0, nullptr, nullptr, nullptr);
return CanvasKit._MakeManagedAnimation(json, 0, nullptr, nullptr, nullptr, prop_filter_prefix);
}
var assetNamePtrs = [];
var assetDataPtrs = [];
@ -43,7 +49,7 @@ CanvasKit.MakeManagedAnimation = function(json, assets) {
var assetSizesPtr = copy1dArray(assetSizes, "HEAPU32");
var anim = CanvasKit._MakeManagedAnimation(json, assetKeys.length, namesPtr,
assetsPtr, assetSizesPtr);
assetsPtr, assetSizesPtr, prop_filter_prefix);
// The C++ code has made copies of the asset and string data, so free our copies.
CanvasKit._free(namesPtr);

View File

@ -89,8 +89,11 @@ private:
class ManagedAnimation final : public SkRefCnt {
public:
static sk_sp<ManagedAnimation> Make(const std::string& json,
sk_sp<skottie::ResourceProvider> rp) {
auto mgr = std::make_unique<skottie_utils::CustomPropertyManager>();
sk_sp<skottie::ResourceProvider> rp,
std::string prop_prefix) {
auto mgr = std::make_unique<skottie_utils::CustomPropertyManager>(
skottie_utils::CustomPropertyManager::Mode::kCollapseProperties,
prop_prefix.empty() ? nullptr : prop_prefix.c_str());
static constexpr char kInterceptPrefix[] = "__";
auto pinterceptor =
sk_make_sp<skottie_utils::ExternalAnimationPrecompInterceptor>(rp, kInterceptPrefix);
@ -243,7 +246,8 @@ EMSCRIPTEN_BINDINGS(Skottie) {
size_t assetCount,
uintptr_t /* char** */ nptr,
uintptr_t /* uint8_t** */ dptr,
uintptr_t /* size_t* */ sptr)
uintptr_t /* size_t* */ sptr,
std::string prop_prefix)
->sk_sp<ManagedAnimation> {
// See the comment in canvaskit_bindings.cpp about the use of uintptr_t
const auto assetNames = reinterpret_cast<char** >(nptr);
@ -260,8 +264,9 @@ EMSCRIPTEN_BINDINGS(Skottie) {
}
return ManagedAnimation::Make(json,
skresources::DataURIResourceProviderProxy::Make(
SkottieAssetProvider::Make(std::move(assets))));
skresources::DataURIResourceProviderProxy::Make(
SkottieAssetProvider::Make(std::move(assets))),
prop_prefix);
}));
constant("managed_skottie", true);
#endif // SK_INCLUDE_MANAGED_SKOTTIE

View File

@ -15,23 +15,34 @@ public:
void onColorProperty(const char node_name[],
const LazyHandle<skottie::ColorPropertyHandle>& c) override {
const auto markedKey = CustomPropertyManager::AcceptKey(node_name);
const auto key = markedKey.empty() ? markedKey : fMgr->fCurrentNode + ".Color";
fMgr->fColorMap[key].push_back(c());
const auto key = fMgr->acceptKey(node_name, ".Color");
if (!key.empty()) {
fMgr->fColorMap[key].push_back(c());
}
}
void onOpacityProperty(const char node_name[],
const LazyHandle<skottie::OpacityPropertyHandle>& o) override {
const auto markedKey = CustomPropertyManager::AcceptKey(node_name);
const auto key = markedKey.empty() ? markedKey : fMgr->fCurrentNode + ".Opacity";
fMgr->fOpacityMap[key].push_back(o());
const auto key = fMgr->acceptKey(node_name, ".Opacity");
if (!key.empty()) {
fMgr->fOpacityMap[key].push_back(o());
}
}
void onTransformProperty(const char node_name[],
const LazyHandle<skottie::TransformPropertyHandle>& t) override {
const auto markedKey = CustomPropertyManager::AcceptKey(node_name);
const auto key = markedKey.empty() ? markedKey : fMgr->fCurrentNode + ".Transform";
fMgr->fTransformMap[key].push_back(t());
const auto key = fMgr->acceptKey(node_name, ".Transform");
if (!key.empty()) {
fMgr->fTransformMap[key].push_back(t());
}
}
void onTextProperty(const char node_name[],
const LazyHandle<skottie::TextPropertyHandle>& t) override {
const auto key = fMgr->acceptKey(node_name, ".Text");
if (!key.empty()) {
fMgr->fTextMap[key].push_back(t());
}
}
void onEnterNode(const char node_name[]) override {
@ -48,14 +59,6 @@ public:
: "";
}
void onTextProperty(const char node_name[],
const LazyHandle<skottie::TextPropertyHandle>& t) override {
const auto key = CustomPropertyManager::AcceptKey(node_name);
if (!key.empty()) {
fMgr->fTextMap[key].push_back(t());
}
}
private:
CustomPropertyManager* fMgr;
};
@ -65,22 +68,32 @@ public:
explicit MarkerInterceptor(CustomPropertyManager* mgr) : fMgr(mgr) {}
void onMarker(const char name[], float t0, float t1) override {
const auto key = CustomPropertyManager::AcceptKey(name);
if (!key.empty()) {
fMgr->fMarkers.push_back({ std::move(key), t0, t1 });
}
// collect all markers
fMgr->fMarkers.push_back({ std::string(name), t0, t1 });
}
private:
CustomPropertyManager* fMgr;
};
CustomPropertyManager::CustomPropertyManager()
: fPropertyInterceptor(sk_make_sp<PropertyInterceptor>(this))
CustomPropertyManager::CustomPropertyManager(Mode mode, const char* prefix)
: fMode(mode)
, fPrefix(prefix ? prefix : "$")
, fPropertyInterceptor(sk_make_sp<PropertyInterceptor>(this))
, fMarkerInterceptor(sk_make_sp<MarkerInterceptor>(this)) {}
CustomPropertyManager::~CustomPropertyManager() = default;
std::string CustomPropertyManager::acceptKey(const char* name, const char* suffix) const {
if (!SkStrStartsWith(name, fPrefix.c_str())) {
return std::string();
}
return fMode == Mode::kCollapseProperties
? std::string(name)
: fCurrentNode + suffix;
}
sk_sp<skottie::PropertyObserver> CustomPropertyManager::getPropertyObserver() const {
return fPropertyInterceptor;
}

View File

@ -33,7 +33,14 @@ namespace skottie_utils {
*/
class CustomPropertyManager final {
public:
CustomPropertyManager();
enum class Mode {
kCollapseProperties, // keys ignore the ancestor chain and are
// grouped based on the local node name
kNamespacedProperties, // keys include the ancestor node names (no grouping)
};
explicit CustomPropertyManager(Mode = Mode::kNamespacedProperties,
const char* prefix = nullptr);
~CustomPropertyManager();
using PropKey = std::string;
@ -70,16 +77,7 @@ private:
class PropertyInterceptor;
class MarkerInterceptor;
static std::string AcceptKey(const char* name) {
static constexpr char kPrefix = '$';
return (name[0] == kPrefix && name[1] != '\0')
? std::string(name + 1)
: std::string();
}
sk_sp<PropertyInterceptor> fPropertyInterceptor;
sk_sp<MarkerInterceptor> fMarkerInterceptor;
std::string acceptKey(const char*, const char*) const;
template <typename T>
using PropGroup = std::vector<std::unique_ptr<T>>;
@ -96,6 +94,12 @@ private:
template <typename V, typename T>
bool set(const PropKey&, const V&, const PropMap<T>& container);
const Mode fMode;
const SkString fPrefix;
sk_sp<PropertyInterceptor> fPropertyInterceptor;
sk_sp<MarkerInterceptor> fMarkerInterceptor;
PropMap<skottie::ColorPropertyHandle> fColorMap;
PropMap<skottie::OpacityPropertyHandle> fOpacityMap;
PropMap<skottie::TransformPropertyHandle> fTransformMap;