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 "gtkcssbordervalueprivate.h"
21
22 #include "gtkcssnumbervalueprivate.h"
23
24 struct _GtkCssValue {
25 GTK_CSS_VALUE_BASE
26 guint fill :1;
27 GtkCssValue *values[4];
28 };
29
30 static void
gtk_css_value_border_free(GtkCssValue * value)31 gtk_css_value_border_free (GtkCssValue *value)
32 {
33 guint i;
34
35 for (i = 0; i < 4; i++)
36 {
37 if (value->values[i])
38 _gtk_css_value_unref (value->values[i]);
39 }
40
41 g_slice_free (GtkCssValue, value);
42 }
43
44 static GtkCssValue *
gtk_css_value_border_compute(GtkCssValue * value,guint property_id,GtkStyleProviderPrivate * provider,GtkCssStyle * style,GtkCssStyle * parent_style)45 gtk_css_value_border_compute (GtkCssValue *value,
46 guint property_id,
47 GtkStyleProviderPrivate *provider,
48 GtkCssStyle *style,
49 GtkCssStyle *parent_style)
50 {
51 GtkCssValue *values[4];
52 GtkCssValue *computed;
53 gboolean changed = FALSE;
54 guint i;
55
56 for (i = 0; i < 4; i++)
57 {
58 if (value->values[i])
59 {
60 values[i] = _gtk_css_value_compute (value->values[i], property_id, provider, style, parent_style);
61 changed |= (values[i] != value->values[i]);
62 }
63 else
64 {
65 values[i] = NULL;
66 }
67 }
68
69 if (!changed)
70 {
71 for (i = 0; i < 4; i++)
72 {
73 if (values[i] != NULL)
74 _gtk_css_value_unref (values[i]);
75 }
76 return _gtk_css_value_ref (value);
77 }
78
79 computed = _gtk_css_border_value_new (values[0], values[1], values[2], values[3]);
80 computed->fill = value->fill;
81
82 return computed;
83 }
84
85 static gboolean
gtk_css_value_border_equal(const GtkCssValue * value1,const GtkCssValue * value2)86 gtk_css_value_border_equal (const GtkCssValue *value1,
87 const GtkCssValue *value2)
88 {
89 guint i;
90
91 if (value1->fill != value2->fill)
92 return FALSE;
93
94 for (i = 0; i < 4; i++)
95 {
96 if (!_gtk_css_value_equal0 (value1->values[i], value2->values[i]))
97 return FALSE;
98 }
99
100 return TRUE;
101 }
102
103 static GtkCssValue *
gtk_css_value_border_transition(GtkCssValue * start,GtkCssValue * end,guint property_id,double progress)104 gtk_css_value_border_transition (GtkCssValue *start,
105 GtkCssValue *end,
106 guint property_id,
107 double progress)
108 {
109 return NULL;
110 }
111
112 static void
gtk_css_value_border_print(const GtkCssValue * value,GString * string)113 gtk_css_value_border_print (const GtkCssValue *value,
114 GString *string)
115 {
116 guint i, n;
117
118 if (!_gtk_css_value_equal0 (value->values[GTK_CSS_RIGHT], value->values[GTK_CSS_LEFT]))
119 n = 4;
120 else if (!_gtk_css_value_equal0 (value->values[GTK_CSS_TOP], value->values[GTK_CSS_BOTTOM]))
121 n = 3;
122 else if (!_gtk_css_value_equal0 (value->values[GTK_CSS_TOP], value->values[GTK_CSS_RIGHT]))
123 n = 2;
124 else
125 n = 1;
126
127 for (i = 0; i < n; i++)
128 {
129 if (i > 0)
130 g_string_append_c (string, ' ');
131
132 if (value->values[i] == NULL)
133 g_string_append (string, "auto");
134 else
135 _gtk_css_value_print (value->values[i], string);
136 }
137
138 if (value->fill)
139 g_string_append (string, " fill");
140 }
141
142 static const GtkCssValueClass GTK_CSS_VALUE_BORDER = {
143 gtk_css_value_border_free,
144 gtk_css_value_border_compute,
145 gtk_css_value_border_equal,
146 gtk_css_value_border_transition,
147 gtk_css_value_border_print
148 };
149
150 GtkCssValue *
_gtk_css_border_value_new(GtkCssValue * top,GtkCssValue * right,GtkCssValue * bottom,GtkCssValue * left)151 _gtk_css_border_value_new (GtkCssValue *top,
152 GtkCssValue *right,
153 GtkCssValue *bottom,
154 GtkCssValue *left)
155 {
156 GtkCssValue *result;
157
158 result = _gtk_css_value_new (GtkCssValue, >K_CSS_VALUE_BORDER);
159 result->values[GTK_CSS_TOP] = top;
160 result->values[GTK_CSS_RIGHT] = right;
161 result->values[GTK_CSS_BOTTOM] = bottom;
162 result->values[GTK_CSS_LEFT] = left;
163
164 return result;
165 }
166
167 GtkCssValue *
_gtk_css_border_value_parse(GtkCssParser * parser,GtkCssNumberParseFlags flags,gboolean allow_auto,gboolean allow_fill)168 _gtk_css_border_value_parse (GtkCssParser *parser,
169 GtkCssNumberParseFlags flags,
170 gboolean allow_auto,
171 gboolean allow_fill)
172 {
173 GtkCssValue *result;
174 guint i;
175
176 result = _gtk_css_border_value_new (NULL, NULL, NULL, NULL);
177
178 if (allow_fill)
179 result->fill = _gtk_css_parser_try (parser, "fill", TRUE);
180
181 for (i = 0; i < 4; i++)
182 {
183 if (allow_auto && _gtk_css_parser_try (parser, "auto", TRUE))
184 continue;
185
186 if (!gtk_css_number_value_can_parse (parser))
187 break;
188
189 result->values[i] = _gtk_css_number_value_parse (parser, flags);
190 if (result->values[i] == NULL)
191 {
192 _gtk_css_value_unref (result);
193 return NULL;
194 }
195 }
196
197 if (i == 0)
198 {
199 _gtk_css_parser_error (parser, "Expected a number");
200 _gtk_css_value_unref (result);
201 return NULL;
202 }
203
204 if (allow_fill && !result->fill)
205 result->fill = _gtk_css_parser_try (parser, "fill", TRUE);
206
207 for (; i < 4; i++)
208 {
209 if (result->values[(i - 1) >> 1])
210 result->values[i] = _gtk_css_value_ref (result->values[(i - 1) >> 1]);
211 }
212
213 return result;
214 }
215
216 GtkCssValue *
_gtk_css_border_value_get_top(const GtkCssValue * value)217 _gtk_css_border_value_get_top (const GtkCssValue *value)
218 {
219 g_return_val_if_fail (value->class == >K_CSS_VALUE_BORDER, NULL);
220
221 return value->values[GTK_CSS_TOP];
222 }
223
224 GtkCssValue *
_gtk_css_border_value_get_right(const GtkCssValue * value)225 _gtk_css_border_value_get_right (const GtkCssValue *value)
226 {
227 g_return_val_if_fail (value->class == >K_CSS_VALUE_BORDER, NULL);
228
229 return value->values[GTK_CSS_RIGHT];
230 }
231
232 GtkCssValue *
_gtk_css_border_value_get_bottom(const GtkCssValue * value)233 _gtk_css_border_value_get_bottom (const GtkCssValue *value)
234 {
235 g_return_val_if_fail (value->class == >K_CSS_VALUE_BORDER, NULL);
236
237 return value->values[GTK_CSS_BOTTOM];
238 }
239
240 GtkCssValue *
_gtk_css_border_value_get_left(const GtkCssValue * value)241 _gtk_css_border_value_get_left (const GtkCssValue *value)
242 {
243 g_return_val_if_fail (value->class == >K_CSS_VALUE_BORDER, NULL);
244
245 return value->values[GTK_CSS_LEFT];
246 }
247
248