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/SkSGPaint.h"
14
15 namespace skottie {
16 namespace internal {
17
18 namespace {
19
20 class FillStrokeAdapter final : public DiscardableAdapterBase<FillStrokeAdapter, sksg::PaintNode> {
21 public:
22 enum class Type { kFill, kStroke };
23
FillStrokeAdapter(const skjson::ObjectValue & jpaint,const AnimationBuilder & abuilder,sk_sp<sksg::PaintNode> paint_node,sk_sp<AnimatablePropertyContainer> gradient_adapter,Type type)24 FillStrokeAdapter(const skjson::ObjectValue& jpaint,
25 const AnimationBuilder& abuilder,
26 sk_sp<sksg::PaintNode> paint_node,
27 sk_sp<AnimatablePropertyContainer> gradient_adapter,
28 Type type)
29 : INHERITED(std::move(paint_node))
30 , fShaderType(gradient_adapter ? ShaderType::kGradient : ShaderType::kColor) {
31
32 this->attachDiscardableAdapter(std::move(gradient_adapter));
33
34 this->bind(abuilder, jpaint["o"], fOpacity);
35
36 this->node()->setAntiAlias(true);
37
38 if (type == Type::kStroke) {
39 this->bind(abuilder, jpaint["w"], fStrokeWidth);
40
41 this->node()->setStyle(SkPaint::kStroke_Style);
42 this->node()->setStrokeMiter(ParseDefault<SkScalar>(jpaint["ml"], 4.0f));
43
44 static constexpr SkPaint::Join gJoins[] = {
45 SkPaint::kMiter_Join,
46 SkPaint::kRound_Join,
47 SkPaint::kBevel_Join,
48 };
49 this->node()->setStrokeJoin(
50 gJoins[std::min<size_t>(ParseDefault<size_t>(jpaint["lj"], 1) - 1,
51 SK_ARRAY_COUNT(gJoins) - 1)]);
52
53 static constexpr SkPaint::Cap gCaps[] = {
54 SkPaint::kButt_Cap,
55 SkPaint::kRound_Cap,
56 SkPaint::kSquare_Cap,
57 };
58 this->node()->setStrokeCap(
59 gCaps[std::min<size_t>(ParseDefault<size_t>(jpaint["lc"], 1) - 1,
60 SK_ARRAY_COUNT(gCaps) - 1)]);
61 }
62
63 if (fShaderType == ShaderType::kColor) {
64 this->bind(abuilder, jpaint["c"], fColor);
65 }
66 }
67
68 private:
onSync()69 void onSync() override {
70 this->node()->setOpacity(fOpacity * 0.01f);
71 this->node()->setStrokeWidth(fStrokeWidth);
72
73 if (fShaderType == ShaderType::kColor) {
74 auto* color_node = static_cast<sksg::Color*>(this->node().get());
75 color_node->setColor(ValueTraits<VectorValue>::As<SkColor>(fColor));
76 }
77 }
78
79 enum class ShaderType { kColor, kGradient };
80
81 const ShaderType fShaderType;
82
83 VectorValue fColor;
84 ScalarValue fOpacity = 100,
85 fStrokeWidth = 1;
86
87 using INHERITED = DiscardableAdapterBase<FillStrokeAdapter, sksg::PaintNode>;
88 };
89
90 } // namespace
91
AttachFill(const skjson::ObjectValue & jpaint,const AnimationBuilder * abuilder,sk_sp<sksg::PaintNode> paint_node,sk_sp<AnimatablePropertyContainer> gradient)92 sk_sp<sksg::PaintNode> ShapeBuilder::AttachFill(const skjson::ObjectValue& jpaint,
93 const AnimationBuilder* abuilder,
94 sk_sp<sksg::PaintNode> paint_node,
95 sk_sp<AnimatablePropertyContainer> gradient) {
96 return abuilder->attachDiscardableAdapter<FillStrokeAdapter, sk_sp<sksg::PaintNode>>
97 (jpaint,
98 *abuilder,
99 std::move(paint_node),
100 std::move(gradient),
101 FillStrokeAdapter::Type::kFill);
102 }
103
AttachStroke(const skjson::ObjectValue & jpaint,const AnimationBuilder * abuilder,sk_sp<sksg::PaintNode> paint_node,sk_sp<AnimatablePropertyContainer> gradient)104 sk_sp<sksg::PaintNode> ShapeBuilder::AttachStroke(const skjson::ObjectValue& jpaint,
105 const AnimationBuilder* abuilder,
106 sk_sp<sksg::PaintNode> paint_node,
107 sk_sp<AnimatablePropertyContainer> gradient) {
108 return abuilder->attachDiscardableAdapter<FillStrokeAdapter, sk_sp<sksg::PaintNode>>
109 (jpaint,
110 *abuilder,
111 std::move(paint_node),
112 std::move(gradient),
113 FillStrokeAdapter::Type::kStroke);
114 }
115
AttachColorFill(const skjson::ObjectValue & jpaint,const AnimationBuilder * abuilder)116 sk_sp<sksg::PaintNode> ShapeBuilder::AttachColorFill(const skjson::ObjectValue& jpaint,
117 const AnimationBuilder* abuilder) {
118 auto color_node = sksg::Color::Make(SK_ColorBLACK);
119 abuilder->dispatchColorProperty(color_node);
120
121 return AttachFill(jpaint, abuilder, std::move(color_node));
122 }
123
AttachColorStroke(const skjson::ObjectValue & jpaint,const AnimationBuilder * abuilder)124 sk_sp<sksg::PaintNode> ShapeBuilder::AttachColorStroke(const skjson::ObjectValue& jpaint,
125 const AnimationBuilder* abuilder) {
126 auto color_node = sksg::Color::Make(SK_ColorBLACK);
127 abuilder->dispatchColorProperty(color_node);
128
129 return AttachStroke(jpaint, abuilder, std::move(color_node));
130 }
131
132 } // namespace internal
133 } // namespace skottie
134