Initial commit of the HEAD branch of the ELinks CVS repository, as of
[elinks/images.git] / src / document / css / stylesheet.c
blob93cec59e54eec98a8f76bbf75a7880b62c87124a
1 /* CSS stylesheet handling */
2 /* $Id: stylesheet.c,v 1.50 2005/07/09 18:41:52 miciah Exp $ */
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 list_head *sels, enum css_selector_type type,
30 enum css_selector_relation rel,
31 unsigned char *name, int namelen)
33 struct css_selector *selector;
35 assert(sels && name);
37 foreach (selector, *sels) {
38 if (type != selector->type || rel != selector->relation)
39 continue;
40 if (strlcasecmp(name, namelen, selector->name, -1))
41 continue;
42 return selector;
45 return NULL;
48 struct css_selector *
49 init_css_selector(struct list_head *sels, enum css_selector_type type,
50 unsigned char *name, int namelen)
52 struct css_selector *selector;
54 selector = mem_calloc(1, sizeof(*selector));
55 if (!selector) return NULL;
57 selector->relation = CSR_ROOT; /* Default */
58 init_list(selector->leaves);
60 selector->type = type;
61 init_list(selector->properties);
63 if (name) {
64 if (namelen < 0)
65 namelen = strlen(name);
66 selector->name = memacpy(name, namelen);
67 if (!selector->name) {
68 mem_free(selector);
69 return NULL;
71 set_mem_comment(selector, name, namelen);
74 if (sels) {
75 add_to_list(*sels, selector);
78 return selector;
81 struct css_selector *
82 get_css_selector(struct list_head *sels, enum css_selector_type type,
83 enum css_selector_relation rel,
84 unsigned char *name, int namelen)
86 struct css_selector *selector = NULL;
88 if (sels && name && namelen) {
89 selector = find_css_selector(sels, type, rel, name, namelen);
90 if (selector)
91 return selector;
94 selector = init_css_selector(sels, type, name, namelen);
95 if (selector) {
96 selector->relation = rel;
97 return selector;
100 return NULL;
103 static struct css_selector *
104 copy_css_selector(struct css_stylesheet *css, struct css_selector *orig)
106 struct css_selector *copy;
108 assert(css && orig);
110 copy = init_css_selector(&css->selectors, orig->type,
111 orig->name, strlen(orig->name));
112 if (!copy)
113 return NULL;
115 return copy;
118 static void
119 add_selector_property(struct css_selector *selector, struct css_property *prop)
121 struct css_property *newprop = mem_alloc(sizeof(*newprop));
123 if (newprop) {
124 copy_struct(newprop, prop);
125 add_to_list(selector->properties, newprop);
129 void
130 add_selector_properties(struct css_selector *selector,
131 struct list_head *properties)
133 struct css_property *prop;
135 foreach (prop, *properties) {
136 add_selector_property(selector, prop);
140 static struct css_selector *
141 clone_css_selector(struct css_stylesheet *css, struct css_selector *orig)
143 struct css_selector *copy;
145 assert(css && orig);
147 copy = copy_css_selector(css, orig);
148 if (!copy)
149 return NULL;
150 add_selector_properties(copy, &orig->properties);
151 return copy;
154 void
155 merge_css_selectors(struct css_selector *sel1, struct css_selector *sel2)
157 struct css_property *prop;
159 foreach (prop, sel2->properties) {
160 struct css_property *origprop;
162 foreach (origprop, sel1->properties)
163 if (origprop->type == prop->type) {
164 del_from_list(origprop);
165 mem_free(origprop);
166 break;
169 /* Not there yet, let's add it. */
170 add_selector_property(sel1, prop);
174 void
175 done_css_selector(struct css_selector *selector)
177 while (selector->leaves.next != &selector->leaves) {
178 done_css_selector(selector->leaves.next);
181 if (selector->next) del_from_list(selector);
182 free_list(selector->properties);
183 mem_free_if(selector->name);
184 mem_free(selector);
187 #ifdef DEBUG_CSS
188 void
189 dump_css_selector_tree_iter(struct list_head *sels, int level)
191 struct css_selector *sel;
193 foreach (sel, *sels) {
194 struct css_property *prop;
196 fprintf(stderr, "%*s +- [%s] type %d rel %d props",
197 level * 4, " ",
198 sel->name, sel->type, sel->relation);
199 foreach (prop, sel->properties) {
200 fprintf(stderr, " [%d]", prop->type);
202 fprintf(stderr, "\n");
203 dump_css_selector_tree_iter(&sel->leaves, level + 1);
207 void
208 dump_css_selector_tree(struct list_head *sels)
210 dump_css_selector_tree_iter(sels, 0);
212 #endif
215 struct css_stylesheet *
216 init_css_stylesheet(css_stylesheet_importer_T importer, void *import_data)
218 struct css_stylesheet *css;
220 css = mem_calloc(1, sizeof(*css));
221 if (!css)
222 return NULL;
223 css->import = importer;
224 css->import_data = import_data;
225 init_list(css->selectors);
226 return css;
229 void
230 mirror_css_stylesheet(struct css_stylesheet *css1, struct css_stylesheet *css2)
232 struct css_selector *selector;
234 foreach (selector, css1->selectors) {
235 clone_css_selector(css2, selector);
239 #if 0
240 struct css_stylesheet *
241 clone_css_stylesheet(struct css_stylesheet *orig)
243 struct css_stylesheet *copy;
244 struct css_selector *selector;
246 copy = init_css_stylesheet(orig->import, orig->import_data);
247 if (!copy)
248 return NULL;
249 mirror_css_stylesheet(orig, copy);
250 return copy;
253 void
254 merge_css_stylesheets(struct css_stylesheet *css1,
255 struct css_stylesheet *css2)
257 struct css_selector *selector;
259 assert(css1 && css2);
261 /* This is 100% evil. And gonna be a huge bottleneck. Essentially
262 * O(N^2) where we could be much smarter (ie. sort it once and then
263 * always be O(N)). */
265 foreach (selector, css2->selectors) {
266 struct css_selector *origsel;
268 origsel = find_css_selector(&css1->selectors, selector->name,
269 strlen(selector->name));
270 if (!origsel) {
271 clone_css_selector(css1, selector);
272 } else {
273 merge_css_selectors(origsel, selector);
277 #endif
279 void
280 done_css_stylesheet(struct css_stylesheet *css)
282 while (!list_empty(css->selectors)) {
283 done_css_selector(css->selectors.next);