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_side (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_set_int (&values[0], width);
274 else if (!G_IS_VALUE (&values[1]) &&
275 _gtk_css_parser_try_enum (parser, GTK_TYPE_BORDER_STYLE, &style))
277 g_value_init (&values[1], GTK_TYPE_BORDER_STYLE);
278 g_value_set_enum (&values[1], style);
280 else if (!G_IS_VALUE (&values[2]))
282 GtkSymbolicColor *symbolic;
284 symbolic = _gtk_css_parser_read_symbolic_color (parser);
285 if (symbolic == NULL)
288 g_value_init (&values[2], GTK_TYPE_SYMBOLIC_COLOR);
289 g_value_take_boxed (&values[2], symbolic);
293 /* We parsed everything and there's still stuff left?
294 * Pretend we didn't notice and let the normal code produce
295 * a 'junk at end of value' error */
299 while (!value_is_done_parsing (parser));
305 parse_border (GtkCssShorthandProperty *shorthand,
307 GtkCssParser *parser,
315 if (!G_IS_VALUE (&values[0]) &&
316 _gtk_css_parser_try_length (parser, &width))
318 g_value_init (&values[0], G_TYPE_INT);
319 g_value_init (&values[1], G_TYPE_INT);
320 g_value_init (&values[2], G_TYPE_INT);
321 g_value_init (&values[3], G_TYPE_INT);
322 g_value_set_int (&values[0], width);
323 g_value_set_int (&values[1], width);
324 g_value_set_int (&values[2], width);
325 g_value_set_int (&values[3], width);
327 else if (!G_IS_VALUE (&values[4]) &&
328 _gtk_css_parser_try_enum (parser, GTK_TYPE_BORDER_STYLE, &style))
330 g_value_init (&values[4], GTK_TYPE_BORDER_STYLE);
331 g_value_init (&values[5], GTK_TYPE_BORDER_STYLE);
332 g_value_init (&values[6], GTK_TYPE_BORDER_STYLE);
333 g_value_init (&values[7], GTK_TYPE_BORDER_STYLE);
334 g_value_set_enum (&values[4], style);
335 g_value_set_enum (&values[5], style);
336 g_value_set_enum (&values[6], style);
337 g_value_set_enum (&values[7], style);
339 else if (!G_IS_VALUE (&values[8]))
341 GtkSymbolicColor *symbolic;
343 symbolic = _gtk_css_parser_read_symbolic_color (parser);
344 if (symbolic == NULL)
347 g_value_init (&values[8], GTK_TYPE_SYMBOLIC_COLOR);
348 g_value_init (&values[9], GTK_TYPE_SYMBOLIC_COLOR);
349 g_value_init (&values[10], GTK_TYPE_SYMBOLIC_COLOR);
350 g_value_init (&values[11], GTK_TYPE_SYMBOLIC_COLOR);
351 g_value_set_boxed (&values[8], symbolic);
352 g_value_set_boxed (&values[9], symbolic);
353 g_value_set_boxed (&values[10], symbolic);
354 g_value_take_boxed (&values[11], symbolic);
358 /* We parsed everything and there's still stuff left?
359 * Pretend we didn't notice and let the normal code produce
360 * a 'junk at end of value' error */
364 while (!value_is_done_parsing (parser));
366 /* Note that border-image values are not set: according to the spec
367 they just need to be reset when using the border shorthand */
373 parse_font (GtkCssShorthandProperty *shorthand,
375 GtkCssParser *parser,
378 PangoFontDescription *desc;
382 str = _gtk_css_parser_read_value (parser);
386 desc = pango_font_description_from_string (str);
389 mask = pango_font_description_get_set_fields (desc);
391 if (mask & PANGO_FONT_MASK_FAMILY)
393 GPtrArray *strv = g_ptr_array_new ();
395 g_ptr_array_add (strv, g_strdup (pango_font_description_get_family (desc)));
396 g_ptr_array_add (strv, NULL);
397 g_value_init (&values[0], G_TYPE_STRV);
398 g_value_take_boxed (&values[0], g_ptr_array_free (strv, FALSE));
400 if (mask & PANGO_FONT_MASK_STYLE)
402 g_value_init (&values[1], PANGO_TYPE_STYLE);
403 g_value_set_enum (&values[1], pango_font_description_get_style (desc));
405 if (mask & PANGO_FONT_MASK_VARIANT)
407 g_value_init (&values[2], PANGO_TYPE_VARIANT);
408 g_value_set_enum (&values[2], pango_font_description_get_variant (desc));
410 if (mask & PANGO_FONT_MASK_WEIGHT)
412 g_value_init (&values[3], PANGO_TYPE_WEIGHT);
413 g_value_set_enum (&values[3], pango_font_description_get_weight (desc));
415 if (mask & PANGO_FONT_MASK_SIZE)
417 g_value_init (&values[4], G_TYPE_DOUBLE);
418 g_value_set_double (&values[4],
419 (double) pango_font_description_get_size (desc) / PANGO_SCALE);
422 pango_font_description_free (desc);
428 parse_background (GtkCssShorthandProperty *shorthand,
430 GtkCssParser *parser,
438 if (!G_IS_VALUE (&values[0]) &&
439 (_gtk_css_parser_has_prefix (parser, "none") ||
440 _gtk_css_image_can_parse (parser)))
444 if (_gtk_css_parser_try (parser, "none", TRUE))
448 image = _gtk_css_image_new_parse (parser, base);
453 g_value_init (&values[0], GTK_TYPE_CSS_IMAGE);
454 g_value_take_object (&values[0], image);
456 else if (!G_IS_VALUE (&values[1]) &&
457 _gtk_css_parser_try_enum (parser, GTK_TYPE_CSS_BACKGROUND_REPEAT, &enum_value))
459 if (enum_value <= GTK_CSS_BACKGROUND_REPEAT_MASK)
463 if (_gtk_css_parser_try_enum (parser, GTK_TYPE_CSS_BACKGROUND_REPEAT, &vertical))
465 if (vertical >= GTK_CSS_BACKGROUND_REPEAT_MASK)
467 _gtk_css_parser_error (parser, "Not a valid 2nd value for border-repeat");
471 enum_value |= vertical << GTK_CSS_BACKGROUND_REPEAT_SHIFT;
474 enum_value |= enum_value << GTK_CSS_BACKGROUND_REPEAT_SHIFT;
477 g_value_init (&values[1], GTK_TYPE_CSS_BACKGROUND_REPEAT);
478 g_value_set_enum (&values[1], enum_value);
480 else if ((!G_IS_VALUE (&values[2]) || !G_IS_VALUE (&values[3])) &&
481 _gtk_css_parser_try_enum (parser, GTK_TYPE_CSS_AREA, &enum_value))
483 guint idx = !G_IS_VALUE (&values[2]) ? 2 : 3;
484 g_value_init (&values[idx], GTK_TYPE_CSS_AREA);
485 g_value_set_enum (&values[idx], enum_value);
487 else if (!G_IS_VALUE (&values[4]))
489 GtkSymbolicColor *symbolic;
491 symbolic = _gtk_css_parser_read_symbolic_color (parser);
492 if (symbolic == NULL)
495 g_value_init (&values[4], GTK_TYPE_SYMBOLIC_COLOR);
496 g_value_take_boxed (&values[4], symbolic);
500 /* We parsed everything and there's still stuff left?
501 * Pretend we didn't notice and let the normal code produce
502 * a 'junk at end of value' error */
506 while (!value_is_done_parsing (parser));
514 unpack_border (const GValue *value,
521 GParameter *parameter = g_new0 (GParameter, 4);
522 GtkBorder *border = g_value_get_boxed (value);
524 parameter[0].name = top;
525 g_value_init (¶meter[0].value, G_TYPE_INT);
526 g_value_set_int (¶meter[0].value, border->top);
527 parameter[1].name = left;
528 g_value_init (¶meter[1].value, G_TYPE_INT);
529 g_value_set_int (¶meter[1].value, border->left);
530 parameter[2].name = bottom;
531 g_value_init (¶meter[2].value, G_TYPE_INT);
532 g_value_set_int (¶meter[2].value, border->bottom);
533 parameter[3].name = right;
534 g_value_init (¶meter[3].value, G_TYPE_INT);
535 g_value_set_int (¶meter[3].value, border->right);
542 pack_border (GValue *value,
543 GtkStyleProperties *props,
553 gtk_style_properties_get (props,
566 g_value_set_boxed (value, &border);
570 unpack_border_width (const GValue *value,
573 return unpack_border (value, n_params,
574 "border-top-width", "border-left-width",
575 "border-bottom-width", "border-right-width");
579 pack_border_width (GValue *value,
580 GtkStyleProperties *props,
583 pack_border (value, props, state,
584 "border-top-width", "border-left-width",
585 "border-bottom-width", "border-right-width");
589 unpack_padding (const GValue *value,
592 return unpack_border (value, n_params,
593 "padding-top", "padding-left",
594 "padding-bottom", "padding-right");
598 pack_padding (GValue *value,
599 GtkStyleProperties *props,
602 pack_border (value, props, state,
603 "padding-top", "padding-left",
604 "padding-bottom", "padding-right");
608 unpack_margin (const GValue *value,
611 return unpack_border (value, n_params,
612 "margin-top", "margin-left",
613 "margin-bottom", "margin-right");
617 pack_margin (GValue *value,
618 GtkStyleProperties *props,
621 pack_border (value, props, state,
622 "margin-top", "margin-left",
623 "margin-bottom", "margin-right");
627 unpack_border_radius (const GValue *value,
630 GParameter *parameter = g_new0 (GParameter, 4);
631 GtkCssBorderCornerRadius border;
633 border.horizontal = border.vertical = g_value_get_int (value);
635 parameter[0].name = "border-top-left-radius";
636 g_value_init (¶meter[0].value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
637 g_value_set_boxed (¶meter[0].value, &border);
638 parameter[1].name = "border-top-right-radius";
639 g_value_init (¶meter[1].value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
640 g_value_set_boxed (¶meter[1].value, &border);
641 parameter[2].name = "border-bottom-right-radius";
642 g_value_init (¶meter[2].value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
643 g_value_set_boxed (¶meter[2].value, &border);
644 parameter[3].name = "border-bottom-left-radius";
645 g_value_init (¶meter[3].value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
646 g_value_set_boxed (¶meter[3].value, &border);
653 pack_border_radius (GValue *value,
654 GtkStyleProperties *props,
657 GtkCssBorderCornerRadius *top_left;
659 /* NB: We are an int property, so we have to resolve to an int here.
660 * So we just resolve to an int. We pick one and stick to it.
661 * Lesson learned: Don't query border-radius shorthand, query the
662 * real properties instead. */
663 gtk_style_properties_get (props,
665 "border-top-left-radius", &top_left,
669 g_value_set_int (value, top_left->horizontal);
675 unpack_font_description (const GValue *value,
678 GParameter *parameter = g_new0 (GParameter, 5);
679 PangoFontDescription *description;
683 /* For backwards compat, we only unpack values that are indeed set.
684 * For strict CSS conformance we need to unpack all of them.
685 * Note that we do set all of them in the parse function, so it
686 * will not have effects when parsing CSS files. It will though
687 * for custom style providers.
690 description = g_value_get_boxed (value);
694 mask = pango_font_description_get_set_fields (description);
698 if (mask & PANGO_FONT_MASK_FAMILY)
700 GPtrArray *strv = g_ptr_array_new ();
702 g_ptr_array_add (strv, g_strdup (pango_font_description_get_family (description)));
703 g_ptr_array_add (strv, NULL);
704 parameter[n].name = "font-family";
705 g_value_init (¶meter[n].value, G_TYPE_STRV);
706 g_value_take_boxed (¶meter[n].value,
707 g_ptr_array_free (strv, FALSE));
711 if (mask & PANGO_FONT_MASK_STYLE)
713 parameter[n].name = "font-style";
714 g_value_init (¶meter[n].value, PANGO_TYPE_STYLE);
715 g_value_set_enum (¶meter[n].value,
716 pango_font_description_get_style (description));
720 if (mask & PANGO_FONT_MASK_VARIANT)
722 parameter[n].name = "font-variant";
723 g_value_init (¶meter[n].value, PANGO_TYPE_VARIANT);
724 g_value_set_enum (¶meter[n].value,
725 pango_font_description_get_variant (description));
729 if (mask & PANGO_FONT_MASK_WEIGHT)
731 parameter[n].name = "font-weight";
732 g_value_init (¶meter[n].value, PANGO_TYPE_WEIGHT);
733 g_value_set_enum (¶meter[n].value,
734 pango_font_description_get_weight (description));
738 if (mask & PANGO_FONT_MASK_SIZE)
740 parameter[n].name = "font-size";
741 g_value_init (¶meter[n].value, G_TYPE_DOUBLE);
742 g_value_set_double (¶meter[n].value,
743 (double) pango_font_description_get_size (description) / PANGO_SCALE);
753 pack_font_description (GValue *value,
754 GtkStyleProperties *props,
757 PangoFontDescription *description;
760 PangoVariant variant;
764 gtk_style_properties_get (props,
766 "font-family", &families,
767 "font-style", &style,
768 "font-variant", &variant,
769 "font-weight", &weight,
773 description = pango_font_description_new ();
774 /* xxx: Can we set all the families here somehow? */
776 pango_font_description_set_family (description, families[0]);
777 pango_font_description_set_size (description, round (size * PANGO_SCALE));
778 pango_font_description_set_style (description, style);
779 pango_font_description_set_variant (description, variant);
780 pango_font_description_set_weight (description, weight);
782 g_strfreev (families);
784 g_value_take_boxed (value, description);
788 unpack_border_color (const GValue *value,
791 GParameter *parameter = g_new0 (GParameter, 4);
794 type = G_VALUE_TYPE (value);
795 if (type == G_TYPE_PTR_ARRAY)
796 type = GTK_TYPE_SYMBOLIC_COLOR;
798 parameter[0].name = "border-top-color";
799 g_value_init (¶meter[0].value, type);
800 parameter[1].name = "border-right-color";
801 g_value_init (¶meter[1].value, type);
802 parameter[2].name = "border-bottom-color";
803 g_value_init (¶meter[2].value, type);
804 parameter[3].name = "border-left-color";
805 g_value_init (¶meter[3].value, type);
807 if (G_VALUE_TYPE (value) == G_TYPE_PTR_ARRAY)
809 GPtrArray *array = g_value_get_boxed (value);
812 for (i = 0; i < 4; i++)
813 g_value_set_boxed (¶meter[i].value, g_ptr_array_index (array, i));
817 /* can be RGBA or symbolic color */
818 gpointer p = g_value_get_boxed (value);
820 g_value_set_boxed (¶meter[0].value, p);
821 g_value_set_boxed (¶meter[1].value, p);
822 g_value_set_boxed (¶meter[2].value, p);
823 g_value_set_boxed (¶meter[3].value, p);
831 pack_border_color (GValue *value,
832 GtkStyleProperties *props,
835 /* NB: We are a color property, so we have to resolve to a color here.
836 * So we just resolve to a color. We pick one and stick to it.
837 * Lesson learned: Don't query border-color shorthand, query the
838 * real properties instead. */
839 g_value_unset (value);
840 gtk_style_properties_get_property (props, "border-top-color", state, value);
844 unpack_border_style (const GValue *value,
847 GParameter *parameter = g_new0 (GParameter, 4);
848 GtkBorderStyle style;
850 style = g_value_get_enum (value);
852 parameter[0].name = "border-top-style";
853 g_value_init (¶meter[0].value, GTK_TYPE_BORDER_STYLE);
854 g_value_set_enum (¶meter[0].value, style);
855 parameter[1].name = "border-right-style";
856 g_value_init (¶meter[1].value, GTK_TYPE_BORDER_STYLE);
857 g_value_set_enum (¶meter[1].value, style);
858 parameter[2].name = "border-bottom-style";
859 g_value_init (¶meter[2].value, GTK_TYPE_BORDER_STYLE);
860 g_value_set_enum (¶meter[2].value, style);
861 parameter[3].name = "border-left-style";
862 g_value_init (¶meter[3].value, GTK_TYPE_BORDER_STYLE);
863 g_value_set_enum (¶meter[3].value, style);
870 pack_border_style (GValue *value,
871 GtkStyleProperties *props,
874 /* NB: We can just resolve to a style. We pick one and stick to it.
875 * Lesson learned: Don't query border-style shorthand, query the
876 * real properties instead. */
877 g_value_unset (value);
878 gtk_style_properties_get_property (props, "border-top-style", state, value);
882 _gtk_css_shorthand_property_register (const char *name,
884 const char **subproperties,
885 GtkCssShorthandPropertyParseFunc parse_func,
886 GtkStyleUnpackFunc unpack_func,
887 GtkStylePackFunc pack_func)
889 GtkStyleProperty *node;
891 node = g_object_new (GTK_TYPE_CSS_SHORTHAND_PROPERTY,
893 "value-type", value_type,
894 "subproperties", subproperties,
897 GTK_CSS_SHORTHAND_PROPERTY (node)->parse = parse_func;
898 node->pack_func = pack_func;
899 node->unpack_func = unpack_func;
903 _gtk_css_shorthand_property_init_properties (void)
905 /* The order is important here, be careful when changing it */
906 const char *font_subproperties[] = { "font-family", "font-style", "font-variant", "font-weight", "font-size", NULL };
907 const char *margin_subproperties[] = { "margin-top", "margin-right", "margin-bottom", "margin-left", NULL };
908 const char *padding_subproperties[] = { "padding-top", "padding-right", "padding-bottom", "padding-left", NULL };
909 const char *border_width_subproperties[] = { "border-top-width", "border-right-width", "border-bottom-width", "border-left-width", NULL };
910 const char *border_radius_subproperties[] = { "border-top-left-radius", "border-top-right-radius",
911 "border-bottom-right-radius", "border-bottom-left-radius", NULL };
912 const char *border_color_subproperties[] = { "border-top-color", "border-right-color", "border-bottom-color", "border-left-color", NULL };
913 const char *border_style_subproperties[] = { "border-top-style", "border-right-style", "border-bottom-style", "border-left-style", NULL };
914 const char *border_image_subproperties[] = { "border-image-source", "border-image-slice", "border-image-width", "border-image-repeat", NULL };
915 const char *border_top_subproperties[] = { "border-top-width", "border-top-style", "border-top-color", NULL };
916 const char *border_right_subproperties[] = { "border-right-width", "border-right-style", "border-right-color", NULL };
917 const char *border_bottom_subproperties[] = { "border-bottom-width", "border-bottom-style", "border-bottom-color", NULL };
918 const char *border_left_subproperties[] = { "border-left-width", "border-left-style", "border-left-color", NULL };
919 const char *border_subproperties[] = { "border-top-width", "border-right-width", "border-bottom-width", "border-left-width",
920 "border-top-style", "border-right-style", "border-bottom-style", "border-left-style",
921 "border-top-color", "border-right-color", "border-bottom-color", "border-left-color",
922 "border-image-source", "border-image-slice", "border-image-width", "border-image-repeat", NULL };
923 const char *background_subproperties[] = { "background-image", "background-repeat", "background-clip", "background-origin",
924 "background-color", NULL };
926 _gtk_css_shorthand_property_register ("font",
927 PANGO_TYPE_FONT_DESCRIPTION,
930 unpack_font_description,
931 pack_font_description);
932 _gtk_css_shorthand_property_register ("margin",
934 margin_subproperties,
938 _gtk_css_shorthand_property_register ("padding",
940 padding_subproperties,
944 _gtk_css_shorthand_property_register ("border-width",
946 border_width_subproperties,
950 _gtk_css_shorthand_property_register ("border-radius",
952 border_radius_subproperties,
954 unpack_border_radius,
956 _gtk_css_shorthand_property_register ("border-color",
958 border_color_subproperties,
962 _gtk_css_shorthand_property_register ("border-style",
963 GTK_TYPE_BORDER_STYLE,
964 border_style_subproperties,
968 _gtk_css_shorthand_property_register ("border-image",
970 border_image_subproperties,
974 _gtk_css_shorthand_property_register ("border-top",
976 border_top_subproperties,
980 _gtk_css_shorthand_property_register ("border-right",
982 border_right_subproperties,
986 _gtk_css_shorthand_property_register ("border-bottom",
988 border_bottom_subproperties,
992 _gtk_css_shorthand_property_register ("border-left",
994 border_left_subproperties,
998 _gtk_css_shorthand_property_register ("border",
1000 border_subproperties,
1004 _gtk_css_shorthand_property_register ("background",
1006 background_subproperties,