]> Pileus Git - ~andy/gtk/blob - gtk/gtkcssenumvalue.c
css: Add more features to font-size code
[~andy/gtk] / gtk / gtkcssenumvalue.c
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 "gtkcsscomputedvaluesprivate.h"
23 #include "gtkcssnumbervalueprivate.h"
24 #include "gtkstyleproviderprivate.h"
25
26 /* repeated API */
27
28 struct _GtkCssValue {
29   GTK_CSS_VALUE_BASE
30   int value;
31   const char *name;
32 };
33
34 static void
35 gtk_css_value_enum_free (GtkCssValue *value)
36 {
37   g_slice_free (GtkCssValue, value);
38 }
39
40 static GtkCssValue *
41 gtk_css_value_enum_compute (GtkCssValue             *value,
42                             guint                    property_id,
43                             GtkStyleProviderPrivate *provider,
44                             GtkCssComputedValues    *values,
45                             GtkCssComputedValues    *parent_values,
46                             GtkCssDependencies      *dependencies)
47 {
48   return _gtk_css_value_ref (value);
49 }
50
51 static gboolean
52 gtk_css_value_enum_equal (const GtkCssValue *enum1,
53                           const GtkCssValue *enum2)
54 {
55   return enum1 == enum2;
56 }
57
58 static GtkCssValue *
59 gtk_css_value_enum_transition (GtkCssValue *start,
60                                GtkCssValue *end,
61                                guint        property_id,
62                                double       progress)
63 {
64   return NULL;
65 }
66
67 static void
68 gtk_css_value_enum_print (const GtkCssValue *value,
69                           GString           *string)
70 {
71   g_string_append (string, value->name);
72 }
73
74 /* GtkBorderStyle */
75
76 static const GtkCssValueClass GTK_CSS_VALUE_BORDER_STYLE = {
77   gtk_css_value_enum_free,
78   gtk_css_value_enum_compute,
79   gtk_css_value_enum_equal,
80   gtk_css_value_enum_transition,
81   gtk_css_value_enum_print
82 };
83
84 static GtkCssValue border_style_values[] = {
85   { &GTK_CSS_VALUE_BORDER_STYLE, 1, GTK_BORDER_STYLE_NONE, "none" },
86   { &GTK_CSS_VALUE_BORDER_STYLE, 1, GTK_BORDER_STYLE_SOLID, "solid" },
87   { &GTK_CSS_VALUE_BORDER_STYLE, 1, GTK_BORDER_STYLE_INSET, "inset" },
88   { &GTK_CSS_VALUE_BORDER_STYLE, 1, GTK_BORDER_STYLE_OUTSET, "outset" },
89   { &GTK_CSS_VALUE_BORDER_STYLE, 1, GTK_BORDER_STYLE_HIDDEN, "hidden" },
90   { &GTK_CSS_VALUE_BORDER_STYLE, 1, GTK_BORDER_STYLE_DOTTED, "dotted" },
91   { &GTK_CSS_VALUE_BORDER_STYLE, 1, GTK_BORDER_STYLE_DASHED, "dashed" },
92   { &GTK_CSS_VALUE_BORDER_STYLE, 1, GTK_BORDER_STYLE_DOUBLE, "double" },
93   { &GTK_CSS_VALUE_BORDER_STYLE, 1, GTK_BORDER_STYLE_GROOVE, "groove" },
94   { &GTK_CSS_VALUE_BORDER_STYLE, 1, GTK_BORDER_STYLE_RIDGE, "ridge" }
95 };
96
97 GtkCssValue *
98 _gtk_css_border_style_value_new (GtkBorderStyle border_style)
99 {
100   g_return_val_if_fail (border_style < G_N_ELEMENTS (border_style_values), NULL);
101
102   return _gtk_css_value_ref (&border_style_values[border_style]);
103 }
104
105 GtkCssValue *
106 _gtk_css_border_style_value_try_parse (GtkCssParser *parser)
107 {
108   guint i;
109
110   g_return_val_if_fail (parser != NULL, NULL);
111
112   for (i = 0; i < G_N_ELEMENTS (border_style_values); i++)
113     {
114       if (_gtk_css_parser_try (parser, border_style_values[i].name, TRUE))
115         return _gtk_css_value_ref (&border_style_values[i]);
116     }
117
118   return NULL;
119 }
120
121 GtkBorderStyle
122 _gtk_css_border_style_value_get (const GtkCssValue *value)
123 {
124   g_return_val_if_fail (value->class == &GTK_CSS_VALUE_BORDER_STYLE, GTK_BORDER_STYLE_NONE);
125
126   return value->value;
127 }
128
129 /* GtkCssFontSize */
130
131 /* XXX: Kinda bad to have that machinery here, nobody expects vital font
132  * size code to appear in gtkcssvalueenum.c.
133  */
134 #define DEFAULT_FONT_SIZE 10
135
136 static double
137 get_default_font_size (GtkStyleProviderPrivate *provider)
138 {
139   GtkSettings *settings;
140   PangoFontDescription *description;
141   char *font_name;
142   double font_size;
143
144   settings = _gtk_style_provider_private_get_settings (provider);
145   if (settings == NULL)
146     return DEFAULT_FONT_SIZE;
147   
148   g_object_get (settings, "gtk-font-name", &font_name, NULL);
149   description = pango_font_description_from_string (font_name);
150   g_free (font_name);
151   if (description == NULL)
152     return DEFAULT_FONT_SIZE;
153
154   if (pango_font_description_get_set_fields (description) & PANGO_FONT_MASK_SIZE)
155     font_size = (double) pango_font_description_get_size (description) / PANGO_SCALE;
156   else
157     font_size = DEFAULT_FONT_SIZE;
158
159   pango_font_description_free (description);
160   return font_size;
161 }
162
163 static GtkCssValue *
164 gtk_css_value_font_size_compute (GtkCssValue             *value,
165                                  guint                    property_id,
166                                  GtkStyleProviderPrivate *provider,
167                                  GtkCssComputedValues    *values,
168                                  GtkCssComputedValues    *parent_values,
169                                  GtkCssDependencies      *dependencies)
170 {
171   double font_size;
172
173   switch (value->value)
174     {
175     case GTK_CSS_FONT_SIZE_XX_SMALL:
176       font_size = get_default_font_size (provider) * 3. / 5;
177       break;
178     case GTK_CSS_FONT_SIZE_X_SMALL:
179       font_size = get_default_font_size (provider) * 3. / 4;
180       break;
181     case GTK_CSS_FONT_SIZE_SMALL:
182       font_size = get_default_font_size (provider) * 8. / 9;
183       break;
184     default:
185       g_assert_not_reached ();
186       /* fall thru */
187     case GTK_CSS_FONT_SIZE_MEDIUM:
188       font_size = get_default_font_size (provider);
189       break;
190     case GTK_CSS_FONT_SIZE_LARGE:
191       font_size = get_default_font_size (provider) * 6. / 5;
192       break;
193     case GTK_CSS_FONT_SIZE_X_LARGE:
194       font_size = get_default_font_size (provider) * 3. / 2;
195       break;
196     case GTK_CSS_FONT_SIZE_XX_LARGE:
197       font_size = get_default_font_size (provider) * 2;
198       break;
199     case GTK_CSS_FONT_SIZE_SMALLER:
200       if (parent_values)
201         font_size = _gtk_css_number_value_get (_gtk_css_computed_values_get_value (parent_values, GTK_CSS_PROPERTY_FONT_SIZE), 100);
202       else
203         font_size = get_default_font_size (provider);
204       /* XXX: This is what WebKit does... */
205       font_size *= 1.2;
206       break;
207     case GTK_CSS_FONT_SIZE_LARGER:
208       if (parent_values)
209         font_size = _gtk_css_number_value_get (_gtk_css_computed_values_get_value (parent_values, GTK_CSS_PROPERTY_FONT_SIZE), 100);
210       else
211         font_size = get_default_font_size (provider);
212       /* XXX: This is what WebKit does... */
213       font_size /= 1.2;
214       break;
215   }
216
217   return _gtk_css_number_value_new (font_size, GTK_CSS_PX);
218 }
219
220 static const GtkCssValueClass GTK_CSS_VALUE_FONT_SIZE = {
221   gtk_css_value_enum_free,
222   gtk_css_value_font_size_compute,
223   gtk_css_value_enum_equal,
224   gtk_css_value_enum_transition,
225   gtk_css_value_enum_print
226 };
227
228 static GtkCssValue font_size_values[] = {
229   { &GTK_CSS_VALUE_FONT_SIZE, 1, GTK_CSS_FONT_SIZE_XX_SMALL, "xx-small" },
230   { &GTK_CSS_VALUE_FONT_SIZE, 1, GTK_CSS_FONT_SIZE_X_SMALL, "x-small" },
231   { &GTK_CSS_VALUE_FONT_SIZE, 1, GTK_CSS_FONT_SIZE_SMALL, "small" },
232   { &GTK_CSS_VALUE_FONT_SIZE, 1, GTK_CSS_FONT_SIZE_MEDIUM, "medium" },
233   { &GTK_CSS_VALUE_FONT_SIZE, 1, GTK_CSS_FONT_SIZE_LARGE, "large" },
234   { &GTK_CSS_VALUE_FONT_SIZE, 1, GTK_CSS_FONT_SIZE_X_LARGE, "x-large" },
235   { &GTK_CSS_VALUE_FONT_SIZE, 1, GTK_CSS_FONT_SIZE_XX_LARGE, "xx-large" },
236   { &GTK_CSS_VALUE_FONT_SIZE, 1, GTK_CSS_FONT_SIZE_SMALLER, "smaller" },
237   { &GTK_CSS_VALUE_FONT_SIZE, 1, GTK_CSS_FONT_SIZE_LARGER, "larger" },
238 };
239
240 GtkCssValue *
241 _gtk_css_font_size_value_new (GtkCssFontSize font_size)
242 {
243   g_return_val_if_fail (font_size < G_N_ELEMENTS (font_size_values), NULL);
244
245   return _gtk_css_value_ref (&font_size_values[font_size]);
246 }
247
248 GtkCssValue *
249 _gtk_css_font_size_value_try_parse (GtkCssParser *parser)
250 {
251   guint i;
252
253   g_return_val_if_fail (parser != NULL, NULL);
254
255   for (i = 0; i < G_N_ELEMENTS (font_size_values); i++)
256     {
257       if (_gtk_css_parser_try (parser, font_size_values[i].name, TRUE))
258         return _gtk_css_value_ref (&font_size_values[i]);
259     }
260
261   return NULL;
262 }
263
264 GtkCssFontSize
265 _gtk_css_font_size_value_get (const GtkCssValue *value)
266 {
267   g_return_val_if_fail (value->class == &GTK_CSS_VALUE_FONT_SIZE, GTK_CSS_FONT_SIZE_MEDIUM);
268
269   return value->value;
270 }
271
272 /* PangoStyle */
273
274 static const GtkCssValueClass GTK_CSS_VALUE_FONT_STYLE = {
275   gtk_css_value_enum_free,
276   gtk_css_value_enum_compute,
277   gtk_css_value_enum_equal,
278   gtk_css_value_enum_transition,
279   gtk_css_value_enum_print
280 };
281
282 static GtkCssValue font_style_values[] = {
283   { &GTK_CSS_VALUE_FONT_STYLE, 1, PANGO_STYLE_NORMAL, "normal" },
284   { &GTK_CSS_VALUE_FONT_STYLE, 1, PANGO_STYLE_OBLIQUE, "oblique" },
285   { &GTK_CSS_VALUE_FONT_STYLE, 1, PANGO_STYLE_ITALIC, "italic" }
286 };
287
288 GtkCssValue *
289 _gtk_css_font_style_value_new (PangoStyle font_style)
290 {
291   g_return_val_if_fail (font_style < G_N_ELEMENTS (font_style_values), NULL);
292
293   return _gtk_css_value_ref (&font_style_values[font_style]);
294 }
295
296 GtkCssValue *
297 _gtk_css_font_style_value_try_parse (GtkCssParser *parser)
298 {
299   guint i;
300
301   g_return_val_if_fail (parser != NULL, NULL);
302
303   for (i = 0; i < G_N_ELEMENTS (font_style_values); i++)
304     {
305       if (_gtk_css_parser_try (parser, font_style_values[i].name, TRUE))
306         return _gtk_css_value_ref (&font_style_values[i]);
307     }
308
309   return NULL;
310 }
311
312 PangoStyle
313 _gtk_css_font_style_value_get (const GtkCssValue *value)
314 {
315   g_return_val_if_fail (value->class == &GTK_CSS_VALUE_FONT_STYLE, PANGO_STYLE_NORMAL);
316
317   return value->value;
318 }
319
320 /* PangoVariant */
321
322 static const GtkCssValueClass GTK_CSS_VALUE_FONT_VARIANT = {
323   gtk_css_value_enum_free,
324   gtk_css_value_enum_compute,
325   gtk_css_value_enum_equal,
326   gtk_css_value_enum_transition,
327   gtk_css_value_enum_print
328 };
329
330 static GtkCssValue font_variant_values[] = {
331   { &GTK_CSS_VALUE_FONT_VARIANT, 1, PANGO_VARIANT_NORMAL, "normal" },
332   { &GTK_CSS_VALUE_FONT_VARIANT, 1, PANGO_VARIANT_SMALL_CAPS, "small-caps" }
333 };
334
335 GtkCssValue *
336 _gtk_css_font_variant_value_new (PangoVariant font_variant)
337 {
338   g_return_val_if_fail (font_variant < G_N_ELEMENTS (font_variant_values), NULL);
339
340   return _gtk_css_value_ref (&font_variant_values[font_variant]);
341 }
342
343 GtkCssValue *
344 _gtk_css_font_variant_value_try_parse (GtkCssParser *parser)
345 {
346   guint i;
347
348   g_return_val_if_fail (parser != NULL, NULL);
349
350   for (i = 0; i < G_N_ELEMENTS (font_variant_values); i++)
351     {
352       if (_gtk_css_parser_try (parser, font_variant_values[i].name, TRUE))
353         return _gtk_css_value_ref (&font_variant_values[i]);
354     }
355
356   return NULL;
357 }
358
359 PangoVariant
360 _gtk_css_font_variant_value_get (const GtkCssValue *value)
361 {
362   g_return_val_if_fail (value->class == &GTK_CSS_VALUE_FONT_VARIANT, PANGO_VARIANT_NORMAL);
363
364   return value->value;
365 }
366
367 /* PangoWeight */
368
369 static const GtkCssValueClass GTK_CSS_VALUE_FONT_WEIGHT = {
370   gtk_css_value_enum_free,
371   gtk_css_value_enum_compute,
372   gtk_css_value_enum_equal,
373   gtk_css_value_enum_transition,
374   gtk_css_value_enum_print
375 };
376
377 static GtkCssValue font_weight_values[] = {
378   { &GTK_CSS_VALUE_FONT_WEIGHT, 1, PANGO_WEIGHT_THIN, "100" },
379   { &GTK_CSS_VALUE_FONT_WEIGHT, 1, PANGO_WEIGHT_ULTRALIGHT, "200" },
380   { &GTK_CSS_VALUE_FONT_WEIGHT, 1, PANGO_WEIGHT_LIGHT, "300" },
381   { &GTK_CSS_VALUE_FONT_WEIGHT, 1, PANGO_WEIGHT_NORMAL, "normal" },
382   { &GTK_CSS_VALUE_FONT_WEIGHT, 1, PANGO_WEIGHT_MEDIUM, "500" },
383   { &GTK_CSS_VALUE_FONT_WEIGHT, 1, PANGO_WEIGHT_SEMIBOLD, "600" },
384   { &GTK_CSS_VALUE_FONT_WEIGHT, 1, PANGO_WEIGHT_BOLD, "bold" },
385   { &GTK_CSS_VALUE_FONT_WEIGHT, 1, PANGO_WEIGHT_ULTRABOLD, "800" },
386   { &GTK_CSS_VALUE_FONT_WEIGHT, 1, PANGO_WEIGHT_HEAVY, "900" }
387 };
388
389 GtkCssValue *
390 _gtk_css_font_weight_value_new (PangoWeight font_weight)
391 {
392   guint i;
393   gint w;
394
395   w = ((font_weight + 50) / 100) * 100;
396
397   for (i = 0; i < G_N_ELEMENTS (font_weight_values); i++)
398     {
399       if (font_weight_values[i].value == w)
400         return _gtk_css_value_ref (&font_weight_values[i]);
401     }
402
403   g_return_val_if_reached (NULL);
404 }
405
406 GtkCssValue *
407 _gtk_css_font_weight_value_try_parse (GtkCssParser *parser)
408 {
409   guint i;
410
411   g_return_val_if_fail (parser != NULL, NULL);
412
413   for (i = 0; i < G_N_ELEMENTS (font_weight_values); i++)
414     {
415       if (_gtk_css_parser_try (parser, font_weight_values[i].name, TRUE))
416         return _gtk_css_value_ref (&font_weight_values[i]);
417     }
418   /* special cases go here */
419   if (_gtk_css_parser_try (parser, "400", TRUE))
420     return _gtk_css_value_ref (&font_weight_values[3]);
421   if (_gtk_css_parser_try (parser, "700", TRUE))
422     return _gtk_css_value_ref (&font_weight_values[6]);
423
424   return NULL;
425 }
426
427 PangoWeight
428 _gtk_css_font_weight_value_get (const GtkCssValue *value)
429 {
430   g_return_val_if_fail (value->class == &GTK_CSS_VALUE_FONT_WEIGHT, PANGO_WEIGHT_NORMAL);
431
432   return value->value;
433 }
434
435 /* GtkCssArea */
436
437 static const GtkCssValueClass GTK_CSS_VALUE_AREA = {
438   gtk_css_value_enum_free,
439   gtk_css_value_enum_compute,
440   gtk_css_value_enum_equal,
441   gtk_css_value_enum_transition,
442   gtk_css_value_enum_print
443 };
444
445 static GtkCssValue area_values[] = {
446   { &GTK_CSS_VALUE_AREA, 1, GTK_CSS_AREA_BORDER_BOX, "border-box" },
447   { &GTK_CSS_VALUE_AREA, 1, GTK_CSS_AREA_PADDING_BOX, "padding-box" },
448   { &GTK_CSS_VALUE_AREA, 1, GTK_CSS_AREA_CONTENT_BOX, "content-box" }
449 };
450
451 GtkCssValue *
452 _gtk_css_area_value_new (GtkCssArea area)
453 {
454   guint i;
455
456   for (i = 0; i < G_N_ELEMENTS (area_values); i++)
457     {
458       if (area_values[i].value == area)
459         return _gtk_css_value_ref (&area_values[i]);
460     }
461
462   g_return_val_if_reached (NULL);
463 }
464
465 GtkCssValue *
466 _gtk_css_area_value_try_parse (GtkCssParser *parser)
467 {
468   guint i;
469
470   g_return_val_if_fail (parser != NULL, NULL);
471
472   for (i = 0; i < G_N_ELEMENTS (area_values); i++)
473     {
474       if (_gtk_css_parser_try (parser, area_values[i].name, TRUE))
475         return _gtk_css_value_ref (&area_values[i]);
476     }
477
478   return NULL;
479 }
480
481 GtkCssArea
482 _gtk_css_area_value_get (const GtkCssValue *value)
483 {
484   g_return_val_if_fail (value->class == &GTK_CSS_VALUE_AREA, GTK_CSS_AREA_BORDER_BOX);
485
486   return value->value;
487 }
488
489 /* GtkCssDirection */
490
491 static const GtkCssValueClass GTK_CSS_VALUE_DIRECTION = {
492   gtk_css_value_enum_free,
493   gtk_css_value_enum_compute,
494   gtk_css_value_enum_equal,
495   gtk_css_value_enum_transition,
496   gtk_css_value_enum_print
497 };
498
499 static GtkCssValue direction_values[] = {
500   { &GTK_CSS_VALUE_DIRECTION, 1, GTK_CSS_DIRECTION_NORMAL, "normal" },
501   { &GTK_CSS_VALUE_DIRECTION, 1, GTK_CSS_DIRECTION_REVERSE, "reverse" },
502   { &GTK_CSS_VALUE_DIRECTION, 1, GTK_CSS_DIRECTION_ALTERNATE, "alternate" },
503   { &GTK_CSS_VALUE_DIRECTION, 1, GTK_CSS_DIRECTION_ALTERNATE_REVERSE, "alternate-reverse" }
504 };
505
506 GtkCssValue *
507 _gtk_css_direction_value_new (GtkCssDirection direction)
508 {
509   guint i;
510
511   for (i = 0; i < G_N_ELEMENTS (direction_values); i++)
512     {
513       if (direction_values[i].value == direction)
514         return _gtk_css_value_ref (&direction_values[i]);
515     }
516
517   g_return_val_if_reached (NULL);
518 }
519
520 GtkCssValue *
521 _gtk_css_direction_value_try_parse (GtkCssParser *parser)
522 {
523   guint i;
524
525   g_return_val_if_fail (parser != NULL, NULL);
526
527   for (i = 0; i < G_N_ELEMENTS (direction_values); i++)
528     {
529       if (_gtk_css_parser_try (parser, direction_values[i].name, TRUE))
530         return _gtk_css_value_ref (&direction_values[i]);
531     }
532
533   return NULL;
534 }
535
536 GtkCssDirection
537 _gtk_css_direction_value_get (const GtkCssValue *value)
538 {
539   g_return_val_if_fail (value->class == &GTK_CSS_VALUE_DIRECTION, GTK_CSS_DIRECTION_NORMAL);
540
541   return value->value;
542 }
543
544 /* GtkCssPlayState */
545
546 static const GtkCssValueClass GTK_CSS_VALUE_PLAY_STATE = {
547   gtk_css_value_enum_free,
548   gtk_css_value_enum_compute,
549   gtk_css_value_enum_equal,
550   gtk_css_value_enum_transition,
551   gtk_css_value_enum_print
552 };
553
554 static GtkCssValue play_state_values[] = {
555   { &GTK_CSS_VALUE_PLAY_STATE, 1, GTK_CSS_PLAY_STATE_RUNNING, "running" },
556   { &GTK_CSS_VALUE_PLAY_STATE, 1, GTK_CSS_PLAY_STATE_PAUSED, "paused" }
557 };
558
559 GtkCssValue *
560 _gtk_css_play_state_value_new (GtkCssPlayState play_state)
561 {
562   guint i;
563
564   for (i = 0; i < G_N_ELEMENTS (play_state_values); i++)
565     {
566       if (play_state_values[i].value == play_state)
567         return _gtk_css_value_ref (&play_state_values[i]);
568     }
569
570   g_return_val_if_reached (NULL);
571 }
572
573 GtkCssValue *
574 _gtk_css_play_state_value_try_parse (GtkCssParser *parser)
575 {
576   guint i;
577
578   g_return_val_if_fail (parser != NULL, NULL);
579
580   for (i = 0; i < G_N_ELEMENTS (play_state_values); i++)
581     {
582       if (_gtk_css_parser_try (parser, play_state_values[i].name, TRUE))
583         return _gtk_css_value_ref (&play_state_values[i]);
584     }
585
586   return NULL;
587 }
588
589 GtkCssPlayState
590 _gtk_css_play_state_value_get (const GtkCssValue *value)
591 {
592   g_return_val_if_fail (value->class == &GTK_CSS_VALUE_PLAY_STATE, GTK_CSS_PLAY_STATE_RUNNING);
593
594   return value->value;
595 }
596
597 /* GtkCssFillMode */
598
599 static const GtkCssValueClass GTK_CSS_VALUE_FILL_MODE = {
600   gtk_css_value_enum_free,
601   gtk_css_value_enum_compute,
602   gtk_css_value_enum_equal,
603   gtk_css_value_enum_transition,
604   gtk_css_value_enum_print
605 };
606
607 static GtkCssValue fill_mode_values[] = {
608   { &GTK_CSS_VALUE_FILL_MODE, 1, GTK_CSS_FILL_NONE, "none" },
609   { &GTK_CSS_VALUE_FILL_MODE, 1, GTK_CSS_FILL_FORWARDS, "forwards" },
610   { &GTK_CSS_VALUE_FILL_MODE, 1, GTK_CSS_FILL_BACKWARDS, "backwards" },
611   { &GTK_CSS_VALUE_FILL_MODE, 1, GTK_CSS_FILL_BOTH, "both" }
612 };
613
614 GtkCssValue *
615 _gtk_css_fill_mode_value_new (GtkCssFillMode fill_mode)
616 {
617   guint i;
618
619   for (i = 0; i < G_N_ELEMENTS (fill_mode_values); i++)
620     {
621       if (fill_mode_values[i].value == fill_mode)
622         return _gtk_css_value_ref (&fill_mode_values[i]);
623     }
624
625   g_return_val_if_reached (NULL);
626 }
627
628 GtkCssValue *
629 _gtk_css_fill_mode_value_try_parse (GtkCssParser *parser)
630 {
631   guint i;
632
633   g_return_val_if_fail (parser != NULL, NULL);
634
635   for (i = 0; i < G_N_ELEMENTS (fill_mode_values); i++)
636     {
637       if (_gtk_css_parser_try (parser, fill_mode_values[i].name, TRUE))
638         return _gtk_css_value_ref (&fill_mode_values[i]);
639     }
640
641   return NULL;
642 }
643
644 GtkCssFillMode
645 _gtk_css_fill_mode_value_get (const GtkCssValue *value)
646 {
647   g_return_val_if_fail (value->class == &GTK_CSS_VALUE_FILL_MODE, GTK_CSS_FILL_NONE);
648
649   return value->value;
650 }
651