]> Pileus Git - ~andy/gtk/blob - gtk/gtkcssstylepropertyimpl.c
cssstyleproperty: Make query func a vfunc
[~andy/gtk] / gtk / gtkcssstylepropertyimpl.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2010 Carlos Garnacho <carlosg@gnome.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include "config.h"
19
20 #include "gtkstylepropertyprivate.h"
21
22 #include <gobject/gvaluecollector.h>
23 #include <gdk-pixbuf/gdk-pixbuf.h>
24 #include <cairo-gobject.h>
25 #include <math.h>
26
27 #include "gtkcssparserprivate.h"
28 #include "gtkcssstylefuncsprivate.h"
29 #include "gtkcssstylepropertyprivate.h"
30 #include "gtkcsstypesprivate.h"
31 #include "gtkintl.h"
32 #include "gtkprivatetypebuiltins.h"
33 #include "gtkstylepropertiesprivate.h"
34
35 /* this is in case round() is not provided by the compiler, 
36  * such as in the case of C89 compilers, like MSVC
37  */
38 #include "fallback-c89.c"
39
40 /* the actual parsers we have */
41 #include "gtkanimationdescription.h"
42 #include "gtkbindings.h"
43 #include "gtkcssimagegradientprivate.h"
44 #include "gtkcssimageprivate.h"
45 #include "gtkcssimageprivate.h"
46 #include "gtkgradient.h"
47 #include "gtkshadowprivate.h"
48 #include "gtksymboliccolorprivate.h"
49 #include "gtkthemingengine.h"
50 #include "gtktypebuiltins.h"
51 #include "gtkwin32themeprivate.h"
52
53 /*** REGISTRATION ***/
54
55 static void
56 gtk_css_style_property_register (const char *                   name,
57                                  GType                          value_type,
58                                  GtkStylePropertyFlags          flags,
59                                  GtkCssStylePropertyParseFunc   parse_value,
60                                  GtkCssStylePropertyPrintFunc   print_value,
61                                  GtkCssStylePropertyComputeFunc compute_value,
62                                  GtkCssStylePropertyQueryFunc   query_value,
63                                  GtkCssStylePropertyEqualFunc   equal_func,
64                                  GtkCssValue *                  initial_value)
65 {
66   GtkCssStyleProperty *node;
67
68   g_assert (initial_value != NULL);
69   g_assert (parse_value != NULL);
70   g_assert (value_type == G_TYPE_NONE || query_value != NULL);
71
72   node = g_object_new (GTK_TYPE_CSS_STYLE_PROPERTY,
73                        "value-type", value_type,
74                        "inherit", (flags & GTK_STYLE_PROPERTY_INHERIT) ? TRUE : FALSE,
75                        "initial-value", initial_value,
76                        "name", name,
77                        NULL);
78   
79   node->parse_value = parse_value;
80   if (print_value)
81     node->print_value = print_value;
82   if (compute_value)
83     node->compute_value = compute_value;
84   node->query_value = query_value;
85   if (equal_func)
86     node->equal_func = equal_func;
87
88   _gtk_css_value_unref (initial_value);
89 }
90
91 /*** HELPERS ***/
92
93 static void
94 string_append_string (GString    *str,
95                       const char *string)
96 {
97   gsize len;
98
99   g_string_append_c (str, '"');
100
101   do {
102     len = strcspn (string, "\"\n\r\f");
103     g_string_append (str, string);
104     string += len;
105     switch (*string)
106       {
107       case '\0':
108         break;
109       case '\n':
110         g_string_append (str, "\\A ");
111         break;
112       case '\r':
113         g_string_append (str, "\\D ");
114         break;
115       case '\f':
116         g_string_append (str, "\\C ");
117         break;
118       case '\"':
119         g_string_append (str, "\\\"");
120         break;
121       default:
122         g_assert_not_reached ();
123         break;
124       }
125   } while (*string);
126
127   g_string_append_c (str, '"');
128 }
129
130 /*** IMPLEMENTATIONS ***/
131
132 static void
133 query_simple (GtkCssStyleProperty *property,
134               const GtkCssValue   *css_value,
135               GValue              *value)
136 {
137   _gtk_css_value_init_gvalue (css_value, value);
138 }
139
140 static void
141 query_length_as_int (GtkCssStyleProperty *property,
142                      const GtkCssValue   *css_value,
143                      GValue              *value)
144 {
145   g_value_init (value, G_TYPE_INT);
146   g_value_set_int (value, round (_gtk_css_number_get (_gtk_css_value_get_number (css_value), 100)));
147 }
148
149 static GtkCssValue *
150 color_parse (GtkCssStyleProperty *property,
151              GtkCssParser        *parser,
152              GFile               *base)
153 {
154   GtkSymbolicColor *symbolic;
155
156   if (_gtk_css_parser_try (parser, "currentcolor", TRUE))
157     {
158       symbolic = gtk_symbolic_color_ref (_gtk_symbolic_color_get_current_color ());
159     }
160   else
161     {
162       symbolic = _gtk_css_parser_read_symbolic_color (parser);
163       if (symbolic == NULL)
164         return NULL;
165     }
166
167   return _gtk_css_value_new_take_symbolic_color (symbolic);
168 }
169
170 static GtkCssValue *
171 color_compute (GtkCssStyleProperty    *property,
172                GtkStyleContext        *context,
173                GtkCssValue            *specified)
174 {
175   GtkSymbolicColor *symbolic = _gtk_css_value_get_symbolic_color (specified);
176   GtkCssValue *resolved;
177
178   if (symbolic == _gtk_symbolic_color_get_current_color ())
179     {
180       /* The computed value of the ‘currentColor’ keyword is the computed
181        * value of the ‘color’ property. If the ‘currentColor’ keyword is
182        * set on the ‘color’ property itself, it is treated as ‘color: inherit’. 
183        */
184       if (g_str_equal (_gtk_style_property_get_name (GTK_STYLE_PROPERTY (property)), "color"))
185         {
186           GtkStyleContext *parent = gtk_style_context_get_parent (context);
187
188           if (parent)
189             return _gtk_css_value_ref (_gtk_style_context_peek_property (parent, "color"));
190           else
191             return _gtk_css_style_compute_value (context,
192                                                  GDK_TYPE_RGBA,
193                                                  _gtk_css_style_property_get_initial_value (property));
194         }
195       else
196         {
197           return _gtk_css_value_ref (_gtk_style_context_peek_property (context, "color"));
198         }
199     }
200   else if ((resolved = _gtk_style_context_resolve_color_value (context,
201                                                                symbolic)) != NULL)
202     {
203       return resolved;
204     }
205   else
206     {
207       return color_compute (property,
208                             context,
209                             _gtk_css_style_property_get_initial_value (property));
210     }
211 }
212
213 static GtkCssValue *
214 font_family_parse (GtkCssStyleProperty *property,
215                    GtkCssParser        *parser,
216                    GFile               *base)
217 {
218   GPtrArray *names;
219   char *name;
220
221   /* We don't special case generic families. Pango should do
222    * that for us */
223
224   names = g_ptr_array_new ();
225
226   do {
227     name = _gtk_css_parser_try_ident (parser, TRUE);
228     if (name)
229       {
230         GString *string = g_string_new (name);
231         g_free (name);
232         while ((name = _gtk_css_parser_try_ident (parser, TRUE)))
233           {
234             g_string_append_c (string, ' ');
235             g_string_append (string, name);
236             g_free (name);
237           }
238         name = g_string_free (string, FALSE);
239       }
240     else 
241       {
242         name = _gtk_css_parser_read_string (parser);
243         if (name == NULL)
244           {
245             g_ptr_array_free (names, TRUE);
246             return FALSE;
247           }
248       }
249
250     g_ptr_array_add (names, name);
251   } while (_gtk_css_parser_try (parser, ",", TRUE));
252
253   /* NULL-terminate array */
254   g_ptr_array_add (names, NULL);
255   return _gtk_css_value_new_take_strv ((char **) g_ptr_array_free (names, FALSE));
256 }
257
258 static void
259 font_family_value_print (GtkCssStyleProperty *property,
260                          const GtkCssValue   *value,
261                          GString             *string)
262 {
263   const char **names = _gtk_css_value_get_strv (value);
264
265   if (names == NULL || *names == NULL)
266     {
267       g_string_append (string, "none");
268       return;
269     }
270
271   string_append_string (string, *names);
272   names++;
273   while (*names)
274     {
275       g_string_append (string, ", ");
276       string_append_string (string, *names);
277       names++;
278     }
279 }
280
281 static GtkCssValue *
282 parse_pango_style (GtkCssStyleProperty *property,
283                    GtkCssParser        *parser,
284                    GFile               *base)
285 {
286   int value;
287
288   if (!_gtk_css_parser_try_enum (parser, PANGO_TYPE_STYLE, &value))
289     {
290       _gtk_css_parser_error (parser, "unknown value for property");
291       return NULL;
292     }
293
294   return _gtk_css_value_new_from_enum (PANGO_TYPE_STYLE, value);
295 }
296
297 static GtkCssValue *
298 parse_pango_weight (GtkCssStyleProperty *property,
299                     GtkCssParser        *parser,
300                     GFile               *base)
301 {
302   int value;
303
304   if (!_gtk_css_parser_try_enum (parser, PANGO_TYPE_WEIGHT, &value))
305     {
306       _gtk_css_parser_error (parser, "unknown value for property");
307       return NULL;
308     }
309
310   return _gtk_css_value_new_from_enum (PANGO_TYPE_WEIGHT, value);
311 }
312
313 static GtkCssValue *
314 parse_pango_variant (GtkCssStyleProperty *property,
315                      GtkCssParser        *parser,
316                      GFile               *base)
317 {
318   int value;
319
320   if (!_gtk_css_parser_try_enum (parser, PANGO_TYPE_VARIANT, &value))
321     {
322       _gtk_css_parser_error (parser, "unknown value for property");
323       return NULL;
324     }
325
326   return _gtk_css_value_new_from_enum (PANGO_TYPE_VARIANT, value);
327 }
328
329 static GtkCssValue *
330 parse_border_style (GtkCssStyleProperty *property,
331                     GtkCssParser        *parser,
332                     GFile               *base)
333 {
334   int value;
335
336   if (!_gtk_css_parser_try_enum (parser, GTK_TYPE_BORDER_STYLE, &value))
337     {
338       _gtk_css_parser_error (parser, "unknown value for property");
339       return NULL;
340     }
341
342   return _gtk_css_value_new_from_enum (GTK_TYPE_BORDER_STYLE, value);
343 }
344
345 static GtkCssValue *
346 parse_css_area (GtkCssStyleProperty *property,
347                 GtkCssParser        *parser,
348                 GFile               *base)
349 {
350   int value;
351
352   if (!_gtk_css_parser_try_enum (parser, GTK_TYPE_CSS_AREA, &value))
353     {
354       _gtk_css_parser_error (parser, "unknown value for property");
355       return NULL;
356     }
357
358   return _gtk_css_value_new_from_enum (GTK_TYPE_CSS_AREA, value);
359 }
360
361 static GtkCssValue *
362 bindings_value_parse (GtkCssStyleProperty *property,
363                       GtkCssParser        *parser,
364                       GFile               *base)
365 {
366   GPtrArray *array;
367   GtkBindingSet *binding_set;
368   char *name;
369
370   array = g_ptr_array_new ();
371
372   do {
373       name = _gtk_css_parser_try_ident (parser, TRUE);
374       if (name == NULL)
375         {
376           _gtk_css_parser_error (parser, "Not a valid binding name");
377           g_ptr_array_free (array, TRUE);
378           return FALSE;
379         }
380
381       binding_set = gtk_binding_set_find (name);
382
383       if (!binding_set)
384         {
385           _gtk_css_parser_error (parser, "No binding set named '%s'", name);
386           g_free (name);
387           continue;
388         }
389
390       g_ptr_array_add (array, binding_set);
391       g_free (name);
392     }
393   while (_gtk_css_parser_try (parser, ",", TRUE));
394
395   return _gtk_css_value_new_take_binding_sets (array);
396 }
397
398 static void
399 bindings_value_print (GtkCssStyleProperty *property,
400                       const GtkCssValue   *value,
401                       GString             *string)
402 {
403   GPtrArray *array;
404   guint i;
405
406   array = _gtk_css_value_get_boxed (value);
407
408   for (i = 0; i < array->len; i++)
409     {
410       GtkBindingSet *binding_set = g_ptr_array_index (array, i);
411
412       if (i > 0)
413         g_string_append (string, ", ");
414       g_string_append (string, binding_set->set_name);
415     }
416 }
417
418 static GtkCssValue *
419 shadow_value_parse (GtkCssStyleProperty *property,
420                     GtkCssParser        *parser,
421                     GFile               *base)
422 {
423   gboolean have_inset, have_color, have_lengths;
424   gdouble hoffset, voffset, blur, spread;
425   GtkSymbolicColor *color;
426   GtkShadow *shadow;
427   guint i;
428
429   if (_gtk_css_parser_try (parser, "none", TRUE))
430     return _gtk_css_value_new_take_shadow (NULL);
431
432   shadow = _gtk_shadow_new ();
433
434   do
435     {
436       have_inset = have_lengths = have_color = FALSE;
437
438       for (i = 0; i < 3; i++)
439         {
440           if (!have_inset && 
441               _gtk_css_parser_try (parser, "inset", TRUE))
442             {
443               have_inset = TRUE;
444               continue;
445             }
446             
447           if (!have_lengths &&
448               _gtk_css_parser_try_double (parser, &hoffset))
449             {
450               have_lengths = TRUE;
451
452               if (!_gtk_css_parser_try_double (parser, &voffset))
453                 {
454                   _gtk_css_parser_error (parser, "Horizontal and vertical offsets are required");
455                   _gtk_shadow_unref (shadow);
456                   return NULL;
457                 }
458
459               if (!_gtk_css_parser_try_double (parser, &blur))
460                 blur = 0;
461
462               if (!_gtk_css_parser_try_double (parser, &spread))
463                 spread = 0;
464
465               continue;
466             }
467
468           if (!have_color)
469             {
470               have_color = TRUE;
471
472               /* XXX: the color is optional and UA-defined if it's missing,
473                * but it doesn't really make sense for us...
474                */
475               color = _gtk_css_parser_read_symbolic_color (parser);
476
477               if (color == NULL)
478                 {
479                   _gtk_shadow_unref (shadow);
480                   return NULL;
481                 }
482             }
483         }
484
485       if (!have_color || !have_lengths)
486         {
487           _gtk_css_parser_error (parser, "Must specify at least color and offsets");
488           _gtk_shadow_unref (shadow);
489           return NULL;
490         }
491
492       _gtk_shadow_append (shadow,
493                           hoffset, voffset,
494                           blur, spread,
495                           have_inset, color);
496
497       gtk_symbolic_color_unref (color);
498
499     }
500   while (_gtk_css_parser_try (parser, ",", TRUE));
501
502   return _gtk_css_value_new_take_shadow (shadow);
503 }
504
505 static void
506 shadow_value_print (GtkCssStyleProperty *property,
507                     const GtkCssValue   *value,
508                     GString             *string)
509 {
510   GtkShadow *shadow;
511
512   shadow = _gtk_css_value_get_shadow (value);
513
514   if (shadow == NULL)
515     g_string_append (string, "none");
516   else
517     _gtk_shadow_print (shadow, string);
518 }
519
520 static GtkCssValue *
521 shadow_value_compute (GtkCssStyleProperty *property,
522                       GtkStyleContext     *context,
523                       GtkCssValue         *specified)
524 {
525   GtkShadow *shadow;
526   
527   shadow = _gtk_css_value_get_shadow (specified);
528   if (shadow)
529     shadow = _gtk_shadow_resolve (shadow, context);
530
531   return _gtk_css_value_new_take_shadow (shadow);
532 }
533
534 static GtkCssValue *
535 border_corner_radius_value_parse (GtkCssStyleProperty *property,
536                                   GtkCssParser        *parser,
537                                   GFile               *base)
538 {
539   GtkCssBorderCornerRadius corner;
540
541   if (!_gtk_css_parser_read_number (parser,
542                                     &corner.horizontal,
543                                     GTK_CSS_POSITIVE_ONLY
544                                     | GTK_CSS_PARSE_PERCENT
545                                     | GTK_CSS_NUMBER_AS_PIXELS
546                                     | GTK_CSS_PARSE_LENGTH))
547     return FALSE;
548
549   if (!_gtk_css_parser_has_number (parser))
550     corner.vertical = corner.horizontal;
551   else if (!_gtk_css_parser_read_number (parser,
552                                          &corner.vertical,
553                                          GTK_CSS_POSITIVE_ONLY
554                                          | GTK_CSS_PARSE_PERCENT
555                                          | GTK_CSS_NUMBER_AS_PIXELS
556                                          | GTK_CSS_PARSE_LENGTH))
557     return FALSE;
558
559   return _gtk_css_value_new_from_border_corner_radius (&corner);
560 }
561
562 static void
563 border_corner_radius_value_print (GtkCssStyleProperty *property,
564                                   const GtkCssValue   *value,
565                                   GString             *string)
566 {
567   const GtkCssBorderCornerRadius *corner;
568
569   corner = _gtk_css_value_get_border_corner_radius (value);
570
571   _gtk_css_number_print (&corner->horizontal, string);
572
573   if (!_gtk_css_number_equal (&corner->horizontal, &corner->vertical))
574     {
575       g_string_append_c (string, ' ');
576       _gtk_css_number_print (&corner->vertical, string);
577     }
578 }
579
580 static GtkCssValue *
581 css_image_value_parse (GtkCssStyleProperty *property,
582                        GtkCssParser        *parser,
583                        GFile               *base)
584 {
585   GtkCssImage *image;
586
587   if (_gtk_css_parser_try (parser, "none", TRUE))
588     image = NULL;
589   else
590     {
591       image = _gtk_css_image_new_parse (parser, base);
592       if (image == NULL)
593         return FALSE;
594     }
595
596   return _gtk_css_value_new_take_image (image);
597 }
598
599 static void
600 css_image_value_print (GtkCssStyleProperty *property,
601                        const GtkCssValue   *value,
602                        GString             *string)
603 {
604   GtkCssImage *image = _gtk_css_value_get_image (value);
605
606   if (image)
607     _gtk_css_image_print (image, string);
608   else
609     g_string_append (string, "none");
610 }
611
612 static GtkCssValue *
613 css_image_value_compute (GtkCssStyleProperty    *property,
614                          GtkStyleContext        *context,
615                          GtkCssValue            *specified)
616 {
617   GtkCssImage *image, *computed;
618   
619   image = _gtk_css_value_get_image (specified);
620
621   if (image == NULL)
622     return _gtk_css_value_ref (specified);
623
624   computed = _gtk_css_image_compute (image, context);
625
626   if (computed == image)
627     {
628       g_object_unref (computed);
629       return _gtk_css_value_ref (specified);
630     }
631
632   return _gtk_css_value_new_take_image (computed);
633 }
634
635 static void
636 css_image_value_query (GtkCssStyleProperty *property,
637                        const GtkCssValue   *css_value,
638                        GValue              *value)
639 {
640   GtkCssImage *image = _gtk_css_value_get_image (css_value);
641   cairo_pattern_t *pattern;
642   cairo_surface_t *surface;
643   cairo_matrix_t matrix;
644   
645   g_value_init (value, CAIRO_GOBJECT_TYPE_PATTERN);
646
647   if (GTK_IS_CSS_IMAGE_GRADIENT (image))
648     g_value_set_boxed (value, GTK_CSS_IMAGE_GRADIENT (image)->pattern);
649   else if (image != NULL)
650     {
651       double width, height;
652
653       /* the 100, 100 is rather random */
654       _gtk_css_image_get_concrete_size (image, 0, 0, 100, 100, &width, &height);
655       surface = _gtk_css_image_get_surface (image, NULL, width, height);
656       pattern = cairo_pattern_create_for_surface (surface);
657       cairo_matrix_init_scale (&matrix, width, height);
658       cairo_pattern_set_matrix (pattern, &matrix);
659       cairo_surface_destroy (surface);
660       g_value_take_boxed (value, pattern);
661     }
662 }
663
664 static GtkCssValue *
665 font_size_parse (GtkCssStyleProperty *property,
666                  GtkCssParser        *parser,
667                  GFile               *base)
668 {
669   gdouble d;
670
671   if (!_gtk_css_parser_try_double (parser, &d))
672     {
673       _gtk_css_parser_error (parser, "Expected a number");
674       return NULL;
675     }
676
677   return _gtk_css_value_new_from_double (d);
678 }
679
680 static GtkCssValue *
681 outline_parse (GtkCssStyleProperty *property,
682                GtkCssParser        *parser,
683                GFile               *base)
684 {
685   int i;
686
687   if (!_gtk_css_parser_try_int (parser, &i))
688     {
689       _gtk_css_parser_error (parser, "Expected an integer");
690       return NULL;
691     }
692
693   return _gtk_css_value_new_from_int (i);
694 }
695
696 static GtkCssValue *
697 border_image_repeat_parse (GtkCssStyleProperty *property,
698                            GtkCssParser        *parser,
699                            GFile               *base)
700 {
701   GValue value = G_VALUE_INIT;
702   GtkCssValue *result;
703
704   g_value_init (&value, GTK_TYPE_CSS_BORDER_IMAGE_REPEAT);
705   if (!_gtk_css_style_parse_value (&value, parser, base))
706     {
707       g_value_unset (&value);
708       return NULL;
709     }
710
711   result = _gtk_css_value_new_from_gvalue (&value);
712   g_value_unset (&value);
713
714   return result;
715 }
716
717 static GtkCssValue *
718 border_image_slice_parse (GtkCssStyleProperty *property,
719                           GtkCssParser        *parser,
720                           GFile               *base)
721 {
722   GValue value = G_VALUE_INIT;
723   GtkCssValue *result;
724
725   g_value_init (&value, GTK_TYPE_BORDER);
726   if (!_gtk_css_style_parse_value (&value, parser, base))
727     {
728       g_value_unset (&value);
729       return NULL;
730     }
731
732   result = _gtk_css_value_new_from_gvalue (&value);
733   g_value_unset (&value);
734
735   return result;
736 }
737
738 static GtkCssValue *
739 border_image_width_parse (GtkCssStyleProperty *property,
740                           GtkCssParser        *parser,
741                           GFile               *base)
742 {
743   GValue value = G_VALUE_INIT;
744   GtkCssValue *result;
745
746   g_value_init (&value, GTK_TYPE_BORDER);
747   if (!_gtk_css_style_parse_value (&value, parser, base))
748     {
749       g_value_unset (&value);
750       return NULL;
751     }
752
753   result = _gtk_css_value_new_from_gvalue (&value);
754   g_value_unset (&value);
755
756   return result;
757 }
758
759 static GtkCssValue *
760 engine_parse (GtkCssStyleProperty *property,
761               GtkCssParser        *parser,
762               GFile               *base)
763 {
764   GtkThemingEngine *engine;
765   char *str;
766
767   if (_gtk_css_parser_try (parser, "none", TRUE))
768     return _gtk_css_value_new_from_theming_engine (gtk_theming_engine_load (NULL));
769
770   str = _gtk_css_parser_try_ident (parser, TRUE);
771   if (str == NULL)
772     {
773       _gtk_css_parser_error (parser, "Expected a valid theme name");
774       return NULL;
775     }
776
777   engine = gtk_theming_engine_load (str);
778
779   if (engine == NULL)
780     {
781       _gtk_css_parser_error (parser, "Theming engine '%s' not found", str);
782       g_free (str);
783       return NULL;
784     }
785
786   g_free (str);
787
788   return _gtk_css_value_new_from_theming_engine (engine);
789 }
790
791 static GtkCssValue *
792 transition_parse (GtkCssStyleProperty *property,
793                   GtkCssParser        *parser,
794                   GFile               *base)
795 {
796   GValue value = G_VALUE_INIT;
797   GtkCssValue *result;
798
799   g_value_init (&value, GTK_TYPE_ANIMATION_DESCRIPTION);
800   if (!_gtk_css_style_parse_value (&value, parser, base))
801     {
802       g_value_unset (&value);
803       return NULL;
804     }
805
806   result = _gtk_css_value_new_from_gvalue (&value);
807   g_value_unset (&value);
808
809   return result;
810 }
811
812 static GtkCssValue *
813 parse_margin (GtkCssStyleProperty *property,
814               GtkCssParser        *parser,
815               GFile               *base)
816 {
817   GtkCssNumber number;
818
819   if (!_gtk_css_parser_read_number (parser,
820                                     &number, 
821                                     GTK_CSS_NUMBER_AS_PIXELS
822                                     | GTK_CSS_PARSE_LENGTH))
823     return NULL;
824
825   return _gtk_css_value_new_from_number (&number);
826 }
827
828 static GtkCssValue *
829 compute_margin (GtkCssStyleProperty *property,
830                 GtkStyleContext     *context,
831                 GtkCssValue         *specified)
832 {
833   GtkCssNumber number;
834   
835   if (_gtk_css_number_compute (&number,
836                                _gtk_css_value_get_number (specified),
837                                context))
838     {
839       return _gtk_css_value_new_from_number (&number);
840     }
841   return  _gtk_css_value_ref (specified);
842 }
843
844 static GtkCssValue *
845 parse_padding (GtkCssStyleProperty *property,
846                GtkCssParser        *parser,
847                GFile               *base)
848 {
849   GtkCssNumber number;
850
851   if (!_gtk_css_parser_read_number (parser,
852                                     &number, 
853                                     GTK_CSS_POSITIVE_ONLY
854                                     | GTK_CSS_NUMBER_AS_PIXELS
855                                     | GTK_CSS_PARSE_LENGTH))
856     return NULL;
857
858   return _gtk_css_value_new_from_number (&number);
859 }
860
861 static GtkCssValue *
862 compute_padding (GtkCssStyleProperty *property,
863                  GtkStyleContext     *context,
864                  GtkCssValue         *specified)
865 {
866   GtkCssNumber number;
867
868   if (_gtk_css_number_compute (&number,
869                                _gtk_css_value_get_number (specified),
870                                context))
871     return _gtk_css_value_new_from_number (&number);
872   return _gtk_css_value_ref (specified);
873 }
874
875 static GtkCssValue *
876 parse_border_width (GtkCssStyleProperty *property,
877                     GtkCssParser        *parser,
878                     GFile               *base)
879 {
880   GtkCssNumber number;
881
882   if (!_gtk_css_parser_read_number (parser,
883                                     &number, 
884                                     GTK_CSS_POSITIVE_ONLY
885                                     | GTK_CSS_NUMBER_AS_PIXELS
886                                     | GTK_CSS_PARSE_LENGTH))
887     return FALSE;
888
889   return _gtk_css_value_new_from_number (&number);
890 }
891
892 static GtkCssValue *
893 compute_border_width (GtkCssStyleProperty    *property,
894                       GtkStyleContext        *context,
895                       GtkCssValue            *specified)
896 {
897   GtkCssStyleProperty *style;
898   GtkBorderStyle border_style;
899   GtkCssNumber number;
900   
901   /* The -1 is magic that is only true because we register the style
902    * properties directly after the width properties.
903    */
904   style = _gtk_css_style_property_lookup_by_id (_gtk_css_style_property_get_id (property) - 1);
905   
906   border_style = _gtk_css_value_get_border_style (_gtk_style_context_peek_property (context, _gtk_style_property_get_name (GTK_STYLE_PROPERTY (style))));
907
908   if (border_style == GTK_BORDER_STYLE_NONE ||
909       border_style == GTK_BORDER_STYLE_HIDDEN)
910     {
911       _gtk_css_number_init (&number, 0, GTK_CSS_PX);
912     }
913   else
914     {
915       _gtk_css_number_compute (&number,
916                                _gtk_css_value_get_number (specified),
917                                context);
918     }
919   return _gtk_css_value_new_from_number (&number);
920 }
921
922 static GtkCssValue *
923 background_repeat_value_parse (GtkCssStyleProperty *property,
924                                GtkCssParser        *parser,
925                                GFile               *base)
926 {
927   int repeat, vertical;
928
929   if (!_gtk_css_parser_try_enum (parser, GTK_TYPE_CSS_BACKGROUND_REPEAT, &repeat))
930     {
931       _gtk_css_parser_error (parser, "Not a valid value");
932       return FALSE;
933     }
934
935   if (repeat <= GTK_CSS_BACKGROUND_REPEAT_MASK)
936     {
937       if (_gtk_css_parser_try_enum (parser, GTK_TYPE_CSS_BACKGROUND_REPEAT, &vertical))
938         {
939           if (vertical >= GTK_CSS_BACKGROUND_REPEAT_MASK)
940             {
941               _gtk_css_parser_error (parser, "Not a valid 2nd value");
942               return FALSE;
943             }
944           else
945             repeat |= vertical << GTK_CSS_BACKGROUND_REPEAT_SHIFT;
946         }
947       else
948         repeat |= repeat << GTK_CSS_BACKGROUND_REPEAT_SHIFT;
949     }
950
951   return _gtk_css_value_new_from_enum (GTK_TYPE_CSS_BACKGROUND_REPEAT, repeat);
952 }
953
954 static void
955 background_repeat_value_print (GtkCssStyleProperty *property,
956                                const GtkCssValue   *value,
957                                GString             *string)
958 {
959   GEnumClass *enum_class;
960   GEnumValue *enum_value;
961   GtkCssBackgroundRepeat repeat;
962
963   repeat = _gtk_css_value_get_enum (value);
964   enum_class = g_type_class_ref (GTK_TYPE_CSS_BACKGROUND_REPEAT);
965   enum_value = g_enum_get_value (enum_class, repeat);
966
967   /* only triggers for 'repeat-x' and 'repeat-y' */
968   if (enum_value)
969     g_string_append (string, enum_value->value_nick);
970   else
971     {
972       enum_value = g_enum_get_value (enum_class, GTK_CSS_BACKGROUND_HORIZONTAL (repeat));
973       g_string_append (string, enum_value->value_nick);
974
975       if (GTK_CSS_BACKGROUND_HORIZONTAL (repeat) != GTK_CSS_BACKGROUND_VERTICAL (repeat))
976         {
977           enum_value = g_enum_get_value (enum_class, GTK_CSS_BACKGROUND_VERTICAL (repeat));
978           g_string_append (string, " ");
979           g_string_append (string, enum_value->value_nick);
980         }
981     }
982
983   g_type_class_unref (enum_class);
984 }
985
986 static GtkCssValue *
987 background_size_parse (GtkCssStyleProperty *property,
988                        GtkCssParser        *parser,
989                        GFile               *base)
990 {
991   GtkCssBackgroundSize size = { GTK_CSS_NUMBER_INIT (0, GTK_CSS_PX), GTK_CSS_NUMBER_INIT (0, GTK_CSS_PX), FALSE, FALSE};
992
993   if (_gtk_css_parser_try (parser, "cover", TRUE))
994     size.cover = TRUE;
995   else if (_gtk_css_parser_try (parser, "contain", TRUE))
996     size.contain = TRUE;
997   else
998     {
999       if (_gtk_css_parser_try (parser, "auto", TRUE))
1000         _gtk_css_number_init (&size.width, 0, GTK_CSS_PX);
1001       else if (!_gtk_css_parser_read_number (parser,
1002                                              &size.width,
1003                                              GTK_CSS_POSITIVE_ONLY
1004                                              | GTK_CSS_PARSE_PERCENT
1005                                              | GTK_CSS_PARSE_LENGTH))
1006         return NULL;
1007
1008       if (_gtk_css_parser_try (parser, "auto", TRUE))
1009         _gtk_css_number_init (&size.height, 0, GTK_CSS_PX);
1010       else if (_gtk_css_parser_has_number (parser))
1011         {
1012           if (!_gtk_css_parser_read_number (parser,
1013                                             &size.height,
1014                                             GTK_CSS_POSITIVE_ONLY
1015                                             | GTK_CSS_PARSE_PERCENT
1016                                             | GTK_CSS_PARSE_LENGTH))
1017             return NULL;
1018         }
1019       else
1020         _gtk_css_number_init (&size.height, 0, GTK_CSS_PX);
1021     }
1022
1023   return _gtk_css_value_new_from_background_size (&size);
1024 }
1025
1026 static void
1027 background_size_print (GtkCssStyleProperty *property,
1028                        const GtkCssValue   *value,
1029                        GString             *string)
1030 {
1031   const GtkCssBackgroundSize *size = _gtk_css_value_get_background_size (value);
1032
1033   if (size->cover)
1034     g_string_append (string, "cover");
1035   else if (size->contain)
1036     g_string_append (string, "contain");
1037   else
1038     {
1039       if (size->width.value == 0)
1040         g_string_append (string, "auto");
1041       else
1042         _gtk_css_number_print (&size->width, string);
1043
1044       if (size->height.value != 0)
1045         {
1046           g_string_append (string, " ");
1047           _gtk_css_number_print (&size->height, string);
1048         }
1049     }
1050 }
1051
1052 static GtkCssValue *
1053 background_size_compute (GtkCssStyleProperty    *property,
1054                          GtkStyleContext        *context,
1055                          GtkCssValue            *specified)
1056 {
1057   const GtkCssBackgroundSize *ssize = _gtk_css_value_get_background_size (specified);
1058   GtkCssBackgroundSize csize;
1059   gboolean changed;
1060
1061   csize.cover = ssize->cover;
1062   csize.contain = ssize->contain;
1063   changed = _gtk_css_number_compute (&csize.width,
1064                                      &ssize->width,
1065                                      context);
1066   changed |= _gtk_css_number_compute (&csize.height,
1067                                       &ssize->height,
1068                                       context);
1069   if (changed)
1070     return _gtk_css_value_new_from_background_size (&csize);
1071   return _gtk_css_value_ref (specified);
1072 }
1073
1074 static GtkCssValue *
1075 background_position_parse (GtkCssStyleProperty *property,
1076                            GtkCssParser        *parser,
1077                            GFile               *base)
1078 {
1079   static const struct {
1080     const char *name;
1081     guint       percentage;
1082     gboolean    horizontal;
1083     gboolean    vertical;
1084   } names[] = {
1085     { "left",     0, TRUE,  FALSE },
1086     { "right",  100, TRUE,  FALSE },
1087     { "center",  50, TRUE,  TRUE  },
1088     { "top",      0, FALSE, TRUE  },
1089     { "bottom", 100, FALSE, TRUE  },
1090     { NULL    ,   0, TRUE,  FALSE }, /* used for numbers */
1091     { NULL    ,  50, TRUE,  TRUE  }  /* used for no value */
1092   };
1093   GtkCssBackgroundPosition pos;
1094   GtkCssNumber *missing;
1095   guint first, second;
1096
1097   for (first = 0; names[first].name != NULL; first++)
1098     {
1099       if (_gtk_css_parser_try (parser, names[first].name, TRUE))
1100         {
1101           if (names[first].horizontal)
1102             {
1103               _gtk_css_number_init (&pos.x, names[first].percentage, GTK_CSS_PERCENT);
1104               missing = &pos.y;
1105             }
1106           else
1107             {
1108               _gtk_css_number_init (&pos.y, names[first].percentage, GTK_CSS_PERCENT);
1109               missing = &pos.x;
1110             }
1111           break;
1112         }
1113     }
1114   if (names[first].name == NULL)
1115     {
1116       missing = &pos.y;
1117       if (!_gtk_css_parser_read_number (parser,
1118                                         &pos.x,
1119                                         GTK_CSS_PARSE_PERCENT
1120                                         | GTK_CSS_PARSE_LENGTH))
1121         return NULL;
1122     }
1123
1124   for (second = 0; names[second].name != NULL; second++)
1125     {
1126       if (_gtk_css_parser_try (parser, names[second].name, TRUE))
1127         {
1128           _gtk_css_number_init (missing, names[second].percentage, GTK_CSS_PERCENT);
1129           break;
1130         }
1131     }
1132
1133   if (names[second].name == NULL)
1134     {
1135       if (_gtk_css_parser_has_number (parser))
1136         {
1137           if (missing != &pos.y)
1138             {
1139               _gtk_css_parser_error (parser, "Invalid combination of values");
1140               return NULL;
1141             }
1142           if (!_gtk_css_parser_read_number (parser,
1143                                             missing,
1144                                             GTK_CSS_PARSE_PERCENT
1145                                             | GTK_CSS_PARSE_LENGTH))
1146             return NULL;
1147         }
1148       else
1149         {
1150           second++;
1151           _gtk_css_number_init (missing, 50, GTK_CSS_PERCENT);
1152         }
1153     }
1154   else
1155     {
1156       if ((names[first].horizontal && !names[second].vertical) ||
1157           (!names[first].horizontal && !names[second].horizontal))
1158         {
1159           _gtk_css_parser_error (parser, "Invalid combination of values");
1160           return NULL;
1161         }
1162     }
1163
1164   return _gtk_css_value_new_from_background_position (&pos);
1165 }
1166
1167 static void
1168 background_position_print (GtkCssStyleProperty *property,
1169                            const GtkCssValue   *value,
1170                            GString             *string)
1171 {
1172   const GtkCssBackgroundPosition *pos = _gtk_css_value_get_background_position (value);
1173   static const GtkCssNumber center = GTK_CSS_NUMBER_INIT (50, GTK_CSS_PERCENT);
1174   static const struct {
1175     const char *x_name;
1176     const char *y_name;
1177     GtkCssNumber number;
1178   } values[] = { 
1179     { "left",   "top",    GTK_CSS_NUMBER_INIT (0,   GTK_CSS_PERCENT) },
1180     { "right",  "bottom", GTK_CSS_NUMBER_INIT (100, GTK_CSS_PERCENT) }
1181   };
1182   guint i;
1183
1184   if (_gtk_css_number_equal (&pos->x, &center))
1185     {
1186       if (_gtk_css_number_equal (&pos->y, &center))
1187         {
1188           g_string_append (string, "center");
1189           return;
1190         }
1191     }
1192   else
1193     {
1194       for (i = 0; i < G_N_ELEMENTS (values); i++)
1195         {
1196           if (_gtk_css_number_equal (&pos->x, &values[i].number))
1197             {
1198               g_string_append (string, values[i].x_name);
1199               break;
1200             }
1201         }
1202       if (i == G_N_ELEMENTS (values))
1203         _gtk_css_number_print (&pos->x, string);
1204
1205       if (_gtk_css_number_equal (&pos->y, &center))
1206         return;
1207
1208       g_string_append_c (string, ' ');
1209     }
1210
1211   for (i = 0; i < G_N_ELEMENTS (values); i++)
1212     {
1213       if (_gtk_css_number_equal (&pos->y, &values[i].number))
1214         {
1215           g_string_append (string, values[i].y_name);
1216           break;
1217         }
1218     }
1219   if (i == G_N_ELEMENTS (values))
1220     {
1221       if (_gtk_css_number_equal (&pos->x, &center))
1222         g_string_append (string, "center ");
1223       _gtk_css_number_print (&pos->y, string);
1224     }
1225 }
1226
1227 static GtkCssValue *
1228 background_position_compute (GtkCssStyleProperty    *property,
1229                              GtkStyleContext        *context,
1230                              GtkCssValue            *specified)
1231 {
1232   const GtkCssBackgroundPosition *spos = _gtk_css_value_get_background_position (specified);
1233   GtkCssBackgroundPosition cpos;
1234   gboolean changed;
1235
1236   changed = _gtk_css_number_compute (&cpos.x,
1237                                      &spos->x,
1238                                      context);
1239   changed |= _gtk_css_number_compute (&cpos.y,
1240                                       &spos->y,
1241                                       context);
1242   if (changed)
1243     return _gtk_css_value_new_from_background_position (&cpos);
1244   return _gtk_css_value_ref (specified);
1245 }
1246
1247 /*** REGISTRATION ***/
1248
1249 static GtkSymbolicColor *
1250 gtk_symbolic_color_new_rgba (double red,
1251                              double green,
1252                              double blue,
1253                              double alpha)
1254 {
1255   GdkRGBA rgba = { red, green, blue, alpha };
1256
1257   return gtk_symbolic_color_new_literal (&rgba);
1258 }
1259
1260 void
1261 _gtk_css_style_property_init_properties (void)
1262 {
1263   char *default_font_family[] = { "Sans", NULL };
1264   GtkCssNumber number;
1265   GtkCssBackgroundSize default_background_size = { GTK_CSS_NUMBER_INIT (0, GTK_CSS_PX), GTK_CSS_NUMBER_INIT (0, GTK_CSS_PX), FALSE, FALSE };
1266   GtkCssBackgroundPosition default_background_position = { GTK_CSS_NUMBER_INIT (0, GTK_CSS_PERCENT), GTK_CSS_NUMBER_INIT (0, GTK_CSS_PERCENT)};
1267   GtkCssBorderCornerRadius no_corner_radius = { GTK_CSS_NUMBER_INIT (0, GTK_CSS_PX), GTK_CSS_NUMBER_INIT (0, GTK_CSS_PX) };
1268   GtkBorder border_of_ones = { 1, 1, 1, 1 };
1269   GtkCssBorderImageRepeat border_image_repeat = { GTK_CSS_REPEAT_STYLE_STRETCH, GTK_CSS_REPEAT_STYLE_STRETCH };
1270
1271   /* Initialize "color" and "font-size" first,
1272    * so that when computing values later they are
1273    * done first. That way, 'currentColor' and font
1274    * sizes in em can be looked up properly */
1275   gtk_css_style_property_register        ("color",
1276                                           GDK_TYPE_RGBA,
1277                                           GTK_STYLE_PROPERTY_INHERIT,
1278                                           color_parse,
1279                                           NULL,
1280                                           color_compute,
1281                                           query_simple,
1282                                           NULL,
1283                                           _gtk_css_value_new_take_symbolic_color (
1284                                             gtk_symbolic_color_new_rgba (1, 1, 1, 1)));
1285   gtk_css_style_property_register        ("font-size",
1286                                           G_TYPE_DOUBLE,
1287                                           GTK_STYLE_PROPERTY_INHERIT,
1288                                           font_size_parse,
1289                                           NULL,
1290                                           NULL,
1291                                           query_simple,
1292                                           NULL,
1293                                           _gtk_css_value_new_from_double (10.0));
1294
1295   /* properties that aren't referenced when computing values
1296    * start here */
1297   gtk_css_style_property_register        ("background-color",
1298                                           GDK_TYPE_RGBA,
1299                                           0,
1300                                           color_parse,
1301                                           NULL,
1302                                           color_compute,
1303                                           query_simple,
1304                                           NULL,
1305                                           _gtk_css_value_new_take_symbolic_color (
1306                                             gtk_symbolic_color_new_rgba (0, 0, 0, 0)));
1307
1308   gtk_css_style_property_register        ("font-family",
1309                                           G_TYPE_STRV,
1310                                           GTK_STYLE_PROPERTY_INHERIT,
1311                                           font_family_parse,
1312                                           font_family_value_print,
1313                                           NULL,
1314                                           query_simple,
1315                                           NULL,
1316                                           _gtk_css_value_new_take_strv (g_strdupv (default_font_family)));
1317   gtk_css_style_property_register        ("font-style",
1318                                           PANGO_TYPE_STYLE,
1319                                           GTK_STYLE_PROPERTY_INHERIT,
1320                                           parse_pango_style,
1321                                           NULL,
1322                                           NULL,
1323                                           query_simple,
1324                                           NULL,
1325                                           _gtk_css_value_new_from_enum (PANGO_TYPE_STYLE,
1326                                                                         PANGO_STYLE_NORMAL));
1327   gtk_css_style_property_register        ("font-variant",
1328                                           PANGO_TYPE_VARIANT,
1329                                           GTK_STYLE_PROPERTY_INHERIT,
1330                                           parse_pango_variant,
1331                                           NULL,
1332                                           NULL,
1333                                           query_simple,
1334                                           NULL,
1335                                           _gtk_css_value_new_from_enum (PANGO_TYPE_VARIANT,
1336                                                                         PANGO_VARIANT_NORMAL));
1337   /* xxx: need to parse this properly, ie parse the numbers */
1338   gtk_css_style_property_register        ("font-weight",
1339                                           PANGO_TYPE_WEIGHT,
1340                                           GTK_STYLE_PROPERTY_INHERIT,
1341                                           parse_pango_weight,
1342                                           NULL,
1343                                           NULL,
1344                                           query_simple,
1345                                           NULL,
1346                                           _gtk_css_value_new_from_enum (PANGO_TYPE_WEIGHT,
1347                                                                         PANGO_WEIGHT_NORMAL));
1348
1349   gtk_css_style_property_register        ("text-shadow",
1350                                           GTK_TYPE_SHADOW,
1351                                           GTK_STYLE_PROPERTY_INHERIT,
1352                                           shadow_value_parse,
1353                                           shadow_value_print,
1354                                           shadow_value_compute,
1355                                           query_simple,
1356                                           NULL,
1357                                           _gtk_css_value_new_take_shadow (NULL));
1358
1359   gtk_css_style_property_register        ("icon-shadow",
1360                                           GTK_TYPE_SHADOW,
1361                                           GTK_STYLE_PROPERTY_INHERIT,
1362                                           shadow_value_parse,
1363                                           shadow_value_print,
1364                                           shadow_value_compute,
1365                                           query_simple,
1366                                           NULL,
1367                                           _gtk_css_value_new_take_shadow (NULL));
1368
1369   gtk_css_style_property_register        ("box-shadow",
1370                                           GTK_TYPE_SHADOW,
1371                                           0,
1372                                           shadow_value_parse,
1373                                           shadow_value_print,
1374                                           shadow_value_compute,
1375                                           query_simple,
1376                                           NULL,
1377                                           _gtk_css_value_new_take_shadow (NULL));
1378
1379   _gtk_css_number_init (&number, 0, GTK_CSS_PX);
1380   gtk_css_style_property_register        ("margin-top",
1381                                           G_TYPE_INT,
1382                                           0,
1383                                           parse_margin,
1384                                           NULL,
1385                                           compute_margin,
1386                                           query_length_as_int,
1387                                           NULL,
1388                                           _gtk_css_value_new_from_number (&number));
1389   gtk_css_style_property_register        ("margin-left",
1390                                           G_TYPE_INT,
1391                                           0,
1392                                           parse_margin,
1393                                           NULL,
1394                                           compute_margin,
1395                                           query_length_as_int,
1396                                           NULL,
1397                                           _gtk_css_value_new_from_number (&number));
1398   gtk_css_style_property_register        ("margin-bottom",
1399                                           G_TYPE_INT,
1400                                           0,
1401                                           parse_margin,
1402                                           NULL,
1403                                           compute_margin,
1404                                           query_length_as_int,
1405                                           NULL,
1406                                           _gtk_css_value_new_from_number (&number));
1407   gtk_css_style_property_register        ("margin-right",
1408                                           G_TYPE_INT,
1409                                           0,
1410                                           parse_margin,
1411                                           NULL,
1412                                           compute_margin,
1413                                           query_length_as_int,
1414                                           NULL,
1415                                           _gtk_css_value_new_from_number (&number));
1416   gtk_css_style_property_register        ("padding-top",
1417                                           G_TYPE_INT,
1418                                           0,
1419                                           parse_padding,
1420                                           NULL,
1421                                           compute_padding,
1422                                           query_length_as_int,
1423                                           NULL,
1424                                           _gtk_css_value_new_from_number (&number));
1425   gtk_css_style_property_register        ("padding-left",
1426                                           G_TYPE_INT,
1427                                           0,
1428                                           parse_padding,
1429                                           NULL,
1430                                           compute_padding,
1431                                           query_length_as_int,
1432                                           NULL,
1433                                           _gtk_css_value_new_from_number (&number));
1434   gtk_css_style_property_register        ("padding-bottom",
1435                                           G_TYPE_INT,
1436                                           0,
1437                                           parse_padding,
1438                                           NULL,
1439                                           compute_padding,
1440                                           query_length_as_int,
1441                                           NULL,
1442                                           _gtk_css_value_new_from_number (&number));
1443   gtk_css_style_property_register        ("padding-right",
1444                                           G_TYPE_INT,
1445                                           0,
1446                                           parse_padding,
1447                                           NULL,
1448                                           compute_padding,
1449                                           query_length_as_int,
1450                                           NULL,
1451                                           _gtk_css_value_new_from_number (&number));
1452   /* IMPORTANT: compute_border_width() requires that the border-width
1453    * properties be immeditaly followed by the border-style properties
1454    */
1455   gtk_css_style_property_register        ("border-top-style",
1456                                           GTK_TYPE_BORDER_STYLE,
1457                                           0,
1458                                           parse_border_style,
1459                                           NULL,
1460                                           NULL,
1461                                           query_simple,
1462                                           NULL,
1463                                           _gtk_css_value_new_from_border_style (GTK_BORDER_STYLE_NONE));
1464   gtk_css_style_property_register        ("border-top-width",
1465                                           G_TYPE_INT,
1466                                           0,
1467                                           parse_border_width,
1468                                           NULL,
1469                                           compute_border_width,
1470                                           query_length_as_int,
1471                                           NULL,
1472                                           _gtk_css_value_new_from_number (&number));
1473   gtk_css_style_property_register        ("border-left-style",
1474                                           GTK_TYPE_BORDER_STYLE,
1475                                           0,
1476                                           parse_border_style,
1477                                           NULL,
1478                                           NULL,
1479                                           query_simple,
1480                                           NULL,
1481                                           _gtk_css_value_new_from_border_style (GTK_BORDER_STYLE_NONE));
1482   gtk_css_style_property_register        ("border-left-width",
1483                                           G_TYPE_INT,
1484                                           0,
1485                                           parse_border_width,
1486                                           NULL,
1487                                           compute_border_width,
1488                                           query_length_as_int,
1489                                           NULL,
1490                                           _gtk_css_value_new_from_number (&number));
1491   gtk_css_style_property_register        ("border-bottom-style",
1492                                           GTK_TYPE_BORDER_STYLE,
1493                                           0,
1494                                           parse_border_style,
1495                                           NULL,
1496                                           NULL,
1497                                           query_simple,
1498                                           NULL,
1499                                           _gtk_css_value_new_from_border_style (GTK_BORDER_STYLE_NONE));
1500   gtk_css_style_property_register        ("border-bottom-width",
1501                                           G_TYPE_INT,
1502                                           0,
1503                                           parse_border_width,
1504                                           NULL,
1505                                           compute_border_width,
1506                                           query_length_as_int,
1507                                           NULL,
1508                                           _gtk_css_value_new_from_number (&number));
1509   gtk_css_style_property_register        ("border-right-style",
1510                                           GTK_TYPE_BORDER_STYLE,
1511                                           0,
1512                                           parse_border_style,
1513                                           NULL,
1514                                           NULL,
1515                                           query_simple,
1516                                           NULL,
1517                                           _gtk_css_value_new_from_border_style (GTK_BORDER_STYLE_NONE));
1518   gtk_css_style_property_register        ("border-right-width",
1519                                           G_TYPE_INT,
1520                                           0,
1521                                           parse_border_width,
1522                                           NULL,
1523                                           compute_border_width,
1524                                           query_length_as_int,
1525                                           NULL,
1526                                           _gtk_css_value_new_from_number (&number));
1527
1528   gtk_css_style_property_register        ("border-top-left-radius",
1529                                           GTK_TYPE_CSS_BORDER_CORNER_RADIUS,
1530                                           0,
1531                                           border_corner_radius_value_parse,
1532                                           border_corner_radius_value_print,
1533                                           NULL,
1534                                           query_simple,
1535                                           NULL,
1536                                           _gtk_css_value_new_from_border_corner_radius (&no_corner_radius));
1537   gtk_css_style_property_register        ("border-top-right-radius",
1538                                           GTK_TYPE_CSS_BORDER_CORNER_RADIUS,
1539                                           0,
1540                                           border_corner_radius_value_parse,
1541                                           border_corner_radius_value_print,
1542                                           NULL,
1543                                           query_simple,
1544                                           NULL,
1545                                           _gtk_css_value_new_from_border_corner_radius (&no_corner_radius));
1546   gtk_css_style_property_register        ("border-bottom-right-radius",
1547                                           GTK_TYPE_CSS_BORDER_CORNER_RADIUS,
1548                                           0,
1549                                           border_corner_radius_value_parse,
1550                                           border_corner_radius_value_print,
1551                                           NULL,
1552                                           query_simple,
1553                                           NULL,
1554                                           _gtk_css_value_new_from_border_corner_radius (&no_corner_radius));
1555   gtk_css_style_property_register        ("border-bottom-left-radius",
1556                                           GTK_TYPE_CSS_BORDER_CORNER_RADIUS,
1557                                           0,
1558                                           border_corner_radius_value_parse,
1559                                           border_corner_radius_value_print,
1560                                           NULL,
1561                                           query_simple,
1562                                           NULL,
1563                                           _gtk_css_value_new_from_border_corner_radius (&no_corner_radius));
1564
1565   gtk_css_style_property_register        ("outline-style",
1566                                           GTK_TYPE_BORDER_STYLE,
1567                                           0,
1568                                           parse_border_style,
1569                                           NULL,
1570                                           NULL,
1571                                           query_simple,
1572                                           NULL,
1573                                           _gtk_css_value_new_from_border_style (GTK_BORDER_STYLE_NONE));
1574   gtk_css_style_property_register        ("outline-width",
1575                                           G_TYPE_INT,
1576                                           0,
1577                                           parse_border_width,
1578                                           NULL,
1579                                           compute_border_width,
1580                                           query_length_as_int,
1581                                           NULL,
1582                                           _gtk_css_value_new_from_number (&number));
1583   gtk_css_style_property_register        ("outline-offset",
1584                                           G_TYPE_INT,
1585                                           0,
1586                                           outline_parse,
1587                                           NULL,
1588                                           NULL,
1589                                           query_simple,
1590                                           NULL,
1591                                           _gtk_css_value_new_from_int (0));
1592
1593   gtk_css_style_property_register        ("background-clip",
1594                                           GTK_TYPE_CSS_AREA,
1595                                           0,
1596                                           parse_css_area,
1597                                           NULL,
1598                                           NULL,
1599                                           query_simple,
1600                                           NULL,
1601                                           _gtk_css_value_new_from_enum (GTK_TYPE_CSS_AREA, GTK_CSS_AREA_BORDER_BOX));
1602   gtk_css_style_property_register        ("background-origin",
1603                                           GTK_TYPE_CSS_AREA,
1604                                           0,
1605                                           parse_css_area,
1606                                           NULL,
1607                                           NULL,
1608                                           query_simple,
1609                                           NULL,
1610                                           _gtk_css_value_new_from_enum (GTK_TYPE_CSS_AREA, GTK_CSS_AREA_PADDING_BOX));
1611   gtk_css_style_property_register        ("background-size",
1612                                           G_TYPE_NONE,
1613                                           0,
1614                                           background_size_parse,
1615                                           background_size_print,
1616                                           background_size_compute,
1617                                           NULL,
1618                                           NULL,
1619                                           _gtk_css_value_new_from_background_size (&default_background_size));
1620   gtk_css_style_property_register        ("background-position",
1621                                           G_TYPE_NONE,
1622                                           0,
1623                                           background_position_parse,
1624                                           background_position_print,
1625                                           background_position_compute,
1626                                           NULL,
1627                                           NULL,
1628                                           _gtk_css_value_new_from_background_position (&default_background_position));
1629
1630   gtk_css_style_property_register        ("border-top-color",
1631                                           GDK_TYPE_RGBA,
1632                                           0,
1633                                           color_parse,
1634                                           NULL,
1635                                           color_compute,
1636                                           query_simple,
1637                                           NULL,
1638                                           _gtk_css_value_new_take_symbolic_color (
1639                                             gtk_symbolic_color_ref (
1640                                               _gtk_symbolic_color_get_current_color ())));
1641   gtk_css_style_property_register        ("border-right-color",
1642                                           GDK_TYPE_RGBA,
1643                                           0,
1644                                           color_parse,
1645                                           NULL,
1646                                           color_compute,
1647                                           query_simple,
1648                                           NULL,
1649                                           _gtk_css_value_new_take_symbolic_color (
1650                                             gtk_symbolic_color_ref (
1651                                               _gtk_symbolic_color_get_current_color ())));
1652   gtk_css_style_property_register        ("border-bottom-color",
1653                                           GDK_TYPE_RGBA,
1654                                           0,
1655                                           color_parse,
1656                                           NULL,
1657                                           color_compute,
1658                                           query_simple,
1659                                           NULL,
1660                                           _gtk_css_value_new_take_symbolic_color (
1661                                             gtk_symbolic_color_ref (
1662                                               _gtk_symbolic_color_get_current_color ())));
1663   gtk_css_style_property_register        ("border-left-color",
1664                                           GDK_TYPE_RGBA,
1665                                           0,
1666                                           color_parse,
1667                                           NULL,
1668                                           color_compute,
1669                                           query_simple,
1670                                           NULL,
1671                                           _gtk_css_value_new_take_symbolic_color (
1672                                             gtk_symbolic_color_ref (
1673                                               _gtk_symbolic_color_get_current_color ())));
1674   gtk_css_style_property_register        ("outline-color",
1675                                           GDK_TYPE_RGBA,
1676                                           0,
1677                                           color_parse,
1678                                           NULL,
1679                                           color_compute,
1680                                           query_simple,
1681                                           NULL,
1682                                           _gtk_css_value_new_take_symbolic_color (
1683                                             gtk_symbolic_color_ref (
1684                                               _gtk_symbolic_color_get_current_color ())));
1685
1686   gtk_css_style_property_register        ("background-repeat",
1687                                           GTK_TYPE_CSS_BACKGROUND_REPEAT,
1688                                           0,
1689                                           background_repeat_value_parse,
1690                                           background_repeat_value_print,
1691                                           NULL,
1692                                           query_simple,
1693                                           NULL,
1694                                           _gtk_css_value_new_from_enum (GTK_TYPE_CSS_BACKGROUND_REPEAT,
1695                                                                         GTK_CSS_BACKGROUND_REPEAT | 
1696                                                                         (GTK_CSS_BACKGROUND_REPEAT << GTK_CSS_BACKGROUND_REPEAT_SHIFT)));
1697   gtk_css_style_property_register        ("background-image",
1698                                           CAIRO_GOBJECT_TYPE_PATTERN,
1699                                           0,
1700                                           css_image_value_parse,
1701                                           css_image_value_print,
1702                                           css_image_value_compute,
1703                                           css_image_value_query,
1704                                           NULL,
1705                                           _gtk_css_value_new_take_image (NULL));
1706
1707   gtk_css_style_property_register        ("border-image-source",
1708                                           CAIRO_GOBJECT_TYPE_PATTERN,
1709                                           0,
1710                                           css_image_value_parse,
1711                                           css_image_value_print,
1712                                           css_image_value_compute,
1713                                           css_image_value_query,
1714                                           NULL,
1715                                           _gtk_css_value_new_take_image (NULL));
1716   gtk_css_style_property_register        ("border-image-repeat",
1717                                           GTK_TYPE_CSS_BORDER_IMAGE_REPEAT,
1718                                           0,
1719                                           border_image_repeat_parse,
1720                                           NULL,
1721                                           NULL,
1722                                           query_simple,
1723                                           NULL,
1724                                           _gtk_css_value_new_from_border_image_repeat (&border_image_repeat));
1725
1726   /* XXX: The initial value is wrong, it should be 100% */
1727   gtk_css_style_property_register        ("border-image-slice",
1728                                           GTK_TYPE_BORDER,
1729                                           0,
1730                                           border_image_slice_parse,
1731                                           NULL,
1732                                           NULL,
1733                                           query_simple,
1734                                           NULL,
1735                                           _gtk_css_value_new_from_boxed (GTK_TYPE_BORDER, &border_of_ones));
1736   gtk_css_style_property_register        ("border-image-width",
1737                                           GTK_TYPE_BORDER,
1738                                           0,
1739                                           border_image_width_parse,
1740                                           NULL,
1741                                           NULL,
1742                                           query_simple,
1743                                           NULL,
1744                                           _gtk_css_value_new_from_boxed (GTK_TYPE_BORDER, NULL));
1745   gtk_css_style_property_register        ("engine",
1746                                           GTK_TYPE_THEMING_ENGINE,
1747                                           0,
1748                                           engine_parse,
1749                                           NULL,
1750                                           NULL,
1751                                           query_simple,
1752                                           NULL,
1753                                           _gtk_css_value_new_from_theming_engine (gtk_theming_engine_load (NULL)));
1754   gtk_css_style_property_register        ("transition",
1755                                           GTK_TYPE_ANIMATION_DESCRIPTION,
1756                                           0,
1757                                           transition_parse,
1758                                           NULL,
1759                                           NULL,
1760                                           query_simple,
1761                                           NULL,
1762                                           _gtk_css_value_new_from_boxed (GTK_TYPE_ANIMATION_DESCRIPTION, NULL));
1763
1764   /* Private property holding the binding sets */
1765   gtk_css_style_property_register        ("gtk-key-bindings",
1766                                           G_TYPE_PTR_ARRAY,
1767                                           0,
1768                                           bindings_value_parse,
1769                                           bindings_value_print,
1770                                           NULL,
1771                                           query_simple,
1772                                           NULL,
1773                                           _gtk_css_value_new_take_binding_sets (NULL));
1774 }
1775