Coverage Report

Created: 2024-05-20 07:14

/src/skia/modules/skottie/src/effects/Effects.cpp
Line
Count
Source (jump to first uncovered line)
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/include/Skottie.h"
11
#include "modules/skottie/include/SkottieProperty.h"
12
#include "modules/skottie/src/SkottieJson.h"
13
#include "modules/skottie/src/SkottiePriv.h"
14
#include "modules/sksg/include/SkSGRenderEffect.h"
15
#include "modules/sksg/include/SkSGRenderNode.h"
16
17
#include <algorithm>
18
#include <cstdint>
19
#include <cstring>
20
#include <iterator>
21
#include <limits>
22
#include <utility>
23
24
namespace skottie {
25
namespace internal {
26
27
EffectBuilder::EffectBuilder(const AnimationBuilder* abuilder,
28
                             const SkSize& layer_size,
29
                             CompositionBuilder* cbuilder)
30
    : fBuilder(abuilder)
31
    , fCompBuilder(cbuilder)
32
47.7k
    , fLayerSize(layer_size) {}
33
34
43.9k
EffectBuilder::EffectBuilderT EffectBuilder::findBuilder(const skjson::ObjectValue& jeffect) const {
35
43.9k
    static constexpr struct BuilderInfo {
36
43.9k
        const char*    fName;
37
43.9k
        EffectBuilderT fBuilder;
38
43.9k
    } gBuilderInfo[] = {
39
        // alphabetized for binary search lookup
40
43.9k
        { "ADBE Black&White"            , &EffectBuilder::attachBlackAndWhiteEffect      },
41
43.9k
        { "ADBE Brightness & Contrast 2", &EffectBuilder::attachBrightnessContrastEffect },
42
43.9k
        { "ADBE Bulge"                  , &EffectBuilder::attachBulgeEffect              },
43
43.9k
        { "ADBE Corner Pin"             , &EffectBuilder::attachCornerPinEffect          },
44
43.9k
        { "ADBE Displacement Map"       , &EffectBuilder::attachDisplacementMapEffect    },
45
43.9k
        { "ADBE Drop Shadow"            , &EffectBuilder::attachDropShadowEffect         },
46
43.9k
        { "ADBE Easy Levels2"           , &EffectBuilder::attachEasyLevelsEffect         },
47
43.9k
        { "ADBE Fill"                   , &EffectBuilder::attachFillEffect               },
48
43.9k
        { "ADBE Fractal Noise"          , &EffectBuilder::attachFractalNoiseEffect       },
49
43.9k
        { "ADBE Gaussian Blur 2"        , &EffectBuilder::attachGaussianBlurEffect       },
50
43.9k
        { "ADBE Geometry2"              , &EffectBuilder::attachTransformEffect          },
51
43.9k
        { "ADBE HUE SATURATION"         , &EffectBuilder::attachHueSaturationEffect      },
52
43.9k
        { "ADBE Invert"                 , &EffectBuilder::attachInvertEffect             },
53
43.9k
        { "ADBE Linear Wipe"            , &EffectBuilder::attachLinearWipeEffect         },
54
43.9k
        { "ADBE Motion Blur"            , &EffectBuilder::attachDirectionalBlurEffect    },
55
43.9k
        { "ADBE Pro Levels2"            , &EffectBuilder::attachProLevelsEffect          },
56
43.9k
        { "ADBE Radial Wipe"            , &EffectBuilder::attachRadialWipeEffect         },
57
43.9k
        { "ADBE Ramp"                   , &EffectBuilder::attachGradientEffect           },
58
43.9k
        { "ADBE Sharpen"                , &EffectBuilder::attachSharpenEffect            },
59
43.9k
        { "ADBE Shift Channels"         , &EffectBuilder::attachShiftChannelsEffect      },
60
43.9k
        { "ADBE Threshold2"             , &EffectBuilder::attachThresholdEffect          },
61
43.9k
        { "ADBE Tile"                   , &EffectBuilder::attachMotionTileEffect         },
62
43.9k
        { "ADBE Tint"                   , &EffectBuilder::attachTintEffect               },
63
43.9k
        { "ADBE Tritone"                , &EffectBuilder::attachTritoneEffect            },
64
43.9k
        { "ADBE Venetian Blinds"        , &EffectBuilder::attachVenetianBlindsEffect     },
65
43.9k
        { "CC Sphere"                   , &EffectBuilder::attachSphereEffect             },
66
43.9k
        { "CC Toner"                    , &EffectBuilder::attachCCTonerEffect            },
67
43.9k
        { "SkSL Color Filter"           , &EffectBuilder::attachSkSLColorFilter          },
68
43.9k
        { "SkSL Shader"                 , &EffectBuilder::attachSkSLShader               },
69
43.9k
    };
70
71
43.9k
    const skjson::StringValue* mn = jeffect["mn"];
72
43.9k
    if (mn) {
73
22.7k
        const BuilderInfo key { mn->begin(), nullptr };
74
22.7k
        const auto* binfo = std::lower_bound(std::begin(gBuilderInfo),
75
22.7k
                                             std::end  (gBuilderInfo),
76
22.7k
                                             key,
77
113k
                                             [](const BuilderInfo& a, const BuilderInfo& b) {
78
113k
                                                 return strcmp(a.fName, b.fName) < 0;
79
113k
                                             });
80
22.7k
        if (binfo != std::end(gBuilderInfo) && !strcmp(binfo->fName, key.fName)) {
81
19.9k
            return binfo->fBuilder;
82
19.9k
        }
83
22.7k
    }
84
85
    // Some legacy clients rely solely on the 'ty' field and generate (non-BM) JSON
86
    // without a valid 'mn' string.  TODO: we should update them and remove this fallback.
87
23.9k
    enum : int32_t {
88
23.9k
        kTint_Effect         = 20,
89
23.9k
        kFill_Effect         = 21,
90
23.9k
        kTritone_Effect      = 23,
91
23.9k
        kDropShadow_Effect   = 25,
92
23.9k
        kRadialWipe_Effect   = 26,
93
23.9k
        kGaussianBlur_Effect = 29,
94
23.9k
    };
95
96
23.9k
    switch (ParseDefault<int>(jeffect["ty"], -1)) {
97
116
        case         kTint_Effect: return &EffectBuilder::attachTintEffect;
98
128
        case         kFill_Effect: return &EffectBuilder::attachFillEffect;
99
4.86k
        case      kTritone_Effect: return &EffectBuilder::attachTritoneEffect;
100
10.4k
        case   kDropShadow_Effect: return &EffectBuilder::attachDropShadowEffect;
101
1.33k
        case   kRadialWipe_Effect: return &EffectBuilder::attachRadialWipeEffect;
102
327
        case kGaussianBlur_Effect: return &EffectBuilder::attachGaussianBlurEffect;
103
6.71k
        default: break;
104
23.9k
    }
105
106
6.71k
    fBuilder->log(Logger::Level::kWarning, &jeffect,
107
6.71k
                  "Unsupported layer effect: %s", mn ? mn->begin() : "(unknown)");
108
109
6.71k
    return nullptr;
110
23.9k
}
111
112
sk_sp<sksg::RenderNode> EffectBuilder::attachEffects(const skjson::ArrayValue& jeffects,
113
47.0k
                                                     sk_sp<sksg::RenderNode> layer) const {
114
47.0k
    if (!layer) {
115
9.00k
        return nullptr;
116
9.00k
    }
117
118
43.9k
    for (const skjson::ObjectValue* jeffect : jeffects) {
119
43.9k
        if (!jeffect) {
120
1
            continue;
121
1
        }
122
123
43.9k
        const auto builder = this->findBuilder(*jeffect);
124
43.9k
        const skjson::ArrayValue* jprops = (*jeffect)["ef"];
125
43.9k
        if (!builder || !jprops) {
126
8.24k
            continue;
127
8.24k
        }
128
129
35.6k
        const AnimationBuilder::AutoPropertyTracker apt(fBuilder, *jeffect, PropertyObserver::NodeType::EFFECT);
130
35.6k
        layer = (this->*builder)(*jprops, std::move(layer));
131
132
35.6k
        if (!layer) {
133
0
            fBuilder->log(Logger::Level::kError, jeffect, "Invalid layer effect.");
134
0
            return nullptr;
135
0
        }
136
35.6k
    }
137
138
38.0k
    return layer;
139
38.0k
}
140
141
sk_sp<sksg::RenderNode> EffectBuilder::attachStyles(const skjson::ArrayValue& jstyles,
142
627
                                                     sk_sp<sksg::RenderNode> layer) const {
143
627
#if !defined(SKOTTIE_DISABLE_STYLES)
144
627
    if (!layer) {
145
375
        return nullptr;
146
375
    }
147
148
252
    using StyleBuilder =
149
252
        sk_sp<sksg::RenderNode> (EffectBuilder::*)(const skjson::ObjectValue&,
150
252
                                                   sk_sp<sksg::RenderNode>) const;
151
252
    static constexpr StyleBuilder gStyleBuilders[] = {
152
252
        nullptr,                                 // 'ty': 0 -> stroke
153
252
        &EffectBuilder::attachDropShadowStyle,   // 'ty': 1 -> drop shadow
154
252
        &EffectBuilder::attachInnerShadowStyle,  // 'ty': 2 -> inner shadow
155
252
        &EffectBuilder::attachOuterGlowStyle,    // 'ty': 3 -> outer glow
156
252
        &EffectBuilder::attachInnerGlowStyle,    // 'ty': 4 -> inner glow
157
252
    };
158
159
49.0k
    for (const skjson::ObjectValue* jstyle : jstyles) {
160
49.0k
        if (!jstyle) {
161
53
            continue;
162
53
        }
163
164
49.0k
        const auto style_type =
165
49.0k
                ParseDefault<size_t>((*jstyle)["ty"], std::numeric_limits<size_t>::max());
166
49.0k
        auto builder = style_type < std::size(gStyleBuilders) ? gStyleBuilders[style_type]
167
49.0k
                                                              : nullptr;
168
169
49.0k
        if (!builder) {
170
4.21k
            fBuilder->log(Logger::Level::kWarning, jstyle, "Unsupported layer style.");
171
4.21k
            continue;
172
4.21k
        }
173
174
44.7k
        layer = (this->*builder)(*jstyle, std::move(layer));
175
44.7k
    }
176
252
#endif // !defined(SKOTTIE_DISABLE_STYLES)
177
178
252
    return layer;
179
627
}
180
181
const skjson::Value& EffectBuilder::GetPropValue(const skjson::ArrayValue& jprops,
182
251k
                                                 size_t prop_index) {
183
251k
    static skjson::NullValue kNull;
184
185
251k
    if (prop_index >= jprops.size()) {
186
145k
        return kNull;
187
145k
    }
188
189
106k
    const skjson::ObjectValue* jprop = jprops[prop_index];
190
191
106k
    return jprop ? (*jprop)["v"] : kNull;
192
251k
}
193
194
MaskShaderEffectBase::MaskShaderEffectBase(sk_sp<sksg::RenderNode> child, const SkSize& ls)
195
    : fMaskEffectNode(sksg::MaskShaderEffect::Make(std::move(child)))
196
0
    , fLayerSize(ls) {}
197
198
0
void MaskShaderEffectBase::onSync() {
199
0
    const auto minfo = this->onMakeMask();
200
201
0
    fMaskEffectNode->setVisible(minfo.fVisible);
202
0
    fMaskEffectNode->setShader(std::move(minfo.fMaskShader));
203
0
}
204
205
} // namespace internal
206
} // namespace skottie