]> Pileus Git - ~andy/gtk/blob - gdk/gdkrgba.c
gdk: Constify argument to gdk_rgba_copy()
[~andy/gtk] / gdk / gdkrgba.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
25  */
26
27 #include "config.h"
28 #include "gdkrgba.h"
29 #include <string.h>
30
31 /**
32  * SECTION:rgba_colors
33  * @Short_description: RGBA colors
34  * @Title: RGBA Colors
35  */
36
37 G_DEFINE_BOXED_TYPE (GdkRGBA, gdk_rgba,
38                      gdk_rgba_copy, gdk_rgba_free)
39
40 /**
41  * gdk_rgba_copy:
42  * @rgba: a #GdkRGBA
43  *
44  * Makes a copy of a #GdkRGBA structure, the result must be freed
45  * through gdk_rgba_free().
46  *
47  * Returns: A newly allocated #GdkRGBA
48  *
49  * Since: 3.0
50  **/
51 GdkRGBA *
52 gdk_rgba_copy (const GdkRGBA *rgba)
53 {
54   GdkRGBA *copy;
55
56   copy = g_slice_new (GdkRGBA);
57   copy->red = rgba->red;
58   copy->green = rgba->green;
59   copy->blue = rgba->blue;
60   copy->alpha = rgba->alpha;
61
62   return copy;
63 }
64
65 /**
66  * gdk_rgba_free:
67  * @rgba: a #GdkRGBA
68  *
69  * Frees a #GdkRGBA struct created with gdk_rgba_copy()
70  *
71  * Since: 3.0
72  **/
73 void
74 gdk_rgba_free (GdkRGBA *rgba)
75 {
76   g_slice_free (GdkRGBA, rgba);
77 }
78
79 #define SKIP_WHITESPACES(s) while (*(s) == ' ') (s)++;
80
81 /* Parses a single color component from a rgb() or rgba() specification
82  * according to CSS3 rules. Compared to exact CSS3 parsing we are liberal
83  * in what we accept as follows:
84  *
85  *  - For non-percentage values, we accept floats in the range 0-255
86  *    not just [0-9]+ integers
87  *  - For percentage values we accept any float, not just
88  *     [ 0-9]+ | [0-9]* '.' [0-9]+
89  *  - We accept mixed percentages and non-percentages in a single
90  *    rgb() or rgba() specification.
91  */
92 static double
93 parse_rgb_value (const char  *str,
94                  char       **endp)
95 {
96   double number;
97   const char *p;
98
99   number = g_ascii_strtod (str, endp);
100
101   p = *endp;
102
103   SKIP_WHITESPACES (p);
104
105   if (*p == '%')
106     {
107       *endp = (char *)(p + 1);
108       return CLAMP(number / 100., 0., 1.);
109     }
110   else
111     {
112       return CLAMP(number / 255., 0., 1.);
113     }
114 }
115
116 /**
117  * gdk_rgba_parse:
118  * @rgba: the #GdkRGBA struct to fill in
119  * @spec: the string specifying the color
120  *
121  * Parses a textual representation of a color, filling in
122  * the <structfield>red</structfield>, <structfield>green</structfield>,
123  * <structfield>blue</structfield> and <structfield>alpha</structfield>
124  * fields of the @rgba struct.
125  *
126  * The string can be either one of:
127  * <itemizedlist>
128  * <listitem>
129  * A standard name (Taken from the X11 rgb.txt file).
130  * </listitem>
131  * <listitem>
132  * A hex value in the form '#rgb' '#rrggbb' '#rrrgggbbb' or '#rrrrggggbbbb'
133  * </listitem>
134  * <listitem>
135  * A RGB color in the form 'rgb(r,g,b)' (In this case the color will
136  * have full opacity)
137  * </listitem>
138  * <listitem>
139  * A RGBA color in the form 'rgba(r,g,b,a)'
140  * </listitem>
141  * </itemizedlist>
142  *
143  * Where 'r', 'g', 'b' and 'a' are respectively the red, green, blue and
144  * alpha color values. In the last two cases, r g and b are either integers
145  * in the range 0 to 255 or precentage values in the range 0% to 100%, and
146  * a is a floating point value in the range 0 to 1.
147  *
148  * Returns: %TRUE if the parsing succeeded
149  *
150  * Since: 3.0
151  **/
152 gboolean
153 gdk_rgba_parse (GdkRGBA     *rgba,
154                 const gchar *spec)
155 {
156   gboolean has_alpha;
157   gdouble r, g, b, a;
158   gchar *str = (gchar *) spec;
159
160   if (strncmp (str, "rgba", 4) == 0)
161     {
162       has_alpha = TRUE;
163       str += 4;
164     }
165   else if (strncmp (str, "rgb", 3) == 0)
166     {
167       has_alpha = FALSE;
168       a = 1;
169       str += 3;
170     }
171   else
172     {
173       PangoColor pango_color;
174
175       /* Resort on PangoColor for rgb.txt color
176        * map and '#' prefixed colors */
177       if (pango_color_parse (&pango_color, str))
178         {
179           if (rgba)
180             {
181               rgba->red = pango_color.red / 65535.;
182               rgba->green = pango_color.green / 65535.;
183               rgba->blue = pango_color.blue / 65535.;
184               rgba->alpha = 1;
185             }
186
187           return TRUE;
188         }
189       else
190         return FALSE;
191     }
192
193   SKIP_WHITESPACES (str);
194
195   if (*str != '(')
196     return FALSE;
197
198   str++;
199
200   /* Parse red */
201   SKIP_WHITESPACES (str);
202   r = parse_rgb_value (str, &str);
203   SKIP_WHITESPACES (str);
204
205   if (*str != ',')
206     return FALSE;
207
208   str++;
209
210   /* Parse green */
211   SKIP_WHITESPACES (str);
212   g = parse_rgb_value (str, &str);
213   SKIP_WHITESPACES (str);
214
215   if (*str != ',')
216     return FALSE;
217
218   str++;
219
220   /* Parse blue */
221   SKIP_WHITESPACES (str);
222   b = parse_rgb_value (str, &str);
223   SKIP_WHITESPACES (str);
224
225   if (has_alpha)
226     {
227       if (*str != ',')
228         return FALSE;
229
230       str++;
231
232       SKIP_WHITESPACES (str);
233       a = g_ascii_strtod (str, &str);
234       SKIP_WHITESPACES (str);
235     }
236
237   if (*str != ')')
238     return FALSE;
239
240   if (rgba)
241     {
242       rgba->red = CLAMP (r, 0, 1);
243       rgba->green = CLAMP (g, 0, 1);
244       rgba->blue = CLAMP (b, 0, 1);
245       rgba->alpha = CLAMP (a, 0, 1);
246     }
247
248   return TRUE;
249 }
250
251 #undef SKIP_WHITESPACES
252
253 /**
254  * gdk_rgba_hash:
255  * @p: a #GdkRGBA pointer.
256  *
257  * A hash function suitable for using for a hash
258  * table that stores #GdkRGBA<!-- -->s.
259  *
260  * Return value: The hash function applied to @p
261  *
262  * Since: 3.0
263  **/
264 guint
265 gdk_rgba_hash (gconstpointer p)
266 {
267   const GdkRGBA *rgba = p;
268
269   return ((guint) (rgba->red * 65535) +
270           ((guint) (rgba->green * 65535) << 11) +
271           ((guint) (rgba->blue * 65535) << 22) +
272           ((guint) (rgba->alpha * 65535) >> 6));
273 }
274
275 /**
276  * gdk_rgba_equal:
277  * @p1: a #GdkRGBA pointer.
278  * @p2: another #GdkRGBA pointer.
279  *
280  * Compares two RGBA colors.
281  *
282  * Return value: %TRUE if the two colors compare equal
283  *
284  * Since: 3.0
285  **/
286 gboolean
287 gdk_rgba_equal (gconstpointer p1,
288                 gconstpointer p2)
289 {
290   const GdkRGBA *rgba1, *rgba2;
291
292   rgba1 = p1;
293   rgba2 = p2;
294
295   if (rgba1->red == rgba2->red &&
296       rgba1->green == rgba2->green &&
297       rgba1->blue == rgba2->blue &&
298       rgba1->alpha == rgba2->alpha)
299     return TRUE;
300
301   return FALSE;
302 }
303
304 /**
305  * gdk_rgba_to_string:
306  * @rgba: a #GdkRGBA
307  *
308  * Returns a textual specification of @rgba in the form <literal>rgb
309  * (r, g, b)</literal> or <literal>rgba (r, g, b, a)</literal>,
310  * where 'r', 'g', 'b' and 'a' represent the red, green, blue and alpha values
311  * respectively. r, g, and b are integers in the range 0 to 255, and a
312  * is a floating point value in the range 0 to 1.
313  *
314  * (These string forms are string forms those supported by the CSS3 colors module)
315  *
316  * Returns: A newly allocated text string
317  *
318  * Since: 3.0
319  **/
320 gchar *
321 gdk_rgba_to_string (const GdkRGBA *rgba)
322 {
323   if (rgba->alpha > 0.999)
324     {
325       return g_strdup_printf ("rgb(%d,%d,%d)",
326                               (int)(0.5 + CLAMP (rgba->red, 0., 1.) * 255.),
327                               (int)(0.5 + CLAMP (rgba->green, 0., 1.) * 255.),
328                               (int)(0.5 + CLAMP (rgba->blue, 0., 1.) * 255.));
329     }
330   else
331     {
332       gchar alpha[G_ASCII_DTOSTR_BUF_SIZE];
333
334       g_ascii_dtostr (alpha, G_ASCII_DTOSTR_BUF_SIZE, CLAMP (rgba->alpha, 0, 1));
335
336       return g_strdup_printf ("rgba(%d,%d,%d,%s)",
337                               (int)(0.5 + CLAMP (rgba->red, 0., 1.) * 255.),
338                               (int)(0.5 + CLAMP (rgba->green, 0., 1.) * 255.),
339                               (int)(0.5 + CLAMP (rgba->blue, 0., 1.) * 255.),
340                               alpha);
341     }
342 }