1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 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 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 
18 #include "config.h"
19 
20 #include "gtkcssrepeatvalueprivate.h"
21 
22 #include "gtkcssnumbervalueprivate.h"
23 
24 struct _GtkCssValue {
25   GTK_CSS_VALUE_BASE
26   GtkCssRepeatStyle x;
27   GtkCssRepeatStyle y;
28 };
29 
30 static void
gtk_css_value_repeat_free(GtkCssValue * value)31 gtk_css_value_repeat_free (GtkCssValue *value)
32 {
33   g_slice_free (GtkCssValue, value);
34 }
35 
36 static GtkCssValue *
gtk_css_value_repeat_compute(GtkCssValue * value,guint property_id,GtkStyleProviderPrivate * provider,GtkCssStyle * style,GtkCssStyle * parent_style)37 gtk_css_value_repeat_compute (GtkCssValue             *value,
38                               guint                    property_id,
39                               GtkStyleProviderPrivate *provider,
40                               GtkCssStyle             *style,
41                               GtkCssStyle             *parent_style)
42 {
43   return _gtk_css_value_ref (value);
44 }
45 
46 static gboolean
gtk_css_value_repeat_equal(const GtkCssValue * repeat1,const GtkCssValue * repeat2)47 gtk_css_value_repeat_equal (const GtkCssValue *repeat1,
48                             const GtkCssValue *repeat2)
49 {
50   return repeat1->x == repeat2->x
51       && repeat1->y == repeat2->y;
52 }
53 
54 static GtkCssValue *
gtk_css_value_repeat_transition(GtkCssValue * start,GtkCssValue * end,guint property_id,double progress)55 gtk_css_value_repeat_transition (GtkCssValue *start,
56                                  GtkCssValue *end,
57                                  guint        property_id,
58                                  double       progress)
59 {
60   return NULL;
61 }
62 
63 static void
gtk_css_value_background_repeat_print(const GtkCssValue * repeat,GString * string)64 gtk_css_value_background_repeat_print (const GtkCssValue *repeat,
65                                        GString           *string)
66 {
67   static const char *names[] = {
68     "no-repeat",
69     "repeat",
70     "round",
71     "space"
72   };
73 
74   if (repeat->x == repeat->y)
75     {
76       g_string_append (string, names[repeat->x]);
77     }
78   else if (repeat->x == GTK_CSS_REPEAT_STYLE_REPEAT &&
79            repeat->y == GTK_CSS_REPEAT_STYLE_NO_REPEAT)
80     {
81       g_string_append (string, "repeat-x");
82     }
83   else if (repeat->x == GTK_CSS_REPEAT_STYLE_NO_REPEAT &&
84            repeat->y == GTK_CSS_REPEAT_STYLE_REPEAT)
85     {
86       g_string_append (string, "repeat-y");
87     }
88   else
89     {
90       g_string_append (string, names[repeat->x]);
91       g_string_append_c (string, ' ');
92       g_string_append (string, names[repeat->y]);
93     }
94 }
95 
96 static void
gtk_css_value_border_repeat_print(const GtkCssValue * repeat,GString * string)97 gtk_css_value_border_repeat_print (const GtkCssValue *repeat,
98                                    GString           *string)
99 {
100   static const char *names[] = {
101     "stretch",
102     "repeat",
103     "round",
104     "space"
105   };
106 
107   g_string_append (string, names[repeat->x]);
108   if (repeat->x != repeat->y)
109     {
110       g_string_append_c (string, ' ');
111       g_string_append (string, names[repeat->y]);
112     }
113 }
114 
115 static const GtkCssValueClass GTK_CSS_VALUE_BACKGROUND_REPEAT = {
116   gtk_css_value_repeat_free,
117   gtk_css_value_repeat_compute,
118   gtk_css_value_repeat_equal,
119   gtk_css_value_repeat_transition,
120   gtk_css_value_background_repeat_print
121 };
122 
123 static const GtkCssValueClass GTK_CSS_VALUE_BORDER_REPEAT = {
124   gtk_css_value_repeat_free,
125   gtk_css_value_repeat_compute,
126   gtk_css_value_repeat_equal,
127   gtk_css_value_repeat_transition,
128   gtk_css_value_border_repeat_print
129 };
130 /* BACKGROUND REPEAT */
131 
132 static struct {
133   const char *name;
134   GtkCssValue values[4];
135 } background_repeat_values[4] = {
136   { "no-repeat",
137   { { &GTK_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_NO_REPEAT, GTK_CSS_REPEAT_STYLE_NO_REPEAT },
138     { &GTK_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_NO_REPEAT, GTK_CSS_REPEAT_STYLE_REPEAT    },
139     { &GTK_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_NO_REPEAT, GTK_CSS_REPEAT_STYLE_ROUND     },
140     { &GTK_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_NO_REPEAT, GTK_CSS_REPEAT_STYLE_SPACE     }
141   } },
142   { "repeat",
143   { { &GTK_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_REPEAT,    GTK_CSS_REPEAT_STYLE_NO_REPEAT },
144     { &GTK_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_REPEAT,    GTK_CSS_REPEAT_STYLE_REPEAT    },
145     { &GTK_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_REPEAT,    GTK_CSS_REPEAT_STYLE_ROUND     },
146     { &GTK_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_REPEAT,    GTK_CSS_REPEAT_STYLE_SPACE     }
147   } },
148   { "round",
149   { { &GTK_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_ROUND,     GTK_CSS_REPEAT_STYLE_NO_REPEAT },
150     { &GTK_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_ROUND,     GTK_CSS_REPEAT_STYLE_REPEAT    },
151     { &GTK_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_ROUND,     GTK_CSS_REPEAT_STYLE_ROUND     },
152     { &GTK_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_ROUND,     GTK_CSS_REPEAT_STYLE_SPACE     }
153   } },
154   { "space",
155   { { &GTK_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_SPACE,     GTK_CSS_REPEAT_STYLE_NO_REPEAT },
156     { &GTK_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_SPACE,     GTK_CSS_REPEAT_STYLE_REPEAT    },
157     { &GTK_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_SPACE,     GTK_CSS_REPEAT_STYLE_ROUND     },
158     { &GTK_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_SPACE,     GTK_CSS_REPEAT_STYLE_SPACE     }
159   } }
160 };
161 
162 GtkCssValue *
_gtk_css_background_repeat_value_new(GtkCssRepeatStyle x,GtkCssRepeatStyle y)163 _gtk_css_background_repeat_value_new (GtkCssRepeatStyle x,
164                                       GtkCssRepeatStyle y)
165 {
166   return _gtk_css_value_ref (&background_repeat_values[x].values[y]);
167 }
168 
169 static gboolean
_gtk_css_background_repeat_style_try(GtkCssParser * parser,GtkCssRepeatStyle * result)170 _gtk_css_background_repeat_style_try (GtkCssParser      *parser,
171                                       GtkCssRepeatStyle *result)
172 {
173   guint i;
174 
175   for (i = 0; i < G_N_ELEMENTS (background_repeat_values); i++)
176     {
177       if (_gtk_css_parser_try (parser, background_repeat_values[i].name, TRUE))
178         {
179           *result = i;
180           return TRUE;
181         }
182     }
183 
184   return FALSE;
185 }
186 
187 GtkCssValue *
_gtk_css_background_repeat_value_try_parse(GtkCssParser * parser)188 _gtk_css_background_repeat_value_try_parse (GtkCssParser *parser)
189 {
190   GtkCssRepeatStyle x, y;
191 
192   g_return_val_if_fail (parser != NULL, NULL);
193 
194   if (_gtk_css_parser_try (parser, "repeat-x", TRUE))
195     return _gtk_css_background_repeat_value_new (GTK_CSS_REPEAT_STYLE_REPEAT, GTK_CSS_REPEAT_STYLE_NO_REPEAT);
196   if (_gtk_css_parser_try (parser, "repeat-y", TRUE))
197     return _gtk_css_background_repeat_value_new (GTK_CSS_REPEAT_STYLE_NO_REPEAT, GTK_CSS_REPEAT_STYLE_REPEAT);
198 
199   if (!_gtk_css_background_repeat_style_try (parser, &x))
200     return NULL;
201 
202   if (!_gtk_css_background_repeat_style_try (parser, &y))
203     y = x;
204 
205   return _gtk_css_background_repeat_value_new (x, y);
206 }
207 
208 GtkCssRepeatStyle
_gtk_css_background_repeat_value_get_x(const GtkCssValue * repeat)209 _gtk_css_background_repeat_value_get_x (const GtkCssValue *repeat)
210 {
211   g_return_val_if_fail (repeat->class == &GTK_CSS_VALUE_BACKGROUND_REPEAT, GTK_CSS_REPEAT_STYLE_NO_REPEAT);
212 
213   return repeat->x;
214 }
215 
216 GtkCssRepeatStyle
_gtk_css_background_repeat_value_get_y(const GtkCssValue * repeat)217 _gtk_css_background_repeat_value_get_y (const GtkCssValue *repeat)
218 {
219   g_return_val_if_fail (repeat->class == &GTK_CSS_VALUE_BACKGROUND_REPEAT, GTK_CSS_REPEAT_STYLE_NO_REPEAT);
220 
221   return repeat->y;
222 }
223 
224 /* BORDER IMAGE REPEAT */
225 
226 static struct {
227   const char *name;
228   GtkCssValue values[4];
229 } border_repeat_values[4] = {
230   { "stretch",
231   { { &GTK_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_STRETCH, GTK_CSS_REPEAT_STYLE_STRETCH },
232     { &GTK_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_STRETCH, GTK_CSS_REPEAT_STYLE_REPEAT  },
233     { &GTK_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_STRETCH, GTK_CSS_REPEAT_STYLE_ROUND   },
234     { &GTK_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_STRETCH, GTK_CSS_REPEAT_STYLE_SPACE   }
235   } },
236   { "repeat",
237   { { &GTK_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_REPEAT,  GTK_CSS_REPEAT_STYLE_STRETCH },
238     { &GTK_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_REPEAT,  GTK_CSS_REPEAT_STYLE_REPEAT  },
239     { &GTK_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_REPEAT,  GTK_CSS_REPEAT_STYLE_ROUND   },
240     { &GTK_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_REPEAT,  GTK_CSS_REPEAT_STYLE_SPACE   }
241   } },
242   { "round",
243   { { &GTK_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_ROUND,   GTK_CSS_REPEAT_STYLE_STRETCH },
244     { &GTK_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_ROUND,   GTK_CSS_REPEAT_STYLE_REPEAT  },
245     { &GTK_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_ROUND,   GTK_CSS_REPEAT_STYLE_ROUND   },
246     { &GTK_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_ROUND,   GTK_CSS_REPEAT_STYLE_SPACE   }
247   } },
248   { "space",
249   { { &GTK_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_SPACE,   GTK_CSS_REPEAT_STYLE_STRETCH },
250     { &GTK_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_SPACE,   GTK_CSS_REPEAT_STYLE_REPEAT  },
251     { &GTK_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_SPACE,   GTK_CSS_REPEAT_STYLE_ROUND   },
252     { &GTK_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_SPACE,   GTK_CSS_REPEAT_STYLE_SPACE   }
253   } }
254 };
255 
256 GtkCssValue *
_gtk_css_border_repeat_value_new(GtkCssRepeatStyle x,GtkCssRepeatStyle y)257 _gtk_css_border_repeat_value_new (GtkCssRepeatStyle x,
258                                   GtkCssRepeatStyle y)
259 {
260   return _gtk_css_value_ref (&border_repeat_values[x].values[y]);
261 }
262 
263 static gboolean
_gtk_css_border_repeat_style_try(GtkCssParser * parser,GtkCssRepeatStyle * result)264 _gtk_css_border_repeat_style_try (GtkCssParser      *parser,
265                                   GtkCssRepeatStyle *result)
266 {
267   guint i;
268 
269   for (i = 0; i < G_N_ELEMENTS (border_repeat_values); i++)
270     {
271       if (_gtk_css_parser_try (parser, border_repeat_values[i].name, TRUE))
272         {
273           *result = i;
274           return TRUE;
275         }
276     }
277 
278   return FALSE;
279 }
280 
281 GtkCssValue *
_gtk_css_border_repeat_value_try_parse(GtkCssParser * parser)282 _gtk_css_border_repeat_value_try_parse (GtkCssParser *parser)
283 {
284   GtkCssRepeatStyle x, y;
285 
286   g_return_val_if_fail (parser != NULL, NULL);
287 
288   if (!_gtk_css_border_repeat_style_try (parser, &x))
289     return NULL;
290 
291   if (!_gtk_css_border_repeat_style_try (parser, &y))
292     y = x;
293 
294   return _gtk_css_border_repeat_value_new (x, y);
295 }
296 
297 GtkCssRepeatStyle
_gtk_css_border_repeat_value_get_x(const GtkCssValue * repeat)298 _gtk_css_border_repeat_value_get_x (const GtkCssValue *repeat)
299 {
300   g_return_val_if_fail (repeat->class == &GTK_CSS_VALUE_BORDER_REPEAT, GTK_CSS_REPEAT_STYLE_STRETCH);
301 
302   return repeat->x;
303 }
304 
305 GtkCssRepeatStyle
_gtk_css_border_repeat_value_get_y(const GtkCssValue * repeat)306 _gtk_css_border_repeat_value_get_y (const GtkCssValue *repeat)
307 {
308   g_return_val_if_fail (repeat->class == &GTK_CSS_VALUE_BORDER_REPEAT, GTK_CSS_REPEAT_STYLE_STRETCH);
309 
310   return repeat->y;
311 }
312 
313