3f45e4b322
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>
245 lines
7.6 KiB
C++
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
|