Code

Node tool: special case node duplication for endnodes - select new endnode
[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 = (CRSimpleSel *)g_try_malloc (sizeof (CRSimpleSel));
37         if (!result) {
38                 cr_utils_trace_info ("Out of memory");
39                 return NULL;
40         }
41         memset (result, 0, sizeof (CRSimpleSel));
43         return result;
44 }
46 /**
47  *Appends a simpe selector to the current list of simple selector.
48  *
49  *@param a_this the this pointer of the current instance of #CRSimpleSel.
50  *@param a_sel the simple selector to append.
51  *@return the new list upon successfull completion, an error code otherwise.
52  */
53 CRSimpleSel *
54 cr_simple_sel_append_simple_sel (CRSimpleSel * a_this, CRSimpleSel * a_sel)
55 {
56         CRSimpleSel *cur = NULL;
58         g_return_val_if_fail (a_sel, NULL);
60         if (a_this == NULL)
61                 return a_sel;
63         for (cur = a_this; cur->next; cur = cur->next) ;
65         cur->next = a_sel;
66         a_sel->prev = cur;
68         return a_this;
69 }
71 /**
72  *Prepends a simple selector to the current list of simple selectors.
73  *@param a_this the this pointer of the current instance of #CRSimpleSel.
74  *@param a_sel the simple selector to prepend.
75  *@return the new list upon successfull completion, an error code otherwise.
76  */
77 CRSimpleSel *
78 cr_simple_sel_prepend_simple_sel (CRSimpleSel * a_this, CRSimpleSel * a_sel)
79 {
80         g_return_val_if_fail (a_sel, NULL);
82         if (a_this == NULL)
83                 return a_sel;
85         a_sel->next = a_this;
86         a_this->prev = a_sel;
88         return a_sel;
89 }
91 guchar *
92 cr_simple_sel_to_string (CRSimpleSel * a_this)
93 {
94         GString *str_buf = NULL;
95         guchar *result = NULL;
97         CRSimpleSel *cur = NULL;
99         g_return_val_if_fail (a_this, NULL);
101         str_buf = g_string_new (NULL);
102         for (cur = a_this; cur; cur = cur->next) {
103                 if (cur->name) {
104                         gchar *str = g_strndup (cur->name->stryng->str,
105                                                  cur->name->stryng->len);
107                         if (str) {
108                                 switch (cur->combinator) {
109                                 case COMB_WS:
110                                         g_string_append (str_buf, " ");
111                                         break;
113                                 case COMB_PLUS:
114                                         g_string_append (str_buf, "+");
115                                         break;
117                                 case COMB_GT:
118                                         g_string_append (str_buf, ">");
119                                         break;
121                                 default:
122                                         break;
123                                 }
125                                 g_string_append (str_buf, str);
126                                 g_free (str);
127                                 str = NULL;
128                         }
129                 }
131                 if (cur->add_sel) {
133                         gchar *tmp_str = (gchar *)cr_additional_sel_to_string (cur->add_sel);
134                         if (tmp_str) {
135                                 g_string_append (str_buf, tmp_str);
136                                 g_free (tmp_str);
137                                 tmp_str = NULL;
138                         }
139                 }
140         }
142         if (str_buf) {
143                 result = (guchar *)str_buf->str;
144                 g_string_free (str_buf, FALSE);
145                 str_buf = NULL;
146         }
148         return result;
152 guchar *
153 cr_simple_sel_one_to_string (CRSimpleSel * a_this)
155         GString *str_buf = NULL;
156         guchar *result = NULL;
158         g_return_val_if_fail (a_this, NULL);
160         str_buf = g_string_new (NULL);
161         if (a_this->name) {
162                 gchar *str = g_strndup (a_this->name->stryng->str,
163                                          a_this->name->stryng->len);
165                 if (str) {
166                         g_string_append_printf (str_buf, "%s", str);
167                         g_free (str);
168                         str = NULL;
169                 }
170         }
172         if (a_this->add_sel) {
174                 gchar *tmp_str = (gchar *)cr_additional_sel_to_string (a_this->add_sel);
175                 if (tmp_str) {
176                         g_string_append_printf
177                                 (str_buf, "%s", tmp_str);
178                         g_free (tmp_str);
179                         tmp_str = NULL;
180                 }
181         }
183         if (str_buf) {
184                 result = (guchar *)str_buf->str;
185                 g_string_free (str_buf, FALSE);
186                 str_buf = NULL;
187         }
189         return result;
192 /**
193  *Dumps the selector to a file.
194  *TODO: add the support of unicode in the dump.
195  *
196  *@param a_this the current instance of #CRSimpleSel.
197  *@param a_fp the destination file pointer.
198  *@return CR_OK upon successfull completion, an error code
199  *otherwise.
200  */
201 enum CRStatus
202 cr_simple_sel_dump (CRSimpleSel * a_this, FILE * a_fp)
204         guchar *tmp_str = NULL;
206         g_return_val_if_fail (a_fp, CR_BAD_PARAM_ERROR);
208         if (a_this) {
209                 tmp_str = cr_simple_sel_to_string (a_this);
210                 if (tmp_str) {
211                         fprintf (a_fp, "%s", tmp_str);
212                         g_free (tmp_str);
213                         tmp_str = NULL;
214                 }
215         }
217         return CR_OK;
220 /**
221  *Computes the selector (combinator separated list of simple selectors)
222  *as defined in the css2 spec in chapter 6.4.3
223  *@param a_this the current instance of #CRSimpleSel
224  *@return CR_OK upon successfull completion, an error code otherwise.
225  */
226 enum CRStatus
227 cr_simple_sel_compute_specificity (CRSimpleSel * a_this)
229         CRAdditionalSel *cur_add_sel = NULL;
230         CRSimpleSel *cur_sel = NULL;
231         gulong a = 0,
232                 b = 0,
233                 c = 0;
235         g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
237         for (cur_sel = a_this; cur_sel; cur_sel = cur_sel->next) {
238                 if (cur_sel->type_mask | TYPE_SELECTOR) {
239                         c++;    /*hmmh, is this a new language ? */
240                 } else if (!cur_sel->name 
241                            || !cur_sel->name->stryng
242                            || !cur_sel->name->stryng->str) {
243                         if (cur_sel->add_sel->type ==
244                             PSEUDO_CLASS_ADD_SELECTOR) {
245                                 /*
246                                  *this is a pseudo element, and
247                                  *the spec says, "ignore pseudo elements".
248                                  */
249                                 continue;
250                         }
251                 }
253                 for (cur_add_sel = cur_sel->add_sel;
254                      cur_add_sel; cur_add_sel = cur_add_sel->next) {
255                         switch (cur_add_sel->type) {
256                         case ID_ADD_SELECTOR:
257                                 a++;
258                                 break;
260                         case NO_ADD_SELECTOR:
261                                 continue;
263                         default:
264                                 b++;
265                                 break;
266                         }
267                 }
268         }
270         /*we suppose a, b and c have 1 to 3 digits */
271         a_this->specificity = a * 1000000 + b * 1000 + c;
273         return CR_OK;
276 /**
277  *The destructor of the current instance of
278  *#CRSimpleSel.
279  *@param a_this the this pointer of the current instance of #CRSimpleSel.
280  *
281  */
282 void
283 cr_simple_sel_destroy (CRSimpleSel * a_this)
285         g_return_if_fail (a_this);
287         if (a_this->name) {
288                 cr_string_destroy (a_this->name);
289                 a_this->name = NULL;
290         }
292         if (a_this->add_sel) {
293                 cr_additional_sel_destroy (a_this->add_sel);
294                 a_this->add_sel = NULL;
295         }
297         if (a_this->next) {
298                 cr_simple_sel_destroy (a_this->next);
299         }
301         if (a_this) {
302                 g_free (a_this);
303         }