#include #include "svgtiny.h" #include "svgtiny_internal.h" static css_error node_name(void *pw, void *node, css_qname *qname); static css_error node_classes(void *pw, void *node, lwc_string ***classes, uint32_t *n_classes); static css_error node_id(void *pw, void *node, lwc_string **id); static css_error named_parent_node(void *pw, void *node, const css_qname *qname, void **parent); /** * Resolve a relative URL to an absolute one by doing nothing. This is * the simplest possible implementation of a URL resolver, needed for * parsing CSS. */ css_error svgtiny_resolve_url(void *pw, const char *base, lwc_string *rel, lwc_string **abs) { UNUSED(pw); UNUSED(base); /* Copy the relative URL to the absolute one (the return value) */ *abs = lwc_string_ref(rel); return CSS_OK; } /** * Create a stylesheet with the default set of params. * * \param sheet A stylesheet pointer, passed in by reference, that * we use to store the newly-created stylesheet. * \param inline_style True if this stylesheet represents an inline * style, and false otherwise. * * \return The return value from css_stylesheet_create() is returned. */ css_error svgtiny_create_stylesheet(css_stylesheet **sheet, bool inline_style) { css_stylesheet_params params; params.params_version = CSS_STYLESHEET_PARAMS_VERSION_1; params.level = CSS_LEVEL_DEFAULT; params.charset = NULL; params.url = ""; params.title = NULL; params.allow_quirks = false; params.inline_style = inline_style; params.resolve = svgtiny_resolve_url; params.resolve_pw = NULL; params.import = NULL; params.import_pw = NULL; params.color = NULL; params.color_pw = NULL; params.font = NULL; params.font_pw = NULL; return css_stylesheet_create(¶ms, sheet); } /**************************/ /* libcss select handlers */ /**************************/ /* * From here on we implement the "select handler "API defined in * libcss's include/libcss/select.h and discussed briefly in its * docs/API document. */ /** * Retrieve the given node's name * * \param pw Pointer to the current SVG parser state * \param node Libdom SVG node * \param qname Address at which to store the node name * * \return CSS_OK on success, or CSS_NOMEM if anything goes wrong */ css_error node_name(void *pw, void *node, css_qname *qname) { dom_string *name; dom_exception err; struct svgtiny_parse_state *state; err = dom_node_get_node_name((dom_node *)node, &name); if (err != DOM_NO_ERR) { return CSS_NOMEM; } state = (struct svgtiny_parse_state *)pw; qname->ns = lwc_string_ref(state->interned_svg_xmlns); err = dom_string_intern(name, &qname->name); if (err != DOM_NO_ERR) { dom_string_unref(name); return CSS_NOMEM; } dom_string_unref(name); return CSS_OK; } /** * Retrieve the given node's classes * * \param pw Pointer to the current SVG parser state * \param node Libdom SVG node * \param classes Address at which to store the class name array * \param n_classes Address at which to store the length of the class * name array * * \return CSS_OK on success, or CSS_NOMEM if anything goes wrong * * \note CSS_NOMEM is not possible in practice as of libdom-0.4.1, * because the underlying libdom function never fails */ css_error node_classes(void *pw, void *node, lwc_string ***classes, uint32_t *n_classes) { UNUSED(pw); dom_exception err; err = dom_element_get_classes((dom_node *)node, classes, n_classes); /* The implementation does not do it, but the documentation for dom_element_get_classes() says that a DOM_NO_MEM_ERR is possible here, so we handle it to be on the safe side. */ if (err != DOM_NO_ERR) { return CSS_NOMEM; } return CSS_OK; } /** * Retrieve the given node's id * * \param pw Pointer to the current SVG parser state * \param node Libdom SVG node * \param id Address at which to store the id * * \return CSS_OK on success, or CSS_NOMEM if anything goes wrong */ css_error node_id(void *pw, void *node, lwc_string **id) { dom_string *attr; dom_exception err; struct svgtiny_parse_state *state; /* Begin with the assumption that this node has no id */ *id = NULL; state = (struct svgtiny_parse_state *)pw; err = dom_element_get_attribute((dom_node *)node, state->interned_id, &attr); if (err != DOM_NO_ERR) { return CSS_NOMEM; } else if (attr == NULL) { /* The node has no id attribute and our return value is already set to NULL so we're done */ return CSS_OK; } /* If we found an id attribute (a dom_string), intern it into an lwc_string that we can return, and then cleanup the dom_string. */ err = dom_string_intern(attr, id); if (err != DOM_NO_ERR) { dom_string_unref(attr); return CSS_NOMEM; } dom_string_unref(attr); return CSS_OK; } /** * Find the first parent of the given element having the given name * * \param pw Pointer to the current SVG parser state * \param node Libdom SVG node * \param qname Name of the parent node to search for * \param parent Address at which to store the parent node pointer * * \return Always returns CSS_OK * * \post If a suitable element is found, a pointer to it will be * stored at the address pointed to by \a parent; otherwise, * NULL will be stored at the address pointed to by \a parent */ css_error named_parent_node(void *pw, void *node, const css_qname *qname, void **parent) { UNUSED(pw); /* dom_element_named_parent_node() was invented to implement * this select handler so there isn't much for us to do except * call it. It's OK if node isn't an element, libdom checks * for it. */ dom_element_named_parent_node((dom_element *)node, qname->name, (struct dom_element **)parent); /* Implementation detail: dom_element_named_parent_node() * increments the reference count of the parent element before * returning it to us. According to docs/RefCnt in the libdom * repository, this will prevent the parent element from being * destroyed if it is pruned from the DOM. That sounds good, * since we don't want to be using a pointer to an object that * has been destroyed... but we also have no way of later * decrementing the reference count ourselves, and don't want * to make the returned node eternal. Decrementing the * reference counter now allows it to be destroyed when the * DOM no longer needs it, and so long as no other parts of * libsvgtiny are messing with the DOM during parsing, that * shouldn't (ha ha) cause any problems. */ dom_node_unref(*parent); return CSS_OK; }