Coverage Report

Created: 2021-08-22 09:07

/src/skia/modules/skottie/src/effects/GradientEffect.cpp
Line
Count
Source
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 "modules/skottie/src/SkottieValue.h"
11
#include "modules/sksg/include/SkSGGradient.h"
12
#include "modules/sksg/include/SkSGRenderEffect.h"
13
#include "src/utils/SkJSON.h"
14
15
namespace skottie {
16
namespace internal {
17
18
namespace  {
19
20
class GradientRampEffectAdapter final : public AnimatablePropertyContainer {
21
public:
22
    static sk_sp<GradientRampEffectAdapter> Make(const skjson::ArrayValue& jprops,
23
                                                 sk_sp<sksg::RenderNode> layer,
24
1.10k
                                                 const AnimationBuilder* abuilder) {
25
1.10k
        return sk_sp<GradientRampEffectAdapter>(new GradientRampEffectAdapter(jprops,
26
1.10k
                                                                              std::move(layer),
27
1.10k
                                                                              abuilder));
28
1.10k
    }
29
30
1.10k
    sk_sp<sksg::RenderNode> node() const { return fShaderEffect; }
31
32
private:
33
    GradientRampEffectAdapter(const skjson::ArrayValue& jprops,
34
                              sk_sp<sksg::RenderNode> layer,
35
                              const AnimationBuilder* abuilder)
36
1.10k
        : fShaderEffect(sksg::ShaderEffect::Make(std::move(layer))) {
37
1.10k
        enum : size_t {
38
1.10k
             kStartPoint_Index = 0,
39
1.10k
             kStartColor_Index = 1,
40
1.10k
               kEndPoint_Index = 2,
41
1.10k
               kEndColor_Index = 3,
42
1.10k
              kRampShape_Index = 4,
43
1.10k
            kRampScatter_Index = 5,
44
1.10k
             kBlendRatio_Index = 6,
45
1.10k
        };
46
47
1.10k
        EffectBinder(jprops, *abuilder, this)
48
1.10k
                .bind( kStartPoint_Index, fStartPoint)
49
1.10k
                .bind( kStartColor_Index, fStartColor)
50
1.10k
                .bind(   kEndPoint_Index, fEndPoint  )
51
1.10k
                .bind(   kEndColor_Index, fEndColor  )
52
1.10k
                .bind(  kRampShape_Index, fShape     )
53
1.10k
                .bind(kRampScatter_Index, fScatter   )
54
1.10k
                .bind( kBlendRatio_Index, fBlend     );
55
1.10k
    }
56
57
    enum class InstanceType {
58
        kNone,
59
        kLinear,
60
        kRadial,
61
    };
62
63
1.10k
    void onSync() override {
64
        // This adapter manages a SG fragment with the following structure:
65
        //
66
        // - ShaderEffect [fRoot]
67
        //     \  GradientShader [fGradient]
68
        //     \  child/wrapped fragment
69
        //
70
        // The gradient shader is updated based on the (animatable) instance type (linear/radial).
71
72
1.10k
        auto update_gradient = [this] (InstanceType new_type) {
73
1.10k
            if (new_type != fInstanceType) {
74
1.10k
                fGradient = new_type == InstanceType::kLinear
75
291
                        ? sk_sp<sksg::Gradient>(sksg::LinearGradient::Make())
76
813
                        : sk_sp<sksg::Gradient>(sksg::RadialGradient::Make());
77
78
1.10k
                fShaderEffect->setShader(fGradient);
79
1.10k
                fInstanceType = new_type;
80
1.10k
            }
81
82
1.10k
            fGradient->setColorStops({{0, fStartColor},
83
1.10k
                                      {1,   fEndColor}});
84
1.10k
        };
85
86
1.10k
        static constexpr int kLinearShapeValue = 1;
87
1.10k
        const auto instance_type = (SkScalarRoundToInt(fShape) == kLinearShapeValue)
88
291
                ? InstanceType::kLinear
89
813
                : InstanceType::kRadial;
90
91
        // Sync the gradient shader instance if needed.
92
1.10k
        update_gradient(instance_type);
93
94
        // Sync instance-dependent gradient params.
95
1.10k
        const auto start_point = SkPoint{fStartPoint.x, fStartPoint.y},
96
1.10k
                     end_point = SkPoint{  fEndPoint.x,   fEndPoint.y};
97
1.10k
        if (instance_type == InstanceType::kLinear) {
98
291
            auto* lg = static_cast<sksg::LinearGradient*>(fGradient.get());
99
291
            lg->setStartPoint(start_point);
100
291
            lg->setEndPoint(end_point);
101
813
        } else {
102
813
            SkASSERT(instance_type == InstanceType::kRadial);
103
104
813
            auto* rg = static_cast<sksg::RadialGradient*>(fGradient.get());
105
813
            rg->setStartCenter(start_point);
106
813
            rg->setEndCenter(start_point);
107
813
            rg->setEndRadius(SkPoint::Distance(start_point, end_point));
108
813
        }
109
110
        // TODO: blend, scatter
111
1.10k
    }
112
113
    const sk_sp<sksg::ShaderEffect> fShaderEffect;
114
    sk_sp<sksg::Gradient>           fGradient;
115
116
    InstanceType              fInstanceType = InstanceType::kNone;
117
118
    VectorValue fStartColor,
119
                  fEndColor;
120
    Vec2Value   fStartPoint = {0,0},
121
                fEndPoint   = {0,0};
122
    ScalarValue fBlend   = 0,
123
                fScatter = 0,
124
                fShape   = 0; // 1 -> linear, 7 -> radial (?!)
125
};
126
127
}  // namespace
128
129
sk_sp<sksg::RenderNode> EffectBuilder::attachGradientEffect(const skjson::ArrayValue& jprops,
130
1.10k
                                                            sk_sp<sksg::RenderNode> layer) const {
131
1.10k
    return fBuilder->attachDiscardableAdapter<GradientRampEffectAdapter>(jprops,
132
1.10k
                                                                         std::move(layer),
133
1.10k
                                                                         fBuilder);
134
1.10k
}
135
136
} // namespace internal
137
} // namespace skottie