• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2022 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/SkBlendMode.h"
9 #include "include/core/SkBlender.h"
10 #include "include/effects/SkRuntimeEffect.h"
11 #include "modules/skottie/src/SkottieJson.h"
12 #include "modules/skottie/src/SkottiePriv.h"
13 #include "modules/sksg/include/SkSGRenderEffect.h"
14 
15 namespace skottie::internal {
16 
17 namespace {
18 
19 enum CustomBlenders {
20     HARDMIX = 17,
21 };
22 
hardMix()23 static sk_sp<SkBlender> hardMix() {
24     static SkRuntimeEffect* hardMixEffect = []{
25         const char hardMix[] =
26             "half4 main(half4 src, half4 dst) {"
27                 "src.rgb = unpremul(src).rgb + unpremul(dst).rgb;"
28                 "src.rgb = min(floor(src.rgb), 1) * src.a;"
29 
30                 "return src + (1 - src.a)*dst;"
31             "}"
32         ;
33         auto result = SkRuntimeEffect::MakeForBlender(SkString(hardMix));
34         return result.effect.release();
35     }();
36     return hardMixEffect->makeBlender(nullptr);
37 }
38 
get_blender(const skjson::ObjectValue & jobject,const AnimationBuilder * abuilder)39 static sk_sp<SkBlender> get_blender(const skjson::ObjectValue& jobject,
40                                     const AnimationBuilder* abuilder) {
41     static constexpr SkBlendMode kBlendModeMap[] = {
42         SkBlendMode::kSrcOver,    // 0:'normal'
43         SkBlendMode::kMultiply,   // 1:'multiply'
44         SkBlendMode::kScreen,     // 2:'screen'
45         SkBlendMode::kOverlay,    // 3:'overlay
46         SkBlendMode::kDarken,     // 4:'darken'
47         SkBlendMode::kLighten,    // 5:'lighten'
48         SkBlendMode::kColorDodge, // 6:'color-dodge'
49         SkBlendMode::kColorBurn,  // 7:'color-burn'
50         SkBlendMode::kHardLight,  // 8:'hard-light'
51         SkBlendMode::kSoftLight,  // 9:'soft-light'
52         SkBlendMode::kDifference, // 10:'difference'
53         SkBlendMode::kExclusion,  // 11:'exclusion'
54         SkBlendMode::kHue,        // 12:'hue'
55         SkBlendMode::kSaturation, // 13:'saturation'
56         SkBlendMode::kColor,      // 14:'color'
57         SkBlendMode::kLuminosity, // 15:'luminosity'
58         SkBlendMode::kPlus,       // 16:'add'
59     };
60 
61     const size_t mode = ParseDefault<size_t>(jobject["bm"], 0);
62 
63     // Special handling of src-over, so we can detect the trivial/no-fancy-blending case
64     // (a null blender is equivalent to src-over).
65     if (!mode) {
66         return nullptr;
67     }
68 
69     // Modes that are expressible as SkBlendMode.
70     if (mode < std::size(kBlendModeMap)) {
71         return SkBlender::Mode(kBlendModeMap[mode]);
72     }
73 
74     // Modes that require custom blenders.
75     switch (mode)
76     {
77     case HARDMIX:
78         return hardMix();
79     default:
80         break;
81     }
82 
83     abuilder->log(Logger::Level::kWarning, &jobject, "Unsupported blend mode %zu\n", mode);
84     return nullptr;
85 }
86 
87 }  // namespace
88 
attachBlendMode(const skjson::ObjectValue & jobject,sk_sp<sksg::RenderNode> child) const89 sk_sp<sksg::RenderNode> AnimationBuilder::attachBlendMode(const skjson::ObjectValue& jobject,
90                                                           sk_sp<sksg::RenderNode> child) const {
91     if (auto blender = get_blender(jobject, this)) {
92         fHasNontrivialBlending = true;
93         child = sksg::BlenderEffect::Make(std::move(child), std::move(blender));
94     }
95 
96     return child;
97 }
98 
99 }  // namespace skottie::internal
100