1 /*
2 * Copyright 2017 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 "SkottieProperties.h"
9
10 #include "SkColor.h"
11 #include "SkJSONCPP.h"
12 #include "SkPath.h"
13 #include "SkSGColor.h"
14 #include "SkSGGradient.h"
15 #include "SkSGPath.h"
16 #include "SkSGRect.h"
17 #include "SkSGTransform.h"
18
19 #include <cmath>
20
21 namespace skottie {
22
23 namespace {
24
VecToColor(const float * v,size_t size)25 SkColor VecToColor(const float* v, size_t size) {
26 // best effort to turn this into a color
27 const auto r = size > 0 ? v[0] : 0,
28 g = size > 1 ? v[1] : 0,
29 b = size > 2 ? v[2] : 0,
30 a = size > 3 ? v[3] : 1;
31
32 return SkColorSetARGB(SkTPin<SkScalar>(a, 0, 1) * 255,
33 SkTPin<SkScalar>(r, 0, 1) * 255,
34 SkTPin<SkScalar>(g, 0, 1) * 255,
35 SkTPin<SkScalar>(b, 0, 1) * 255);
36 }
37
38 } // namespace
39
40 template <>
Cardinality(const ScalarValue &)41 size_t ValueTraits<ScalarValue>::Cardinality(const ScalarValue&) {
42 return 1;
43 }
44
45 template <>
46 template <>
As(const ScalarValue & v)47 SkScalar ValueTraits<ScalarValue>::As<SkScalar>(const ScalarValue& v) {
48 return v;
49 }
50
51 template <>
Cardinality(const VectorValue & vec)52 size_t ValueTraits<VectorValue>::Cardinality(const VectorValue& vec) {
53 return vec.size();
54 }
55
56 template <>
57 template <>
As(const VectorValue & vec)58 SkColor ValueTraits<VectorValue>::As<SkColor>(const VectorValue& vec) {
59 return VecToColor(vec.data(), vec.size());
60 }
61
62 template <>
63 template <>
As(const VectorValue & vec)64 SkPoint ValueTraits<VectorValue>::As<SkPoint>(const VectorValue& vec) {
65 // best effort to turn this into a point
66 const auto x = vec.size() > 0 ? vec[0] : 0,
67 y = vec.size() > 1 ? vec[1] : 0;
68 return SkPoint::Make(x, y);
69 }
70
71 template <>
72 template <>
As(const VectorValue & vec)73 SkSize ValueTraits<VectorValue>::As<SkSize>(const VectorValue& vec) {
74 const auto pt = ValueTraits::As<SkPoint>(vec);
75 return SkSize::Make(pt.x(), pt.y());
76 }
77
78 template <>
Cardinality(const ShapeValue & path)79 size_t ValueTraits<ShapeValue>::Cardinality(const ShapeValue& path) {
80 return SkTo<size_t>(path.countVerbs());
81 }
82
83 template <>
84 template <>
As(const ShapeValue & path)85 SkPath ValueTraits<ShapeValue>::As<SkPath>(const ShapeValue& path) {
86 return path;
87 }
88
CompositeRRect(sk_sp<sksg::RRect> wrapped_node)89 CompositeRRect::CompositeRRect(sk_sp<sksg::RRect> wrapped_node)
90 : fRRectNode(std::move(wrapped_node)) {}
91
apply()92 void CompositeRRect::apply() {
93 // BM "position" == "center position"
94 auto rr = SkRRect::MakeRectXY(SkRect::MakeXYWH(fPosition.x() - fSize.width() / 2,
95 fPosition.y() - fSize.height() / 2,
96 fSize.width(), fSize.height()),
97 fRadius.width(),
98 fRadius.height());
99 fRRectNode->setRRect(rr);
100 }
101
CompositeTransform(sk_sp<sksg::Matrix> matrix)102 CompositeTransform::CompositeTransform(sk_sp<sksg::Matrix> matrix)
103 : fMatrixNode(std::move(matrix)) {}
104
apply()105 void CompositeTransform::apply() {
106 SkMatrix t = SkMatrix::MakeTrans(-fAnchorPoint.x(), -fAnchorPoint.y());
107
108 t.postScale(fScale.x() / 100, fScale.y() / 100); // 100% based
109 t.postRotate(fRotation);
110 t.postTranslate(fPosition.x(), fPosition.y());
111 // TODO: skew
112
113 fMatrixNode->setMatrix(t);
114 }
115
CompositePolyStar(sk_sp<sksg::Path> wrapped_node,Type t)116 CompositePolyStar::CompositePolyStar(sk_sp<sksg::Path> wrapped_node, Type t)
117 : fPathNode(std::move(wrapped_node))
118 , fType(t) {}
119
apply()120 void CompositePolyStar::apply() {
121 const auto count = SkScalarTruncToInt(fPointCount);
122 const auto arc = SK_ScalarPI * 2 / count;
123
124 const auto pt_on_circle = [](const SkPoint& c, SkScalar r, SkScalar a) {
125 return SkPoint::Make(c.x() + r * std::cos(a),
126 c.y() + r * std::sin(a));
127 };
128
129 // TODO: inner/outer "roundness"?
130
131 SkPath poly;
132
133 auto angle = SkDegreesToRadians(fRotation);
134 poly.moveTo(pt_on_circle(fPosition, fOuterRadius, angle));
135
136 for (int i = 0; i < count; ++i) {
137 if (fType == Type::kStar) {
138 poly.lineTo(pt_on_circle(fPosition, fInnerRadius, angle + arc * 0.5f));
139 }
140 angle += arc;
141 poly.lineTo(pt_on_circle(fPosition, fOuterRadius, angle));
142 }
143
144 poly.close();
145 fPathNode->setPath(poly);
146 }
147
CompositeGradient(sk_sp<sksg::Gradient> grad,size_t stopCount)148 CompositeGradient::CompositeGradient(sk_sp<sksg::Gradient> grad, size_t stopCount)
149 : fGradient(std::move(grad))
150 , fStopCount(stopCount) {}
151
apply()152 void CompositeGradient::apply() {
153 this->onApply();
154
155 // |fColorStops| holds |fStopCount| x [ pos, r, g, g ] + ? x [ pos, alpha ]
156
157 if (fColorStops.size() < fStopCount * 4 || ((fColorStops.size() - fStopCount * 4) % 2)) {
158 SkDebugf("!! Invalid gradient stop array size: %zu", fColorStops.size());
159 return;
160 }
161
162 std::vector<sksg::Gradient::ColorStop> stops;
163
164 // TODO: merge/lerp opacity stops
165 const auto csEnd = fColorStops.cbegin() + fStopCount * 4;
166 for (auto cs = fColorStops.cbegin(); cs != csEnd; cs += 4) {
167 stops.push_back({ *cs, VecToColor(&*(cs + 1), 3) });
168 }
169
170 fGradient->setColorStops(std::move(stops));
171 }
172
CompositeLinearGradient(sk_sp<sksg::LinearGradient> grad,size_t stopCount)173 CompositeLinearGradient::CompositeLinearGradient(sk_sp<sksg::LinearGradient> grad, size_t stopCount)
174 : INHERITED(std::move(grad), stopCount) {}
175
onApply()176 void CompositeLinearGradient::onApply() {
177 auto* grad = static_cast<sksg::LinearGradient*>(fGradient.get());
178 grad->setStartPoint(this->startPoint());
179 grad->setEndPoint(this->endPoint());
180 }
181
CompositeRadialGradient(sk_sp<sksg::RadialGradient> grad,size_t stopCount)182 CompositeRadialGradient::CompositeRadialGradient(sk_sp<sksg::RadialGradient> grad, size_t stopCount)
183 : INHERITED(std::move(grad), stopCount) {}
184
onApply()185 void CompositeRadialGradient::onApply() {
186 auto* grad = static_cast<sksg::RadialGradient*>(fGradient.get());
187 grad->setStartCenter(this->startPoint());
188 grad->setEndCenter(this->startPoint());
189 grad->setStartRadius(0);
190 grad->setEndRadius(SkPoint::Distance(this->startPoint(), this->endPoint()));
191 }
192
193 } // namespace skottie
194