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 "gtkcssstylefuncsprivate.h"
29 #include "gtkcsstypesprivate.h"
30 #include "gtkprivatetypebuiltins.h"
31 #include "gtkstylepropertiesprivate.h"
32 #include "gtksymboliccolorprivate.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_four_numbers (GtkCssShorthandProperty *shorthand,
54 GtkCssNumberParseFlags flags)
56 GtkCssNumber numbers[4];
59 for (i = 0; i < 4; i++)
61 if (!_gtk_css_parser_has_number (parser))
64 if (!_gtk_css_parser_read_number (parser,
72 _gtk_css_parser_error (parser, "Expected a length");
78 numbers[i] = numbers[(i - 1) >> 1];
81 for (i = 0; i < 4; i++)
83 g_value_init (&values[i], GTK_TYPE_CSS_NUMBER);
84 g_value_set_boxed (&values[i], &numbers[i]);
91 parse_margin (GtkCssShorthandProperty *shorthand,
96 return parse_four_numbers (shorthand,
99 GTK_CSS_NUMBER_AS_PIXELS
100 | GTK_CSS_PARSE_LENGTH);
104 parse_padding (GtkCssShorthandProperty *shorthand,
106 GtkCssParser *parser,
109 return parse_four_numbers (shorthand,
112 GTK_CSS_POSITIVE_ONLY
113 | GTK_CSS_NUMBER_AS_PIXELS
114 | GTK_CSS_PARSE_LENGTH);
118 parse_border_width (GtkCssShorthandProperty *shorthand,
120 GtkCssParser *parser,
123 return parse_four_numbers (shorthand,
126 GTK_CSS_POSITIVE_ONLY
127 | GTK_CSS_NUMBER_AS_PIXELS
128 | GTK_CSS_PARSE_LENGTH);
132 parse_border_radius (GtkCssShorthandProperty *shorthand,
134 GtkCssParser *parser,
137 GtkCssBorderCornerRadius borders[4];
140 for (i = 0; i < G_N_ELEMENTS (borders); i++)
142 if (!_gtk_css_parser_has_number (parser))
144 if (!_gtk_css_parser_read_number (parser,
145 &borders[i].horizontal,
146 GTK_CSS_POSITIVE_ONLY
147 | GTK_CSS_PARSE_PERCENT
148 | GTK_CSS_NUMBER_AS_PIXELS
149 | GTK_CSS_PARSE_LENGTH))
155 _gtk_css_parser_error (parser, "Expected a number");
159 /* The magic (i - 1) >> 1 below makes it take the correct value
160 * according to spec. Feel free to check the 4 cases */
161 for (; i < G_N_ELEMENTS (borders); i++)
162 borders[i].horizontal = borders[(i - 1) >> 1].horizontal;
164 if (_gtk_css_parser_try (parser, "/", TRUE))
166 for (i = 0; i < G_N_ELEMENTS (borders); i++)
168 if (!_gtk_css_parser_has_number (parser))
170 if (!_gtk_css_parser_read_number (parser,
171 &borders[i].vertical,
172 GTK_CSS_POSITIVE_ONLY
173 | GTK_CSS_PARSE_PERCENT
174 | GTK_CSS_NUMBER_AS_PIXELS
175 | GTK_CSS_PARSE_LENGTH))
181 _gtk_css_parser_error (parser, "Expected a number");
185 for (; i < G_N_ELEMENTS (borders); i++)
186 borders[i].vertical = borders[(i - 1) >> 1].vertical;
191 for (i = 0; i < G_N_ELEMENTS (borders); i++)
192 borders[i].vertical = borders[i].horizontal;
195 for (i = 0; i < G_N_ELEMENTS (borders); i++)
197 g_value_init (&values[i], GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
198 g_value_set_boxed (&values[i], &borders[i]);
205 parse_border_color (GtkCssShorthandProperty *shorthand,
207 GtkCssParser *parser,
210 GtkSymbolicColor *symbolic;
213 for (i = 0; i < 4; i++)
215 if (_gtk_css_parser_try (parser, "currentcolor", TRUE))
217 symbolic = gtk_symbolic_color_ref (_gtk_symbolic_color_get_current_color ());
221 symbolic = _gtk_css_parser_read_symbolic_color (parser);
222 if (symbolic == NULL)
226 g_value_init (&values[i], GTK_TYPE_SYMBOLIC_COLOR);
227 g_value_set_boxed (&values[i], symbolic);
229 if (value_is_done_parsing (parser))
233 for (i++; i < 4; i++)
235 g_value_init (&values[i], G_VALUE_TYPE (&values[(i - 1) >> 1]));
236 g_value_copy (&values[(i - 1) >> 1], &values[i]);
243 parse_border_style (GtkCssShorthandProperty *shorthand,
245 GtkCssParser *parser,
248 GtkBorderStyle styles[4];
251 for (i = 0; i < 4; i++)
253 if (!_gtk_css_parser_try_enum (parser, GTK_TYPE_BORDER_STYLE, (int *)&styles[i]))
259 _gtk_css_parser_error (parser, "Expected a border style");
263 for (; i < G_N_ELEMENTS (styles); i++)
264 styles[i] = styles[(i - 1) >> 1];
266 for (i = 0; i < G_N_ELEMENTS (styles); i++)
268 g_value_init (&values[i], GTK_TYPE_BORDER_STYLE);
269 g_value_set_enum (&values[i], styles[i]);
276 parse_border_image (GtkCssShorthandProperty *shorthand,
278 GtkCssParser *parser,
283 if (_gtk_css_parser_try (parser, "none", TRUE))
287 image = _gtk_css_image_new_parse (parser, base);
291 g_value_init (&values[0], GTK_TYPE_CSS_IMAGE);
292 g_value_set_object (&values[0], image);
294 if (value_is_done_parsing (parser))
297 g_value_init (&values[1], GTK_TYPE_BORDER);
298 if (!_gtk_css_style_parse_value (&values[1], parser, base))
301 if (_gtk_css_parser_try (parser, "/", TRUE))
303 g_value_init (&values[2], GTK_TYPE_BORDER);
304 if (!_gtk_css_style_parse_value (&values[2], parser, base))
308 if (value_is_done_parsing (parser))
311 g_value_init (&values[3], GTK_TYPE_CSS_BORDER_IMAGE_REPEAT);
312 if (!_gtk_css_style_parse_value (&values[3], parser, base))
319 parse_border_side (GtkCssShorthandProperty *shorthand,
321 GtkCssParser *parser,
328 if (!G_IS_VALUE (&values[0]) &&
329 _gtk_css_parser_has_number (parser))
332 if (!_gtk_css_parser_read_number (parser,
334 GTK_CSS_POSITIVE_ONLY
335 | GTK_CSS_NUMBER_AS_PIXELS
336 | GTK_CSS_PARSE_LENGTH))
339 g_value_init (&values[0], GTK_TYPE_CSS_NUMBER);
340 g_value_set_boxed (&values[0], &number);
342 else if (!G_IS_VALUE (&values[1]) &&
343 _gtk_css_parser_try_enum (parser, GTK_TYPE_BORDER_STYLE, &style))
345 g_value_init (&values[1], GTK_TYPE_BORDER_STYLE);
346 g_value_set_enum (&values[1], style);
348 else if (!G_IS_VALUE (&values[2]))
350 GtkSymbolicColor *symbolic;
352 symbolic = _gtk_css_parser_read_symbolic_color (parser);
353 if (symbolic == NULL)
356 g_value_init (&values[2], GTK_TYPE_SYMBOLIC_COLOR);
357 g_value_take_boxed (&values[2], symbolic);
361 /* We parsed everything and there's still stuff left?
362 * Pretend we didn't notice and let the normal code produce
363 * a 'junk at end of value' error */
367 while (!value_is_done_parsing (parser));
373 parse_border (GtkCssShorthandProperty *shorthand,
375 GtkCssParser *parser,
382 if (!G_IS_VALUE (&values[0]) &&
383 _gtk_css_parser_has_number (parser))
386 if (!_gtk_css_parser_read_number (parser,
388 GTK_CSS_POSITIVE_ONLY
389 | GTK_CSS_NUMBER_AS_PIXELS
390 | GTK_CSS_PARSE_LENGTH))
393 g_value_init (&values[0], GTK_TYPE_CSS_NUMBER);
394 g_value_init (&values[1], GTK_TYPE_CSS_NUMBER);
395 g_value_init (&values[2], GTK_TYPE_CSS_NUMBER);
396 g_value_init (&values[3], GTK_TYPE_CSS_NUMBER);
397 g_value_set_boxed (&values[0], &number);
398 g_value_set_boxed (&values[1], &number);
399 g_value_set_boxed (&values[2], &number);
400 g_value_set_boxed (&values[3], &number);
402 else if (!G_IS_VALUE (&values[4]) &&
403 _gtk_css_parser_try_enum (parser, GTK_TYPE_BORDER_STYLE, &style))
405 g_value_init (&values[4], GTK_TYPE_BORDER_STYLE);
406 g_value_init (&values[5], GTK_TYPE_BORDER_STYLE);
407 g_value_init (&values[6], GTK_TYPE_BORDER_STYLE);
408 g_value_init (&values[7], GTK_TYPE_BORDER_STYLE);
409 g_value_set_enum (&values[4], style);
410 g_value_set_enum (&values[5], style);
411 g_value_set_enum (&values[6], style);
412 g_value_set_enum (&values[7], style);
414 else if (!G_IS_VALUE (&values[8]))
416 GtkSymbolicColor *symbolic;
418 symbolic = _gtk_css_parser_read_symbolic_color (parser);
419 if (symbolic == NULL)
422 g_value_init (&values[8], GTK_TYPE_SYMBOLIC_COLOR);
423 g_value_init (&values[9], GTK_TYPE_SYMBOLIC_COLOR);
424 g_value_init (&values[10], GTK_TYPE_SYMBOLIC_COLOR);
425 g_value_init (&values[11], GTK_TYPE_SYMBOLIC_COLOR);
426 g_value_set_boxed (&values[8], symbolic);
427 g_value_set_boxed (&values[9], symbolic);
428 g_value_set_boxed (&values[10], symbolic);
429 g_value_take_boxed (&values[11], symbolic);
433 /* We parsed everything and there's still stuff left?
434 * Pretend we didn't notice and let the normal code produce
435 * a 'junk at end of value' error */
439 while (!value_is_done_parsing (parser));
441 /* Note that border-image values are not set: according to the spec
442 they just need to be reset when using the border shorthand */
448 parse_font (GtkCssShorthandProperty *shorthand,
450 GtkCssParser *parser,
453 PangoFontDescription *desc;
457 str = _gtk_css_parser_read_value (parser);
461 desc = pango_font_description_from_string (str);
464 mask = pango_font_description_get_set_fields (desc);
466 if (mask & PANGO_FONT_MASK_FAMILY)
468 GPtrArray *strv = g_ptr_array_new ();
470 g_ptr_array_add (strv, g_strdup (pango_font_description_get_family (desc)));
471 g_ptr_array_add (strv, NULL);
472 g_value_init (&values[0], G_TYPE_STRV);
473 g_value_take_boxed (&values[0], g_ptr_array_free (strv, FALSE));
475 if (mask & PANGO_FONT_MASK_STYLE)
477 g_value_init (&values[1], PANGO_TYPE_STYLE);
478 g_value_set_enum (&values[1], pango_font_description_get_style (desc));
480 if (mask & PANGO_FONT_MASK_VARIANT)
482 g_value_init (&values[2], PANGO_TYPE_VARIANT);
483 g_value_set_enum (&values[2], pango_font_description_get_variant (desc));
485 if (mask & PANGO_FONT_MASK_WEIGHT)
487 g_value_init (&values[3], PANGO_TYPE_WEIGHT);
488 g_value_set_enum (&values[3], pango_font_description_get_weight (desc));
490 if (mask & PANGO_FONT_MASK_SIZE)
492 g_value_init (&values[4], G_TYPE_DOUBLE);
493 g_value_set_double (&values[4],
494 (double) pango_font_description_get_size (desc) / PANGO_SCALE);
497 pango_font_description_free (desc);
503 parse_background (GtkCssShorthandProperty *shorthand,
505 GtkCssParser *parser,
513 if (!G_IS_VALUE (&values[0]) &&
514 (_gtk_css_parser_has_prefix (parser, "none") ||
515 _gtk_css_image_can_parse (parser)))
519 if (_gtk_css_parser_try (parser, "none", TRUE))
523 image = _gtk_css_image_new_parse (parser, base);
528 g_value_init (&values[0], GTK_TYPE_CSS_IMAGE);
529 g_value_take_object (&values[0], image);
531 else if (!G_IS_VALUE (&values[1]) &&
532 _gtk_css_parser_try_enum (parser, GTK_TYPE_CSS_BACKGROUND_REPEAT, &enum_value))
534 if (enum_value <= GTK_CSS_BACKGROUND_REPEAT_MASK)
538 if (_gtk_css_parser_try_enum (parser, GTK_TYPE_CSS_BACKGROUND_REPEAT, &vertical))
540 if (vertical >= GTK_CSS_BACKGROUND_REPEAT_MASK)
542 _gtk_css_parser_error (parser, "Not a valid 2nd value for border-repeat");
546 enum_value |= vertical << GTK_CSS_BACKGROUND_REPEAT_SHIFT;
549 enum_value |= enum_value << GTK_CSS_BACKGROUND_REPEAT_SHIFT;
552 g_value_init (&values[1], GTK_TYPE_CSS_BACKGROUND_REPEAT);
553 g_value_set_enum (&values[1], enum_value);
555 else if ((!G_IS_VALUE (&values[2]) || !G_IS_VALUE (&values[3])) &&
556 _gtk_css_parser_try_enum (parser, GTK_TYPE_CSS_AREA, &enum_value))
558 guint idx = !G_IS_VALUE (&values[2]) ? 2 : 3;
559 g_value_init (&values[idx], GTK_TYPE_CSS_AREA);
560 g_value_set_enum (&values[idx], enum_value);
562 else if (!G_IS_VALUE (&values[4]))
564 GtkSymbolicColor *symbolic;
566 symbolic = _gtk_css_parser_read_symbolic_color (parser);
567 if (symbolic == NULL)
570 g_value_init (&values[4], GTK_TYPE_SYMBOLIC_COLOR);
571 g_value_take_boxed (&values[4], symbolic);
575 /* We parsed everything and there's still stuff left?
576 * Pretend we didn't notice and let the normal code produce
577 * a 'junk at end of value' error */
581 while (!value_is_done_parsing (parser));
589 unpack_border (GtkCssShorthandProperty *shorthand,
590 GtkStyleProperties *props,
594 GValue v = G_VALUE_INIT;
595 GtkBorder *border = g_value_get_boxed (value);
597 g_value_init (&v, G_TYPE_INT);
599 g_value_set_int (&v, border->top);
600 _gtk_style_property_assign (GTK_STYLE_PROPERTY (_gtk_css_shorthand_property_get_subproperty (shorthand, 0)), props, state, &v);
601 g_value_set_int (&v, border->right);
602 _gtk_style_property_assign (GTK_STYLE_PROPERTY (_gtk_css_shorthand_property_get_subproperty (shorthand, 1)), props, state, &v);
603 g_value_set_int (&v, border->bottom);
604 _gtk_style_property_assign (GTK_STYLE_PROPERTY (_gtk_css_shorthand_property_get_subproperty (shorthand, 2)), props, state, &v);
605 g_value_set_int (&v, border->left);
606 _gtk_style_property_assign (GTK_STYLE_PROPERTY (_gtk_css_shorthand_property_get_subproperty (shorthand, 3)), props, state, &v);
612 pack_border (GtkCssShorthandProperty *shorthand,
614 GtkStyleQueryFunc query_func,
617 GtkCssStyleProperty *prop;
621 prop = _gtk_css_shorthand_property_get_subproperty (shorthand, 0);
622 v = (* query_func) (_gtk_css_style_property_get_id (prop), query_data);
624 border.top = g_value_get_int (v);
625 prop = _gtk_css_shorthand_property_get_subproperty (shorthand, 1);
626 v = (* query_func) (_gtk_css_style_property_get_id (prop), query_data);
628 border.right = g_value_get_int (v);
629 prop = _gtk_css_shorthand_property_get_subproperty (shorthand, 2);
630 v = (* query_func) (_gtk_css_style_property_get_id (prop), query_data);
632 border.bottom = g_value_get_int (v);
633 prop = _gtk_css_shorthand_property_get_subproperty (shorthand, 3);
634 v = (* query_func) (_gtk_css_style_property_get_id (prop), query_data);
636 border.left = g_value_get_int (v);
638 g_value_set_boxed (value, &border);
642 unpack_border_radius (GtkCssShorthandProperty *shorthand,
643 GtkStyleProperties *props,
647 GtkCssBorderCornerRadius border;
648 GValue v = G_VALUE_INIT;
651 _gtk_css_number_init (&border.horizontal, g_value_get_int (value), GTK_CSS_PX);
652 border.vertical = border.horizontal;
653 g_value_init (&v, GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
654 g_value_set_boxed (&v, &border);
656 for (i = 0; i < 4; i++)
657 _gtk_style_property_assign (GTK_STYLE_PROPERTY (_gtk_css_shorthand_property_get_subproperty (shorthand, i)), props, state, &v);
663 pack_border_radius (GtkCssShorthandProperty *shorthand,
665 GtkStyleQueryFunc query_func,
668 GtkCssBorderCornerRadius *top_left;
669 GtkCssStyleProperty *prop;
672 prop = GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("border-top-left-radius"));
673 v = (* query_func) (_gtk_css_style_property_get_id (prop), query_data);
676 top_left = g_value_get_boxed (v);
678 g_value_set_int (value, top_left->horizontal.value);
683 unpack_font_description (GtkCssShorthandProperty *shorthand,
684 GtkStyleProperties *props,
688 GtkStyleProperty *prop;
689 PangoFontDescription *description;
691 GValue v = G_VALUE_INIT;
693 /* For backwards compat, we only unpack values that are indeed set.
694 * For strict CSS conformance we need to unpack all of them.
695 * Note that we do set all of them in the parse function, so it
696 * will not have effects when parsing CSS files. It will though
697 * for custom style providers.
700 description = g_value_get_boxed (value);
703 mask = pango_font_description_get_set_fields (description);
707 if (mask & PANGO_FONT_MASK_FAMILY)
709 GPtrArray *strv = g_ptr_array_new ();
711 g_ptr_array_add (strv, g_strdup (pango_font_description_get_family (description)));
712 g_ptr_array_add (strv, NULL);
713 g_value_init (&v, G_TYPE_STRV);
714 g_value_take_boxed (&v, g_ptr_array_free (strv, FALSE));
716 prop = _gtk_style_property_lookup ("font-family");
717 _gtk_style_property_assign (prop, props, state, &v);
721 if (mask & PANGO_FONT_MASK_STYLE)
723 g_value_init (&v, PANGO_TYPE_STYLE);
724 g_value_set_enum (&v, pango_font_description_get_style (description));
726 prop = _gtk_style_property_lookup ("font-style");
727 _gtk_style_property_assign (prop, props, state, &v);
731 if (mask & PANGO_FONT_MASK_VARIANT)
733 g_value_init (&v, PANGO_TYPE_VARIANT);
734 g_value_set_enum (&v, pango_font_description_get_variant (description));
736 prop = _gtk_style_property_lookup ("font-variant");
737 _gtk_style_property_assign (prop, props, state, &v);
741 if (mask & PANGO_FONT_MASK_WEIGHT)
743 g_value_init (&v, PANGO_TYPE_WEIGHT);
744 g_value_set_enum (&v, pango_font_description_get_weight (description));
746 prop = _gtk_style_property_lookup ("font-weight");
747 _gtk_style_property_assign (prop, props, state, &v);
751 if (mask & PANGO_FONT_MASK_SIZE)
753 g_value_init (&v, G_TYPE_DOUBLE);
754 g_value_set_double (&v, (double) pango_font_description_get_size (description) / PANGO_SCALE);
756 prop = _gtk_style_property_lookup ("font-size");
757 _gtk_style_property_assign (prop, props, state, &v);
763 pack_font_description (GtkCssShorthandProperty *shorthand,
765 GtkStyleQueryFunc query_func,
768 PangoFontDescription *description;
771 description = pango_font_description_new ();
773 v = (* query_func) (_gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("font-family"))), query_data);
776 const char **families = g_value_get_boxed (v);
777 /* xxx: Can we set all the families here somehow? */
779 pango_font_description_set_family (description, families[0]);
782 v = (* query_func) (_gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("font-size"))), query_data);
784 pango_font_description_set_size (description, round (g_value_get_double (v) * PANGO_SCALE));
786 v = (* query_func) (_gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("font-style"))), query_data);
788 pango_font_description_set_style (description, g_value_get_enum (v));
790 v = (* query_func) (_gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("font-variant"))), query_data);
792 pango_font_description_set_variant (description, g_value_get_enum (v));
794 v = (* query_func) (_gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("font-weight"))), query_data);
796 pango_font_description_set_weight (description, g_value_get_enum (v));
798 g_value_take_boxed (value, description);
802 unpack_to_everything (GtkCssShorthandProperty *shorthand,
803 GtkStyleProperties *props,
807 GtkCssStyleProperty *prop;
810 n = _gtk_css_shorthand_property_get_n_subproperties (shorthand);
812 for (i = 0; i < n; i++)
814 prop = _gtk_css_shorthand_property_get_subproperty (shorthand, i);
815 _gtk_style_property_assign (GTK_STYLE_PROPERTY (prop), props, state, value);
820 pack_first_element (GtkCssShorthandProperty *shorthand,
822 GtkStyleQueryFunc query_func,
825 GtkCssStyleProperty *prop;
829 /* NB: This is a fallback for properties that originally were
830 * not used as shorthand. We just pick the first subproperty
831 * as a representative.
832 * Lesson learned: Don't query the shorthand, query the
833 * real properties instead. */
834 for (i = 0; i < _gtk_css_shorthand_property_get_n_subproperties (shorthand); i++)
836 prop = _gtk_css_shorthand_property_get_subproperty (shorthand, 0);
837 v = (* query_func) (_gtk_css_style_property_get_id (prop), query_data);
840 g_value_copy (v, value);
847 _gtk_css_shorthand_property_register (const char *name,
849 const char **subproperties,
850 GtkCssShorthandPropertyParseFunc parse_func,
851 GtkCssShorthandPropertyAssignFunc assign_func,
852 GtkCssShorthandPropertyQueryFunc query_func)
854 GtkCssShorthandProperty *node;
856 node = g_object_new (GTK_TYPE_CSS_SHORTHAND_PROPERTY,
858 "value-type", value_type,
859 "subproperties", subproperties,
862 node->parse = parse_func;
863 node->assign = assign_func;
864 node->query = query_func;
868 _gtk_css_shorthand_property_init_properties (void)
870 /* The order is important here, be careful when changing it */
871 const char *font_subproperties[] = { "font-family", "font-style", "font-variant", "font-weight", "font-size", NULL };
872 const char *margin_subproperties[] = { "margin-top", "margin-right", "margin-bottom", "margin-left", NULL };
873 const char *padding_subproperties[] = { "padding-top", "padding-right", "padding-bottom", "padding-left", NULL };
874 const char *border_width_subproperties[] = { "border-top-width", "border-right-width", "border-bottom-width", "border-left-width", NULL };
875 const char *border_radius_subproperties[] = { "border-top-left-radius", "border-top-right-radius",
876 "border-bottom-right-radius", "border-bottom-left-radius", NULL };
877 const char *border_color_subproperties[] = { "border-top-color", "border-right-color", "border-bottom-color", "border-left-color", NULL };
878 const char *border_style_subproperties[] = { "border-top-style", "border-right-style", "border-bottom-style", "border-left-style", NULL };
879 const char *border_image_subproperties[] = { "border-image-source", "border-image-slice", "border-image-width", "border-image-repeat", NULL };
880 const char *border_top_subproperties[] = { "border-top-width", "border-top-style", "border-top-color", NULL };
881 const char *border_right_subproperties[] = { "border-right-width", "border-right-style", "border-right-color", NULL };
882 const char *border_bottom_subproperties[] = { "border-bottom-width", "border-bottom-style", "border-bottom-color", NULL };
883 const char *border_left_subproperties[] = { "border-left-width", "border-left-style", "border-left-color", NULL };
884 const char *border_subproperties[] = { "border-top-width", "border-right-width", "border-bottom-width", "border-left-width",
885 "border-top-style", "border-right-style", "border-bottom-style", "border-left-style",
886 "border-top-color", "border-right-color", "border-bottom-color", "border-left-color",
887 "border-image-source", "border-image-slice", "border-image-width", "border-image-repeat", NULL };
888 const char *outline_subproperties[] = { "outline-width", "outline-style", "outline-color", NULL };
889 const char *background_subproperties[] = { "background-image", "background-repeat", "background-clip", "background-origin",
890 "background-color", NULL };
892 _gtk_css_shorthand_property_register ("font",
893 PANGO_TYPE_FONT_DESCRIPTION,
896 unpack_font_description,
897 pack_font_description);
898 _gtk_css_shorthand_property_register ("margin",
900 margin_subproperties,
904 _gtk_css_shorthand_property_register ("padding",
906 padding_subproperties,
910 _gtk_css_shorthand_property_register ("border-width",
912 border_width_subproperties,
916 _gtk_css_shorthand_property_register ("border-radius",
918 border_radius_subproperties,
920 unpack_border_radius,
922 _gtk_css_shorthand_property_register ("border-color",
924 border_color_subproperties,
926 unpack_to_everything,
928 _gtk_css_shorthand_property_register ("border-style",
929 GTK_TYPE_BORDER_STYLE,
930 border_style_subproperties,
932 unpack_to_everything,
934 _gtk_css_shorthand_property_register ("border-image",
936 border_image_subproperties,
940 _gtk_css_shorthand_property_register ("border-top",
942 border_top_subproperties,
946 _gtk_css_shorthand_property_register ("border-right",
948 border_right_subproperties,
952 _gtk_css_shorthand_property_register ("border-bottom",
954 border_bottom_subproperties,
958 _gtk_css_shorthand_property_register ("border-left",
960 border_left_subproperties,
964 _gtk_css_shorthand_property_register ("border",
966 border_subproperties,
970 _gtk_css_shorthand_property_register ("outline",
972 outline_subproperties,
976 _gtk_css_shorthand_property_register ("background",
978 background_subproperties,