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