Flutter Engine
The Flutter Engine
Repeater.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2020 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
11#include "include/core/SkRect.h"
22#include "src/utils/SkJSON.h"
23
24#include <algorithm>
25#include <cmath>
26#include <cstddef>
27#include <utility>
28#include <vector>
29
30struct SkPoint;
31
32namespace sksg {
33class InvalidationController;
34}
35
36namespace skottie {
37namespace internal {
38
39namespace {
40
41class RepeaterRenderNode final : public sksg::CustomRenderNode {
42public:
43 enum class CompositeMode { kBelow, kAbove };
44
45 RepeaterRenderNode(std::vector<sk_sp<RenderNode>>&& children, CompositeMode mode)
46 : INHERITED(std::move(children))
47 , fMode(mode) {}
48
49 SG_ATTRIBUTE(Count , size_t, fCount )
50 SG_ATTRIBUTE(Offset , float , fOffset )
51 SG_ATTRIBUTE(AnchorPoint , SkV2 , fAnchorPoint )
52 SG_ATTRIBUTE(Position , SkV2 , fPosition )
53 SG_ATTRIBUTE(Scale , SkV2 , fScale )
54 SG_ATTRIBUTE(Rotation , float , fRotation )
55 SG_ATTRIBUTE(StartOpacity, float , fStartOpacity)
56 SG_ATTRIBUTE(EndOpacity , float , fEndOpacity )
57
58private:
59 const RenderNode* onNodeAt(const SkPoint&) const override { return nullptr; } // no hit-testing
60
61 SkMatrix instanceTransform(size_t i) const {
62 const auto t = fOffset + i;
63
64 // Position, scale & rotation are "scaled" by index/offset.
65 return SkMatrix::Translate(t * fPosition.x + fAnchorPoint.x,
66 t * fPosition.y + fAnchorPoint.y)
67 * SkMatrix::RotateDeg(t * fRotation)
68 * SkMatrix::Scale(std::pow(fScale.x, t),
69 std::pow(fScale.y, t))
70 * SkMatrix::Translate(-fAnchorPoint.x,
71 -fAnchorPoint.y);
72 }
73
74 SkRect onRevalidate(sksg::InvalidationController* ic, const SkMatrix& ctm) override {
75 fChildrenBounds = SkRect::MakeEmpty();
76 for (const auto& child : this->children()) {
77 fChildrenBounds.join(child->revalidate(ic, ctm));
78 }
79
81 for (size_t i = 0; i < fCount; ++i) {
82 bounds.join(this->instanceTransform(i).mapRect(fChildrenBounds));
83 }
84
85 return bounds;
86 }
87
88 void onRender(SkCanvas* canvas, const RenderContext* ctx) const override {
89 // To cover the full opacity range, the denominator below should be (fCount - 1).
90 // Interstingly, that's not what AE does. Off-by-one bug?
91 const auto dOpacity = fCount > 1 ? (fEndOpacity - fStartOpacity) / fCount : 0.0f;
92
93 for (size_t i = 0; i < fCount; ++i) {
94 const auto render_index = fMode == CompositeMode::kAbove ? i : fCount - i - 1;
95 const auto opacity = fStartOpacity + dOpacity * render_index;
96
97 if (opacity <= 0) {
98 continue;
99 }
100
101 SkAutoCanvasRestore acr(canvas, true);
102 canvas->concat(this->instanceTransform(render_index));
103
104 const auto& children = this->children();
105 const auto local_ctx = ScopedRenderContext(canvas, ctx)
106 .modulateOpacity(opacity)
107 .setIsolation(fChildrenBounds,
108 canvas->getTotalMatrix(),
109 children.size() > 1);
110 for (const auto& child : children) {
111 child->render(canvas, local_ctx);
112 }
113 }
114 }
115
116 const CompositeMode fMode;
117
118 SkRect fChildrenBounds = SkRect::MakeEmpty(); // cached
119
120 size_t fCount = 0;
121 float fOffset = 0,
122 fRotation = 0,
123 fStartOpacity = 1,
124 fEndOpacity = 1;
125 SkV2 fAnchorPoint = {0,0},
126 fPosition = {0,0},
127 fScale = {1,1};
128
130};
131
132class RepeaterAdapter final : public DiscardableAdapterBase<RepeaterAdapter, RepeaterRenderNode> {
133public:
134 RepeaterAdapter(const skjson::ObjectValue& jrepeater,
135 const skjson::ObjectValue& jtransform,
136 const AnimationBuilder& abuilder,
137 std::vector<sk_sp<sksg::RenderNode>>&& draws)
138 : INHERITED(sk_make_sp<RepeaterRenderNode>(std::move(draws),
139 (ParseDefault(jrepeater["m"], 1) == 1)
140 ? RepeaterRenderNode::CompositeMode::kBelow
141 : RepeaterRenderNode::CompositeMode::kAbove))
142 {
143 this->bind(abuilder, jrepeater["c"], fCount);
144 this->bind(abuilder, jrepeater["o"], fOffset);
145
146 this->bind(abuilder, jtransform["a" ], fAnchorPoint);
147 this->bind(abuilder, jtransform["p" ], fPosition);
148 this->bind(abuilder, jtransform["s" ], fScale);
149 this->bind(abuilder, jtransform["r" ], fRotation);
150 this->bind(abuilder, jtransform["so"], fStartOpacity);
151 this->bind(abuilder, jtransform["eo"], fEndOpacity);
152 }
153
154private:
155 void onSync() override {
156 static constexpr SkScalar kMaxCount = 1024;
157 this->node()->setCount(static_cast<size_t>(SkTPin(fCount, 0.0f, kMaxCount) + 0.5f));
158 this->node()->setOffset(fOffset);
159 this->node()->setAnchorPoint(fAnchorPoint);
160 this->node()->setPosition(fPosition);
161 this->node()->setScale(fScale * 0.01f);
162 this->node()->setRotation(fRotation);
163 this->node()->setStartOpacity(SkTPin(fStartOpacity * 0.01f, 0.0f, 1.0f));
164 this->node()->setEndOpacity (SkTPin(fEndOpacity * 0.01f, 0.0f, 1.0f));
165 }
166
167 // Repeater props
169 fOffset = 0;
170
171 // Transform props
172 Vec2Value fAnchorPoint = { 0, 0 },
173 fPosition = { 0, 0 },
174 fScale = { 100, 100 };
175 ScalarValue fRotation = 0,
176 fStartOpacity = 100,
177 fEndOpacity = 100;
178
179 using INHERITED = DiscardableAdapterBase<RepeaterAdapter, RepeaterRenderNode>;
180};
181
182} // namespace
183
184std::vector<sk_sp<sksg::RenderNode>> ShapeBuilder::AttachRepeaterDrawEffect(
185 const skjson::ObjectValue& jrepeater,
186 const AnimationBuilder* abuilder,
187 std::vector<sk_sp<sksg::RenderNode>>&& draws) {
188 std::vector<sk_sp<sksg::RenderNode>> repeater_draws;
189
190 if (const skjson::ObjectValue* jtransform = jrepeater["tr"]) {
191 // input draws are in top->bottom order - reverse for paint order
192 std::reverse(draws.begin(), draws.end());
193
194 repeater_draws.reserve(1);
195 repeater_draws.push_back(
196 abuilder->attachDiscardableAdapter<RepeaterAdapter>(jrepeater,
197 *jtransform,
198 *abuilder,
199 std::move(draws)));
200 } else {
201 repeater_draws = std::move(draws);
202 }
203
204 return repeater_draws;
205}
206
207} // namespace internal
208} // namespace skottie
#define INHERITED(method,...)
Definition: SkRecorder.cpp:128
sk_sp< T > sk_make_sp(Args &&... args)
Definition: SkRefCnt.h:371
#define SG_ATTRIBUTE(attr_name, attr_type, attr_container)
Definition: SkSGNode.h:100
static constexpr const T & SkTPin(const T &x, const T &lo, const T &hi)
Definition: SkTPin.h:19
SkMatrix getTotalMatrix() const
Definition: SkCanvas.cpp:1629
void concat(const SkMatrix &matrix)
Definition: SkCanvas.cpp:1318
static SkMatrix Scale(SkScalar sx, SkScalar sy)
Definition: SkMatrix.h:75
static SkMatrix RotateDeg(SkScalar deg)
Definition: SkMatrix.h:104
static SkMatrix Translate(SkScalar dx, SkScalar dy)
Definition: SkMatrix.h:91
void attachDiscardableAdapter(sk_sp< T > adapter) const
Definition: SkottiePriv.h:139
static std::vector< sk_sp< sksg::RenderNode > > AttachRepeaterDrawEffect(const skjson::ObjectValue &, const AnimationBuilder *, std::vector< sk_sp< sksg::RenderNode > > &&)
Definition: Repeater.cpp:184
float SkScalar
Definition: extension.cpp:12
Definition: dart.idl:629
Optional< SkRect > bounds
Definition: SkRecords.h:189
static constexpr size_t kMaxCount
Definition: dart_vm.cc:287
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive mode
Definition: switches.h:228
SkScalar ScalarValue
Definition: SkottieValue.h:22
SkV2 Vec2Value
Definition: SkottieValue.h:23
T ParseDefault(const skjson::Value &v, const T &defaultValue)
Definition: SkottieJson.h:23
Definition: Skottie.h:32
Definition: ref_ptr.h:256
static constexpr SkRect MakeEmpty()
Definition: SkRect.h:595
void join(const SkRect &r)
Definition: SkRect.cpp:126
Definition: SkM44.h:19
float x
Definition: SkM44.h:20
float y
Definition: SkM44.h:20
SkBlendMode fMode
Definition: xfermodes.cpp:52