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,
516 GtkStyleProperties *props,
520 GValue v = G_VALUE_INIT;
521 GtkBorder *border = g_value_get_boxed (value);
523 g_value_init (&v, G_TYPE_INT);
525 g_value_set_int (&v, border->top);
526 _gtk_style_property_assign (GTK_STYLE_PROPERTY (_gtk_css_shorthand_property_get_subproperty (shorthand, 0)), props, state, &v);
527 g_value_set_int (&v, border->right);
528 _gtk_style_property_assign (GTK_STYLE_PROPERTY (_gtk_css_shorthand_property_get_subproperty (shorthand, 1)), props, state, &v);
529 g_value_set_int (&v, border->bottom);
530 _gtk_style_property_assign (GTK_STYLE_PROPERTY (_gtk_css_shorthand_property_get_subproperty (shorthand, 2)), props, state, &v);
531 g_value_set_int (&v, border->left);
532 _gtk_style_property_assign (GTK_STYLE_PROPERTY (_gtk_css_shorthand_property_get_subproperty (shorthand, 3)), props, state, &v);
538 pack_border (GtkCssShorthandProperty *shorthand,
540 GtkStyleQueryFunc query_func,
543 GtkCssStyleProperty *prop;
547 prop = _gtk_css_shorthand_property_get_subproperty (shorthand, 0);
548 v = (* query_func) (_gtk_css_style_property_get_id (prop), query_data);
550 border.top = g_value_get_int (v);
551 prop = _gtk_css_shorthand_property_get_subproperty (shorthand, 1);
552 v = (* query_func) (_gtk_css_style_property_get_id (prop), query_data);
554 border.right = g_value_get_int (v);
555 prop = _gtk_css_shorthand_property_get_subproperty (shorthand, 2);
556 v = (* query_func) (_gtk_css_style_property_get_id (prop), query_data);
558 border.bottom = g_value_get_int (v);
559 prop = _gtk_css_shorthand_property_get_subproperty (shorthand, 3);
560 v = (* query_func) (_gtk_css_style_property_get_id (prop), query_data);
562 border.left = g_value_get_int (v);
564 g_value_set_boxed (value, &border);
568 unpack_border_radius (GtkCssShorthandProperty *shorthand,
569 GtkStyleProperties *props,
573 GtkCssBorderCornerRadius border;
574 GValue v = G_VALUE_INIT;
577 border.horizontal = border.vertical = g_value_get_int (value);
578 g_value_init (&v, GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
579 g_value_set_boxed (&v, &border);
581 for (i = 0; i < 4; i++)
582 _gtk_style_property_assign (GTK_STYLE_PROPERTY (_gtk_css_shorthand_property_get_subproperty (shorthand, i)), props, state, &v);
588 pack_border_radius (GtkCssShorthandProperty *shorthand,
590 GtkStyleQueryFunc query_func,
593 GtkCssBorderCornerRadius *top_left;
594 GtkCssStyleProperty *prop;
597 prop = GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("border-top-left-radius"));
598 v = (* query_func) (_gtk_css_style_property_get_id (prop), query_data);
601 top_left = g_value_get_boxed (v);
603 g_value_set_int (value, top_left->horizontal);
608 unpack_font_description (GtkCssShorthandProperty *shorthand,
609 GtkStyleProperties *props,
613 GtkStyleProperty *prop;
614 PangoFontDescription *description;
616 GValue v = G_VALUE_INIT;
618 /* For backwards compat, we only unpack values that are indeed set.
619 * For strict CSS conformance we need to unpack all of them.
620 * Note that we do set all of them in the parse function, so it
621 * will not have effects when parsing CSS files. It will though
622 * for custom style providers.
625 description = g_value_get_boxed (value);
628 mask = pango_font_description_get_set_fields (description);
632 if (mask & PANGO_FONT_MASK_FAMILY)
634 GPtrArray *strv = g_ptr_array_new ();
636 g_ptr_array_add (strv, g_strdup (pango_font_description_get_family (description)));
637 g_ptr_array_add (strv, NULL);
638 g_value_init (&v, G_TYPE_STRV);
639 g_value_take_boxed (&v, g_ptr_array_free (strv, FALSE));
641 prop = _gtk_style_property_lookup ("font-family");
642 _gtk_style_property_assign (prop, props, state, &v);
646 if (mask & PANGO_FONT_MASK_STYLE)
648 g_value_init (&v, PANGO_TYPE_STYLE);
649 g_value_set_enum (&v, pango_font_description_get_style (description));
651 prop = _gtk_style_property_lookup ("font-style");
652 _gtk_style_property_assign (prop, props, state, &v);
656 if (mask & PANGO_FONT_MASK_VARIANT)
658 g_value_init (&v, PANGO_TYPE_VARIANT);
659 g_value_set_enum (&v, pango_font_description_get_variant (description));
661 prop = _gtk_style_property_lookup ("font-variant");
662 _gtk_style_property_assign (prop, props, state, &v);
666 if (mask & PANGO_FONT_MASK_WEIGHT)
668 g_value_init (&v, PANGO_TYPE_WEIGHT);
669 g_value_set_enum (&v, pango_font_description_get_weight (description));
671 prop = _gtk_style_property_lookup ("font-weight");
672 _gtk_style_property_assign (prop, props, state, &v);
676 if (mask & PANGO_FONT_MASK_SIZE)
678 g_value_init (&v, G_TYPE_DOUBLE);
679 g_value_set_double (&v, (double) pango_font_description_get_size (description) / PANGO_SCALE);
681 prop = _gtk_style_property_lookup ("font-size");
682 _gtk_style_property_assign (prop, props, state, &v);
688 pack_font_description (GtkCssShorthandProperty *shorthand,
690 GtkStyleQueryFunc query_func,
693 PangoFontDescription *description;
696 description = pango_font_description_new ();
698 v = (* query_func) (_gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("font-family"))), query_data);
701 const char **families = g_value_get_boxed (v);
702 /* xxx: Can we set all the families here somehow? */
704 pango_font_description_set_family (description, families[0]);
707 v = (* query_func) (_gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("font-size"))), query_data);
709 pango_font_description_set_size (description, round (g_value_get_double (v) * PANGO_SCALE));
711 v = (* query_func) (_gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("font-style"))), query_data);
713 pango_font_description_set_style (description, g_value_get_enum (v));
715 v = (* query_func) (_gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("font-variant"))), query_data);
717 pango_font_description_set_variant (description, g_value_get_enum (v));
719 v = (* query_func) (_gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("font-weight"))), query_data);
721 pango_font_description_set_weight (description, g_value_get_enum (v));
723 g_value_take_boxed (value, description);
727 unpack_to_everything (GtkCssShorthandProperty *shorthand,
728 GtkStyleProperties *props,
732 GtkCssStyleProperty *prop;
735 n = _gtk_css_shorthand_property_get_n_subproperties (shorthand);
737 for (i = 0; i < n; i++)
739 prop = _gtk_css_shorthand_property_get_subproperty (shorthand, i);
740 _gtk_style_property_assign (GTK_STYLE_PROPERTY (prop), props, state, value);
745 pack_first_element (GtkCssShorthandProperty *shorthand,
747 GtkStyleQueryFunc query_func,
750 GtkCssStyleProperty *prop;
754 /* NB: This is a fallback for properties that originally were
755 * not used as shorthand. We just pick the first subproperty
756 * as a representative.
757 * Lesson learned: Don't query the shorthand, query the
758 * real properties instead. */
759 for (i = 0; i < _gtk_css_shorthand_property_get_n_subproperties (shorthand); i++)
761 prop = _gtk_css_shorthand_property_get_subproperty (shorthand, 0);
762 v = (* query_func) (_gtk_css_style_property_get_id (prop), query_data);
765 g_value_copy (v, value);
772 _gtk_css_shorthand_property_register (const char *name,
774 const char **subproperties,
775 GtkCssShorthandPropertyParseFunc parse_func,
776 GtkCssShorthandPropertyAssignFunc assign_func,
777 GtkCssShorthandPropertyQueryFunc query_func)
779 GtkCssShorthandProperty *node;
781 node = g_object_new (GTK_TYPE_CSS_SHORTHAND_PROPERTY,
783 "value-type", value_type,
784 "subproperties", subproperties,
787 node->parse = parse_func;
788 node->assign = assign_func;
789 node->query = query_func;
793 _gtk_css_shorthand_property_init_properties (void)
795 /* The order is important here, be careful when changing it */
796 const char *font_subproperties[] = { "font-family", "font-style", "font-variant", "font-weight", "font-size", NULL };
797 const char *margin_subproperties[] = { "margin-top", "margin-right", "margin-bottom", "margin-left", NULL };
798 const char *padding_subproperties[] = { "padding-top", "padding-right", "padding-bottom", "padding-left", NULL };
799 const char *border_width_subproperties[] = { "border-top-width", "border-right-width", "border-bottom-width", "border-left-width", NULL };
800 const char *border_radius_subproperties[] = { "border-top-left-radius", "border-top-right-radius",
801 "border-bottom-right-radius", "border-bottom-left-radius", NULL };
802 const char *border_color_subproperties[] = { "border-top-color", "border-right-color", "border-bottom-color", "border-left-color", NULL };
803 const char *border_style_subproperties[] = { "border-top-style", "border-right-style", "border-bottom-style", "border-left-style", NULL };
804 const char *border_image_subproperties[] = { "border-image-source", "border-image-slice", "border-image-width", "border-image-repeat", NULL };
805 const char *border_top_subproperties[] = { "border-top-width", "border-top-style", "border-top-color", NULL };
806 const char *border_right_subproperties[] = { "border-right-width", "border-right-style", "border-right-color", NULL };
807 const char *border_bottom_subproperties[] = { "border-bottom-width", "border-bottom-style", "border-bottom-color", NULL };
808 const char *border_left_subproperties[] = { "border-left-width", "border-left-style", "border-left-color", NULL };
809 const char *border_subproperties[] = { "border-top-width", "border-right-width", "border-bottom-width", "border-left-width",
810 "border-top-style", "border-right-style", "border-bottom-style", "border-left-style",
811 "border-top-color", "border-right-color", "border-bottom-color", "border-left-color",
812 "border-image-source", "border-image-slice", "border-image-width", "border-image-repeat", NULL };
813 const char *outline_subproperties[] = { "outline-width", "outline-style", "outline-color", NULL };
814 const char *background_subproperties[] = { "background-image", "background-repeat", "background-clip", "background-origin",
815 "background-color", NULL };
817 _gtk_css_shorthand_property_register ("font",
818 PANGO_TYPE_FONT_DESCRIPTION,
821 unpack_font_description,
822 pack_font_description);
823 _gtk_css_shorthand_property_register ("margin",
825 margin_subproperties,
829 _gtk_css_shorthand_property_register ("padding",
831 padding_subproperties,
835 _gtk_css_shorthand_property_register ("border-width",
837 border_width_subproperties,
841 _gtk_css_shorthand_property_register ("border-radius",
843 border_radius_subproperties,
845 unpack_border_radius,
847 _gtk_css_shorthand_property_register ("border-color",
849 border_color_subproperties,
851 unpack_to_everything,
853 _gtk_css_shorthand_property_register ("border-style",
854 GTK_TYPE_BORDER_STYLE,
855 border_style_subproperties,
857 unpack_to_everything,
859 _gtk_css_shorthand_property_register ("border-image",
861 border_image_subproperties,
865 _gtk_css_shorthand_property_register ("border-top",
867 border_top_subproperties,
871 _gtk_css_shorthand_property_register ("border-right",
873 border_right_subproperties,
877 _gtk_css_shorthand_property_register ("border-bottom",
879 border_bottom_subproperties,
883 _gtk_css_shorthand_property_register ("border-left",
885 border_left_subproperties,
889 _gtk_css_shorthand_property_register ("border",
891 border_subproperties,
895 _gtk_css_shorthand_property_register ("outline",
897 outline_subproperties,
901 _gtk_css_shorthand_property_register ("background",
903 background_subproperties,