]> Pileus Git - ~andy/gtk/blob - gtk/gtkcsscolorvalue.c
deprecations: Move files into deprecated/ dir
[~andy/gtk] / gtk / gtkcsscolorvalue.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
20 #include "gtkcsscolorvalueprivate.h"
21
22 #include "gtkcssrgbavalueprivate.h"
23 #include "gtkcssstylepropertyprivate.h"
24 #include "gtkhslaprivate.h"
25 #include "gtkstylepropertyprivate.h"
26 #include "gtkstyleproperties.h"
27 #include "gtkwin32themeprivate.h"
28
29 typedef enum {
30   COLOR_TYPE_LITERAL,
31   COLOR_TYPE_NAME,
32   COLOR_TYPE_SHADE,
33   COLOR_TYPE_ALPHA,
34   COLOR_TYPE_MIX,
35   COLOR_TYPE_WIN32,
36   COLOR_TYPE_CURRENT_COLOR
37 } ColorType;
38
39 struct _GtkCssValue
40 {
41   GTK_CSS_VALUE_BASE
42   ColorType type;
43   GtkCssValue *last_value;
44
45   union
46   {
47     gchar *name;
48
49     struct
50     {
51       GtkCssValue *color;
52       gdouble factor;
53     } shade, alpha;
54
55     struct
56     {
57       GtkCssValue *color1;
58       GtkCssValue *color2;
59       gdouble factor;
60     } mix;
61
62     struct
63     {
64       gchar *theme_class;
65       gint id;
66     } win32;
67   } sym_col;
68 };
69
70 static void
71 gtk_css_value_color_free (GtkCssValue *color)
72 {
73   if (color->last_value)
74     _gtk_css_value_unref (color->last_value);
75
76   switch (color->type)
77     {
78     case COLOR_TYPE_NAME:
79       g_free (color->sym_col.name);
80       break;
81     case COLOR_TYPE_SHADE:
82       _gtk_css_value_unref (color->sym_col.shade.color);
83       break;
84     case COLOR_TYPE_ALPHA:
85       _gtk_css_value_unref (color->sym_col.alpha.color);
86       break;
87     case COLOR_TYPE_MIX:
88       _gtk_css_value_unref (color->sym_col.mix.color1);
89       _gtk_css_value_unref (color->sym_col.mix.color2);
90       break;
91     case COLOR_TYPE_WIN32:
92       g_free (color->sym_col.win32.theme_class);
93       break;
94     default:
95       break;
96     }
97
98   g_slice_free (GtkCssValue, color);
99 }
100
101 static GtkCssValue *
102 gtk_css_value_color_get_fallback (guint                    property_id,
103                                   GtkStyleProviderPrivate *provider,
104                                   GtkCssComputedValues    *values,
105                                   GtkCssComputedValues    *parent_values)
106 {
107   static const GdkRGBA transparent = { 0, 0, 0, 0 };
108
109   switch (property_id)
110     {
111       case GTK_CSS_PROPERTY_BACKGROUND_IMAGE:
112       case GTK_CSS_PROPERTY_BORDER_IMAGE_SOURCE:
113       case GTK_CSS_PROPERTY_TEXT_SHADOW:
114       case GTK_CSS_PROPERTY_ICON_SHADOW:
115       case GTK_CSS_PROPERTY_BOX_SHADOW:
116         return _gtk_css_rgba_value_new_from_rgba (&transparent);
117       case GTK_CSS_PROPERTY_COLOR:
118       case GTK_CSS_PROPERTY_BACKGROUND_COLOR:
119       case GTK_CSS_PROPERTY_BORDER_TOP_COLOR:
120       case GTK_CSS_PROPERTY_BORDER_RIGHT_COLOR:
121       case GTK_CSS_PROPERTY_BORDER_BOTTOM_COLOR:
122       case GTK_CSS_PROPERTY_BORDER_LEFT_COLOR:
123       case GTK_CSS_PROPERTY_OUTLINE_COLOR:
124         return _gtk_css_value_compute (_gtk_css_style_property_get_initial_value (_gtk_css_style_property_lookup_by_id (property_id)),
125                                        property_id,
126                                        provider,
127                                        values,
128                                        parent_values,
129                                        NULL);
130       default:
131         if (property_id < GTK_CSS_PROPERTY_N_PROPERTIES)
132           g_warning ("No fallback color defined for property '%s'", 
133                      _gtk_style_property_get_name (GTK_STYLE_PROPERTY (_gtk_css_style_property_lookup_by_id (property_id))));
134         return _gtk_css_rgba_value_new_from_rgba (&transparent);
135     }
136 }
137
138 GtkCssValue *
139 _gtk_css_color_value_resolve (GtkCssValue             *color,
140                               GtkStyleProviderPrivate *provider,
141                               GtkCssValue             *current,
142                               GtkCssDependencies       current_deps,
143                               GtkCssDependencies      *dependencies)
144 {
145   GtkCssDependencies unused;
146   GtkCssValue *value;
147
148   g_return_val_if_fail (color != NULL, FALSE);
149   g_return_val_if_fail (provider == NULL || GTK_IS_STYLE_PROVIDER_PRIVATE (provider), FALSE);
150   g_return_val_if_fail (current != NULL, FALSE);
151
152   if (dependencies == NULL)
153     dependencies = &unused;
154   *dependencies = 0;
155
156   value = NULL;
157   switch (color->type)
158     {
159     case COLOR_TYPE_LITERAL:
160       return _gtk_css_value_ref (color->last_value);
161     case COLOR_TYPE_NAME:
162       {
163         GtkCssValue *named;
164
165         named = _gtk_style_provider_private_get_color (provider, color->sym_col.name);
166         if (named == NULL)
167           return NULL;
168
169         value = _gtk_css_color_value_resolve (named, provider, current, current_deps, dependencies);
170       }
171
172       break;
173     case COLOR_TYPE_SHADE:
174       {
175         GtkCssValue *val;
176         GtkHSLA hsla;
177         GdkRGBA shade;
178
179         val = _gtk_css_color_value_resolve (color->sym_col.shade.color, provider, current, current_deps, dependencies);
180         if (val == NULL)
181           return NULL;
182
183         *dependencies = _gtk_css_dependencies_union (*dependencies, 0);
184         
185         _gtk_hsla_init_from_rgba (&hsla, _gtk_css_rgba_value_get_rgba (val));
186         _gtk_hsla_shade (&hsla, &hsla, color->sym_col.shade.factor);
187
188         _gdk_rgba_init_from_hsla (&shade, &hsla);
189
190         _gtk_css_value_unref (val);
191
192         value = _gtk_css_rgba_value_new_from_rgba (&shade);
193       }
194
195       break;
196     case COLOR_TYPE_ALPHA:
197       {
198         GtkCssValue *val;
199         GdkRGBA alpha;
200
201         val = _gtk_css_color_value_resolve (color->sym_col.alpha.color, provider, current, current_deps, dependencies);
202         if (val == NULL)
203           return NULL;
204
205         *dependencies = _gtk_css_dependencies_union (*dependencies, 0);
206         alpha = *_gtk_css_rgba_value_get_rgba (val);
207         alpha.alpha = CLAMP (alpha.alpha * color->sym_col.alpha.factor, 0, 1);
208
209         _gtk_css_value_unref (val);
210
211         value = _gtk_css_rgba_value_new_from_rgba (&alpha);
212       }
213       break;
214
215     case COLOR_TYPE_MIX:
216       {
217         GtkCssValue *val;
218         GdkRGBA color1, color2, res;
219         GtkCssDependencies dep1, dep2;
220
221         val = _gtk_css_color_value_resolve (color->sym_col.mix.color1, provider, current, current_deps, &dep1);
222         if (val == NULL)
223           return NULL;
224         color1 = *_gtk_css_rgba_value_get_rgba (val);
225         _gtk_css_value_unref (val);
226
227         val = _gtk_css_color_value_resolve (color->sym_col.mix.color2, provider, current, current_deps, &dep2);
228         if (val == NULL)
229           return NULL;
230         color2 = *_gtk_css_rgba_value_get_rgba (val);
231         _gtk_css_value_unref (val);
232
233         *dependencies = _gtk_css_dependencies_union (dep1, dep2);
234         res.red = CLAMP (color1.red + ((color2.red - color1.red) * color->sym_col.mix.factor), 0, 1);
235         res.green = CLAMP (color1.green + ((color2.green - color1.green) * color->sym_col.mix.factor), 0, 1);
236         res.blue = CLAMP (color1.blue + ((color2.blue - color1.blue) * color->sym_col.mix.factor), 0, 1);
237         res.alpha = CLAMP (color1.alpha + ((color2.alpha - color1.alpha) * color->sym_col.mix.factor), 0, 1);
238
239         value =_gtk_css_rgba_value_new_from_rgba (&res);
240       }
241
242       break;
243     case COLOR_TYPE_WIN32:
244       {
245         GdkRGBA res;
246
247         if (!_gtk_win32_theme_color_resolve (color->sym_col.win32.theme_class,
248                                              color->sym_col.win32.id,
249                                              &res))
250           return NULL;
251
252         value = _gtk_css_rgba_value_new_from_rgba (&res);
253       }
254
255       break;
256     case COLOR_TYPE_CURRENT_COLOR:
257       if (current)
258         {
259           *dependencies = current_deps;
260           return _gtk_css_value_ref (current);
261         }
262       else
263         {
264           return NULL;
265         }
266       break;
267     default:
268       g_assert_not_reached ();
269     }
270
271   if (value != NULL)
272     {
273       if (color->last_value != NULL &&
274           _gtk_css_value_equal (color->last_value, value))
275         {
276           _gtk_css_value_unref (value);
277           value = _gtk_css_value_ref (color->last_value);
278         }
279       else
280         {
281           if (color->last_value != NULL)
282             _gtk_css_value_unref (color->last_value);
283           color->last_value = _gtk_css_value_ref (value);
284         }
285     }
286
287   _gtk_css_rgba_value_get_rgba (value);
288   return value;
289 }
290
291 static GtkCssValue *
292 gtk_css_value_color_compute (GtkCssValue             *value,
293                              guint                    property_id,
294                              GtkStyleProviderPrivate *provider,
295                              GtkCssComputedValues    *values,
296                              GtkCssComputedValues    *parent_values,
297                              GtkCssDependencies      *dependencies)
298 {
299   GtkCssValue *resolved, *current;
300   GtkCssDependencies current_deps;
301
302   /* The computed value of the â€˜currentColor’ keyword is the computed
303    * value of the â€˜color’ property. If the â€˜currentColor’ keyword is
304    * set on the â€˜color’ property itself, it is treated as â€˜color: inherit’. 
305    */
306   if (property_id == GTK_CSS_PROPERTY_COLOR)
307     {
308       if (parent_values)
309         {
310           current = _gtk_css_computed_values_get_value (parent_values, GTK_CSS_PROPERTY_COLOR);
311           current_deps = GTK_CSS_EQUALS_PARENT;
312         }
313       else
314         {
315           current = _gtk_css_style_property_get_initial_value (_gtk_css_style_property_lookup_by_id (GTK_CSS_PROPERTY_COLOR));
316           current_deps = 0;
317         }
318     }
319   else
320     {
321       current = _gtk_css_computed_values_get_value (values, GTK_CSS_PROPERTY_COLOR);
322       current_deps = GTK_CSS_DEPENDS_ON_COLOR;
323     }
324   
325   resolved = _gtk_css_color_value_resolve (value,
326                                            provider,
327                                            current,
328                                            current_deps,
329                                            dependencies);
330
331   if (resolved == NULL)
332     return gtk_css_value_color_get_fallback (property_id, provider, values, parent_values);
333
334   return resolved;
335 }
336
337 static gboolean
338 gtk_css_value_color_equal (const GtkCssValue *value1,
339                            const GtkCssValue *value2)
340 {
341   if (value1->type != value2->type)
342     return FALSE;
343
344   switch (value1->type)
345     {
346     case COLOR_TYPE_LITERAL:
347       return _gtk_css_value_equal (value1->last_value, value2->last_value);
348     case COLOR_TYPE_NAME:
349       return g_str_equal (value1->sym_col.name, value2->sym_col.name);
350     case COLOR_TYPE_SHADE:
351       return value1->sym_col.shade.factor == value2->sym_col.shade.factor &&
352              _gtk_css_value_equal (value1->sym_col.shade.color,
353                                    value2->sym_col.shade.color);
354     case COLOR_TYPE_ALPHA:
355       return value1->sym_col.alpha.factor == value2->sym_col.alpha.factor &&
356              _gtk_css_value_equal (value1->sym_col.alpha.color,
357                                    value2->sym_col.alpha.color);
358     case COLOR_TYPE_MIX:
359       return value1->sym_col.mix.factor == value2->sym_col.mix.factor &&
360              _gtk_css_value_equal (value1->sym_col.mix.color1,
361                                    value2->sym_col.mix.color1) &&
362              _gtk_css_value_equal (value1->sym_col.mix.color2,
363                                    value2->sym_col.mix.color2);
364     case COLOR_TYPE_WIN32:
365       return g_str_equal (value1->sym_col.win32.theme_class, value2->sym_col.win32.theme_class) &&
366              value1->sym_col.win32.id == value2->sym_col.win32.id;
367     case COLOR_TYPE_CURRENT_COLOR:
368       return TRUE;
369     default:
370       g_assert_not_reached ();
371       return FALSE;
372     }
373 }
374
375 static GtkCssValue *
376 gtk_css_value_color_transition (GtkCssValue *start,
377                                 GtkCssValue *end,
378                                 guint        property_id,
379                                 double       progress)
380 {
381   return _gtk_css_color_value_new_mix (start, end, progress);
382 }
383
384 static void
385 gtk_css_value_color_print (const GtkCssValue *value,
386                            GString           *string)
387 {
388   switch (value->type)
389     {
390     case COLOR_TYPE_LITERAL:
391       _gtk_css_value_print (value->last_value, string);
392       break;
393     case COLOR_TYPE_NAME:
394       g_string_append (string, "@");
395       g_string_append (string, value->sym_col.name);
396       break;
397     case COLOR_TYPE_SHADE:
398       {
399         char factor[G_ASCII_DTOSTR_BUF_SIZE];
400
401         g_string_append (string, "shade(");
402         _gtk_css_value_print (value->sym_col.shade.color, string);
403         g_string_append (string, ", ");
404         g_ascii_dtostr (factor, sizeof (factor), value->sym_col.shade.factor);
405         g_string_append (string, factor);
406         g_string_append (string, ")");
407       }
408       break;
409     case COLOR_TYPE_ALPHA:
410       {
411         char factor[G_ASCII_DTOSTR_BUF_SIZE];
412
413         g_string_append (string, "alpha(");
414         _gtk_css_value_print (value->sym_col.alpha.color, string);
415         g_string_append (string, ", ");
416         g_ascii_dtostr (factor, sizeof (factor), value->sym_col.alpha.factor);
417         g_string_append (string, factor);
418         g_string_append (string, ")");
419       }
420       break;
421     case COLOR_TYPE_MIX:
422       {
423         char factor[G_ASCII_DTOSTR_BUF_SIZE];
424
425         g_string_append (string, "mix(");
426         _gtk_css_value_print (value->sym_col.mix.color1, string);
427         g_string_append (string, ", ");
428         _gtk_css_value_print (value->sym_col.mix.color2, string);
429         g_string_append (string, ", ");
430         g_ascii_dtostr (factor, sizeof (factor), value->sym_col.mix.factor);
431         g_string_append (string, factor);
432         g_string_append (string, ")");
433       }
434       break;
435     case COLOR_TYPE_WIN32:
436       {
437         g_string_append_printf (string, GTK_WIN32_THEME_SYMBOLIC_COLOR_NAME"(%s, %d)", 
438                                 value->sym_col.win32.theme_class, value->sym_col.win32.id);
439       }
440       break;
441     case COLOR_TYPE_CURRENT_COLOR:
442       g_string_append (string, "currentColor");
443       break;
444     default:
445       g_assert_not_reached ();
446     }
447 }
448
449 static const GtkCssValueClass GTK_CSS_VALUE_COLOR = {
450   gtk_css_value_color_free,
451   gtk_css_value_color_compute,
452   gtk_css_value_color_equal,
453   gtk_css_value_color_transition,
454   gtk_css_value_color_print
455 };
456
457 GtkCssValue *
458 _gtk_css_color_value_new_literal (const GdkRGBA *color)
459 {
460   GtkCssValue *value;
461
462   g_return_val_if_fail (color != NULL, NULL);
463
464   value = _gtk_css_value_new (GtkCssValue, &GTK_CSS_VALUE_COLOR);
465   value->type = COLOR_TYPE_LITERAL;
466   value->last_value = _gtk_css_rgba_value_new_from_rgba (color);
467
468   return value;
469 }
470
471 GtkCssValue *
472 _gtk_css_color_value_new_rgba (double red,
473                                double green,
474                                double blue,
475                                double alpha)
476 {
477   GdkRGBA rgba = { red, green, blue, alpha };
478
479   return _gtk_css_color_value_new_literal (&rgba);
480 }
481
482 GtkCssValue *
483 _gtk_css_color_value_new_name (const gchar *name)
484 {
485   GtkCssValue *value;
486
487   g_return_val_if_fail (name != NULL, NULL);
488
489   value = _gtk_css_value_new (GtkCssValue, &GTK_CSS_VALUE_COLOR);
490   value->type = COLOR_TYPE_NAME;
491   value->sym_col.name = g_strdup (name);
492
493   return value;
494 }
495
496 GtkCssValue *
497 _gtk_css_color_value_new_shade (GtkCssValue *color,
498                                 gdouble      factor)
499 {
500   GtkCssValue *value;
501
502   g_return_val_if_fail (color->class == &GTK_CSS_VALUE_COLOR, NULL);
503
504   value = _gtk_css_value_new (GtkCssValue, &GTK_CSS_VALUE_COLOR);
505   value->type = COLOR_TYPE_SHADE;
506   value->sym_col.shade.color = _gtk_css_value_ref (color);
507   value->sym_col.shade.factor = factor;
508
509   return value;
510 }
511
512 GtkCssValue *
513 _gtk_css_color_value_new_alpha (GtkCssValue *color,
514                                 gdouble      factor)
515 {
516   GtkCssValue *value;
517
518   g_return_val_if_fail (color->class == &GTK_CSS_VALUE_COLOR, NULL);
519
520   value = _gtk_css_value_new (GtkCssValue, &GTK_CSS_VALUE_COLOR);
521   value->type = COLOR_TYPE_ALPHA;
522   value->sym_col.alpha.color = _gtk_css_value_ref (color);
523   value->sym_col.alpha.factor = factor;
524
525   return value;
526 }
527
528 GtkCssValue *
529 _gtk_css_color_value_new_mix (GtkCssValue *color1,
530                               GtkCssValue *color2,
531                               gdouble      factor)
532 {
533   GtkCssValue *value;
534
535   g_return_val_if_fail (color1->class == &GTK_CSS_VALUE_COLOR, NULL);
536   g_return_val_if_fail (color2->class == &GTK_CSS_VALUE_COLOR, NULL);
537
538   value = _gtk_css_value_new (GtkCssValue, &GTK_CSS_VALUE_COLOR);
539   value->type = COLOR_TYPE_MIX;
540   value->sym_col.mix.color1 = _gtk_css_value_ref (color1);
541   value->sym_col.mix.color2 = _gtk_css_value_ref (color2);
542   value->sym_col.mix.factor = factor;
543
544   return value;
545 }
546
547 GtkCssValue *
548 _gtk_css_color_value_new_win32 (const gchar *theme_class,
549                                 gint         id)
550 {
551   GtkCssValue *value;
552
553   g_return_val_if_fail (theme_class != NULL, NULL);
554
555   value = _gtk_css_value_new (GtkCssValue, &GTK_CSS_VALUE_COLOR);
556   value->type = COLOR_TYPE_WIN32;
557   value->sym_col.win32.theme_class = g_strdup (theme_class);
558   value->sym_col.win32.id = id;
559
560   return value;
561 }
562
563 GtkCssValue *
564 _gtk_css_color_value_new_current_color (void)
565 {
566   static GtkCssValue current_color = { &GTK_CSS_VALUE_COLOR, 1, COLOR_TYPE_CURRENT_COLOR, NULL, };
567
568   return _gtk_css_value_ref (&current_color);
569 }
570
571 typedef enum {
572   COLOR_RGBA,
573   COLOR_RGB,
574   COLOR_LIGHTER,
575   COLOR_DARKER,
576   COLOR_SHADE,
577   COLOR_ALPHA,
578   COLOR_MIX,
579   COLOR_WIN32
580 } ColorParseType;
581
582 static GtkCssValue *
583 gtk_css_color_parse_win32 (GtkCssParser *parser)
584 {
585   GtkCssValue *color;
586   char *class;
587   int id;
588
589   class = _gtk_css_parser_try_name (parser, TRUE);
590   if (class == NULL)
591     {
592       _gtk_css_parser_error (parser,
593                              "Expected name as first argument to  '-gtk-win32-color'");
594       return NULL;
595     }
596
597   if (! _gtk_css_parser_try (parser, ",", TRUE))
598     {
599       g_free (class);
600       _gtk_css_parser_error (parser,
601                              "Expected ','");
602       return NULL;
603     }
604
605   if (!_gtk_css_parser_try_int (parser, &id))
606     {
607       g_free (class);
608       _gtk_css_parser_error (parser, "Expected a valid integer value");
609       return NULL;
610     }
611
612   color = _gtk_css_color_value_new_win32 (class, id);
613   g_free (class);
614   return color;
615 }
616
617 static GtkCssValue *
618 _gtk_css_color_value_parse_function (GtkCssParser   *parser,
619                                      ColorParseType  color)
620 {
621   GtkCssValue *value;
622   GtkCssValue *child1, *child2;
623   double d;
624
625   if (!_gtk_css_parser_try (parser, "(", TRUE))
626     {
627       _gtk_css_parser_error (parser, "Missing opening bracket in color definition");
628       return NULL;
629     }
630
631   if (color == COLOR_RGB || color == COLOR_RGBA)
632     {
633       GdkRGBA rgba;
634       double tmp;
635       guint i;
636
637       for (i = 0; i < 3; i++)
638         {
639           if (i > 0 && !_gtk_css_parser_try (parser, ",", TRUE))
640             {
641               _gtk_css_parser_error (parser, "Expected ',' in color definition");
642               return NULL;
643             }
644
645           if (!_gtk_css_parser_try_double (parser, &tmp))
646             {
647               _gtk_css_parser_error (parser, "Invalid number for color value");
648               return NULL;
649             }
650           if (_gtk_css_parser_try (parser, "%", TRUE))
651             tmp /= 100.0;
652           else
653             tmp /= 255.0;
654           if (i == 0)
655             rgba.red = tmp;
656           else if (i == 1)
657             rgba.green = tmp;
658           else if (i == 2)
659             rgba.blue = tmp;
660           else
661             g_assert_not_reached ();
662         }
663
664       if (color == COLOR_RGBA)
665         {
666           if (i > 0 && !_gtk_css_parser_try (parser, ",", TRUE))
667             {
668               _gtk_css_parser_error (parser, "Expected ',' in color definition");
669               return NULL;
670             }
671
672           if (!_gtk_css_parser_try_double (parser, &rgba.alpha))
673             {
674               _gtk_css_parser_error (parser, "Invalid number for alpha value");
675               return NULL;
676             }
677         }
678       else
679         rgba.alpha = 1.0;
680       
681       value = _gtk_css_color_value_new_literal (&rgba);
682     }
683   else if (color == COLOR_WIN32)
684     {
685       value = gtk_css_color_parse_win32 (parser);
686       if (value == NULL)
687         return NULL;
688     }
689   else
690     {
691       child1 = _gtk_css_color_value_parse (parser);
692       if (child1 == NULL)
693         return NULL;
694
695       if (color == COLOR_MIX)
696         {
697           if (!_gtk_css_parser_try (parser, ",", TRUE))
698             {
699               _gtk_css_parser_error (parser, "Expected ',' in color definition");
700               _gtk_css_value_unref (child1);
701               return NULL;
702             }
703
704           child2 = _gtk_css_color_value_parse (parser);
705           if (child2 == NULL)
706             {
707               _gtk_css_value_unref (child1);
708               return NULL;
709             }
710         }
711       else
712         child2 = NULL;
713
714       if (color == COLOR_LIGHTER)
715         d = 1.3;
716       else if (color == COLOR_DARKER)
717         d = 0.7;
718       else
719         {
720           if (!_gtk_css_parser_try (parser, ",", TRUE))
721             {
722               _gtk_css_parser_error (parser, "Expected ',' in color definition");
723               _gtk_css_value_unref (child1);
724               if (child2)
725                 _gtk_css_value_unref (child2);
726               return NULL;
727             }
728
729           if (!_gtk_css_parser_try_double (parser, &d))
730             {
731               _gtk_css_parser_error (parser, "Expected number in color definition");
732               _gtk_css_value_unref (child1);
733               if (child2)
734                 _gtk_css_value_unref (child2);
735               return NULL;
736             }
737         }
738       
739       switch (color)
740         {
741         case COLOR_LIGHTER:
742         case COLOR_DARKER:
743         case COLOR_SHADE:
744           value = _gtk_css_color_value_new_shade (child1, d);
745           break;
746         case COLOR_ALPHA:
747           value = _gtk_css_color_value_new_alpha (child1, d);
748           break;
749         case COLOR_MIX:
750           value = _gtk_css_color_value_new_mix (child1, child2, d);
751           break;
752         default:
753           g_assert_not_reached ();
754           value = NULL;
755         }
756
757       _gtk_css_value_unref (child1);
758       if (child2)
759         _gtk_css_value_unref (child2);
760     }
761
762   if (!_gtk_css_parser_try (parser, ")", TRUE))
763     {
764       _gtk_css_parser_error (parser, "Expected ')' in color definition");
765       _gtk_css_value_unref (value);
766       return NULL;
767     }
768
769   return value;
770 }
771
772 GtkCssValue *
773 _gtk_css_color_value_parse (GtkCssParser *parser)
774 {
775   GtkCssValue *value;
776   GdkRGBA rgba;
777   guint color;
778   const char *names[] = {"rgba", "rgb",  "lighter", "darker", "shade", "alpha", "mix",
779                          GTK_WIN32_THEME_SYMBOLIC_COLOR_NAME};
780   char *name;
781
782   if (_gtk_css_parser_try (parser, "currentColor", TRUE))
783     return _gtk_css_color_value_new_current_color ();
784
785   if (_gtk_css_parser_try (parser, "transparent", TRUE))
786     {
787       GdkRGBA transparent = { 0, 0, 0, 0 };
788       
789       return _gtk_css_color_value_new_literal (&transparent);
790     }
791
792   if (_gtk_css_parser_try (parser, "@", FALSE))
793     {
794       name = _gtk_css_parser_try_name (parser, TRUE);
795
796       if (name)
797         {
798           value = _gtk_css_color_value_new_name (name);
799         }
800       else
801         {
802           _gtk_css_parser_error (parser, "'%s' is not a valid color color name", name);
803           value = NULL;
804         }
805
806       g_free (name);
807       return value;
808     }
809
810   for (color = 0; color < G_N_ELEMENTS (names); color++)
811     {
812       if (_gtk_css_parser_try (parser, names[color], TRUE))
813         break;
814     }
815
816   if (color < G_N_ELEMENTS (names))
817     return _gtk_css_color_value_parse_function (parser, color);
818
819   if (_gtk_css_parser_try_hash_color (parser, &rgba))
820     return _gtk_css_color_value_new_literal (&rgba);
821
822   name = _gtk_css_parser_try_name (parser, TRUE);
823   if (name)
824     {
825       if (gdk_rgba_parse (&rgba, name))
826         {
827           value = _gtk_css_color_value_new_literal (&rgba);
828         }
829       else
830         {
831           _gtk_css_parser_error (parser, "'%s' is not a valid color name", name);
832           value = NULL;
833         }
834       g_free (name);
835       return value;
836     }
837
838   _gtk_css_parser_error (parser, "Not a color definition");
839   return NULL;
840 }
841