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 "gtkstylepropertiesprivate.h"
33 #include "gtktypebuiltins.h"
35 /* this is in case round() is not provided by the compiler,
36 * such as in the case of C89 compilers, like MSVC
38 #include "fallback-c89.c"
43 value_is_done_parsing (GtkCssParser *parser)
45 return _gtk_css_parser_is_eof (parser) ||
46 _gtk_css_parser_begins_with (parser, ';') ||
47 _gtk_css_parser_begins_with (parser, '}');
51 parse_border_width (GtkCssShorthandProperty *shorthand,
56 GValue temp = G_VALUE_INIT;
59 g_value_init (&temp, GTK_TYPE_BORDER);
60 if (!_gtk_css_style_parse_value (&temp, parser, base))
62 g_value_unset (&temp);
66 border = g_value_get_boxed (&temp);
68 g_value_init (&values[0], G_TYPE_INT);
69 g_value_init (&values[1], G_TYPE_INT);
70 g_value_init (&values[2], G_TYPE_INT);
71 g_value_init (&values[3], G_TYPE_INT);
72 g_value_set_int (&values[0], border->top);
73 g_value_set_int (&values[1], border->right);
74 g_value_set_int (&values[2], border->bottom);
75 g_value_set_int (&values[3], border->left);
77 g_value_unset (&temp);
83 parse_border_radius (GtkCssShorthandProperty *shorthand,
88 GtkCssBorderCornerRadius borders[4];
91 for (i = 0; i < G_N_ELEMENTS (borders); i++)
93 if (!_gtk_css_parser_try_double (parser, &borders[i].horizontal))
95 if (borders[i].horizontal < 0)
97 _gtk_css_parser_error (parser, "Border radius values cannot be negative");
104 _gtk_css_parser_error (parser, "Expected a number");
108 /* The magic (i - 1) >> 1 below makes it take the correct value
109 * according to spec. Feel free to check the 4 cases */
110 for (; i < G_N_ELEMENTS (borders); i++)
111 borders[i].horizontal = borders[(i - 1) >> 1].horizontal;
113 if (_gtk_css_parser_try (parser, "/", TRUE))
115 for (i = 0; i < G_N_ELEMENTS (borders); i++)
117 if (!_gtk_css_parser_try_double (parser, &borders[i].vertical))
119 if (borders[i].vertical < 0)
121 _gtk_css_parser_error (parser, "Border radius values cannot be negative");
128 _gtk_css_parser_error (parser, "Expected a number");
132 for (; i < G_N_ELEMENTS (borders); i++)
133 borders[i].vertical = borders[(i - 1) >> 1].vertical;
138 for (i = 0; i < G_N_ELEMENTS (borders); i++)
139 borders[i].vertical = borders[i].horizontal;
142 for (i = 0; i < G_N_ELEMENTS (borders); i++)
144 g_value_init (&values[i], GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
145 g_value_set_boxed (&values[i], &borders[i]);
152 parse_border_color (GtkCssShorthandProperty *shorthand,
154 GtkCssParser *parser,
157 GtkSymbolicColor *symbolic;
160 for (i = 0; i < 4; i++)
162 symbolic = _gtk_css_parser_read_symbolic_color (parser);
163 if (symbolic == NULL)
166 g_value_init (&values[i], GTK_TYPE_SYMBOLIC_COLOR);
167 g_value_set_boxed (&values[i], symbolic);
169 if (value_is_done_parsing (parser))
173 for (i++; i < 4; i++)
175 g_value_init (&values[i], GTK_TYPE_SYMBOLIC_COLOR);
176 g_value_copy (&values[(i - 1) >> 1], &values[i]);
183 parse_border_style (GtkCssShorthandProperty *shorthand,
185 GtkCssParser *parser,
188 GtkBorderStyle styles[4];
191 for (i = 0; i < 4; i++)
193 if (!_gtk_css_parser_try_enum (parser, GTK_TYPE_BORDER_STYLE, (int *)&styles[i]))
199 _gtk_css_parser_error (parser, "Expected a border style");
203 for (; i < G_N_ELEMENTS (styles); i++)
204 styles[i] = styles[(i - 1) >> 1];
206 for (i = 0; i < G_N_ELEMENTS (styles); i++)
208 g_value_init (&values[i], GTK_TYPE_BORDER_STYLE);
209 g_value_set_enum (&values[i], styles[i]);
216 parse_border_image (GtkCssShorthandProperty *shorthand,
218 GtkCssParser *parser,
223 if (_gtk_css_parser_try (parser, "none", TRUE))
227 image = _gtk_css_image_new_parse (parser, base);
231 g_value_init (&values[0], GTK_TYPE_CSS_IMAGE);
232 g_value_set_object (&values[0], image);
234 if (value_is_done_parsing (parser))
237 g_value_init (&values[1], GTK_TYPE_BORDER);
238 if (!_gtk_css_style_parse_value (&values[1], parser, base))
241 if (_gtk_css_parser_try (parser, "/", TRUE))
243 g_value_init (&values[2], GTK_TYPE_BORDER);
244 if (!_gtk_css_style_parse_value (&values[2], parser, base))
248 if (value_is_done_parsing (parser))
251 g_value_init (&values[3], GTK_TYPE_CSS_BORDER_IMAGE_REPEAT);
252 if (!_gtk_css_style_parse_value (&values[3], parser, base))
259 parse_border_side (GtkCssShorthandProperty *shorthand,
261 GtkCssParser *parser,
269 if (!G_IS_VALUE (&values[0]) &&
270 _gtk_css_parser_try_length (parser, &width))
272 g_value_init (&values[0], G_TYPE_INT);
273 g_value_set_int (&values[0], width);
275 else if (!G_IS_VALUE (&values[1]) &&
276 _gtk_css_parser_try_enum (parser, GTK_TYPE_BORDER_STYLE, &style))
278 g_value_init (&values[1], GTK_TYPE_BORDER_STYLE);
279 g_value_set_enum (&values[1], style);
281 else if (!G_IS_VALUE (&values[2]))
283 GtkSymbolicColor *symbolic;
285 symbolic = _gtk_css_parser_read_symbolic_color (parser);
286 if (symbolic == NULL)
289 g_value_init (&values[2], GTK_TYPE_SYMBOLIC_COLOR);
290 g_value_take_boxed (&values[2], symbolic);
294 /* We parsed everything and there's still stuff left?
295 * Pretend we didn't notice and let the normal code produce
296 * a 'junk at end of value' error */
300 while (!value_is_done_parsing (parser));
306 parse_border (GtkCssShorthandProperty *shorthand,
308 GtkCssParser *parser,
316 if (!G_IS_VALUE (&values[0]) &&
317 _gtk_css_parser_try_length (parser, &width))
319 g_value_init (&values[0], G_TYPE_INT);
320 g_value_init (&values[1], G_TYPE_INT);
321 g_value_init (&values[2], G_TYPE_INT);
322 g_value_init (&values[3], G_TYPE_INT);
323 g_value_set_int (&values[0], width);
324 g_value_set_int (&values[1], width);
325 g_value_set_int (&values[2], width);
326 g_value_set_int (&values[3], width);
328 else if (!G_IS_VALUE (&values[4]) &&
329 _gtk_css_parser_try_enum (parser, GTK_TYPE_BORDER_STYLE, &style))
331 g_value_init (&values[4], GTK_TYPE_BORDER_STYLE);
332 g_value_init (&values[5], GTK_TYPE_BORDER_STYLE);
333 g_value_init (&values[6], GTK_TYPE_BORDER_STYLE);
334 g_value_init (&values[7], GTK_TYPE_BORDER_STYLE);
335 g_value_set_enum (&values[4], style);
336 g_value_set_enum (&values[5], style);
337 g_value_set_enum (&values[6], style);
338 g_value_set_enum (&values[7], style);
340 else if (!G_IS_VALUE (&values[8]))
342 GtkSymbolicColor *symbolic;
344 symbolic = _gtk_css_parser_read_symbolic_color (parser);
345 if (symbolic == NULL)
348 g_value_init (&values[8], GTK_TYPE_SYMBOLIC_COLOR);
349 g_value_init (&values[9], GTK_TYPE_SYMBOLIC_COLOR);
350 g_value_init (&values[10], GTK_TYPE_SYMBOLIC_COLOR);
351 g_value_init (&values[11], GTK_TYPE_SYMBOLIC_COLOR);
352 g_value_set_boxed (&values[8], symbolic);
353 g_value_set_boxed (&values[9], symbolic);
354 g_value_set_boxed (&values[10], symbolic);
355 g_value_take_boxed (&values[11], symbolic);
359 /* We parsed everything and there's still stuff left?
360 * Pretend we didn't notice and let the normal code produce
361 * a 'junk at end of value' error */
365 while (!value_is_done_parsing (parser));
367 /* Note that border-image values are not set: according to the spec
368 they just need to be reset when using the border shorthand */
374 parse_font (GtkCssShorthandProperty *shorthand,
376 GtkCssParser *parser,
379 PangoFontDescription *desc;
383 str = _gtk_css_parser_read_value (parser);
387 desc = pango_font_description_from_string (str);
390 mask = pango_font_description_get_set_fields (desc);
392 if (mask & PANGO_FONT_MASK_FAMILY)
394 GPtrArray *strv = g_ptr_array_new ();
396 g_ptr_array_add (strv, g_strdup (pango_font_description_get_family (desc)));
397 g_ptr_array_add (strv, NULL);
398 g_value_init (&values[0], G_TYPE_STRV);
399 g_value_take_boxed (&values[0], g_ptr_array_free (strv, FALSE));
401 if (mask & PANGO_FONT_MASK_STYLE)
403 g_value_init (&values[1], PANGO_TYPE_STYLE);
404 g_value_set_enum (&values[1], pango_font_description_get_style (desc));
406 if (mask & PANGO_FONT_MASK_VARIANT)
408 g_value_init (&values[2], PANGO_TYPE_VARIANT);
409 g_value_set_enum (&values[2], pango_font_description_get_variant (desc));
411 if (mask & PANGO_FONT_MASK_WEIGHT)
413 g_value_init (&values[3], PANGO_TYPE_WEIGHT);
414 g_value_set_enum (&values[3], pango_font_description_get_weight (desc));
416 if (mask & PANGO_FONT_MASK_SIZE)
418 g_value_init (&values[4], G_TYPE_DOUBLE);
419 g_value_set_double (&values[4],
420 (double) pango_font_description_get_size (desc) / PANGO_SCALE);
423 pango_font_description_free (desc);
429 parse_background (GtkCssShorthandProperty *shorthand,
431 GtkCssParser *parser,
439 if (!G_IS_VALUE (&values[0]) &&
440 (_gtk_css_parser_has_prefix (parser, "none") ||
441 _gtk_css_image_can_parse (parser)))
445 if (_gtk_css_parser_try (parser, "none", TRUE))
449 image = _gtk_css_image_new_parse (parser, base);
454 g_value_init (&values[0], GTK_TYPE_CSS_IMAGE);
455 g_value_take_object (&values[0], image);
457 else if (!G_IS_VALUE (&values[1]) &&
458 _gtk_css_parser_try_enum (parser, GTK_TYPE_CSS_BACKGROUND_REPEAT, &enum_value))
460 if (enum_value <= GTK_CSS_BACKGROUND_REPEAT_MASK)
464 if (_gtk_css_parser_try_enum (parser, GTK_TYPE_CSS_BACKGROUND_REPEAT, &vertical))
466 if (vertical >= GTK_CSS_BACKGROUND_REPEAT_MASK)
468 _gtk_css_parser_error (parser, "Not a valid 2nd value for border-repeat");
472 enum_value |= vertical << GTK_CSS_BACKGROUND_REPEAT_SHIFT;
475 enum_value |= enum_value << GTK_CSS_BACKGROUND_REPEAT_SHIFT;
478 g_value_init (&values[1], GTK_TYPE_CSS_BACKGROUND_REPEAT);
479 g_value_set_enum (&values[1], enum_value);
481 else if ((!G_IS_VALUE (&values[2]) || !G_IS_VALUE (&values[3])) &&
482 _gtk_css_parser_try_enum (parser, GTK_TYPE_CSS_AREA, &enum_value))
484 guint idx = !G_IS_VALUE (&values[2]) ? 2 : 3;
485 g_value_init (&values[idx], GTK_TYPE_CSS_AREA);
486 g_value_set_enum (&values[idx], enum_value);
488 else if (!G_IS_VALUE (&values[4]))
490 GtkSymbolicColor *symbolic;
492 symbolic = _gtk_css_parser_read_symbolic_color (parser);
493 if (symbolic == NULL)
496 g_value_init (&values[4], GTK_TYPE_SYMBOLIC_COLOR);
497 g_value_take_boxed (&values[4], symbolic);
501 /* We parsed everything and there's still stuff left?
502 * Pretend we didn't notice and let the normal code produce
503 * a 'junk at end of value' error */
507 while (!value_is_done_parsing (parser));
515 unpack_border (GtkCssShorthandProperty *shorthand,
519 GParameter *parameter = g_new0 (GParameter, 4);
520 GtkBorder *border = g_value_get_boxed (value);
522 parameter[0].name = _gtk_style_property_get_name (GTK_STYLE_PROPERTY (_gtk_css_shorthand_property_get_subproperty (shorthand, 0)));
523 g_value_init (¶meter[0].value, G_TYPE_INT);
524 g_value_set_int (¶meter[0].value, border->top);
525 parameter[1].name = _gtk_style_property_get_name (GTK_STYLE_PROPERTY (_gtk_css_shorthand_property_get_subproperty (shorthand, 1)));
526 g_value_init (¶meter[1].value, G_TYPE_INT);
527 g_value_set_int (¶meter[1].value, border->right);
528 parameter[2].name = _gtk_style_property_get_name (GTK_STYLE_PROPERTY (_gtk_css_shorthand_property_get_subproperty (shorthand, 2)));
529 g_value_init (¶meter[2].value, G_TYPE_INT);
530 g_value_set_int (¶meter[2].value, border->bottom);
531 parameter[3].name = _gtk_style_property_get_name (GTK_STYLE_PROPERTY (_gtk_css_shorthand_property_get_subproperty (shorthand, 3)));
532 g_value_init (¶meter[3].value, G_TYPE_INT);
533 g_value_set_int (¶meter[3].value, border->left);
540 pack_border (GtkCssShorthandProperty *shorthand,
542 GtkStyleProperties *props,
545 GtkCssStyleProperty *prop;
549 prop = _gtk_css_shorthand_property_get_subproperty (shorthand, 0);
550 v = _gtk_style_properties_peek_property (props, prop, state);
552 border.top = g_value_get_int (v);
553 prop = _gtk_css_shorthand_property_get_subproperty (shorthand, 1);
554 v = _gtk_style_properties_peek_property (props, prop, state);
556 border.right = g_value_get_int (v);
557 prop = _gtk_css_shorthand_property_get_subproperty (shorthand, 2);
558 v = _gtk_style_properties_peek_property (props, prop, state);
560 border.bottom = g_value_get_int (v);
561 prop = _gtk_css_shorthand_property_get_subproperty (shorthand, 3);
562 v = _gtk_style_properties_peek_property (props, prop, state);
564 border.left = g_value_get_int (v);
566 g_value_set_boxed (value, &border);
570 unpack_border_radius (GtkCssShorthandProperty *shorthand,
574 GParameter *parameter = g_new0 (GParameter, 4);
575 GtkCssBorderCornerRadius border;
577 border.horizontal = border.vertical = g_value_get_int (value);
579 parameter[0].name = "border-top-left-radius";
580 g_value_init (¶meter[0].value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
581 g_value_set_boxed (¶meter[0].value, &border);
582 parameter[1].name = "border-top-right-radius";
583 g_value_init (¶meter[1].value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
584 g_value_set_boxed (¶meter[1].value, &border);
585 parameter[2].name = "border-bottom-right-radius";
586 g_value_init (¶meter[2].value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
587 g_value_set_boxed (¶meter[2].value, &border);
588 parameter[3].name = "border-bottom-left-radius";
589 g_value_init (¶meter[3].value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
590 g_value_set_boxed (¶meter[3].value, &border);
597 pack_border_radius (GtkCssShorthandProperty *shorthand,
599 GtkStyleProperties *props,
602 GtkCssBorderCornerRadius *top_left;
604 /* NB: We are an int property, so we have to resolve to an int here.
605 * So we just resolve to an int. We pick one and stick to it.
606 * Lesson learned: Don't query border-radius shorthand, query the
607 * real properties instead. */
608 gtk_style_properties_get (props,
610 "border-top-left-radius", &top_left,
614 g_value_set_int (value, top_left->horizontal);
620 unpack_font_description (GtkCssShorthandProperty *shorthand,
624 GParameter *parameter = g_new0 (GParameter, 5);
625 PangoFontDescription *description;
629 /* For backwards compat, we only unpack values that are indeed set.
630 * For strict CSS conformance we need to unpack all of them.
631 * Note that we do set all of them in the parse function, so it
632 * will not have effects when parsing CSS files. It will though
633 * for custom style providers.
636 description = g_value_get_boxed (value);
640 mask = pango_font_description_get_set_fields (description);
644 if (mask & PANGO_FONT_MASK_FAMILY)
646 GPtrArray *strv = g_ptr_array_new ();
648 g_ptr_array_add (strv, g_strdup (pango_font_description_get_family (description)));
649 g_ptr_array_add (strv, NULL);
650 parameter[n].name = "font-family";
651 g_value_init (¶meter[n].value, G_TYPE_STRV);
652 g_value_take_boxed (¶meter[n].value,
653 g_ptr_array_free (strv, FALSE));
657 if (mask & PANGO_FONT_MASK_STYLE)
659 parameter[n].name = "font-style";
660 g_value_init (¶meter[n].value, PANGO_TYPE_STYLE);
661 g_value_set_enum (¶meter[n].value,
662 pango_font_description_get_style (description));
666 if (mask & PANGO_FONT_MASK_VARIANT)
668 parameter[n].name = "font-variant";
669 g_value_init (¶meter[n].value, PANGO_TYPE_VARIANT);
670 g_value_set_enum (¶meter[n].value,
671 pango_font_description_get_variant (description));
675 if (mask & PANGO_FONT_MASK_WEIGHT)
677 parameter[n].name = "font-weight";
678 g_value_init (¶meter[n].value, PANGO_TYPE_WEIGHT);
679 g_value_set_enum (¶meter[n].value,
680 pango_font_description_get_weight (description));
684 if (mask & PANGO_FONT_MASK_SIZE)
686 parameter[n].name = "font-size";
687 g_value_init (¶meter[n].value, G_TYPE_DOUBLE);
688 g_value_set_double (¶meter[n].value,
689 (double) pango_font_description_get_size (description) / PANGO_SCALE);
699 pack_font_description (GtkCssShorthandProperty *shorthand,
701 GtkStyleProperties *props,
704 PangoFontDescription *description;
707 PangoVariant variant;
711 gtk_style_properties_get (props,
713 "font-family", &families,
714 "font-style", &style,
715 "font-variant", &variant,
716 "font-weight", &weight,
720 description = pango_font_description_new ();
721 /* xxx: Can we set all the families here somehow? */
723 pango_font_description_set_family (description, families[0]);
724 pango_font_description_set_size (description, round (size * PANGO_SCALE));
725 pango_font_description_set_style (description, style);
726 pango_font_description_set_variant (description, variant);
727 pango_font_description_set_weight (description, weight);
729 g_strfreev (families);
731 g_value_take_boxed (value, description);
735 unpack_to_everything (GtkCssShorthandProperty *shorthand,
739 GtkCssStyleProperty *prop;
740 GParameter *parameter;
744 n = _gtk_css_shorthand_property_get_n_subproperties (shorthand);
745 parameter = g_new0 (GParameter, n);
746 type = G_VALUE_TYPE (value);
748 for (i = 0; i < n; i++)
750 prop = _gtk_css_shorthand_property_get_subproperty (shorthand, i);
751 parameter[i].name = _gtk_style_property_get_name (GTK_STYLE_PROPERTY (prop));
752 g_value_init (¶meter[i].value, type);
753 g_value_copy (value, ¶meter[i].value);
761 pack_first_element (GtkCssShorthandProperty *shorthand,
763 GtkStyleProperties *props,
766 GtkCssStyleProperty *prop;
770 /* NB: This is a fallback for properties that originally were
771 * not used as shorthand. We just pick the first subproperty
772 * as a representative.
773 * Lesson learned: Don't query the shorthand, query the
774 * real properties instead. */
775 for (i = 0; i < _gtk_css_shorthand_property_get_n_subproperties (shorthand); i++)
777 prop = _gtk_css_shorthand_property_get_subproperty (shorthand, 0);
778 v = _gtk_style_properties_peek_property (props, prop, state);
781 g_value_copy (v, value);
788 _gtk_css_shorthand_property_register (const char *name,
790 const char **subproperties,
791 GtkCssShorthandPropertyParseFunc parse_func,
792 GtkCssShorthandPropertyAssignFunc assign_func,
793 GtkCssShorthandPropertyQueryFunc query_func)
795 GtkCssShorthandProperty *node;
797 node = g_object_new (GTK_TYPE_CSS_SHORTHAND_PROPERTY,
799 "value-type", value_type,
800 "subproperties", subproperties,
803 node->parse = parse_func;
804 node->assign = assign_func;
805 node->query = query_func;
809 _gtk_css_shorthand_property_init_properties (void)
811 /* The order is important here, be careful when changing it */
812 const char *font_subproperties[] = { "font-family", "font-style", "font-variant", "font-weight", "font-size", NULL };
813 const char *margin_subproperties[] = { "margin-top", "margin-right", "margin-bottom", "margin-left", NULL };
814 const char *padding_subproperties[] = { "padding-top", "padding-right", "padding-bottom", "padding-left", NULL };
815 const char *border_width_subproperties[] = { "border-top-width", "border-right-width", "border-bottom-width", "border-left-width", NULL };
816 const char *border_radius_subproperties[] = { "border-top-left-radius", "border-top-right-radius",
817 "border-bottom-right-radius", "border-bottom-left-radius", NULL };
818 const char *border_color_subproperties[] = { "border-top-color", "border-right-color", "border-bottom-color", "border-left-color", NULL };
819 const char *border_style_subproperties[] = { "border-top-style", "border-right-style", "border-bottom-style", "border-left-style", NULL };
820 const char *border_image_subproperties[] = { "border-image-source", "border-image-slice", "border-image-width", "border-image-repeat", NULL };
821 const char *border_top_subproperties[] = { "border-top-width", "border-top-style", "border-top-color", NULL };
822 const char *border_right_subproperties[] = { "border-right-width", "border-right-style", "border-right-color", NULL };
823 const char *border_bottom_subproperties[] = { "border-bottom-width", "border-bottom-style", "border-bottom-color", NULL };
824 const char *border_left_subproperties[] = { "border-left-width", "border-left-style", "border-left-color", NULL };
825 const char *border_subproperties[] = { "border-top-width", "border-right-width", "border-bottom-width", "border-left-width",
826 "border-top-style", "border-right-style", "border-bottom-style", "border-left-style",
827 "border-top-color", "border-right-color", "border-bottom-color", "border-left-color",
828 "border-image-source", "border-image-slice", "border-image-width", "border-image-repeat", NULL };
829 const char *outline_subproperties[] = { "outline-width", "outline-style", "outline-color", NULL };
830 const char *background_subproperties[] = { "background-image", "background-repeat", "background-clip", "background-origin",
831 "background-color", NULL };
833 _gtk_css_shorthand_property_register ("font",
834 PANGO_TYPE_FONT_DESCRIPTION,
837 unpack_font_description,
838 pack_font_description);
839 _gtk_css_shorthand_property_register ("margin",
841 margin_subproperties,
845 _gtk_css_shorthand_property_register ("padding",
847 padding_subproperties,
851 _gtk_css_shorthand_property_register ("border-width",
853 border_width_subproperties,
857 _gtk_css_shorthand_property_register ("border-radius",
859 border_radius_subproperties,
861 unpack_border_radius,
863 _gtk_css_shorthand_property_register ("border-color",
865 border_color_subproperties,
867 unpack_to_everything,
869 _gtk_css_shorthand_property_register ("border-style",
870 GTK_TYPE_BORDER_STYLE,
871 border_style_subproperties,
873 unpack_to_everything,
875 _gtk_css_shorthand_property_register ("border-image",
877 border_image_subproperties,
881 _gtk_css_shorthand_property_register ("border-top",
883 border_top_subproperties,
887 _gtk_css_shorthand_property_register ("border-right",
889 border_right_subproperties,
893 _gtk_css_shorthand_property_register ("border-bottom",
895 border_bottom_subproperties,
899 _gtk_css_shorthand_property_register ("border-left",
901 border_left_subproperties,
905 _gtk_css_shorthand_property_register ("border",
907 border_subproperties,
911 _gtk_css_shorthand_property_register ("outline",
913 outline_subproperties,
917 _gtk_css_shorthand_property_register ("background",
919 background_subproperties,