Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 8ec9a60

Browse files
fmalitaSkia Commit-Bot
authored andcommitted
[skottie] Initial repeater support
TBR=reed Bug: skia:8399 Change-Id: Iadaf6b7b363e345d736efd3fd3a5f401963a457b Reviewed-on: https://skia-review.googlesource.com/c/188631 Commit-Queue: Florin Malita <fmalita@chromium.org> Reviewed-by: Florin Malita <fmalita@chromium.org>
1 parent 00dcf66 commit 8ec9a60

File tree

5 files changed

+163
-0
lines changed

5 files changed

+163
-0
lines changed

modules/skottie/src/SkottieAdapter.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,43 @@ void TransformAdapter3D::apply() {
102102
fMatrixNode->setMatrix(this->totalMatrix());
103103
}
104104

105+
RepeaterAdapter::RepeaterAdapter(sk_sp<sksg::RenderNode> repeater_node, Composite composite)
106+
: fRepeaterNode(repeater_node)
107+
, fComposite(composite)
108+
, fRoot(sksg::Group::Make()) {}
109+
110+
RepeaterAdapter::~RepeaterAdapter() = default;
111+
112+
void RepeaterAdapter::apply() {
113+
static constexpr SkScalar kMaxCount = 512;
114+
const auto count = static_cast<size_t>(SkTPin(fCount, 0.0f, kMaxCount) + 0.5f);
115+
116+
const auto& compute_transform = [this] (size_t index) {
117+
const auto t = fOffset + index;
118+
119+
// Position, scale & rotation are "scaled" by index/offset.
120+
SkMatrix m = SkMatrix::MakeTrans(-fAnchorPoint.x(),
121+
-fAnchorPoint.y());
122+
m.postScale(std::pow(fScale.x() * .01f, fOffset),
123+
std::pow(fScale.y() * .01f, fOffset));
124+
m.postRotate(t * fRotation);
125+
m.postTranslate(t * fPosition.x() + fAnchorPoint.x(),
126+
t * fPosition.y() + fAnchorPoint.y());
127+
128+
return m;
129+
};
130+
131+
// TODO: start/end opacity support.
132+
133+
// TODO: we can avoid rebuilding all the fragments in most cases.
134+
fRoot->clear();
135+
for (size_t i = 0; i < count; ++i) {
136+
const auto insert_index = (fComposite == Composite::kAbove) ? i : count - i - 1;
137+
fRoot->addChild(sksg::TransformEffect::Make(fRepeaterNode,
138+
compute_transform(insert_index)));
139+
}
140+
}
141+
105142
PolyStarAdapter::PolyStarAdapter(sk_sp<sksg::Path> wrapped_node, Type t)
106143
: fPathNode(std::move(wrapped_node))
107144
, fType(t) {}

modules/skottie/src/SkottieAdapter.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@ template <typename>
2424
class Matrix;
2525
class Path;
2626
class RadialGradient;
27+
class RenderNode;
2728
class RRect;
2829
class TextBlob;
30+
class TransformEffect;
2931
class TrimEffect;
3032

3133
};
@@ -133,6 +135,36 @@ class TransformAdapter3D final : public SkNVRefCnt<TransformAdapter3D> {
133135
sk_sp<sksg::Matrix<SkMatrix44>> fMatrixNode;
134136
};
135137

