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 { { >K_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_NO_REPEAT, GTK_CSS_REPEAT_STYLE_NO_REPEAT },
138 { >K_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_NO_REPEAT, GTK_CSS_REPEAT_STYLE_REPEAT },
139 { >K_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_NO_REPEAT, GTK_CSS_REPEAT_STYLE_ROUND },
140 { >K_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_NO_REPEAT, GTK_CSS_REPEAT_STYLE_SPACE }
141 } },
142 { "repeat",
143 { { >K_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_REPEAT, GTK_CSS_REPEAT_STYLE_NO_REPEAT },
144 { >K_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_REPEAT, GTK_CSS_REPEAT_STYLE_REPEAT },
145 { >K_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_REPEAT, GTK_CSS_REPEAT_STYLE_ROUND },
146 { >K_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_REPEAT, GTK_CSS_REPEAT_STYLE_SPACE }
147 } },
148 { "round",
149 { { >K_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_ROUND, GTK_CSS_REPEAT_STYLE_NO_REPEAT },
150 { >K_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_ROUND, GTK_CSS_REPEAT_STYLE_REPEAT },
151 { >K_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_ROUND, GTK_CSS_REPEAT_STYLE_ROUND },
152 { >K_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_ROUND, GTK_CSS_REPEAT_STYLE_SPACE }
153 } },
154 { "space",
155 { { >K_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_SPACE, GTK_CSS_REPEAT_STYLE_NO_REPEAT },
156 { >K_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_SPACE, GTK_CSS_REPEAT_STYLE_REPEAT },
157 { >K_CSS_VALUE_BACKGROUND_REPEAT, 1, GTK_CSS_REPEAT_STYLE_SPACE, GTK_CSS_REPEAT_STYLE_ROUND },
158 { >K_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 == >K_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 == >K_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 { { >K_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_STRETCH, GTK_CSS_REPEAT_STYLE_STRETCH },
232 { >K_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_STRETCH, GTK_CSS_REPEAT_STYLE_REPEAT },
233 { >K_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_STRETCH, GTK_CSS_REPEAT_STYLE_ROUND },
234 { >K_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_STRETCH, GTK_CSS_REPEAT_STYLE_SPACE }
235 } },
236 { "repeat",
237 { { >K_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_REPEAT, GTK_CSS_REPEAT_STYLE_STRETCH },
238 { >K_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_REPEAT, GTK_CSS_REPEAT_STYLE_REPEAT },
239 { >K_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_REPEAT, GTK_CSS_REPEAT_STYLE_ROUND },
240 { >K_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_REPEAT, GTK_CSS_REPEAT_STYLE_SPACE }
241 } },
242 { "round",
243 { { >K_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_ROUND, GTK_CSS_REPEAT_STYLE_STRETCH },
244 { >K_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_ROUND, GTK_CSS_REPEAT_STYLE_REPEAT },
245 { >K_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_ROUND, GTK_CSS_REPEAT_STYLE_ROUND },
246 { >K_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_ROUND, GTK_CSS_REPEAT_STYLE_SPACE }
247 } },
248 { "space",
249 { { >K_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_SPACE, GTK_CSS_REPEAT_STYLE_STRETCH },
250 { >K_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_SPACE, GTK_CSS_REPEAT_STYLE_REPEAT },
251 { >K_CSS_VALUE_BORDER_REPEAT, 1, GTK_CSS_REPEAT_STYLE_SPACE, GTK_CSS_REPEAT_STYLE_ROUND },
252 { >K_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 == >K_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 == >K_CSS_VALUE_BORDER_REPEAT, GTK_CSS_REPEAT_STYLE_STRETCH);
309
310 return repeat->y;
311 }
312
313