]> Pileus Git - ~andy/gtk/blob - gtk/gtkcsslookup.c
csslookup: Use the new gtk_style_context_peek_property()
[~andy/gtk] / gtk / gtkcsslookup.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2011 Benjamin Otte <otte@gnome.org>
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, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "config.h"
21
22 #include "gtkcsslookupprivate.h"
23
24 #include "gtkcsstypesprivate.h"
25 #include "gtkprivatetypebuiltins.h"
26 #include "gtkcssstylepropertyprivate.h"
27 #include "gtkstylepropertiesprivate.h"
28
29 typedef struct {
30   GtkCssSection     *section;
31   const GValue      *value;
32 } GtkCssLookupValue;
33
34 struct _GtkCssLookup {
35   GtkBitmask        *missing;
36   GtkCssLookupValue  values[1];
37 };
38
39 GtkCssLookup *
40 _gtk_css_lookup_new (void)
41 {
42   GtkCssLookup *lookup;
43   guint n = _gtk_css_style_property_get_n_properties ();
44
45   lookup = g_malloc0 (sizeof (GtkCssLookup) + sizeof (GtkCssLookupValue) * n);
46   lookup->missing = _gtk_bitmask_new ();
47   _gtk_bitmask_invert_range (lookup->missing, 0, n);
48
49   return lookup;
50 }
51
52 void
53 _gtk_css_lookup_free (GtkCssLookup *lookup)
54 {
55   g_return_if_fail (lookup != NULL);
56
57   _gtk_bitmask_free (lookup->missing);
58   g_free (lookup);
59 }
60
61 const GtkBitmask *
62 _gtk_css_lookup_get_missing (const GtkCssLookup *lookup)
63 {
64   g_return_val_if_fail (lookup != NULL, NULL);
65
66   return lookup->missing;
67 }
68
69 gboolean
70 _gtk_css_lookup_is_missing (const GtkCssLookup *lookup,
71                             guint               id)
72 {
73   g_return_val_if_fail (lookup != NULL, FALSE);
74
75   return lookup->values[id].value == NULL;
76 }
77
78 /**
79  * _gtk_css_lookup_set:
80  * @lookup: the lookup
81  * @id: id of the property to set, see _gtk_style_property_get_id()
82  * @section: (allow-none): The @section the value was defined in or %NULL
83  * @value: the "cascading value" to use
84  *
85  * Sets the @value for a given @id. No value may have been set for @id
86  * before. See _gtk_css_lookup_is_missing(). This function is used to
87  * set the "winning declaration" of a lookup. Note that for performance
88  * reasons @value and @section are not copied. It is your responsibility
89  * to ensure they are kept alive until _gtk_css_lookup_free() is called.
90  **/
91 void
92 _gtk_css_lookup_set (GtkCssLookup  *lookup,
93                      guint          id,
94                      GtkCssSection *section,
95                      const GValue  *value)
96 {
97   g_return_if_fail (lookup != NULL);
98   g_return_if_fail (_gtk_bitmask_get (lookup->missing, id));
99   g_return_if_fail (value != NULL);
100
101   _gtk_bitmask_set (lookup->missing, id, FALSE);
102   lookup->values[id].value = value;
103   lookup->values[id].section = section;
104 }
105
106 /**
107  * _gtk_css_lookup_resolve:
108  * @lookup: the lookup
109  * @context: the context the values are resolved for
110  *
111  * Resolves the current lookup into a styleproperties object. This is done
112  * by converting from the "winning declaration" to the "computed value".
113  *
114  * XXX: This bypasses the notion of "specified value". If this ever becomes
115  * an issue, go fix it.
116  *
117  * Returns: a new #GtkStyleProperties
118  **/
119 GtkStyleProperties *
120 _gtk_css_lookup_resolve (GtkCssLookup    *lookup,
121                          GtkStyleContext *context)
122 {
123   GtkStyleProperties *props;
124   GtkStyleContext *parent;
125   guint i, n;
126
127   g_return_val_if_fail (lookup != NULL, NULL);
128   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
129
130   parent = gtk_style_context_get_parent (context);
131   n = _gtk_css_style_property_get_n_properties ();
132   props = gtk_style_properties_new ();
133
134   for (i = 0; i < n; i++)
135     {
136       GtkCssStyleProperty *prop = _gtk_css_style_property_lookup_by_id (i);
137       const GValue *result;
138       GValue value = { 0, };
139
140       /* http://www.w3.org/TR/css3-cascade/#cascade
141        * Then, for every element, the value for each property can be found
142        * by following this pseudo-algorithm:
143        * 1) Identify all declarations that apply to the element
144        */
145       if (lookup->values[i].value != NULL)
146         {
147           /* 2) If the cascading process (described below) yields a winning
148            * declaration and the value of the winning declaration is not
149            * ‘initial’ or ‘inherit’, the value of the winning declaration
150            * becomes the specified value.
151            */
152           if (!G_VALUE_HOLDS (lookup->values[i].value, GTK_TYPE_CSS_SPECIAL_VALUE))
153             {
154               result = lookup->values[i].value;
155             }
156           else
157             {
158               switch (g_value_get_enum (lookup->values[i].value))
159                 {
160                 case GTK_CSS_INHERIT:
161                   /* 3) if the value of the winning declaration is ‘inherit’,
162                    * the inherited value (see below) becomes the specified value.
163                    */
164                   result = NULL;
165                   break;
166                 case GTK_CSS_INITIAL:
167                   /* if the value of the winning declaration is ‘initial’,
168                    * the initial value (see below) becomes the specified value.
169                    */
170                   result = _gtk_css_style_property_get_initial_value (prop);
171                   break;
172                 default:
173                   /* This is part of (2) above */
174                   result = lookup->values[i].value;
175                   break;
176                 }
177             }
178         }
179       else
180         {
181           if (_gtk_css_style_property_is_inherit (prop))
182             {
183               /* 4) if the property is inherited, the inherited value becomes
184                * the specified value.
185                */
186               result = NULL;
187             }
188           else
189             {
190               /* 5) Otherwise, the initial value becomes the specified value.
191                */
192               result = _gtk_css_style_property_get_initial_value (prop);
193             }
194         }
195
196       if (result == NULL && parent == NULL)
197         {
198           /* If the ‘inherit’ value is set on the root element, the property is
199            * assigned its initial value. */
200           result = _gtk_css_style_property_get_initial_value (prop);
201         }
202
203       if (result)
204         {
205           _gtk_css_style_property_compute_value (prop, &value, context, result);
206         }
207       else
208         {
209           /* Set NULL here and do the inheritance upon lookup? */
210           result = _gtk_style_context_peek_property (parent,
211                                                      _gtk_style_property_get_name (GTK_STYLE_PROPERTY (prop)));
212           g_value_init (&value, G_VALUE_TYPE (result));
213           g_value_copy (result, &value);
214         }
215
216       _gtk_style_properties_set_property_by_property (props,
217                                                       prop,
218                                                       0,
219                                                       &value);
220       g_value_unset (&value);
221     }
222
223   return props;
224 }