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