Revert "[skottie] Initial property setters"

This reverts commit 7903957247.

Reason for revert: breaking SAN bots

Original change's description:
> [skottie] Initial property setters
> 
> Introduce a PropertyObserver to receive property notifications for layer
> and shape nodes.
> 
> Properties are communicated using strongly-typed "handles", which act
> as impedance adapters between the AE/BM model and the internal Skottie
> model.
> 
> Bug: skia:
> Change-Id: Ieb9be1ff843673f1f4fe900d3774c36956b7c941
> Reviewed-on: https://skia-review.googlesource.com/156186
> Commit-Queue: Florin Malita <fmalita@chromium.org>
> Reviewed-by: Mike Reed <reed@google.com>

TBR=fmalita@chromium.org,reed@google.com

Change-Id: Ic737766e305bb8dff10a817fa37f16fdfa051c93
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: skia:
Reviewed-on: https://skia-review.googlesource.com/156620
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
This commit is contained in:
Brian Salomon 2018-09-24 20:46:16 +00:00 committed by Skia Commit-Bot
parent 41e404746d
commit 39e1d13d35
11 changed files with 36 additions and 514 deletions

View File

@ -26,8 +26,6 @@ namespace sksg { class Scene; }
namespace skottie {
class PropertyObserver;
/**
* ResourceProvider allows Skottie embedders to control loading of external
* Skottie resources -- e.g. images, fonts, nested animations.
@ -64,9 +62,6 @@ public:
class Builder final {
public:
Builder();
~Builder();
struct Stats {
float fTotalLoadTimeMS = 0, // Total animation instantiation time.
fJsonParseTimeMS = 0, // Time spent building a JSON DOM.
@ -92,14 +87,6 @@ public:
*/
Builder& setFontManager(sk_sp<SkFontMgr>);
/**
* Specify a PropertyObserver to receive callbacks during parsing.
*
* See SkottieProperty.h for more details.
*
*/
Builder& setPropertyObserver(sk_sp<PropertyObserver>);
/**
* Animation factories.
*/
@ -110,7 +97,6 @@ public:
private:
sk_sp<ResourceProvider> fResourceProvider;
sk_sp<SkFontMgr> fFontMgr;
sk_sp<PropertyObserver> fPropertyObserver;
Stats fStats;
};

View File

@ -1,121 +0,0 @@
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkottieProperty_DEFINED
#define SkottieProperty_DEFINED
#include "SkColor.h"
#include "SkPoint.h"
#include "SkRefCnt.h"
#include <functional>
class SkMatrix;
namespace sksg {
class Color;
class OpacityEffect;
} // namespace sksg
namespace skottie {
class ColorPropertyHandle;
class OpacityPropertyHandle;
class TransformPropertyHandle;
/**
* A PropertyObserver can be used to track and manipulate certain properties of "interesting"
* Lottie nodes.
*
* When registered with an animation builder, PropertyObserver receives notifications for
* various properties of layer and shape nodes. The |node_name| argument corresponds to the
* name ("nm") node property.
*/
class PropertyObserver : public SkRefCnt {
public:
template <typename T>
using LazyHandle = std::function<std::unique_ptr<T>()>;
virtual void onColorProperty (const char node_name[],
const LazyHandle<ColorPropertyHandle>&);
virtual void onOpacityProperty (const char node_name[],
const LazyHandle<OpacityPropertyHandle>&);
virtual void onTransformProperty(const char node_name[],
const LazyHandle<TransformPropertyHandle>&);
};
namespace internal { class AnimationBuilder; }
class ColorPropertyHandle final {
public:
~ColorPropertyHandle();
SkColor getColor() const;
void setColor(SkColor);
private:
explicit ColorPropertyHandle(sk_sp<sksg::Color>);
friend class skottie::internal::AnimationBuilder;
const sk_sp<sksg::Color> fColor;
};
class OpacityPropertyHandle final {
public:
~OpacityPropertyHandle();
float getOpacity() const;
void setOpacity(float);
private:
explicit OpacityPropertyHandle(sk_sp<sksg::OpacityEffect>);
friend class skottie::internal::AnimationBuilder;
const sk_sp<sksg::OpacityEffect> fOpacity;
};
class TransformAdapter;
class TransformPropertyHandle final {
public:
~TransformPropertyHandle();
SkPoint getAnchorPoint() const;
void setAnchorPoint(const SkPoint&);
SkPoint getPosition() const;
void setPosition(const SkPoint&);
SkVector getScale() const;
void setScale(const SkVector&);
SkScalar getRotation() const;
void setRotation(SkScalar);
SkScalar getSkew() const;
void setSkew(SkScalar);
SkScalar getSkewAxis() const;
void setSkewAxis(SkScalar);
SkMatrix getTotalMatrix() const;
private:
explicit TransformPropertyHandle(sk_sp<TransformAdapter>);
friend class skottie::internal::AnimationBuilder;
const sk_sp<TransformAdapter> fTransform;
};
} // namespace skottie
#endif // SkottieProperty_DEFINED

