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