1/*
2 * Copyright 2019 Google LLC
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// Convert HSLA -> RGBA (including clamp and premul).
9//
10// Based on work by Sam Hocevar, Emil Persson, and Ian Taylor [1][2][3].
11//
12// [1] http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv
13// [2] http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl
14// [3] http://www.chilliant.com/rgb2hsv.html
15
16in fragmentProcessor? inputFP;
17
18void main() {
19    half4   inputColor = sample(inputFP);
20    half3   hsl = inputColor.rgb;
21
22    half      C = (1 - abs(2 * hsl.z - 1)) * hsl.y;
23    half3     p = hsl.xxx + half3(0, 2/3.0, 1/3.0);
24    half3     q = saturate(abs(fract(p) * 6 - 3) - 1);
25    half3   rgb = (q - 0.5) * C + hsl.z;
26
27    sk_OutColor = saturate(half4(rgb, inputColor.a));
28    sk_OutColor.rgb *= sk_OutColor.a;
29}
30
31@optimizationFlags {
32    (inputFP ? ProcessorOptimizationFlags(inputFP.get()) : kAll_OptimizationFlags) &
33    (kConstantOutputForConstantInput_OptimizationFlag | kPreservesOpaqueInput_OptimizationFlag)
34}
35
36@class {
37    #include "include/private/SkColorData.h"
38    #include "include/private/SkNx.h"
39
40    SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& inColor) const override {
41        SkPMColor4f c = ConstantOutputForConstantInput(this->childProcessor(0), inColor);
42        const auto H = c[0],
43                   S = c[1],
44                   L = c[2],
45                   C = (1 - std::abs(2 * L - 1)) * S;
46
47        const auto p = H + Sk4f(0, 2/3.f, 1/3.f, 0),
48                   q = Sk4f::Min(Sk4f::Max(((p - p.floor()) * 6 - 3).abs() - 1, 0), 1),
49                 rgb = (q - 0.5f) * C + L,
50                rgba = Sk4f::Min(Sk4f::Max(Sk4f(rgb[0], rgb[1], rgb[2], c.fA), 0), 1);
51
52        return SkColor4f{rgba[0], rgba[1], rgba[2], rgba[3]}.premul();
53    }
54}
55