]> gitweb.michael.orlitzky.com - libsvgtiny.git/blob - src/svgtiny_css.c
src/svgtiny_css.c: implement named_parent_node() select handler
[libsvgtiny.git] / src / svgtiny_css.c
1 #include <libcss/libcss.h>
2
3 #include "svgtiny.h"
4 #include "svgtiny_internal.h"
5
6 static css_error node_name(void *pw, void *node, css_qname *qname);
7 static css_error node_classes(void *pw, void *node,
8 lwc_string ***classes, uint32_t *n_classes);
9 static css_error node_id(void *pw, void *node, lwc_string **id);
10 static css_error named_parent_node(void *pw, void *node,
11 const css_qname *qname, void **parent);
12
13
14 /**
15 * Resolve a relative URL to an absolute one by doing nothing. This is
16 * the simplest possible implementation of a URL resolver, needed for
17 * parsing CSS.
18 */
19 css_error svgtiny_resolve_url(void *pw,
20 const char *base, lwc_string *rel, lwc_string **abs)
21 {
22 UNUSED(pw);
23 UNUSED(base);
24
25 /* Copy the relative URL to the absolute one (the return
26 value) */
27 *abs = lwc_string_ref(rel);
28 return CSS_OK;
29 }
30
31 /**
32 * Create a stylesheet with the default set of params.
33 *
34 * \param sheet A stylesheet pointer, passed in by reference, that
35 * we use to store the newly-created stylesheet.
36 * \param inline_style True if this stylesheet represents an inline
37 * style, and false otherwise.
38 *
39 * \return The return value from css_stylesheet_create() is returned.
40 */
41 css_error svgtiny_create_stylesheet(css_stylesheet **sheet,
42 bool inline_style)
43 {
44 css_stylesheet_params params;
45
46 params.params_version = CSS_STYLESHEET_PARAMS_VERSION_1;
47 params.level = CSS_LEVEL_DEFAULT;
48 params.charset = NULL;
49 params.url = "";
50 params.title = NULL;
51 params.allow_quirks = false;
52 params.inline_style = inline_style;
53 params.resolve = svgtiny_resolve_url;
54 params.resolve_pw = NULL;
55 params.import = NULL;
56 params.import_pw = NULL;
57 params.color = NULL;
58 params.color_pw = NULL;
59 params.font = NULL;
60 params.font_pw = NULL;
61
62 return css_stylesheet_create(&params, sheet);
63 }
64
65
66 /**************************/
67 /* libcss select handlers */
68 /**************************/
69 /*
70 * From here on we implement the "select handler "API defined in
71 * libcss's include/libcss/select.h and discussed briefly in its
72 * docs/API document.
73 */
74
75
76 /**
77 * Retrieve the given node's name
78 *
79 * \param pw Pointer to the current SVG parser state
80 * \param node Libdom SVG node
81 * \param qname Address at which to store the node name
82 *
83 * \return CSS_OK on success, or CSS_NOMEM if anything goes wrong
84 */
85 css_error node_name(void *pw, void *node, css_qname *qname)
86 {
87 dom_string *name;
88 dom_exception err;
89 struct svgtiny_parse_state *state;
90
91 err = dom_node_get_node_name((dom_node *)node, &name);
92 if (err != DOM_NO_ERR) {
93 return CSS_NOMEM;
94 }
95
96 state = (struct svgtiny_parse_state *)pw;
97 qname->ns = lwc_string_ref(state->interned_svg_xmlns);
98
99 err = dom_string_intern(name, &qname->name);
100 if (err != DOM_NO_ERR) {
101 dom_string_unref(name);
102 return CSS_NOMEM;
103 }
104
105 dom_string_unref(name);
106
107 return CSS_OK;
108 }
109
110
111 /**
112 * Retrieve the given node's classes
113 *
114 * \param pw Pointer to the current SVG parser state
115 * \param node Libdom SVG node
116 * \param classes Address at which to store the class name array
117 * \param n_classes Address at which to store the length of the class
118 * name array
119 *
120 * \return CSS_OK on success, or CSS_NOMEM if anything goes wrong
121 *
122 * \note CSS_NOMEM is not possible in practice as of libdom-0.4.1,
123 * because the underlying libdom function never fails
124 */
125 css_error node_classes(void *pw, void *node,
126 lwc_string ***classes, uint32_t *n_classes)
127 {
128 UNUSED(pw);
129 dom_exception err;
130
131 err = dom_element_get_classes((dom_node *)node, classes, n_classes);
132
133 /* The implementation does not do it, but the documentation
134 for dom_element_get_classes() says that a DOM_NO_MEM_ERR is
135 possible here, so we handle it to be on the safe side. */
136 if (err != DOM_NO_ERR) {
137 return CSS_NOMEM;
138 }
139
140 return CSS_OK;
141 }
142
143
144 /**
145 * Retrieve the given node's id
146 *
147 * \param pw Pointer to the current SVG parser state
148 * \param node Libdom SVG node
149 * \param id Address at which to store the id
150 *
151 * \return CSS_OK on success, or CSS_NOMEM if anything goes wrong
152 */
153 css_error node_id(void *pw, void *node, lwc_string **id)
154 {
155 dom_string *attr;
156 dom_exception err;
157 struct svgtiny_parse_state *state;
158
159 /* Begin with the assumption that this node has no id */
160 *id = NULL;
161
162 state = (struct svgtiny_parse_state *)pw;
163 err = dom_element_get_attribute((dom_node *)node,
164 state->interned_id, &attr);
165 if (err != DOM_NO_ERR) {
166 return CSS_NOMEM;
167 }
168 else if (attr == NULL) {
169 /* The node has no id attribute and our return value
170 is already set to NULL so we're done */
171 return CSS_OK;
172 }
173
174 /* If we found an id attribute (a dom_string), intern it into
175 an lwc_string that we can return, and then cleanup the
176 dom_string. */
177 err = dom_string_intern(attr, id);
178 if (err != DOM_NO_ERR) {
179 dom_string_unref(attr);
180 return CSS_NOMEM;
181 }
182 dom_string_unref(attr);
183 return CSS_OK;
184 }
185
186
187
188 /**
189 * Find the first parent of the given element having the given name
190 *
191 * \param pw Pointer to the current SVG parser state
192 * \param node Libdom SVG node
193 * \param qname Name of the parent node to search for
194 * \param parent Address at which to store the parent node pointer
195 *
196 * \return Always returns CSS_OK
197 *
198 * \post If a suitable element is found, a pointer to it will be
199 * stored at the address pointed to by \a parent; otherwise,
200 * NULL will be stored at the address pointed to by \a parent
201 */
202 css_error named_parent_node(void *pw, void *node,
203 const css_qname *qname, void **parent)
204 {
205 UNUSED(pw);
206 /* dom_element_named_parent_node() was invented to implement
207 * this select handler so there isn't much for us to do except
208 * call it. It's OK if node isn't an element, libdom checks
209 * for it. */
210 dom_element_named_parent_node((dom_element *)node,
211 qname->name,
212 (struct dom_element **)parent);
213
214 /* Implementation detail: dom_element_named_parent_node()
215 * increments the reference count of the parent element before
216 * returning it to us. According to docs/RefCnt in the libdom
217 * repository, this will prevent the parent element from being
218 * destroyed if it is pruned from the DOM. That sounds good,
219 * since we don't want to be using a pointer to an object that
220 * has been destroyed... but we also have no way of later
221 * decrementing the reference count ourselves, and don't want
222 * to make the returned node eternal. Decrementing the
223 * reference counter now allows it to be destroyed when the
224 * DOM no longer needs it, and so long as no other parts of
225 * libsvgtiny are messing with the DOM during parsing, that
226 * shouldn't (ha ha) cause any problems. */
227 dom_node_unref(*parent);
228
229 return CSS_OK;
230 }