Code

moving trunk for module inkscape
[inkscape.git] / src / libcroco / cr-simple-sel.c
1 /* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
3 /*
4  * This file is part of The Croco Library
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of version 2.1 of the GNU Lesser General Public
8  * License as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18  * USA
19  *
20  * Author: Dodji Seketeli
21  * See COPYRIGHTS file for copyright information.
22  */
24 #include <string.h>
25 #include <glib.h>
26 #include "cr-simple-sel.h"
28 /**
29  *The constructor of #CRSimpleSel.
30  *
31  *@return the new instance of #CRSimpleSel.
32  */
33 CRSimpleSel *
34 cr_simple_sel_new (void)
35 {
36         CRSimpleSel *result = NULL;
38         result = g_try_malloc (sizeof (CRSimpleSel));
39         if (!result) {
40                 cr_utils_trace_info ("Out of memory");
41                 return NULL;
42         }
43         memset (result, 0, sizeof (CRSimpleSel));
45         return result;
46 }
48 /**
49  *Appends a simpe selector to the current list of simple selector.
50  *
51  *@param a_this the this pointer of the current instance of #CRSimpleSel.
52  *@param a_sel the simple selector to append.
53  *@return the new list upon successfull completion, an error code otherwise.
54  */
55 CRSimpleSel *
56 cr_simple_sel_append_simple_sel (CRSimpleSel * a_this, CRSimpleSel * a_sel)
57 {
58         CRSimpleSel *cur = NULL;
60         g_return_val_if_fail (a_sel, NULL);
62         if (a_this == NULL)
63                 return a_sel;
65         for (cur = a_this; cur->next; cur = cur->next) ;
67         cur->next = a_sel;
68         a_sel->prev = cur;
70         return a_this;
71 }
73 /**
74  *Prepends a simple selector to the current list of simple selectors.
75  *@param a_this the this pointer of the current instance of #CRSimpleSel.
76  *@param a_sel the simple selector to prepend.
77  *@return the new list upon successfull completion, an error code otherwise.
78  */
79 CRSimpleSel *
80 cr_simple_sel_prepend_simple_sel (CRSimpleSel * a_this, CRSimpleSel * a_sel)
81 {
82         g_return_val_if_fail (a_sel, NULL);
84         if (a_this == NULL)
85                 return a_sel;
87         a_sel->next = a_this;
88         a_this->prev = a_sel;
90         return a_sel;
91 }
93 guchar *
94 cr_simple_sel_to_string (CRSimpleSel * a_this)
95 {
96         GString *str_buf = NULL;
97         guchar *result = NULL;
99         CRSimpleSel *cur = NULL;
101         g_return_val_if_fail (a_this, NULL);
103         str_buf = g_string_new (NULL);
104         for (cur = a_this; cur; cur = cur->next) {
105                 if (cur->name) {
106                         guchar *str = g_strndup (cur->name->stryng->str,
107                                                  cur->name->stryng->len);
109                         if (str) {
110                                 switch (cur->combinator) {
111                                 case COMB_WS:
112                                         g_string_append (str_buf, " ");
113                                         break;
115                                 case COMB_PLUS:
116                                         g_string_append (str_buf, "+");
117                                         break;
119                                 case COMB_GT:
120                                         g_string_append (str_buf, ">");
121                                         break;
123                                 default:
124                                         break;
125                                 }
127                                 g_string_append (str_buf, str);
128                                 g_free (str);
129                                 str = NULL;
130                         }
131                 }
133                 if (cur->add_sel) {
134                         guchar *tmp_str = NULL;
136                         tmp_str = cr_additional_sel_to_string (cur->add_sel);
137                         if (tmp_str) {
138                                 g_string_append (str_buf, tmp_str);
139                                 g_free (tmp_str);
140                                 tmp_str = NULL;
141                         }
142                 }
143         }
145         if (str_buf) {
146                 result = str_buf->str;
147                 g_string_free (str_buf, FALSE);
148                 str_buf = NULL;
149         }
151         return result;
155 guchar *
156 cr_simple_sel_one_to_string (CRSimpleSel * a_this)
158         GString *str_buf = NULL;
159         guchar *result = NULL;
161         g_return_val_if_fail (a_this, NULL);
163         str_buf = g_string_new (NULL);
164         if (a_this->name) {
165                 guchar *str = g_strndup (a_this->name->stryng->str,
166                                          a_this->name->stryng->len);
168                 if (str) {
169                         g_string_append_printf (str_buf, "%s", str);
170                         g_free (str);
171                         str = NULL;
172                 }
173         }
175         if (a_this->add_sel) {
176                 guchar *tmp_str = NULL;
178                 tmp_str = cr_additional_sel_to_string (a_this->add_sel);
179                 if (tmp_str) {
180                         g_string_append_printf
181                                 (str_buf, "%s", tmp_str);
182                         g_free (tmp_str);
183                         tmp_str = NULL;
184                 }
185         }
187         if (str_buf) {
188                 result = str_buf->str;
189                 g_string_free (str_buf, FALSE);
190                 str_buf = NULL;
191         }
193         return result;
196 /**
197  *Dumps the selector to a file.
198  *TODO: add the support of unicode in the dump.
199  *
200  *@param a_this the current instance of #CRSimpleSel.
201  *@param a_fp the destination file pointer.
202  *@return CR_OK upon successfull completion, an error code
203  *otherwise.
204  */
205 enum CRStatus
206 cr_simple_sel_dump (CRSimpleSel * a_this, FILE * a_fp)
208         guchar *tmp_str = NULL;
210         g_return_val_if_fail (a_fp, CR_BAD_PARAM_ERROR);
212         if (a_this) {
213                 tmp_str = cr_simple_sel_to_string (a_this);
214                 if (tmp_str) {
215                         fprintf (a_fp, "%s", tmp_str);
216                         g_free (tmp_str);
217                         tmp_str = NULL;
218                 }
219         }
221         return CR_OK;
224 /**
225  *Computes the selector (combinator separated list of simple selectors)
226  *as defined in the css2 spec in chapter 6.4.3
227  *@param a_this the current instance of #CRSimpleSel
228  *@return CR_OK upon successfull completion, an error code otherwise.
229  */
230 enum CRStatus
231 cr_simple_sel_compute_specificity (CRSimpleSel * a_this)
233         CRAdditionalSel *cur_add_sel = NULL;
234         CRSimpleSel *cur_sel = NULL;
235         gulong a = 0,
236                 b = 0,
237                 c = 0;
239         g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
241         for (cur_sel = a_this; cur_sel; cur_sel = cur_sel->next) {
242                 if (cur_sel->type_mask | TYPE_SELECTOR) {
243                         c++;    /*hmmh, is this a new language ? */
244                 } else if (!cur_sel->name 
245                            || !cur_sel->name->stryng
246                            || !cur_sel->name->stryng->str) {
247                         if (cur_sel->add_sel->type ==
248                             PSEUDO_CLASS_ADD_SELECTOR) {
249                                 /*
250                                  *this is a pseudo element, and
251                                  *the spec says, "ignore pseudo elements".
252                                  */
253                                 continue;
254                         }
255                 }
257                 for (cur_add_sel = cur_sel->add_sel;
258                      cur_add_sel; cur_add_sel = cur_add_sel->next) {
259                         switch (cur_add_sel->type) {
260                         case ID_ADD_SELECTOR:
261                                 a++;
262                                 break;
264                         case NO_ADD_SELECTOR:
265                                 continue;
267                         default:
268                                 b++;
269                                 break;
270                         }
271                 }
272         }
274         /*we suppose a, b and c have 1 to 3 digits */
275         a_this->specificity = a * 1000000 + b * 1000 + c;
277         return CR_OK;
280 /**
281  *The destructor of the current instance of
282  *#CRSimpleSel.
283  *@param a_this the this pointer of the current instance of #CRSimpleSel.
284  *
285  */
286 void
287 cr_simple_sel_destroy (CRSimpleSel * a_this)
289         g_return_if_fail (a_this);
291         if (a_this->name) {
292                 cr_string_destroy (a_this->name);
293                 a_this->name = NULL;
294         }
296         if (a_this->add_sel) {
297                 cr_additional_sel_destroy (a_this->add_sel);
298                 a_this->add_sel = NULL;
299         }
301         if (a_this->next) {
302                 cr_simple_sel_destroy (a_this->next);
303         }
305         if (a_this) {
306                 g_free (a_this);
307         }