• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/effects/SkHighContrastFilter.h"
9 
10 #include "include/core/SkColorFilter.h"
11 #include "include/core/SkRefCnt.h"
12 #include "include/core/SkTypes.h"
13 
14 #ifdef SK_ENABLE_SKSL
15 #include "include/core/SkAlphaType.h"
16 #include "include/core/SkColorSpace.h"
17 #include "include/core/SkData.h"
18 #include "include/core/SkString.h"
19 #include "include/effects/SkRuntimeEffect.h"
20 #include "include/private/base/SkTPin.h"
21 #include "modules/skcms/skcms.h"
22 #include "src/core/SkColorFilterPriv.h"
23 #include "src/core/SkRuntimeEffectPriv.h"
24 
25 #include <cfloat>
26 
Make(const SkHighContrastConfig & config)27 sk_sp<SkColorFilter> SkHighContrastFilter::Make(const SkHighContrastConfig& config) {
28     if (!config.isValid()) {
29         return nullptr;
30     }
31 
32     struct Uniforms { float grayscale, invertStyle, contrast; };
33 
34     static constexpr char kHighContrastFilterCode[] =
35             "uniform half grayscale, invertStyle, contrast;"
36 
37             // TODO(skia:13540): Investigate using $rgb_to_hsl from sksl_shared instead.
38             "half3 rgb_to_hsl(half3 c) {"
39                 "half mx = max(max(c.r,c.g),c.b),"
40                      "mn = min(min(c.r,c.g),c.b),"
41                       "d = mx-mn,"
42                    "invd = 1.0 / d,"
43                  "g_lt_b = c.g < c.b ? 6.0 : 0.0;"
44 
45             // We'd prefer to write these tests like `mx == c.r`, but on some GPUs max(x,y) is
46             // not always equal to either x or y.  So we use long form, c.r >= c.g && c.r >= c.b.
47                 "half h = (1/6.0) * (mx == mn                 ? 0.0 :"
48                      /*mx==c.r*/    "c.r >= c.g && c.r >= c.b ? invd * (c.g - c.b) + g_lt_b :"
49                      /*mx==c.g*/    "c.g >= c.b               ? invd * (c.b - c.r) + 2.0"
50                      /*mx==c.b*/                             ": invd * (c.r - c.g) + 4.0);"
51                 "half sum = mx+mn,"
52                        "l = sum * 0.5,"
53                        "s = mx == mn ? 0.0"
54                                     ": d / (l > 0.5 ? 2.0 - sum : sum);"
55                 "return half3(h,s,l);"
56             "}"
57             "half4 main(half4 inColor) {"
58                 "half4 c = inColor;"  // linear unpremul RGBA in dst gamut
59                 "if (grayscale == 1) {"
60                     "c.rgb = dot(half3(0.2126, 0.7152, 0.0722), c.rgb).rrr;"
61                 "}"
62                 "if (invertStyle == 1) {"  // brightness
63                     "c.rgb = 1 - c.rgb;"
64                 "} else if (invertStyle == 2) {"  // lightness
65                     "c.rgb = rgb_to_hsl(c.rgb);"
66                     "c.b = 1 - c.b;"
67                     "c.rgb = $hsl_to_rgb(c.rgb);"
68                 "}"
69                 "c.rgb = mix(half3(0.5), c.rgb, contrast);"
70                 "return half4(saturate(c.rgb), c.a);"
71             "}";
72 
73     static const SkRuntimeEffect* effect = SkMakeCachedRuntimeEffect(
74         SkRuntimeEffect::MakeForColorFilter,
75         SkString(kHighContrastFilterCode)
76     ).release();
77 
78     SkASSERT(effect);
79 
80     // A contrast setting of exactly +1 would divide by zero (1+c)/(1-c), so pull in to +1-ε.
81     // I'm not exactly sure why we've historically pinned -1 up to -1+ε, maybe just symmetry?
82     float c = SkTPin(config.fContrast,
83                      -1.0f + FLT_EPSILON,
84                      +1.0f - FLT_EPSILON);
85 
86     Uniforms uniforms = {
87         config.fGrayscale ? 1.0f : 0.0f,
88         (float)config.fInvertStyle,  // 0.0f for none, 1.0f for brightness, 2.0f for lightness
89         (1+c)/(1-c),
90     };
91 
92     skcms_TransferFunction linear = SkNamedTransferFn::kLinear;
93     SkAlphaType          unpremul = kUnpremul_SkAlphaType;
94     return SkColorFilterPriv::WithWorkingFormat(
95             effect->makeColorFilter(SkData::MakeWithCopy(&uniforms,sizeof(uniforms))),
96             &linear, nullptr/*use dst gamut*/, &unpremul);
97 }
98 #else // SK_ENABLE_SKSL
Make(const SkHighContrastConfig & config)99 sk_sp<SkColorFilter> SkHighContrastFilter::Make(const SkHighContrastConfig& config) {
100     // TODO(skia:12197)
101     return nullptr;
102 }
103 #endif
104 
105