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 21namespace skottie { 22 23namespace { 24 25SkColor 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 40template <> 41size_t ValueTraits<ScalarValue>::Cardinality(const ScalarValue&) { 42 return 1; 43} 44 45template <> 46template <> 47SkScalar ValueTraits<ScalarValue>::As<SkScalar>(const ScalarValue& v) { 48 return v; 49} 50 51template <> 52size_t ValueTraits<VectorValue>::Cardinality(const VectorValue& vec) { 53 return vec.size(); 54} 55 56template <> 57template <> 58SkColor ValueTraits<VectorValue>::As<SkColor>(const VectorValue& vec) { 59 return VecToColor(vec.data(), vec.size()); 60} 61 62template <> 63template <> 64SkPoint 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 71template <> 72template <> 73SkSize 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 78template <> 79size_t ValueTraits<ShapeValue>::Cardinality(const ShapeValue& path) { 80 return SkTo<size_t>(path.countVerbs()); 81} 82 83template <> 84template <> 85SkPath ValueTraits<ShapeValue>::As<SkPath>(const ShapeValue& path) { 86 return path; 87} 88 89CompositeRRect::CompositeRRect(sk_sp<sksg::RRect> wrapped_node) 90 : fRRectNode(std::move(wrapped_node)) {} 91 92void 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 102CompositeTransform::CompositeTransform(sk_sp<sksg::Matrix> matrix) 103 : fMatrixNode(std::move(matrix)) {} 104 105void 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 116CompositePolyStar::CompositePolyStar(sk_sp<sksg::Path> wrapped_node, Type t) 117 : fPathNode(std::move(wrapped_node)) 118 , fType(t) {} 119 120void 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 148CompositeGradient::CompositeGradient(sk_sp<sksg::Gradient> grad, size_t stopCount) 149 : fGradient(std::move(grad)) 150 , fStopCount(stopCount) {} 151 152void 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 173CompositeLinearGradient::CompositeLinearGradient(sk_sp<sksg::LinearGradient> grad, size_t stopCount) 174 : INHERITED(std::move(grad), stopCount) {} 175 176void CompositeLinearGradient::onApply() { 177 auto* grad = static_cast<sksg::LinearGradient*>(fGradient.get()); 178 grad->setStartPoint(this->startPoint()); 179 grad->setEndPoint(this->endPoint()); 180} 181 182CompositeRadialGradient::CompositeRadialGradient(sk_sp<sksg::RadialGradient> grad, size_t stopCount) 183 : INHERITED(std::move(grad), stopCount) {} 184 185void 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