]> Pileus Git - ~andy/gtk/blob - gtk/gtkcssshadowsvalue.c
stylecontext: Do invalidation on first resize container
[~andy/gtk] / gtk / gtkcssshadowsvalue.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2011 Red Hat, Inc.
3  *
4  * Author: Cosimo Cecchi <cosimoc@gnome.org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "config.h"
21
22 #include "gtkcssshadowsvalueprivate.h"
23
24 #include "gtkcssshadowvalueprivate.h"
25
26 #include <string.h>
27
28 struct _GtkCssValue {
29   GTK_CSS_VALUE_BASE
30   guint         len;
31   GtkCssValue  *values[1];
32 };
33
34 static GtkCssValue *    gtk_css_shadows_value_new       (GtkCssValue **values,
35                                                          guint         len);
36
37 static void
38 gtk_css_value_shadows_free (GtkCssValue *value)
39 {
40   guint i;
41
42   for (i = 0; i < value->len; i++)
43     {
44       _gtk_css_value_unref (value->values[i]);
45     }
46
47   g_slice_free1 (sizeof (GtkCssValue) + sizeof (GtkCssValue *) * (value->len - 1), value);
48 }
49
50 static GtkCssValue *
51 gtk_css_value_shadows_compute (GtkCssValue             *value,
52                                guint                    property_id,
53                                GtkStyleProviderPrivate *provider,
54                                GtkCssComputedValues    *values,
55                                GtkCssComputedValues    *parent_values,
56                                GtkCssDependencies      *dependencies)
57 {
58   GtkCssValue *result;
59   GtkCssDependencies child_deps;
60   guint i;
61
62   if (value->len == 0)
63     return _gtk_css_value_ref (value);
64
65   result = gtk_css_shadows_value_new (value->values, value->len);
66   for (i = 0; i < value->len; i++)
67     {
68       result->values[i] = _gtk_css_value_compute (value->values[i], property_id, provider, values, parent_values, &child_deps);
69       *dependencies = _gtk_css_dependencies_union (*dependencies, child_deps);
70     }
71
72   return result;
73 }
74
75 static gboolean
76 gtk_css_value_shadows_equal (const GtkCssValue *value1,
77                              const GtkCssValue *value2)
78 {
79   guint i;
80
81   /* XXX: Should we fill up here? */
82   if (value1->len != value2->len)
83     return FALSE;
84
85   for (i = 0; i < value1->len; i++)
86     {
87       if (!_gtk_css_value_equal (value1->values[i],
88                                  value2->values[i]))
89         return FALSE;
90     }
91
92   return TRUE;
93 }
94
95 static GtkCssValue *
96 gtk_css_value_shadows_transition (GtkCssValue *start,
97                                   GtkCssValue *end,
98                                   guint        property_id,
99                                   double       progress)
100 {
101   guint i, len;
102   GtkCssValue **values;
103
104   /* catches the important case of 2 none values */
105   if (start == end)
106     return _gtk_css_value_ref (start);
107
108   if (start->len > end->len)
109     len = start->len;
110   else
111     len = end->len;
112
113   values = g_newa (GtkCssValue *, len);
114
115   for (i = 0; i < MIN (start->len, end->len); i++)
116     {
117       values[i] = _gtk_css_value_transition (start->values[i], end->values[i], property_id, progress);
118       if (values[i] == NULL)
119         {
120           while (i--)
121             _gtk_css_value_unref (values[i]);
122           return NULL;
123         }
124     }
125   if (start->len > end->len)
126     {
127       for (; i < len; i++)
128         {
129           GtkCssValue *fill = _gtk_css_shadow_value_new_for_transition (start->values[i]);
130           values[i] = _gtk_css_value_transition (start->values[i], fill, property_id, progress);
131           _gtk_css_value_unref (fill);
132
133           if (values[i] == NULL)
134             {
135               while (i--)
136                 _gtk_css_value_unref (values[i]);
137               return NULL;
138             }
139         }
140     }
141   else
142     {
143       for (; i < len; i++)
144         {
145           GtkCssValue *fill = _gtk_css_shadow_value_new_for_transition (end->values[i]);
146           values[i] = _gtk_css_value_transition (fill, end->values[i], property_id, progress);
147           _gtk_css_value_unref (fill);
148
149           if (values[i] == NULL)
150             {
151               while (i--)
152                 _gtk_css_value_unref (values[i]);
153               return NULL;
154             }
155         }
156     }
157
158   return gtk_css_shadows_value_new (values, len);
159 }
160
161 static void
162 gtk_css_value_shadows_print (const GtkCssValue *value,
163                              GString           *string)
164 {
165   guint i;
166
167   if (value->len == 0)
168     {
169       g_string_append (string, "none");
170       return;
171     }
172
173   for (i = 0; i < value->len; i++)
174     {
175       if (i > 0)
176         g_string_append (string, ", ");
177       _gtk_css_value_print (value->values[i], string);
178     }
179 }
180
181 static const GtkCssValueClass GTK_CSS_VALUE_SHADOWS = {
182   gtk_css_value_shadows_free,
183   gtk_css_value_shadows_compute,
184   gtk_css_value_shadows_equal,
185   gtk_css_value_shadows_transition,
186   gtk_css_value_shadows_print
187 };
188
189 static GtkCssValue none_singleton = { &GTK_CSS_VALUE_SHADOWS, 1, 0, { NULL } };
190
191 GtkCssValue *
192 _gtk_css_shadows_value_new_none (void)
193 {
194   return _gtk_css_value_ref (&none_singleton);
195 }
196
197 static GtkCssValue *
198 gtk_css_shadows_value_new (GtkCssValue **values,
199                            guint         len)
200 {
201   GtkCssValue *result;
202            
203   g_return_val_if_fail (values != NULL, NULL);
204   g_return_val_if_fail (len > 0, NULL);
205          
206   result = _gtk_css_value_alloc (&GTK_CSS_VALUE_SHADOWS, sizeof (GtkCssValue) + sizeof (GtkCssValue *) * (len - 1));
207   result->len = len;
208   memcpy (&result->values[0], values, sizeof (GtkCssValue *) * len);
209             
210   return result;
211 }
212
213 GtkCssValue *
214 _gtk_css_shadows_value_parse (GtkCssParser *parser)
215 {
216   GtkCssValue *value, *result;
217   GPtrArray *values;
218
219   if (_gtk_css_parser_try (parser, "none", TRUE))
220     return _gtk_css_shadows_value_new_none ();
221
222   values = g_ptr_array_new ();
223
224   do {
225     value = _gtk_css_shadow_value_parse (parser);
226
227     if (value == NULL)
228       {
229         g_ptr_array_set_free_func (values, (GDestroyNotify) _gtk_css_value_unref);
230         g_ptr_array_free (values, TRUE);
231         return NULL;
232       }
233
234     g_ptr_array_add (values, value);
235   } while (_gtk_css_parser_try (parser, ",", TRUE));
236
237   result = gtk_css_shadows_value_new ((GtkCssValue **) values->pdata, values->len);
238   g_ptr_array_free (values, TRUE);
239   return result;
240 }
241
242 void
243 _gtk_css_shadows_value_paint_layout (const GtkCssValue *shadows,
244                                      cairo_t           *cr,
245                                      PangoLayout       *layout)
246 {
247   guint i;
248
249   g_return_if_fail (shadows->class == &GTK_CSS_VALUE_SHADOWS);
250
251   for (i = 0; i < shadows->len; i++)
252     {
253       _gtk_css_shadow_value_paint_layout (shadows->values[i], cr, layout);
254     }
255 }
256
257 void
258 _gtk_css_shadows_value_paint_icon (const GtkCssValue *shadows,
259                                    cairo_t           *cr)
260 {
261   guint i;
262
263   g_return_if_fail (shadows->class == &GTK_CSS_VALUE_SHADOWS);
264
265   for (i = 0; i < shadows->len; i++)
266     {
267       _gtk_css_shadow_value_paint_icon (shadows->values[i], cr);
268     }
269 }
270
271 void
272 _gtk_css_shadows_value_paint_spinner (const GtkCssValue *shadows,
273                                       cairo_t           *cr,
274                                       gdouble            radius,
275                                       gdouble            progress)
276 {
277   guint i;
278
279   g_return_if_fail (shadows->class == &GTK_CSS_VALUE_SHADOWS);
280
281   for (i = 0; i < shadows->len; i++)
282     {
283       _gtk_css_shadow_value_paint_spinner (shadows->values[i], cr, radius, progress);
284     }
285 }
286
287 void
288 _gtk_css_shadows_value_paint_box (const GtkCssValue   *shadows,
289                                   cairo_t             *cr,
290                                   const GtkRoundedBox *padding_box)
291 {
292   guint i;
293
294   g_return_if_fail (shadows->class == &GTK_CSS_VALUE_SHADOWS);
295
296   for (i = 0; i < shadows->len; i++)
297     {
298       _gtk_css_shadow_value_paint_box (shadows->values[i], cr, padding_box);
299     }
300 }