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