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