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