iconv: Bail out of the loop when an illegal sequence of bytes occurs.
[elinks/elinks-j605.git] / src / document / css / stylesheet.c
blob892f0c5c5a2c8d5a77264cc3d229dc7cdf1c4f97
1 /** CSS stylesheet handling
2 * @file */
4 #ifdef HAVE_CONFIG_H
5 #include "config.h"
6 #endif
8 #include <stdlib.h>
9 #include <string.h>
11 #include "elinks.h"
13 #include "document/css/property.h"
14 #include "document/css/stylesheet.h"
15 #include "util/error.h"
16 #include "util/lists.h"
17 #include "util/memory.h"
18 #include "util/string.h"
21 /* You can find some mysterious functions commented out here. I planned to use
22 * them for various smart things (well they all report to
23 * merge_css_stylesheets()), but it turns out it makes no sense to merge
24 * stylesheets now (and maybe it won't in the future neither...). But maybe you
25 * will find them useful at some time, so... Dunno. --pasky */
28 struct css_selector *
29 find_css_selector(struct css_selector_set *sels,
30 enum css_selector_type type,
31 enum css_selector_relation rel,
32 const unsigned char *name, int namelen)
34 struct css_selector *selector;
36 assert(sels && name);
38 foreach_css_selector (selector, sels) {
39 if (type != selector->type || rel != selector->relation)
40 continue;
41 if (c_strlcasecmp(name, namelen, selector->name, -1))
42 continue;
43 return selector;
46 return NULL;
49 struct css_selector *
50 init_css_selector(struct css_selector_set *sels,
51 enum css_selector_type type,
52 enum css_selector_relation relation,
53 const unsigned char *name, int namelen)
55 struct css_selector *selector;
57 selector = mem_calloc(1, sizeof(*selector));
58 if (!selector) return NULL;
60 selector->relation = relation;
61 init_css_selector_set(&selector->leaves);
63 selector->type = type;
64 init_list(selector->properties);
66 if (name) {
67 if (namelen < 0)
68 namelen = strlen(name);
69 selector->name = memacpy(name, namelen);
70 if (!selector->name) {
71 done_css_selector_set(&selector->leaves);
72 mem_free(selector);
73 return NULL;
75 set_mem_comment(selector, name, namelen);
78 if (sels) {
79 add_css_selector_to_set(selector, sels);
82 return selector;
85 void
86 set_css_selector_relation(struct css_selector *selector,
87 enum css_selector_relation relation)
89 /* Changing the relation after the selector is in a set might require
90 * setting css_relation_set.may_contain_rel_ancestor_or_parent,
91 * but we don't have a pointer to the set here. */
92 assert(!css_selector_is_in_set(selector));
93 selector->relation = relation;
96 struct css_selector *
97 get_css_selector(struct css_selector_set *sels,
98 enum css_selector_type type,
99 enum css_selector_relation rel,
100 const unsigned char *name, int namelen)
102 struct css_selector *selector = NULL;
104 if (sels && name && namelen) {
105 selector = find_css_selector(sels, type, rel, name, namelen);
106 if (selector)
107 return selector;
110 return init_css_selector(sels, type, rel, name, namelen);
113 static struct css_selector *
114 copy_css_selector(struct css_stylesheet *css, struct css_selector *orig)
116 struct css_selector *copy;
118 assert(css && orig);
119 assert(orig->relation == CSR_ROOT);
121 copy = init_css_selector(&css->selectors, orig->type, CSR_ROOT,
122 orig->name, strlen(orig->name));
123 if (!copy)
124 return NULL;
126 return copy;
129 static void
130 add_selector_property(struct css_selector *selector, struct css_property *prop)
132 struct css_property *newprop = mem_alloc(sizeof(*newprop));
134 if (newprop) {
135 copy_struct(newprop, prop);
136 add_to_list(selector->properties, newprop);
140 void
141 add_selector_properties(struct css_selector *selector,
142 LIST_OF(struct css_property) *properties)
144 struct css_property *prop;
146 foreach (prop, *properties) {
147 add_selector_property(selector, prop);
151 static struct css_selector *
152 clone_css_selector(struct css_stylesheet *css, struct css_selector *orig)
154 struct css_selector *copy;
156 assert(css && orig);
158 copy = copy_css_selector(css, orig);
159 if (!copy)
160 return NULL;
161 add_selector_properties(copy, &orig->properties);
162 return copy;
165 void
166 merge_css_selectors(struct css_selector *sel1, struct css_selector *sel2)
168 struct css_property *prop;
170 foreach (prop, sel2->properties) {
171 struct css_property *origprop;
173 foreach (origprop, sel1->properties)
174 if (origprop->type == prop->type) {
175 del_from_list(origprop);
176 mem_free(origprop);
177 break;
180 /* Not there yet, let's add it. */
181 add_selector_property(sel1, prop);
185 void
186 done_css_selector(struct css_selector *selector)
188 done_css_selector_set(&selector->leaves);
190 if (css_selector_is_in_set(selector))
191 del_css_selector_from_set(selector);
192 free_list(selector->properties);
193 mem_free_if(selector->name);
194 mem_free(selector);
197 void
198 init_css_selector_set(struct css_selector_set *set)
200 set->may_contain_rel_ancestor_or_parent = 0;
201 init_list(set->list);
204 void
205 done_css_selector_set(struct css_selector_set *set)
207 while (!css_selector_set_empty(set)) {
208 done_css_selector(css_selector_set_front(set));
212 void
213 add_css_selector_to_set(struct css_selector *selector,
214 struct css_selector_set *set)
216 assert(!css_selector_is_in_set(selector));
218 add_to_list(set->list, selector);
219 if (selector->relation == CSR_ANCESTOR
220 || selector->relation == CSR_PARENT)
221 set->may_contain_rel_ancestor_or_parent = 1;
224 void
225 del_css_selector_from_set(struct css_selector *selector)
227 del_from_list(selector);
228 selector->next = NULL;
229 selector->prev = NULL;
232 #ifdef DEBUG_CSS
233 void
234 dump_css_selector_tree_iter(struct css_selector_set *sels, int level)
236 struct css_selector *sel;
238 foreach_css_selector (sel, sels) {
239 struct css_property *prop;
241 fprintf(stderr, "%*s +- [%s] type %d rel %d props",
242 level * 4, " ",
243 sel->name, sel->type, sel->relation);
244 foreach (prop, sel->properties) {
245 fprintf(stderr, " [%d]", prop->type);
247 fprintf(stderr, "\n");
248 dump_css_selector_tree_iter(&sel->leaves, level + 1);
252 void
253 dump_css_selector_tree(struct css_selector_set *sels)
255 dump_css_selector_tree_iter(sels, 0);
257 #endif
260 #if 0 /* used only by clone_css_stylesheet */
261 struct css_stylesheet *
262 init_css_stylesheet(css_stylesheet_importer_T importer, void *import_data)
264 struct css_stylesheet *css;
266 css = mem_calloc(1, sizeof(*css));
267 if (!css)
268 return NULL;
269 css->import = importer;
270 css->import_data = import_data;
271 init_css_selector_set(&css->selectors);
272 return css;
274 #endif
276 void
277 mirror_css_stylesheet(struct css_stylesheet *css1, struct css_stylesheet *css2)
279 struct css_selector *selector;
281 foreach_css_selector (selector, &css1->selectors) {
282 clone_css_selector(css2, selector);
286 #if 0
287 struct css_stylesheet *
288 clone_css_stylesheet(struct css_stylesheet *orig)
290 struct css_stylesheet *copy;
291 struct css_selector *selector;
293 copy = init_css_stylesheet(orig->import, orig->import_data);
294 if (!copy)
295 return NULL;
296 mirror_css_stylesheet(orig, copy);
297 return copy;
300 void
301 merge_css_stylesheets(struct css_stylesheet *css1,
302 struct css_stylesheet *css2)
304 struct css_selector *selector;
306 assert(css1 && css2);
308 /* This is 100% evil. And gonna be a huge bottleneck. Essentially
309 * O(N^2) where we could be much smarter (ie. sort it once and then
310 * always be O(N)). */
312 foreach_css_selector (selector, &css2->selectors) {
313 struct css_selector *origsel;
315 origsel = find_css_selector(&css1->selectors, selector->name,
316 strlen(selector->name));
317 if (!origsel) {
318 clone_css_selector(css1, selector);
319 } else {
320 merge_css_selectors(origsel, selector);
324 #endif
326 void
327 done_css_stylesheet(struct css_stylesheet *css)
329 done_css_selector_set(&css->selectors);