Coverage Report

Created: 2021-08-22 09:07

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