1 /*
2 * Copyright 2017 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/SkString.h"
9 #include "include/effects/SkHighContrastFilter.h"
10 #include "include/effects/SkRuntimeEffect.h"
11 #include "include/private/SkTPin.h"
12 #include "src/core/SkRuntimeEffectPriv.h"
13
Make(const SkHighContrastConfig & config)14 sk_sp<SkColorFilter> SkHighContrastFilter::Make(const SkHighContrastConfig& config) {
15 if (!config.isValid()) {
16 return nullptr;
17 }
18
19 struct Uniforms { float grayscale, invertStyle, contrast; };
20
21 SkString code{R"(
22 uniform half grayscale, invertStyle, contrast;
23 )"};
24 code += kRGB_to_HSL_sksl;
25 code += kHSL_to_RGB_sksl;
26 code += R"(
27 half4 main(half4 inColor) {
28 half4 c = inColor; // linear unpremul RGBA in dst gamut.
29 if (grayscale == 1) {
30 c.rgb = dot(half3(0.2126, 0.7152, 0.0722), c.rgb).rrr;
31 }
32 if (invertStyle == 1/*brightness*/) {
33 c.rgb = 1 - c.rgb;
34 } else if (invertStyle == 2/*lightness*/) {
35 c.rgb = rgb_to_hsl(c.rgb);
36 c.b = 1 - c.b;
37 c.rgb = hsl_to_rgb(c.rgb);
38 }
39 c.rgb = mix(half3(0.5), c.rgb, contrast);
40 return half4(saturate(c.rgb), c.a);
41 }
42 )";
43
44 sk_sp<SkRuntimeEffect> effect = SkMakeCachedRuntimeEffect(SkRuntimeEffect::MakeForColorFilter,
45 std::move(code));
46 SkASSERT(effect);
47
48 // A contrast setting of exactly +1 would divide by zero (1+c)/(1-c), so pull in to +1-ε.
49 // I'm not exactly sure why we've historically pinned -1 up to -1+ε, maybe just symmetry?
50 float c = SkTPin(config.fContrast,
51 -1.0f + FLT_EPSILON,
52 +1.0f - FLT_EPSILON);
53
54 Uniforms uniforms = {
55 config.fGrayscale ? 1.0f : 0.0f,
56 (float)config.fInvertStyle, // 0.0f for none, 1.0f for brightness, 2.0f for lightness
57 (1+c)/(1-c),
58 };
59
60 skcms_TransferFunction linear = SkNamedTransferFn::kLinear;
61 SkAlphaType unpremul = kUnpremul_SkAlphaType;
62 return SkColorFilters::WithWorkingFormat(
63 effect->makeColorFilter(SkData::MakeWithCopy(&uniforms,sizeof(uniforms))),
64 &linear, nullptr/*use dst gamut*/, &unpremul);
65 }
66
67