xref: /aosp_15_r20/external/skia/modules/skottie/src/layers/shapelayer/Repeater.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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 
8 #include "include/core/SkCanvas.h"
9 #include "include/core/SkM44.h"
10 #include "include/core/SkMatrix.h"
11 #include "include/core/SkRect.h"
12 #include "include/core/SkRefCnt.h"
13 #include "include/core/SkScalar.h"
14 #include "include/private/base/SkTPin.h"
15 #include "modules/skottie/src/Adapter.h"
16 #include "modules/skottie/src/SkottieJson.h"
17 #include "modules/skottie/src/SkottiePriv.h"
18 #include "modules/skottie/src/SkottieValue.h"
19 #include "modules/skottie/src/layers/shapelayer/ShapeLayer.h"
20 #include "modules/sksg/include/SkSGNode.h"
21 #include "modules/sksg/include/SkSGRenderNode.h"
22 #include "src/utils/SkJSON.h"
23 
24 #include <algorithm>
25 #include <cmath>
26 #include <cstddef>
27 #include <utility>
28 #include <vector>
29 
30 struct SkPoint;
31 
32 namespace sksg {
33 class InvalidationController;
34 }
35 
36 namespace skottie {
37 namespace internal {
38 
39 namespace  {
40 
41 class RepeaterRenderNode final : public sksg::CustomRenderNode {
42 public:
43     enum class CompositeMode { kBelow, kAbove };
44 
RepeaterRenderNode(std::vector<sk_sp<RenderNode>> && children,CompositeMode mode)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 
58 private:
onNodeAt(const SkPoint &) const59     const RenderNode* onNodeAt(const SkPoint&) const override { return nullptr; } // no hit-testing
60 
instanceTransform(size_t i) const61     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 
onRevalidate(sksg::InvalidationController * ic,const SkMatrix & ctm)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 
80         auto bounds = SkRect::MakeEmpty();
81         for (size_t i = 0; i < fCount; ++i) {
82             bounds.join(this->instanceTransform(i).mapRect(fChildrenBounds));
83         }
84 
85         return bounds;
86     }
87 
onRender(SkCanvas * canvas,const RenderContext * ctx) const88     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 
129     using INHERITED = sksg::CustomRenderNode;
130 };
131 
132 class RepeaterAdapter final : public DiscardableAdapterBase<RepeaterAdapter, RepeaterRenderNode> {
133 public:
RepeaterAdapter(const skjson::ObjectValue & jrepeater,const skjson::ObjectValue & jtransform,const AnimationBuilder & abuilder,std::vector<sk_sp<sksg::RenderNode>> && draws)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 
154 private:
onSync()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
168     ScalarValue fCount  = 0,
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 
AttachRepeaterDrawEffect(const skjson::ObjectValue & jrepeater,const AnimationBuilder * abuilder,std::vector<sk_sp<sksg::RenderNode>> && draws)184 std::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
209