1/* GTK - The GIMP Toolkit
2 * Copyright (C) 2011 Red Hat, Inc.
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 "gtkcssenumvalueprivate.h"
21
22#include "gtkcssstyleprivate.h"
23#include "gtkcssnumbervalueprivate.h"
24#include "gtkstyleproviderprivate.h"
25#include "gtksettingsprivate.h"
26
27#include "gtkpopcountprivate.h"
28
29/* repeated API */
30
31struct _GtkCssValue {
32 GTK_CSS_VALUE_BASE
33 int value;
34 const char *name;
35};
36
37static void
38gtk_css_value_enum_free (GtkCssValue *value)
39{
40 g_slice_free (GtkCssValue, value);
41}
42
43static GtkCssValue *
44gtk_css_value_enum_compute (GtkCssValue *value,
45 guint property_id,
46 GtkStyleProvider *provider,
47 GtkCssStyle *style,
48 GtkCssStyle *parent_style)
49{
50 return _gtk_css_value_ref (value);
51}
52
53static gboolean
54gtk_css_value_enum_equal (const GtkCssValue *enum1,
55 const GtkCssValue *enum2)
56{
57 return enum1 == enum2;
58}
59
60static GtkCssValue *
61gtk_css_value_enum_transition (GtkCssValue *start,
62 GtkCssValue *end,
63 guint property_id,
64 double progress)
65{
66 return NULL;
67}
68
69static void
70gtk_css_value_enum_print (const GtkCssValue *value,
71 GString *string)
72{
73 g_string_append (string, val: value->name);
74}
75
76/* GtkBorderStyle */
77
78static const GtkCssValueClass GTK_CSS_VALUE_BORDER_STYLE = {
79 "GtkCssBorderStyleValue",
80 gtk_css_value_enum_free,
81 gtk_css_value_enum_compute,
82 gtk_css_value_enum_equal,
83 gtk_css_value_enum_transition,
84 NULL,
85 NULL,
86 gtk_css_value_enum_print
87};
88
89static GtkCssValue border_style_values[] = {
90 { .class: &GTK_CSS_VALUE_BORDER_STYLE, .ref_count: 1, TRUE, .value: GTK_BORDER_STYLE_NONE, .name: "none" },
91 { &GTK_CSS_VALUE_BORDER_STYLE, 1, TRUE, GTK_BORDER_STYLE_SOLID, "solid" },
92 { &GTK_CSS_VALUE_BORDER_STYLE, 1, TRUE, GTK_BORDER_STYLE_INSET, "inset" },
93 { &GTK_CSS_VALUE_BORDER_STYLE, 1, TRUE, GTK_BORDER_STYLE_OUTSET, "outset" },
94 { &GTK_CSS_VALUE_BORDER_STYLE, 1, TRUE, GTK_BORDER_STYLE_HIDDEN, "hidden" },
95 { &GTK_CSS_VALUE_BORDER_STYLE, 1, TRUE, GTK_BORDER_STYLE_DOTTED, "dotted" },
96 { &GTK_CSS_VALUE_BORDER_STYLE, 1, TRUE, GTK_BORDER_STYLE_DASHED, "dashed" },
97 { &GTK_CSS_VALUE_BORDER_STYLE, 1, TRUE, GTK_BORDER_STYLE_DOUBLE, "double" },
98 { &GTK_CSS_VALUE_BORDER_STYLE, 1, TRUE, GTK_BORDER_STYLE_GROOVE, "groove" },
99 { &GTK_CSS_VALUE_BORDER_STYLE, 1, TRUE, GTK_BORDER_STYLE_RIDGE, "ridge" }
100};
101
102GtkCssValue *
103_gtk_css_border_style_value_new (GtkBorderStyle border_style)
104{
105 g_return_val_if_fail (border_style < G_N_ELEMENTS (border_style_values), NULL);
106
107 return _gtk_css_value_ref (value: &border_style_values[border_style]);
108}
109
110GtkCssValue *
111_gtk_css_border_style_value_try_parse (GtkCssParser *parser)
112{
113 guint i;
114
115 g_return_val_if_fail (parser != NULL, NULL);
116
117 for (i = 0; i < G_N_ELEMENTS (border_style_values); i++)
118 {
119 if (gtk_css_parser_try_ident (self: parser, ident: border_style_values[i].name))
120 return _gtk_css_value_ref (value: &border_style_values[i]);
121 }
122
123 return NULL;
124}
125
126GtkBorderStyle
127_gtk_css_border_style_value_get (const GtkCssValue *value)
128{
129 g_return_val_if_fail (value->class == &GTK_CSS_VALUE_BORDER_STYLE, GTK_BORDER_STYLE_NONE);
130
131 return value->value;
132}
133
134/* GtkCssBlendMode */
135
136static const GtkCssValueClass GTK_CSS_VALUE_BLEND_MODE = {
137 "GtkCssBlendModeValue",
138 gtk_css_value_enum_free,
139 gtk_css_value_enum_compute,
140 gtk_css_value_enum_equal,
141 gtk_css_value_enum_transition,
142 NULL,
143 NULL,
144 gtk_css_value_enum_print
145};
146
147static GtkCssValue blend_mode_values[] = {
148 { .class: &GTK_CSS_VALUE_BLEND_MODE, .ref_count: 1, TRUE, .value: GSK_BLEND_MODE_DEFAULT, .name: "normal" },
149 { &GTK_CSS_VALUE_BLEND_MODE, 1, TRUE, GSK_BLEND_MODE_MULTIPLY, "multiply" },
150 { &GTK_CSS_VALUE_BLEND_MODE, 1, TRUE, GSK_BLEND_MODE_SCREEN, "screen" },
151 { &GTK_CSS_VALUE_BLEND_MODE, 1, TRUE, GSK_BLEND_MODE_OVERLAY, "overlay" },
152 { &GTK_CSS_VALUE_BLEND_MODE, 1, TRUE, GSK_BLEND_MODE_DARKEN, "darken" },
153 { &GTK_CSS_VALUE_BLEND_MODE, 1, TRUE, GSK_BLEND_MODE_LIGHTEN, "lighten" },
154 { &GTK_CSS_VALUE_BLEND_MODE, 1, TRUE, GSK_BLEND_MODE_COLOR_DODGE, "color-dodge" },
155 { &GTK_CSS_VALUE_BLEND_MODE, 1, TRUE, GSK_BLEND_MODE_COLOR_BURN, "color-burn" },
156 { &GTK_CSS_VALUE_BLEND_MODE, 1, TRUE, GSK_BLEND_MODE_HARD_LIGHT, "hard-light" },
157 { &GTK_CSS_VALUE_BLEND_MODE, 1, TRUE, GSK_BLEND_MODE_SOFT_LIGHT, "soft-light" },
158 { &GTK_CSS_VALUE_BLEND_MODE, 1, TRUE, GSK_BLEND_MODE_DIFFERENCE, "difference" },
159 { &GTK_CSS_VALUE_BLEND_MODE, 1, TRUE, GSK_BLEND_MODE_EXCLUSION, "exclusion" },
160 { &GTK_CSS_VALUE_BLEND_MODE, 1, TRUE, GSK_BLEND_MODE_COLOR, "color" },
161 { &GTK_CSS_VALUE_BLEND_MODE, 1, TRUE, GSK_BLEND_MODE_HUE, "hue" },
162 { &GTK_CSS_VALUE_BLEND_MODE, 1, TRUE, GSK_BLEND_MODE_SATURATION, "saturation" },
163 { &GTK_CSS_VALUE_BLEND_MODE, 1, TRUE, GSK_BLEND_MODE_LUMINOSITY, "luminosity" }
164};
165
166GtkCssValue *
167_gtk_css_blend_mode_value_new (GskBlendMode blend_mode)
168{
169 g_return_val_if_fail (blend_mode < G_N_ELEMENTS (blend_mode_values), NULL);
170
171 return _gtk_css_value_ref (value: &blend_mode_values[blend_mode]);
172}
173
174GtkCssValue *
175_gtk_css_blend_mode_value_try_parse (GtkCssParser *parser)
176{
177 guint i;
178
179 g_return_val_if_fail (parser != NULL, NULL);
180
181 for (i = 0; i < G_N_ELEMENTS (blend_mode_values); i++)
182 {
183 if (gtk_css_parser_try_ident (self: parser, ident: blend_mode_values[i].name))
184 return _gtk_css_value_ref (value: &blend_mode_values[i]);
185 }
186
187 return NULL;
188}
189
190GskBlendMode
191_gtk_css_blend_mode_value_get (const GtkCssValue *value)
192{
193 g_return_val_if_fail (value->class == &GTK_CSS_VALUE_BLEND_MODE, GSK_BLEND_MODE_DEFAULT);
194
195 return value->value;
196}
197
198/* GtkCssFontSize */
199
200static double
201get_dpi (GtkCssStyle *style)
202{
203 return _gtk_css_number_value_get (number: style->core->dpi, one_hundred_percent: 96);
204}
205
206/* XXX: Kinda bad to have that machinery here, nobody expects vital font
207 * size code to appear in gtkcssvalueenum.c.
208 */
209#define DEFAULT_FONT_SIZE_PT 10
210
211double
212gtk_css_font_size_get_default_px (GtkStyleProvider *provider,
213 GtkCssStyle *style)
214{
215 GtkSettings *settings;
216 int font_size;
217
218 settings = gtk_style_provider_get_settings (provider);
219 if (settings == NULL)
220 return DEFAULT_FONT_SIZE_PT * get_dpi (style) / 72.0;
221
222 font_size = gtk_settings_get_font_size (settings);
223 if (font_size == 0)
224 return DEFAULT_FONT_SIZE_PT * get_dpi (style) / 72.0;
225 else if (gtk_settings_get_font_size_is_absolute (settings))
226 return (double) font_size / PANGO_SCALE;
227 else
228 return ((double) font_size / PANGO_SCALE) * get_dpi (style) / 72.0;
229}
230
231static GtkCssValue *
232gtk_css_value_font_size_compute (GtkCssValue *value,
233 guint property_id,
234 GtkStyleProvider *provider,
235 GtkCssStyle *style,
236 GtkCssStyle *parent_style)
237{
238 double font_size;
239
240 switch (value->value)
241 {
242 case GTK_CSS_FONT_SIZE_XX_SMALL:
243 font_size = gtk_css_font_size_get_default_px (provider, style) * 3. / 5;
244 break;
245 case GTK_CSS_FONT_SIZE_X_SMALL:
246 font_size = gtk_css_font_size_get_default_px (provider, style) * 3. / 4;
247 break;
248 case GTK_CSS_FONT_SIZE_SMALL:
249 font_size = gtk_css_font_size_get_default_px (provider, style) * 8. / 9;
250 break;
251 default:
252 g_assert_not_reached ();
253 /* fall thru */
254 case GTK_CSS_FONT_SIZE_MEDIUM:
255 font_size = gtk_css_font_size_get_default_px (provider, style);
256 break;
257 case GTK_CSS_FONT_SIZE_LARGE:
258 font_size = gtk_css_font_size_get_default_px (provider, style) * 6. / 5;
259 break;
260 case GTK_CSS_FONT_SIZE_X_LARGE:
261 font_size = gtk_css_font_size_get_default_px (provider, style) * 3. / 2;
262 break;
263 case GTK_CSS_FONT_SIZE_XX_LARGE:
264 font_size = gtk_css_font_size_get_default_px (provider, style) * 2;
265 break;
266 case GTK_CSS_FONT_SIZE_SMALLER:
267 if (parent_style)
268 font_size = _gtk_css_number_value_get (number: parent_style->core->font_size, one_hundred_percent: 100);
269 else
270 font_size = gtk_css_font_size_get_default_px (provider, style);
271 /* This is what WebKit does... */
272 font_size /= 1.2;
273 break;
274 case GTK_CSS_FONT_SIZE_LARGER:
275 if (parent_style)
276 font_size = _gtk_css_number_value_get (number: parent_style->core->font_size, one_hundred_percent: 100);
277 else
278 font_size = gtk_css_font_size_get_default_px (provider, style);
279 /* This is what WebKit does... */
280 font_size *= 1.2;
281 break;
282 }
283
284 return _gtk_css_number_value_new (value: font_size, unit: GTK_CSS_PX);
285}
286
287static const GtkCssValueClass GTK_CSS_VALUE_FONT_SIZE = {
288 "GtkCssFontSizeValue",
289 gtk_css_value_enum_free,
290 gtk_css_value_font_size_compute,
291 gtk_css_value_enum_equal,
292 gtk_css_value_enum_transition,
293 NULL,
294 NULL,
295 gtk_css_value_enum_print
296};
297
298static GtkCssValue font_size_values[] = {
299 { .class: &GTK_CSS_VALUE_FONT_SIZE, .ref_count: 1, FALSE, .value: GTK_CSS_FONT_SIZE_SMALLER, .name: "smaller" },
300 { &GTK_CSS_VALUE_FONT_SIZE, 1, FALSE, GTK_CSS_FONT_SIZE_LARGER, "larger" },
301 { &GTK_CSS_VALUE_FONT_SIZE, 1, FALSE, GTK_CSS_FONT_SIZE_XX_SMALL, "xx-small" },
302 { &GTK_CSS_VALUE_FONT_SIZE, 1, FALSE, GTK_CSS_FONT_SIZE_X_SMALL, "x-small" },
303 { &GTK_CSS_VALUE_FONT_SIZE, 1, FALSE, GTK_CSS_FONT_SIZE_SMALL, "small" },
304 { &GTK_CSS_VALUE_FONT_SIZE, 1, FALSE, GTK_CSS_FONT_SIZE_MEDIUM, "medium" },
305 { &GTK_CSS_VALUE_FONT_SIZE, 1, FALSE, GTK_CSS_FONT_SIZE_LARGE, "large" },
306 { &GTK_CSS_VALUE_FONT_SIZE, 1, FALSE, GTK_CSS_FONT_SIZE_X_LARGE, "x-large" },
307 { &GTK_CSS_VALUE_FONT_SIZE, 1, FALSE, GTK_CSS_FONT_SIZE_XX_LARGE, "xx-large" }
308};
309
310GtkCssValue *
311_gtk_css_font_size_value_new (GtkCssFontSize font_size)
312{
313 g_return_val_if_fail (font_size < G_N_ELEMENTS (font_size_values), NULL);
314
315 return _gtk_css_value_ref (value: &font_size_values[font_size]);
316}
317
318GtkCssValue *
319_gtk_css_font_size_value_try_parse (GtkCssParser *parser)
320{
321 guint i;
322
323 g_return_val_if_fail (parser != NULL, NULL);
324
325 for (i = 0; i < G_N_ELEMENTS (font_size_values); i++)
326 {
327 if (gtk_css_parser_try_ident (self: parser, ident: font_size_values[i].name))
328 return _gtk_css_value_ref (value: &font_size_values[i]);
329 }
330
331 return NULL;
332}
333
334GtkCssFontSize
335_gtk_css_font_size_value_get (const GtkCssValue *value)
336{
337 g_return_val_if_fail (value->class == &GTK_CSS_VALUE_FONT_SIZE, GTK_CSS_FONT_SIZE_MEDIUM);
338
339 return value->value;
340}
341
342/* PangoStyle */
343
344static const GtkCssValueClass GTK_CSS_VALUE_FONT_STYLE = {
345 "GtkCssFontStyleValue",
346 gtk_css_value_enum_free,
347 gtk_css_value_enum_compute,
348 gtk_css_value_enum_equal,
349 gtk_css_value_enum_transition,
350 NULL,
351 NULL,
352 gtk_css_value_enum_print
353};
354
355static GtkCssValue font_style_values[] = {
356 { .class: &GTK_CSS_VALUE_FONT_STYLE, .ref_count: 1, TRUE, .value: PANGO_STYLE_NORMAL, .name: "normal" },
357 { &GTK_CSS_VALUE_FONT_STYLE, 1, TRUE, PANGO_STYLE_OBLIQUE, "oblique" },
358 { &GTK_CSS_VALUE_FONT_STYLE, 1, TRUE, PANGO_STYLE_ITALIC, "italic" }
359};
360
361GtkCssValue *
362_gtk_css_font_style_value_new (PangoStyle font_style)
363{
364 g_return_val_if_fail (font_style < G_N_ELEMENTS (font_style_values), NULL);
365
366 return _gtk_css_value_ref (value: &font_style_values[font_style]);
367}
368
369GtkCssValue *
370_gtk_css_font_style_value_try_parse (GtkCssParser *parser)
371{
372 guint i;
373
374 g_return_val_if_fail (parser != NULL, NULL);
375
376 for (i = 0; i < G_N_ELEMENTS (font_style_values); i++)
377 {
378 if (gtk_css_parser_try_ident (self: parser, ident: font_style_values[i].name))
379 return _gtk_css_value_ref (value: &font_style_values[i]);
380 }
381
382 return NULL;
383}
384
385PangoStyle
386_gtk_css_font_style_value_get (const GtkCssValue *value)
387{
388 g_return_val_if_fail (value->class == &GTK_CSS_VALUE_FONT_STYLE, PANGO_STYLE_NORMAL);
389
390 return value->value;
391}
392
393/* PangoWeight */
394
395#define BOLDER -1
396#define LIGHTER -2
397
398static GtkCssValue *
399gtk_css_value_font_weight_compute (GtkCssValue *value,
400 guint property_id,
401 GtkStyleProvider *provider,
402 GtkCssStyle *style,
403 GtkCssStyle *parent_style)
404{
405 PangoWeight new_weight;
406 int parent_value;
407
408 if (value->value >= 0)
409 return _gtk_css_value_ref (value);
410
411 if (parent_style)
412 parent_value = _gtk_css_number_value_get (number: parent_style->font->font_weight, one_hundred_percent: 100);
413 else
414 parent_value = 400;
415
416 if (value->value == BOLDER)
417 {
418 if (parent_value < 350)
419 new_weight = 400;
420 else if (parent_value < 550)
421 new_weight = 700;
422 else
423 new_weight = 900;
424 }
425 else if (value->value == LIGHTER)
426 {
427 if (parent_value > 750)
428 new_weight = 700;
429 else if (parent_value > 550)
430 new_weight = 400;
431 else
432 new_weight = 100;
433 }
434 else
435 {
436 g_assert_not_reached ();
437 new_weight = PANGO_WEIGHT_NORMAL;
438 }
439
440 return _gtk_css_number_value_new (value: new_weight, unit: GTK_CSS_NUMBER);
441}
442
443static const GtkCssValueClass GTK_CSS_VALUE_FONT_WEIGHT = {
444 "GtkCssFontWeightValue",
445 gtk_css_value_enum_free,
446 gtk_css_value_font_weight_compute,
447 gtk_css_value_enum_equal,
448 NULL,
449 NULL,
450 NULL,
451 gtk_css_value_enum_print
452};
453
454static GtkCssValue font_weight_values[] = {
455 { .class: &GTK_CSS_VALUE_FONT_WEIGHT, .ref_count: 1, FALSE, BOLDER, .name: "bolder" },
456 { &GTK_CSS_VALUE_FONT_WEIGHT, 1, FALSE, LIGHTER, "lighter" },
457};
458
459GtkCssValue *
460gtk_css_font_weight_value_try_parse (GtkCssParser *parser)
461{
462 guint i;
463
464 g_return_val_if_fail (parser != NULL, NULL);
465
466 for (i = 0; i < G_N_ELEMENTS (font_weight_values); i++)
467 {
468 if (gtk_css_parser_try_ident (self: parser, ident: font_weight_values[i].name))
469 return _gtk_css_value_ref (value: &font_weight_values[i]);
470 }
471
472 if (gtk_css_parser_try_ident (self: parser, ident: "normal"))
473 return _gtk_css_number_value_new (value: PANGO_WEIGHT_NORMAL, unit: GTK_CSS_NUMBER);
474 if (gtk_css_parser_try_ident (self: parser, ident: "bold"))
475 return _gtk_css_number_value_new (value: PANGO_WEIGHT_BOLD, unit: GTK_CSS_NUMBER);
476
477 return NULL;
478}
479
480PangoWeight
481gtk_css_font_weight_value_get (const GtkCssValue *value)
482{
483 g_return_val_if_fail (value->class == &GTK_CSS_VALUE_FONT_WEIGHT, PANGO_WEIGHT_NORMAL);
484
485 return value->value;
486}
487
488#undef BOLDER
489#undef LIGHTER
490
491/* PangoStretch */
492
493static const GtkCssValueClass GTK_CSS_VALUE_FONT_STRETCH = {
494 "GtkCssFontStretchValue",
495 gtk_css_value_enum_free,
496 gtk_css_value_enum_compute,
497 gtk_css_value_enum_equal,
498 gtk_css_value_enum_transition,
499 NULL,
500 NULL,
501 gtk_css_value_enum_print
502};
503
504static GtkCssValue font_stretch_values[] = {
505 { .class: &GTK_CSS_VALUE_FONT_STRETCH, .ref_count: 1, TRUE, .value: PANGO_STRETCH_ULTRA_CONDENSED, .name: "ultra-condensed" },
506 { &GTK_CSS_VALUE_FONT_STRETCH, 1, TRUE, PANGO_STRETCH_EXTRA_CONDENSED, "extra-condensed" },
507 { &GTK_CSS_VALUE_FONT_STRETCH, 1, TRUE, PANGO_STRETCH_CONDENSED, "condensed" },
508 { &GTK_CSS_VALUE_FONT_STRETCH, 1, TRUE, PANGO_STRETCH_SEMI_CONDENSED, "semi-condensed" },
509 { &GTK_CSS_VALUE_FONT_STRETCH, 1, TRUE, PANGO_STRETCH_NORMAL, "normal" },
510 { &GTK_CSS_VALUE_FONT_STRETCH, 1, TRUE, PANGO_STRETCH_SEMI_EXPANDED, "semi-expanded" },
511 { &GTK_CSS_VALUE_FONT_STRETCH, 1, TRUE, PANGO_STRETCH_EXPANDED, "expanded" },
512 { &GTK_CSS_VALUE_FONT_STRETCH, 1, TRUE, PANGO_STRETCH_EXTRA_EXPANDED, "extra-expanded" },
513 { &GTK_CSS_VALUE_FONT_STRETCH, 1, TRUE, PANGO_STRETCH_ULTRA_EXPANDED, "ultra-expanded" },
514};
515
516GtkCssValue *
517_gtk_css_font_stretch_value_new (PangoStretch font_stretch)
518{
519 g_return_val_if_fail (font_stretch < G_N_ELEMENTS (font_stretch_values), NULL);
520
521 return _gtk_css_value_ref (value: &font_stretch_values[font_stretch]);
522}
523
524GtkCssValue *
525_gtk_css_font_stretch_value_try_parse (GtkCssParser *parser)
526{
527 guint i;
528
529 g_return_val_if_fail (parser != NULL, NULL);
530
531 for (i = 0; i < G_N_ELEMENTS (font_stretch_values); i++)
532 {
533 if (gtk_css_parser_try_ident (self: parser, ident: font_stretch_values[i].name))
534 return _gtk_css_value_ref (value: &font_stretch_values[i]);
535 }
536
537 return NULL;
538}
539
540PangoStretch
541_gtk_css_font_stretch_value_get (const GtkCssValue *value)
542{
543 g_return_val_if_fail (value->class == &GTK_CSS_VALUE_FONT_STRETCH, PANGO_STRETCH_NORMAL);
544
545 return value->value;
546}
547
548/* GtkTextDecorationStyle */
549
550static const GtkCssValueClass GTK_CSS_VALUE_TEXT_DECORATION_STYLE = {
551 "GtkCssTextDecorationStyleValue",
552 gtk_css_value_enum_free,
553 gtk_css_value_enum_compute,
554 gtk_css_value_enum_equal,
555 gtk_css_value_enum_transition,
556 NULL,
557 NULL,
558 gtk_css_value_enum_print
559};
560
561static GtkCssValue text_decoration_style_values[] = {
562 { .class: &GTK_CSS_VALUE_TEXT_DECORATION_STYLE, .ref_count: 1, TRUE, .value: GTK_CSS_TEXT_DECORATION_STYLE_SOLID, .name: "solid" },
563 { &GTK_CSS_VALUE_TEXT_DECORATION_STYLE, 1, TRUE, GTK_CSS_TEXT_DECORATION_STYLE_DOUBLE, "double" },
564 { &GTK_CSS_VALUE_TEXT_DECORATION_STYLE, 1, TRUE, GTK_CSS_TEXT_DECORATION_STYLE_WAVY, "wavy" },
565};
566
567GtkCssValue *
568_gtk_css_text_decoration_style_value_new (GtkTextDecorationStyle style)
569{
570 g_return_val_if_fail (style < G_N_ELEMENTS (text_decoration_style_values), NULL);
571
572 return _gtk_css_value_ref (value: &text_decoration_style_values[style]);
573}
574
575GtkCssValue *
576_gtk_css_text_decoration_style_value_try_parse (GtkCssParser *parser)
577{
578 guint i;
579
580 g_return_val_if_fail (parser != NULL, NULL);
581
582 for (i = 0; i < G_N_ELEMENTS (text_decoration_style_values); i++)
583 {
584 if (gtk_css_parser_try_ident (self: parser, ident: text_decoration_style_values[i].name))
585 return _gtk_css_value_ref (value: &text_decoration_style_values[i]);
586 }
587
588 return NULL;
589}
590
591GtkTextDecorationStyle
592_gtk_css_text_decoration_style_value_get (const GtkCssValue *value)
593{
594 g_return_val_if_fail (value->class == &GTK_CSS_VALUE_TEXT_DECORATION_STYLE, GTK_CSS_TEXT_DECORATION_STYLE_SOLID);
595
596 return value->value;
597}
598
599/* GtkCssArea */
600
601static const GtkCssValueClass GTK_CSS_VALUE_AREA = {
602 "GtkCssAreaValue",
603 gtk_css_value_enum_free,
604 gtk_css_value_enum_compute,
605 gtk_css_value_enum_equal,
606 gtk_css_value_enum_transition,
607 NULL,
608 NULL,
609 gtk_css_value_enum_print
610};
611
612static GtkCssValue area_values[] = {
613 { .class: &GTK_CSS_VALUE_AREA, .ref_count: 1, TRUE, .value: GTK_CSS_AREA_BORDER_BOX, .name: "border-box" },
614 { &GTK_CSS_VALUE_AREA, 1, TRUE, GTK_CSS_AREA_PADDING_BOX, "padding-box" },
615 { &GTK_CSS_VALUE_AREA, 1, TRUE, GTK_CSS_AREA_CONTENT_BOX, "content-box" }
616};
617
618GtkCssValue *
619_gtk_css_area_value_new (GtkCssArea area)
620{
621 guint i;
622
623 for (i = 0; i < G_N_ELEMENTS (area_values); i++)
624 {
625 if (area_values[i].value == area)
626 return _gtk_css_value_ref (value: &area_values[i]);
627 }
628
629 g_return_val_if_reached (NULL);
630}
631
632GtkCssValue *
633_gtk_css_area_value_try_parse (GtkCssParser *parser)
634{
635 guint i;
636
637 g_return_val_if_fail (parser != NULL, NULL);
638
639 for (i = 0; i < G_N_ELEMENTS (area_values); i++)
640 {
641 if (gtk_css_parser_try_ident (self: parser, ident: area_values[i].name))
642 return _gtk_css_value_ref (value: &area_values[i]);
643 }
644
645 return NULL;
646}
647
648GtkCssArea
649_gtk_css_area_value_get (const GtkCssValue *value)
650{
651 g_return_val_if_fail (value->class == &GTK_CSS_VALUE_AREA, GTK_CSS_AREA_BORDER_BOX);
652
653 return value->value;
654}
655
656/* GtkCssDirection */
657
658static const GtkCssValueClass GTK_CSS_VALUE_DIRECTION = {
659 "GtkCssDirectionValue",
660 gtk_css_value_enum_free,
661 gtk_css_value_enum_compute,
662 gtk_css_value_enum_equal,
663 gtk_css_value_enum_transition,
664 NULL,
665 NULL,
666 gtk_css_value_enum_print
667};
668
669static GtkCssValue direction_values[] = {
670 { .class: &GTK_CSS_VALUE_DIRECTION, .ref_count: 1, TRUE, .value: GTK_CSS_DIRECTION_NORMAL, .name: "normal" },
671 { &GTK_CSS_VALUE_DIRECTION, 1, TRUE, GTK_CSS_DIRECTION_REVERSE, "reverse" },
672 { &GTK_CSS_VALUE_DIRECTION, 1, TRUE, GTK_CSS_DIRECTION_ALTERNATE, "alternate" },
673 { &GTK_CSS_VALUE_DIRECTION, 1, TRUE, GTK_CSS_DIRECTION_ALTERNATE_REVERSE, "alternate-reverse" }
674};
675
676GtkCssValue *
677_gtk_css_direction_value_new (GtkCssDirection direction)
678{
679 guint i;
680
681 for (i = 0; i < G_N_ELEMENTS (direction_values); i++)
682 {
683 if (direction_values[i].value == direction)
684 return _gtk_css_value_ref (value: &direction_values[i]);
685 }
686
687 g_return_val_if_reached (NULL);
688}
689
690GtkCssValue *
691_gtk_css_direction_value_try_parse (GtkCssParser *parser)
692{
693 int i;
694
695 g_return_val_if_fail (parser != NULL, NULL);
696
697 /* need to parse backwards here, otherwise "alternate" will also match "alternate-reverse".
698 * Our parser rocks!
699 */
700 for (i = G_N_ELEMENTS (direction_values) - 1; i >= 0; i--)
701 {
702 if (gtk_css_parser_try_ident (self: parser, ident: direction_values[i].name))
703 return _gtk_css_value_ref (value: &direction_values[i]);
704 }
705
706 return NULL;
707}
708
709GtkCssDirection
710_gtk_css_direction_value_get (const GtkCssValue *value)
711{
712 g_return_val_if_fail (value->class == &GTK_CSS_VALUE_DIRECTION, GTK_CSS_DIRECTION_NORMAL);
713
714 return value->value;
715}
716
717/* GtkCssPlayState */
718
719static const GtkCssValueClass GTK_CSS_VALUE_PLAY_STATE = {
720 "GtkCssPlayStateValue",
721 gtk_css_value_enum_free,
722 gtk_css_value_enum_compute,
723 gtk_css_value_enum_equal,
724 gtk_css_value_enum_transition,
725 NULL,
726 NULL,
727 gtk_css_value_enum_print
728};
729
730static GtkCssValue play_state_values[] = {
731 { .class: &GTK_CSS_VALUE_PLAY_STATE, .ref_count: 1, TRUE, .value: GTK_CSS_PLAY_STATE_RUNNING, .name: "running" },
732 { &GTK_CSS_VALUE_PLAY_STATE, 1, TRUE, GTK_CSS_PLAY_STATE_PAUSED, "paused" }
733};
734
735GtkCssValue *
736_gtk_css_play_state_value_new (GtkCssPlayState play_state)
737{
738 guint i;
739
740 for (i = 0; i < G_N_ELEMENTS (play_state_values); i++)
741 {
742 if (play_state_values[i].value == play_state)
743 return _gtk_css_value_ref (value: &play_state_values[i]);
744 }
745
746 g_return_val_if_reached (NULL);
747}
748
749GtkCssValue *
750_gtk_css_play_state_value_try_parse (GtkCssParser *parser)
751{
752 guint i;
753
754 g_return_val_if_fail (parser != NULL, NULL);
755
756 for (i = 0; i < G_N_ELEMENTS (play_state_values); i++)
757 {
758 if (gtk_css_parser_try_ident (self: parser, ident: play_state_values[i].name))
759 return _gtk_css_value_ref (value: &play_state_values[i]);
760 }
761
762 return NULL;
763}
764
765GtkCssPlayState
766_gtk_css_play_state_value_get (const GtkCssValue *value)
767{
768 g_return_val_if_fail (value->class == &GTK_CSS_VALUE_PLAY_STATE, GTK_CSS_PLAY_STATE_RUNNING);
769
770 return value->value;
771}
772
773/* GtkCssFillMode */
774
775static const GtkCssValueClass GTK_CSS_VALUE_FILL_MODE = {
776 "GtkCssFillModeValue",
777 gtk_css_value_enum_free,
778 gtk_css_value_enum_compute,
779 gtk_css_value_enum_equal,
780 gtk_css_value_enum_transition,
781 NULL,
782 NULL,
783 gtk_css_value_enum_print
784};
785
786static GtkCssValue fill_mode_values[] = {
787 { .class: &GTK_CSS_VALUE_FILL_MODE, .ref_count: 1, TRUE, .value: GTK_CSS_FILL_NONE, .name: "none" },
788 { &GTK_CSS_VALUE_FILL_MODE, 1, TRUE, GTK_CSS_FILL_FORWARDS, "forwards" },
789 { &GTK_CSS_VALUE_FILL_MODE, 1, TRUE, GTK_CSS_FILL_BACKWARDS, "backwards" },
790 { &GTK_CSS_VALUE_FILL_MODE, 1, TRUE, GTK_CSS_FILL_BOTH, "both" }
791};
792
793GtkCssValue *
794_gtk_css_fill_mode_value_new (GtkCssFillMode fill_mode)
795{
796 guint i;
797
798 for (i = 0; i < G_N_ELEMENTS (fill_mode_values); i++)
799 {
800 if (fill_mode_values[i].value == fill_mode)
801 return _gtk_css_value_ref (value: &fill_mode_values[i]);
802 }
803
804 g_return_val_if_reached (NULL);
805}
806
807GtkCssValue *
808_gtk_css_fill_mode_value_try_parse (GtkCssParser *parser)
809{
810 guint i;
811
812 g_return_val_if_fail (parser != NULL, NULL);
813
814 for (i = 0; i < G_N_ELEMENTS (fill_mode_values); i++)
815 {
816 if (gtk_css_parser_try_ident (self: parser, ident: fill_mode_values[i].name))
817 return _gtk_css_value_ref (value: &fill_mode_values[i]);
818 }
819
820 return NULL;
821}
822
823GtkCssFillMode
824_gtk_css_fill_mode_value_get (const GtkCssValue *value)
825{
826 g_return_val_if_fail (value->class == &GTK_CSS_VALUE_FILL_MODE, GTK_CSS_FILL_NONE);
827
828 return value->value;
829}
830
831/* GtkCssIconStyle */
832
833static const GtkCssValueClass GTK_CSS_VALUE_ICON_STYLE = {
834 "GtkCssIconStyleValue",
835 gtk_css_value_enum_free,
836 gtk_css_value_enum_compute,
837 gtk_css_value_enum_equal,
838 gtk_css_value_enum_transition,
839 NULL,
840 NULL,
841 gtk_css_value_enum_print
842};
843
844static GtkCssValue icon_style_values[] = {
845 { .class: &GTK_CSS_VALUE_ICON_STYLE, .ref_count: 1, TRUE, .value: GTK_CSS_ICON_STYLE_REQUESTED, .name: "requested" },
846 { &GTK_CSS_VALUE_ICON_STYLE, 1, TRUE, GTK_CSS_ICON_STYLE_REGULAR, "regular" },
847 { &GTK_CSS_VALUE_ICON_STYLE, 1, TRUE, GTK_CSS_ICON_STYLE_SYMBOLIC, "symbolic" }
848};
849
850GtkCssValue *
851_gtk_css_icon_style_value_new (GtkCssIconStyle icon_style)
852{
853 guint i;
854
855 for (i = 0; i < G_N_ELEMENTS (icon_style_values); i++)
856 {
857 if (icon_style_values[i].value == icon_style)
858 return _gtk_css_value_ref (value: &icon_style_values[i]);
859 }
860
861 g_return_val_if_reached (NULL);
862}
863
864GtkCssValue *
865_gtk_css_icon_style_value_try_parse (GtkCssParser *parser)
866{
867 guint i;
868
869 g_return_val_if_fail (parser != NULL, NULL);
870
871 for (i = 0; i < G_N_ELEMENTS (icon_style_values); i++)
872 {
873 if (gtk_css_parser_try_ident (self: parser, ident: icon_style_values[i].name))
874 return _gtk_css_value_ref (value: &icon_style_values[i]);
875 }
876
877 return NULL;
878}
879
880GtkCssIconStyle
881_gtk_css_icon_style_value_get (const GtkCssValue *value)
882{
883 g_return_val_if_fail (value->class == &GTK_CSS_VALUE_ICON_STYLE, GTK_CSS_ICON_STYLE_REQUESTED);
884
885 return value->value;
886}
887
888/* GtkCssFontKerning */
889
890static const GtkCssValueClass GTK_CSS_VALUE_FONT_KERNING = {
891 "GtkCssFontKerningValue",
892 gtk_css_value_enum_free,
893 gtk_css_value_enum_compute,
894 gtk_css_value_enum_equal,
895 gtk_css_value_enum_transition,
896 NULL,
897 NULL,
898 gtk_css_value_enum_print
899};
900
901static GtkCssValue font_kerning_values[] = {
902 { .class: &GTK_CSS_VALUE_FONT_KERNING, .ref_count: 1, TRUE, .value: GTK_CSS_FONT_KERNING_AUTO, .name: "auto" },
903 { &GTK_CSS_VALUE_FONT_KERNING, 1, TRUE, GTK_CSS_FONT_KERNING_NORMAL, "normal" },
904 { &GTK_CSS_VALUE_FONT_KERNING, 1, TRUE, GTK_CSS_FONT_KERNING_NONE, "none" }
905};
906
907GtkCssValue *
908_gtk_css_font_kerning_value_new (GtkCssFontKerning kerning)
909{
910 guint i;
911
912 for (i = 0; i < G_N_ELEMENTS (font_kerning_values); i++)
913 {
914 if (font_kerning_values[i].value == kerning)
915 return _gtk_css_value_ref (value: &font_kerning_values[i]);
916 }
917
918 g_return_val_if_reached (NULL);
919}
920
921GtkCssValue *
922_gtk_css_font_kerning_value_try_parse (GtkCssParser *parser)
923{
924 guint i;
925
926 g_return_val_if_fail (parser != NULL, NULL);
927
928 for (i = 0; i < G_N_ELEMENTS (font_kerning_values); i++)
929 {
930 if (gtk_css_parser_try_ident (self: parser, ident: font_kerning_values[i].name))
931 return _gtk_css_value_ref (value: &font_kerning_values[i]);
932 }
933
934 return NULL;
935}
936
937GtkCssFontKerning
938_gtk_css_font_kerning_value_get (const GtkCssValue *value)
939{
940 g_return_val_if_fail (value->class == &GTK_CSS_VALUE_FONT_KERNING, GTK_CSS_FONT_KERNING_AUTO);
941
942 return value->value;
943}
944
945/* GtkCssFontVariantPos */
946
947static const GtkCssValueClass GTK_CSS_VALUE_FONT_VARIANT_POSITION = {
948 "GtkCssFontVariationPositionValue",
949 gtk_css_value_enum_free,
950 gtk_css_value_enum_compute,
951 gtk_css_value_enum_equal,
952 gtk_css_value_enum_transition,
953 NULL,
954 NULL,
955 gtk_css_value_enum_print
956};
957
958static GtkCssValue font_variant_position_values[] = {
959 { .class: &GTK_CSS_VALUE_FONT_VARIANT_POSITION, .ref_count: 1, TRUE, .value: GTK_CSS_FONT_VARIANT_POSITION_NORMAL, .name: "normal" },
960 { &GTK_CSS_VALUE_FONT_VARIANT_POSITION, 1, TRUE, GTK_CSS_FONT_VARIANT_POSITION_SUB, "sub" },
961 { &GTK_CSS_VALUE_FONT_VARIANT_POSITION, 1, TRUE, GTK_CSS_FONT_VARIANT_POSITION_SUPER, "super" }
962};
963
964GtkCssValue *
965_gtk_css_font_variant_position_value_new (GtkCssFontVariantPosition position)
966{
967 guint i;
968
969 for (i = 0; i < G_N_ELEMENTS (font_variant_position_values); i++)
970 {
971 if (font_variant_position_values[i].value == position)
972 return _gtk_css_value_ref (value: &font_variant_position_values[i]);
973 }
974
975 g_return_val_if_reached (NULL);
976}
977
978GtkCssValue *
979_gtk_css_font_variant_position_value_try_parse (GtkCssParser *parser)
980{
981 guint i;
982
983 g_return_val_if_fail (parser != NULL, NULL);
984
985 for (i = 0; i < G_N_ELEMENTS (font_variant_position_values); i++)
986 {
987 if (gtk_css_parser_try_ident (self: parser, ident: font_variant_position_values[i].name))
988 return _gtk_css_value_ref (value: &font_variant_position_values[i]);
989 }
990
991 return NULL;
992}
993
994GtkCssFontVariantPosition
995_gtk_css_font_variant_position_value_get (const GtkCssValue *value)
996{
997 g_return_val_if_fail (value->class == &GTK_CSS_VALUE_FONT_VARIANT_POSITION, GTK_CSS_FONT_VARIANT_POSITION_NORMAL);
998
999 return value->value;
1000}
1001
1002/* GtkCssFontVariantCaps */
1003
1004static const GtkCssValueClass GTK_CSS_VALUE_FONT_VARIANT_CAPS = {
1005 "GtkCssFontVariantCapsValue",
1006 gtk_css_value_enum_free,
1007 gtk_css_value_enum_compute,
1008 gtk_css_value_enum_equal,
1009 gtk_css_value_enum_transition,
1010 NULL,
1011 NULL,
1012 gtk_css_value_enum_print
1013};
1014
1015static GtkCssValue font_variant_caps_values[] = {
1016 { .class: &GTK_CSS_VALUE_FONT_VARIANT_CAPS, .ref_count: 1, TRUE, .value: GTK_CSS_FONT_VARIANT_CAPS_NORMAL, .name: "normal" },
1017 { &GTK_CSS_VALUE_FONT_VARIANT_CAPS, 1, TRUE, GTK_CSS_FONT_VARIANT_CAPS_SMALL_CAPS, "small-caps" },
1018 { &GTK_CSS_VALUE_FONT_VARIANT_CAPS, 1, TRUE, GTK_CSS_FONT_VARIANT_CAPS_ALL_SMALL_CAPS, "all-small-caps" },
1019 { &GTK_CSS_VALUE_FONT_VARIANT_CAPS, 1, TRUE, GTK_CSS_FONT_VARIANT_CAPS_PETITE_CAPS, "petite-caps" },
1020 { &GTK_CSS_VALUE_FONT_VARIANT_CAPS, 1, TRUE, GTK_CSS_FONT_VARIANT_CAPS_ALL_PETITE_CAPS, "all-petite-caps" },
1021 { &GTK_CSS_VALUE_FONT_VARIANT_CAPS, 1, TRUE, GTK_CSS_FONT_VARIANT_CAPS_UNICASE, "unicase" },
1022 { &GTK_CSS_VALUE_FONT_VARIANT_CAPS, 1, TRUE, GTK_CSS_FONT_VARIANT_CAPS_TITLING_CAPS, "titling-caps" }
1023};
1024
1025GtkCssValue *
1026_gtk_css_font_variant_caps_value_new (GtkCssFontVariantCaps caps)
1027{
1028 guint i;
1029
1030 for (i = 0; i < G_N_ELEMENTS (font_variant_caps_values); i++)
1031 {
1032 if (font_variant_caps_values[i].value == caps)
1033 return _gtk_css_value_ref (value: &font_variant_caps_values[i]);
1034 }
1035
1036 g_return_val_if_reached (NULL);
1037}
1038
1039GtkCssValue *
1040_gtk_css_font_variant_caps_value_try_parse (GtkCssParser *parser)
1041{
1042 guint i;
1043
1044 g_return_val_if_fail (parser != NULL, NULL);
1045
1046 for (i = 0; i < G_N_ELEMENTS (font_variant_caps_values); i++)
1047 {
1048 if (gtk_css_parser_try_ident (self: parser, ident: font_variant_caps_values[i].name))
1049 return _gtk_css_value_ref (value: &font_variant_caps_values[i]);
1050 }
1051
1052 return NULL;
1053}
1054
1055GtkCssFontVariantCaps
1056_gtk_css_font_variant_caps_value_get (const GtkCssValue *value)
1057{
1058 g_return_val_if_fail (value->class == &GTK_CSS_VALUE_FONT_VARIANT_CAPS, GTK_CSS_FONT_VARIANT_CAPS_NORMAL);
1059
1060 return value->value;
1061}
1062
1063/* GtkCssFontVariantAlternate */
1064
1065static const GtkCssValueClass GTK_CSS_VALUE_FONT_VARIANT_ALTERNATE = {
1066 "GtkCssFontVariantAlternateValue",
1067 gtk_css_value_enum_free,
1068 gtk_css_value_enum_compute,
1069 gtk_css_value_enum_equal,
1070 gtk_css_value_enum_transition,
1071 NULL,
1072 NULL,
1073 gtk_css_value_enum_print
1074};
1075
1076static GtkCssValue font_variant_alternate_values[] = {
1077 { .class: &GTK_CSS_VALUE_FONT_VARIANT_ALTERNATE, .ref_count: 1, TRUE, .value: GTK_CSS_FONT_VARIANT_ALTERNATE_NORMAL, .name: "normal" },
1078 { &GTK_CSS_VALUE_FONT_VARIANT_ALTERNATE, 1, TRUE, GTK_CSS_FONT_VARIANT_ALTERNATE_HISTORICAL_FORMS, "historical-forms" }
1079};
1080
1081GtkCssValue *
1082_gtk_css_font_variant_alternate_value_new (GtkCssFontVariantAlternate alternate)
1083{
1084 guint i;
1085
1086 for (i = 0; i < G_N_ELEMENTS (font_variant_alternate_values); i++)
1087 {
1088 if (font_variant_alternate_values[i].value == alternate)
1089 return _gtk_css_value_ref (value: &font_variant_alternate_values[i]);
1090 }
1091
1092 g_return_val_if_reached (NULL);
1093}
1094
1095GtkCssValue *
1096_gtk_css_font_variant_alternate_value_try_parse (GtkCssParser *parser)
1097{
1098 guint i;
1099
1100 g_return_val_if_fail (parser != NULL, NULL);
1101
1102 for (i = 0; i < G_N_ELEMENTS (font_variant_alternate_values); i++)
1103 {
1104 if (gtk_css_parser_try_ident (self: parser, ident: font_variant_alternate_values[i].name))
1105 return _gtk_css_value_ref (value: &font_variant_alternate_values[i]);
1106 }
1107
1108 return NULL;
1109}
1110
1111GtkCssFontVariantAlternate
1112_gtk_css_font_variant_alternate_value_get (const GtkCssValue *value)
1113{
1114 g_return_val_if_fail (value->class == &GTK_CSS_VALUE_FONT_VARIANT_ALTERNATE, GTK_CSS_FONT_VARIANT_ALTERNATE_NORMAL);
1115
1116 return value->value;
1117}
1118
1119/* below are flags, which are handle a bit differently. We allocate values dynamically,
1120 * and we parse one bit at a time, while allowing for detection of invalid combinations.
1121 */
1122
1123typedef struct {
1124 int value;
1125 const char *name;
1126} FlagsValue;
1127
1128static gboolean
1129gtk_css_value_flags_equal (const GtkCssValue *enum1,
1130 const GtkCssValue *enum2)
1131{
1132 return enum1->value == enum2->value;
1133}
1134
1135static void
1136gtk_css_value_flags_print (const FlagsValue *values,
1137 guint n_values,
1138 const GtkCssValue *value,
1139 GString *string)
1140{
1141 guint i;
1142 const char *sep = "";
1143
1144 for (i = 0; i < n_values; i++)
1145 {
1146 if (value->value & values[i].value)
1147 {
1148 g_string_append (string, val: sep);
1149 g_string_append (string, val: values[i].name);
1150 sep = " ";
1151 }
1152 }
1153}
1154
1155/* GtkTextDecorationLine */
1156
1157static FlagsValue text_decoration_line_values[] = {
1158 { GTK_CSS_TEXT_DECORATION_LINE_NONE, "none" },
1159 { GTK_CSS_TEXT_DECORATION_LINE_UNDERLINE, "underline" },
1160 { GTK_CSS_TEXT_DECORATION_LINE_OVERLINE, "overline" },
1161 { GTK_CSS_TEXT_DECORATION_LINE_LINE_THROUGH, "line-through" },
1162};
1163
1164static void
1165gtk_css_text_decoration_line_value_print (const GtkCssValue *value,
1166 GString *string)
1167{
1168 gtk_css_value_flags_print (values: text_decoration_line_values,
1169 G_N_ELEMENTS (text_decoration_line_values),
1170 value, string);
1171}
1172
1173static const GtkCssValueClass GTK_CSS_VALUE_TEXT_DECORATION_LINE = {
1174 "GtkCssTextDecorationLine",
1175 gtk_css_value_enum_free,
1176 gtk_css_value_enum_compute,
1177 gtk_css_value_flags_equal,
1178 gtk_css_value_enum_transition,
1179 NULL,
1180 NULL,
1181 gtk_css_text_decoration_line_value_print
1182};
1183
1184static gboolean
1185text_decoration_line_is_valid (GtkTextDecorationLine line)
1186{
1187 if ((line & GTK_CSS_TEXT_DECORATION_LINE_NONE) &&
1188 (line != GTK_CSS_TEXT_DECORATION_LINE_NONE))
1189 return FALSE;
1190
1191 return TRUE;
1192}
1193
1194GtkCssValue *
1195_gtk_css_text_decoration_line_value_new (GtkTextDecorationLine line)
1196{
1197 GtkCssValue *value;
1198
1199 if (!text_decoration_line_is_valid (line))
1200 return NULL;
1201
1202 value = _gtk_css_value_new (GtkCssValue, &GTK_CSS_VALUE_TEXT_DECORATION_LINE);
1203 value->value = line;
1204 value->name = NULL;
1205 value->is_computed = TRUE;
1206
1207 return value;
1208}
1209
1210GtkTextDecorationLine
1211_gtk_css_text_decoration_line_try_parse_one (GtkCssParser *parser,
1212 GtkTextDecorationLine base)
1213{
1214 guint i;
1215 GtkTextDecorationLine value = 0;
1216
1217 g_return_val_if_fail (parser != NULL, 0);
1218
1219 for (i = 0; i < G_N_ELEMENTS (text_decoration_line_values); i++)
1220 {
1221 if (gtk_css_parser_try_ident (self: parser, ident: text_decoration_line_values[i].name))
1222 {
1223 value = text_decoration_line_values[i].value;
1224 break;
1225 }
1226 }
1227
1228 if (value == 0)
1229 return base; /* not parsing this value */
1230
1231 if ((base | value) == base)
1232 return 0; /* repeated value */
1233
1234 if (!text_decoration_line_is_valid (line: base | value))
1235 return 0; /* bad combination */
1236
1237 return base | value;
1238}
1239
1240GtkTextDecorationLine
1241_gtk_css_text_decoration_line_value_get (const GtkCssValue *value)
1242{
1243 g_return_val_if_fail (value->class == &GTK_CSS_VALUE_TEXT_DECORATION_LINE, GTK_CSS_TEXT_DECORATION_LINE_NONE);
1244
1245 return value->value;
1246}
1247
1248/* GtkCssFontVariantLigature */
1249
1250static FlagsValue font_variant_ligature_values[] = {
1251 { GTK_CSS_FONT_VARIANT_LIGATURE_NORMAL, "normal" },
1252 { GTK_CSS_FONT_VARIANT_LIGATURE_NONE, "none" },
1253 { GTK_CSS_FONT_VARIANT_LIGATURE_COMMON_LIGATURES, "common-ligatures" },
1254 { GTK_CSS_FONT_VARIANT_LIGATURE_NO_COMMON_LIGATURES, "no-common-ligatures" },
1255 { GTK_CSS_FONT_VARIANT_LIGATURE_DISCRETIONARY_LIGATURES, "discretionary-ligatures" },
1256 { GTK_CSS_FONT_VARIANT_LIGATURE_NO_DISCRETIONARY_LIGATURES, "no-discretionary-ligatures" },
1257 { GTK_CSS_FONT_VARIANT_LIGATURE_HISTORICAL_LIGATURES, "historical-ligatures" },
1258 { GTK_CSS_FONT_VARIANT_LIGATURE_NO_HISTORICAL_LIGATURES, "no-historical-ligatures" },
1259 { GTK_CSS_FONT_VARIANT_LIGATURE_CONTEXTUAL, "contextual" },
1260 { GTK_CSS_FONT_VARIANT_LIGATURE_NO_CONTEXTUAL, "no-contextual" }
1261};
1262
1263static void
1264gtk_css_font_variant_ligature_value_print (const GtkCssValue *value,
1265 GString *string)
1266{
1267 gtk_css_value_flags_print (values: font_variant_ligature_values,
1268 G_N_ELEMENTS (font_variant_ligature_values),
1269 value, string);
1270}
1271
1272static const GtkCssValueClass GTK_CSS_VALUE_FONT_VARIANT_LIGATURE = {
1273 "GtkCssFontVariantLigatureValue",
1274 gtk_css_value_enum_free,
1275 gtk_css_value_enum_compute,
1276 gtk_css_value_flags_equal,
1277 gtk_css_value_enum_transition,
1278 NULL,
1279 NULL,
1280 gtk_css_font_variant_ligature_value_print
1281};
1282
1283static gboolean
1284ligature_value_is_valid (GtkCssFontVariantLigature ligatures)
1285{
1286 if (((ligatures & GTK_CSS_FONT_VARIANT_LIGATURE_NORMAL) &&
1287 (ligatures != GTK_CSS_FONT_VARIANT_LIGATURE_NORMAL)) ||
1288 ((ligatures & GTK_CSS_FONT_VARIANT_LIGATURE_NONE) &&
1289 (ligatures != GTK_CSS_FONT_VARIANT_LIGATURE_NONE)) ||
1290 ((ligatures & GTK_CSS_FONT_VARIANT_LIGATURE_COMMON_LIGATURES) &&
1291 (ligatures & GTK_CSS_FONT_VARIANT_LIGATURE_NO_COMMON_LIGATURES)) ||
1292 ((ligatures & GTK_CSS_FONT_VARIANT_LIGATURE_DISCRETIONARY_LIGATURES) &&
1293 (ligatures & GTK_CSS_FONT_VARIANT_LIGATURE_NO_DISCRETIONARY_LIGATURES)) ||
1294 ((ligatures & GTK_CSS_FONT_VARIANT_LIGATURE_HISTORICAL_LIGATURES) &&
1295 (ligatures & GTK_CSS_FONT_VARIANT_LIGATURE_NO_HISTORICAL_LIGATURES)) ||
1296 ((ligatures & GTK_CSS_FONT_VARIANT_LIGATURE_CONTEXTUAL) &&
1297 (ligatures & GTK_CSS_FONT_VARIANT_LIGATURE_NO_CONTEXTUAL)))
1298 return FALSE;
1299
1300 return TRUE;
1301}
1302
1303GtkCssValue *
1304_gtk_css_font_variant_ligature_value_new (GtkCssFontVariantLigature ligatures)
1305{
1306 GtkCssValue *value;
1307
1308 if (!ligature_value_is_valid (ligatures))
1309 return NULL;
1310
1311 value = _gtk_css_value_new (GtkCssValue, &GTK_CSS_VALUE_FONT_VARIANT_LIGATURE);
1312 value->value = ligatures;
1313 value->name = NULL;
1314 value->is_computed = TRUE;
1315
1316 return value;
1317}
1318
1319GtkCssFontVariantLigature
1320_gtk_css_font_variant_ligature_try_parse_one (GtkCssParser *parser,
1321 GtkCssFontVariantLigature base)
1322{
1323 guint i;
1324 GtkCssFontVariantLigature value = 0;
1325
1326 g_return_val_if_fail (parser != NULL, 0);
1327
1328 for (i = 0; i < G_N_ELEMENTS (font_variant_ligature_values); i++)
1329 {
1330 if (gtk_css_parser_try_ident (self: parser, ident: font_variant_ligature_values[i].name))
1331 {
1332 value = font_variant_ligature_values[i].value;
1333 break;
1334 }
1335 }
1336
1337 if (value == 0)
1338 return base; /* not parsing this value */
1339
1340 if ((base | value) == base)
1341 return 0; /* repeated value */
1342
1343 if (!ligature_value_is_valid (ligatures: base | value))
1344 return 0; /* bad combination */
1345
1346 return base | value;
1347}
1348
1349GtkCssFontVariantLigature
1350_gtk_css_font_variant_ligature_value_get (const GtkCssValue *value)
1351{
1352 g_return_val_if_fail (value->class == &GTK_CSS_VALUE_FONT_VARIANT_LIGATURE, GTK_CSS_FONT_VARIANT_LIGATURE_NORMAL);
1353
1354 return value->value;
1355}
1356
1357/* GtkCssFontVariantNumeric */
1358
1359static FlagsValue font_variant_numeric_values[] = {
1360 { GTK_CSS_FONT_VARIANT_NUMERIC_NORMAL, "normal" },
1361 { GTK_CSS_FONT_VARIANT_NUMERIC_LINING_NUMS, "lining-nums" },
1362 { GTK_CSS_FONT_VARIANT_NUMERIC_OLDSTYLE_NUMS, "oldstyle-nums" },
1363 { GTK_CSS_FONT_VARIANT_NUMERIC_PROPORTIONAL_NUMS, "proportional-nums" },
1364 { GTK_CSS_FONT_VARIANT_NUMERIC_TABULAR_NUMS, "tabular-nums" },
1365 { GTK_CSS_FONT_VARIANT_NUMERIC_DIAGONAL_FRACTIONS, "diagonal-fractions" },
1366 { GTK_CSS_FONT_VARIANT_NUMERIC_STACKED_FRACTIONS, "stacked-fractions" },
1367 { GTK_CSS_FONT_VARIANT_NUMERIC_ORDINAL, "ordinal" },
1368 { GTK_CSS_FONT_VARIANT_NUMERIC_SLASHED_ZERO, "slashed-zero" }
1369};
1370
1371static void
1372gtk_css_font_variant_numeric_value_print (const GtkCssValue *value,
1373 GString *string)
1374{
1375 gtk_css_value_flags_print (values: font_variant_numeric_values,
1376 G_N_ELEMENTS (font_variant_numeric_values),
1377 value, string);
1378}
1379
1380static const GtkCssValueClass GTK_CSS_VALUE_FONT_VARIANT_NUMERIC = {
1381 "GtkCssFontVariantNumbericValue",
1382 gtk_css_value_enum_free,
1383 gtk_css_value_enum_compute,
1384 gtk_css_value_flags_equal,
1385 gtk_css_value_enum_transition,
1386 NULL,
1387 NULL,
1388 gtk_css_font_variant_numeric_value_print
1389};
1390
1391static gboolean
1392numeric_value_is_valid (GtkCssFontVariantNumeric numeric)
1393{
1394 if (((numeric & GTK_CSS_FONT_VARIANT_NUMERIC_NORMAL) &&
1395 (numeric != GTK_CSS_FONT_VARIANT_NUMERIC_NORMAL)) ||
1396 ((numeric & GTK_CSS_FONT_VARIANT_NUMERIC_LINING_NUMS) &&
1397 (numeric & GTK_CSS_FONT_VARIANT_NUMERIC_OLDSTYLE_NUMS)) ||
1398 ((numeric & GTK_CSS_FONT_VARIANT_NUMERIC_PROPORTIONAL_NUMS) &&
1399 (numeric & GTK_CSS_FONT_VARIANT_NUMERIC_TABULAR_NUMS)) ||
1400 ((numeric & GTK_CSS_FONT_VARIANT_NUMERIC_DIAGONAL_FRACTIONS) &&
1401 (numeric & GTK_CSS_FONT_VARIANT_NUMERIC_STACKED_FRACTIONS)))
1402 return FALSE;
1403
1404 return TRUE;
1405}
1406
1407GtkCssValue *
1408_gtk_css_font_variant_numeric_value_new (GtkCssFontVariantNumeric numeric)
1409{
1410 GtkCssValue *value;
1411
1412 if (!numeric_value_is_valid (numeric))
1413 return NULL;
1414
1415 value = _gtk_css_value_new (GtkCssValue, &GTK_CSS_VALUE_FONT_VARIANT_NUMERIC);
1416 value->value = numeric;
1417 value->name = NULL;
1418 value->is_computed = TRUE;
1419
1420 return value;
1421}
1422
1423GtkCssFontVariantNumeric
1424_gtk_css_font_variant_numeric_try_parse_one (GtkCssParser *parser,
1425 GtkCssFontVariantNumeric base)
1426{
1427 guint i;
1428 GtkCssFontVariantNumeric value = 0;
1429
1430 g_return_val_if_fail (parser != NULL, 0);
1431
1432 for (i = 0; i < G_N_ELEMENTS (font_variant_numeric_values); i++)
1433 {
1434 if (gtk_css_parser_try_ident (self: parser, ident: font_variant_numeric_values[i].name))
1435 {
1436 value = font_variant_numeric_values[i].value;
1437 break;
1438 }
1439 }
1440
1441 if (value == 0)
1442 return base; /* not parsing this value */
1443
1444 if ((base | value) == base)
1445 return 0; /* repeated value */
1446
1447 if (!numeric_value_is_valid (numeric: base | value))
1448 return 0; /* bad combination */
1449
1450 return base | value;
1451}
1452
1453GtkCssFontVariantNumeric
1454_gtk_css_font_variant_numeric_value_get (const GtkCssValue *value)
1455{
1456 g_return_val_if_fail (value->class == &GTK_CSS_VALUE_FONT_VARIANT_NUMERIC, GTK_CSS_FONT_VARIANT_NUMERIC_NORMAL);
1457
1458 return value->value;
1459}
1460
1461/* GtkCssFontVariantEastAsian */
1462
1463static FlagsValue font_variant_east_asian_values[] = {
1464 { GTK_CSS_FONT_VARIANT_EAST_ASIAN_NORMAL, "normal" },
1465 { GTK_CSS_FONT_VARIANT_EAST_ASIAN_JIS78, "jis78" },
1466 { GTK_CSS_FONT_VARIANT_EAST_ASIAN_JIS83, "jis83" },
1467 { GTK_CSS_FONT_VARIANT_EAST_ASIAN_JIS90, "jis90" },
1468 { GTK_CSS_FONT_VARIANT_EAST_ASIAN_JIS04, "jis04" },
1469 { GTK_CSS_FONT_VARIANT_EAST_ASIAN_SIMPLIFIED, "simplified" },
1470 { GTK_CSS_FONT_VARIANT_EAST_ASIAN_TRADITIONAL, "traditional" },
1471 { GTK_CSS_FONT_VARIANT_EAST_ASIAN_FULL_WIDTH, "full-width" },
1472 { GTK_CSS_FONT_VARIANT_EAST_ASIAN_PROPORTIONAL, "proportional-width" },
1473 { GTK_CSS_FONT_VARIANT_EAST_ASIAN_RUBY, "ruby" }
1474};
1475
1476static void
1477gtk_css_font_variant_east_asian_value_print (const GtkCssValue *value,
1478 GString *string)
1479{
1480 gtk_css_value_flags_print (values: font_variant_east_asian_values,
1481 G_N_ELEMENTS (font_variant_east_asian_values),
1482 value, string);
1483}
1484
1485static const GtkCssValueClass GTK_CSS_VALUE_FONT_VARIANT_EAST_ASIAN = {
1486 "GtkCssFontVariantEastAsianValue",
1487 gtk_css_value_enum_free,
1488 gtk_css_value_enum_compute,
1489 gtk_css_value_flags_equal,
1490 gtk_css_value_enum_transition,
1491 NULL,
1492 NULL,
1493 gtk_css_font_variant_east_asian_value_print
1494};
1495
1496static gboolean
1497east_asian_value_is_valid (GtkCssFontVariantEastAsian east_asian)
1498{
1499 if ((east_asian & GTK_CSS_FONT_VARIANT_EAST_ASIAN_NORMAL) &&
1500 (east_asian != GTK_CSS_FONT_VARIANT_EAST_ASIAN_NORMAL))
1501 return FALSE;
1502
1503 if (gtk_popcount (east_asian & (GTK_CSS_FONT_VARIANT_EAST_ASIAN_JIS78 |
1504 GTK_CSS_FONT_VARIANT_EAST_ASIAN_JIS83 |
1505 GTK_CSS_FONT_VARIANT_EAST_ASIAN_JIS90 |
1506 GTK_CSS_FONT_VARIANT_EAST_ASIAN_JIS04 |
1507 GTK_CSS_FONT_VARIANT_EAST_ASIAN_SIMPLIFIED |
1508 GTK_CSS_FONT_VARIANT_EAST_ASIAN_TRADITIONAL)) > 1)
1509 return FALSE;
1510
1511 if (gtk_popcount (east_asian & (GTK_CSS_FONT_VARIANT_EAST_ASIAN_FULL_WIDTH |
1512 GTK_CSS_FONT_VARIANT_EAST_ASIAN_PROPORTIONAL)) > 1)
1513 return FALSE;
1514
1515 return TRUE;
1516}
1517
1518GtkCssValue *
1519_gtk_css_font_variant_east_asian_value_new (GtkCssFontVariantEastAsian east_asian)
1520{
1521 GtkCssValue *value;
1522
1523 if (!east_asian_value_is_valid (east_asian))
1524 return NULL;
1525
1526 value = _gtk_css_value_new (GtkCssValue, &GTK_CSS_VALUE_FONT_VARIANT_EAST_ASIAN);
1527 value->value = east_asian;
1528 value->name = NULL;
1529 value->is_computed = TRUE;
1530
1531 return value;
1532}
1533
1534GtkCssFontVariantEastAsian
1535_gtk_css_font_variant_east_asian_try_parse_one (GtkCssParser *parser,
1536 GtkCssFontVariantEastAsian base)
1537{
1538 guint i;
1539 GtkCssFontVariantEastAsian value = 0;
1540
1541 g_return_val_if_fail (parser != NULL, 0);
1542
1543 for (i = 0; i < G_N_ELEMENTS (font_variant_east_asian_values); i++)
1544 {
1545 if (gtk_css_parser_try_ident (self: parser, ident: font_variant_east_asian_values[i].name))
1546 {
1547 value = font_variant_east_asian_values[i].value;
1548 break;
1549 }
1550 }
1551
1552 if (value == 0)
1553 return base; /* not parsing this value */
1554
1555 if ((base | value) == base)
1556 return 0; /* repeated value */
1557
1558 if (!east_asian_value_is_valid (east_asian: base | value))
1559 return 0; /* bad combination */
1560
1561 return base | value;
1562}
1563
1564GtkCssFontVariantEastAsian
1565_gtk_css_font_variant_east_asian_value_get (const GtkCssValue *value)
1566{
1567 g_return_val_if_fail (value->class == &GTK_CSS_VALUE_FONT_VARIANT_EAST_ASIAN, GTK_CSS_FONT_VARIANT_EAST_ASIAN_NORMAL);
1568
1569 return value->value;
1570}
1571
1572/* GtkTextTransform */
1573
1574static const GtkCssValueClass GTK_CSS_VALUE_TEXT_TRANSFORM = {
1575 "GtkCssTextTransformValue",
1576 gtk_css_value_enum_free,
1577 gtk_css_value_enum_compute,
1578 gtk_css_value_enum_equal,
1579 gtk_css_value_enum_transition,
1580 NULL,
1581 NULL,
1582 gtk_css_value_enum_print
1583};
1584
1585static GtkCssValue text_transform_values[] = {
1586 { .class: &GTK_CSS_VALUE_TEXT_TRANSFORM, .ref_count: 1, TRUE, .value: GTK_CSS_TEXT_TRANSFORM_NONE, .name: "none" },
1587 { &GTK_CSS_VALUE_TEXT_TRANSFORM, 1, TRUE, GTK_CSS_TEXT_TRANSFORM_LOWERCASE, "lowercase" },
1588 { &GTK_CSS_VALUE_TEXT_TRANSFORM, 1, TRUE, GTK_CSS_TEXT_TRANSFORM_UPPERCASE, "uppercase" },
1589 { &GTK_CSS_VALUE_TEXT_TRANSFORM, 1, TRUE, GTK_CSS_TEXT_TRANSFORM_CAPITALIZE, "capitalize" },
1590};
1591
1592GtkCssValue *
1593_gtk_css_text_transform_value_new (GtkTextTransform transform)
1594{
1595 g_return_val_if_fail (transform < G_N_ELEMENTS (text_transform_values), NULL);
1596
1597 return _gtk_css_value_ref (value: &text_transform_values[transform]);
1598}
1599
1600GtkCssValue *
1601_gtk_css_text_transform_value_try_parse (GtkCssParser *parser)
1602{
1603 guint i;
1604
1605 g_return_val_if_fail (parser != NULL, NULL);
1606
1607 for (i = 0; i < G_N_ELEMENTS (text_transform_values); i++)
1608 {
1609 if (gtk_css_parser_try_ident (self: parser, ident: text_transform_values[i].name))
1610 return _gtk_css_value_ref (value: &text_transform_values[i]);
1611 }
1612
1613 return NULL;
1614}
1615
1616GtkTextTransform
1617_gtk_css_text_transform_value_get (const GtkCssValue *value)
1618{
1619 g_return_val_if_fail (value->class == &GTK_CSS_VALUE_TEXT_TRANSFORM, GTK_CSS_TEXT_TRANSFORM_NONE);
1620
1621 return value->value;
1622}
1623

source code of gtk/gtk/gtkcssenumvalue.c