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 "gtkcssstylepropertyprivate.h"
23#include "gtkprivate.h"
24#include "gtkstylepropertyprivate.h"
25
26#include "gdk/gdkhslaprivate.h"
27#include "gdk/gdkrgbaprivate.h"
28
29typedef enum {
30 COLOR_TYPE_LITERAL,
31 COLOR_TYPE_NAME,
32 COLOR_TYPE_SHADE,
33 COLOR_TYPE_ALPHA,
34 COLOR_TYPE_MIX,
35 COLOR_TYPE_CURRENT_COLOR
36} ColorType;
37
38struct _GtkCssValue
39{
40 GTK_CSS_VALUE_BASE
41 ColorType type;
42 GtkCssValue *last_value;
43
44 union
45 {
46 char *name;
47 GdkRGBA rgba;
48
49 struct
50 {
51 GtkCssValue *color;
52 double factor;
53 } shade, alpha;
54
55 struct
56 {
57 GtkCssValue *color1;
58 GtkCssValue *color2;
59 double factor;
60 } mix;
61 } sym_col;
62};
63
64static void
65gtk_css_value_color_free (GtkCssValue *color)
66{
67 if (color->last_value)
68 _gtk_css_value_unref (value: color->last_value);
69
70 switch (color->type)
71 {
72 case COLOR_TYPE_NAME:
73 g_free (mem: color->sym_col.name);
74 break;
75 case COLOR_TYPE_SHADE:
76 _gtk_css_value_unref (value: color->sym_col.shade.color);
77 break;
78 case COLOR_TYPE_ALPHA:
79 _gtk_css_value_unref (value: color->sym_col.alpha.color);
80 break;
81 case COLOR_TYPE_MIX:
82 _gtk_css_value_unref (value: color->sym_col.mix.color1);
83 _gtk_css_value_unref (value: color->sym_col.mix.color2);
84 break;
85 case COLOR_TYPE_LITERAL:
86 case COLOR_TYPE_CURRENT_COLOR:
87 default:
88 break;
89 }
90
91 g_slice_free (GtkCssValue, color);
92}
93
94static GtkCssValue *
95gtk_css_value_color_get_fallback (guint property_id,
96 GtkStyleProvider *provider,
97 GtkCssStyle *style,
98 GtkCssStyle *parent_style)
99{
100 switch (property_id)
101 {
102 case GTK_CSS_PROPERTY_BACKGROUND_IMAGE:
103 case GTK_CSS_PROPERTY_BORDER_IMAGE_SOURCE:
104 case GTK_CSS_PROPERTY_TEXT_SHADOW:
105 case GTK_CSS_PROPERTY_ICON_SHADOW:
106 case GTK_CSS_PROPERTY_BOX_SHADOW:
107 return gtk_css_color_value_new_transparent ();
108 case GTK_CSS_PROPERTY_COLOR:
109 case GTK_CSS_PROPERTY_BACKGROUND_COLOR:
110 case GTK_CSS_PROPERTY_BORDER_TOP_COLOR:
111 case GTK_CSS_PROPERTY_BORDER_RIGHT_COLOR:
112 case GTK_CSS_PROPERTY_BORDER_BOTTOM_COLOR:
113 case GTK_CSS_PROPERTY_BORDER_LEFT_COLOR:
114 case GTK_CSS_PROPERTY_OUTLINE_COLOR:
115 case GTK_CSS_PROPERTY_CARET_COLOR:
116 case GTK_CSS_PROPERTY_SECONDARY_CARET_COLOR:
117 return _gtk_css_value_compute (value: _gtk_css_style_property_get_initial_value (property: _gtk_css_style_property_lookup_by_id (id: property_id)),
118 property_id,
119 provider,
120 style,
121 parent_style);
122 case GTK_CSS_PROPERTY_ICON_PALETTE:
123 return _gtk_css_value_ref (value: style->core->color);
124 default:
125 if (property_id < GTK_CSS_PROPERTY_N_PROPERTIES)
126 g_warning ("No fallback color defined for property '%s'",
127 _gtk_style_property_get_name (GTK_STYLE_PROPERTY (_gtk_css_style_property_lookup_by_id (property_id))));
128 return gtk_css_color_value_new_transparent ();
129 }
130}
131
132static GtkCssValue *
133gtk_css_value_color_compute (GtkCssValue *value,
134 guint property_id,
135 GtkStyleProvider *provider,
136 GtkCssStyle *style,
137 GtkCssStyle *parent_style)
138{
139 GtkCssValue *resolved;
140
141 /* The computed value of the ‘currentColor’ keyword is the computed
142 * value of the ‘color’ property. If the ‘currentColor’ keyword is
143 * set on the ‘color’ property itself, it is treated as ‘color: inherit’.
144 */
145 if (property_id == GTK_CSS_PROPERTY_COLOR)
146 {
147 GtkCssValue *current;
148
149 if (parent_style)
150 current = parent_style->core->color;
151 else
152 current = NULL;
153
154 resolved = _gtk_css_color_value_resolve (color: value,
155 provider,
156 current,
157 NULL);
158 }
159 else if (value->type == COLOR_TYPE_LITERAL)
160 {
161 resolved = _gtk_css_value_ref (value);
162 }
163 else
164 {
165 GtkCssValue *current = style->core->color;
166
167 resolved = _gtk_css_color_value_resolve (color: value,
168 provider,
169 current,
170 NULL);
171 }
172
173 if (resolved == NULL)
174 return gtk_css_value_color_get_fallback (property_id, provider, style, parent_style);
175
176 return resolved;
177}
178
179static gboolean
180gtk_css_value_color_equal (const GtkCssValue *value1,
181 const GtkCssValue *value2)
182{
183 if (value1->type != value2->type)
184 return FALSE;
185
186 switch (value1->type)
187 {
188 case COLOR_TYPE_LITERAL:
189 return gdk_rgba_equal (p1: &value1->sym_col.rgba, p2: &value2->sym_col.rgba);
190 case COLOR_TYPE_NAME:
191 return g_str_equal (v1: value1->sym_col.name, v2: value2->sym_col.name);
192 case COLOR_TYPE_SHADE:
193 return value1->sym_col.shade.factor == value2->sym_col.shade.factor &&
194 _gtk_css_value_equal (value1: value1->sym_col.shade.color,
195 value2: value2->sym_col.shade.color);
196 case COLOR_TYPE_ALPHA:
197 return value1->sym_col.alpha.factor == value2->sym_col.alpha.factor &&
198 _gtk_css_value_equal (value1: value1->sym_col.alpha.color,
199 value2: value2->sym_col.alpha.color);
200 case COLOR_TYPE_MIX:
201 return value1->sym_col.mix.factor == value2->sym_col.mix.factor &&
202 _gtk_css_value_equal (value1: value1->sym_col.mix.color1,
203 value2: value2->sym_col.mix.color1) &&
204 _gtk_css_value_equal (value1: value1->sym_col.mix.color2,
205 value2: value2->sym_col.mix.color2);
206 case COLOR_TYPE_CURRENT_COLOR:
207 return TRUE;
208 default:
209 g_assert_not_reached ();
210 return FALSE;
211 }
212}
213
214static GtkCssValue *
215gtk_css_value_color_transition (GtkCssValue *start,
216 GtkCssValue *end,
217 guint property_id,
218 double progress)
219{
220 return _gtk_css_color_value_new_mix (color1: start, color2: end, factor: progress);
221}
222
223static void
224gtk_css_value_color_print (const GtkCssValue *value,
225 GString *string)
226{
227 switch (value->type)
228 {
229 case COLOR_TYPE_LITERAL:
230 {
231 char *s = gdk_rgba_to_string (rgba: &value->sym_col.rgba);
232 g_string_append (string, val: s);
233 g_free (mem: s);
234 }
235 break;
236 case COLOR_TYPE_NAME:
237 g_string_append (string, val: "@");
238 g_string_append (string, val: value->sym_col.name);
239 break;
240 case COLOR_TYPE_SHADE:
241 {
242 char factor[G_ASCII_DTOSTR_BUF_SIZE];
243
244 g_string_append (string, val: "shade(");
245 _gtk_css_value_print (value: value->sym_col.shade.color, string);
246 g_string_append (string, val: ", ");
247 g_ascii_dtostr (buffer: factor, buf_len: sizeof (factor), d: value->sym_col.shade.factor);
248 g_string_append (string, val: factor);
249 g_string_append (string, val: ")");
250 }
251 break;
252 case COLOR_TYPE_ALPHA:
253 {
254 char factor[G_ASCII_DTOSTR_BUF_SIZE];
255
256 g_string_append (string, val: "alpha(");
257 _gtk_css_value_print (value: value->sym_col.alpha.color, string);
258 g_string_append (string, val: ", ");
259 g_ascii_dtostr (buffer: factor, buf_len: sizeof (factor), d: value->sym_col.alpha.factor);
260 g_string_append (string, val: factor);
261 g_string_append (string, val: ")");
262 }
263 break;
264 case COLOR_TYPE_MIX:
265 {
266 char factor[G_ASCII_DTOSTR_BUF_SIZE];
267
268 g_string_append (string, val: "mix(");
269 _gtk_css_value_print (value: value->sym_col.mix.color1, string);
270 g_string_append (string, val: ", ");
271 _gtk_css_value_print (value: value->sym_col.mix.color2, string);
272 g_string_append (string, val: ", ");
273 g_ascii_dtostr (buffer: factor, buf_len: sizeof (factor), d: value->sym_col.mix.factor);
274 g_string_append (string, val: factor);
275 g_string_append (string, val: ")");
276 }
277 break;
278 case COLOR_TYPE_CURRENT_COLOR:
279 g_string_append (string, val: "currentColor");
280 break;
281 default:
282 g_assert_not_reached ();
283 }
284}
285
286static const GtkCssValueClass GTK_CSS_VALUE_COLOR = {
287 "GtkCssColorValue",
288 gtk_css_value_color_free,
289 gtk_css_value_color_compute,
290 gtk_css_value_color_equal,
291 gtk_css_value_color_transition,
292 NULL,
293 NULL,
294 gtk_css_value_color_print
295};
296
297static void
298apply_alpha (const GdkRGBA *in,
299 GdkRGBA *out,
300 double factor)
301{
302 *out = *in;
303
304 out->alpha = CLAMP (in->alpha * factor, 0, 1);
305}
306
307static void
308apply_shade (const GdkRGBA *in,
309 GdkRGBA *out,
310 double factor)
311{
312 GdkHSLA hsla;
313
314 _gdk_hsla_init_from_rgba (hsla: &hsla, rgba: in);
315 _gdk_hsla_shade (dest: &hsla, src: &hsla, factor);
316
317 _gdk_rgba_init_from_hsla (rgba: out, hsla: &hsla);
318}
319
320static inline double
321transition (double start,
322 double end,
323 double progress)
324{
325 return start + (end - start) * progress;
326}
327
328static void
329apply_mix (const GdkRGBA *in1,
330 const GdkRGBA *in2,
331 GdkRGBA *out,
332 double factor)
333{
334 out->alpha = CLAMP (transition (in1->alpha, in2->alpha, factor), 0, 1);
335
336 if (out->alpha <= 0.0)
337 {
338 out->red = out->green = out->blue = 0.0;
339 }
340 else
341 {
342 out->red = CLAMP (transition (in1->red * in1->alpha, in2->red * in2->alpha, factor), 0, 1) / out->alpha;
343 out->green = CLAMP (transition (in1->green * in1->alpha, in2->green * in2->alpha, factor), 0, 1) / out->alpha;
344 out->blue = CLAMP (transition (in1->blue * in1->alpha, in2->blue * in2->alpha, factor), 0, 1) / out->alpha;
345 }
346}
347
348GtkCssValue *
349_gtk_css_color_value_resolve (GtkCssValue *color,
350 GtkStyleProvider *provider,
351 GtkCssValue *current,
352 GSList *cycle_list)
353{
354 GtkCssValue *value;
355
356 gtk_internal_return_val_if_fail (color != NULL, NULL);
357
358 switch (color->type)
359 {
360 case COLOR_TYPE_LITERAL:
361 return _gtk_css_value_ref (value: color);
362 case COLOR_TYPE_NAME:
363 {
364 GtkCssValue *named;
365 GSList cycle = { color, cycle_list };
366
367 /* If color exists in cycle_list, we're currently resolving it.
368 * So we've detected a cycle. */
369 if (g_slist_find (list: cycle_list, data: color))
370 return NULL;
371
372 named = gtk_style_provider_get_color (provider, name: color->sym_col.name);
373 if (named == NULL)
374 return NULL;
375
376 value = _gtk_css_color_value_resolve (color: named, provider, current, cycle_list: &cycle);
377 if (value == NULL)
378 return NULL;
379 }
380
381 break;
382 case COLOR_TYPE_SHADE:
383 {
384 const GdkRGBA *c;
385 GtkCssValue *val;
386 GdkRGBA shade;
387
388 val = _gtk_css_color_value_resolve (color: color->sym_col.shade.color, provider, current, cycle_list);
389 if (val == NULL)
390 return NULL;
391 c = gtk_css_color_value_get_rgba (color: val);
392
393 apply_shade (in: c, out: &shade, factor: color->sym_col.shade.factor);
394
395 value = _gtk_css_color_value_new_literal (color: &shade);
396 _gtk_css_value_unref (value: val);
397 }
398
399 break;
400 case COLOR_TYPE_ALPHA:
401 {
402 const GdkRGBA *c;
403 GtkCssValue *val;
404 GdkRGBA alpha;
405
406 val = _gtk_css_color_value_resolve (color: color->sym_col.alpha.color, provider, current, cycle_list);
407 if (val == NULL)
408 return NULL;
409 c = gtk_css_color_value_get_rgba (color: val);
410
411 apply_alpha (in: c, out: &alpha, factor: color->sym_col.alpha.factor);
412
413 value = _gtk_css_color_value_new_literal (color: &alpha);
414 _gtk_css_value_unref (value: val);
415 }
416 break;
417
418 case COLOR_TYPE_MIX:
419 {
420 const GdkRGBA *color1, *color2;
421 GtkCssValue *val1, *val2;
422 GdkRGBA res;
423
424 val1 = _gtk_css_color_value_resolve (color: color->sym_col.mix.color1, provider, current, cycle_list);
425 if (val1 == NULL)
426 return NULL;
427 color1 = gtk_css_color_value_get_rgba (color: val1);
428
429 val2 = _gtk_css_color_value_resolve (color: color->sym_col.mix.color2, provider, current, cycle_list);
430 if (val2 == NULL)
431 return NULL;
432 color2 = gtk_css_color_value_get_rgba (color: val2);
433
434 apply_mix (in1: color1, in2: color2, out: &res, factor: color->sym_col.mix.factor);
435
436 value = _gtk_css_color_value_new_literal (color: &res);
437 _gtk_css_value_unref (value: val1);
438 _gtk_css_value_unref (value: val2);
439 }
440
441 break;
442 case COLOR_TYPE_CURRENT_COLOR:
443 if (current)
444 {
445 return _gtk_css_value_ref (value: current);
446 }
447 else
448 {
449 GtkCssValue *initial = _gtk_css_style_property_get_initial_value (property: _gtk_css_style_property_lookup_by_id (id: GTK_CSS_PROPERTY_COLOR));
450
451 if (initial->class == &GTK_CSS_VALUE_COLOR)
452 {
453 return _gtk_css_color_value_resolve (color: initial,
454 provider,
455 NULL,
456 cycle_list);
457 }
458 else
459 {
460 return _gtk_css_value_ref (value: initial);
461 }
462 }
463 break;
464 default:
465 value = NULL;
466 g_assert_not_reached ();
467 }
468
469 if (color->last_value != NULL &&
470 _gtk_css_value_equal (value1: color->last_value, value2: value))
471 {
472 _gtk_css_value_unref (value);
473 value = _gtk_css_value_ref (value: color->last_value);
474 }
475 else
476 {
477 if (color->last_value != NULL)
478 _gtk_css_value_unref (value: color->last_value);
479 color->last_value = _gtk_css_value_ref (value);
480 }
481
482 return value;
483}
484
485static GtkCssValue transparent_black_singleton = { &GTK_CSS_VALUE_COLOR, 1, TRUE, COLOR_TYPE_LITERAL, NULL,
486 .sym_col.rgba = {0, 0, 0, 0} };
487static GtkCssValue white_singleton = { &GTK_CSS_VALUE_COLOR, 1, TRUE, COLOR_TYPE_LITERAL, NULL,
488 .sym_col.rgba = {1, 1, 1, 1} };
489
490
491GtkCssValue *
492gtk_css_color_value_new_transparent (void)
493{
494 return _gtk_css_value_ref (value: &transparent_black_singleton);
495}
496
497GtkCssValue *
498gtk_css_color_value_new_white (void)
499{
500 return _gtk_css_value_ref (value: &white_singleton);
501}
502
503GtkCssValue *
504_gtk_css_color_value_new_literal (const GdkRGBA *color)
505{
506 GtkCssValue *value;
507
508 g_return_val_if_fail (color != NULL, NULL);
509
510 if (gdk_rgba_equal (p1: color, p2: &white_singleton.sym_col.rgba))
511 return _gtk_css_value_ref (value: &white_singleton);
512
513 if (gdk_rgba_equal (p1: color, p2: &transparent_black_singleton.sym_col.rgba))
514 return _gtk_css_value_ref (value: &transparent_black_singleton);
515
516 value = _gtk_css_value_new (GtkCssValue, &GTK_CSS_VALUE_COLOR);
517 value->type = COLOR_TYPE_LITERAL;
518 value->is_computed = TRUE;
519 value->sym_col.rgba = *color;
520
521 return value;
522}
523
524GtkCssValue *
525_gtk_css_color_value_new_name (const char *name)
526{
527 GtkCssValue *value;
528
529 gtk_internal_return_val_if_fail (name != NULL, NULL);
530
531 value = _gtk_css_value_new (GtkCssValue, &GTK_CSS_VALUE_COLOR);
532 value->type = COLOR_TYPE_NAME;
533 value->sym_col.name = g_strdup (str: name);
534
535 return value;
536}
537
538GtkCssValue *
539_gtk_css_color_value_new_shade (GtkCssValue *color,
540 double factor)
541{
542 GtkCssValue *value;
543
544 gtk_internal_return_val_if_fail (color->class == &GTK_CSS_VALUE_COLOR, NULL);
545
546 if (color->type == COLOR_TYPE_LITERAL)
547 {
548 GdkRGBA c;
549
550 apply_shade (in: &color->sym_col.rgba, out: &c, factor);
551
552 return _gtk_css_color_value_new_literal (color: &c);
553 }
554
555 value = _gtk_css_value_new (GtkCssValue, &GTK_CSS_VALUE_COLOR);
556 value->type = COLOR_TYPE_SHADE;
557 value->sym_col.shade.color = _gtk_css_value_ref (value: color);
558 value->sym_col.shade.factor = factor;
559
560 return value;
561}
562
563GtkCssValue *
564_gtk_css_color_value_new_alpha (GtkCssValue *color,
565 double factor)
566{
567 GtkCssValue *value;
568
569 gtk_internal_return_val_if_fail (color->class == &GTK_CSS_VALUE_COLOR, NULL);
570
571 if (color->type == COLOR_TYPE_LITERAL)
572 {
573 GdkRGBA c;
574
575 apply_alpha (in: &color->sym_col.rgba, out: &c, factor);
576
577 return _gtk_css_color_value_new_literal (color: &c);
578 }
579
580 value = _gtk_css_value_new (GtkCssValue, &GTK_CSS_VALUE_COLOR);
581 value->type = COLOR_TYPE_ALPHA;
582 value->sym_col.alpha.color = _gtk_css_value_ref (value: color);
583 value->sym_col.alpha.factor = factor;
584
585 return value;
586}
587
588GtkCssValue *
589_gtk_css_color_value_new_mix (GtkCssValue *color1,
590 GtkCssValue *color2,
591 double factor)
592{
593 GtkCssValue *value;
594
595 gtk_internal_return_val_if_fail (color1->class == &GTK_CSS_VALUE_COLOR, NULL);
596 gtk_internal_return_val_if_fail (color2->class == &GTK_CSS_VALUE_COLOR, NULL);
597
598 if (color1->type == COLOR_TYPE_LITERAL &&
599 color2->type == COLOR_TYPE_LITERAL)
600 {
601 GdkRGBA result;
602
603 apply_mix (in1: &color1->sym_col.rgba, in2: &color2->sym_col.rgba, out: &result, factor);
604
605 return _gtk_css_color_value_new_literal (color: &result);
606
607 }
608
609 value = _gtk_css_value_new (GtkCssValue, &GTK_CSS_VALUE_COLOR);
610 value->type = COLOR_TYPE_MIX;
611 value->sym_col.mix.color1 = _gtk_css_value_ref (value: color1);
612 value->sym_col.mix.color2 = _gtk_css_value_ref (value: color2);
613 value->sym_col.mix.factor = factor;
614
615 return value;
616}
617
618GtkCssValue *
619_gtk_css_color_value_new_current_color (void)
620{
621 static GtkCssValue current_color = { &GTK_CSS_VALUE_COLOR, 1, FALSE, COLOR_TYPE_CURRENT_COLOR, NULL, };
622
623 return _gtk_css_value_ref (value: &current_color);
624}
625
626typedef struct
627{
628 GtkCssValue *color;
629 GtkCssValue *color2;
630 double value;
631} ColorFunctionData;
632
633static guint
634parse_color_mix (GtkCssParser *parser,
635 guint arg,
636 gpointer data_)
637{
638 ColorFunctionData *data = data_;
639
640 switch (arg)
641 {
642 case 0:
643 data->color = _gtk_css_color_value_parse (parser);
644 if (data->color == NULL)
645 return 0;
646 return 1;
647
648 case 1:
649 data->color2 = _gtk_css_color_value_parse (parser);
650 if (data->color2 == NULL)
651 return 0;
652 return 1;
653
654 case 2:
655 if (!gtk_css_parser_consume_number (self: parser, number: &data->value))
656 return 0;
657 return 1;
658
659 default:
660 g_return_val_if_reached (0);
661 }
662}
663
664static guint
665parse_color_number (GtkCssParser *parser,
666 guint arg,
667 gpointer data_)
668{
669 ColorFunctionData *data = data_;
670
671 switch (arg)
672 {
673 case 0:
674 data->color = _gtk_css_color_value_parse (parser);
675 if (data->color == NULL)
676 return 0;
677 return 1;
678
679 case 1:
680 if (!gtk_css_parser_consume_number (self: parser, number: &data->value))
681 return 0;
682 return 1;
683
684 default:
685 g_return_val_if_reached (0);
686 }
687}
688
689gboolean
690gtk_css_color_value_can_parse (GtkCssParser *parser)
691{
692 /* This is way too generous, but meh... */
693 return gtk_css_parser_has_token (self: parser, token_type: GTK_CSS_TOKEN_IDENT)
694 || gtk_css_parser_has_token (self: parser, token_type: GTK_CSS_TOKEN_AT_KEYWORD)
695 || gtk_css_parser_has_token (self: parser, token_type: GTK_CSS_TOKEN_HASH_ID)
696 || gtk_css_parser_has_token (self: parser, token_type: GTK_CSS_TOKEN_HASH_UNRESTRICTED)
697 || gtk_css_parser_has_function (self: parser, name: "lighter")
698 || gtk_css_parser_has_function (self: parser, name: "darker")
699 || gtk_css_parser_has_function (self: parser, name: "shade")
700 || gtk_css_parser_has_function (self: parser, name: "alpha")
701 || gtk_css_parser_has_function (self: parser, name: "mix")
702 || gtk_css_parser_has_function (self: parser, name: "hsl")
703 || gtk_css_parser_has_function (self: parser, name: "hsla")
704 || gtk_css_parser_has_function (self: parser, name: "rgb")
705 || gtk_css_parser_has_function (self: parser, name: "rgba");
706}
707
708GtkCssValue *
709_gtk_css_color_value_parse (GtkCssParser *parser)
710{
711 ColorFunctionData data = { NULL, };
712 GtkCssValue *value;
713 GdkRGBA rgba;
714
715 if (gtk_css_parser_try_ident (self: parser, ident: "currentColor"))
716 {
717 return _gtk_css_color_value_new_current_color ();
718 }
719 else if (gtk_css_parser_has_token (self: parser, token_type: GTK_CSS_TOKEN_AT_KEYWORD))
720 {
721 const GtkCssToken *token = gtk_css_parser_get_token (self: parser);
722
723 value = _gtk_css_color_value_new_name (name: token->string.string);
724 gtk_css_parser_consume_token (self: parser);
725
726 return value;
727 }
728 else if (gtk_css_parser_has_function (self: parser, name: "lighter"))
729 {
730 if (gtk_css_parser_consume_function (self: parser, min_args: 1, max_args: 1, parse_func: parse_color_number, data: &data))
731 value = _gtk_css_color_value_new_shade (color: data.color, factor: 1.3);
732 else
733 value = NULL;
734
735 g_clear_pointer (&data.color, gtk_css_value_unref);
736 return value;
737 }
738 else if (gtk_css_parser_has_function (self: parser, name: "darker"))
739 {
740 if (gtk_css_parser_consume_function (self: parser, min_args: 1, max_args: 1, parse_func: parse_color_number, data: &data))
741 value = _gtk_css_color_value_new_shade (color: data.color, factor: 0.7);
742 else
743 value = NULL;
744
745 g_clear_pointer (&data.color, gtk_css_value_unref);
746 return value;
747 }
748 else if (gtk_css_parser_has_function (self: parser, name: "shade"))
749 {
750 if (gtk_css_parser_consume_function (self: parser, min_args: 2, max_args: 2, parse_func: parse_color_number, data: &data))
751 value = _gtk_css_color_value_new_shade (color: data.color, factor: data.value);
752 else
753 value = NULL;
754
755 g_clear_pointer (&data.color, gtk_css_value_unref);
756 return value;
757 }
758 else if (gtk_css_parser_has_function (self: parser, name: "alpha"))
759 {
760 if (gtk_css_parser_consume_function (self: parser, min_args: 2, max_args: 2, parse_func: parse_color_number, data: &data))
761 value = _gtk_css_color_value_new_alpha (color: data.color, factor: data.value);
762 else
763 value = NULL;
764
765 g_clear_pointer (&data.color, gtk_css_value_unref);
766 return value;
767 }
768 else if (gtk_css_parser_has_function (self: parser, name: "mix"))
769 {
770 if (gtk_css_parser_consume_function (self: parser, min_args: 3, max_args: 3, parse_func: parse_color_mix, data: &data))
771 value = _gtk_css_color_value_new_mix (color1: data.color, color2: data.color2, factor: data.value);
772 else
773 value = NULL;
774
775 g_clear_pointer (&data.color, gtk_css_value_unref);
776 g_clear_pointer (&data.color2, gtk_css_value_unref);
777 return value;
778 }
779
780 if (gdk_rgba_parser_parse (parser, rgba: &rgba))
781 return _gtk_css_color_value_new_literal (color: &rgba);
782 else
783 return NULL;
784}
785
786const GdkRGBA *
787gtk_css_color_value_get_rgba (const GtkCssValue *color)
788{
789 g_assert (color->class == &GTK_CSS_VALUE_COLOR);
790 g_assert (color->type == COLOR_TYPE_LITERAL);
791
792 return &color->sym_col.rgba;
793}
794

source code of gtk/gtk/gtkcsscolorvalue.c