]> Pileus Git - ~andy/gtk/blob - gtk/gtksymboliccolor.c
css: Make color lookup handle dependencies
[~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   };
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->name);
101       break;
102     case COLOR_TYPE_SHADE:
103       gtk_symbolic_color_unref (color->shade.color);
104       break;
105     case COLOR_TYPE_ALPHA:
106       gtk_symbolic_color_unref (color->alpha.color);
107       break;
108     case COLOR_TYPE_MIX:
109       gtk_symbolic_color_unref (color->mix.color1);
110       gtk_symbolic_color_unref (color->mix.color2);
111       break;
112     case COLOR_TYPE_WIN32:
113       g_free (color->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                                      GtkStyleContext *context)
125 {
126   static const GdkRGBA transparent = { 0, 0, 0, 0 };
127
128   switch (property_id)
129     {
130       case GTK_CSS_PROPERTY_BACKGROUND_IMAGE:
131       case GTK_CSS_PROPERTY_BORDER_IMAGE_SOURCE:
132       case GTK_CSS_PROPERTY_TEXT_SHADOW:
133       case GTK_CSS_PROPERTY_ICON_SHADOW:
134       case GTK_CSS_PROPERTY_BOX_SHADOW:
135         return _gtk_css_rgba_value_new_from_rgba (&transparent);
136       case GTK_CSS_PROPERTY_COLOR:
137       case GTK_CSS_PROPERTY_BACKGROUND_COLOR:
138       case GTK_CSS_PROPERTY_BORDER_TOP_COLOR:
139       case GTK_CSS_PROPERTY_BORDER_RIGHT_COLOR:
140       case GTK_CSS_PROPERTY_BORDER_BOTTOM_COLOR:
141       case GTK_CSS_PROPERTY_BORDER_LEFT_COLOR:
142       case GTK_CSS_PROPERTY_OUTLINE_COLOR:
143         return _gtk_css_value_compute (_gtk_css_style_property_get_initial_value (_gtk_css_style_property_lookup_by_id (property_id)),
144                                        property_id,
145                                        context,
146                                        NULL);
147       default:
148         if (property_id < GTK_CSS_PROPERTY_N_PROPERTIES)
149           g_warning ("No fallback color defined for property '%s'", 
150                      _gtk_style_property_get_name (GTK_STYLE_PROPERTY (_gtk_css_style_property_lookup_by_id (property_id))));
151         return _gtk_css_rgba_value_new_from_rgba (&transparent);
152     }
153 }
154
155 static GtkCssValue *
156 gtk_css_value_symbolic_compute (GtkCssValue        *value,
157                                 guint               property_id,
158                                 GtkStyleContext    *context,
159                                 GtkCssDependencies *dependencies)
160 {
161   GtkCssValue *resolved, *current;
162   GtkCssDependencies current_deps;
163
164   /* The computed value of the ‘currentColor’ keyword is the computed
165    * value of the ‘color’ property. If the ‘currentColor’ keyword is
166    * set on the ‘color’ property itself, it is treated as ‘color: inherit’. 
167    */
168   if (property_id == GTK_CSS_PROPERTY_COLOR)
169     {
170       GtkStyleContext *parent = gtk_style_context_get_parent (context);
171
172       if (parent)
173         {
174           current = _gtk_style_context_peek_property (parent, GTK_CSS_PROPERTY_COLOR);
175           current_deps = GTK_CSS_EQUALS_PARENT;
176         }
177       else
178         {
179           current = _gtk_css_style_property_get_initial_value (_gtk_css_style_property_lookup_by_id (GTK_CSS_PROPERTY_COLOR));
180           current_deps = 0;
181         }
182     }
183   else
184     {
185       current = _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_COLOR);
186       current_deps = GTK_CSS_DEPENDS_ON_COLOR;
187     }
188   
189   resolved = _gtk_style_context_resolve_color_value (context, current, current_deps, value, dependencies);
190
191   if (resolved == NULL)
192     return gtk_css_value_symbolic_get_fallback (property_id, context);
193
194   return resolved;
195 }
196
197 static gboolean
198 gtk_css_value_symbolic_equal (const GtkCssValue *value1,
199                               const GtkCssValue *value2)
200 {
201   GtkSymbolicColor *color1 = (GtkSymbolicColor *) value1;
202   GtkSymbolicColor *color2 = (GtkSymbolicColor *) value2;
203
204   if (color1->type != color2->type)
205     return FALSE;
206
207   switch (color1->type)
208     {
209     case COLOR_TYPE_LITERAL:
210       return _gtk_css_value_equal (color1->last_value, color2->last_value);
211     case COLOR_TYPE_NAME:
212       return g_str_equal (color1->name, color2->name);
213     case COLOR_TYPE_SHADE:
214       return color1->shade.factor == color2->shade.factor &&
215              _gtk_css_value_equal ((GtkCssValue *) color1->shade.color,
216                                    (GtkCssValue *) color2->shade.color);
217     case COLOR_TYPE_ALPHA:
218       return color1->alpha.factor == color2->alpha.factor &&
219              _gtk_css_value_equal ((GtkCssValue *) color1->alpha.color,
220                                    (GtkCssValue *) color2->alpha.color);
221     case COLOR_TYPE_MIX:
222       return color1->mix.factor == color2->mix.factor &&
223              _gtk_css_value_equal ((GtkCssValue *) color1->mix.color1,
224                                    (GtkCssValue *) color2->mix.color1) &&
225              _gtk_css_value_equal ((GtkCssValue *) color1->mix.color2,
226                                    (GtkCssValue *) color2->mix.color2);
227     case COLOR_TYPE_WIN32:
228       return g_str_equal (color1->win32.theme_class, color2->win32.theme_class) &&
229              color1->win32.id == color2->win32.id;
230     case COLOR_TYPE_CURRENT_COLOR:
231       return TRUE;
232     default:
233       g_assert_not_reached ();
234       return FALSE;
235     }
236 }
237
238 static GtkCssValue *
239 gtk_css_value_symbolic_transition (GtkCssValue *start,
240                                    GtkCssValue *end,
241                                    double       progress)
242 {
243   return NULL;
244 }
245
246 static void
247 gtk_css_value_symbolic_print (const GtkCssValue *value,
248                               GString           *string)
249 {
250   GtkSymbolicColor *color = (GtkSymbolicColor *) value;
251   char *s;
252   
253   s = gtk_symbolic_color_to_string (color);
254   g_string_append (string, s);
255   g_free (s);
256 }
257
258 static const GtkCssValueClass GTK_CSS_VALUE_SYMBOLIC = {
259   gtk_css_value_symbolic_free,
260   gtk_css_value_symbolic_compute,
261   gtk_css_value_symbolic_equal,
262   gtk_css_value_symbolic_transition,
263   gtk_css_value_symbolic_print
264 };
265
266 /**
267  * gtk_symbolic_color_new_literal:
268  * @color: a #GdkRGBA
269  *
270  * Creates a symbolic color pointing to a literal color.
271  *
272  * Returns: a newly created #GtkSymbolicColor
273  *
274  * Since: 3.0
275  **/
276 GtkSymbolicColor *
277 gtk_symbolic_color_new_literal (const GdkRGBA *color)
278 {
279   GtkSymbolicColor *symbolic_color;
280
281   g_return_val_if_fail (color != NULL, NULL);
282
283   symbolic_color = _gtk_css_value_new (GtkSymbolicColor, &GTK_CSS_VALUE_SYMBOLIC);
284   symbolic_color->type = COLOR_TYPE_LITERAL;
285   symbolic_color->last_value = _gtk_css_rgba_value_new_from_rgba (color);
286
287   return symbolic_color;
288 }
289
290 /**
291  * gtk_symbolic_color_new_name:
292  * @name: color name
293  *
294  * Creates a symbolic color pointing to an unresolved named
295  * color. See gtk_style_context_lookup_color() and
296  * gtk_style_properties_lookup_color().
297  *
298  * Returns: a newly created #GtkSymbolicColor
299  *
300  * Since: 3.0
301  **/
302 GtkSymbolicColor *
303 gtk_symbolic_color_new_name (const gchar *name)
304 {
305   GtkSymbolicColor *symbolic_color;
306
307   g_return_val_if_fail (name != NULL, NULL);
308
309   symbolic_color = _gtk_css_value_new (GtkSymbolicColor, &GTK_CSS_VALUE_SYMBOLIC);
310   symbolic_color->type = COLOR_TYPE_NAME;
311   symbolic_color->name = g_strdup (name);
312
313   return symbolic_color;
314 }
315
316 /**
317  * gtk_symbolic_color_new_shade: (constructor)
318  * @color: another #GtkSymbolicColor
319  * @factor: shading factor to apply to @color
320  *
321  * Creates a symbolic color defined as a shade of
322  * another color. A factor > 1.0 would resolve to
323  * a brighter color, while < 1.0 would resolve to
324  * a darker color.
325  *
326  * Returns: A newly created #GtkSymbolicColor
327  *
328  * Since: 3.0
329  **/
330 GtkSymbolicColor *
331 gtk_symbolic_color_new_shade (GtkSymbolicColor *color,
332                               gdouble           factor)
333 {
334   GtkSymbolicColor *symbolic_color;
335
336   g_return_val_if_fail (color != NULL, NULL);
337
338   symbolic_color = _gtk_css_value_new (GtkSymbolicColor, &GTK_CSS_VALUE_SYMBOLIC);
339   symbolic_color->type = COLOR_TYPE_SHADE;
340   symbolic_color->shade.color = gtk_symbolic_color_ref (color);
341   symbolic_color->shade.factor = factor;
342
343   return symbolic_color;
344 }
345
346 /**
347  * gtk_symbolic_color_new_alpha: (constructor)
348  * @color: another #GtkSymbolicColor
349  * @factor: factor to apply to @color alpha
350  *
351  * Creates a symbolic color by modifying the relative alpha
352  * value of @color. A factor < 1.0 would resolve to a more
353  * transparent color, while > 1.0 would resolve to a more
354  * opaque color.
355  *
356  * Returns: A newly created #GtkSymbolicColor
357  *
358  * Since: 3.0
359  **/
360 GtkSymbolicColor *
361 gtk_symbolic_color_new_alpha (GtkSymbolicColor *color,
362                               gdouble           factor)
363 {
364   GtkSymbolicColor *symbolic_color;
365
366   g_return_val_if_fail (color != NULL, NULL);
367
368   symbolic_color = _gtk_css_value_new (GtkSymbolicColor, &GTK_CSS_VALUE_SYMBOLIC);
369   symbolic_color->type = COLOR_TYPE_ALPHA;
370   symbolic_color->alpha.color = gtk_symbolic_color_ref (color);
371   symbolic_color->alpha.factor = factor;
372
373   return symbolic_color;
374 }
375
376 /**
377  * gtk_symbolic_color_new_mix: (constructor)
378  * @color1: color to mix
379  * @color2: another color to mix
380  * @factor: mix factor
381  *
382  * Creates a symbolic color defined as a mix of another
383  * two colors. a mix factor of 0 would resolve to @color1,
384  * while a factor of 1 would resolve to @color2.
385  *
386  * Returns: A newly created #GtkSymbolicColor
387  *
388  * Since: 3.0
389  **/
390 GtkSymbolicColor *
391 gtk_symbolic_color_new_mix (GtkSymbolicColor *color1,
392                             GtkSymbolicColor *color2,
393                             gdouble           factor)
394 {
395   GtkSymbolicColor *symbolic_color;
396
397   g_return_val_if_fail (color1 != NULL, NULL);
398   g_return_val_if_fail (color1 != NULL, NULL);
399
400   symbolic_color = _gtk_css_value_new (GtkSymbolicColor, &GTK_CSS_VALUE_SYMBOLIC);
401   symbolic_color->type = COLOR_TYPE_MIX;
402   symbolic_color->mix.color1 = gtk_symbolic_color_ref (color1);
403   symbolic_color->mix.color2 = gtk_symbolic_color_ref (color2);
404   symbolic_color->mix.factor = factor;
405
406   return symbolic_color;
407 }
408
409 /**
410  * gtk_symbolic_color_new_win32: (constructor)
411  * @theme_class: The theme class to pull color from
412  * @id: The color id
413  *
414  * Creates a symbolic color based on the current win32
415  * theme.
416  *
417  * Note that while this call is available on all platforms
418  * the actual value returned is not reliable on non-win32
419  * platforms.
420  *
421  * Returns: A newly created #GtkSymbolicColor
422  *
423  * Since: 3.4
424  */
425 GtkSymbolicColor *
426 gtk_symbolic_color_new_win32 (const gchar *theme_class,
427                               gint         id)
428 {
429   GtkSymbolicColor *symbolic_color;
430
431   g_return_val_if_fail (theme_class != NULL, NULL);
432
433   symbolic_color = _gtk_css_value_new (GtkSymbolicColor, &GTK_CSS_VALUE_SYMBOLIC);
434   symbolic_color->type = COLOR_TYPE_WIN32;
435   symbolic_color->win32.theme_class = g_strdup (theme_class);
436   symbolic_color->win32.id = id;
437
438   return symbolic_color;
439 }
440
441 /**
442  * _gtk_symbolic_color_get_current_color:
443  *
444  * Gets the color representing the CSS 'currentColor' keyword.
445  * This color will resolve to the color set for the color property.
446  *
447  * Returns: (transfer none): The singleton representing the
448  *     'currentColor' keyword
449  **/
450 GtkSymbolicColor *
451 _gtk_symbolic_color_get_current_color (void)
452 {
453   static GtkSymbolicColor *current_color = NULL;
454
455   if (G_UNLIKELY (current_color == NULL))
456     {
457       current_color = _gtk_css_value_new (GtkSymbolicColor, &GTK_CSS_VALUE_SYMBOLIC);
458       current_color->type = COLOR_TYPE_CURRENT_COLOR;
459     }
460
461   return current_color;
462 }
463
464 /**
465  * gtk_symbolic_color_ref:
466  * @color: a #GtkSymbolicColor
467  *
468  * Increases the reference count of @color
469  *
470  * Returns: the same @color
471  *
472  * Since: 3.0
473  **/
474 GtkSymbolicColor *
475 gtk_symbolic_color_ref (GtkSymbolicColor *color)
476 {
477   g_return_val_if_fail (color != NULL, NULL);
478
479   _gtk_css_value_ref ((GtkCssValue *) color);
480
481   return color;
482 }
483
484 /**
485  * gtk_symbolic_color_unref:
486  * @color: a #GtkSymbolicColor
487  *
488  * Decreases the reference count of @color, freeing its memory if the
489  * reference count reaches 0.
490  *
491  * Since: 3.0
492  **/
493 void
494 gtk_symbolic_color_unref (GtkSymbolicColor *color)
495 {
496   g_return_if_fail (color != NULL);
497
498   _gtk_css_value_unref ((GtkCssValue *) color);
499 }
500
501 static void
502 rgb_to_hls (gdouble *r,
503             gdouble *g,
504             gdouble *b)
505 {
506   gdouble min;
507   gdouble max;
508   gdouble red;
509   gdouble green;
510   gdouble blue;
511   gdouble h, l, s;
512   gdouble delta;
513   
514   red = *r;
515   green = *g;
516   blue = *b;
517   
518   if (red > green)
519     {
520       if (red > blue)
521         max = red;
522       else
523         max = blue;
524       
525       if (green < blue)
526         min = green;
527       else
528         min = blue;
529     }
530   else
531     {
532       if (green > blue)
533         max = green;
534       else
535         max = blue;
536       
537       if (red < blue)
538         min = red;
539       else
540         min = blue;
541     }
542   
543   l = (max + min) / 2;
544   s = 0;
545   h = 0;
546   
547   if (max != min)
548     {
549       if (l <= 0.5)
550         s = (max - min) / (max + min);
551       else
552         s = (max - min) / (2 - max - min);
553       
554       delta = max -min;
555       if (red == max)
556         h = (green - blue) / delta;
557       else if (green == max)
558         h = 2 + (blue - red) / delta;
559       else if (blue == max)
560         h = 4 + (red - green) / delta;
561       
562       h *= 60;
563       if (h < 0.0)
564         h += 360;
565     }
566   
567   *r = h;
568   *g = l;
569   *b = s;
570 }
571
572 static void
573 hls_to_rgb (gdouble *h,
574             gdouble *l,
575             gdouble *s)
576 {
577   gdouble hue;
578   gdouble lightness;
579   gdouble saturation;
580   gdouble m1, m2;
581   gdouble r, g, b;
582   
583   lightness = *l;
584   saturation = *s;
585   
586   if (lightness <= 0.5)
587     m2 = lightness * (1 + saturation);
588   else
589     m2 = lightness + saturation - lightness * saturation;
590   m1 = 2 * lightness - m2;
591   
592   if (saturation == 0)
593     {
594       *h = lightness;
595       *l = lightness;
596       *s = lightness;
597     }
598   else
599     {
600       hue = *h + 120;
601       while (hue > 360)
602         hue -= 360;
603       while (hue < 0)
604         hue += 360;
605       
606       if (hue < 60)
607         r = m1 + (m2 - m1) * hue / 60;
608       else if (hue < 180)
609         r = m2;
610       else if (hue < 240)
611         r = m1 + (m2 - m1) * (240 - hue) / 60;
612       else
613         r = m1;
614       
615       hue = *h;
616       while (hue > 360)
617         hue -= 360;
618       while (hue < 0)
619         hue += 360;
620       
621       if (hue < 60)
622         g = m1 + (m2 - m1) * hue / 60;
623       else if (hue < 180)
624         g = m2;
625       else if (hue < 240)
626         g = m1 + (m2 - m1) * (240 - hue) / 60;
627       else
628         g = m1;
629       
630       hue = *h - 120;
631       while (hue > 360)
632         hue -= 360;
633       while (hue < 0)
634         hue += 360;
635       
636       if (hue < 60)
637         b = m1 + (m2 - m1) * hue / 60;
638       else if (hue < 180)
639         b = m2;
640       else if (hue < 240)
641         b = m1 + (m2 - m1) * (240 - hue) / 60;
642       else
643         b = m1;
644       
645       *h = r;
646       *l = g;
647       *s = b;
648     }
649 }
650
651 static void
652 _shade_color (GdkRGBA *color,
653               gdouble  factor)
654 {
655   GdkRGBA temp;
656
657   temp = *color;
658   rgb_to_hls (&temp.red, &temp.green, &temp.blue);
659
660   temp.green *= factor;
661   if (temp.green > 1.0)
662     temp.green = 1.0;
663   else if (temp.green < 0.0)
664     temp.green = 0.0;
665
666   temp.blue *= factor;
667   if (temp.blue > 1.0)
668     temp.blue = 1.0;
669   else if (temp.blue < 0.0)
670     temp.blue = 0.0;
671
672   hls_to_rgb (&temp.red, &temp.green, &temp.blue);
673   *color = temp;
674 }
675
676 static GtkSymbolicColor *
677 resolve_lookup_color (gpointer data, const char *name)
678 {
679   if (data == NULL)
680     return NULL;
681
682   return gtk_style_properties_lookup_color (data, name);
683 }
684
685 /**
686  * gtk_symbolic_color_resolve:
687  * @color: a #GtkSymbolicColor
688  * @props: (allow-none): #GtkStyleProperties to use when resolving
689  *    named colors, or %NULL
690  * @resolved_color: (out): return location for the resolved color
691  *
692  * If @color is resolvable, @resolved_color will be filled in
693  * with the resolved color, and %TRUE will be returned. Generally,
694  * if @color can't be resolved, it is due to it being defined on
695  * top of a named color that doesn't exist in @props.
696  *
697  * When @props is %NULL, resolving of named colors will fail, so if
698  * your @color is or references such a color, this function will
699  * return %FALSE.
700  *
701  * Returns: %TRUE if the color has been resolved
702  *
703  * Since: 3.0
704  **/
705 gboolean
706 gtk_symbolic_color_resolve (GtkSymbolicColor   *color,
707                             GtkStyleProperties *props,
708                             GdkRGBA            *resolved_color)
709 {
710   GdkRGBA pink = { 1.0, 0.5, 0.5, 1.0 };
711   GtkCssValue *v, *current;
712
713   g_return_val_if_fail (color != NULL, FALSE);
714   g_return_val_if_fail (resolved_color != NULL, FALSE);
715   g_return_val_if_fail (props == NULL || GTK_IS_STYLE_PROPERTIES (props), FALSE);
716
717   current = _gtk_css_rgba_value_new_from_rgba (&pink);
718   v =_gtk_symbolic_color_resolve_full (color,
719                                        current,
720                                        0,
721                                        resolve_lookup_color,
722                                        props,
723                                        NULL);
724   _gtk_css_value_unref (current);
725   if (v == NULL)
726     return FALSE;
727
728   *resolved_color = *_gtk_css_rgba_value_get_rgba (v);
729   _gtk_css_value_unref (v);
730   return TRUE;
731 }
732
733 GtkCssValue *
734 _gtk_symbolic_color_resolve_full (GtkSymbolicColor           *color,
735                                   GtkCssValue                *current,
736                                   GtkCssDependencies          current_deps,
737                                   GtkSymbolicColorLookupFunc  func,
738                                   gpointer                    data,
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 (current != NULL, FALSE);
746   g_return_val_if_fail (func != 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 = func (data, color->name);
762
763         if (!named_color)
764           return NULL;
765
766         return _gtk_symbolic_color_resolve_full (named_color, current, current_deps, func, data, 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->shade.color, current, current_deps, func, data, 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->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->alpha.color, current, current_deps, func, data, 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->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->mix.color1, current, current_deps, func, data, &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->mix.color2, current, current_deps, func, data, &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->mix.factor), 0, 1);
828         res.green = CLAMP (color1.green + ((color2.green - color1.green) * color->mix.factor), 0, 1);
829         res.blue = CLAMP (color1.blue + ((color2.blue - color1.blue) * color->mix.factor), 0, 1);
830         res.alpha = CLAMP (color1.alpha + ((color2.alpha - color1.alpha) * color->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->win32.theme_class,
841                                              color->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->name, NULL);
910       break;
911     case COLOR_TYPE_SHADE:
912       {
913         char *color_string = gtk_symbolic_color_to_string (color->shade.color);
914         char factor[G_ASCII_DTOSTR_BUF_SIZE];
915
916         g_ascii_dtostr (factor, sizeof (factor), color->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->shade.color);
924         char factor[G_ASCII_DTOSTR_BUF_SIZE];
925
926         g_ascii_dtostr (factor, sizeof (factor), color->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->mix.color1);
934         char *color_string2 = gtk_symbolic_color_to_string (color->mix.color2);
935         char factor[G_ASCII_DTOSTR_BUF_SIZE];
936
937         g_ascii_dtostr (factor, sizeof (factor), color->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->win32.theme_class, color->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