]> Pileus Git - ~andy/gtk/blob - gtk/gtksymboliccolor.c
Use named union for _GtkSymbolicColor in gtk/gtksymboliccolor.c
[~andy/gtk] / gtk / gtksymboliccolor.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2010 Carlos Garnacho <carlosg@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 #include "gtkcssrgbavalueprivate.h"
20 #include "gtkcssstylepropertyprivate.h"
21 #include "gtkstylepropertyprivate.h"
22 #include "gtksymboliccolorprivate.h"
23 #include "gtkstyleproperties.h"
24 #include "gtkintl.h"
25 #include "gtkwin32themeprivate.h"
26
27 /**
28  * SECTION:gtksymboliccolor
29  * @Short_description: Symbolic colors
30  * @Title: GtkSymbolicColor
31  *
32  * GtkSymbolicColor is a boxed type that represents a symbolic color.
33  * It is the result of parsing a
34  * <link linkend="gtkcssprovider-symbolic-colors">color expression</link>.
35  * To obtain the color represented by a GtkSymbolicColor, it has to
36  * be resolved with gtk_symbolic_color_resolve(), which replaces all
37  * symbolic color references by the colors they refer to (in a given
38  * context) and evaluates mix, shade and other expressions, resulting
39  * in a #GdkRGBA value.
40  *
41  * It is not normally necessary to deal directly with #GtkSymbolicColors,
42  * since they are mostly used behind the scenes by #GtkStyleContext and
43  * #GtkCssProvider.
44  */
45
46 G_DEFINE_BOXED_TYPE (GtkSymbolicColor, gtk_symbolic_color,
47                      gtk_symbolic_color_ref, gtk_symbolic_color_unref)
48
49 /* Symbolic colors */
50 typedef enum {
51   COLOR_TYPE_LITERAL,
52   COLOR_TYPE_NAME,
53   COLOR_TYPE_SHADE,
54   COLOR_TYPE_ALPHA,
55   COLOR_TYPE_MIX,
56   COLOR_TYPE_WIN32,
57   COLOR_TYPE_CURRENT_COLOR
58 } ColorType;
59
60 struct _GtkSymbolicColor
61 {
62   GTK_CSS_VALUE_BASE
63   ColorType type;
64   GtkCssValue *last_value;
65
66   union
67   {
68     gchar *name;
69
70     struct
71     {
72       GtkSymbolicColor *color;
73       gdouble factor;
74     } shade, alpha;
75
76     struct
77     {
78       GtkSymbolicColor *color1;
79       GtkSymbolicColor *color2;
80       gdouble factor;
81     } mix;
82
83     struct
84     {
85       gchar *theme_class;
86       gint id;
87     } win32;
88   } sym_col;
89 };
90
91 static void
92 gtk_css_value_symbolic_free (GtkCssValue *value)
93 {
94   GtkSymbolicColor *color = (GtkSymbolicColor *) value;
95
96   _gtk_css_value_unref (color->last_value);
97   switch (color->type)
98     {
99     case COLOR_TYPE_NAME:
100       g_free (color->sym_col.name);
101       break;
102     case COLOR_TYPE_SHADE:
103       gtk_symbolic_color_unref (color->sym_col.shade.color);
104       break;
105     case COLOR_TYPE_ALPHA:
106       gtk_symbolic_color_unref (color->sym_col.alpha.color);
107       break;
108     case COLOR_TYPE_MIX:
109       gtk_symbolic_color_unref (color->sym_col.mix.color1);
110       gtk_symbolic_color_unref (color->sym_col.mix.color2);
111       break;
112     case COLOR_TYPE_WIN32:
113       g_free (color->sym_col.win32.theme_class);
114       break;
115     default:
116       break;
117     }
118
119   g_slice_free (GtkSymbolicColor, color);
120 }
121
122 static GtkCssValue *
123 gtk_css_value_symbolic_get_fallback (guint                    property_id,
124                                      GtkStyleProviderPrivate *provider,
125                                      GtkCssComputedValues    *values,
126                                      GtkCssComputedValues    *parent_values)
127 {
128   static const GdkRGBA transparent = { 0, 0, 0, 0 };
129
130   switch (property_id)
131     {
132       case GTK_CSS_PROPERTY_BACKGROUND_IMAGE:
133       case GTK_CSS_PROPERTY_BORDER_IMAGE_SOURCE:
134       case GTK_CSS_PROPERTY_TEXT_SHADOW:
135       case GTK_CSS_PROPERTY_ICON_SHADOW:
136       case GTK_CSS_PROPERTY_BOX_SHADOW:
137         return _gtk_css_rgba_value_new_from_rgba (&transparent);
138       case GTK_CSS_PROPERTY_COLOR:
139       case GTK_CSS_PROPERTY_BACKGROUND_COLOR:
140       case GTK_CSS_PROPERTY_BORDER_TOP_COLOR:
141       case GTK_CSS_PROPERTY_BORDER_RIGHT_COLOR:
142       case GTK_CSS_PROPERTY_BORDER_BOTTOM_COLOR:
143       case GTK_CSS_PROPERTY_BORDER_LEFT_COLOR:
144       case GTK_CSS_PROPERTY_OUTLINE_COLOR:
145         return _gtk_css_value_compute (_gtk_css_style_property_get_initial_value (_gtk_css_style_property_lookup_by_id (property_id)),
146                                        property_id,
147                                        provider,
148                                        values,
149                                        parent_values,
150                                        NULL);
151       default:
152         if (property_id < GTK_CSS_PROPERTY_N_PROPERTIES)
153           g_warning ("No fallback color defined for property '%s'", 
154                      _gtk_style_property_get_name (GTK_STYLE_PROPERTY (_gtk_css_style_property_lookup_by_id (property_id))));
155         return _gtk_css_rgba_value_new_from_rgba (&transparent);
156     }
157 }
158
159 static GtkCssValue *
160 gtk_css_value_symbolic_compute (GtkCssValue             *value,
161                                 guint                    property_id,
162                                 GtkStyleProviderPrivate *provider,
163                                 GtkCssComputedValues    *values,
164                                 GtkCssComputedValues    *parent_values,
165                                 GtkCssDependencies      *dependencies)
166 {
167   GtkCssValue *resolved, *current;
168   GtkCssDependencies current_deps;
169
170   /* The computed value of the ‘currentColor’ keyword is the computed
171    * value of the ‘color’ property. If the ‘currentColor’ keyword is
172    * set on the ‘color’ property itself, it is treated as ‘color: inherit’. 
173    */
174   if (property_id == GTK_CSS_PROPERTY_COLOR)
175     {
176       if (parent_values)
177         {
178           current = _gtk_css_computed_values_get_value (parent_values, GTK_CSS_PROPERTY_COLOR);
179           current_deps = GTK_CSS_EQUALS_PARENT;
180         }
181       else
182         {
183           current = _gtk_css_style_property_get_initial_value (_gtk_css_style_property_lookup_by_id (GTK_CSS_PROPERTY_COLOR));
184           current_deps = 0;
185         }
186     }
187   else
188     {
189       current = _gtk_css_computed_values_get_value (values, GTK_CSS_PROPERTY_COLOR);
190       current_deps = GTK_CSS_DEPENDS_ON_COLOR;
191     }
192   
193   resolved = _gtk_symbolic_color_resolve_full ((GtkSymbolicColor *) value,
194                                                provider,
195                                                current,
196                                                current_deps,
197                                                dependencies);
198
199   if (resolved == NULL)
200     return gtk_css_value_symbolic_get_fallback (property_id, provider, values, parent_values);
201
202   return resolved;
203 }
204
205 static gboolean
206 gtk_css_value_symbolic_equal (const GtkCssValue *value1,
207                               const GtkCssValue *value2)
208 {
209   GtkSymbolicColor *color1 = (GtkSymbolicColor *) value1;
210   GtkSymbolicColor *color2 = (GtkSymbolicColor *) value2;
211
212   if (color1->type != color2->type)
213     return FALSE;
214
215   switch (color1->type)
216     {
217     case COLOR_TYPE_LITERAL:
218       return _gtk_css_value_equal (color1->last_value, color2->last_value);
219     case COLOR_TYPE_NAME:
220       return g_str_equal (color1->sym_col.name, color2->sym_col.name);
221     case COLOR_TYPE_SHADE:
222       return color1->sym_col.shade.factor == color2->sym_col.shade.factor &&
223              _gtk_css_value_equal ((GtkCssValue *) color1->sym_col.shade.color,
224                                    (GtkCssValue *) color2->sym_col.shade.color);
225     case COLOR_TYPE_ALPHA:
226       return color1->sym_col.alpha.factor == color2->sym_col.alpha.factor &&
227              _gtk_css_value_equal ((GtkCssValue *) color1->sym_col.alpha.color,
228                                    (GtkCssValue *) color2->sym_col.alpha.color);
229     case COLOR_TYPE_MIX:
230       return color1->sym_col.mix.factor == color2->sym_col.mix.factor &&
231              _gtk_css_value_equal ((GtkCssValue *) color1->sym_col.mix.color1,
232                                    (GtkCssValue *) color2->sym_col.mix.color1) &&
233              _gtk_css_value_equal ((GtkCssValue *) color1->sym_col.mix.color2,
234                                    (GtkCssValue *) color2->sym_col.mix.color2);
235     case COLOR_TYPE_WIN32:
236       return g_str_equal (color1->sym_col.win32.theme_class, color2->sym_col.win32.theme_class) &&
237              color1->sym_col.win32.id == color2->sym_col.win32.id;
238     case COLOR_TYPE_CURRENT_COLOR:
239       return TRUE;
240     default:
241       g_assert_not_reached ();
242       return FALSE;
243     }
244 }
245
246 static GtkCssValue *
247 gtk_css_value_symbolic_transition (GtkCssValue *start,
248                                    GtkCssValue *end,
249                                    guint        property_id,
250                                    double       progress)
251 {
252   return (GtkCssValue *) gtk_symbolic_color_new_mix ((GtkSymbolicColor *) start,
253                                                      (GtkSymbolicColor *) end,
254                                                      progress);
255 }
256
257 static void
258 gtk_css_value_symbolic_print (const GtkCssValue *value,
259                               GString           *string)
260 {
261   GtkSymbolicColor *color = (GtkSymbolicColor *) value;
262   char *s;
263   
264   s = gtk_symbolic_color_to_string (color);
265   g_string_append (string, s);
266   g_free (s);
267 }
268
269 static const GtkCssValueClass GTK_CSS_VALUE_SYMBOLIC = {
270   gtk_css_value_symbolic_free,
271   gtk_css_value_symbolic_compute,
272   gtk_css_value_symbolic_equal,
273   gtk_css_value_symbolic_transition,
274   gtk_css_value_symbolic_print
275 };
276
277 /**
278  * gtk_symbolic_color_new_literal:
279  * @color: a #GdkRGBA
280  *
281  * Creates a symbolic color pointing to a literal color.
282  *
283  * Returns: a newly created #GtkSymbolicColor
284  *
285  * Since: 3.0
286  **/
287 GtkSymbolicColor *
288 gtk_symbolic_color_new_literal (const GdkRGBA *color)
289 {
290   GtkSymbolicColor *symbolic_color;
291
292   g_return_val_if_fail (color != NULL, NULL);
293
294   symbolic_color = _gtk_css_value_new (GtkSymbolicColor, &GTK_CSS_VALUE_SYMBOLIC);
295   symbolic_color->type = COLOR_TYPE_LITERAL;
296   symbolic_color->last_value = _gtk_css_rgba_value_new_from_rgba (color);
297
298   return symbolic_color;
299 }
300
301 /**
302  * gtk_symbolic_color_new_name:
303  * @name: color name
304  *
305  * Creates a symbolic color pointing to an unresolved named
306  * color. See gtk_style_context_lookup_color() and
307  * gtk_style_properties_lookup_color().
308  *
309  * Returns: a newly created #GtkSymbolicColor
310  *
311  * Since: 3.0
312  **/
313 GtkSymbolicColor *
314 gtk_symbolic_color_new_name (const gchar *name)
315 {
316   GtkSymbolicColor *symbolic_color;
317
318   g_return_val_if_fail (name != NULL, NULL);
319
320   symbolic_color = _gtk_css_value_new (GtkSymbolicColor, &GTK_CSS_VALUE_SYMBOLIC);
321   symbolic_color->type = COLOR_TYPE_NAME;
322   symbolic_color->sym_col.name = g_strdup (name);
323
324   return symbolic_color;
325 }
326
327 /**
328  * gtk_symbolic_color_new_shade: (constructor)
329  * @color: another #GtkSymbolicColor
330  * @factor: shading factor to apply to @color
331  *
332  * Creates a symbolic color defined as a shade of
333  * another color. A factor > 1.0 would resolve to
334  * a brighter color, while < 1.0 would resolve to
335  * a darker color.
336  *
337  * Returns: A newly created #GtkSymbolicColor
338  *
339  * Since: 3.0
340  **/
341 GtkSymbolicColor *
342 gtk_symbolic_color_new_shade (GtkSymbolicColor *color,
343                               gdouble           factor)
344 {
345   GtkSymbolicColor *symbolic_color;
346
347   g_return_val_if_fail (color != NULL, NULL);
348
349   symbolic_color = _gtk_css_value_new (GtkSymbolicColor, &GTK_CSS_VALUE_SYMBOLIC);
350   symbolic_color->type = COLOR_TYPE_SHADE;
351   symbolic_color->sym_col.shade.color = gtk_symbolic_color_ref (color);
352   symbolic_color->sym_col.shade.factor = factor;
353
354   return symbolic_color;
355 }
356
357 /**
358  * gtk_symbolic_color_new_alpha: (constructor)
359  * @color: another #GtkSymbolicColor
360  * @factor: factor to apply to @color alpha
361  *
362  * Creates a symbolic color by modifying the relative alpha
363  * value of @color. A factor < 1.0 would resolve to a more
364  * transparent color, while > 1.0 would resolve to a more
365  * opaque color.
366  *
367  * Returns: A newly created #GtkSymbolicColor
368  *
369  * Since: 3.0
370  **/
371 GtkSymbolicColor *
372 gtk_symbolic_color_new_alpha (GtkSymbolicColor *color,
373                               gdouble           factor)
374 {
375   GtkSymbolicColor *symbolic_color;
376
377   g_return_val_if_fail (color != NULL, NULL);
378
379   symbolic_color = _gtk_css_value_new (GtkSymbolicColor, &GTK_CSS_VALUE_SYMBOLIC);
380   symbolic_color->type = COLOR_TYPE_ALPHA;
381   symbolic_color->sym_col.alpha.color = gtk_symbolic_color_ref (color);
382   symbolic_color->sym_col.alpha.factor = factor;
383
384   return symbolic_color;
385 }
386
387 /**
388  * gtk_symbolic_color_new_mix: (constructor)
389  * @color1: color to mix
390  * @color2: another color to mix
391  * @factor: mix factor
392  *
393  * Creates a symbolic color defined as a mix of another
394  * two colors. a mix factor of 0 would resolve to @color1,
395  * while a factor of 1 would resolve to @color2.
396  *
397  * Returns: A newly created #GtkSymbolicColor
398  *
399  * Since: 3.0
400  **/
401 GtkSymbolicColor *
402 gtk_symbolic_color_new_mix (GtkSymbolicColor *color1,
403                             GtkSymbolicColor *color2,
404                             gdouble           factor)
405 {
406   GtkSymbolicColor *symbolic_color;
407
408   g_return_val_if_fail (color1 != NULL, NULL);
409   g_return_val_if_fail (color1 != NULL, NULL);
410
411   symbolic_color = _gtk_css_value_new (GtkSymbolicColor, &GTK_CSS_VALUE_SYMBOLIC);
412   symbolic_color->type = COLOR_TYPE_MIX;
413   symbolic_color->sym_col.mix.color1 = gtk_symbolic_color_ref (color1);
414   symbolic_color->sym_col.mix.color2 = gtk_symbolic_color_ref (color2);
415   symbolic_color->sym_col.mix.factor = factor;
416
417   return symbolic_color;
418 }
419
420 /**
421  * gtk_symbolic_color_new_win32: (constructor)
422  * @theme_class: The theme class to pull color from
423  * @id: The color id
424  *
425  * Creates a symbolic color based on the current win32
426  * theme.
427  *
428  * Note that while this call is available on all platforms
429  * the actual value returned is not reliable on non-win32
430  * platforms.
431  *
432  * Returns: A newly created #GtkSymbolicColor
433  *
434  * Since: 3.4
435  */
436 GtkSymbolicColor *
437 gtk_symbolic_color_new_win32 (const gchar *theme_class,
438                               gint         id)
439 {
440   GtkSymbolicColor *symbolic_color;
441
442   g_return_val_if_fail (theme_class != NULL, NULL);
443
444   symbolic_color = _gtk_css_value_new (GtkSymbolicColor, &GTK_CSS_VALUE_SYMBOLIC);
445   symbolic_color->type = COLOR_TYPE_WIN32;
446   symbolic_color->sym_col.win32.theme_class = g_strdup (theme_class);
447   symbolic_color->sym_col.win32.id = id;
448
449   return symbolic_color;
450 }
451
452 /**
453  * _gtk_symbolic_color_get_current_color:
454  *
455  * Gets the color representing the CSS 'currentColor' keyword.
456  * This color will resolve to the color set for the color property.
457  *
458  * Returns: (transfer none): The singleton representing the
459  *     'currentColor' keyword
460  **/
461 GtkSymbolicColor *
462 _gtk_symbolic_color_get_current_color (void)
463 {
464   static GtkSymbolicColor *current_color = NULL;
465
466   if (G_UNLIKELY (current_color == NULL))
467     {
468       current_color = _gtk_css_value_new (GtkSymbolicColor, &GTK_CSS_VALUE_SYMBOLIC);
469       current_color->type = COLOR_TYPE_CURRENT_COLOR;
470     }
471
472   return current_color;
473 }
474
475 /**
476  * gtk_symbolic_color_ref:
477  * @color: a #GtkSymbolicColor
478  *
479  * Increases the reference count of @color
480  *
481  * Returns: the same @color
482  *
483  * Since: 3.0
484  **/
485 GtkSymbolicColor *
486 gtk_symbolic_color_ref (GtkSymbolicColor *color)
487 {
488   g_return_val_if_fail (color != NULL, NULL);
489
490   _gtk_css_value_ref ((GtkCssValue *) color);
491
492   return color;
493 }
494
495 /**
496  * gtk_symbolic_color_unref:
497  * @color: a #GtkSymbolicColor
498  *
499  * Decreases the reference count of @color, freeing its memory if the
500  * reference count reaches 0.
501  *
502  * Since: 3.0
503  **/
504 void
505 gtk_symbolic_color_unref (GtkSymbolicColor *color)
506 {
507   g_return_if_fail (color != NULL);
508
509   _gtk_css_value_unref ((GtkCssValue *) color);
510 }
511
512 static void
513 rgb_to_hls (gdouble *r,
514             gdouble *g,
515             gdouble *b)
516 {
517   gdouble min;
518   gdouble max;
519   gdouble red;
520   gdouble green;
521   gdouble blue;
522   gdouble h, l, s;
523   gdouble delta;
524   
525   red = *r;
526   green = *g;
527   blue = *b;
528   
529   if (red > green)
530     {
531       if (red > blue)
532         max = red;
533       else
534         max = blue;
535       
536       if (green < blue)
537         min = green;
538       else
539         min = blue;
540     }
541   else
542     {
543       if (green > blue)
544         max = green;
545       else
546         max = blue;
547       
548       if (red < blue)
549         min = red;
550       else
551         min = blue;
552     }
553   
554   l = (max + min) / 2;
555   s = 0;
556   h = 0;
557   
558   if (max != min)
559     {
560       if (l <= 0.5)
561         s = (max - min) / (max + min);
562       else
563         s = (max - min) / (2 - max - min);
564       
565       delta = max -min;
566       if (red == max)
567         h = (green - blue) / delta;
568       else if (green == max)
569         h = 2 + (blue - red) / delta;
570       else if (blue == max)
571         h = 4 + (red - green) / delta;
572       
573       h *= 60;
574       if (h < 0.0)
575         h += 360;
576     }
577   
578   *r = h;
579   *g = l;
580   *b = s;
581 }
582
583 static void
584 hls_to_rgb (gdouble *h,
585             gdouble *l,
586             gdouble *s)
587 {
588   gdouble hue;
589   gdouble lightness;
590   gdouble saturation;
591   gdouble m1, m2;
592   gdouble r, g, b;
593   
594   lightness = *l;
595   saturation = *s;
596   
597   if (lightness <= 0.5)
598     m2 = lightness * (1 + saturation);
599   else
600     m2 = lightness + saturation - lightness * saturation;
601   m1 = 2 * lightness - m2;
602   
603   if (saturation == 0)
604     {
605       *h = lightness;
606       *l = lightness;
607       *s = lightness;
608     }
609   else
610     {
611       hue = *h + 120;
612       while (hue > 360)
613         hue -= 360;
614       while (hue < 0)
615         hue += 360;
616       
617       if (hue < 60)
618         r = m1 + (m2 - m1) * hue / 60;
619       else if (hue < 180)
620         r = m2;
621       else if (hue < 240)
622         r = m1 + (m2 - m1) * (240 - hue) / 60;
623       else
624         r = m1;
625       
626       hue = *h;
627       while (hue > 360)
628         hue -= 360;
629       while (hue < 0)
630         hue += 360;
631       
632       if (hue < 60)
633         g = m1 + (m2 - m1) * hue / 60;
634       else if (hue < 180)
635         g = m2;
636       else if (hue < 240)
637         g = m1 + (m2 - m1) * (240 - hue) / 60;
638       else
639         g = m1;
640       
641       hue = *h - 120;
642       while (hue > 360)
643         hue -= 360;
644       while (hue < 0)
645         hue += 360;
646       
647       if (hue < 60)
648         b = m1 + (m2 - m1) * hue / 60;
649       else if (hue < 180)
650         b = m2;
651       else if (hue < 240)
652         b = m1 + (m2 - m1) * (240 - hue) / 60;
653       else
654         b = m1;
655       
656       *h = r;
657       *l = g;
658       *s = b;
659     }
660 }
661
662 static void
663 _shade_color (GdkRGBA *color,
664               gdouble  factor)
665 {
666   GdkRGBA temp;
667
668   temp = *color;
669   rgb_to_hls (&temp.red, &temp.green, &temp.blue);
670
671   temp.green *= factor;
672   if (temp.green > 1.0)
673     temp.green = 1.0;
674   else if (temp.green < 0.0)
675     temp.green = 0.0;
676
677   temp.blue *= factor;
678   if (temp.blue > 1.0)
679     temp.blue = 1.0;
680   else if (temp.blue < 0.0)
681     temp.blue = 0.0;
682
683   hls_to_rgb (&temp.red, &temp.green, &temp.blue);
684   *color = temp;
685 }
686
687 /**
688  * gtk_symbolic_color_resolve:
689  * @color: a #GtkSymbolicColor
690  * @props: (allow-none): #GtkStyleProperties to use when resolving
691  *    named colors, or %NULL
692  * @resolved_color: (out): return location for the resolved color
693  *
694  * If @color is resolvable, @resolved_color will be filled in
695  * with the resolved color, and %TRUE will be returned. Generally,
696  * if @color can't be resolved, it is due to it being defined on
697  * top of a named color that doesn't exist in @props.
698  *
699  * When @props is %NULL, resolving of named colors will fail, so if
700  * your @color is or references such a color, this function will
701  * return %FALSE.
702  *
703  * Returns: %TRUE if the color has been resolved
704  *
705  * Since: 3.0
706  **/
707 gboolean
708 gtk_symbolic_color_resolve (GtkSymbolicColor   *color,
709                             GtkStyleProperties *props,
710                             GdkRGBA            *resolved_color)
711 {
712   GdkRGBA pink = { 1.0, 0.5, 0.5, 1.0 };
713   GtkCssValue *v, *current;
714
715   g_return_val_if_fail (color != NULL, FALSE);
716   g_return_val_if_fail (resolved_color != NULL, FALSE);
717   g_return_val_if_fail (props == NULL || GTK_IS_STYLE_PROPERTIES (props), FALSE);
718
719   current = _gtk_css_rgba_value_new_from_rgba (&pink);
720   v =_gtk_symbolic_color_resolve_full (color,
721                                        GTK_STYLE_PROVIDER_PRIVATE (props),
722                                        current,
723                                        0,
724                                        NULL);
725   _gtk_css_value_unref (current);
726   if (v == NULL)
727     return FALSE;
728
729   *resolved_color = *_gtk_css_rgba_value_get_rgba (v);
730   _gtk_css_value_unref (v);
731   return TRUE;
732 }
733
734 GtkCssValue *
735 _gtk_symbolic_color_resolve_full (GtkSymbolicColor        *color,
736                                   GtkStyleProviderPrivate *provider,
737                                   GtkCssValue             *current,
738                                   GtkCssDependencies       current_deps,
739                                   GtkCssDependencies      *dependencies)
740 {
741   GtkCssDependencies unused;
742   GtkCssValue *value;
743
744   g_return_val_if_fail (color != NULL, FALSE);
745   g_return_val_if_fail (provider == NULL || GTK_IS_STYLE_PROVIDER_PRIVATE (provider), FALSE);
746   g_return_val_if_fail (current != NULL, FALSE);
747
748   if (dependencies == NULL)
749     dependencies = &unused;
750   *dependencies = 0;
751
752   value = NULL;
753   switch (color->type)
754     {
755     case COLOR_TYPE_LITERAL:
756       return _gtk_css_value_ref (color->last_value);
757     case COLOR_TYPE_NAME:
758       {
759         GtkSymbolicColor *named_color;
760
761         named_color = _gtk_style_provider_private_get_color (provider, color->sym_col.name);
762
763         if (!named_color)
764           return NULL;
765
766         return _gtk_symbolic_color_resolve_full (named_color, provider, current, current_deps, dependencies);
767       }
768
769       break;
770     case COLOR_TYPE_SHADE:
771       {
772         GtkCssValue *val;
773         GdkRGBA shade;
774
775         val = _gtk_symbolic_color_resolve_full (color->sym_col.shade.color, provider, current, current_deps, dependencies);
776         if (val == NULL)
777           return NULL;
778
779         *dependencies = _gtk_css_dependencies_union (*dependencies, 0);
780         shade = *_gtk_css_rgba_value_get_rgba (val);
781         _shade_color (&shade, color->sym_col.shade.factor);
782
783         _gtk_css_value_unref (val);
784
785         value = _gtk_css_rgba_value_new_from_rgba (&shade);
786       }
787
788       break;
789     case COLOR_TYPE_ALPHA:
790       {
791         GtkCssValue *val;
792         GdkRGBA alpha;
793
794         val = _gtk_symbolic_color_resolve_full (color->sym_col.alpha.color, provider, current, current_deps, dependencies);
795         if (val == NULL)
796           return NULL;
797
798         *dependencies = _gtk_css_dependencies_union (*dependencies, 0);
799         alpha = *_gtk_css_rgba_value_get_rgba (val);
800         alpha.alpha = CLAMP (alpha.alpha * color->sym_col.alpha.factor, 0, 1);
801
802         _gtk_css_value_unref (val);
803
804         value = _gtk_css_rgba_value_new_from_rgba (&alpha);
805       }
806       break;
807
808     case COLOR_TYPE_MIX:
809       {
810         GtkCssValue *val;
811         GdkRGBA color1, color2, res;
812         GtkCssDependencies dep1, dep2;
813
814         val = _gtk_symbolic_color_resolve_full (color->sym_col.mix.color1, provider, current, current_deps, &dep1);
815         if (val == NULL)
816           return NULL;
817         color1 = *_gtk_css_rgba_value_get_rgba (val);
818         _gtk_css_value_unref (val);
819
820         val = _gtk_symbolic_color_resolve_full (color->sym_col.mix.color2, provider, current, current_deps, &dep2);
821         if (val == NULL)
822           return NULL;
823         color2 = *_gtk_css_rgba_value_get_rgba (val);
824         _gtk_css_value_unref (val);
825
826         *dependencies = _gtk_css_dependencies_union (dep1, dep2);
827         res.red = CLAMP (color1.red + ((color2.red - color1.red) * color->sym_col.mix.factor), 0, 1);
828         res.green = CLAMP (color1.green + ((color2.green - color1.green) * color->sym_col.mix.factor), 0, 1);
829         res.blue = CLAMP (color1.blue + ((color2.blue - color1.blue) * color->sym_col.mix.factor), 0, 1);
830         res.alpha = CLAMP (color1.alpha + ((color2.alpha - color1.alpha) * color->sym_col.mix.factor), 0, 1);
831
832         value =_gtk_css_rgba_value_new_from_rgba (&res);
833       }
834
835       break;
836     case COLOR_TYPE_WIN32:
837       {
838         GdkRGBA res;
839
840         if (!_gtk_win32_theme_color_resolve (color->sym_col.win32.theme_class,
841                                              color->sym_col.win32.id,
842                                              &res))
843           return NULL;
844
845         value = _gtk_css_rgba_value_new_from_rgba (&res);
846       }
847
848       break;
849     case COLOR_TYPE_CURRENT_COLOR:
850       if (current)
851         {
852           *dependencies = current_deps;
853           return _gtk_css_value_ref (current);
854         }
855       else
856         {
857           return NULL;
858         }
859       break;
860     default:
861       g_assert_not_reached ();
862     }
863
864   if (value != NULL)
865     {
866       if (color->last_value != NULL &&
867           _gtk_css_value_equal (color->last_value, value))
868         {
869           _gtk_css_value_unref (value);
870           value = _gtk_css_value_ref (color->last_value);
871         }
872       else
873         {
874           if (color->last_value != NULL)
875             _gtk_css_value_unref (color->last_value);
876           color->last_value = _gtk_css_value_ref (value);
877         }
878     }
879
880   _gtk_css_rgba_value_get_rgba (value);
881   return value;
882 }
883
884 /**
885  * gtk_symbolic_color_to_string:
886  * @color: color to convert to a string
887  *
888  * Converts the given @color to a string representation. This is useful
889  * both for debugging and for serialization of strings. The format of
890  * the string may change between different versions of GTK, but it is
891  * guaranteed that the GTK css parser is able to read the string and
892  * create the same symbolic color from it.
893  *
894  * Returns: a new string representing @color
895  **/
896 char *
897 gtk_symbolic_color_to_string (GtkSymbolicColor *color)
898 {
899   char *s;
900
901   g_return_val_if_fail (color != NULL, NULL);
902
903   switch (color->type)
904     {
905     case COLOR_TYPE_LITERAL:
906       s = gdk_rgba_to_string (_gtk_css_rgba_value_get_rgba (color->last_value));
907       break;
908     case COLOR_TYPE_NAME:
909       s = g_strconcat ("@", color->sym_col.name, NULL);
910       break;
911     case COLOR_TYPE_SHADE:
912       {
913         char *color_string = gtk_symbolic_color_to_string (color->sym_col.shade.color);
914         char factor[G_ASCII_DTOSTR_BUF_SIZE];
915
916         g_ascii_dtostr (factor, sizeof (factor), color->sym_col.shade.factor);
917         s = g_strdup_printf ("shade (%s, %s)", color_string, factor);
918         g_free (color_string);
919       }
920       break;
921     case COLOR_TYPE_ALPHA:
922       {
923         char *color_string = gtk_symbolic_color_to_string (color->sym_col.shade.color);
924         char factor[G_ASCII_DTOSTR_BUF_SIZE];
925
926         g_ascii_dtostr (factor, sizeof (factor), color->sym_col.alpha.factor);
927         s = g_strdup_printf ("alpha (%s, %s)", color_string, factor);
928         g_free (color_string);
929       }
930       break;
931     case COLOR_TYPE_MIX:
932       {
933         char *color_string1 = gtk_symbolic_color_to_string (color->sym_col.mix.color1);
934         char *color_string2 = gtk_symbolic_color_to_string (color->sym_col.mix.color2);
935         char factor[G_ASCII_DTOSTR_BUF_SIZE];
936
937         g_ascii_dtostr (factor, sizeof (factor), color->sym_col.mix.factor);
938         s = g_strdup_printf ("mix (%s, %s, %s)", color_string1, color_string2, factor);
939         g_free (color_string1);
940         g_free (color_string2);
941       }
942       break;
943     case COLOR_TYPE_WIN32:
944       {
945         s = g_strdup_printf (GTK_WIN32_THEME_SYMBOLIC_COLOR_NAME"(%s, %d)", 
946                              color->sym_col.win32.theme_class, color->sym_col.win32.id);
947       }
948       break;
949     case COLOR_TYPE_CURRENT_COLOR:
950       s = g_strdup ("currentColor");
951       break;
952     default:
953       g_assert_not_reached ();
954     }
955
956   return s;
957 }
958
959 typedef enum {
960   COLOR_RGBA,
961   COLOR_RGB,
962   COLOR_LIGHTER,
963   COLOR_DARKER,
964   COLOR_SHADE,
965   COLOR_ALPHA,
966   COLOR_MIX,
967   COLOR_WIN32
968 } ColorParseType;
969
970 static GtkSymbolicColor * gtk_css_parser_read_symbolic_color (GtkCssParser *parser);
971
972 static GtkSymbolicColor *
973 gtk_css_parser_read_symbolic_color_function (GtkCssParser   *parser,
974                                              ColorParseType  color)
975 {
976   GtkSymbolicColor *symbolic;
977   GtkSymbolicColor *child1, *child2;
978   double value;
979
980   if (!_gtk_css_parser_try (parser, "(", TRUE))
981     {
982       _gtk_css_parser_error (parser, "Missing opening bracket in color definition");
983       return NULL;
984     }
985
986   if (color == COLOR_RGB || color == COLOR_RGBA)
987     {
988       GdkRGBA rgba;
989       double tmp;
990       guint i;
991
992       for (i = 0; i < 3; i++)
993         {
994           if (i > 0 && !_gtk_css_parser_try (parser, ",", TRUE))
995             {
996               _gtk_css_parser_error (parser, "Expected ',' in color definition");
997               return NULL;
998             }
999
1000           if (!_gtk_css_parser_try_double (parser, &tmp))
1001             {
1002               _gtk_css_parser_error (parser, "Invalid number for color value");
1003               return NULL;
1004             }
1005           if (_gtk_css_parser_try (parser, "%", TRUE))
1006             tmp /= 100.0;
1007           else
1008             tmp /= 255.0;
1009           if (i == 0)
1010             rgba.red = tmp;
1011           else if (i == 1)
1012             rgba.green = tmp;
1013           else if (i == 2)
1014             rgba.blue = tmp;
1015           else
1016             g_assert_not_reached ();
1017         }
1018
1019       if (color == COLOR_RGBA)
1020         {
1021           if (i > 0 && !_gtk_css_parser_try (parser, ",", TRUE))
1022             {
1023               _gtk_css_parser_error (parser, "Expected ',' in color definition");
1024               return NULL;
1025             }
1026
1027           if (!_gtk_css_parser_try_double (parser, &rgba.alpha))
1028             {
1029               _gtk_css_parser_error (parser, "Invalid number for alpha value");
1030               return NULL;
1031             }
1032         }
1033       else
1034         rgba.alpha = 1.0;
1035       
1036       symbolic = gtk_symbolic_color_new_literal (&rgba);
1037     }
1038   else if (color == COLOR_WIN32)
1039     {
1040       symbolic = _gtk_win32_theme_color_parse (parser);
1041       if (symbolic == NULL)
1042         return NULL;
1043     }
1044   else
1045     {
1046       child1 = gtk_css_parser_read_symbolic_color (parser);
1047       if (child1 == NULL)
1048         return NULL;
1049
1050       if (color == COLOR_MIX)
1051         {
1052           if (!_gtk_css_parser_try (parser, ",", TRUE))
1053             {
1054               _gtk_css_parser_error (parser, "Expected ',' in color definition");
1055               gtk_symbolic_color_unref (child1);
1056               return NULL;
1057             }
1058
1059           child2 = gtk_css_parser_read_symbolic_color (parser);
1060           if (child2 == NULL)
1061             {
1062               gtk_symbolic_color_unref (child1);
1063               return NULL;
1064             }
1065         }
1066       else
1067         child2 = NULL;
1068
1069       if (color == COLOR_LIGHTER)
1070         value = 1.3;
1071       else if (color == COLOR_DARKER)
1072         value = 0.7;
1073       else
1074         {
1075           if (!_gtk_css_parser_try (parser, ",", TRUE))
1076             {
1077               _gtk_css_parser_error (parser, "Expected ',' in color definition");
1078               gtk_symbolic_color_unref (child1);
1079               if (child2)
1080                 gtk_symbolic_color_unref (child2);
1081               return NULL;
1082             }
1083
1084           if (!_gtk_css_parser_try_double (parser, &value))
1085             {
1086               _gtk_css_parser_error (parser, "Expected number in color definition");
1087               gtk_symbolic_color_unref (child1);
1088               if (child2)
1089                 gtk_symbolic_color_unref (child2);
1090               return NULL;
1091             }
1092         }
1093       
1094       switch (color)
1095         {
1096         case COLOR_LIGHTER:
1097         case COLOR_DARKER:
1098         case COLOR_SHADE:
1099           symbolic = gtk_symbolic_color_new_shade (child1, value);
1100           break;
1101         case COLOR_ALPHA:
1102           symbolic = gtk_symbolic_color_new_alpha (child1, value);
1103           break;
1104         case COLOR_MIX:
1105           symbolic = gtk_symbolic_color_new_mix (child1, child2, value);
1106           break;
1107         default:
1108           g_assert_not_reached ();
1109           symbolic = NULL;
1110         }
1111
1112       gtk_symbolic_color_unref (child1);
1113       if (child2)
1114         gtk_symbolic_color_unref (child2);
1115     }
1116
1117   if (!_gtk_css_parser_try (parser, ")", TRUE))
1118     {
1119       _gtk_css_parser_error (parser, "Expected ')' in color definition");
1120       gtk_symbolic_color_unref (symbolic);
1121       return NULL;
1122     }
1123
1124   return symbolic;
1125 }
1126
1127 static GtkSymbolicColor *
1128 gtk_css_parser_read_symbolic_color (GtkCssParser *parser)
1129 {
1130   GtkSymbolicColor *symbolic;
1131   GdkRGBA rgba;
1132   guint color;
1133   const char *names[] = {"rgba", "rgb",  "lighter", "darker", "shade", "alpha", "mix",
1134                          GTK_WIN32_THEME_SYMBOLIC_COLOR_NAME};
1135   char *name;
1136
1137   if (_gtk_css_parser_try (parser, "currentColor", TRUE))
1138     return gtk_symbolic_color_ref (_gtk_symbolic_color_get_current_color ());
1139
1140   if (_gtk_css_parser_try (parser, "transparent", TRUE))
1141     {
1142       GdkRGBA transparent = { 0, 0, 0, 0 };
1143       
1144       return gtk_symbolic_color_new_literal (&transparent);
1145     }
1146
1147   if (_gtk_css_parser_try (parser, "@", FALSE))
1148     {
1149       name = _gtk_css_parser_try_name (parser, TRUE);
1150
1151       if (name)
1152         {
1153           symbolic = gtk_symbolic_color_new_name (name);
1154         }
1155       else
1156         {
1157           _gtk_css_parser_error (parser, "'%s' is not a valid symbolic color name", name);
1158           symbolic = NULL;
1159         }
1160
1161       g_free (name);
1162       return symbolic;
1163     }
1164
1165   for (color = 0; color < G_N_ELEMENTS (names); color++)
1166     {
1167       if (_gtk_css_parser_try (parser, names[color], TRUE))
1168         break;
1169     }
1170
1171   if (color < G_N_ELEMENTS (names))
1172     return gtk_css_parser_read_symbolic_color_function (parser, color);
1173
1174   if (_gtk_css_parser_try_hash_color (parser, &rgba))
1175     return gtk_symbolic_color_new_literal (&rgba);
1176
1177   name = _gtk_css_parser_try_name (parser, TRUE);
1178   if (name)
1179     {
1180       if (gdk_rgba_parse (&rgba, name))
1181         {
1182           symbolic = gtk_symbolic_color_new_literal (&rgba);
1183         }
1184       else
1185         {
1186           _gtk_css_parser_error (parser, "'%s' is not a valid color name", name);
1187           symbolic = NULL;
1188         }
1189       g_free (name);
1190       return symbolic;
1191     }
1192
1193   _gtk_css_parser_error (parser, "Not a color definition");
1194   return NULL;
1195 }
1196
1197 GtkCssValue *
1198 _gtk_css_symbolic_value_new (GtkCssParser *parser)
1199 {
1200   g_return_val_if_fail (parser != NULL, NULL);
1201
1202   return _gtk_css_symbolic_value_new_take_symbolic_color (gtk_css_parser_read_symbolic_color (parser));
1203 }
1204