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