138+
class RepeaterAdapter final : public SkNVRefCnt<RepeaterAdapter> {
139+
public:
140+
enum class Composite { kAbove, kBelow };
141+
142+
RepeaterAdapter(sk_sp<sksg::RenderNode>, Composite);
143+
~RepeaterAdapter();
144+
145+
// Repeater props
146+
ADAPTER_PROPERTY(Count , SkScalar, 0)
147+
ADAPTER_PROPERTY(Offset , SkScalar, 0)
148+
149+
// Transform props
150+
ADAPTER_PROPERTY(AnchorPoint , SkPoint , SkPoint::Make(0, 0))
151+
ADAPTER_PROPERTY(Position , SkPoint , SkPoint::Make(0, 0))
152+
ADAPTER_PROPERTY(Scale , SkVector, SkPoint::Make(100, 100))
153+
ADAPTER_PROPERTY(Rotation , SkScalar, 0)
154+
ADAPTER_PROPERTY(StartOpacity, SkScalar, 100)
155+
ADAPTER_PROPERTY(EndOpacity , SkScalar, 100)
156+
157+
const sk_sp<sksg::Group>& root() const { return fRoot; }
158+
159+
private:
160+
void apply();
161+
162+
const sk_sp<sksg::RenderNode> fRepeaterNode;
163+
const Composite fComposite;
164+
165+
sk_sp<sksg::Group> fRoot;
166+
};
167+
136168
class GradientAdapter : public SkRefCnt {
137169
public:
138170
ADAPTER_PROPERTY(StartPoint, SkPoint , SkPoint::Make(0, 0) )

modules/skottie/src/SkottieShapeLayer.cpp

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,71 @@ std::vector<sk_sp<sksg::GeometryNode>> AttachRoundGeometryEffect(
357357
return rounded;
358358
}
359359

360+
std::vector<sk_sp<sksg::RenderNode>> AttachRepeaterDrawEffect(
361+
const skjson::ObjectValue& jrepeater,
362+
const AnimationBuilder* abuilder,
363+
AnimatorScope* ascope,
364+
std::vector<sk_sp<sksg::RenderNode>>&& draws) {
365+
366+
std::vector<sk_sp<sksg::RenderNode>> repeater_draws;
367+
368+
if (const skjson::ObjectValue* jtransform = jrepeater["tr"]) {
369+
sk_sp<sksg::RenderNode> repeater_node;
370+
if (draws.size() > 1) {
371+
repeater_node = sksg::Group::Make(std::move(draws));
372+
} else {
373+
repeater_node = std::move(draws[0]);
374+
}
375+
376+
const auto repeater_composite = (ParseDefault(jrepeater["m"], 1) == 1)
377+
? RepeaterAdapter::Composite::kAbove
378+
: RepeaterAdapter::Composite::kBelow;
379+
380+
auto adapter = sk_make_sp<RepeaterAdapter>(std::move(repeater_node),
381+
repeater_composite);
382+
383+
abuilder->bindProperty<ScalarValue>(jrepeater["c"], ascope,
384+
[adapter](const ScalarValue& c) {
385+
adapter->setCount(c);
386+
});
387+
abuilder->bindProperty<ScalarValue>(jrepeater["o"], ascope,
388+
[adapter](const ScalarValue& o) {
389+
adapter->setOffset(o);
390+
});
391+
abuilder->bindProperty<VectorValue>((*jtransform)["a"], ascope,
392+
[adapter](const VectorValue& a) {
393+
adapter->setAnchorPoint(ValueTraits<VectorValue>::As<SkPoint>(a));
394+
});
395+
abuilder->bindProperty<VectorValue>((*jtransform)["p"], ascope,
396+
[adapter](const VectorValue& p) {
397+
adapter->setPosition(ValueTraits<VectorValue>::As<SkPoint>(p));
398+
});
399+
abuilder->bindProperty<VectorValue>((*jtransform)["s"], ascope,
400+
[adapter](const VectorValue& s) {
401+
adapter->setScale(ValueTraits<VectorValue>::As<SkVector>(s));
402+
});
403+
abuilder->bindProperty<ScalarValue>((*jtransform)["r"], ascope,
404+
[adapter](const ScalarValue& r) {
405+
adapter->setRotation(r);
406+
});
407+
abuilder->bindProperty<ScalarValue>((*jtransform)["so"], ascope,
408+
[adapter](const ScalarValue& so) {
409+
adapter->setStartOpacity(so);
410+
});
411+
abuilder->bindProperty<ScalarValue>((*jtransform)["eo"], ascope,
412+
[adapter](const ScalarValue& eo) {
413+
adapter->setEndOpacity(eo);
414+
});
415+
416+
repeater_draws.reserve(1);
417+
repeater_draws.push_back(adapter->root());
418+
} else {
419+
repeater_draws = std::move(draws);
420+
}
421+
422+
return repeater_draws;
423+
}
424+
360425
using GeometryAttacherT = sk_sp<sksg::GeometryNode> (*)(const skjson::ObjectValue&,
361426
const AnimationBuilder*, AnimatorScope*);
362427
static constexpr GeometryAttacherT gGeometryAttachers[] = {
@@ -385,12 +450,22 @@ static constexpr GeometryEffectAttacherT gGeometryEffectAttachers[] = {
385450
AttachRoundGeometryEffect,
386451
};
387452

453+
using DrawEffectAttacherT =
454+
std::vector<sk_sp<sksg::RenderNode>> (*)(const skjson::ObjectValue&,
455+
const AnimationBuilder*, AnimatorScope*,
456+
std::vector<sk_sp<sksg::RenderNode>>&&);
457+
458+
static constexpr DrawEffectAttacherT gDrawEffectAttachers[] = {
459+
AttachRepeaterDrawEffect,
460+
};
461+
388462
enum class ShapeType {
389463
kGeometry,
390464
kGeometryEffect,
391465
kPaint,
392466
kGroup,
393467
kTransform,
468+
kDrawEffect,
394469
};
395470

396471
struct ShapeInfo {
@@ -409,6 +484,7 @@ const ShapeInfo* FindShapeInfo(const skjson::ObjectValue& jshape) {
409484
{ "mm", ShapeType::kGeometryEffect, 0 }, // merge -> AttachMergeGeometryEffect
410485
{ "rc", ShapeType::kGeometry , 1 }, // rrect -> AttachRRectGeometry
411486
{ "rd", ShapeType::kGeometryEffect, 2 }, // round -> AttachRoundGeometryEffect
487+
{ "rp", ShapeType::kDrawEffect , 0 }, // repeater -> AttachRepeaterDrawEffect
412488
{ "sh", ShapeType::kGeometry , 0 }, // shape -> AttachPathGeometry
413489
{ "sr", ShapeType::kGeometry , 3 }, // polystar -> AttachPolyStarGeometry
414490
{ "st", ShapeType::kPaint , 1 }, // stroke -> AttachColorStroke
@@ -574,6 +650,16 @@ sk_sp<sksg::RenderNode> AnimationBuilder::attachShape(const skjson::ArrayValue*
574650
draws.push_back(sksg::Draw::Make(std::move(geo), std::move(paint)));
575651
ctx->fCommittedAnimators = ctx->fScope->size();
576652
} break;
653+
case ShapeType::kDrawEffect: {
654+
SkASSERT(rec->fInfo.fAttacherIndex < SK_ARRAY_COUNT(gDrawEffectAttachers));
655+
if (!draws.empty()) {
656+
draws = gDrawEffectAttachers[rec->fInfo.fAttacherIndex](rec->fJson,
657+
this,
658+
ctx->fScope,
659+
std::move(draws));
660+
ctx->fCommittedAnimators = ctx->fScope->size();
661+
}
662+
} break;
577663
default:
578664
break;
579665
}

modules/sksg/include/SkSGGroup.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class Group : public RenderNode {
3232

3333
size_t size() const { return fChildren.size(); }
3434
bool empty() const { return fChildren.empty(); }
35+
void clear();
3536

3637
protected:
3738
explicit Group(std::vector<sk_sp<RenderNode>>);

modules/sksg/src/SkSGGroup.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ Group::~Group() {
2424
}
2525
}
2626

27+
void Group::clear() {
28+
for (const auto& child : fChildren) {
29+
this->unobserveInval(child);
30+
}
31+
fChildren.clear();
32+
}
33+
2734
void Group::addChild(sk_sp<RenderNode> node) {
2835
// should we allow duplicates?
2936
for (const auto& child : fChildren) {

0 commit comments

Comments
 (0)