• 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/SkSGMerge.h"
15 
16 #include <vector>
17 
18 namespace skottie {
19 namespace internal {
20 
21 namespace  {
22 
23 class TrimEffectAdapter final : public DiscardableAdapterBase<TrimEffectAdapter, sksg::TrimEffect> {
24 public:
TrimEffectAdapter(const skjson::ObjectValue & jtrim,const AnimationBuilder & abuilder,sk_sp<sksg::GeometryNode> child)25     TrimEffectAdapter(const skjson::ObjectValue& jtrim,
26                       const AnimationBuilder& abuilder,
27                       sk_sp<sksg::GeometryNode> child)
28         : INHERITED(sksg::TrimEffect::Make(std::move(child))) {
29         this->bind(abuilder, jtrim["s"], &fStart);
30         this->bind(abuilder, jtrim["e"], &fEnd);
31         this->bind(abuilder, jtrim["o"], &fOffset);
32     }
33 
34 private:
onSync()35     void onSync() override {
36         // BM semantics: start/end are percentages, offset is "degrees" (?!).
37         const auto  start = fStart  / 100,
38                       end = fEnd    / 100,
39                    offset = fOffset / 360;
40 
41         auto startT = std::min(start, end) + offset,
42               stopT = std::max(start, end) + offset;
43         auto   mode = SkTrimPathEffect::Mode::kNormal;
44 
45         if (stopT - startT < 1) {
46             startT -= SkScalarFloorToScalar(startT);
47             stopT  -= SkScalarFloorToScalar(stopT);
48 
49             if (startT > stopT) {
50                 using std::swap;
51                 swap(startT, stopT);
52                 mode = SkTrimPathEffect::Mode::kInverted;
53             }
54         } else {
55             startT = 0;
56             stopT  = 1;
57         }
58 
59         this->node()->setStart(startT);
60         this->node()->setStop(stopT);
61         this->node()->setMode(mode);
62     }
63 
64     ScalarValue fStart  =   0,
65                 fEnd    = 100,
66                 fOffset =   0;
67 
68     using INHERITED = DiscardableAdapterBase<TrimEffectAdapter, sksg::TrimEffect>;
69 };
70 
71 } // namespace
72 
AttachTrimGeometryEffect(const skjson::ObjectValue & jtrim,const AnimationBuilder * abuilder,std::vector<sk_sp<sksg::GeometryNode>> && geos)73 std::vector<sk_sp<sksg::GeometryNode>> ShapeBuilder::AttachTrimGeometryEffect(
74         const skjson::ObjectValue& jtrim,
75         const AnimationBuilder* abuilder,
76         std::vector<sk_sp<sksg::GeometryNode>>&& geos) {
77 
78     enum class Mode {
79         kParallel, // "m": 1 (Trim Multiple Shapes: Simultaneously)
80         kSerial,   // "m": 2 (Trim Multiple Shapes: Individually)
81     } gModes[] = { Mode::kParallel, Mode::kSerial};
82 
83     const auto mode = gModes[std::min<size_t>(ParseDefault<size_t>(jtrim["m"], 1) - 1,
84                                             SK_ARRAY_COUNT(gModes) - 1)];
85 
86     std::vector<sk_sp<sksg::GeometryNode>> inputs;
87     if (mode == Mode::kSerial) {
88         inputs.push_back(ShapeBuilder::MergeGeometry(std::move(geos), sksg::Merge::Mode::kMerge));
89     } else {
90         inputs = std::move(geos);
91     }
92 
93     std::vector<sk_sp<sksg::GeometryNode>> trimmed;
94     trimmed.reserve(inputs.size());
95 
96     for (const auto& i : inputs) {
97         trimmed.push_back(
98             abuilder->attachDiscardableAdapter<TrimEffectAdapter>(jtrim, *abuilder, i));
99     }
100 
101     return trimmed;
102 }
103 
104 } // namespace internal
105 } // namespace skottie
106