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