1 /*
2 * Copyright 2021 Google LLC
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/SkScalar.h"
9 #include "include/effects/SkBlenders.h"
10 #include "include/effects/SkRuntimeEffect.h"
11
Arithmetic(float k1,float k2,float k3,float k4,bool enforcePremul)12 sk_sp<SkBlender> SkBlenders::Arithmetic(float k1, float k2, float k3, float k4,
13 bool enforcePremul) {
14 #ifdef SK_ENABLE_SKSL
15 if (!SkScalarIsFinite(k1) ||
16 !SkScalarIsFinite(k2) ||
17 !SkScalarIsFinite(k3) ||
18 !SkScalarIsFinite(k4)) {
19 return nullptr;
20 }
21
22 // Are we nearly a SkBlendMode?
23 const struct {
24 float k1, k2, k3, k4;
25 SkBlendMode mode;
26 } table[] = {
27 { 0, 1, 0, 0, SkBlendMode::kSrc },
28 { 0, 0, 1, 0, SkBlendMode::kDst },
29 { 0, 0, 0, 0, SkBlendMode::kClear },
30 };
31 for (const auto& t : table) {
32 if (SkScalarNearlyEqual(k1, t.k1) &&
33 SkScalarNearlyEqual(k2, t.k2) &&
34 SkScalarNearlyEqual(k3, t.k3) &&
35 SkScalarNearlyEqual(k4, t.k4)) {
36 return SkBlender::Mode(t.mode);
37 }
38 }
39
40 // If we get here, we need the actual blender effect.
41
42 static SkRuntimeEffect* gArithmeticEffect = []{
43 const char prog[] = R"(
44 uniform half4 k;
45 uniform half pmClamp;
46
47 half4 main(half4 src, half4 dst) {
48 half4 c = k.x * src * dst + k.y * src + k.z * dst + k.w;
49 c.rgb = min(c.rgb, max(c.a, pmClamp));
50 // rely on skia to saturate our alpha
51 return c;
52 }
53 )";
54 auto result = SkRuntimeEffect::MakeForBlender(SkString(prog));
55 SkASSERTF(result.effect, "SkBlenders::Arithmetic: %s", result.errorText.c_str());
56 return result.effect.release();
57 }();
58
59 const float array[] = {
60 k1, k2, k3, k4,
61 enforcePremul ? 0.0f : 1.0f,
62 };
63 return gArithmeticEffect->makeBlender(SkData::MakeWithCopy(array, sizeof(array)));
64 #else
65 // TODO(skia:12197)
66 return nullptr;
67 #endif
68 }
69