View File

@ -7,10 +7,7 @@
_src = get_path_info("src", "abspath")
_include = get_path_info("include", "abspath")
skia_skottie_public = [
"$_include/Skottie.h",
"$_include/SkottieProperty.h",
]
skia_skottie_public = [ "$_include/Skottie.h" ]
skia_skottie_sources = [
"$_src/Skottie.cpp",
@ -23,7 +20,6 @@ skia_skottie_sources = [
"$_src/SkottieLayerEffect.cpp",
"$_src/SkottiePriv.h",
"$_src/SkottiePrecompLayer.cpp",
"$_src/SkottieProperty.cpp",
"$_src/SkottieShapeLayer.cpp",
"$_src/SkottieTextLayer.cpp",
"$_src/SkottieValue.cpp",

View File

@ -27,7 +27,6 @@
#include "SkottieAdapter.h"
#include "SkottieJson.h"
#include "SkottiePriv.h"
#include "SkottieProperty.h"
#include "SkottieValue.h"
#include <cmath>
@ -84,9 +83,7 @@ sk_sp<sksg::Matrix> AnimationBuilder::attachMatrix(const skjson::ObjectValue& t,
adapter->setSkewAxis(sa);
}, 0.0f);
const auto dispatched = this->dispatchTransformProperty(adapter);
return (bound || dispatched) ? matrix : parentMatrix;
return bound ? matrix : parentMatrix;
}
sk_sp<sksg::RenderNode> AnimationBuilder::attachOpacity(const skjson::ObjectValue& jtransform,
@ -97,15 +94,16 @@ sk_sp<sksg::RenderNode> AnimationBuilder::attachOpacity(const skjson::ObjectValu
auto opacityNode = sksg::OpacityEffect::Make(childNode);
const auto bound = this->bindProperty<ScalarValue>(jtransform["o"], ascope,
if (!this->bindProperty<ScalarValue>(jtransform["o"], ascope,
[opacityNode](const ScalarValue& o) {
// BM opacity is [0..100]
opacityNode->setOpacity(o * 0.01f);
}, 100.0f);
const auto dispatched = this->dispatchOpacityProperty(opacityNode);
}, 100.0f)) {
// We can ignore static full opacity.
return childNode;
}
// We can ignore constant full opacity.
return (bound || dispatched) ? std::move(opacityNode) : childNode;
return std::move(opacityNode);
}
sk_sp<sksg::Path> AnimationBuilder::attachPath(const skjson::Value& jpath,
@ -126,23 +124,19 @@ sk_sp<sksg::Color> AnimationBuilder::attachColor(const skjson::ObjectValue& jcol
AnimatorScope* ascope,
const char prop_name[]) const {
auto color_node = sksg::Color::Make(SK_ColorBLACK);
this->bindProperty<VectorValue>(jcolor[prop_name], ascope,
[color_node](const VectorValue& c) {
color_node->setColor(ValueTraits<VectorValue>::As<SkColor>(c));
});
this->dispatchColorProperty(color_node);
return color_node;
}
AnimationBuilder::AnimationBuilder(sk_sp<ResourceProvider> rp, sk_sp<SkFontMgr> fontmgr,
sk_sp<PropertyObserver> pobserver,
Animation::Builder::Stats* stats,
float duration, float framerate)
: fResourceProvider(std::move(rp))
, fLazyFontMgr(std::move(fontmgr))
, fPropertyObserver(std::move(pobserver))
, fStats(stats)
, fDuration(duration)
, fFrameRate(framerate) {}
@ -171,56 +165,6 @@ void AnimationBuilder::parseAssets(const skjson::ArrayValue* jassets) {
}
}
bool AnimationBuilder::dispatchColorProperty(const sk_sp<sksg::Color>& c) const {
bool dispatched = false;
if (fPropertyObserver) {
fPropertyObserver->onColorProperty(fPropertyObserverContext,
[&]() {
dispatched = true;
return std::unique_ptr<ColorPropertyHandle>(new ColorPropertyHandle(c));
});
}
return dispatched;
}
bool AnimationBuilder::dispatchOpacityProperty(const sk_sp<sksg::OpacityEffect>& o) const {
bool dispatched = false;
if (fPropertyObserver) {
fPropertyObserver->onOpacityProperty(fPropertyObserverContext,
[&]() {
dispatched = true;
return std::unique_ptr<OpacityPropertyHandle>(new OpacityPropertyHandle(o));
});
}
return dispatched;
}
bool AnimationBuilder::dispatchTransformProperty(const sk_sp<TransformAdapter>& t) const {
bool dispatched = false;
if (fPropertyObserver) {
fPropertyObserver->onTransformProperty(fPropertyObserverContext,
[&]() {
dispatched = true;
return std::unique_ptr<TransformPropertyHandle>(new TransformPropertyHandle(t));
});
}
return dispatched;
}
void AnimationBuilder::AutoPropertyTracker::updateContext(PropertyObserver* observer,
const skjson::ObjectValue& obj) {
const skjson::StringValue* name = obj["nm"];
fBuilder->fPropertyObserverContext = name ? name->begin() : nullptr;
}
} // namespace internal
sk_sp<SkData> ResourceProvider::load(const char[], const char[]) const {
@ -231,9 +175,6 @@ sk_sp<SkData> ResourceProvider::loadWebFont(const char[]) const {
return nullptr;
}
Animation::Builder::Builder() = default;
Animation::Builder::~Builder() = default;
Animation::Builder& Animation::Builder::setResourceProvider(sk_sp<ResourceProvider> rp) {
fResourceProvider = std::move(rp);
return *this;
@ -244,11 +185,6 @@ Animation::Builder& Animation::Builder::setFontManager(sk_sp<SkFontMgr> fmgr) {
return *this;
}
Animation::Builder& Animation::Builder::setPropertyObserver(sk_sp<PropertyObserver> pobserver) {
fPropertyObserver = std::move(pobserver);
return *this;
}
sk_sp<Animation> Animation::Builder::make(SkStream* stream) {
if (!stream->hasLength()) {
// TODO: handle explicit buffering?
@ -307,7 +243,7 @@ sk_sp<Animation> Animation::Builder::make(const char* data, size_t data_len) {
SkASSERT(resolvedProvider);
internal::AnimationBuilder builder(std::move(resolvedProvider), fFontMgr,
std::move(fPropertyObserver), &fStats, duration, fps);
&fStats, duration, fps);
auto scene = builder.parse(json);
const auto t2 = SkTime::GetMSecs();

View File

@ -43,7 +43,7 @@ void RRectAdapter::apply() {
TransformAdapter::TransformAdapter(sk_sp<sksg::Matrix> matrix)
: fMatrixNode(std::move(matrix)) {}
SkMatrix TransformAdapter::totalMatrix() const {
void TransformAdapter::apply() {
SkMatrix t = SkMatrix::MakeTrans(-fAnchorPoint.x(), -fAnchorPoint.y());
t.postScale(fScale.x() / 100, fScale.y() / 100); // 100% based
@ -51,11 +51,7 @@ SkMatrix TransformAdapter::totalMatrix() const {
t.postTranslate(fPosition.x(), fPosition.y());
// TODO: skew
return t;
}
void TransformAdapter::apply() {
fMatrixNode->setMatrix(this->totalMatrix());
fMatrixNode->setMatrix(t);
}
PolyStarAdapter::PolyStarAdapter(sk_sp<sksg::Path> wrapped_node, Type t)

View File

@ -32,9 +32,6 @@ class TrimEffect;
namespace skottie {
#define ADAPTER_PROPERTY(p_name, p_type, p_default) \
const p_type& get##p_name() const { \
return f##p_name; \
} \
void set##p_name(const p_type& p) { \
if (p == f##p_name) return; \
f##p_name = p; \
@ -96,8 +93,6 @@ public:
ADAPTER_PROPERTY(Skew , SkScalar, 0)
ADAPTER_PROPERTY(SkewAxis , SkScalar, 0)
SkMatrix totalMatrix() const;
private:
void apply();

View File

@ -408,8 +408,6 @@ sk_sp<sksg::RenderNode> AnimationBuilder::attachLayer(const skjson::ObjectValue*
AttachLayerContext* layerCtx) const {
if (!jlayer) return nullptr;
const AutoPropertyTracker apt(this, *jlayer);
using LayerAttacher = sk_sp<sksg::RenderNode> (AnimationBuilder::*)(const skjson::ObjectValue&,
AnimatorScope*) const;
static constexpr LayerAttacher gLayerAttachers[] = {

View File

@ -11,7 +11,6 @@
#include "Skottie.h"
#include "SkFontStyle.h"
#include "SkottieProperty.h"
#include "SkSGScene.h"
#include "SkString.h"
#include "SkTHash.h"
@ -45,8 +44,8 @@ using AnimatorScope = sksg::AnimatorList;
class AnimationBuilder final : public SkNoncopyable {
public:
AnimationBuilder(sk_sp<ResourceProvider>, sk_sp<SkFontMgr>, sk_sp<PropertyObserver>,
Animation::Builder::Stats*, float duration, float framerate);
AnimationBuilder(sk_sp<ResourceProvider>, sk_sp<SkFontMgr>, Animation::Builder::Stats*,
float duration, float framerate);
std::unique_ptr<sksg::Scene> parse(const skjson::ObjectValue&);
@ -78,7 +77,6 @@ public:
private:
struct AttachLayerContext;
struct AttachShapeContext;
void parseAssets(const skjson::ArrayValue*);
void parseFonts (const skjson::ObjectValue* jfonts,
@ -89,7 +87,6 @@ private:
sk_sp<sksg::RenderNode> attachLayerEffects(const skjson::ArrayValue& jeffects, AnimatorScope*,
sk_sp<sksg::RenderNode>) const;
sk_sp<sksg::RenderNode> attachShape(const skjson::ArrayValue*, AttachShapeContext*) const;
sk_sp<sksg::RenderNode> attachAssetRef(const skjson::ObjectValue&, AnimatorScope*,
sk_sp<sksg::RenderNode>(AnimationBuilder::*)(const skjson::ObjectValue&,
AnimatorScope* ctx) const) const;
@ -104,10 +101,6 @@ private:
sk_sp<sksg::RenderNode> attachSolidLayer (const skjson::ObjectValue&, AnimatorScope*) const;
sk_sp<sksg::RenderNode> attachTextLayer (const skjson::ObjectValue&, AnimatorScope*) const;
bool dispatchColorProperty(const sk_sp<sksg::Color>&) const;
bool dispatchOpacityProperty(const sk_sp<sksg::OpacityEffect>&) const;
bool dispatchTransformProperty(const sk_sp<TransformAdapter>&) const;
// Delay resolving the fontmgr until it is actually needed.
struct LazyResolveFontMgr {
LazyResolveFontMgr(sk_sp<SkFontMgr> fontMgr) : fFontMgr(std::move(fontMgr)) {}
@ -126,37 +119,12 @@ private:
sk_sp<SkFontMgr> fFontMgr;
};
class AutoPropertyTracker {
public:
AutoPropertyTracker(const AnimationBuilder* builder, const skjson::ObjectValue& obj)
: fBuilder(builder)
, fPrevContext(builder->fPropertyObserverContext) {
if (fBuilder->fPropertyObserver) {
this->updateContext(builder->fPropertyObserver.get(), obj);
}
}
~AutoPropertyTracker() {
if (fBuilder->fPropertyObserver) {
fBuilder->fPropertyObserverContext = fPrevContext;
}
}
private:
void updateContext(PropertyObserver*, const skjson::ObjectValue&);
const AnimationBuilder* fBuilder;
const char* fPrevContext;
};
sk_sp<ResourceProvider> fResourceProvider;
LazyResolveFontMgr fLazyFontMgr;
sk_sp<PropertyObserver> fPropertyObserver;
Animation::Builder::Stats* fStats;
const float fDuration,
fFrameRate;
mutable const char* fPropertyObserverContext;
struct AssetInfo {
const skjson::ObjectValue* fAsset;
mutable bool fIsAttaching; // Used for cycle detection

View File

@ -1,114 +0,0 @@
/*
* 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 "SkottieProperty.h"
#include "SkottieAdapter.h"
#include "SkSGColor.h"
#include "SkSGOpacityEffect.h"
namespace skottie {
ColorPropertyHandle::ColorPropertyHandle(sk_sp<sksg::Color> color)
: fColor(std::move(color)) {
SkASSERT(fColor);
}
ColorPropertyHandle::~ColorPropertyHandle() = default;
SkColor ColorPropertyHandle::getColor() const {
return fColor->getColor();
}
void ColorPropertyHandle::setColor(SkColor color) {
fColor->setColor(color);
}
OpacityPropertyHandle::OpacityPropertyHandle(sk_sp<sksg::OpacityEffect> opacity)
: fOpacity(std::move(opacity)) {
SkASSERT(fOpacity);
}
OpacityPropertyHandle::~OpacityPropertyHandle() = default;
float OpacityPropertyHandle::getOpacity() const {
return fOpacity->getOpacity() * 100;
}
void OpacityPropertyHandle::setOpacity(float opacity) {
fOpacity->setOpacity(opacity / 100);
}
TransformPropertyHandle::TransformPropertyHandle(sk_sp<TransformAdapter> transform)
: fTransform(std::move(transform)) {
SkASSERT(fTransform);
}
TransformPropertyHandle::~TransformPropertyHandle() = default;
SkPoint TransformPropertyHandle::getAnchorPoint() const {
return fTransform->getAnchorPoint();
}
void TransformPropertyHandle::setAnchorPoint(const SkPoint& ap) {
fTransform->setAnchorPoint(ap);
}
SkPoint TransformPropertyHandle::getPosition() const {
return fTransform->getPosition();
}
void TransformPropertyHandle::setPosition(const SkPoint& position) {
fTransform->setPosition(position);
}
SkVector TransformPropertyHandle::getScale() const {
return fTransform->getScale();
}
void TransformPropertyHandle::setScale(const SkVector& scale) {
fTransform->setScale(scale);
}
SkScalar TransformPropertyHandle::getRotation() const {
return fTransform->getRotation();
}
void TransformPropertyHandle::setRotation(SkScalar rotation) {
fTransform->setRotation(rotation);
}
SkScalar TransformPropertyHandle::getSkew() const {
return fTransform->getSkew();
}
void TransformPropertyHandle::setSkew(SkScalar skew) {
fTransform->setSkew(skew);
}
SkScalar TransformPropertyHandle::getSkewAxis() const {
return fTransform->getSkewAxis();
}
void TransformPropertyHandle::setSkewAxis(SkScalar sa) {
fTransform->setSkewAxis(sa);
}
SkMatrix TransformPropertyHandle::getTotalMatrix() const {
return fTransform->totalMatrix();
}
void PropertyObserver::onColorProperty(const char[],
const LazyHandle<ColorPropertyHandle>&) {}
void PropertyObserver::onOpacityProperty(const char[],
const LazyHandle<OpacityPropertyHandle>&) {}
void PropertyObserver::onTransformProperty(const char[],
const LazyHandle<TransformPropertyHandle>&) {}
} // namespace skottie

View File

@ -430,26 +430,26 @@ struct GeometryEffectRec {
GeometryEffectAttacherT fAttach;
};
} // namespace
struct AnimationBuilder::AttachShapeContext {
AttachShapeContext(AnimatorScope* ascope,
struct AttachShapeContext {
AttachShapeContext(const AnimationBuilder* abuilder,
AnimatorScope* ascope,
std::vector<sk_sp<sksg::GeometryNode>>* geos,
std::vector<GeometryEffectRec>* effects,
size_t committedAnimators)
: fScope(ascope)
: fBuilder(abuilder)
, fScope(ascope)
, fGeometryStack(geos)
, fGeometryEffectStack(effects)
, fCommittedAnimators(committedAnimators) {}
const AnimationBuilder* fBuilder;
AnimatorScope* fScope;
std::vector<sk_sp<sksg::GeometryNode>>* fGeometryStack;
std::vector<GeometryEffectRec>* fGeometryEffectStack;
size_t fCommittedAnimators;
};
sk_sp<sksg::RenderNode> AnimationBuilder::attachShape(const skjson::ArrayValue* jshape,
AttachShapeContext* ctx) const {
sk_sp<sksg::RenderNode> AttachShape(const skjson::ArrayValue* jshape, AttachShapeContext* ctx) {
if (!jshape)
return nullptr;
@ -504,13 +504,11 @@ sk_sp<sksg::RenderNode> AnimationBuilder::attachShape(const skjson::ArrayValue*
std::vector<sk_sp<sksg::GeometryNode>> geos;
std::vector<sk_sp<sksg::RenderNode >> draws;
for (auto rec = recs.rbegin(); rec != recs.rend(); ++rec) {
const AutoPropertyTracker apt(this, rec->fJson);
switch (rec->fInfo.fShapeType) {
case ShapeType::kGeometry: {
SkASSERT(rec->fInfo.fAttacherIndex < SK_ARRAY_COUNT(gGeometryAttachers));
if (auto geo = gGeometryAttachers[rec->fInfo.fAttacherIndex](rec->fJson,
this,
ctx->fBuilder,
ctx->fScope)) {
geos.push_back(std::move(geo));
}
@ -520,7 +518,7 @@ sk_sp<sksg::RenderNode> AnimationBuilder::attachShape(const skjson::ArrayValue*
SkASSERT(rec->fInfo.fAttacherIndex < SK_ARRAY_COUNT(gGeometryEffectAttachers));
if (!geos.empty()) {
geos = gGeometryEffectAttachers[rec->fInfo.fAttacherIndex](rec->fJson,
this,
ctx->fBuilder,
ctx->fScope,
std::move(geos));
}
@ -531,11 +529,12 @@ sk_sp<sksg::RenderNode> AnimationBuilder::attachShape(const skjson::ArrayValue*
ctx->fGeometryEffectStack->pop_back();
} break;
case ShapeType::kGroup: {
AttachShapeContext groupShapeCtx(ctx->fScope,
AttachShapeContext groupShapeCtx(ctx->fBuilder,
ctx->fScope,
&geos,
ctx->fGeometryEffectStack,
ctx->fCommittedAnimators);
if (auto subgroup = this->attachShape(rec->fJson["it"], &groupShapeCtx)) {
if (auto subgroup = AttachShape(rec->fJson["it"], &groupShapeCtx)) {
draws.push_back(std::move(subgroup));
SkASSERT(groupShapeCtx.fCommittedAnimators >= ctx->fCommittedAnimators);
ctx->fCommittedAnimators = groupShapeCtx.fCommittedAnimators;
@ -544,7 +543,7 @@ sk_sp<sksg::RenderNode> AnimationBuilder::attachShape(const skjson::ArrayValue*
case ShapeType::kPaint: {
SkASSERT(rec->fInfo.fAttacherIndex < SK_ARRAY_COUNT(gPaintAttachers));
auto paint = gPaintAttachers[rec->fInfo.fAttacherIndex](rec->fJson,
this,
ctx->fBuilder,
ctx->fScope);
if (!paint || geos.empty())
break;
@ -554,7 +553,7 @@ sk_sp<sksg::RenderNode> AnimationBuilder::attachShape(const skjson::ArrayValue*
// Apply all pending effects from the stack.
for (auto it = ctx->fGeometryEffectStack->rbegin();
it != ctx->fGeometryEffectStack->rend(); ++it) {
drawGeos = it->fAttach(it->fJson, this, ctx->fScope, std::move(drawGeos));
drawGeos = it->fAttach(it->fJson, ctx->fBuilder, ctx->fScope, std::move(drawGeos));
}
// If we still have multiple geos, reduce using 'merge'.
@ -589,17 +588,16 @@ sk_sp<sksg::RenderNode> AnimationBuilder::attachShape(const skjson::ArrayValue*
sk_sp<sksg::Matrix> shape_matrix;
if (jtransform) {
const AutoPropertyTracker apt(this, *jtransform);
// This is tricky due to the interaction with ctx->fCommittedAnimators: we want any
// animators related to tranform/opacity to be committed => they must be inserted in front
// of the dangling/uncommitted ones.
AnimatorScope local_scope;
if ((shape_matrix = this->attachMatrix(*jtransform, &local_scope, nullptr))) {
if ((shape_matrix = ctx->fBuilder->attachMatrix(*jtransform, &local_scope, nullptr))) {
shape_wrapper = sksg::Transform::Make(std::move(shape_wrapper), shape_matrix);
}
shape_wrapper = this->attachOpacity(*jtransform, &local_scope, std::move(shape_wrapper));
shape_wrapper = ctx->fBuilder->attachOpacity(*jtransform, &local_scope,
std::move(shape_wrapper));
ctx->fScope->insert(ctx->fScope->begin() + ctx->fCommittedAnimators,
std::make_move_iterator(local_scope.begin()),
@ -617,12 +615,14 @@ sk_sp<sksg::RenderNode> AnimationBuilder::attachShape(const skjson::ArrayValue*
return shape_wrapper;
}
} // namespace
sk_sp<sksg::RenderNode> AnimationBuilder::attachShapeLayer(const skjson::ObjectValue& layer,
AnimatorScope* ascope) const {
std::vector<sk_sp<sksg::GeometryNode>> geometryStack;
std::vector<GeometryEffectRec> geometryEffectStack;
AttachShapeContext shapeCtx(ascope, &geometryStack, &geometryEffectStack, ascope->size());
auto shapeNode = this->attachShape(layer["shapes"], &shapeCtx);
AttachShapeContext shapeCtx(this, ascope, &geometryStack, &geometryEffectStack, ascope->size());
auto shapeNode = AttachShape(layer["shapes"], &shapeCtx);
// Trim uncommitted animators: AttachShape consumes effects on the fly, and greedily attaches
// geometries => at the end, we can end up with unused geometries, which are nevertheless alive

View File

@ -5,19 +5,13 @@
* found in the LICENSE file.
*/
#include "SkMatrix.h"
#include "Skottie.h"
#include "SkottieProperty.h"
#include "SkStream.h"
#include "Test.h"
#include <vector>
using namespace skottie;
DEF_TEST(Skottie_OssFuzz8956, reporter) {
static constexpr char json[] =
static constexpr const char json[] =
"{\"v\":\" \",\"fr\":3,\"w\":4,\"h\":3,\"layers\":[{\"ty\": 1, \"sw\": 10, \"sh\": 10,"
" \"sc\":\"#ffffff\", \"ks\":{\"o\":{\"a\": true, \"k\":"
" [{\"t\": 0, \"s\": 0, \"e\": 1, \"i\": {\"x\":[]}}]}}}]}";
@ -25,117 +19,5 @@ DEF_TEST(Skottie_OssFuzz8956, reporter) {
SkMemoryStream stream(json, strlen(json));
// Passes if parsing doesn't crash.
auto animation = Animation::Make(&stream);
}
DEF_TEST(Skottie_Properties, reporter) {
static constexpr char json[] = R"({
"v": "5.2.1",
"w": 100,
"h": 100,
"fr": 1,
"ip": 0,
"op": 1,
"layers": [
{
"ty": 4,
"nm": "layer_0",
"ind": 0,
"ip": 0,
"op": 1,
"ks": {
"o": { "a": 0, "k": 50 }
},
"shapes": [
{
"ty": "el",
"nm": "geometry_0",
"p": { "a": 0, "k": [ 50, 50 ] },
"s": { "a": 0, "k": [ 50, 50 ] }
},
{
"ty": "fl",
"nm": "fill_0",
"c": { "a": 0, "k": [ 1, 0, 0] }
},
{
"ty": "tr",
"nm": "shape_transform_0",
"o": { "a": 0, "k": 100 },
"s": { "a": 0, "k": [ 50, 50 ] }
}
]
}
]
})";
class TestPropertyObserver final : public PropertyObserver {
public:
struct ColorInfo {
const char* node_name;
SkColor color;
};
struct OpacityInfo {
const char* node_name;
float opacity;
};
struct TransformInfo {
const char* node_name;
SkMatrix matrix;
};
void onColorProperty(const char node_name[],
const PropertyObserver::LazyHandle<ColorPropertyHandle>& lh) override {
fColors.push_back({node_name, lh()->getColor()});
}
void onOpacityProperty(const char node_name[],
const PropertyObserver::LazyHandle<OpacityPropertyHandle>& lh) override {
fOpacities.push_back({node_name, lh()->getOpacity()});
}
void onTransformProperty(const char node_name[],
const PropertyObserver::LazyHandle<TransformPropertyHandle>& lh) override {
fTransforms.push_back({node_name, lh()->getTotalMatrix()});
}
const std::vector<ColorInfo>& colors() const { return fColors; }
const std::vector<OpacityInfo>& opacities() const { return fOpacities; }
const std::vector<TransformInfo>& transforms() const { return fTransforms; }
private:
std::vector<ColorInfo> fColors;
std::vector<OpacityInfo> fOpacities;
std::vector<TransformInfo> fTransforms;
};
SkMemoryStream stream(json, strlen(json));
auto observer = sk_make_sp<TestPropertyObserver>();
auto animation = skottie::Animation::Builder()
.setPropertyObserver(observer)
.make(&stream);
REPORTER_ASSERT(reporter, animation);
const auto& colors = observer->colors();
REPORTER_ASSERT(reporter, colors.size() == 1);
REPORTER_ASSERT(reporter, !strcmp(colors[0].node_name, "fill_0"));
REPORTER_ASSERT(reporter, colors[0].color == 0xffff0000);
const auto& opacities = observer->opacities();
REPORTER_ASSERT(reporter, opacities.size() == 2);
REPORTER_ASSERT(reporter, !strcmp(opacities[0].node_name, "shape_transform_0"));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(opacities[0].opacity, 100));
REPORTER_ASSERT(reporter, !strcmp(opacities[1].node_name, "layer_0"));
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(opacities[1].opacity, 50));
const auto& transforms = observer->transforms();
REPORTER_ASSERT(reporter, transforms.size() == 2);
REPORTER_ASSERT(reporter, !strcmp(transforms[0].node_name, "shape_transform_0"));
REPORTER_ASSERT(reporter, transforms[0].matrix == SkMatrix::MakeScale(0.5, 0.5));
REPORTER_ASSERT(reporter, !strcmp(transforms[1].node_name, "layer_0"));
REPORTER_ASSERT(reporter, transforms[1].matrix == SkMatrix::I());
auto animation = skottie::Animation::Make(&stream);
}