skia2/modules/skottie/utils/SkottieUtils.cpp
Florin Malita 3f45e4b322 [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>
2020-08-20 19:59:22 +00:00

245 lines
7.6 KiB
C++

/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "modules/skottie/utils/SkottieUtils.h"
namespace skottie_utils {
class CustomPropertyManager::PropertyInterceptor final : public skottie::PropertyObserver {
public:
explicit PropertyInterceptor(CustomPropertyManager* mgr) : fMgr(mgr) {}
void onColorProperty(const char node_name[],
const LazyHandle<skottie::ColorPropertyHandle>& c) override {
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 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 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 {
fMgr->fCurrentNode =
fMgr->fCurrentNode.empty() ? node_name : fMgr->fCurrentNode + "." + node_name;
}
void onLeavingNode(const char node_name[]) override {
auto length = strlen(node_name);
fMgr->fCurrentNode =
fMgr->fCurrentNode.length() > length
? fMgr->fCurrentNode.substr(
0, fMgr->fCurrentNode.length() - strlen(node_name) - 1)
: "";
}
private:
CustomPropertyManager* fMgr;
};
class CustomPropertyManager::MarkerInterceptor final : public skottie::MarkerObserver {
public:
explicit MarkerInterceptor(CustomPropertyManager* mgr) : fMgr(mgr) {}
void onMarker(const char name[], float t0, float t1) override {
// collect all markers
fMgr->fMarkers.push_back({ std::string(name), t0, t1 });
}
private:
CustomPropertyManager* fMgr;
};
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;
}
sk_sp<skottie::MarkerObserver> CustomPropertyManager::getMarkerObserver() const {
return fMarkerInterceptor;
}
template <typename T>
std::vector<CustomPropertyManager::PropKey>
CustomPropertyManager::getProps(const PropMap<T>& container) const {
std::vector<PropKey> props;
for (const auto& prop_list : container) {
SkASSERT(!prop_list.second.empty());
props.push_back(prop_list.first);
}
return props;
}
template <typename V, typename T>
V CustomPropertyManager::get(const PropKey& key, const PropMap<T>& container) const {
auto prop_group = container.find(key);
return prop_group == container.end()
? V()
: prop_group->second.front()->get();
}
template <typename V, typename T>
bool CustomPropertyManager::set(const PropKey& key, const V& val, const PropMap<T>& container) {
auto prop_group = container.find(key);
if (prop_group == container.end()) {
return false;
}
for (auto& handle : prop_group->second) {
handle->set(val);
}
return true;
}
std::vector<CustomPropertyManager::PropKey>
CustomPropertyManager::getColorProps() const {
return this->getProps(fColorMap);
}
skottie::ColorPropertyValue CustomPropertyManager::getColor(const PropKey& key) const {
return this->get<skottie::ColorPropertyValue>(key, fColorMap);
}
bool CustomPropertyManager::setColor(const PropKey& key, const skottie::ColorPropertyValue& c) {
return this->set(key, c, fColorMap);
}
std::vector<CustomPropertyManager::PropKey>
CustomPropertyManager::getOpacityProps() const {
return this->getProps(fOpacityMap);
}
skottie::OpacityPropertyValue CustomPropertyManager::getOpacity(const PropKey& key) const {
return this->get<skottie::OpacityPropertyValue>(key, fOpacityMap);
}
bool CustomPropertyManager::setOpacity(const PropKey& key, const skottie::OpacityPropertyValue& o) {
return this->set(key, o, fOpacityMap);
}
std::vector<CustomPropertyManager::PropKey>
CustomPropertyManager::getTransformProps() const {
return this->getProps(fTransformMap);
}
skottie::TransformPropertyValue CustomPropertyManager::getTransform(const PropKey& key) const {
return this->get<skottie::TransformPropertyValue>(key, fTransformMap);
}
bool CustomPropertyManager::setTransform(const PropKey& key,
const skottie::TransformPropertyValue& t) {
return this->set(key, t, fTransformMap);
}
std::vector<CustomPropertyManager::PropKey>
CustomPropertyManager::getTextProps() const {
return this->getProps(fTextMap);
}
skottie::TextPropertyValue CustomPropertyManager::getText(const PropKey& key) const {
return this->get<skottie::TextPropertyValue>(key, fTextMap);
}
bool CustomPropertyManager::setText(const PropKey& key, const skottie::TextPropertyValue& o) {
return this->set(key, o, fTextMap);
}
namespace {
class ExternalAnimationLayer final : public skottie::ExternalLayer {
public:
ExternalAnimationLayer(sk_sp<skottie::Animation> anim, const SkSize& size)
: fAnimation(std::move(anim))
, fSize(size) {}
private:
void render(SkCanvas* canvas, double t) override {
fAnimation->seekFrameTime(t);
const auto dst_rect = SkRect::MakeSize(fSize);
fAnimation->render(canvas, &dst_rect);
}
const sk_sp<skottie::Animation> fAnimation;
const SkSize fSize;
};
} // namespace
ExternalAnimationPrecompInterceptor::ExternalAnimationPrecompInterceptor(
sk_sp<skresources::ResourceProvider> rprovider,
const char prefixp[])
: fResourceProvider(std::move(rprovider))
, fPrefix(prefixp) {}
ExternalAnimationPrecompInterceptor::~ExternalAnimationPrecompInterceptor() = default;
sk_sp<skottie::ExternalLayer> ExternalAnimationPrecompInterceptor::onLoadPrecomp(
const char[], const char name[], const SkSize& size) {
if (0 != strncmp(name, fPrefix.c_str(), fPrefix.size())) {
return nullptr;
}
auto data = fResourceProvider->load("", name + fPrefix.size());
if (!data) {
return nullptr;
}
auto anim = skottie::Animation::Builder()
.setPrecompInterceptor(sk_ref_sp(this))
.make(static_cast<const char*>(data->data()), data->size());
return anim ? sk_make_sp<ExternalAnimationLayer>(std::move(anim), size)
: nullptr;
}
} // namespace skottie_utils