2 * Copyright © 2011 Red Hat Inc.
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.1 of the License, or (at your option) any later version.
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.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 * Authors: Benjamin Otte <otte@gnome.org>
23 #include "gtkcssshorthandpropertyprivate.h"
25 #include <cairo-gobject.h>
28 #include "gtkcssimageprivate.h"
29 #include "gtkcssstylefuncsprivate.h"
30 #include "gtkcsstypesprivate.h"
31 #include "gtkprivatetypebuiltins.h"
32 #include "gtktypebuiltins.h"
34 /* this is in case round() is not provided by the compiler,
35 * such as in the case of C89 compilers, like MSVC
37 #include "fallback-c89.c"
42 value_is_done_parsing (GtkCssParser *parser)
44 return _gtk_css_parser_is_eof (parser) ||
45 _gtk_css_parser_begins_with (parser, ';') ||
46 _gtk_css_parser_begins_with (parser, '}');
50 parse_border_width (GtkCssShorthandProperty *shorthand,
55 GValue temp = G_VALUE_INIT;
58 g_value_init (&temp, GTK_TYPE_BORDER);
59 if (!_gtk_css_style_parse_value (&temp, parser, base))
61 g_value_unset (&temp);
65 border = g_value_get_boxed (&temp);
67 g_value_init (&values[0], G_TYPE_INT);
68 g_value_init (&values[1], G_TYPE_INT);
69 g_value_init (&values[2], G_TYPE_INT);
70 g_value_init (&values[3], G_TYPE_INT);
71 g_value_set_int (&values[0], border->top);
72 g_value_set_int (&values[1], border->right);
73 g_value_set_int (&values[2], border->bottom);
74 g_value_set_int (&values[3], border->left);
76 g_value_unset (&temp);
82 parse_border_radius (GtkCssShorthandProperty *shorthand,
87 GtkCssBorderCornerRadius borders[4];
90 for (i = 0; i < G_N_ELEMENTS (borders); i++)
92 if (!_gtk_css_parser_try_double (parser, &borders[i].horizontal))
94 if (borders[i].horizontal < 0)
96 _gtk_css_parser_error (parser, "Border radius values cannot be negative");
103 _gtk_css_parser_error (parser, "Expected a number");
107 /* The magic (i - 1) >> 1 below makes it take the correct value
108 * according to spec. Feel free to check the 4 cases */
109 for (; i < G_N_ELEMENTS (borders); i++)
110 borders[i].horizontal = borders[(i - 1) >> 1].horizontal;
112 if (_gtk_css_parser_try (parser, "/", TRUE))
114 for (i = 0; i < G_N_ELEMENTS (borders); i++)
116 if (!_gtk_css_parser_try_double (parser, &borders[i].vertical))
118 if (borders[i].vertical < 0)
120 _gtk_css_parser_error (parser, "Border radius values cannot be negative");
127 _gtk_css_parser_error (parser, "Expected a number");
131 for (; i < G_N_ELEMENTS (borders); i++)
132 borders[i].vertical = borders[(i - 1) >> 1].vertical;
137 for (i = 0; i < G_N_ELEMENTS (borders); i++)
138 borders[i].vertical = borders[i].horizontal;
141 for (i = 0; i < G_N_ELEMENTS (borders); i++)
143 g_value_init (&values[i], GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
144 g_value_set_boxed (&values[i], &borders[i]);
151 parse_border_color (GtkCssShorthandProperty *shorthand,
153 GtkCssParser *parser,
156 GtkSymbolicColor *symbolic;
159 for (i = 0; i < 4; i++)
161 symbolic = _gtk_css_parser_read_symbolic_color (parser);
162 if (symbolic == NULL)
165 g_value_init (&values[i], GTK_TYPE_SYMBOLIC_COLOR);
166 g_value_set_boxed (&values[i], symbolic);
168 if (value_is_done_parsing (parser))
172 for (i++; i < 4; i++)
174 g_value_init (&values[i], GTK_TYPE_SYMBOLIC_COLOR);
175 g_value_copy (&values[(i - 1) >> 1], &values[i]);
182 parse_border_style (GtkCssShorthandProperty *shorthand,
184 GtkCssParser *parser,
187 GtkBorderStyle styles[4];
190 for (i = 0; i < 4; i++)
192 if (!_gtk_css_parser_try_enum (parser, GTK_TYPE_BORDER_STYLE, (int *)&styles[i]))
198 _gtk_css_parser_error (parser, "Expected a border style");
202 for (; i < G_N_ELEMENTS (styles); i++)
203 styles[i] = styles[(i - 1) >> 1];
205 for (i = 0; i < G_N_ELEMENTS (styles); i++)
207 g_value_init (&values[i], GTK_TYPE_BORDER_STYLE);
208 g_value_set_enum (&values[i], styles[i]);
215 parse_border_image (GtkCssShorthandProperty *shorthand,
217 GtkCssParser *parser,
222 if (_gtk_css_parser_try (parser, "none", TRUE))
226 image = _gtk_css_image_new_parse (parser, base);
230 g_value_init (&values[0], GTK_TYPE_CSS_IMAGE);
231 g_value_set_object (&values[0], image);
233 if (value_is_done_parsing (parser))
236 g_value_init (&values[1], GTK_TYPE_BORDER);
237 if (!_gtk_css_style_parse_value (&values[1], parser, base))
240 if (_gtk_css_parser_try (parser, "/", TRUE))
242 g_value_init (&values[2], GTK_TYPE_BORDER);
243 if (!_gtk_css_style_parse_value (&values[2], parser, base))
247 if (value_is_done_parsing (parser))
250 g_value_init (&values[3], GTK_TYPE_CSS_BORDER_IMAGE_REPEAT);
251 if (!_gtk_css_style_parse_value (&values[3], parser, base))
258 parse_border (GtkCssShorthandProperty *shorthand,
260 GtkCssParser *parser,
268 if (!G_IS_VALUE (&values[0]) &&
269 _gtk_css_parser_try_length (parser, &width))
271 g_value_init (&values[0], G_TYPE_INT);
272 g_value_init (&values[1], G_TYPE_INT);
273 g_value_init (&values[2], G_TYPE_INT);
274 g_value_init (&values[3], G_TYPE_INT);
275 g_value_set_int (&values[0], width);
276 g_value_set_int (&values[1], width);
277 g_value_set_int (&values[2], width);
278 g_value_set_int (&values[3], width);
280 else if (!G_IS_VALUE (&values[4]) &&
281 _gtk_css_parser_try_enum (parser, GTK_TYPE_BORDER_STYLE, &style))
283 g_value_init (&values[4], GTK_TYPE_BORDER_STYLE);
284 g_value_init (&values[5], GTK_TYPE_BORDER_STYLE);
285 g_value_init (&values[6], GTK_TYPE_BORDER_STYLE);
286 g_value_init (&values[7], GTK_TYPE_BORDER_STYLE);
287 g_value_set_enum (&values[4], style);
288 g_value_set_enum (&values[5], style);
289 g_value_set_enum (&values[6], style);
290 g_value_set_enum (&values[7], style);
292 else if (!G_IS_VALUE (&values[8]))
294 GtkSymbolicColor *symbolic;
296 symbolic = _gtk_css_parser_read_symbolic_color (parser);
297 if (symbolic == NULL)
300 g_value_init (&values[8], GTK_TYPE_SYMBOLIC_COLOR);
301 g_value_init (&values[9], GTK_TYPE_SYMBOLIC_COLOR);
302 g_value_init (&values[10], GTK_TYPE_SYMBOLIC_COLOR);
303 g_value_init (&values[11], GTK_TYPE_SYMBOLIC_COLOR);
304 g_value_set_boxed (&values[8], symbolic);
305 g_value_set_boxed (&values[9], symbolic);
306 g_value_set_boxed (&values[10], symbolic);
307 g_value_take_boxed (&values[11], symbolic);
311 /* We parsed everything and there's still stuff left?
312 * Pretend we didn't notice and let the normal code produce
313 * a 'junk at end of value' error */
317 while (!value_is_done_parsing (parser));
319 /* Note that border-image values are not set: according to the spec
320 they just need to be reset when using the border shorthand */
326 parse_font (GtkCssShorthandProperty *shorthand,
328 GtkCssParser *parser,
331 PangoFontDescription *desc;
335 str = _gtk_css_parser_read_value (parser);
339 desc = pango_font_description_from_string (str);
342 mask = pango_font_description_get_set_fields (desc);
344 if (mask & PANGO_FONT_MASK_FAMILY)
346 GPtrArray *strv = g_ptr_array_new ();
348 g_ptr_array_add (strv, g_strdup (pango_font_description_get_family (desc)));
349 g_ptr_array_add (strv, NULL);
350 g_value_init (&values[0], G_TYPE_STRV);
351 g_value_take_boxed (&values[0], g_ptr_array_free (strv, FALSE));
353 if (mask & PANGO_FONT_MASK_STYLE)
355 g_value_init (&values[1], PANGO_TYPE_STYLE);
356 g_value_set_enum (&values[1], pango_font_description_get_style (desc));
358 if (mask & PANGO_FONT_MASK_VARIANT)
360 g_value_init (&values[2], PANGO_TYPE_VARIANT);
361 g_value_set_enum (&values[2], pango_font_description_get_variant (desc));
363 if (mask & PANGO_FONT_MASK_WEIGHT)
365 g_value_init (&values[3], PANGO_TYPE_WEIGHT);
366 g_value_set_enum (&values[3], pango_font_description_get_weight (desc));
368 if (mask & PANGO_FONT_MASK_SIZE)
370 g_value_init (&values[4], G_TYPE_DOUBLE);
371 g_value_set_double (&values[4],
372 (double) pango_font_description_get_size (desc) / PANGO_SCALE);
375 pango_font_description_free (desc);
381 parse_background (GtkCssShorthandProperty *shorthand,
383 GtkCssParser *parser,
391 if (!G_IS_VALUE (&values[0]) &&
392 (_gtk_css_parser_has_prefix (parser, "none") ||
393 _gtk_css_image_can_parse (parser)))
397 if (_gtk_css_parser_try (parser, "none", TRUE))
401 image = _gtk_css_image_new_parse (parser, base);
406 g_value_init (&values[0], GTK_TYPE_CSS_IMAGE);
407 g_value_take_object (&values[0], image);
409 else if (!G_IS_VALUE (&values[1]) &&
410 _gtk_css_parser_try_enum (parser, GTK_TYPE_CSS_BACKGROUND_REPEAT, &enum_value))
412 if (enum_value <= GTK_CSS_BACKGROUND_REPEAT_MASK)
416 if (_gtk_css_parser_try_enum (parser, GTK_TYPE_CSS_BACKGROUND_REPEAT, &vertical))
418 if (vertical >= GTK_CSS_BACKGROUND_REPEAT_MASK)
420 _gtk_css_parser_error (parser, "Not a valid 2nd value for border-repeat");
424 enum_value |= vertical << GTK_CSS_BACKGROUND_REPEAT_SHIFT;
427 enum_value |= enum_value << GTK_CSS_BACKGROUND_REPEAT_SHIFT;
430 g_value_init (&values[1], GTK_TYPE_CSS_BACKGROUND_REPEAT);
431 g_value_set_enum (&values[1], enum_value);
433 else if ((!G_IS_VALUE (&values[2]) || !G_IS_VALUE (&values[3])) &&
434 _gtk_css_parser_try_enum (parser, GTK_TYPE_CSS_AREA, &enum_value))
436 guint idx = !G_IS_VALUE (&values[2]) ? 2 : 3;
437 g_value_init (&values[idx], GTK_TYPE_CSS_AREA);
438 g_value_set_enum (&values[idx], enum_value);
440 else if (!G_IS_VALUE (&values[4]))
442 GtkSymbolicColor *symbolic;
444 symbolic = _gtk_css_parser_read_symbolic_color (parser);
445 if (symbolic == NULL)
448 g_value_init (&values[4], GTK_TYPE_SYMBOLIC_COLOR);
449 g_value_take_boxed (&values[4], symbolic);
453 /* We parsed everything and there's still stuff left?
454 * Pretend we didn't notice and let the normal code produce
455 * a 'junk at end of value' error */
459 while (!value_is_done_parsing (parser));
467 unpack_border (const GValue *value,
474 GParameter *parameter = g_new0 (GParameter, 4);
475 GtkBorder *border = g_value_get_boxed (value);
477 parameter[0].name = top;
478 g_value_init (¶meter[0].value, G_TYPE_INT);
479 g_value_set_int (¶meter[0].value, border->top);
480 parameter[1].name = left;
481 g_value_init (¶meter[1].value, G_TYPE_INT);
482 g_value_set_int (¶meter[1].value, border->left);
483 parameter[2].name = bottom;
484 g_value_init (¶meter[2].value, G_TYPE_INT);
485 g_value_set_int (¶meter[2].value, border->bottom);
486 parameter[3].name = right;
487 g_value_init (¶meter[3].value, G_TYPE_INT);
488 g_value_set_int (¶meter[3].value, border->right);
495 pack_border (GValue *value,
496 GtkStyleProperties *props,
506 gtk_style_properties_get (props,
519 g_value_set_boxed (value, &border);
523 unpack_border_width (const GValue *value,
526 return unpack_border (value, n_params,
527 "border-top-width", "border-left-width",
528 "border-bottom-width", "border-right-width");
532 pack_border_width (GValue *value,
533 GtkStyleProperties *props,
536 pack_border (value, props, state,
537 "border-top-width", "border-left-width",
538 "border-bottom-width", "border-right-width");
542 unpack_padding (const GValue *value,
545 return unpack_border (value, n_params,
546 "padding-top", "padding-left",
547 "padding-bottom", "padding-right");
551 pack_padding (GValue *value,
552 GtkStyleProperties *props,
555 pack_border (value, props, state,
556 "padding-top", "padding-left",
557 "padding-bottom", "padding-right");
561 unpack_margin (const GValue *value,
564 return unpack_border (value, n_params,
565 "margin-top", "margin-left",
566 "margin-bottom", "margin-right");
570 pack_margin (GValue *value,
571 GtkStyleProperties *props,
574 pack_border (value, props, state,
575 "margin-top", "margin-left",
576 "margin-bottom", "margin-right");
580 unpack_border_radius (const GValue *value,
583 GParameter *parameter = g_new0 (GParameter, 4);
584 GtkCssBorderCornerRadius border;
586 border.horizontal = border.vertical = g_value_get_int (value);
588 parameter[0].name = "border-top-left-radius";
589 g_value_init (¶meter[0].value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
590 g_value_set_boxed (¶meter[0].value, &border);
591 parameter[1].name = "border-top-right-radius";
592 g_value_init (¶meter[1].value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
593 g_value_set_boxed (¶meter[1].value, &border);
594 parameter[2].name = "border-bottom-right-radius";
595 g_value_init (¶meter[2].value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
596 g_value_set_boxed (¶meter[2].value, &border);
597 parameter[3].name = "border-bottom-left-radius";
598 g_value_init (¶meter[3].value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
599 g_value_set_boxed (¶meter[3].value, &border);
606 pack_border_radius (GValue *value,
607 GtkStyleProperties *props,
610 GtkCssBorderCornerRadius *top_left;
612 /* NB: We are an int property, so we have to resolve to an int here.
613 * So we just resolve to an int. We pick one and stick to it.
614 * Lesson learned: Don't query border-radius shorthand, query the
615 * real properties instead. */
616 gtk_style_properties_get (props,
618 "border-top-left-radius", &top_left,
622 g_value_set_int (value, top_left->horizontal);
628 unpack_font_description (const GValue *value,
631 GParameter *parameter = g_new0 (GParameter, 5);
632 PangoFontDescription *description;
636 /* For backwards compat, we only unpack values that are indeed set.
637 * For strict CSS conformance we need to unpack all of them.
638 * Note that we do set all of them in the parse function, so it
639 * will not have effects when parsing CSS files. It will though
640 * for custom style providers.
643 description = g_value_get_boxed (value);
647 mask = pango_font_description_get_set_fields (description);
651 if (mask & PANGO_FONT_MASK_FAMILY)
653 GPtrArray *strv = g_ptr_array_new ();
655 g_ptr_array_add (strv, g_strdup (pango_font_description_get_family (description)));
656 g_ptr_array_add (strv, NULL);
657 parameter[n].name = "font-family";
658 g_value_init (¶meter[n].value, G_TYPE_STRV);
659 g_value_take_boxed (¶meter[n].value,
660 g_ptr_array_free (strv, FALSE));
664 if (mask & PANGO_FONT_MASK_STYLE)
666 parameter[n].name = "font-style";
667 g_value_init (¶meter[n].value, PANGO_TYPE_STYLE);
668 g_value_set_enum (¶meter[n].value,
669 pango_font_description_get_style (description));
673 if (mask & PANGO_FONT_MASK_VARIANT)
675 parameter[n].name = "font-variant";
676 g_value_init (¶meter[n].value, PANGO_TYPE_VARIANT);
677 g_value_set_enum (¶meter[n].value,
678 pango_font_description_get_variant (description));
682 if (mask & PANGO_FONT_MASK_WEIGHT)
684 parameter[n].name = "font-weight";
685 g_value_init (¶meter[n].value, PANGO_TYPE_WEIGHT);
686 g_value_set_enum (¶meter[n].value,
687 pango_font_description_get_weight (description));
691 if (mask & PANGO_FONT_MASK_SIZE)
693 parameter[n].name = "font-size";
694 g_value_init (¶meter[n].value, G_TYPE_DOUBLE);
695 g_value_set_double (¶meter[n].value,
696 (double) pango_font_description_get_size (description) / PANGO_SCALE);
706 pack_font_description (GValue *value,
707 GtkStyleProperties *props,
710 PangoFontDescription *description;
713 PangoVariant variant;
717 gtk_style_properties_get (props,
719 "font-family", &families,
720 "font-style", &style,
721 "font-variant", &variant,
722 "font-weight", &weight,
726 description = pango_font_description_new ();
727 /* xxx: Can we set all the families here somehow? */
729 pango_font_description_set_family (description, families[0]);
730 pango_font_description_set_size (description, round (size * PANGO_SCALE));
731 pango_font_description_set_style (description, style);
732 pango_font_description_set_variant (description, variant);
733 pango_font_description_set_weight (description, weight);
735 g_strfreev (families);
737 g_value_take_boxed (value, description);
741 unpack_border_color (const GValue *value,
744 GParameter *parameter = g_new0 (GParameter, 4);
747 type = G_VALUE_TYPE (value);
748 if (type == G_TYPE_PTR_ARRAY)
749 type = GTK_TYPE_SYMBOLIC_COLOR;
751 parameter[0].name = "border-top-color";
752 g_value_init (¶meter[0].value, type);
753 parameter[1].name = "border-right-color";
754 g_value_init (¶meter[1].value, type);
755 parameter[2].name = "border-bottom-color";
756 g_value_init (¶meter[2].value, type);
757 parameter[3].name = "border-left-color";
758 g_value_init (¶meter[3].value, type);
760 if (G_VALUE_TYPE (value) == G_TYPE_PTR_ARRAY)
762 GPtrArray *array = g_value_get_boxed (value);
765 for (i = 0; i < 4; i++)
766 g_value_set_boxed (¶meter[i].value, g_ptr_array_index (array, i));
770 /* can be RGBA or symbolic color */
771 gpointer p = g_value_get_boxed (value);
773 g_value_set_boxed (¶meter[0].value, p);
774 g_value_set_boxed (¶meter[1].value, p);
775 g_value_set_boxed (¶meter[2].value, p);
776 g_value_set_boxed (¶meter[3].value, p);
784 pack_border_color (GValue *value,
785 GtkStyleProperties *props,
788 /* NB: We are a color property, so we have to resolve to a color here.
789 * So we just resolve to a color. We pick one and stick to it.
790 * Lesson learned: Don't query border-color shorthand, query the
791 * real properties instead. */
792 g_value_unset (value);
793 gtk_style_properties_get_property (props, "border-top-color", state, value);
797 unpack_border_style (const GValue *value,
800 GParameter *parameter = g_new0 (GParameter, 4);
801 GtkBorderStyle style;
803 style = g_value_get_enum (value);
805 parameter[0].name = "border-top-style";
806 g_value_init (¶meter[0].value, GTK_TYPE_BORDER_STYLE);
807 g_value_set_enum (¶meter[0].value, style);
808 parameter[1].name = "border-right-style";
809 g_value_init (¶meter[1].value, GTK_TYPE_BORDER_STYLE);
810 g_value_set_enum (¶meter[1].value, style);
811 parameter[2].name = "border-bottom-style";
812 g_value_init (¶meter[2].value, GTK_TYPE_BORDER_STYLE);
813 g_value_set_enum (¶meter[2].value, style);
814 parameter[3].name = "border-left-style";
815 g_value_init (¶meter[3].value, GTK_TYPE_BORDER_STYLE);
816 g_value_set_enum (¶meter[3].value, style);
823 pack_border_style (GValue *value,
824 GtkStyleProperties *props,
827 /* NB: We can just resolve to a style. We pick one and stick to it.
828 * Lesson learned: Don't query border-style shorthand, query the
829 * real properties instead. */
830 g_value_unset (value);
831 gtk_style_properties_get_property (props, "border-top-style", state, value);
835 _gtk_css_shorthand_property_register (const char *name,
837 const char **subproperties,
838 GtkCssShorthandPropertyParseFunc parse_func,
839 GtkStyleUnpackFunc unpack_func,
840 GtkStylePackFunc pack_func)
842 GtkStyleProperty *node;
844 node = g_object_new (GTK_TYPE_CSS_SHORTHAND_PROPERTY,
846 "value-type", value_type,
847 "subproperties", subproperties,
850 GTK_CSS_SHORTHAND_PROPERTY (node)->parse = parse_func;
851 node->pack_func = pack_func;
852 node->unpack_func = unpack_func;
856 _gtk_css_shorthand_property_init_properties (void)
858 /* The order is important here, be careful when changing it */
859 const char *font_subproperties[] = { "font-family", "font-style", "font-variant", "font-weight", "font-size", NULL };
860 const char *margin_subproperties[] = { "margin-top", "margin-right", "margin-bottom", "margin-left", NULL };
861 const char *padding_subproperties[] = { "padding-top", "padding-right", "padding-bottom", "padding-left", NULL };
862 const char *border_width_subproperties[] = { "border-top-width", "border-right-width", "border-bottom-width", "border-left-width", NULL };
863 const char *border_radius_subproperties[] = { "border-top-left-radius", "border-top-right-radius",
864 "border-bottom-right-radius", "border-bottom-left-radius", NULL };
865 const char *border_color_subproperties[] = { "border-top-color", "border-right-color", "border-bottom-color", "border-left-color", NULL };
866 const char *border_style_subproperties[] = { "border-top-style", "border-right-style", "border-bottom-style", "border-left-style", NULL };
867 const char *border_image_subproperties[] = { "border-image-source", "border-image-slice", "border-image-width", "border-image-repeat", NULL };
868 const char *border_subproperties[] = { "border-top-width", "border-right-width", "border-bottom-width", "border-left-width",
869 "border-top-style", "border-right-style", "border-bottom-style", "border-left-style",
870 "border-top-color", "border-right-color", "border-bottom-color", "border-left-color",
871 "border-image-source", "border-image-slice", "border-image-width", "border-image-repeat", NULL };
872 const char *background_subproperties[] = { "background-image", "background-repeat", "background-clip", "background-origin",
873 "background-color", NULL };
875 _gtk_css_shorthand_property_register ("font",
876 PANGO_TYPE_FONT_DESCRIPTION,
879 unpack_font_description,
880 pack_font_description);
881 _gtk_css_shorthand_property_register ("margin",
883 margin_subproperties,
887 _gtk_css_shorthand_property_register ("padding",
889 padding_subproperties,
893 _gtk_css_shorthand_property_register ("border-width",
895 border_width_subproperties,
899 _gtk_css_shorthand_property_register ("border-radius",
901 border_radius_subproperties,
903 unpack_border_radius,
905 _gtk_css_shorthand_property_register ("border-color",
907 border_color_subproperties,
911 _gtk_css_shorthand_property_register ("border-style",
912 GTK_TYPE_BORDER_STYLE,
913 border_style_subproperties,
917 _gtk_css_shorthand_property_register ("border-image",
919 border_image_subproperties,
923 _gtk_css_shorthand_property_register ("border",
925 border_subproperties,
929 _gtk_css_shorthand_property_register ("background",
931 background_subproperties,