]> Pileus Git - ~andy/gtk/blob - gtk/gtksymboliccolor.c
css: Huge refactoring to avoid computing wrong values
[~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                                      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->name, color2->name);
221     case COLOR_TYPE_SHADE:
222       return color1->shade.factor == color2->shade.factor &&
223              _gtk_css_value_equal ((GtkCssValue *) color1->shade.color,
224                                    (GtkCssValue *) color2->shade.color);
225     case COLOR_TYPE_ALPHA:
226       return color1->alpha.factor == color2->alpha.factor &&
227              _gtk_css_value_equal ((GtkCssValue *) color1->alpha.color,
228                                    (GtkCssValue *) color2->alpha.color);
229     case COLOR_TYPE_MIX:
230       return color1->mix.factor == color2->mix.factor &&
231              _gtk_css_value_equal ((GtkCssValue *) color1->mix.color1,
232                                    (GtkCssValue *) color2->mix.color1) &&
233              _gtk_css_value_equal ((GtkCssValue *) color1->mix.color2,
234                                    (GtkCssValue *) color2->mix.color2);
235     case COLOR_TYPE_WIN32:
236       return g_str_equal (color1->win32.theme_class, color2->win32.theme_class) &&
237              color1->win32.id == color2->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 NULL;
253 }
254
255 static void
256 gtk_css_value_symbolic_print (const GtkCssValue *value,
257                               GString           *string)
258 {
259   GtkSymbolicColor *color = (GtkSymbolicColor *) value;
260   char *s;
261   
262   s = gtk_symbolic_color_to_string (color);
263   g_string_append (string, s);
264   g_free (s);
265 }
266
267 static const GtkCssValueClass GTK_CSS_VALUE_SYMBOLIC = {
268   gtk_css_value_symbolic_free,
269   gtk_css_value_symbolic_compute,
270   gtk_css_value_symbolic_equal,
271   gtk_css_value_symbolic_transition,
272   gtk_css_value_symbolic_print
273 };
274
275 /**
276  * gtk_symbolic_color_new_literal:
277  * @color: a #GdkRGBA
278  *
279  * Creates a symbolic color pointing to a literal color.
280  *
281  * Returns: a newly created #GtkSymbolicColor
282  *
283  * Since: 3.0
284  **/
285 GtkSymbolicColor *
286 gtk_symbolic_color_new_literal (const GdkRGBA *color)
287 {
288   GtkSymbolicColor *symbolic_color;
289
290   g_return_val_if_fail (color != NULL, NULL);
291
292   symbolic_color = _gtk_css_value_new (GtkSymbolicColor, &GTK_CSS_VALUE_SYMBOLIC);
293   symbolic_color->type = COLOR_TYPE_LITERAL;
294   symbolic_color->last_value = _gtk_css_rgba_value_new_from_rgba (color);
295
296   return symbolic_color;
297 }
298
299 /**
300  * gtk_symbolic_color_new_name:
301  * @name: color name
302  *
303  * Creates a symbolic color pointing to an unresolved named
304  * color. See gtk_style_context_lookup_color() and
305  * gtk_style_properties_lookup_color().
306  *
307  * Returns: a newly created #GtkSymbolicColor
308  *
309  * Since: 3.0
310  **/
311 GtkSymbolicColor *
312 gtk_symbolic_color_new_name (const gchar *name)
313 {
314   GtkSymbolicColor *symbolic_color;
315
316   g_return_val_if_fail (name != NULL, NULL);
317
318   symbolic_color = _gtk_css_value_new (GtkSymbolicColor, &GTK_CSS_VALUE_SYMBOLIC);
319   symbolic_color->type = COLOR_TYPE_NAME;
320   symbolic_color->name = g_strdup (name);
321
322   return symbolic_color;
323 }
324
325 /**
326  * gtk_symbolic_color_new_shade: (constructor)
327  * @color: another #GtkSymbolicColor
328  * @factor: shading factor to apply to @color
329  *
330  * Creates a symbolic color defined as a shade of
331  * another color. A factor > 1.0 would resolve to
332  * a brighter color, while < 1.0 would resolve to
333  * a darker color.
334  *
335  * Returns: A newly created #GtkSymbolicColor
336  *
337  * Since: 3.0
338  **/
339 GtkSymbolicColor *
340 gtk_symbolic_color_new_shade (GtkSymbolicColor *color,
341                               gdouble           factor)
342 {
343   GtkSymbolicColor *symbolic_color;
344
345   g_return_val_if_fail (color != NULL, NULL);
346
347   symbolic_color = _gtk_css_value_new (GtkSymbolicColor, &GTK_CSS_VALUE_SYMBOLIC);
348   symbolic_color->type = COLOR_TYPE_SHADE;
349   symbolic_color->shade.color = gtk_symbolic_color_ref (color);
350   symbolic_color->shade.factor = factor;
351
352   return symbolic_color;
353 }
354
355 /**
356  * gtk_symbolic_color_new_alpha: (constructor)
357  * @color: another #GtkSymbolicColor
358  * @factor: factor to apply to @color alpha
359  *
360  * Creates a symbolic color by modifying the relative alpha
361  * value of @color. A factor < 1.0 would resolve to a more
362  * transparent color, while > 1.0 would resolve to a more
363  * opaque color.
364  *
365  * Returns: A newly created #GtkSymbolicColor
366  *
367  * Since: 3.0
368  **/
369 GtkSymbolicColor *
370 gtk_symbolic_color_new_alpha (GtkSymbolicColor *color,
371                               gdouble           factor)
372 {
373   GtkSymbolicColor *symbolic_color;
374
375   g_return_val_if_fail (color != NULL, NULL);
376
377   symbolic_color = _gtk_css_value_new (GtkSymbolicColor, &GTK_CSS_VALUE_SYMBOLIC);
378   symbolic_color->type = COLOR_TYPE_ALPHA;
379   symbolic_color->alpha.color = gtk_symbolic_color_ref (color);
380   symbolic_color->alpha.factor = factor;
381
382   return symbolic_color;
383 }
384
385 /**
386  * gtk_symbolic_color_new_mix: (constructor)
387  * @color1: color to mix
388  * @color2: another color to mix
389  * @factor: mix factor
390  *
391  * Creates a symbolic color defined as a mix of another
392  * two colors. a mix factor of 0 would resolve to @color1,
393  * while a factor of 1 would resolve to @color2.
394  *
395  * Returns: A newly created #GtkSymbolicColor
396  *
397  * Since: 3.0
398  **/
399 GtkSymbolicColor *
400 gtk_symbolic_color_new_mix (GtkSymbolicColor *color1,
401                             GtkSymbolicColor *color2,
402                             gdouble           factor)
403 {
404   GtkSymbolicColor *symbolic_color;
405
406   g_return_val_if_fail (color1 != NULL, NULL);
407   g_return_val_if_fail (color1 != NULL, NULL);
408
409   symbolic_color = _gtk_css_value_new (GtkSymbolicColor, &GTK_CSS_VALUE_SYMBOLIC);
410   symbolic_color->type = COLOR_TYPE_MIX;
411   symbolic_color->mix.color1 = gtk_symbolic_color_ref (color1);
412   symbolic_color->mix.color2 = gtk_symbolic_color_ref (color2);
413   symbolic_color->mix.factor = factor;
414
415   return symbolic_color;
416 }
417
418 /**
419  * gtk_symbolic_color_new_win32: (constructor)
420  * @theme_class: The theme class to pull color from
421  * @id: The color id
422  *
423  * Creates a symbolic color based on the current win32
424  * theme.
425  *
426  * Note that while this call is available on all platforms
427  * the actual value returned is not reliable on non-win32
428  * platforms.
429  *
430  * Returns: A newly created #GtkSymbolicColor
431  *
432  * Since: 3.4
433  */
434 GtkSymbolicColor *
435 gtk_symbolic_color_new_win32 (const gchar *theme_class,
436                               gint         id)
437 {
438   GtkSymbolicColor *symbolic_color;
439
440   g_return_val_if_fail (theme_class != NULL, NULL);
441
442   symbolic_color = _gtk_css_value_new (GtkSymbolicColor, &GTK_CSS_VALUE_SYMBOLIC);
443   symbolic_color->type = COLOR_TYPE_WIN32;
444   symbolic_color->win32.theme_class = g_strdup (theme_class);
445   symbolic_color->win32.id = id;
446
447   return symbolic_color;
448 }
449
450 /**
451  * _gtk_symbolic_color_get_current_color:
452  *
453  * Gets the color representing the CSS 'currentColor' keyword.
454  * This color will resolve to the color set for the color property.
455  *
456  * Returns: (transfer none): The singleton representing the
457  *     'currentColor' keyword
458  **/
459 GtkSymbolicColor *
460 _gtk_symbolic_color_get_current_color (void)
461 {
462   static GtkSymbolicColor *current_color = NULL;
463
464   if (G_UNLIKELY (current_color == NULL))
465     {
466       current_color = _gtk_css_value_new (GtkSymbolicColor, &GTK_CSS_VALUE_SYMBOLIC);
467       current_color->type = COLOR_TYPE_CURRENT_COLOR;
468     }
469
470   return current_color;
471 }
472
473 /**
474  * gtk_symbolic_color_ref:
475  * @color: a #GtkSymbolicColor
476  *
477  * Increases the reference count of @color
478  *
479  * Returns: the same @color
480  *
481  * Since: 3.0
482  **/
483 GtkSymbolicColor *
484 gtk_symbolic_color_ref (GtkSymbolicColor *color)
485 {
486   g_return_val_if_fail (color != NULL, NULL);
487
488   _gtk_css_value_ref ((GtkCssValue *) color);
489
490   return color;
491 }
492
493 /**
494  * gtk_symbolic_color_unref:
495  * @color: a #GtkSymbolicColor
496  *
497  * Decreases the reference count of @color, freeing its memory if the
498  * reference count reaches 0.
499  *
500  * Since: 3.0
501  **/
502 void
503 gtk_symbolic_color_unref (GtkSymbolicColor *color)
504 {
505   g_return_if_fail (color != NULL);
506
507   _gtk_css_value_unref ((GtkCssValue *) color);
508 }
509
510 static void
511 rgb_to_hls (gdouble *r,
512             gdouble *g,
513             gdouble *b)
514 {
515   gdouble min;
516   gdouble max;
517   gdouble red;
518   gdouble green;
519   gdouble blue;
520   gdouble h, l, s;
521   gdouble delta;
522   
523   red = *r;
524   green = *g;
525   blue = *b;
526   
527   if (red > green)
528     {
529       if (red > blue)
530         max = red;
531       else
532         max = blue;
533       
534       if (green < blue)
535         min = green;
536       else
537         min = blue;
538     }
539   else
540     {
541       if (green > blue)
542         max = green;
543       else
544         max = blue;
545       
546       if (red < blue)
547         min = red;
548       else
549         min = blue;
550     }
551   
552   l = (max + min) / 2;
553   s = 0;
554   h = 0;
555   
556   if (max != min)
557     {
558       if (l <= 0.5)
559         s = (max - min) / (max + min);
560       else
561         s = (max - min) / (2 - max - min);
562       
563       delta = max -min;
564       if (red == max)
565         h = (green - blue) / delta;
566       else if (green == max)
567         h = 2 + (blue - red) / delta;
568       else if (blue == max)
569         h = 4 + (red - green) / delta;
570       
571       h *= 60;
572       if (h < 0.0)
573         h += 360;
574     }
575   
576   *r = h;
577   *g = l;
578   *b = s;
579 }
580
581 static void
582 hls_to_rgb (gdouble *h,
583             gdouble *l,
584             gdouble *s)
585 {
586   gdouble hue;
587   gdouble lightness;
588   gdouble saturation;
589   gdouble m1, m2;
590   gdouble r, g, b;
591   
592   lightness = *l;
593   saturation = *s;
594   
595   if (lightness <= 0.5)
596     m2 = lightness * (1 + saturation);
597   else
598     m2 = lightness + saturation - lightness * saturation;
599   m1 = 2 * lightness - m2;
600   
601   if (saturation == 0)
602     {
603       *h = lightness;
604       *l = lightness;
605       *s = lightness;
606     }
607   else
608     {
609       hue = *h + 120;
610       while (hue > 360)
611         hue -= 360;
612       while (hue < 0)
613         hue += 360;
614       
615       if (hue < 60)
616         r = m1 + (m2 - m1) * hue / 60;
617       else if (hue < 180)
618         r = m2;
619       else if (hue < 240)
620         r = m1 + (m2 - m1) * (240 - hue) / 60;
621       else
622         r = m1;
623       
624       hue = *h;
625       while (hue > 360)
626         hue -= 360;
627       while (hue < 0)
628         hue += 360;
629       
630       if (hue < 60)
631         g = m1 + (m2 - m1) * hue / 60;
632       else if (hue < 180)
633         g = m2;
634       else if (hue < 240)
635         g = m1 + (m2 - m1) * (240 - hue) / 60;
636       else
637         g = m1;
638       
639       hue = *h - 120;
640       while (hue > 360)
641         hue -= 360;
642       while (hue < 0)
643         hue += 360;
644       
645       if (hue < 60)
646         b = m1 + (m2 - m1) * hue / 60;
647       else if (hue < 180)
648         b = m2;
649       else if (hue < 240)
650         b = m1 + (m2 - m1) * (240 - hue) / 60;
651       else
652         b = m1;
653       
654       *h = r;
655       *l = g;
656       *s = b;
657     }
658 }
659
660 static void
661 _shade_color (GdkRGBA *color,
662               gdouble  factor)
663 {
664   GdkRGBA temp;
665
666   temp = *color;
667   rgb_to_hls (&temp.red, &temp.green, &temp.blue);
668
669   temp.green *= factor;
670   if (temp.green > 1.0)
671     temp.green = 1.0;
672   else if (temp.green < 0.0)
673     temp.green = 0.0;
674
675   temp.blue *= factor;
676   if (temp.blue > 1.0)
677     temp.blue = 1.0;
678   else if (temp.blue < 0.0)
679     temp.blue = 0.0;
680
681   hls_to_rgb (&temp.red, &temp.green, &temp.blue);
682   *color = temp;
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                                        GTK_STYLE_PROVIDER_PRIVATE (props),
720                                        current,
721                                        0,
722                                        NULL);
723   _gtk_css_value_unref (current);
724   if (v == NULL)
725     return FALSE;
726
727   *resolved_color = *_gtk_css_rgba_value_get_rgba (v);
728   _gtk_css_value_unref (v);
729   return TRUE;
730 }
731
732 GtkCssValue *
733 _gtk_symbolic_color_resolve_full (GtkSymbolicColor        *color,
734                                   GtkStyleProviderPrivate *provider,
735                                   GtkCssValue             *current,
736                                   GtkCssDependencies       current_deps,
737                                   GtkCssDependencies      *dependencies)
738 {
739   GtkCssDependencies unused;
740   GtkCssValue *value;
741
742   g_return_val_if_fail (color != NULL, FALSE);
743   g_return_val_if_fail (GTK_IS_STYLE_PROVIDER_PRIVATE (provider), FALSE);
744   g_return_val_if_fail (current != NULL, FALSE);
745
746   if (dependencies == NULL)
747     dependencies = &unused;
748   *dependencies = 0;
749
750   value = NULL;
751   switch (color->type)
752     {
753     case COLOR_TYPE_LITERAL:
754       return _gtk_css_value_ref (color->last_value);
755     case COLOR_TYPE_NAME:
756       {
757         GtkSymbolicColor *named_color;
758
759         named_color = _gtk_style_provider_private_get_color (provider, color->name);
760
761         if (!named_color)
762           return NULL;
763
764         return _gtk_symbolic_color_resolve_full (named_color, provider, current, current_deps, dependencies);
765       }
766
767       break;
768     case COLOR_TYPE_SHADE:
769       {
770         GtkCssValue *val;
771         GdkRGBA shade;
772
773         val = _gtk_symbolic_color_resolve_full (color->shade.color, provider, current, current_deps, dependencies);
774         if (val == NULL)
775           return NULL;
776
777         *dependencies = _gtk_css_dependencies_union (*dependencies, 0);
778         shade = *_gtk_css_rgba_value_get_rgba (val);
779         _shade_color (&shade, color->shade.factor);
780
781         _gtk_css_value_unref (val);
782
783         value = _gtk_css_rgba_value_new_from_rgba (&shade);
784       }
785
786       break;
787     case COLOR_TYPE_ALPHA:
788       {
789         GtkCssValue *val;
790         GdkRGBA alpha;
791
792         val = _gtk_symbolic_color_resolve_full (color->alpha.color, provider, current, current_deps, dependencies);
793         if (val == NULL)
794           return NULL;
795
796         *dependencies = _gtk_css_dependencies_union (*dependencies, 0);
797         alpha = *_gtk_css_rgba_value_get_rgba (val);
798         alpha.alpha = CLAMP (alpha.alpha * color->alpha.factor, 0, 1);
799
800         _gtk_css_value_unref (val);
801
802         value = _gtk_css_rgba_value_new_from_rgba (&alpha);
803       }
804       break;
805
806     case COLOR_TYPE_MIX:
807       {
808         GtkCssValue *val;
809         GdkRGBA color1, color2, res;
810         GtkCssDependencies dep1, dep2;
811
812         val = _gtk_symbolic_color_resolve_full (color->mix.color1, provider, current, current_deps, &dep1);
813         if (val == NULL)
814           return NULL;
815         color1 = *_gtk_css_rgba_value_get_rgba (val);
816         _gtk_css_value_unref (val);
817
818         val = _gtk_symbolic_color_resolve_full (color->mix.color2, provider, current, current_deps, &dep2);
819         if (val == NULL)
820           return NULL;
821         color2 = *_gtk_css_rgba_value_get_rgba (val);
822         _gtk_css_value_unref (val);
823
824         *dependencies = _gtk_css_dependencies_union (dep1, dep2);
825         res.red = CLAMP (color1.red + ((color2.red - color1.red) * color->mix.factor), 0, 1);
826         res.green = CLAMP (color1.green + ((color2.green - color1.green) * color->mix.factor), 0, 1);
827         res.blue = CLAMP (color1.blue + ((color2.blue - color1.blue) * color->mix.factor), 0, 1);
828         res.alpha = CLAMP (color1.alpha + ((color2.alpha - color1.alpha) * color->mix.factor), 0, 1);
829
830         value =_gtk_css_rgba_value_new_from_rgba (&res);
831       }
832
833       break;
834     case COLOR_TYPE_WIN32:
835       {
836         GdkRGBA res;
837
838         if (!_gtk_win32_theme_color_resolve (color->win32.theme_class,
839                                              color->win32.id,
840                                              &res))
841           return NULL;
842
843         value = _gtk_css_rgba_value_new_from_rgba (&res);
844       }
845
846       break;
847     case COLOR_TYPE_CURRENT_COLOR:
848       if (current)
849         {
850           *dependencies = current_deps;
851           return _gtk_css_value_ref (current);
852         }
853       else
854         {
855           return NULL;
856         }
857       break;
858     default:
859       g_assert_not_reached ();
860     }
861
862   if (value != NULL)
863     {
864       if (color->last_value != NULL &&
865           _gtk_css_value_equal (color->last_value, value))
866         {
867           _gtk_css_value_unref (value);
868           value = _gtk_css_value_ref (color->last_value);
869         }
870       else
871         {
872           if (color->last_value != NULL)
873             _gtk_css_value_unref (color->last_value);
874           color->last_value = _gtk_css_value_ref (value);
875         }
876     }
877
878   _gtk_css_rgba_value_get_rgba (value);
879   return value;
880 }
881
882 /**
883  * gtk_symbolic_color_to_string:
884  * @color: color to convert to a string
885  *
886  * Converts the given @color to a string representation. This is useful
887  * both for debugging and for serialization of strings. The format of
888  * the string may change between different versions of GTK, but it is
889  * guaranteed that the GTK css parser is able to read the string and
890  * create the same symbolic color from it.
891  *
892  * Returns: a new string representing @color
893  **/
894 char *
895 gtk_symbolic_color_to_string (GtkSymbolicColor *color)
896 {
897   char *s;
898
899   g_return_val_if_fail (color != NULL, NULL);
900
901   switch (color->type)
902     {
903     case COLOR_TYPE_LITERAL:
904       s = gdk_rgba_to_string (_gtk_css_rgba_value_get_rgba (color->last_value));
905       break;
906     case COLOR_TYPE_NAME:
907       s = g_strconcat ("@", color->name, NULL);
908       break;
909     case COLOR_TYPE_SHADE:
910       {
911         char *color_string = gtk_symbolic_color_to_string (color->shade.color);
912         char factor[G_ASCII_DTOSTR_BUF_SIZE];
913
914         g_ascii_dtostr (factor, sizeof (factor), color->shade.factor);
915         s = g_strdup_printf ("shade (%s, %s)", color_string, factor);
916         g_free (color_string);
917       }
918       break;
919     case COLOR_TYPE_ALPHA:
920       {
921         char *color_string = gtk_symbolic_color_to_string (color->shade.color);
922         char factor[G_ASCII_DTOSTR_BUF_SIZE];
923
924         g_ascii_dtostr (factor, sizeof (factor), color->alpha.factor);
925         s = g_strdup_printf ("alpha (%s, %s)", color_string, factor);
926         g_free (color_string);
927       }
928       break;
929     case COLOR_TYPE_MIX:
930       {
931         char *color_string1 = gtk_symbolic_color_to_string (color->mix.color1);
932         char *color_string2 = gtk_symbolic_color_to_string (color->mix.color2);
933         char factor[G_ASCII_DTOSTR_BUF_SIZE];
934
935         g_ascii_dtostr (factor, sizeof (factor), color->mix.factor);
936         s = g_strdup_printf ("mix (%s, %s, %s)", color_string1, color_string2, factor);
937         g_free (color_string1);
938         g_free (color_string2);
939       }
940       break;
941     case COLOR_TYPE_WIN32:
942       {
943         s = g_strdup_printf (GTK_WIN32_THEME_SYMBOLIC_COLOR_NAME"(%s, %d)", 
944                              color->win32.theme_class, color->win32.id);
945       }
946       break;
947     case COLOR_TYPE_CURRENT_COLOR:
948       s = g_strdup ("currentColor");
949       break;
950     default:
951       g_assert_not_reached ();
952     }
953
954   return s;
955 }
956
957 typedef enum {
958   COLOR_RGBA,
959   COLOR_RGB,
960   COLOR_LIGHTER,
961   COLOR_DARKER,
962   COLOR_SHADE,
963   COLOR_ALPHA,
964   COLOR_MIX,
965   COLOR_WIN32
966 } ColorParseType;
967
968 static GtkSymbolicColor * gtk_css_parser_read_symbolic_color (GtkCssParser *parser);
969
970 static GtkSymbolicColor *
971 gtk_css_parser_read_symbolic_color_function (GtkCssParser   *parser,
972                                              ColorParseType  color)
973 {
974   GtkSymbolicColor *symbolic;
975   GtkSymbolicColor *child1, *child2;
976   double value;
977
978   if (!_gtk_css_parser_try (parser, "(", TRUE))
979     {
980       _gtk_css_parser_error (parser, "Missing opening bracket in color definition");
981       return NULL;
982     }
983
984   if (color == COLOR_RGB || color == COLOR_RGBA)
985     {
986       GdkRGBA rgba;
987       double tmp;
988       guint i;
989
990       for (i = 0; i < 3; i++)
991         {
992           if (i > 0 && !_gtk_css_parser_try (parser, ",", TRUE))
993             {
994               _gtk_css_parser_error (parser, "Expected ',' in color definition");
995               return NULL;
996             }
997
998           if (!_gtk_css_parser_try_double (parser, &tmp))
999             {
1000               _gtk_css_parser_error (parser, "Invalid number for color value");
1001               return NULL;
1002             }
1003           if (_gtk_css_parser_try (parser, "%", TRUE))
1004             tmp /= 100.0;
1005           else
1006             tmp /= 255.0;
1007           if (i == 0)
1008             rgba.red = tmp;
1009           else if (i == 1)
1010             rgba.green = tmp;
1011           else if (i == 2)
1012             rgba.blue = tmp;
1013           else
1014             g_assert_not_reached ();
1015         }
1016
1017       if (color == COLOR_RGBA)
1018         {
1019           if (i > 0 && !_gtk_css_parser_try (parser, ",", TRUE))
1020             {
1021               _gtk_css_parser_error (parser, "Expected ',' in color definition");
1022               return NULL;
1023             }
1024
1025           if (!_gtk_css_parser_try_double (parser, &rgba.alpha))
1026             {
1027               _gtk_css_parser_error (parser, "Invalid number for alpha value");
1028               return NULL;
1029             }
1030         }
1031       else
1032         rgba.alpha = 1.0;
1033       
1034       symbolic = gtk_symbolic_color_new_literal (&rgba);
1035     }
1036   else if (color == COLOR_WIN32)
1037     {
1038       symbolic = _gtk_win32_theme_color_parse (parser);
1039       if (symbolic == NULL)
1040         return NULL;
1041     }
1042   else
1043     {
1044       child1 = gtk_css_parser_read_symbolic_color (parser);
1045       if (child1 == NULL)
1046         return NULL;
1047
1048       if (color == COLOR_MIX)
1049         {
1050           if (!_gtk_css_parser_try (parser, ",", TRUE))
1051             {
1052               _gtk_css_parser_error (parser, "Expected ',' in color definition");
1053               gtk_symbolic_color_unref (child1);
1054               return NULL;
1055             }
1056
1057           child2 = gtk_css_parser_read_symbolic_color (parser);
1058           if (child2 == NULL)
1059             {
1060               gtk_symbolic_color_unref (child1);
1061               return NULL;
1062             }
1063         }
1064       else
1065         child2 = NULL;
1066
1067       if (color == COLOR_LIGHTER)
1068         value = 1.3;
1069       else if (color == COLOR_DARKER)
1070         value = 0.7;
1071       else
1072         {
1073           if (!_gtk_css_parser_try (parser, ",", TRUE))
1074             {
1075               _gtk_css_parser_error (parser, "Expected ',' in color definition");
1076               gtk_symbolic_color_unref (child1);
1077               if (child2)
1078                 gtk_symbolic_color_unref (child2);
1079               return NULL;
1080             }
1081
1082           if (!_gtk_css_parser_try_double (parser, &value))
1083             {
1084               _gtk_css_parser_error (parser, "Expected number in color definition");
1085               gtk_symbolic_color_unref (child1);
1086               if (child2)
1087                 gtk_symbolic_color_unref (child2);
1088               return NULL;
1089             }
1090         }
1091       
1092       switch (color)
1093         {
1094         case COLOR_LIGHTER:
1095         case COLOR_DARKER:
1096         case COLOR_SHADE:
1097           symbolic = gtk_symbolic_color_new_shade (child1, value);
1098           break;
1099         case COLOR_ALPHA:
1100           symbolic = gtk_symbolic_color_new_alpha (child1, value);
1101           break;
1102         case COLOR_MIX:
1103           symbolic = gtk_symbolic_color_new_mix (child1, child2, value);
1104           break;
1105         default:
1106           g_assert_not_reached ();
1107           symbolic = NULL;
1108         }
1109
1110       gtk_symbolic_color_unref (child1);
1111       if (child2)
1112         gtk_symbolic_color_unref (child2);
1113     }
1114
1115   if (!_gtk_css_parser_try (parser, ")", TRUE))
1116     {
1117       _gtk_css_parser_error (parser, "Expected ')' in color definition");
1118       gtk_symbolic_color_unref (symbolic);
1119       return NULL;
1120     }
1121
1122   return symbolic;
1123 }
1124
1125 static GtkSymbolicColor *
1126 gtk_css_parser_read_symbolic_color (GtkCssParser *parser)
1127 {
1128   GtkSymbolicColor *symbolic;
1129   GdkRGBA rgba;
1130   guint color;
1131   const char *names[] = {"rgba", "rgb",  "lighter", "darker", "shade", "alpha", "mix",
1132                          GTK_WIN32_THEME_SYMBOLIC_COLOR_NAME};
1133   char *name;
1134
1135   if (_gtk_css_parser_try (parser, "currentColor", TRUE))
1136     return gtk_symbolic_color_ref (_gtk_symbolic_color_get_current_color ());
1137
1138   if (_gtk_css_parser_try (parser, "transparent", TRUE))
1139     {
1140       GdkRGBA transparent = { 0, 0, 0, 0 };
1141       
1142       return gtk_symbolic_color_new_literal (&transparent);
1143     }
1144
1145   if (_gtk_css_parser_try (parser, "@", FALSE))
1146     {
1147       name = _gtk_css_parser_try_name (parser, TRUE);
1148
1149       if (name)
1150         {
1151           symbolic = gtk_symbolic_color_new_name (name);
1152         }
1153       else
1154         {
1155           _gtk_css_parser_error (parser, "'%s' is not a valid symbolic color name", name);
1156           symbolic = NULL;
1157         }
1158
1159       g_free (name);
1160       return symbolic;
1161     }
1162
1163   for (color = 0; color < G_N_ELEMENTS (names); color++)
1164     {
1165       if (_gtk_css_parser_try (parser, names[color], TRUE))
1166         break;
1167     }
1168
1169   if (color < G_N_ELEMENTS (names))
1170     return gtk_css_parser_read_symbolic_color_function (parser, color);
1171
1172   if (_gtk_css_parser_try_hash_color (parser, &rgba))
1173     return gtk_symbolic_color_new_literal (&rgba);
1174
1175   name = _gtk_css_parser_try_name (parser, TRUE);
1176   if (name)
1177     {
1178       if (gdk_rgba_parse (&rgba, name))
1179         {
1180           symbolic = gtk_symbolic_color_new_literal (&rgba);
1181         }
1182       else
1183         {
1184           _gtk_css_parser_error (parser, "'%s' is not a valid color name", name);
1185           symbolic = NULL;
1186         }
1187       g_free (name);
1188       return symbolic;
1189     }
1190
1191   _gtk_css_parser_error (parser, "Not a color definition");
1192   return NULL;
1193 }
1194
1195 GtkCssValue *
1196 _gtk_css_symbolic_value_new (GtkCssParser *parser)
1197 {
1198   g_return_val_if_fail (parser != NULL, NULL);
1199
1200   return _gtk_css_symbolic_value_new_take_symbolic_color (gtk_css_parser_read_symbolic_color (parser));
1201 }
1202