#define degToRad(angleInDegrees) ((angleInDegrees) * M_PI / 180.0)
#define radToDeg(angleInRadians) ((angleInRadians) * 180.0 / M_PI)
+static svgtiny_code svgtiny_parse_style_element(dom_element *style,
+ struct svgtiny_parse_state state);
+static svgtiny_code svgtiny_preparse_styles(dom_element *svg,
+ struct svgtiny_parse_state state);
static svgtiny_code svgtiny_parse_svg(dom_element *svg,
struct svgtiny_parse_state state);
static svgtiny_code svgtiny_parse_path(dom_element *path,
state.stroke_width = 1;
/* parse tree */
- code = svgtiny_parse_svg(svg, state);
+ code = svgtiny_preparse_styles(svg, state);
+ if (code == svgtiny_OK) {
+ code = svgtiny_parse_svg(svg, state);
+ }
dom_node_unref(svg);
dom_node_unref(document);
}
+/**
+ * Parse a single <style> element, appending the result to the CSS
+ * select context within the given parser state.
+ */
+svgtiny_code svgtiny_parse_style_element(dom_element *style,
+ struct svgtiny_parse_state state)
+{
+ css_stylesheet *sheet;
+ css_error code;
+ dom_exception exc;
+
+ code = svgtiny_create_stylesheet(&sheet, false);
+ if (code != CSS_OK) {
+ return svgtiny_LIBCSS_ERROR;
+ }
+
+ /* Parse the style element's "media" attribute if it has
+ one. We don't do anything with it right now. */
+ dom_string *media_attr;
+ exc = dom_element_get_attribute(style, state.interned_media,
+ &media_attr);
+ if (exc != DOM_NO_ERR) {
+ css_stylesheet_destroy(sheet);
+ return svgtiny_LIBDOM_ERROR;
+ }
+
+ if (media_attr) {
+ /* Here's where we'd actually change the media type if
+ we were going to use it */
+ dom_string_unref(media_attr);
+ }
+
+ dom_string *data;
+ dom_node_get_text_content(style, &data);
+ if (data == NULL) {
+ /* Empty stylesheet? That's fine. */
+ css_stylesheet_destroy(sheet);
+ return svgtiny_OK;
+ }
+
+ code = css_stylesheet_append_data(sheet,
+ (uint8_t *)dom_string_data(data),
+ dom_string_byte_length(data));
+ if (code != CSS_OK && code != CSS_NEEDDATA) {
+ dom_string_unref(data);
+ css_stylesheet_destroy(sheet);
+ return svgtiny_LIBCSS_ERROR;
+ }
+
+ code = css_stylesheet_data_done(sheet);
+ if (code != CSS_OK) {
+ dom_string_unref(data);
+ css_stylesheet_destroy(sheet);
+ return svgtiny_LIBCSS_ERROR;
+ }
+
+ code = css_select_ctx_append_sheet(state.select_ctx,
+ sheet,
+ CSS_ORIGIN_AUTHOR,
+ NULL);
+ if (code != CSS_OK) {
+ dom_string_unref(data);
+ return svgtiny_LIBCSS_ERROR;
+ }
+
+ dom_string_unref(data);
+ return svgtiny_OK;
+}
+
+
+/**
+ * Parse all <style> elements within a root <svg> element. This
+ * should be called before svgtiny_parse_svg() because that function
+ * makes a single pass through the document and we'd like all style
+ * information to be available during that pass. Specifically, we'd
+ * like a <style> sheet at the end of the document to affect the
+ * rendering of elements at its beginning.
+ *
+ * The element-parsing inner loop here is essentially the same as
+ * that within svgtiny_parse_svg().
+ */
+svgtiny_code svgtiny_preparse_styles(dom_element *svg,
+ struct svgtiny_parse_state state)
+{
+ dom_element *child;
+ dom_exception exc;
+
+ exc = dom_node_get_first_child(svg, (dom_node **) (void *) &child);
+ if (exc != DOM_NO_ERR) {
+ return svgtiny_LIBDOM_ERROR;
+ }
+ while (child != NULL) {
+ dom_element *next;
+ dom_node_type nodetype;
+ svgtiny_code code = svgtiny_OK;
+
+ exc = dom_node_get_node_type(child, &nodetype);
+ if (exc != DOM_NO_ERR) {
+ dom_node_unref(child);
+ return svgtiny_LIBDOM_ERROR;
+ }
+ if (nodetype == DOM_ELEMENT_NODE) {
+ dom_string *nodename;
+ exc = dom_node_get_node_name(child, &nodename);
+ if (exc != DOM_NO_ERR) {
+ dom_node_unref(child);
+ return svgtiny_LIBDOM_ERROR;
+ }
+
+ if (dom_string_caseless_isequal(state.interned_style,
+ nodename)) {
+ /* We have a <style> element, parse it */
+ code = svgtiny_parse_style_element(child,
+ state);
+ }
+
+
+ dom_string_unref(nodename);
+ }
+ if (code != svgtiny_OK) {
+ dom_node_unref(child);
+ return code;
+ }
+ exc = dom_node_get_next_sibling(child,
+ (dom_node **) (void *) &next);
+ dom_node_unref(child);
+ if (exc != DOM_NO_ERR) {
+ return svgtiny_LIBDOM_ERROR;
+ }
+ child = next;
+ }
+
+ return svgtiny_OK;
+}
+
/**
* Parse a <svg> or <g> element node.
*/