• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 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/effects/Effects.h"
9 
10 #include "include/effects/SkGradientShader.h"
11 #include "include/effects/SkShaderMaskFilter.h"
12 #include "modules/skottie/src/SkottieAdapter.h"
13 #include "modules/skottie/src/SkottieValue.h"
14 #include "modules/sksg/include/SkSGRenderEffect.h"
15 #include "src/utils/SkJSON.h"
16 
17 #include <cmath>
18 #include <utility>
19 
20 namespace skottie {
21 namespace internal {
22 
23 namespace  {
24 
25 class LinearWipeAdapter final : public MaskFilterEffectBase {
26 public:
LinearWipeAdapter(sk_sp<sksg::RenderNode> layer,const SkSize & ls)27     LinearWipeAdapter(sk_sp<sksg::RenderNode> layer, const SkSize& ls)
28         : INHERITED(std::move(layer), ls) {}
29 
30     ADAPTER_PROPERTY(Completion, float, 0)
31     ADAPTER_PROPERTY(Angle     , float, 0)
32     ADAPTER_PROPERTY(Feather   , float, 0)
33 
34 private:
onMakeMask() const35     MaskInfo onMakeMask() const override {
36         if (fCompletion >= 100) {
37             // The layer is fully disabled.
38             return { nullptr, false };
39         }
40 
41         if (fCompletion <= 0) {
42             // The layer is fully visible (no mask).
43             return { nullptr, true };
44         }
45 
46         const auto t = SkTPin(fCompletion * 0.01f, 0.0f, 1.0f),
47              feather = std::max(fFeather, 0.0f),
48                angle = SkDegreesToRadians(90 - fAngle),
49                 cos_ = std::cos(angle),
50                 sin_ = std::sin(angle);
51 
52         // Select the correct diagonal vector depending on quadrant.
53         const SkVector angle_v = {cos_, sin_},
54                         diag_v = {std::copysign(this->layerSize().width() , cos_),
55                                   std::copysign(this->layerSize().height(), sin_)};
56 
57         // The transition length is the projection of the diagonal onto the angle vector.
58         const auto len = SkVector::DotProduct(diag_v, angle_v);
59 
60         // Pad the gradient segment to accommodate optional feather ramps at both extremities.
61         const auto grad_len   = len + feather * 2;
62         const SkVector grad_v = angle_v * grad_len,
63               adjusted_grad_v = { grad_v.fX, -grad_v.fY }, // Y flipped for drawing space.
64                      center_v = {0.5f * this->layerSize().width(),
65                                  0.5f * this->layerSize().height()};
66 
67         // Gradient start/end points:
68         const SkPoint pts[] = {
69             center_v - adjusted_grad_v * 0.5f,
70             center_v + adjusted_grad_v * 0.5f,
71         };
72 
73         static constexpr SkColor colors[] = { 0x00000000,
74                                               0xffffffff };
75 
76         // To emulate the feather effect, we distance the color stops to generate
77         // a linear transition/ramp.  For t == 0 the ramp should be completely outside/before
78         // the transition domain, and for t == 1 it should be completely outside/after.
79         //
80         //                      [0 ................... |len|]
81         //
82         //   [0  <feather_ramp> [                           ] <feather_ramp> |grad_len|]
83         const auto adjusted_t = t * (len + feather) / grad_len;
84         const SkScalar  pos[] = { adjusted_t,
85                                   adjusted_t + feather / grad_len };
86 
87         return { SkShaderMaskFilter::Make(SkGradientShader::MakeLinear(pts, colors, pos, 2,
88                                                                        SkTileMode::kClamp)),
89                  true };
90     }
91 
92     using INHERITED = MaskFilterEffectBase;
93 };
94 
95 } // namespace
96 
attachLinearWipeEffect(const skjson::ArrayValue & jprops,sk_sp<sksg::RenderNode> layer) const97 sk_sp<sksg::RenderNode> EffectBuilder::attachLinearWipeEffect(const skjson::ArrayValue& jprops,
98                                                               sk_sp<sksg::RenderNode> layer) const {
99     enum : size_t {
100         kCompletion_Index = 0,
101         kAngle_Index      = 1,
102         kFeather_Index    = 2,
103     };
104 
105     auto adapter = sk_make_sp<LinearWipeAdapter>(std::move(layer), fLayerSize);
106 
107     fBuilder->bindProperty<ScalarValue>(GetPropValue(jprops, kCompletion_Index),
108         [adapter](const ScalarValue& c) {
109             adapter->setCompletion(c);
110         });
111     fBuilder->bindProperty<ScalarValue>(GetPropValue(jprops, kAngle_Index),
112         [adapter](const ScalarValue& a) {
113             adapter->setAngle(a);
114         });
115     fBuilder->bindProperty<ScalarValue>(GetPropValue(jprops, kFeather_Index),
116         [adapter](const ScalarValue& f) {
117             adapter->setFeather(f);
118         });
119 
120     return adapter->root();
121 }
122 
123 } // namespace internal
124 } // namespace skottie
125 
126