1 /*
2 * Copyright © 2011 Red Hat Inc.
3 *
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.
8 *
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.
13 *
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/>.
16 *
17 * Authors: Benjamin Otte <otte@gnome.org>
18 */
19
20 #include "config.h"
21
22 #include "gtkcssshorthandpropertyprivate.h"
23
24 #include <cairo-gobject.h>
25 #include <math.h>
26
27 #include "gtkcssarrayvalueprivate.h"
28 #include "gtkcssbgsizevalueprivate.h"
29 #include "gtkcssbordervalueprivate.h"
30 #include "gtkcsscolorvalueprivate.h"
31 #include "gtkcsscornervalueprivate.h"
32 #include "gtkcsseasevalueprivate.h"
33 #include "gtkcssenumvalueprivate.h"
34 #include "gtkcssimageprivate.h"
35 #include "gtkcssimagevalueprivate.h"
36 #include "gtkcssnumbervalueprivate.h"
37 #include "gtkcsspositionvalueprivate.h"
38 #include "gtkcssrepeatvalueprivate.h"
39 #include "gtkcssstringvalueprivate.h"
40 #include "gtkcssstylefuncsprivate.h"
41 #include "gtkcssvalueprivate.h"
42 #include "deprecated/gtkstylepropertiesprivate.h"
43 #include "gtktypebuiltins.h"
44
45 /* this is in case round() is not provided by the compiler,
46 * such as in the case of C89 compilers, like MSVC
47 */
48 #include "fallback-c89.c"
49
50 /*** PARSING ***/
51
52 static gboolean
value_is_done_parsing(GtkCssParser * parser)53 value_is_done_parsing (GtkCssParser *parser)
54 {
55 return _gtk_css_parser_is_eof (parser) ||
56 _gtk_css_parser_begins_with (parser, ',') ||
57 _gtk_css_parser_begins_with (parser, ';') ||
58 _gtk_css_parser_begins_with (parser, '}');
59 }
60
61 static gboolean
parse_four_numbers(GtkCssShorthandProperty * shorthand,GtkCssValue ** values,GtkCssParser * parser,GtkCssNumberParseFlags flags)62 parse_four_numbers (GtkCssShorthandProperty *shorthand,
63 GtkCssValue **values,
64 GtkCssParser *parser,
65 GtkCssNumberParseFlags flags)
66 {
67 guint i;
68
69 for (i = 0; i < 4; i++)
70 {
71 if (!gtk_css_number_value_can_parse (parser))
72 break;
73
74 values[i] = _gtk_css_number_value_parse (parser, flags);
75 if (values[i] == NULL)
76 return FALSE;
77 }
78
79 if (i == 0)
80 {
81 _gtk_css_parser_error (parser, "Expected a length");
82 return FALSE;
83 }
84
85 for (; i < 4; i++)
86 {
87 values[i] = _gtk_css_value_ref (values[(i - 1) >> 1]);
88 }
89
90 return TRUE;
91 }
92
93 static gboolean
parse_margin(GtkCssShorthandProperty * shorthand,GtkCssValue ** values,GtkCssParser * parser)94 parse_margin (GtkCssShorthandProperty *shorthand,
95 GtkCssValue **values,
96 GtkCssParser *parser)
97 {
98 return parse_four_numbers (shorthand,
99 values,
100 parser,
101 GTK_CSS_NUMBER_AS_PIXELS
102 | GTK_CSS_PARSE_LENGTH);
103 }
104
105 static gboolean
parse_padding(GtkCssShorthandProperty * shorthand,GtkCssValue ** values,GtkCssParser * parser)106 parse_padding (GtkCssShorthandProperty *shorthand,
107 GtkCssValue **values,
108 GtkCssParser *parser)
109 {
110 return parse_four_numbers (shorthand,
111 values,
112 parser,
113 GTK_CSS_POSITIVE_ONLY
114 | GTK_CSS_NUMBER_AS_PIXELS
115 | GTK_CSS_PARSE_LENGTH);
116 }
117
118 static gboolean
parse_border_width(GtkCssShorthandProperty * shorthand,GtkCssValue ** values,GtkCssParser * parser)119 parse_border_width (GtkCssShorthandProperty *shorthand,
120 GtkCssValue **values,
121 GtkCssParser *parser)
122 {
123 return parse_four_numbers (shorthand,
124 values,
125 parser,
126 GTK_CSS_POSITIVE_ONLY
127 | GTK_CSS_NUMBER_AS_PIXELS
128 | GTK_CSS_PARSE_LENGTH);
129 }
130
131 static gboolean
parse_border_radius(GtkCssShorthandProperty * shorthand,GtkCssValue ** values,GtkCssParser * parser)132 parse_border_radius (GtkCssShorthandProperty *shorthand,
133 GtkCssValue **values,
134 GtkCssParser *parser)
135 {
136 GtkCssValue *x[4] = { NULL, }, *y[4] = { NULL, };
137 guint i;
138
139 for (i = 0; i < 4; i++)
140 {
141 if (!gtk_css_number_value_can_parse (parser))
142 break;
143 x[i] = _gtk_css_number_value_parse (parser,
144 GTK_CSS_POSITIVE_ONLY
145 | GTK_CSS_PARSE_PERCENT
146 | GTK_CSS_NUMBER_AS_PIXELS
147 | GTK_CSS_PARSE_LENGTH);
148 if (x[i] == NULL)
149 goto fail;
150 }
151
152 if (i == 0)
153 {
154 _gtk_css_parser_error (parser, "Expected a number");
155 goto fail;
156 }
157
158 /* The magic (i - 1) >> 1 below makes it take the correct value
159 * according to spec. Feel free to check the 4 cases
160 */
161 for (; i < 4; i++)
162 x[i] = _gtk_css_value_ref (x[(i - 1) >> 1]);
163
164 if (_gtk_css_parser_try (parser, "/", TRUE))
165 {
166 for (i = 0; i < 4; i++)
167 {
168 if (!gtk_css_number_value_can_parse (parser))
169 break;
170 y[i] = _gtk_css_number_value_parse (parser,
171 GTK_CSS_POSITIVE_ONLY
172 | GTK_CSS_PARSE_PERCENT
173 | GTK_CSS_NUMBER_AS_PIXELS
174 | GTK_CSS_PARSE_LENGTH);
175 if (y[i] == NULL)
176 goto fail;
177 }
178
179 if (i == 0)
180 {
181 _gtk_css_parser_error (parser, "Expected a number");
182 goto fail;
183 }
184
185 for (; i < 4; i++)
186 y[i] = _gtk_css_value_ref (y[(i - 1) >> 1]);
187 }
188 else
189 {
190 for (i = 0; i < 4; i++)
191 y[i] = _gtk_css_value_ref (x[i]);
192 }
193
194 for (i = 0; i < 4; i++)
195 {
196 values[i] = _gtk_css_corner_value_new (x[i], y[i]);
197 }
198
199 return TRUE;
200
201 fail:
202 for (i = 0; i < 4; i++)
203 {
204 if (x[i])
205 _gtk_css_value_unref (x[i]);
206 if (y[i])
207 _gtk_css_value_unref (y[i]);
208 }
209 return FALSE;
210 }
211
212 static gboolean
parse_border_color(GtkCssShorthandProperty * shorthand,GtkCssValue ** values,GtkCssParser * parser)213 parse_border_color (GtkCssShorthandProperty *shorthand,
214 GtkCssValue **values,
215 GtkCssParser *parser)
216 {
217 guint i;
218
219 for (i = 0; i < 4; i++)
220 {
221 values[i] = _gtk_css_color_value_parse (parser);
222 if (values[i] == NULL)
223 return FALSE;
224
225 if (value_is_done_parsing (parser))
226 break;
227 }
228
229 for (i++; i < 4; i++)
230 {
231 values[i] = _gtk_css_value_ref (values[(i - 1) >> 1]);
232 }
233
234 return TRUE;
235 }
236
237 static gboolean
parse_border_style(GtkCssShorthandProperty * shorthand,GtkCssValue ** values,GtkCssParser * parser)238 parse_border_style (GtkCssShorthandProperty *shorthand,
239 GtkCssValue **values,
240 GtkCssParser *parser)
241 {
242 guint i;
243
244 for (i = 0; i < 4; i++)
245 {
246 values[i] = _gtk_css_border_style_value_try_parse (parser);
247 if (values[i] == NULL)
248 break;
249 }
250
251 if (i == 0)
252 {
253 _gtk_css_parser_error (parser, "Expected a border style");
254 return FALSE;
255 }
256
257 for (; i < 4; i++)
258 values[i] = _gtk_css_value_ref (values[(i - 1) >> 1]);
259
260 return TRUE;
261 }
262
263 static gboolean
parse_border_image(GtkCssShorthandProperty * shorthand,GtkCssValue ** values,GtkCssParser * parser)264 parse_border_image (GtkCssShorthandProperty *shorthand,
265 GtkCssValue **values,
266 GtkCssParser *parser)
267 {
268 do
269 {
270 if (values[0] == NULL &&
271 (_gtk_css_parser_has_prefix (parser, "none") ||
272 _gtk_css_image_can_parse (parser)))
273 {
274 GtkCssImage *image;
275
276 if (_gtk_css_parser_try (parser, "none", TRUE))
277 image = NULL;
278 else
279 {
280 image = _gtk_css_image_new_parse (parser);
281 if (image == NULL)
282 return FALSE;
283 }
284
285 values[0] = _gtk_css_image_value_new (image);
286 }
287 else if (values[3] == NULL &&
288 (values[3] = _gtk_css_border_repeat_value_try_parse (parser)))
289 {
290 /* please move along */
291 }
292 else if (values[1] == NULL)
293 {
294 values[1] = _gtk_css_border_value_parse (parser,
295 GTK_CSS_PARSE_PERCENT
296 | GTK_CSS_PARSE_NUMBER
297 | GTK_CSS_POSITIVE_ONLY,
298 FALSE,
299 TRUE);
300 if (values[1] == NULL)
301 return FALSE;
302
303 if (_gtk_css_parser_try (parser, "/", TRUE))
304 {
305 values[2] = _gtk_css_border_value_parse (parser,
306 GTK_CSS_PARSE_PERCENT
307 | GTK_CSS_PARSE_LENGTH
308 | GTK_CSS_PARSE_NUMBER
309 | GTK_CSS_POSITIVE_ONLY,
310 TRUE,
311 FALSE);
312 if (values[2] == NULL)
313 return FALSE;
314 }
315 }
316 else
317 {
318 /* We parsed everything and there's still stuff left?
319 * Pretend we didn't notice and let the normal code produce
320 * a 'junk at end of value' error
321 */
322 break;
323 }
324 }
325 while (!value_is_done_parsing (parser));
326
327 return TRUE;
328 }
329
330 static gboolean
parse_border_side(GtkCssShorthandProperty * shorthand,GtkCssValue ** values,GtkCssParser * parser)331 parse_border_side (GtkCssShorthandProperty *shorthand,
332 GtkCssValue **values,
333 GtkCssParser *parser)
334 {
335 do
336 {
337 if (values[0] == NULL &&
338 gtk_css_number_value_can_parse (parser))
339 {
340 values[0] = _gtk_css_number_value_parse (parser,
341 GTK_CSS_POSITIVE_ONLY
342 | GTK_CSS_NUMBER_AS_PIXELS
343 | GTK_CSS_PARSE_LENGTH);
344 if (values[0] == NULL)
345 return FALSE;
346 }
347 else if (values[1] == NULL &&
348 (values[1] = _gtk_css_border_style_value_try_parse (parser)))
349 {
350 /* Nothing to do */
351 }
352 else if (values[2] == NULL)
353 {
354 values[2] = _gtk_css_color_value_parse (parser);
355 if (values[2] == NULL)
356 return FALSE;
357 }
358 else
359 {
360 /* We parsed and there's still stuff left?
361 * Pretend we didn't notice and let the normal code produce
362 * a 'junk at end of value' error
363 */
364 break;
365 }
366 }
367 while (!value_is_done_parsing (parser));
368
369 return TRUE;
370 }
371
372 static gboolean
parse_border(GtkCssShorthandProperty * shorthand,GtkCssValue ** values,GtkCssParser * parser)373 parse_border (GtkCssShorthandProperty *shorthand,
374 GtkCssValue **values,
375 GtkCssParser *parser)
376 {
377 do
378 {
379 if (values[0] == NULL &&
380 gtk_css_number_value_can_parse (parser))
381 {
382 values[0] = _gtk_css_number_value_parse (parser,
383 GTK_CSS_POSITIVE_ONLY
384 | GTK_CSS_NUMBER_AS_PIXELS
385 | GTK_CSS_PARSE_LENGTH);
386 if (values[0] == NULL)
387 return FALSE;
388 values[1] = _gtk_css_value_ref (values[0]);
389 values[2] = _gtk_css_value_ref (values[0]);
390 values[3] = _gtk_css_value_ref (values[0]);
391 }
392 else if (values[4] == NULL &&
393 (values[4] = _gtk_css_border_style_value_try_parse (parser)))
394 {
395 values[5] = _gtk_css_value_ref (values[4]);
396 values[6] = _gtk_css_value_ref (values[4]);
397 values[7] = _gtk_css_value_ref (values[4]);
398 }
399 else if (values[8] == NULL)
400 {
401 values[8] = _gtk_css_color_value_parse (parser);
402 if (values[8] == NULL)
403 return FALSE;
404
405 values[9] = _gtk_css_value_ref (values[8]);
406 values[10] = _gtk_css_value_ref (values[8]);
407 values[11] = _gtk_css_value_ref (values[8]);
408 }
409 else
410 {
411 /* We parsed everything and there's still stuff left?
412 * Pretend we didn't notice and let the normal code produce
413 * a 'junk at end of value' error
414 */
415 break;
416 }
417 }
418 while (!value_is_done_parsing (parser));
419
420 /* Note that border-image values are not set: according to the spec
421 * they just need to be reset when using the border shorthand
422 */
423
424 return TRUE;
425 }
426
427 static gboolean
parse_font_with_pango(GtkCssShorthandProperty * shorthand,GtkCssValue ** values,GtkCssParser * parser)428 parse_font_with_pango (GtkCssShorthandProperty *shorthand,
429 GtkCssValue **values,
430 GtkCssParser *parser)
431 {
432 PangoFontDescription *desc;
433 guint mask;
434 char *str;
435
436 str = _gtk_css_parser_read_value (parser);
437 if (str == NULL)
438 return FALSE;
439
440 desc = pango_font_description_from_string (str);
441 g_free (str);
442
443 mask = pango_font_description_get_set_fields (desc);
444
445 if (mask & PANGO_FONT_MASK_FAMILY)
446 {
447 values[0] = _gtk_css_array_value_new (_gtk_css_string_value_new (pango_font_description_get_family (desc)));
448 }
449 if (mask & PANGO_FONT_MASK_STYLE)
450 {
451 values[1] = _gtk_css_font_style_value_new (pango_font_description_get_style (desc));
452 }
453 if (mask & PANGO_FONT_MASK_VARIANT)
454 {
455 values[2] = _gtk_css_font_variant_value_new (pango_font_description_get_variant (desc));
456 }
457 if (mask & PANGO_FONT_MASK_WEIGHT)
458 {
459 values[3] = _gtk_css_font_weight_value_new (pango_font_description_get_weight (desc));
460 }
461 if (mask & PANGO_FONT_MASK_STRETCH)
462 {
463 values[4] = _gtk_css_font_stretch_value_new (pango_font_description_get_stretch (desc));
464 }
465 if (mask & PANGO_FONT_MASK_SIZE)
466 {
467 values[5] = _gtk_css_number_value_new ((double) pango_font_description_get_size (desc) / PANGO_SCALE, GTK_CSS_PX);
468 }
469
470 pango_font_description_free (desc);
471
472 return TRUE;
473 }
474
475 static gboolean
parse_font(GtkCssShorthandProperty * shorthand,GtkCssValue ** values,GtkCssParser * parser)476 parse_font (GtkCssShorthandProperty *shorthand,
477 GtkCssValue **values,
478 GtkCssParser *parser)
479 {
480 gboolean parsed_one;
481
482 do
483 {
484 parsed_one = FALSE;
485
486 if (values[1] == NULL)
487 {
488 values[1] = _gtk_css_font_style_value_try_parse (parser);
489 parsed_one = parsed_one || values[1] != NULL;
490 }
491
492 if (values[2] == NULL)
493 {
494 values[2] = _gtk_css_font_variant_value_try_parse (parser);
495 parsed_one = parsed_one || values[2] != NULL;
496 }
497
498 if (values[3] == NULL)
499 {
500 values[3] = _gtk_css_font_weight_value_try_parse (parser);
501 parsed_one = parsed_one || values[3] != NULL;
502 }
503
504 if (values[4] == NULL)
505 {
506 values[4] = _gtk_css_font_stretch_value_try_parse (parser);
507 parsed_one = parsed_one || values[4] != NULL;
508 }
509 }
510 while (parsed_one && !value_is_done_parsing (parser));
511
512 values[5] = gtk_css_font_size_value_parse (parser);
513
514 if (values[1] == NULL && values[2] == NULL && values[3] == NULL &&
515 values[4] == NULL && values[5] == NULL)
516 {
517 if (parse_font_with_pango (shorthand, values, parser))
518 {
519 _gtk_css_parser_error_full (parser,
520 GTK_CSS_PROVIDER_ERROR_DEPRECATED,
521 "Using Pango syntax for the font: style property is deprecated; please use CSS syntax");
522 return TRUE;
523 }
524 }
525
526 values[0] = gtk_css_font_family_value_parse (parser);
527
528 return values[0] != NULL && values[5] != NULL;
529 }
530
531 static gboolean
parse_one_background(GtkCssShorthandProperty * shorthand,GtkCssValue ** values,GtkCssParser * parser)532 parse_one_background (GtkCssShorthandProperty *shorthand,
533 GtkCssValue **values,
534 GtkCssParser *parser)
535 {
536 GtkCssValue *value = NULL;
537
538 do
539 {
540 /* the image part */
541 if (values[0] == NULL &&
542 (_gtk_css_parser_has_prefix (parser, "none") ||
543 _gtk_css_image_can_parse (parser)))
544 {
545 GtkCssImage *image;
546
547 if (_gtk_css_parser_try (parser, "none", TRUE))
548 image = NULL;
549 else
550 {
551 image = _gtk_css_image_new_parse (parser);
552 if (image == NULL)
553 return FALSE;
554 }
555
556 values[0] = _gtk_css_image_value_new (image);
557 }
558 else if (values[1] == NULL &&
559 (value = _gtk_css_position_value_try_parse (parser)))
560 {
561 values[1] = value;
562 value = NULL;
563
564 if (_gtk_css_parser_try (parser, "/", TRUE) &&
565 (value = _gtk_css_bg_size_value_parse (parser)))
566 {
567 values[2] = value;
568 value = NULL;
569 }
570 }
571 else if (values[3] == NULL &&
572 (value = _gtk_css_background_repeat_value_try_parse (parser)))
573 {
574 values[3] = value;
575 value = NULL;
576 }
577 else if ((values[4] == NULL || values[5] == NULL) &&
578 (value = _gtk_css_area_value_try_parse (parser)))
579 {
580 values[4] = value;
581
582 if (values[5] == NULL)
583 {
584 values[5] = values[4];
585 values[4] = NULL;
586 }
587 value = NULL;
588 }
589 else if (values[6] == NULL)
590 {
591 value = _gtk_css_color_value_parse (parser);
592 if (value == NULL)
593 values[6] = _gtk_css_value_ref (_gtk_css_style_property_get_initial_value
594 (_gtk_css_shorthand_property_get_subproperty (shorthand, 6)));
595 else
596 values[6] = value;
597
598 value = NULL;
599 }
600 else
601 {
602 /* We parsed everything and there's still stuff left?
603 * Pretend we didn't notice and let the normal code produce
604 * a 'junk at end of value' error
605 */
606 break;
607 }
608 }
609 while (!value_is_done_parsing (parser));
610
611 if (values[5] != NULL && values[4] == NULL)
612 values[4] = _gtk_css_value_ref (values[5]);
613
614 return TRUE;
615 }
616
617 static gboolean
parse_background(GtkCssShorthandProperty * shorthand,GtkCssValue ** values,GtkCssParser * parser)618 parse_background (GtkCssShorthandProperty *shorthand,
619 GtkCssValue **values,
620 GtkCssParser *parser)
621 {
622 GtkCssValue *step_values[7];
623 GPtrArray *arrays[6];
624 guint i;
625
626 for (i = 0; i < 6; i++)
627 {
628 arrays[i] = g_ptr_array_new ();
629 step_values[i] = NULL;
630 }
631
632 step_values[6] = NULL;
633
634 do {
635 if (!parse_one_background (shorthand, step_values, parser))
636 {
637 for (i = 0; i < 6; i++)
638 {
639 g_ptr_array_set_free_func (arrays[i], (GDestroyNotify) _gtk_css_value_unref);
640 g_ptr_array_unref (arrays[i]);
641 }
642 return FALSE;
643 }
644
645 for (i = 0; i < 6; i++)
646 {
647 if (step_values[i] == NULL)
648 {
649 GtkCssValue *initial = _gtk_css_style_property_get_initial_value (
650 _gtk_css_shorthand_property_get_subproperty (shorthand, i));
651 step_values[i] = _gtk_css_value_ref (_gtk_css_array_value_get_nth (initial, 0));
652 }
653
654 g_ptr_array_add (arrays[i], step_values[i]);
655 step_values[i] = NULL;
656 }
657 } while (_gtk_css_parser_try (parser, ",", TRUE));
658
659 for (i = 0; i < 6; i++)
660 {
661 values[i] = _gtk_css_array_value_new_from_array ((GtkCssValue **) arrays[i]->pdata, arrays[i]->len);
662 g_ptr_array_unref (arrays[i]);
663 }
664
665 values[6] = step_values[6];
666
667 return TRUE;
668 }
669
670 static gboolean
parse_one_transition(GtkCssShorthandProperty * shorthand,GtkCssValue ** values,GtkCssParser * parser)671 parse_one_transition (GtkCssShorthandProperty *shorthand,
672 GtkCssValue **values,
673 GtkCssParser *parser)
674 {
675 do
676 {
677 /* the image part */
678 if (values[2] == NULL &&
679 gtk_css_number_value_can_parse (parser) && !_gtk_css_parser_begins_with (parser, '-'))
680 {
681 GtkCssValue *number = _gtk_css_number_value_parse (parser, GTK_CSS_PARSE_TIME);
682
683 if (number == NULL)
684 return FALSE;
685
686 if (values[1] == NULL)
687 values[1] = number;
688 else
689 values[2] = number;
690 }
691 else if (values[3] == NULL &&
692 _gtk_css_ease_value_can_parse (parser))
693 {
694 values[3] = _gtk_css_ease_value_parse (parser);
695
696 if (values[3] == NULL)
697 return FALSE;
698 }
699 else if (values[0] == NULL)
700 {
701 values[0] = _gtk_css_ident_value_try_parse (parser);
702 if (values[0] == NULL)
703 {
704 _gtk_css_parser_error (parser, "Unknown value for property");
705 return FALSE;
706 }
707
708 }
709 else
710 {
711 /* We parsed everything and there's still stuff left?
712 * Pretend we didn't notice and let the normal code produce
713 * a 'junk at end of value' error
714 */
715 break;
716 }
717 }
718 while (!value_is_done_parsing (parser));
719
720 return TRUE;
721 }
722
723 static gboolean
parse_transition(GtkCssShorthandProperty * shorthand,GtkCssValue ** values,GtkCssParser * parser)724 parse_transition (GtkCssShorthandProperty *shorthand,
725 GtkCssValue **values,
726 GtkCssParser *parser)
727 {
728 GtkCssValue *step_values[4];
729 GPtrArray *arrays[4];
730 guint i;
731
732 for (i = 0; i < 4; i++)
733 {
734 arrays[i] = g_ptr_array_new ();
735 step_values[i] = NULL;
736 }
737
738 do {
739 if (!parse_one_transition (shorthand, step_values, parser))
740 {
741 for (i = 0; i < 4; i++)
742 {
743 g_ptr_array_set_free_func (arrays[i], (GDestroyNotify) _gtk_css_value_unref);
744 g_ptr_array_unref (arrays[i]);
745 }
746 return FALSE;
747 }
748
749 for (i = 0; i < 4; i++)
750 {
751 if (step_values[i] == NULL)
752 {
753 GtkCssValue *initial = _gtk_css_style_property_get_initial_value (
754 _gtk_css_shorthand_property_get_subproperty (shorthand, i));
755 step_values[i] = _gtk_css_value_ref (_gtk_css_array_value_get_nth (initial, 0));
756 }
757
758 g_ptr_array_add (arrays[i], step_values[i]);
759 step_values[i] = NULL;
760 }
761 } while (_gtk_css_parser_try (parser, ",", TRUE));
762
763 for (i = 0; i < 4; i++)
764 {
765 values[i] = _gtk_css_array_value_new_from_array ((GtkCssValue **) arrays[i]->pdata, arrays[i]->len);
766 g_ptr_array_unref (arrays[i]);
767 }
768
769 return TRUE;
770 }
771
772 static gboolean
parse_one_animation(GtkCssShorthandProperty * shorthand,GtkCssValue ** values,GtkCssParser * parser)773 parse_one_animation (GtkCssShorthandProperty *shorthand,
774 GtkCssValue **values,
775 GtkCssParser *parser)
776 {
777 do
778 {
779 if (values[1] == NULL && _gtk_css_parser_try (parser, "infinite", TRUE))
780 {
781 values[1] = _gtk_css_number_value_new (HUGE_VAL, GTK_CSS_NUMBER);
782 }
783 else if ((values[1] == NULL || values[3] == NULL) &&
784 gtk_css_number_value_can_parse (parser))
785 {
786 GtkCssValue *value;
787
788 value = _gtk_css_number_value_parse (parser,
789 GTK_CSS_POSITIVE_ONLY
790 | (values[1] == NULL ? GTK_CSS_PARSE_NUMBER : 0)
791 | (values[3] == NULL ? GTK_CSS_PARSE_TIME : 0));
792 if (value == NULL)
793 return FALSE;
794
795 if (gtk_css_number_value_get_dimension (value) == GTK_CSS_DIMENSION_NUMBER)
796 values[1] = value;
797 else if (values[2] == NULL)
798 values[2] = value;
799 else
800 values[3] = value;
801 }
802 else if (values[4] == NULL &&
803 _gtk_css_ease_value_can_parse (parser))
804 {
805 values[4] = _gtk_css_ease_value_parse (parser);
806
807 if (values[4] == NULL)
808 return FALSE;
809 }
810 else if (values[5] == NULL &&
811 (values[5] = _gtk_css_direction_value_try_parse (parser)))
812 {
813 /* nothing to do */
814 }
815 else if (values[6] == NULL &&
816 (values[6] = _gtk_css_fill_mode_value_try_parse (parser)))
817 {
818 /* nothing to do */
819 }
820 else if (values[0] == NULL &&
821 (values[0] = _gtk_css_ident_value_try_parse (parser)))
822 {
823 /* nothing to do */
824 /* keep in mind though that this needs to come last as fill modes, directions
825 * etc are valid idents */
826 }
827 else
828 {
829 /* We parsed everything and there's still stuff left?
830 * Pretend we didn't notice and let the normal code produce
831 * a 'junk at end of value' error */
832 break;
833 }
834 }
835 while (!value_is_done_parsing (parser));
836
837 return TRUE;
838 }
839
840 static gboolean
parse_animation(GtkCssShorthandProperty * shorthand,GtkCssValue ** values,GtkCssParser * parser)841 parse_animation (GtkCssShorthandProperty *shorthand,
842 GtkCssValue **values,
843 GtkCssParser *parser)
844 {
845 GtkCssValue *step_values[7];
846 GPtrArray *arrays[7];
847 guint i;
848
849 for (i = 0; i < 7; i++)
850 {
851 arrays[i] = g_ptr_array_new ();
852 step_values[i] = NULL;
853 }
854
855 do {
856 if (!parse_one_animation (shorthand, step_values, parser))
857 {
858 for (i = 0; i < 7; i++)
859 {
860 g_ptr_array_set_free_func (arrays[i], (GDestroyNotify) _gtk_css_value_unref);
861 g_ptr_array_unref (arrays[i]);
862 }
863 return FALSE;
864 }
865
866 for (i = 0; i < 7; i++)
867 {
868 if (step_values[i] == NULL)
869 {
870 GtkCssValue *initial = _gtk_css_style_property_get_initial_value (
871 _gtk_css_shorthand_property_get_subproperty (shorthand, i));
872 step_values[i] = _gtk_css_value_ref (_gtk_css_array_value_get_nth (initial, 0));
873 }
874
875 g_ptr_array_add (arrays[i], step_values[i]);
876 step_values[i] = NULL;
877 }
878 } while (_gtk_css_parser_try (parser, ",", TRUE));
879
880 for (i = 0; i < 7; i++)
881 {
882 values[i] = _gtk_css_array_value_new_from_array ((GtkCssValue **) arrays[i]->pdata, arrays[i]->len);
883 g_ptr_array_unref (arrays[i]);
884 }
885
886 return TRUE;
887 }
888
889 static gboolean
parse_text_decoration(GtkCssShorthandProperty * shorthand,GtkCssValue ** values,GtkCssParser * parser)890 parse_text_decoration (GtkCssShorthandProperty *shorthand,
891 GtkCssValue **values,
892 GtkCssParser *parser)
893 {
894 do
895 {
896 if (values[0] == NULL &&
897 (values[0] = _gtk_css_text_decoration_line_value_try_parse (parser)))
898 {
899 if (values[0] == NULL)
900 return FALSE;
901 }
902 else if (values[1] == NULL &&
903 (values[1] = _gtk_css_text_decoration_style_value_try_parse (parser)))
904 {
905 if (values[1] == NULL)
906 return FALSE;
907 }
908 else if (values[2] == NULL)
909 {
910 values[2] = _gtk_css_color_value_parse (parser);
911 if (values[2] == NULL)
912 return FALSE;
913 }
914 else
915 {
916 /* We parsed and there's still stuff left?
917 * Pretend we didn't notice and let the normal code produce
918 * a 'junk at end of value' error */
919 break;
920 }
921 }
922 while (!value_is_done_parsing (parser));
923
924 return TRUE;
925 }
926
927 static gboolean
parse_all(GtkCssShorthandProperty * shorthand,GtkCssValue ** values,GtkCssParser * parser)928 parse_all (GtkCssShorthandProperty *shorthand,
929 GtkCssValue **values,
930 GtkCssParser *parser)
931 {
932 _gtk_css_parser_error (parser, "The 'all' property can only be set to 'initial', 'inherit' or 'unset'");
933 return FALSE;
934 }
935
936 /*** PACKING ***/
937
938 static void
unpack_border(GtkCssShorthandProperty * shorthand,GtkStyleProperties * props,GtkStateFlags state,const GValue * value)939 unpack_border (GtkCssShorthandProperty *shorthand,
940 GtkStyleProperties *props,
941 GtkStateFlags state,
942 const GValue *value)
943 {
944 GValue v = G_VALUE_INIT;
945 GtkBorder *border = g_value_get_boxed (value);
946
947 g_value_init (&v, G_TYPE_INT);
948
949 g_value_set_int (&v, border->top);
950 _gtk_style_property_assign (GTK_STYLE_PROPERTY (_gtk_css_shorthand_property_get_subproperty (shorthand, 0)), props, state, &v);
951 g_value_set_int (&v, border->right);
952 _gtk_style_property_assign (GTK_STYLE_PROPERTY (_gtk_css_shorthand_property_get_subproperty (shorthand, 1)), props, state, &v);
953 g_value_set_int (&v, border->bottom);
954 _gtk_style_property_assign (GTK_STYLE_PROPERTY (_gtk_css_shorthand_property_get_subproperty (shorthand, 2)), props, state, &v);
955 g_value_set_int (&v, border->left);
956 _gtk_style_property_assign (GTK_STYLE_PROPERTY (_gtk_css_shorthand_property_get_subproperty (shorthand, 3)), props, state, &v);
957
958 g_value_unset (&v);
959 }
960
961 static void
pack_border(GtkCssShorthandProperty * shorthand,GValue * value,GtkStyleQueryFunc query_func,gpointer query_data)962 pack_border (GtkCssShorthandProperty *shorthand,
963 GValue *value,
964 GtkStyleQueryFunc query_func,
965 gpointer query_data)
966 {
967 GtkCssStyleProperty *prop;
968 GtkBorder border;
969 GValue v;
970
971 prop = _gtk_css_shorthand_property_get_subproperty (shorthand, 0);
972 _gtk_style_property_query (GTK_STYLE_PROPERTY (prop), &v, query_func, query_data);
973 border.top = g_value_get_int (&v);
974 g_value_unset (&v);
975
976 prop = _gtk_css_shorthand_property_get_subproperty (shorthand, 1);
977 _gtk_style_property_query (GTK_STYLE_PROPERTY (prop), &v, query_func, query_data);
978 border.right = g_value_get_int (&v);
979 g_value_unset (&v);
980
981 prop = _gtk_css_shorthand_property_get_subproperty (shorthand, 2);
982 _gtk_style_property_query (GTK_STYLE_PROPERTY (prop), &v, query_func, query_data);
983 border.bottom = g_value_get_int (&v);
984 g_value_unset (&v);
985
986 prop = _gtk_css_shorthand_property_get_subproperty (shorthand, 3);
987 _gtk_style_property_query (GTK_STYLE_PROPERTY (prop), &v, query_func, query_data);
988 border.left = g_value_get_int (&v);
989 g_value_unset (&v);
990
991 g_value_init (value, GTK_TYPE_BORDER);
992 g_value_set_boxed (value, &border);
993 }
994
995 static void
unpack_border_radius(GtkCssShorthandProperty * shorthand,GtkStyleProperties * props,GtkStateFlags state,const GValue * value)996 unpack_border_radius (GtkCssShorthandProperty *shorthand,
997 GtkStyleProperties *props,
998 GtkStateFlags state,
999 const GValue *value)
1000 {
1001 GtkCssValue *css_value;
1002 guint i;
1003
1004 css_value = _gtk_css_corner_value_new (_gtk_css_number_value_new (g_value_get_int (value), GTK_CSS_PX),
1005 _gtk_css_number_value_new (g_value_get_int (value), GTK_CSS_PX));
1006
1007 for (i = 0; i < 4; i++)
1008 _gtk_style_properties_set_property_by_property (props,
1009 _gtk_css_shorthand_property_get_subproperty (shorthand, i),
1010 state,
1011 css_value);
1012
1013 _gtk_css_value_unref (css_value);
1014 }
1015
1016 static void
pack_border_radius(GtkCssShorthandProperty * shorthand,GValue * value,GtkStyleQueryFunc query_func,gpointer query_data)1017 pack_border_radius (GtkCssShorthandProperty *shorthand,
1018 GValue *value,
1019 GtkStyleQueryFunc query_func,
1020 gpointer query_data)
1021 {
1022 GtkCssStyleProperty *prop;
1023 GtkCssValue *v;
1024 int i = 0;
1025
1026 prop = GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("border-top-left-radius"));
1027 v = (* query_func) (_gtk_css_style_property_get_id (prop), query_data);
1028 if (v)
1029 i = _gtk_css_corner_value_get_x (v, 100);
1030
1031 g_value_init (value, G_TYPE_INT);
1032 g_value_set_int (value, i);
1033 }
1034
1035 static void
unpack_font_description(GtkCssShorthandProperty * shorthand,GtkStyleProperties * props,GtkStateFlags state,const GValue * value)1036 unpack_font_description (GtkCssShorthandProperty *shorthand,
1037 GtkStyleProperties *props,
1038 GtkStateFlags state,
1039 const GValue *value)
1040 {
1041 GtkStyleProperty *prop;
1042 PangoFontDescription *description;
1043 PangoFontMask mask;
1044 GValue v = G_VALUE_INIT;
1045
1046 /* For backwards compat, we only unpack values that are indeed set.
1047 * For strict CSS conformance we need to unpack all of them.
1048 * Note that we do set all of them in the parse function, so it
1049 * will not have effects when parsing CSS files. It will though
1050 * for custom style providers.
1051 */
1052
1053 description = g_value_get_boxed (value);
1054
1055 if (description)
1056 mask = pango_font_description_get_set_fields (description);
1057 else
1058 mask = 0;
1059
1060 if (mask & PANGO_FONT_MASK_FAMILY)
1061 {
1062 GPtrArray *strv = g_ptr_array_new ();
1063
1064 g_ptr_array_add (strv, g_strdup (pango_font_description_get_family (description)));
1065 g_ptr_array_add (strv, NULL);
1066 g_value_init (&v, G_TYPE_STRV);
1067 g_value_take_boxed (&v, g_ptr_array_free (strv, FALSE));
1068
1069 prop = _gtk_style_property_lookup ("font-family");
1070 _gtk_style_property_assign (prop, props, state, &v);
1071 g_value_unset (&v);
1072 }
1073
1074 if (mask & PANGO_FONT_MASK_STYLE)
1075 {
1076 g_value_init (&v, PANGO_TYPE_STYLE);
1077 g_value_set_enum (&v, pango_font_description_get_style (description));
1078
1079 prop = _gtk_style_property_lookup ("font-style");
1080 _gtk_style_property_assign (prop, props, state, &v);
1081 g_value_unset (&v);
1082 }
1083
1084 if (mask & PANGO_FONT_MASK_VARIANT)
1085 {
1086 g_value_init (&v, PANGO_TYPE_VARIANT);
1087 g_value_set_enum (&v, pango_font_description_get_variant (description));
1088
1089 prop = _gtk_style_property_lookup ("font-variant");
1090 _gtk_style_property_assign (prop, props, state, &v);
1091 g_value_unset (&v);
1092 }
1093
1094 if (mask & PANGO_FONT_MASK_WEIGHT)
1095 {
1096 g_value_init (&v, PANGO_TYPE_WEIGHT);
1097 g_value_set_enum (&v, pango_font_description_get_weight (description));
1098
1099 prop = _gtk_style_property_lookup ("font-weight");
1100 _gtk_style_property_assign (prop, props, state, &v);
1101 g_value_unset (&v);
1102 }
1103
1104 if (mask & PANGO_FONT_MASK_STRETCH)
1105 {
1106 g_value_init (&v, PANGO_TYPE_STRETCH);
1107 g_value_set_enum (&v, pango_font_description_get_stretch (description));
1108
1109 prop = _gtk_style_property_lookup ("font-stretch");
1110 _gtk_style_property_assign (prop, props, state, &v);
1111 g_value_unset (&v);
1112 }
1113
1114 if (mask & PANGO_FONT_MASK_SIZE)
1115 {
1116 double size;
1117
1118 g_value_init (&v, G_TYPE_DOUBLE);
1119 size = pango_font_description_get_size (description) / PANGO_SCALE;
1120 if (!pango_font_description_get_size_is_absolute (description))
1121 {
1122 double dpi = gdk_screen_get_resolution (gdk_screen_get_default ());
1123 if (dpi <= 0.0)
1124 dpi = 96.0;
1125 size = size * dpi / 72.0;
1126 }
1127 g_value_set_double (&v, size);
1128 prop = _gtk_style_property_lookup ("font-size");
1129 _gtk_style_property_assign (prop, props, state, &v);
1130 g_value_unset (&v);
1131 }
1132 }
1133
1134 static void
pack_font_description(GtkCssShorthandProperty * shorthand,GValue * value,GtkStyleQueryFunc query_func,gpointer query_data)1135 pack_font_description (GtkCssShorthandProperty *shorthand,
1136 GValue *value,
1137 GtkStyleQueryFunc query_func,
1138 gpointer query_data)
1139 {
1140 PangoFontDescription *description;
1141 GtkCssValue *v;
1142 double dpi;
1143
1144 description = pango_font_description_new ();
1145
1146 v = (* query_func) (_gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("font-family"))), query_data);
1147 if (v)
1148 {
1149 int i;
1150 GString *s = g_string_new ("");
1151
1152 for (i = 0; i < _gtk_css_array_value_get_n_values (v); i++)
1153 {
1154 if (i > 0)
1155 g_string_append (s, ",");
1156 g_string_append (s, _gtk_css_string_value_get (_gtk_css_array_value_get_nth (v, i)));
1157 }
1158
1159 pango_font_description_set_family (description, s->str);
1160 g_string_free (s, TRUE);
1161 }
1162
1163 v = (* query_func) (_gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("-gtk-dpi"))), query_data);
1164 dpi = _gtk_css_number_value_get (v, 96);
1165 v = (* query_func) (_gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("font-size"))), query_data);
1166 if (v)
1167 pango_font_description_set_size (description, round (_gtk_css_number_value_get (v, 100) * PANGO_SCALE * 72 / dpi));
1168
1169 v = (* query_func) (_gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("font-style"))), query_data);
1170 if (v)
1171 pango_font_description_set_style (description, _gtk_css_font_style_value_get (v));
1172
1173 v = (* query_func) (_gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("font-variant"))), query_data);
1174 if (v)
1175 pango_font_description_set_variant (description, _gtk_css_font_variant_value_get (v));
1176
1177 v = (* query_func) (_gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("font-weight"))), query_data);
1178 if (v)
1179 pango_font_description_set_weight (description, _gtk_css_font_weight_value_get (v));
1180
1181 v = (* query_func) (_gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("font-stretch"))), query_data);
1182 if (v)
1183 pango_font_description_set_stretch (description, _gtk_css_font_stretch_value_get (v));
1184
1185 g_value_init (value, PANGO_TYPE_FONT_DESCRIPTION);
1186 g_value_take_boxed (value, description);
1187 }
1188
1189 static void
unpack_to_everything(GtkCssShorthandProperty * shorthand,GtkStyleProperties * props,GtkStateFlags state,const GValue * value)1190 unpack_to_everything (GtkCssShorthandProperty *shorthand,
1191 GtkStyleProperties *props,
1192 GtkStateFlags state,
1193 const GValue *value)
1194 {
1195 GtkCssStyleProperty *prop;
1196 guint i, n;
1197
1198 n = _gtk_css_shorthand_property_get_n_subproperties (shorthand);
1199
1200 for (i = 0; i < n; i++)
1201 {
1202 prop = _gtk_css_shorthand_property_get_subproperty (shorthand, i);
1203 _gtk_style_property_assign (GTK_STYLE_PROPERTY (prop), props, state, value);
1204 }
1205 }
1206
1207 static void
pack_first_element(GtkCssShorthandProperty * shorthand,GValue * value,GtkStyleQueryFunc query_func,gpointer query_data)1208 pack_first_element (GtkCssShorthandProperty *shorthand,
1209 GValue *value,
1210 GtkStyleQueryFunc query_func,
1211 gpointer query_data)
1212 {
1213 GtkCssStyleProperty *prop;
1214
1215 /* NB: This is a fallback for properties that originally were
1216 * not used as shorthand. We just pick the first subproperty
1217 * as a representative.
1218 * Lesson learned: Don't query the shorthand, query the
1219 * real properties instead. */
1220 prop = _gtk_css_shorthand_property_get_subproperty (shorthand, 0);
1221 _gtk_style_property_query (GTK_STYLE_PROPERTY (prop),
1222 value,
1223 query_func,
1224 query_data);
1225 }
1226
1227 static void
_gtk_css_shorthand_property_register(const char * name,GType value_type,const char ** subproperties,GtkCssShorthandPropertyParseFunc parse_func,GtkCssShorthandPropertyAssignFunc assign_func,GtkCssShorthandPropertyQueryFunc query_func)1228 _gtk_css_shorthand_property_register (const char *name,
1229 GType value_type,
1230 const char **subproperties,
1231 GtkCssShorthandPropertyParseFunc parse_func,
1232 GtkCssShorthandPropertyAssignFunc assign_func,
1233 GtkCssShorthandPropertyQueryFunc query_func)
1234 {
1235 GtkCssShorthandProperty *node;
1236
1237 node = g_object_new (GTK_TYPE_CSS_SHORTHAND_PROPERTY,
1238 "name", name,
1239 "value-type", value_type,
1240 "subproperties", subproperties,
1241 NULL);
1242
1243 node->parse = parse_func;
1244 node->assign = assign_func;
1245 node->query = query_func;
1246 }
1247
1248 /* NB: return value is transfer: container */
1249 static const char **
get_all_subproperties(void)1250 get_all_subproperties (void)
1251 {
1252 const char **properties;
1253 guint i, n;
1254
1255 n = _gtk_css_style_property_get_n_properties ();
1256 properties = g_new (const char *, n + 1);
1257 properties[n] = NULL;
1258
1259 for (i = 0; i < n; i++)
1260 {
1261 properties[i] = _gtk_style_property_get_name (GTK_STYLE_PROPERTY (_gtk_css_style_property_lookup_by_id (i)));
1262 }
1263
1264 return properties;
1265 }
1266
1267 void
_gtk_css_shorthand_property_init_properties(void)1268 _gtk_css_shorthand_property_init_properties (void)
1269 {
1270 /* The order is important here, be careful when changing it */
1271 const char *font_subproperties[] = { "font-family", "font-style", "font-variant", "font-weight", "font-stretch", "font-size", NULL };
1272 const char *margin_subproperties[] = { "margin-top", "margin-right", "margin-bottom", "margin-left", NULL };
1273 const char *padding_subproperties[] = { "padding-top", "padding-right", "padding-bottom", "padding-left", NULL };
1274 const char *border_width_subproperties[] = { "border-top-width", "border-right-width", "border-bottom-width", "border-left-width", NULL };
1275 const char *border_radius_subproperties[] = { "border-top-left-radius", "border-top-right-radius",
1276 "border-bottom-right-radius", "border-bottom-left-radius", NULL };
1277 const char *border_color_subproperties[] = { "border-top-color", "border-right-color", "border-bottom-color", "border-left-color", NULL };
1278 const char *border_style_subproperties[] = { "border-top-style", "border-right-style", "border-bottom-style", "border-left-style", NULL };
1279 const char *border_image_subproperties[] = { "border-image-source", "border-image-slice", "border-image-width", "border-image-repeat", NULL };
1280 const char *border_top_subproperties[] = { "border-top-width", "border-top-style", "border-top-color", NULL };
1281 const char *border_right_subproperties[] = { "border-right-width", "border-right-style", "border-right-color", NULL };
1282 const char *border_bottom_subproperties[] = { "border-bottom-width", "border-bottom-style", "border-bottom-color", NULL };
1283 const char *border_left_subproperties[] = { "border-left-width", "border-left-style", "border-left-color", NULL };
1284 const char *border_subproperties[] = { "border-top-width", "border-right-width", "border-bottom-width", "border-left-width",
1285 "border-top-style", "border-right-style", "border-bottom-style", "border-left-style",
1286 "border-top-color", "border-right-color", "border-bottom-color", "border-left-color",
1287 "border-image-source", "border-image-slice", "border-image-width", "border-image-repeat", NULL };
1288 const char *outline_subproperties[] = { "outline-width", "outline-style", "outline-color", NULL };
1289 const char *outline_radius_subproperties[] = { "outline-top-left-radius", "outline-top-right-radius",
1290 "outline-bottom-right-radius", "outline-bottom-left-radius", NULL };
1291 const char *background_subproperties[] = { "background-image", "background-position", "background-size", "background-repeat", "background-clip", "background-origin",
1292 "background-color", NULL };
1293 const char *transition_subproperties[] = { "transition-property", "transition-duration", "transition-delay", "transition-timing-function", NULL };
1294 const char *animation_subproperties[] = { "animation-name", "animation-iteration-count", "animation-duration", "animation-delay",
1295 "animation-timing-function", "animation-direction", "animation-fill-mode", NULL };
1296 const char *text_decoration_subproperties[] = { "text-decoration-line", "text-decoration-style", "text-decoration-color", NULL };
1297
1298 const char **all_subproperties;
1299
1300 _gtk_css_shorthand_property_register ("font",
1301 PANGO_TYPE_FONT_DESCRIPTION,
1302 font_subproperties,
1303 parse_font,
1304 unpack_font_description,
1305 pack_font_description);
1306 _gtk_css_shorthand_property_register ("margin",
1307 GTK_TYPE_BORDER,
1308 margin_subproperties,
1309 parse_margin,
1310 unpack_border,
1311 pack_border);
1312 _gtk_css_shorthand_property_register ("padding",
1313 GTK_TYPE_BORDER,
1314 padding_subproperties,
1315 parse_padding,
1316 unpack_border,
1317 pack_border);
1318 _gtk_css_shorthand_property_register ("border-width",
1319 GTK_TYPE_BORDER,
1320 border_width_subproperties,
1321 parse_border_width,
1322 unpack_border,
1323 pack_border);
1324 _gtk_css_shorthand_property_register ("border-radius",
1325 G_TYPE_INT,
1326 border_radius_subproperties,
1327 parse_border_radius,
1328 unpack_border_radius,
1329 pack_border_radius);
1330 _gtk_css_shorthand_property_register ("border-color",
1331 GDK_TYPE_RGBA,
1332 border_color_subproperties,
1333 parse_border_color,
1334 unpack_to_everything,
1335 pack_first_element);
1336 _gtk_css_shorthand_property_register ("border-style",
1337 GTK_TYPE_BORDER_STYLE,
1338 border_style_subproperties,
1339 parse_border_style,
1340 unpack_to_everything,
1341 pack_first_element);
1342 _gtk_css_shorthand_property_register ("border-image",
1343 G_TYPE_NONE,
1344 border_image_subproperties,
1345 parse_border_image,
1346 NULL,
1347 NULL);
1348 _gtk_css_shorthand_property_register ("border-top",
1349 G_TYPE_NONE,
1350 border_top_subproperties,
1351 parse_border_side,
1352 NULL,
1353 NULL);
1354 _gtk_css_shorthand_property_register ("border-right",
1355 G_TYPE_NONE,
1356 border_right_subproperties,
1357 parse_border_side,
1358 NULL,
1359 NULL);
1360 _gtk_css_shorthand_property_register ("border-bottom",
1361 G_TYPE_NONE,
1362 border_bottom_subproperties,
1363 parse_border_side,
1364 NULL,
1365 NULL);
1366 _gtk_css_shorthand_property_register ("border-left",
1367 G_TYPE_NONE,
1368 border_left_subproperties,
1369 parse_border_side,
1370 NULL,
1371 NULL);
1372 _gtk_css_shorthand_property_register ("border",
1373 G_TYPE_NONE,
1374 border_subproperties,
1375 parse_border,
1376 NULL,
1377 NULL);
1378 _gtk_css_shorthand_property_register ("-gtk-outline-radius",
1379 G_TYPE_INT,
1380 outline_radius_subproperties,
1381 parse_border_radius,
1382 unpack_border_radius,
1383 pack_border_radius);
1384 _gtk_style_property_add_alias ("-gtk-outline-radius", "outline-radius");
1385 _gtk_css_shorthand_property_register ("outline",
1386 G_TYPE_NONE,
1387 outline_subproperties,
1388 parse_border_side,
1389 NULL,
1390 NULL);
1391 _gtk_css_shorthand_property_register ("background",
1392 G_TYPE_NONE,
1393 background_subproperties,
1394 parse_background,
1395 NULL,
1396 NULL);
1397 _gtk_css_shorthand_property_register ("transition",
1398 G_TYPE_NONE,
1399 transition_subproperties,
1400 parse_transition,
1401 NULL,
1402 NULL);
1403 _gtk_css_shorthand_property_register ("animation",
1404 G_TYPE_NONE,
1405 animation_subproperties,
1406 parse_animation,
1407 NULL,
1408 NULL);
1409 _gtk_css_shorthand_property_register ("text-decoration",
1410 G_TYPE_NONE,
1411 text_decoration_subproperties,
1412 parse_text_decoration,
1413 NULL,
1414 NULL);
1415
1416 all_subproperties = get_all_subproperties ();
1417 _gtk_css_shorthand_property_register ("all",
1418 G_TYPE_NONE,
1419 all_subproperties,
1420 parse_all,
1421 NULL,
1422 NULL);
1423 g_free (all_subproperties);
1424 }
1425