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