• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "modules/skottie/src/Adapter.h"
9 #include "modules/skottie/src/SkottieJson.h"
10 #include "modules/skottie/src/SkottiePriv.h"
11 #include "modules/skottie/src/SkottieValue.h"
12 #include "modules/skottie/src/layers/shapelayer/ShapeLayer.h"
13 #include "modules/sksg/include/SkSGGeometryEffect.h"
14 #include "modules/sksg/include/SkSGPaint.h"
15 
16 namespace skottie {
17 namespace internal {
18 
19 namespace  {
20 
21 class FillStrokeAdapter final : public DiscardableAdapterBase<FillStrokeAdapter, sksg::PaintNode> {
22 public:
23     enum class Type { kFill, kStroke };
24 
FillStrokeAdapter(const skjson::ObjectValue & jpaint,const AnimationBuilder & abuilder,sk_sp<sksg::PaintNode> paint_node,sk_sp<AnimatablePropertyContainer> gradient_adapter,Type type)25     FillStrokeAdapter(const skjson::ObjectValue& jpaint,
26                       const AnimationBuilder& abuilder,
27                       sk_sp<sksg::PaintNode> paint_node,
28                       sk_sp<AnimatablePropertyContainer> gradient_adapter,
29                       Type type)
30         : INHERITED(std::move(paint_node))
31         , fShaderType(gradient_adapter ? ShaderType::kGradient : ShaderType::kColor) {
32 
33         this->attachDiscardableAdapter(std::move(gradient_adapter));
34 
35         this->bind(abuilder, jpaint["o"], fOpacity);
36 
37         this->node()->setAntiAlias(true);
38 
39         if (type == Type::kStroke) {
40             this->bind(abuilder, jpaint["w"], fStrokeWidth);
41 
42             this->node()->setStyle(SkPaint::kStroke_Style);
43             this->node()->setStrokeMiter(ParseDefault<SkScalar>(jpaint["ml"], 4.0f));
44 
45             static constexpr SkPaint::Join gJoins[] = {
46                 SkPaint::kMiter_Join,
47                 SkPaint::kRound_Join,
48                 SkPaint::kBevel_Join,
49             };
50             this->node()->setStrokeJoin(
51                         gJoins[std::min<size_t>(ParseDefault<size_t>(jpaint["lj"], 1) - 1,
52                                               SK_ARRAY_COUNT(gJoins) - 1)]);
53 
54             static constexpr SkPaint::Cap gCaps[] = {
55                 SkPaint::kButt_Cap,
56                 SkPaint::kRound_Cap,
57                 SkPaint::kSquare_Cap,
58             };
59             this->node()->setStrokeCap(
60                         gCaps[std::min<size_t>(ParseDefault<size_t>(jpaint["lc"], 1) - 1,
61                                              SK_ARRAY_COUNT(gCaps) - 1)]);
62         }
63 
64         if (fShaderType == ShaderType::kColor) {
65             this->bind(abuilder, jpaint["c"], fColor);
66         }
67     }
68 
69 private:
onSync()70     void onSync() override {
71         this->node()->setOpacity(fOpacity * 0.01f);
72         this->node()->setStrokeWidth(fStrokeWidth);
73 
74         if (fShaderType == ShaderType::kColor) {
75             auto* color_node = static_cast<sksg::Color*>(this->node().get());
76             color_node->setColor(fColor);
77         }
78     }
79 
80     enum class ShaderType { kColor, kGradient };
81 
82     const ShaderType fShaderType;
83 
84     VectorValue      fColor;
85     ScalarValue      fOpacity     = 100,
86                      fStrokeWidth = 1;
87 
88     using INHERITED = DiscardableAdapterBase<FillStrokeAdapter, sksg::PaintNode>;
89 };
90 
91 class DashAdapter final : public DiscardableAdapterBase<DashAdapter, sksg::DashEffect> {
92 public:
DashAdapter(const skjson::ArrayValue & jdash,const AnimationBuilder & abuilder,sk_sp<sksg::GeometryNode> geo)93     DashAdapter(const skjson::ArrayValue& jdash,
94                 const AnimationBuilder& abuilder,
95                 sk_sp<sksg::GeometryNode> geo)
96         : INHERITED(sksg::DashEffect::Make(std::move(geo))) {
97         SkASSERT(jdash.size() > 1);
98 
99         // The dash is encoded as an arbitrary number of intervals (alternating dash/gap),
100         // plus a single trailing offset.  Each value can be animated independently.
101         const auto interval_count = jdash.size() - 1;
102         fIntervals.resize(interval_count, 0);
103 
104         for (size_t i = 0; i < jdash.size(); ++i) {
105             if (const skjson::ObjectValue* jint = jdash[i]) {
106                 auto* target = i < interval_count
107                         ? &fIntervals[i]
108                         : &fOffset;
109                 this->bind(abuilder, (*jint)["v"], target);
110             }
111         }
112     }
113 
114 private:
onSync()115     void onSync() override {
116         this->node()->setPhase(fOffset);
117         this->node()->setIntervals(fIntervals);
118     }
119 
120     std::vector<ScalarValue> fIntervals;
121     ScalarValue              fOffset = 0;
122 
123     using INHERITED = DiscardableAdapterBase<DashAdapter, sksg::DashEffect>;
124 };
125 
126 } // namespace
127 
AttachFill(const skjson::ObjectValue & jpaint,const AnimationBuilder * abuilder,sk_sp<sksg::PaintNode> paint_node,sk_sp<AnimatablePropertyContainer> gradient)128 sk_sp<sksg::PaintNode> ShapeBuilder::AttachFill(const skjson::ObjectValue& jpaint,
129                                                 const AnimationBuilder* abuilder,
130                                                 sk_sp<sksg::PaintNode> paint_node,
131                                                 sk_sp<AnimatablePropertyContainer> gradient) {
132     return abuilder->attachDiscardableAdapter<FillStrokeAdapter>
133             (jpaint,
134              *abuilder,
135              std::move(paint_node),
136              std::move(gradient),
137              FillStrokeAdapter::Type::kFill);
138 }
139 
AttachStroke(const skjson::ObjectValue & jpaint,const AnimationBuilder * abuilder,sk_sp<sksg::PaintNode> paint_node,sk_sp<AnimatablePropertyContainer> gradient)140 sk_sp<sksg::PaintNode> ShapeBuilder::AttachStroke(const skjson::ObjectValue& jpaint,
141                                                   const AnimationBuilder* abuilder,
142                                                   sk_sp<sksg::PaintNode> paint_node,
143                                                   sk_sp<AnimatablePropertyContainer> gradient) {
144     return abuilder->attachDiscardableAdapter<FillStrokeAdapter>
145             (jpaint,
146              *abuilder,
147              std::move(paint_node),
148              std::move(gradient),
149              FillStrokeAdapter::Type::kStroke);
150 }
151 
AttachColorFill(const skjson::ObjectValue & jpaint,const AnimationBuilder * abuilder)152 sk_sp<sksg::PaintNode> ShapeBuilder::AttachColorFill(const skjson::ObjectValue& jpaint,
153                                                      const AnimationBuilder* abuilder) {
154     auto color_node = sksg::Color::Make(SK_ColorBLACK);
155     abuilder->dispatchColorProperty(color_node);
156 
157     return AttachFill(jpaint, abuilder, std::move(color_node));
158 }
159 
AttachColorStroke(const skjson::ObjectValue & jpaint,const AnimationBuilder * abuilder)160 sk_sp<sksg::PaintNode> ShapeBuilder::AttachColorStroke(const skjson::ObjectValue& jpaint,
161                                                        const AnimationBuilder* abuilder) {
162     auto color_node = sksg::Color::Make(SK_ColorBLACK);
163     abuilder->dispatchColorProperty(color_node);
164 
165     return AttachStroke(jpaint, abuilder, std::move(color_node));
166 }
167 
AdjustStrokeGeometry(const skjson::ObjectValue & jstroke,const AnimationBuilder * abuilder,std::vector<sk_sp<sksg::GeometryNode>> && geos)168 std::vector<sk_sp<sksg::GeometryNode>> ShapeBuilder::AdjustStrokeGeometry(
169         const skjson::ObjectValue& jstroke,
170         const AnimationBuilder* abuilder,
171         std::vector<sk_sp<sksg::GeometryNode>>&& geos) {
172 
173     const skjson::ArrayValue* jdash = jstroke["d"];
174     if (jdash && jdash->size() > 1) {
175         for (size_t i = 0; i < geos.size(); ++i) {
176             geos[i] = abuilder->attachDiscardableAdapter<DashAdapter>(
177                           *jdash, *abuilder, std::move(geos[i]));
178         }
179     }
180 
181     return std::move(geos);
182 }
183 
184 } // namespace internal
185 } // namespace skottie
186