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