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 if (_gtk_css_parser_try (parser, "currentcolor", TRUE))
164 g_value_init (&values[i], GTK_TYPE_CSS_SPECIAL_VALUE);
165 g_value_set_enum (&values[i], GTK_CSS_CURRENT_COLOR);
169 symbolic = _gtk_css_parser_read_symbolic_color (parser);
170 if (symbolic == NULL)
173 g_value_init (&values[i], GTK_TYPE_SYMBOLIC_COLOR);
174 g_value_set_boxed (&values[i], symbolic);
177 if (value_is_done_parsing (parser))
181 for (i++; i < 4; i++)
183 g_value_init (&values[i], G_VALUE_TYPE (&values[(i - 1) >> 1]));
184 g_value_copy (&values[(i - 1) >> 1], &values[i]);
191 parse_border_style (GtkCssShorthandProperty *shorthand,
193 GtkCssParser *parser,
196 GtkBorderStyle styles[4];
199 for (i = 0; i < 4; i++)
201 if (!_gtk_css_parser_try_enum (parser, GTK_TYPE_BORDER_STYLE, (int *)&styles[i]))
207 _gtk_css_parser_error (parser, "Expected a border style");
211 for (; i < G_N_ELEMENTS (styles); i++)
212 styles[i] = styles[(i - 1) >> 1];
214 for (i = 0; i < G_N_ELEMENTS (styles); i++)
216 g_value_init (&values[i], GTK_TYPE_BORDER_STYLE);
217 g_value_set_enum (&values[i], styles[i]);
224 parse_border_image (GtkCssShorthandProperty *shorthand,
226 GtkCssParser *parser,
231 if (_gtk_css_parser_try (parser, "none", TRUE))
235 image = _gtk_css_image_new_parse (parser, base);
239 g_value_init (&values[0], GTK_TYPE_CSS_IMAGE);
240 g_value_set_object (&values[0], image);
242 if (value_is_done_parsing (parser))
245 g_value_init (&values[1], GTK_TYPE_BORDER);
246 if (!_gtk_css_style_parse_value (&values[1], parser, base))
249 if (_gtk_css_parser_try (parser, "/", TRUE))
251 g_value_init (&values[2], GTK_TYPE_BORDER);
252 if (!_gtk_css_style_parse_value (&values[2], parser, base))
256 if (value_is_done_parsing (parser))
259 g_value_init (&values[3], GTK_TYPE_CSS_BORDER_IMAGE_REPEAT);
260 if (!_gtk_css_style_parse_value (&values[3], parser, base))
267 parse_border_side (GtkCssShorthandProperty *shorthand,
269 GtkCssParser *parser,
277 if (!G_IS_VALUE (&values[0]) &&
278 _gtk_css_parser_try_length (parser, &width))
280 g_value_init (&values[0], G_TYPE_INT);
281 g_value_set_int (&values[0], width);
283 else if (!G_IS_VALUE (&values[1]) &&
284 _gtk_css_parser_try_enum (parser, GTK_TYPE_BORDER_STYLE, &style))
286 g_value_init (&values[1], GTK_TYPE_BORDER_STYLE);
287 g_value_set_enum (&values[1], style);
289 else if (!G_IS_VALUE (&values[2]))
291 GtkSymbolicColor *symbolic;
293 symbolic = _gtk_css_parser_read_symbolic_color (parser);
294 if (symbolic == NULL)
297 g_value_init (&values[2], GTK_TYPE_SYMBOLIC_COLOR);
298 g_value_take_boxed (&values[2], symbolic);
302 /* We parsed everything and there's still stuff left?
303 * Pretend we didn't notice and let the normal code produce
304 * a 'junk at end of value' error */
308 while (!value_is_done_parsing (parser));
314 parse_border (GtkCssShorthandProperty *shorthand,
316 GtkCssParser *parser,
324 if (!G_IS_VALUE (&values[0]) &&
325 _gtk_css_parser_try_length (parser, &width))
327 g_value_init (&values[0], G_TYPE_INT);
328 g_value_init (&values[1], G_TYPE_INT);
329 g_value_init (&values[2], G_TYPE_INT);
330 g_value_init (&values[3], G_TYPE_INT);
331 g_value_set_int (&values[0], width);
332 g_value_set_int (&values[1], width);
333 g_value_set_int (&values[2], width);
334 g_value_set_int (&values[3], width);
336 else if (!G_IS_VALUE (&values[4]) &&
337 _gtk_css_parser_try_enum (parser, GTK_TYPE_BORDER_STYLE, &style))
339 g_value_init (&values[4], GTK_TYPE_BORDER_STYLE);
340 g_value_init (&values[5], GTK_TYPE_BORDER_STYLE);
341 g_value_init (&values[6], GTK_TYPE_BORDER_STYLE);
342 g_value_init (&values[7], GTK_TYPE_BORDER_STYLE);
343 g_value_set_enum (&values[4], style);
344 g_value_set_enum (&values[5], style);
345 g_value_set_enum (&values[6], style);
346 g_value_set_enum (&values[7], style);
348 else if (!G_IS_VALUE (&values[8]))
350 GtkSymbolicColor *symbolic;
352 symbolic = _gtk_css_parser_read_symbolic_color (parser);
353 if (symbolic == NULL)
356 g_value_init (&values[8], GTK_TYPE_SYMBOLIC_COLOR);
357 g_value_init (&values[9], GTK_TYPE_SYMBOLIC_COLOR);
358 g_value_init (&values[10], GTK_TYPE_SYMBOLIC_COLOR);
359 g_value_init (&values[11], GTK_TYPE_SYMBOLIC_COLOR);
360 g_value_set_boxed (&values[8], symbolic);
361 g_value_set_boxed (&values[9], symbolic);
362 g_value_set_boxed (&values[10], symbolic);
363 g_value_take_boxed (&values[11], symbolic);
367 /* We parsed everything and there's still stuff left?
368 * Pretend we didn't notice and let the normal code produce
369 * a 'junk at end of value' error */
373 while (!value_is_done_parsing (parser));
375 /* Note that border-image values are not set: according to the spec
376 they just need to be reset when using the border shorthand */
382 parse_font (GtkCssShorthandProperty *shorthand,
384 GtkCssParser *parser,
387 PangoFontDescription *desc;
391 str = _gtk_css_parser_read_value (parser);
395 desc = pango_font_description_from_string (str);
398 mask = pango_font_description_get_set_fields (desc);
400 if (mask & PANGO_FONT_MASK_FAMILY)
402 GPtrArray *strv = g_ptr_array_new ();
404 g_ptr_array_add (strv, g_strdup (pango_font_description_get_family (desc)));
405 g_ptr_array_add (strv, NULL);
406 g_value_init (&values[0], G_TYPE_STRV);
407 g_value_take_boxed (&values[0], g_ptr_array_free (strv, FALSE));
409 if (mask & PANGO_FONT_MASK_STYLE)
411 g_value_init (&values[1], PANGO_TYPE_STYLE);
412 g_value_set_enum (&values[1], pango_font_description_get_style (desc));
414 if (mask & PANGO_FONT_MASK_VARIANT)
416 g_value_init (&values[2], PANGO_TYPE_VARIANT);
417 g_value_set_enum (&values[2], pango_font_description_get_variant (desc));
419 if (mask & PANGO_FONT_MASK_WEIGHT)
421 g_value_init (&values[3], PANGO_TYPE_WEIGHT);
422 g_value_set_enum (&values[3], pango_font_description_get_weight (desc));
424 if (mask & PANGO_FONT_MASK_SIZE)
426 g_value_init (&values[4], G_TYPE_DOUBLE);
427 g_value_set_double (&values[4],
428 (double) pango_font_description_get_size (desc) / PANGO_SCALE);
431 pango_font_description_free (desc);
437 parse_background (GtkCssShorthandProperty *shorthand,
439 GtkCssParser *parser,
447 if (!G_IS_VALUE (&values[0]) &&
448 (_gtk_css_parser_has_prefix (parser, "none") ||
449 _gtk_css_image_can_parse (parser)))
453 if (_gtk_css_parser_try (parser, "none", TRUE))
457 image = _gtk_css_image_new_parse (parser, base);
462 g_value_init (&values[0], GTK_TYPE_CSS_IMAGE);
463 g_value_take_object (&values[0], image);
465 else if (!G_IS_VALUE (&values[1]) &&
466 _gtk_css_parser_try_enum (parser, GTK_TYPE_CSS_BACKGROUND_REPEAT, &enum_value))
468 if (enum_value <= GTK_CSS_BACKGROUND_REPEAT_MASK)
472 if (_gtk_css_parser_try_enum (parser, GTK_TYPE_CSS_BACKGROUND_REPEAT, &vertical))
474 if (vertical >= GTK_CSS_BACKGROUND_REPEAT_MASK)
476 _gtk_css_parser_error (parser, "Not a valid 2nd value for border-repeat");
480 enum_value |= vertical << GTK_CSS_BACKGROUND_REPEAT_SHIFT;
483 enum_value |= enum_value << GTK_CSS_BACKGROUND_REPEAT_SHIFT;
486 g_value_init (&values[1], GTK_TYPE_CSS_BACKGROUND_REPEAT);
487 g_value_set_enum (&values[1], enum_value);
489 else if ((!G_IS_VALUE (&values[2]) || !G_IS_VALUE (&values[3])) &&
490 _gtk_css_parser_try_enum (parser, GTK_TYPE_CSS_AREA, &enum_value))
492 guint idx = !G_IS_VALUE (&values[2]) ? 2 : 3;
493 g_value_init (&values[idx], GTK_TYPE_CSS_AREA);
494 g_value_set_enum (&values[idx], enum_value);
496 else if (!G_IS_VALUE (&values[4]))
498 GtkSymbolicColor *symbolic;
500 symbolic = _gtk_css_parser_read_symbolic_color (parser);
501 if (symbolic == NULL)
504 g_value_init (&values[4], GTK_TYPE_SYMBOLIC_COLOR);
505 g_value_take_boxed (&values[4], symbolic);
509 /* We parsed everything and there's still stuff left?
510 * Pretend we didn't notice and let the normal code produce
511 * a 'junk at end of value' error */
515 while (!value_is_done_parsing (parser));
523 unpack_border (GtkCssShorthandProperty *shorthand,
524 GtkStyleProperties *props,
528 GValue v = G_VALUE_INIT;
529 GtkBorder *border = g_value_get_boxed (value);
531 g_value_init (&v, G_TYPE_INT);
533 g_value_set_int (&v, border->top);
534 _gtk_style_property_assign (GTK_STYLE_PROPERTY (_gtk_css_shorthand_property_get_subproperty (shorthand, 0)), props, state, &v);
535 g_value_set_int (&v, border->right);
536 _gtk_style_property_assign (GTK_STYLE_PROPERTY (_gtk_css_shorthand_property_get_subproperty (shorthand, 1)), props, state, &v);
537 g_value_set_int (&v, border->bottom);
538 _gtk_style_property_assign (GTK_STYLE_PROPERTY (_gtk_css_shorthand_property_get_subproperty (shorthand, 2)), props, state, &v);
539 g_value_set_int (&v, border->left);
540 _gtk_style_property_assign (GTK_STYLE_PROPERTY (_gtk_css_shorthand_property_get_subproperty (shorthand, 3)), props, state, &v);
546 pack_border (GtkCssShorthandProperty *shorthand,
548 GtkStyleQueryFunc query_func,
551 GtkCssStyleProperty *prop;
555 prop = _gtk_css_shorthand_property_get_subproperty (shorthand, 0);
556 v = (* query_func) (_gtk_css_style_property_get_id (prop), query_data);
558 border.top = g_value_get_int (v);
559 prop = _gtk_css_shorthand_property_get_subproperty (shorthand, 1);
560 v = (* query_func) (_gtk_css_style_property_get_id (prop), query_data);
562 border.right = g_value_get_int (v);
563 prop = _gtk_css_shorthand_property_get_subproperty (shorthand, 2);
564 v = (* query_func) (_gtk_css_style_property_get_id (prop), query_data);
566 border.bottom = g_value_get_int (v);
567 prop = _gtk_css_shorthand_property_get_subproperty (shorthand, 3);
568 v = (* query_func) (_gtk_css_style_property_get_id (prop), query_data);
570 border.left = g_value_get_int (v);
572 g_value_set_boxed (value, &border);
576 unpack_border_radius (GtkCssShorthandProperty *shorthand,
577 GtkStyleProperties *props,
581 GtkCssBorderCornerRadius border;
582 GValue v = G_VALUE_INIT;
585 border.horizontal = border.vertical = g_value_get_int (value);
586 g_value_init (&v, GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
587 g_value_set_boxed (&v, &border);
589 for (i = 0; i < 4; i++)
590 _gtk_style_property_assign (GTK_STYLE_PROPERTY (_gtk_css_shorthand_property_get_subproperty (shorthand, i)), props, state, &v);
596 pack_border_radius (GtkCssShorthandProperty *shorthand,
598 GtkStyleQueryFunc query_func,
601 GtkCssBorderCornerRadius *top_left;
602 GtkCssStyleProperty *prop;
605 prop = GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("border-top-left-radius"));
606 v = (* query_func) (_gtk_css_style_property_get_id (prop), query_data);
609 top_left = g_value_get_boxed (v);
611 g_value_set_int (value, top_left->horizontal);
616 unpack_font_description (GtkCssShorthandProperty *shorthand,
617 GtkStyleProperties *props,
621 GtkStyleProperty *prop;
622 PangoFontDescription *description;
624 GValue v = G_VALUE_INIT;
626 /* For backwards compat, we only unpack values that are indeed set.
627 * For strict CSS conformance we need to unpack all of them.
628 * Note that we do set all of them in the parse function, so it
629 * will not have effects when parsing CSS files. It will though
630 * for custom style providers.
633 description = g_value_get_boxed (value);
636 mask = pango_font_description_get_set_fields (description);
640 if (mask & PANGO_FONT_MASK_FAMILY)
642 GPtrArray *strv = g_ptr_array_new ();
644 g_ptr_array_add (strv, g_strdup (pango_font_description_get_family (description)));
645 g_ptr_array_add (strv, NULL);
646 g_value_init (&v, G_TYPE_STRV);
647 g_value_take_boxed (&v, g_ptr_array_free (strv, FALSE));
649 prop = _gtk_style_property_lookup ("font-family");
650 _gtk_style_property_assign (prop, props, state, &v);
654 if (mask & PANGO_FONT_MASK_STYLE)
656 g_value_init (&v, PANGO_TYPE_STYLE);
657 g_value_set_enum (&v, pango_font_description_get_style (description));
659 prop = _gtk_style_property_lookup ("font-style");
660 _gtk_style_property_assign (prop, props, state, &v);
664 if (mask & PANGO_FONT_MASK_VARIANT)
666 g_value_init (&v, PANGO_TYPE_VARIANT);
667 g_value_set_enum (&v, pango_font_description_get_variant (description));
669 prop = _gtk_style_property_lookup ("font-variant");
670 _gtk_style_property_assign (prop, props, state, &v);
674 if (mask & PANGO_FONT_MASK_WEIGHT)
676 g_value_init (&v, PANGO_TYPE_WEIGHT);
677 g_value_set_enum (&v, pango_font_description_get_weight (description));
679 prop = _gtk_style_property_lookup ("font-weight");
680 _gtk_style_property_assign (prop, props, state, &v);
684 if (mask & PANGO_FONT_MASK_SIZE)
686 g_value_init (&v, G_TYPE_DOUBLE);
687 g_value_set_double (&v, (double) pango_font_description_get_size (description) / PANGO_SCALE);
689 prop = _gtk_style_property_lookup ("font-size");
690 _gtk_style_property_assign (prop, props, state, &v);
696 pack_font_description (GtkCssShorthandProperty *shorthand,
698 GtkStyleQueryFunc query_func,
701 PangoFontDescription *description;
704 description = pango_font_description_new ();
706 v = (* query_func) (_gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("font-family"))), query_data);
709 const char **families = g_value_get_boxed (v);
710 /* xxx: Can we set all the families here somehow? */
712 pango_font_description_set_family (description, families[0]);
715 v = (* query_func) (_gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("font-size"))), query_data);
717 pango_font_description_set_size (description, round (g_value_get_double (v) * PANGO_SCALE));
719 v = (* query_func) (_gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("font-style"))), query_data);
721 pango_font_description_set_style (description, g_value_get_enum (v));
723 v = (* query_func) (_gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("font-variant"))), query_data);
725 pango_font_description_set_variant (description, g_value_get_enum (v));
727 v = (* query_func) (_gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("font-weight"))), query_data);
729 pango_font_description_set_weight (description, g_value_get_enum (v));
731 g_value_take_boxed (value, description);
735 unpack_to_everything (GtkCssShorthandProperty *shorthand,
736 GtkStyleProperties *props,
740 GtkCssStyleProperty *prop;
743 n = _gtk_css_shorthand_property_get_n_subproperties (shorthand);
745 for (i = 0; i < n; i++)
747 prop = _gtk_css_shorthand_property_get_subproperty (shorthand, i);
748 _gtk_style_property_assign (GTK_STYLE_PROPERTY (prop), props, state, value);
753 pack_first_element (GtkCssShorthandProperty *shorthand,
755 GtkStyleQueryFunc query_func,
758 GtkCssStyleProperty *prop;
762 /* NB: This is a fallback for properties that originally were
763 * not used as shorthand. We just pick the first subproperty
764 * as a representative.
765 * Lesson learned: Don't query the shorthand, query the
766 * real properties instead. */
767 for (i = 0; i < _gtk_css_shorthand_property_get_n_subproperties (shorthand); i++)
769 prop = _gtk_css_shorthand_property_get_subproperty (shorthand, 0);
770 v = (* query_func) (_gtk_css_style_property_get_id (prop), query_data);
773 g_value_copy (v, value);
780 _gtk_css_shorthand_property_register (const char *name,
782 const char **subproperties,
783 GtkCssShorthandPropertyParseFunc parse_func,
784 GtkCssShorthandPropertyAssignFunc assign_func,
785 GtkCssShorthandPropertyQueryFunc query_func)
787 GtkCssShorthandProperty *node;
789 node = g_object_new (GTK_TYPE_CSS_SHORTHAND_PROPERTY,
791 "value-type", value_type,
792 "subproperties", subproperties,
795 node->parse = parse_func;
796 node->assign = assign_func;
797 node->query = query_func;
801 _gtk_css_shorthand_property_init_properties (void)
803 /* The order is important here, be careful when changing it */
804 const char *font_subproperties[] = { "font-family", "font-style", "font-variant", "font-weight", "font-size", NULL };
805 const char *margin_subproperties[] = { "margin-top", "margin-right", "margin-bottom", "margin-left", NULL };
806 const char *padding_subproperties[] = { "padding-top", "padding-right", "padding-bottom", "padding-left", NULL };
807 const char *border_width_subproperties[] = { "border-top-width", "border-right-width", "border-bottom-width", "border-left-width", NULL };
808 const char *border_radius_subproperties[] = { "border-top-left-radius", "border-top-right-radius",
809 "border-bottom-right-radius", "border-bottom-left-radius", NULL };
810 const char *border_color_subproperties[] = { "border-top-color", "border-right-color", "border-bottom-color", "border-left-color", NULL };
811 const char *border_style_subproperties[] = { "border-top-style", "border-right-style", "border-bottom-style", "border-left-style", NULL };
812 const char *border_image_subproperties[] = { "border-image-source", "border-image-slice", "border-image-width", "border-image-repeat", NULL };
813 const char *border_top_subproperties[] = { "border-top-width", "border-top-style", "border-top-color", NULL };
814 const char *border_right_subproperties[] = { "border-right-width", "border-right-style", "border-right-color", NULL };
815 const char *border_bottom_subproperties[] = { "border-bottom-width", "border-bottom-style", "border-bottom-color", NULL };
816 const char *border_left_subproperties[] = { "border-left-width", "border-left-style", "border-left-color", NULL };
817 const char *border_subproperties[] = { "border-top-width", "border-right-width", "border-bottom-width", "border-left-width",
818 "border-top-style", "border-right-style", "border-bottom-style", "border-left-style",
819 "border-top-color", "border-right-color", "border-bottom-color", "border-left-color",
820 "border-image-source", "border-image-slice", "border-image-width", "border-image-repeat", NULL };
821 const char *outline_subproperties[] = { "outline-width", "outline-style", "outline-color", NULL };
822 const char *background_subproperties[] = { "background-image", "background-repeat", "background-clip", "background-origin",
823 "background-color", NULL };
825 _gtk_css_shorthand_property_register ("font",
826 PANGO_TYPE_FONT_DESCRIPTION,
829 unpack_font_description,
830 pack_font_description);
831 _gtk_css_shorthand_property_register ("margin",
833 margin_subproperties,
837 _gtk_css_shorthand_property_register ("padding",
839 padding_subproperties,
843 _gtk_css_shorthand_property_register ("border-width",
845 border_width_subproperties,
849 _gtk_css_shorthand_property_register ("border-radius",
851 border_radius_subproperties,
853 unpack_border_radius,
855 _gtk_css_shorthand_property_register ("border-color",
857 border_color_subproperties,
859 unpack_to_everything,
861 _gtk_css_shorthand_property_register ("border-style",
862 GTK_TYPE_BORDER_STYLE,
863 border_style_subproperties,
865 unpack_to_everything,
867 _gtk_css_shorthand_property_register ("border-image",
869 border_image_subproperties,
873 _gtk_css_shorthand_property_register ("border-top",
875 border_top_subproperties,
879 _gtk_css_shorthand_property_register ("border-right",
881 border_right_subproperties,
885 _gtk_css_shorthand_property_register ("border-bottom",
887 border_bottom_subproperties,
891 _gtk_css_shorthand_property_register ("border-left",
893 border_left_subproperties,
897 _gtk_css_shorthand_property_register ("border",
899 border_subproperties,
903 _gtk_css_shorthand_property_register ("outline",
905 outline_subproperties,
909 _gtk_css_shorthand_property_register ("background",
911 background_subproperties,