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