1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2012 Benjamin Otte <otte@gnome.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "config.h"
19 
20 #include "gtkhslaprivate.h"
21 
22 #include <math.h>
23 
24 void
_gtk_hsla_init(GtkHSLA * hsla,double hue,double saturation,double lightness,double alpha)25 _gtk_hsla_init (GtkHSLA *hsla,
26                 double   hue,
27                 double   saturation,
28                 double   lightness,
29                 double   alpha)
30 {
31   g_return_if_fail (hsla != NULL);
32 
33   if (hue >= 0)
34     hsla->hue = fmod (hue, 360);
35   else
36     hsla->hue = fmod (hue, 360) + 360;
37   hsla->saturation = CLAMP (saturation, 0, 1);
38   hsla->lightness = CLAMP (lightness, 0, 1);
39   hsla->alpha = CLAMP (alpha, 0, 1);
40 }
41 
42 void
_gtk_hsla_init_from_rgba(GtkHSLA * hsla,const GdkRGBA * rgba)43 _gtk_hsla_init_from_rgba (GtkHSLA       *hsla,
44                           const GdkRGBA *rgba)
45 {
46   gdouble min;
47   gdouble max;
48   gdouble red;
49   gdouble green;
50   gdouble blue;
51   gdouble delta;
52 
53   g_return_if_fail (hsla != NULL);
54   g_return_if_fail (rgba != NULL);
55 
56   red = rgba->red;
57   green = rgba->green;
58   blue = rgba->blue;
59 
60   if (red > green)
61     {
62       if (red > blue)
63         max = red;
64       else
65         max = blue;
66 
67       if (green < blue)
68         min = green;
69       else
70         min = blue;
71     }
72   else
73     {
74       if (green > blue)
75         max = green;
76       else
77         max = blue;
78 
79       if (red < blue)
80         min = red;
81       else
82         min = blue;
83     }
84 
85   hsla->lightness = (max + min) / 2;
86   hsla->saturation = 0;
87   hsla->hue = 0;
88   hsla->alpha = rgba->alpha;
89 
90   if (max != min)
91     {
92       if (hsla->lightness <= 0.5)
93         hsla->saturation = (max - min) / (max + min);
94       else
95         hsla->saturation = (max - min) / (2 - max - min);
96 
97       delta = max -min;
98       if (red == max)
99         hsla->hue = (green - blue) / delta;
100       else if (green == max)
101         hsla->hue = 2 + (blue - red) / delta;
102       else if (blue == max)
103         hsla->hue = 4 + (red - green) / delta;
104 
105       hsla->hue *= 60;
106       if (hsla->hue < 0.0)
107         hsla->hue += 360;
108     }
109 }
110 
111 void
_gdk_rgba_init_from_hsla(GdkRGBA * rgba,const GtkHSLA * hsla)112 _gdk_rgba_init_from_hsla (GdkRGBA       *rgba,
113                           const GtkHSLA *hsla)
114 {
115   gdouble hue;
116   gdouble lightness;
117   gdouble saturation;
118   gdouble m1, m2;
119 
120   lightness = hsla->lightness;
121   saturation = hsla->saturation;
122 
123   if (lightness <= 0.5)
124     m2 = lightness * (1 + saturation);
125   else
126     m2 = lightness + saturation - lightness * saturation;
127   m1 = 2 * lightness - m2;
128 
129   rgba->alpha = hsla->alpha;
130 
131   if (saturation == 0)
132     {
133       rgba->red = lightness;
134       rgba->green = lightness;
135       rgba->blue = lightness;
136     }
137   else
138     {
139       hue = hsla->hue + 120;
140       while (hue > 360)
141         hue -= 360;
142       while (hue < 0)
143         hue += 360;
144 
145       if (hue < 60)
146         rgba->red = m1 + (m2 - m1) * hue / 60;
147       else if (hue < 180)
148         rgba->red = m2;
149       else if (hue < 240)
150         rgba->red = m1 + (m2 - m1) * (240 - hue) / 60;
151       else
152         rgba->red = m1;
153 
154       hue = hsla->hue;
155       while (hue > 360)
156         hue -= 360;
157       while (hue < 0)
158         hue += 360;
159 
160       if (hue < 60)
161         rgba->green = m1 + (m2 - m1) * hue / 60;
162       else if (hue < 180)
163         rgba->green = m2;
164       else if (hue < 240)
165         rgba->green = m1 + (m2 - m1) * (240 - hue) / 60;
166       else
167         rgba->green = m1;
168 
169       hue = hsla->hue - 120;
170       while (hue > 360)
171         hue -= 360;
172       while (hue < 0)
173         hue += 360;
174 
175       if (hue < 60)
176         rgba->blue = m1 + (m2 - m1) * hue / 60;
177       else if (hue < 180)
178         rgba->blue = m2;
179       else if (hue < 240)
180         rgba->blue = m1 + (m2 - m1) * (240 - hue) / 60;
181       else
182         rgba->blue = m1;
183     }
184 }
185 
186 void
_gtk_hsla_shade(GtkHSLA * dest,const GtkHSLA * src,double factor)187 _gtk_hsla_shade (GtkHSLA       *dest,
188                  const GtkHSLA *src,
189                  double         factor)
190 {
191   g_return_if_fail (dest != NULL);
192   g_return_if_fail (src != NULL);
193 
194   dest->hue = src->hue;
195 
196   dest->lightness = src->lightness * factor;
197   dest->lightness = CLAMP (dest->lightness, 0.0, 1.0);
198 
199   dest->saturation = src->saturation * factor;
200   dest->saturation = CLAMP (dest->saturation, 0.0, 1.0);
201 
202   dest->alpha = src->alpha;
203 }
204