| /* |
| * Copyright 2017 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "SkottieProperties.h" |
| |
| #include "SkColor.h" |
| #include "SkJSONCPP.h" |
| #include "SkPath.h" |
| #include "SkSGColor.h" |
| #include "SkSGGradient.h" |
| #include "SkSGPath.h" |
| #include "SkSGRect.h" |
| #include "SkSGTransform.h" |
| |
| #include <cmath> |
| |
| namespace skottie { |
| |
| namespace { |
| |
| SkColor VecToColor(const float* v, size_t size) { |
| // best effort to turn this into a color |
| const auto r = size > 0 ? v[0] : 0, |
| g = size > 1 ? v[1] : 0, |
| b = size > 2 ? v[2] : 0, |
| a = size > 3 ? v[3] : 1; |
| |
| return SkColorSetARGB(SkTPin<SkScalar>(a, 0, 1) * 255, |
| SkTPin<SkScalar>(r, 0, 1) * 255, |
| SkTPin<SkScalar>(g, 0, 1) * 255, |
| SkTPin<SkScalar>(b, 0, 1) * 255); |
| } |
| |
| } // namespace |
| |
| template <> |
| size_t ValueTraits<ScalarValue>::Cardinality(const ScalarValue&) { |
| return 1; |
| } |
| |
| template <> |
| template <> |
| SkScalar ValueTraits<ScalarValue>::As<SkScalar>(const ScalarValue& v) { |
| return v; |
| } |
| |
| template <> |
| size_t ValueTraits<VectorValue>::Cardinality(const VectorValue& vec) { |
| return vec.size(); |
| } |
| |
| template <> |
| template <> |
| SkColor ValueTraits<VectorValue>::As<SkColor>(const VectorValue& vec) { |
| return VecToColor(vec.data(), vec.size()); |
| } |
| |
| template <> |
| template <> |
| SkPoint ValueTraits<VectorValue>::As<SkPoint>(const VectorValue& vec) { |
| // best effort to turn this into a point |
| const auto x = vec.size() > 0 ? vec[0] : 0, |
| y = vec.size() > 1 ? vec[1] : 0; |
| return SkPoint::Make(x, y); |
| } |
| |
| template <> |
| template <> |
| SkSize ValueTraits<VectorValue>::As<SkSize>(const VectorValue& vec) { |
| const auto pt = ValueTraits::As<SkPoint>(vec); |
| return SkSize::Make(pt.x(), pt.y()); |
| } |
| |
| template <> |
| size_t ValueTraits<ShapeValue>::Cardinality(const ShapeValue& path) { |
| return SkTo<size_t>(path.countVerbs()); |
| } |
| |
| template <> |
| template <> |
| SkPath ValueTraits<ShapeValue>::As<SkPath>(const ShapeValue& path) { |
| return path; |
| } |
| |
| CompositeRRect::CompositeRRect(sk_sp<sksg::RRect> wrapped_node) |
| : fRRectNode(std::move(wrapped_node)) {} |
| |
| void CompositeRRect::apply() { |
| // BM "position" == "center position" |
| auto rr = SkRRect::MakeRectXY(SkRect::MakeXYWH(fPosition.x() - fSize.width() / 2, |
| fPosition.y() - fSize.height() / 2, |
| fSize.width(), fSize.height()), |
| fRadius.width(), |
| fRadius.height()); |
| fRRectNode->setRRect(rr); |
| } |
| |
| CompositeTransform::CompositeTransform(sk_sp<sksg::Matrix> matrix) |
| : fMatrixNode(std::move(matrix)) {} |
| |
| void CompositeTransform::apply() { |
| SkMatrix t = SkMatrix::MakeTrans(-fAnchorPoint.x(), -fAnchorPoint.y()); |
| |
| t.postScale(fScale.x() / 100, fScale.y() / 100); // 100% based |
| t.postRotate(fRotation); |
| t.postTranslate(fPosition.x(), fPosition.y()); |
| // TODO: skew |
| |
| fMatrixNode->setMatrix(t); |
| } |
| |
| CompositePolyStar::CompositePolyStar(sk_sp<sksg::Path> wrapped_node, Type t) |
| : fPathNode(std::move(wrapped_node)) |
| , fType(t) {} |
| |
| void CompositePolyStar::apply() { |
| const auto count = SkScalarTruncToInt(fPointCount); |
| const auto arc = SK_ScalarPI * 2 / count; |
| |
| const auto pt_on_circle = [](const SkPoint& c, SkScalar r, SkScalar a) { |
| return SkPoint::Make(c.x() + r * std::cos(a), |
| c.y() + r * std::sin(a)); |
| }; |
| |
| // TODO: inner/outer "roundness"? |
| |
| SkPath poly; |
| |
| auto angle = SkDegreesToRadians(fRotation); |
| poly.moveTo(pt_on_circle(fPosition, fOuterRadius, angle)); |
| |
| for (int i = 0; i < count; ++i) { |
| if (fType == Type::kStar) { |
| poly.lineTo(pt_on_circle(fPosition, fInnerRadius, angle + arc * 0.5f)); |
| } |
| angle += arc; |
| poly.lineTo(pt_on_circle(fPosition, fOuterRadius, angle)); |
| } |
| |
| poly.close(); |
| fPathNode->setPath(poly); |
| } |
| |
| CompositeGradient::CompositeGradient(sk_sp<sksg::Gradient> grad, size_t stopCount) |
| : fGradient(std::move(grad)) |
| , fStopCount(stopCount) {} |
| |
| void CompositeGradient::apply() { |
| this->onApply(); |
| |
| // |fColorStops| holds |fStopCount| x [ pos, r, g, g ] + ? x [ pos, alpha ] |
| |
| if (fColorStops.size() < fStopCount * 4 || ((fColorStops.size() - fStopCount * 4) % 2)) { |
| SkDebugf("!! Invalid gradient stop array size: %zu", fColorStops.size()); |
| return; |
| } |
| |
| std::vector<sksg::Gradient::ColorStop> stops; |
| |
| // TODO: merge/lerp opacity stops |
| const auto csEnd = fColorStops.cbegin() + fStopCount * 4; |
| for (auto cs = fColorStops.cbegin(); cs != csEnd; cs += 4) { |
| stops.push_back({ *cs, VecToColor(&*(cs + 1), 3) }); |
| } |
| |
| fGradient->setColorStops(std::move(stops)); |
| } |
| |
| CompositeLinearGradient::CompositeLinearGradient(sk_sp<sksg::LinearGradient> grad, size_t stopCount) |
| : INHERITED(std::move(grad), stopCount) {} |
| |
| void CompositeLinearGradient::onApply() { |
| auto* grad = static_cast<sksg::LinearGradient*>(fGradient.get()); |
| grad->setStartPoint(this->startPoint()); |
| grad->setEndPoint(this->endPoint()); |
| } |
| |
| CompositeRadialGradient::CompositeRadialGradient(sk_sp<sksg::RadialGradient> grad, size_t stopCount) |
| : INHERITED(std::move(grad), stopCount) {} |
| |
| void CompositeRadialGradient::onApply() { |
| auto* grad = static_cast<sksg::RadialGradient*>(fGradient.get()); |
| grad->setStartCenter(this->startPoint()); |
| grad->setEndCenter(this->startPoint()); |
| grad->setStartRadius(0); |
| grad->setEndRadius(SkPoint::Distance(this->startPoint(), this->endPoint())); |
| } |
| |
| } // namespace skottie |