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, see <http://www.gnu.org/licenses/>.
17 * Authors: Benjamin Otte <otte@gnome.org>
22 #include "gtkcssshorthandpropertyprivate.h"
24 #include <cairo-gobject.h>
27 #include "gtkcssimageprivate.h"
28 #include "gtkcssnumbervalueprivate.h"
29 #include "gtkcssstylefuncsprivate.h"
30 #include "gtkcsstypesprivate.h"
31 #include "gtkcssvalueprivate.h"
32 #include "gtkprivatetypebuiltins.h"
33 #include "gtkstylepropertiesprivate.h"
34 #include "gtksymboliccolorprivate.h"
35 #include "gtktypebuiltins.h"
37 /* this is in case round() is not provided by the compiler,
38 * such as in the case of C89 compilers, like MSVC
40 #include "fallback-c89.c"
45 value_is_done_parsing (GtkCssParser *parser)
47 return _gtk_css_parser_is_eof (parser) ||
48 _gtk_css_parser_begins_with (parser, ';') ||
49 _gtk_css_parser_begins_with (parser, '}');
53 parse_four_numbers (GtkCssShorthandProperty *shorthand,
56 GtkCssNumberParseFlags flags)
60 for (i = 0; i < 4; i++)
62 if (!_gtk_css_parser_has_number (parser))
65 values[i] = _gtk_css_number_value_parse (parser, flags);
66 if (values[i] == NULL)
72 _gtk_css_parser_error (parser, "Expected a length");
78 values[i] = _gtk_css_value_ref (values[(i - 1) >> 1]);
85 parse_margin (GtkCssShorthandProperty *shorthand,
90 return parse_four_numbers (shorthand,
93 GTK_CSS_NUMBER_AS_PIXELS
94 | GTK_CSS_PARSE_LENGTH);
98 parse_padding (GtkCssShorthandProperty *shorthand,
100 GtkCssParser *parser,
103 return parse_four_numbers (shorthand,
106 GTK_CSS_POSITIVE_ONLY
107 | GTK_CSS_NUMBER_AS_PIXELS
108 | GTK_CSS_PARSE_LENGTH);
112 parse_border_width (GtkCssShorthandProperty *shorthand,
113 GtkCssValue **values,
114 GtkCssParser *parser,
117 return parse_four_numbers (shorthand,
120 GTK_CSS_POSITIVE_ONLY
121 | GTK_CSS_NUMBER_AS_PIXELS
122 | GTK_CSS_PARSE_LENGTH);
126 parse_border_radius (GtkCssShorthandProperty *shorthand,
127 GtkCssValue **values,
128 GtkCssParser *parser,
131 GtkCssBorderCornerRadius borders[4];
134 for (i = 0; i < G_N_ELEMENTS (borders); i++)
136 if (!_gtk_css_parser_has_number (parser))
138 if (!_gtk_css_parser_read_number (parser,
139 &borders[i].horizontal,
140 GTK_CSS_POSITIVE_ONLY
141 | GTK_CSS_PARSE_PERCENT
142 | GTK_CSS_NUMBER_AS_PIXELS
143 | GTK_CSS_PARSE_LENGTH))
149 _gtk_css_parser_error (parser, "Expected a number");
153 /* The magic (i - 1) >> 1 below makes it take the correct value
154 * according to spec. Feel free to check the 4 cases */
155 for (; i < G_N_ELEMENTS (borders); i++)
156 borders[i].horizontal = borders[(i - 1) >> 1].horizontal;
158 if (_gtk_css_parser_try (parser, "/", TRUE))
160 for (i = 0; i < G_N_ELEMENTS (borders); i++)
162 if (!_gtk_css_parser_has_number (parser))
164 if (!_gtk_css_parser_read_number (parser,
165 &borders[i].vertical,
166 GTK_CSS_POSITIVE_ONLY
167 | GTK_CSS_PARSE_PERCENT
168 | GTK_CSS_NUMBER_AS_PIXELS
169 | GTK_CSS_PARSE_LENGTH))
175 _gtk_css_parser_error (parser, "Expected a number");
179 for (; i < G_N_ELEMENTS (borders); i++)
180 borders[i].vertical = borders[(i - 1) >> 1].vertical;
185 for (i = 0; i < G_N_ELEMENTS (borders); i++)
186 borders[i].vertical = borders[i].horizontal;
189 for (i = 0; i < G_N_ELEMENTS (borders); i++)
191 values[i] = _gtk_css_value_new_from_border_corner_radius (&borders[i]);
198 parse_border_color (GtkCssShorthandProperty *shorthand,
199 GtkCssValue **values,
200 GtkCssParser *parser,
203 GtkSymbolicColor *symbolic;
206 for (i = 0; i < 4; i++)
208 if (_gtk_css_parser_try (parser, "currentcolor", TRUE))
210 symbolic = gtk_symbolic_color_ref (_gtk_symbolic_color_get_current_color ());
214 symbolic = _gtk_css_parser_read_symbolic_color (parser);
215 if (symbolic == NULL)
219 values[i] = _gtk_css_value_new_take_symbolic_color (symbolic);
221 if (value_is_done_parsing (parser))
225 for (i++; i < 4; i++)
227 values[i] = _gtk_css_value_ref (values[(i - 1) >> 1]);
234 parse_border_style (GtkCssShorthandProperty *shorthand,
235 GtkCssValue **values,
236 GtkCssParser *parser,
239 GtkBorderStyle styles[4];
242 for (i = 0; i < 4; i++)
244 if (!_gtk_css_parser_try_enum (parser, GTK_TYPE_BORDER_STYLE, (int *)&styles[i]))
250 _gtk_css_parser_error (parser, "Expected a border style");
254 for (; i < G_N_ELEMENTS (styles); i++)
255 styles[i] = styles[(i - 1) >> 1];
257 for (i = 0; i < G_N_ELEMENTS (styles); i++)
259 values[i] = _gtk_css_value_new_from_enum (GTK_TYPE_BORDER_STYLE, styles[i]);
266 parse_border_image (GtkCssShorthandProperty *shorthand,
267 GtkCssValue **values,
268 GtkCssParser *parser,
271 GValue value = G_VALUE_INIT;
274 if (_gtk_css_parser_try (parser, "none", TRUE))
278 image = _gtk_css_image_new_parse (parser, base);
282 values[0] = _gtk_css_value_new_take_image (image);
284 if (value_is_done_parsing (parser))
287 g_value_init (&value, GTK_TYPE_BORDER);
288 if (!_gtk_css_style_parse_value (&value, parser, base))
290 values[1] = _gtk_css_value_new_from_gvalue (&value);
291 g_value_unset (&value);
293 if (_gtk_css_parser_try (parser, "/", TRUE))
295 g_value_init (&value, GTK_TYPE_BORDER);
296 if (!_gtk_css_style_parse_value (&value, parser, base))
298 values[2] = _gtk_css_value_new_from_gvalue (&value);
299 g_value_unset (&value);
302 if (value_is_done_parsing (parser))
305 g_value_init (&value, GTK_TYPE_CSS_BORDER_IMAGE_REPEAT);
306 if (!_gtk_css_style_parse_value (&value, parser, base))
308 values[3] = _gtk_css_value_new_from_gvalue (&value);
309 g_value_unset (&value);
315 parse_border_side (GtkCssShorthandProperty *shorthand,
316 GtkCssValue **values,
317 GtkCssParser *parser,
324 if (values[0] == NULL &&
325 _gtk_css_parser_has_number (parser))
327 values[0] = _gtk_css_number_value_parse (parser,
328 GTK_CSS_POSITIVE_ONLY
329 | GTK_CSS_NUMBER_AS_PIXELS
330 | GTK_CSS_PARSE_LENGTH);
331 if (values[0] == NULL)
334 else if (values[1] == NULL &&
335 _gtk_css_parser_try_enum (parser, GTK_TYPE_BORDER_STYLE, &style))
337 values[1] = _gtk_css_value_new_from_enum (GTK_TYPE_BORDER_STYLE, style);
339 else if (values[2] == NULL)
341 GtkSymbolicColor *symbolic;
343 symbolic = _gtk_css_parser_read_symbolic_color (parser);
344 if (symbolic == NULL)
347 values[2] = _gtk_css_value_new_take_symbolic_color (symbolic);
351 /* We parsed everything and there's still stuff left?
352 * Pretend we didn't notice and let the normal code produce
353 * a 'junk at end of value' error */
357 while (!value_is_done_parsing (parser));
363 parse_border (GtkCssShorthandProperty *shorthand,
364 GtkCssValue **values,
365 GtkCssParser *parser,
372 if (values[0] == NULL &&
373 _gtk_css_parser_has_number (parser))
375 values[0] = _gtk_css_number_value_parse (parser,
376 GTK_CSS_POSITIVE_ONLY
377 | GTK_CSS_NUMBER_AS_PIXELS
378 | GTK_CSS_PARSE_LENGTH);
379 if (values[0] == NULL)
381 values[1] = _gtk_css_value_ref (values[0]);
382 values[2] = _gtk_css_value_ref (values[0]);
383 values[3] = _gtk_css_value_ref (values[0]);
385 else if (values[4] == NULL &&
386 _gtk_css_parser_try_enum (parser, GTK_TYPE_BORDER_STYLE, &style))
388 values[4] = _gtk_css_value_new_from_enum (GTK_TYPE_BORDER_STYLE, style);
389 values[5] = _gtk_css_value_ref (values[4]);
390 values[6] = _gtk_css_value_ref (values[4]);
391 values[7] = _gtk_css_value_ref (values[4]);
393 else if (!G_IS_VALUE (&values[8]))
395 GtkSymbolicColor *symbolic;
397 symbolic = _gtk_css_parser_read_symbolic_color (parser);
398 if (symbolic == NULL)
401 values[8] = _gtk_css_value_new_take_symbolic_color (symbolic);
402 values[9] = _gtk_css_value_ref (values[8]);
403 values[10] = _gtk_css_value_ref (values[8]);
404 values[11] = _gtk_css_value_ref (values[8]);
408 /* We parsed everything and there's still stuff left?
409 * Pretend we didn't notice and let the normal code produce
410 * a 'junk at end of value' error */
414 while (!value_is_done_parsing (parser));
416 /* Note that border-image values are not set: according to the spec
417 they just need to be reset when using the border shorthand */
423 parse_font (GtkCssShorthandProperty *shorthand,
424 GtkCssValue **values,
425 GtkCssParser *parser,
428 PangoFontDescription *desc;
432 str = _gtk_css_parser_read_value (parser);
436 desc = pango_font_description_from_string (str);
439 mask = pango_font_description_get_set_fields (desc);
441 if (mask & PANGO_FONT_MASK_FAMILY)
443 char **strv = g_new0 (char *, 2);
445 strv[0] = g_strdup (pango_font_description_get_family (desc));
446 values[0] = _gtk_css_value_new_take_strv (strv);
448 if (mask & PANGO_FONT_MASK_STYLE)
450 values[1] = _gtk_css_value_new_from_enum (PANGO_TYPE_STYLE,
451 pango_font_description_get_style (desc));
453 if (mask & PANGO_FONT_MASK_VARIANT)
455 values[2] = _gtk_css_value_new_from_enum (PANGO_TYPE_VARIANT,
456 pango_font_description_get_variant (desc));
458 if (mask & PANGO_FONT_MASK_WEIGHT)
460 values[3] = _gtk_css_value_new_from_enum (PANGO_TYPE_WEIGHT,
461 pango_font_description_get_weight (desc));
463 if (mask & PANGO_FONT_MASK_SIZE)
465 values[4] = _gtk_css_value_new_from_double ((double) pango_font_description_get_size (desc) / PANGO_SCALE);
468 pango_font_description_free (desc);
474 parse_background (GtkCssShorthandProperty *shorthand,
475 GtkCssValue **values,
476 GtkCssParser *parser,
484 if (values[0] == NULL &&
485 (_gtk_css_parser_has_prefix (parser, "none") ||
486 _gtk_css_image_can_parse (parser)))
490 if (_gtk_css_parser_try (parser, "none", TRUE))
494 image = _gtk_css_image_new_parse (parser, base);
499 values[0] = _gtk_css_value_new_take_image (image);
501 else if (values[1] == NULL &&
502 _gtk_css_parser_try_enum (parser, GTK_TYPE_CSS_BACKGROUND_REPEAT, &enum_value))
504 if (enum_value <= GTK_CSS_BACKGROUND_REPEAT_MASK)
508 if (_gtk_css_parser_try_enum (parser, GTK_TYPE_CSS_BACKGROUND_REPEAT, &vertical))
510 if (vertical >= GTK_CSS_BACKGROUND_REPEAT_MASK)
512 _gtk_css_parser_error (parser, "Not a valid 2nd value for border-repeat");
516 enum_value |= vertical << GTK_CSS_BACKGROUND_REPEAT_SHIFT;
519 enum_value |= enum_value << GTK_CSS_BACKGROUND_REPEAT_SHIFT;
522 values[1] = _gtk_css_value_new_from_enum (GTK_TYPE_CSS_BACKGROUND_REPEAT, enum_value);
524 else if ((values[2] == NULL || values[3] == NULL) &&
525 _gtk_css_parser_try_enum (parser, GTK_TYPE_CSS_AREA, &enum_value))
527 guint idx = values[2] == NULL ? 2 : 3;
528 values[idx] = _gtk_css_value_new_from_enum (GTK_TYPE_CSS_AREA, enum_value);
530 else if (values[4] == NULL)
532 GtkSymbolicColor *symbolic;
534 symbolic = _gtk_css_parser_read_symbolic_color (parser);
535 if (symbolic == NULL)
538 values[4] = _gtk_css_value_new_take_symbolic_color (symbolic);
542 /* We parsed everything and there's still stuff left?
543 * Pretend we didn't notice and let the normal code produce
544 * a 'junk at end of value' error */
548 while (!value_is_done_parsing (parser));
556 unpack_border (GtkCssShorthandProperty *shorthand,
557 GtkStyleProperties *props,
561 GValue v = G_VALUE_INIT;
562 GtkBorder *border = g_value_get_boxed (value);
564 g_value_init (&v, G_TYPE_INT);
566 g_value_set_int (&v, border->top);
567 _gtk_style_property_assign (GTK_STYLE_PROPERTY (_gtk_css_shorthand_property_get_subproperty (shorthand, 0)), props, state, &v);
568 g_value_set_int (&v, border->right);
569 _gtk_style_property_assign (GTK_STYLE_PROPERTY (_gtk_css_shorthand_property_get_subproperty (shorthand, 1)), props, state, &v);
570 g_value_set_int (&v, border->bottom);
571 _gtk_style_property_assign (GTK_STYLE_PROPERTY (_gtk_css_shorthand_property_get_subproperty (shorthand, 2)), props, state, &v);
572 g_value_set_int (&v, border->left);
573 _gtk_style_property_assign (GTK_STYLE_PROPERTY (_gtk_css_shorthand_property_get_subproperty (shorthand, 3)), props, state, &v);
579 pack_border (GtkCssShorthandProperty *shorthand,
581 GtkStyleQueryFunc query_func,
584 GtkCssStyleProperty *prop;
588 prop = _gtk_css_shorthand_property_get_subproperty (shorthand, 0);
589 v = (* query_func) (_gtk_css_style_property_get_id (prop), query_data);
591 border.top = _gtk_css_value_get_int (v);
592 prop = _gtk_css_shorthand_property_get_subproperty (shorthand, 1);
593 v = (* query_func) (_gtk_css_style_property_get_id (prop), query_data);
595 border.right = _gtk_css_value_get_int (v);
596 prop = _gtk_css_shorthand_property_get_subproperty (shorthand, 2);
597 v = (* query_func) (_gtk_css_style_property_get_id (prop), query_data);
599 border.bottom = _gtk_css_value_get_int (v);
600 prop = _gtk_css_shorthand_property_get_subproperty (shorthand, 3);
601 v = (* query_func) (_gtk_css_style_property_get_id (prop), query_data);
603 border.left = _gtk_css_value_get_int (v);
605 g_value_init (value, GTK_TYPE_BORDER);
606 g_value_set_boxed (value, &border);
610 unpack_border_radius (GtkCssShorthandProperty *shorthand,
611 GtkStyleProperties *props,
615 GtkCssBorderCornerRadius border;
616 GValue v = G_VALUE_INIT;
619 _gtk_css_number_init (&border.horizontal, g_value_get_int (value), GTK_CSS_PX);
620 border.vertical = border.horizontal;
621 g_value_init (&v, GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
622 g_value_set_boxed (&v, &border);
624 for (i = 0; i < 4; i++)
625 _gtk_style_property_assign (GTK_STYLE_PROPERTY (_gtk_css_shorthand_property_get_subproperty (shorthand, i)), props, state, &v);
631 pack_border_radius (GtkCssShorthandProperty *shorthand,
633 GtkStyleQueryFunc query_func,
636 const GtkCssBorderCornerRadius *top_left;
637 GtkCssStyleProperty *prop;
641 prop = GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("border-top-left-radius"));
642 v = (* query_func) (_gtk_css_style_property_get_id (prop), query_data);
645 top_left = _gtk_css_value_get_border_corner_radius (v);
647 i = top_left->horizontal.value;
650 g_value_init (value, G_TYPE_INT);
651 g_value_set_int (value, i);
655 unpack_font_description (GtkCssShorthandProperty *shorthand,
656 GtkStyleProperties *props,
660 GtkStyleProperty *prop;
661 PangoFontDescription *description;
663 GValue v = G_VALUE_INIT;
665 /* For backwards compat, we only unpack values that are indeed set.
666 * For strict CSS conformance we need to unpack all of them.
667 * Note that we do set all of them in the parse function, so it
668 * will not have effects when parsing CSS files. It will though
669 * for custom style providers.
672 description = g_value_get_boxed (value);
675 mask = pango_font_description_get_set_fields (description);
679 if (mask & PANGO_FONT_MASK_FAMILY)
681 GPtrArray *strv = g_ptr_array_new ();
683 g_ptr_array_add (strv, g_strdup (pango_font_description_get_family (description)));
684 g_ptr_array_add (strv, NULL);
685 g_value_init (&v, G_TYPE_STRV);
686 g_value_take_boxed (&v, g_ptr_array_free (strv, FALSE));
688 prop = _gtk_style_property_lookup ("font-family");
689 _gtk_style_property_assign (prop, props, state, &v);
693 if (mask & PANGO_FONT_MASK_STYLE)
695 g_value_init (&v, PANGO_TYPE_STYLE);
696 g_value_set_enum (&v, pango_font_description_get_style (description));
698 prop = _gtk_style_property_lookup ("font-style");
699 _gtk_style_property_assign (prop, props, state, &v);
703 if (mask & PANGO_FONT_MASK_VARIANT)
705 g_value_init (&v, PANGO_TYPE_VARIANT);
706 g_value_set_enum (&v, pango_font_description_get_variant (description));
708 prop = _gtk_style_property_lookup ("font-variant");
709 _gtk_style_property_assign (prop, props, state, &v);
713 if (mask & PANGO_FONT_MASK_WEIGHT)
715 g_value_init (&v, PANGO_TYPE_WEIGHT);
716 g_value_set_enum (&v, pango_font_description_get_weight (description));
718 prop = _gtk_style_property_lookup ("font-weight");
719 _gtk_style_property_assign (prop, props, state, &v);
723 if (mask & PANGO_FONT_MASK_SIZE)
725 g_value_init (&v, G_TYPE_DOUBLE);
726 g_value_set_double (&v, (double) pango_font_description_get_size (description) / PANGO_SCALE);
728 prop = _gtk_style_property_lookup ("font-size");
729 _gtk_style_property_assign (prop, props, state, &v);
735 pack_font_description (GtkCssShorthandProperty *shorthand,
737 GtkStyleQueryFunc query_func,
740 PangoFontDescription *description;
743 description = pango_font_description_new ();
745 v = (* query_func) (_gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("font-family"))), query_data);
748 const char **families = _gtk_css_value_get_strv (v);
749 /* xxx: Can we set all the families here somehow? */
751 pango_font_description_set_family (description, families[0]);
754 v = (* query_func) (_gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("font-size"))), query_data);
756 pango_font_description_set_size (description, round (_gtk_css_value_get_double (v) * PANGO_SCALE));
758 v = (* query_func) (_gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("font-style"))), query_data);
760 pango_font_description_set_style (description, _gtk_css_value_get_pango_style (v));
762 v = (* query_func) (_gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("font-variant"))), query_data);
764 pango_font_description_set_variant (description, _gtk_css_value_get_pango_variant (v));
766 v = (* query_func) (_gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("font-weight"))), query_data);
768 pango_font_description_set_weight (description, _gtk_css_value_get_pango_weight (v));
770 g_value_init (value, PANGO_TYPE_FONT_DESCRIPTION);
771 g_value_take_boxed (value, description);
775 unpack_to_everything (GtkCssShorthandProperty *shorthand,
776 GtkStyleProperties *props,
780 GtkCssStyleProperty *prop;
783 n = _gtk_css_shorthand_property_get_n_subproperties (shorthand);
785 for (i = 0; i < n; i++)
787 prop = _gtk_css_shorthand_property_get_subproperty (shorthand, i);
788 _gtk_style_property_assign (GTK_STYLE_PROPERTY (prop), props, state, value);
793 pack_first_element (GtkCssShorthandProperty *shorthand,
795 GtkStyleQueryFunc query_func,
798 GtkCssStyleProperty *prop;
800 /* NB: This is a fallback for properties that originally were
801 * not used as shorthand. We just pick the first subproperty
802 * as a representative.
803 * Lesson learned: Don't query the shorthand, query the
804 * real properties instead. */
805 prop = _gtk_css_shorthand_property_get_subproperty (shorthand, 0);
806 _gtk_style_property_query (GTK_STYLE_PROPERTY (prop),
813 _gtk_css_shorthand_property_register (const char *name,
815 const char **subproperties,
816 GtkCssShorthandPropertyParseFunc parse_func,
817 GtkCssShorthandPropertyAssignFunc assign_func,
818 GtkCssShorthandPropertyQueryFunc query_func)
820 GtkCssShorthandProperty *node;
822 node = g_object_new (GTK_TYPE_CSS_SHORTHAND_PROPERTY,
824 "value-type", value_type,
825 "subproperties", subproperties,
828 node->parse = parse_func;
829 node->assign = assign_func;
830 node->query = query_func;
834 _gtk_css_shorthand_property_init_properties (void)
836 /* The order is important here, be careful when changing it */
837 const char *font_subproperties[] = { "font-family", "font-style", "font-variant", "font-weight", "font-size", NULL };
838 const char *margin_subproperties[] = { "margin-top", "margin-right", "margin-bottom", "margin-left", NULL };
839 const char *padding_subproperties[] = { "padding-top", "padding-right", "padding-bottom", "padding-left", NULL };
840 const char *border_width_subproperties[] = { "border-top-width", "border-right-width", "border-bottom-width", "border-left-width", NULL };
841 const char *border_radius_subproperties[] = { "border-top-left-radius", "border-top-right-radius",
842 "border-bottom-right-radius", "border-bottom-left-radius", NULL };
843 const char *border_color_subproperties[] = { "border-top-color", "border-right-color", "border-bottom-color", "border-left-color", NULL };
844 const char *border_style_subproperties[] = { "border-top-style", "border-right-style", "border-bottom-style", "border-left-style", NULL };
845 const char *border_image_subproperties[] = { "border-image-source", "border-image-slice", "border-image-width", "border-image-repeat", NULL };
846 const char *border_top_subproperties[] = { "border-top-width", "border-top-style", "border-top-color", NULL };
847 const char *border_right_subproperties[] = { "border-right-width", "border-right-style", "border-right-color", NULL };
848 const char *border_bottom_subproperties[] = { "border-bottom-width", "border-bottom-style", "border-bottom-color", NULL };
849 const char *border_left_subproperties[] = { "border-left-width", "border-left-style", "border-left-color", NULL };
850 const char *border_subproperties[] = { "border-top-width", "border-right-width", "border-bottom-width", "border-left-width",
851 "border-top-style", "border-right-style", "border-bottom-style", "border-left-style",
852 "border-top-color", "border-right-color", "border-bottom-color", "border-left-color",
853 "border-image-source", "border-image-slice", "border-image-width", "border-image-repeat", NULL };
854 const char *outline_subproperties[] = { "outline-width", "outline-style", "outline-color", NULL };
855 const char *background_subproperties[] = { "background-image", "background-repeat", "background-clip", "background-origin",
856 "background-color", NULL };
858 _gtk_css_shorthand_property_register ("font",
859 PANGO_TYPE_FONT_DESCRIPTION,
862 unpack_font_description,
863 pack_font_description);
864 _gtk_css_shorthand_property_register ("margin",
866 margin_subproperties,
870 _gtk_css_shorthand_property_register ("padding",
872 padding_subproperties,
876 _gtk_css_shorthand_property_register ("border-width",
878 border_width_subproperties,
882 _gtk_css_shorthand_property_register ("border-radius",
884 border_radius_subproperties,
886 unpack_border_radius,
888 _gtk_css_shorthand_property_register ("border-color",
890 border_color_subproperties,
892 unpack_to_everything,
894 _gtk_css_shorthand_property_register ("border-style",
895 GTK_TYPE_BORDER_STYLE,
896 border_style_subproperties,
898 unpack_to_everything,
900 _gtk_css_shorthand_property_register ("border-image",
902 border_image_subproperties,
906 _gtk_css_shorthand_property_register ("border-top",
908 border_top_subproperties,
912 _gtk_css_shorthand_property_register ("border-right",
914 border_right_subproperties,
918 _gtk_css_shorthand_property_register ("border-bottom",
920 border_bottom_subproperties,
924 _gtk_css_shorthand_property_register ("border-left",
926 border_left_subproperties,
930 _gtk_css_shorthand_property_register ("border",
932 border_subproperties,
936 _gtk_css_shorthand_property_register ("outline",
938 outline_subproperties,
942 _gtk_css_shorthand_property_register ("background",
944 background_subproperties,