]> gitweb.michael.orlitzky.com - libsvgtiny.git/blobdiff - src/svgtiny.c
Fix parsing of multiple vertical lineto commands
[libsvgtiny.git] / src / svgtiny.c
index bd9aeaa89486ddc873249744feed390d78042801..69cbcf7125b2f7ae540d5743e40be7d0edf3200f 100644 (file)
@@ -20,6 +20,9 @@
 #include "svgtiny.h"
 #include "svgtiny_internal.h"
 
+/* Source file generated by `gperf`. */
+#include "autogenerated_colors.c"
+
 #ifndef M_PI
 #define M_PI           3.14159265358979323846
 #endif
@@ -54,54 +57,74 @@ static void svgtiny_parse_transform_attributes(dom_element *node,
 static svgtiny_code svgtiny_add_path(float *p, unsigned int n,
                struct svgtiny_parse_state *state);
 static void _svgtiny_parse_color(const char *s, svgtiny_colour *c,
+               struct svgtiny_parse_state_gradient *grad,
                struct svgtiny_parse_state *state);
 
 /**
- * Set the local externally-stored parts of a parse state.
- * Call this in functions that made a new state on the stack.
- * Doesn't make own copy of global state, such as the interned string list.
+ * Call this to ref the strings in a gradient state.
  */
-static void svgtiny_setup_state_local(struct svgtiny_parse_state *state)
+static void svgtiny_grad_string_ref(struct svgtiny_parse_state_gradient *grad)
 {
-       if (state->gradient_x1 != NULL) {
-               dom_string_ref(state->gradient_x1);
+       if (grad->gradient_x1 != NULL) {
+               dom_string_ref(grad->gradient_x1);
        }
-       if (state->gradient_y1 != NULL) {
-               dom_string_ref(state->gradient_y1);
+       if (grad->gradient_y1 != NULL) {
+               dom_string_ref(grad->gradient_y1);
        }
-       if (state->gradient_x2 != NULL) {
-               dom_string_ref(state->gradient_x2);
+       if (grad->gradient_x2 != NULL) {
+               dom_string_ref(grad->gradient_x2);
        }
-       if (state->gradient_y2 != NULL) {
-               dom_string_ref(state->gradient_y2);
+       if (grad->gradient_y2 != NULL) {
+               dom_string_ref(grad->gradient_y2);
        }
 }
 
 /**
- * Cleanup the local externally-stored parts of a parse state.
- * Call this in functions that made a new state on the stack.
- * Doesn't cleanup global state, such as the interned string list.
+ * Call this to clean up the strings in a gradient state.
  */
-static void svgtiny_cleanup_state_local(struct svgtiny_parse_state *state)
+static void svgtiny_grad_string_cleanup(
+               struct svgtiny_parse_state_gradient *grad)
 {
-       if (state->gradient_x1 != NULL) {
-               dom_string_unref(state->gradient_x1);
-               state->gradient_x1 = NULL;
+       if (grad->gradient_x1 != NULL) {
+               dom_string_unref(grad->gradient_x1);
+               grad->gradient_x1 = NULL;
        }
-       if (state->gradient_y1 != NULL) {
-               dom_string_unref(state->gradient_y1);
-               state->gradient_y1 = NULL;
+       if (grad->gradient_y1 != NULL) {
+               dom_string_unref(grad->gradient_y1);
+               grad->gradient_y1 = NULL;
        }
-       if (state->gradient_x2 != NULL) {
-               dom_string_unref(state->gradient_x2);
-               state->gradient_x2 = NULL;
+       if (grad->gradient_x2 != NULL) {
+               dom_string_unref(grad->gradient_x2);
+               grad->gradient_x2 = NULL;
        }
-       if (state->gradient_y2 != NULL) {
-               dom_string_unref(state->gradient_y2);
-               state->gradient_y2 = NULL;
+       if (grad->gradient_y2 != NULL) {
+               dom_string_unref(grad->gradient_y2);
+               grad->gradient_y2 = NULL;
        }
 }
 
+/**
+ * Set the local externally-stored parts of a parse state.
+ * Call this in functions that made a new state on the stack.
+ * Doesn't make own copy of global state, such as the interned string list.
+ */
+static void svgtiny_setup_state_local(struct svgtiny_parse_state *state)
+{
+       svgtiny_grad_string_ref(&(state->fill_grad));
+       svgtiny_grad_string_ref(&(state->stroke_grad));
+}
+
+/**
+ * Cleanup the local externally-stored parts of a parse state.
+ * Call this in functions that made a new state on the stack.
+ * Doesn't cleanup global state, such as the interned string list.
+ */
+static void svgtiny_cleanup_state_local(struct svgtiny_parse_state *state)
+{
+       svgtiny_grad_string_cleanup(&(state->fill_grad));
+       svgtiny_grad_string_cleanup(&(state->stroke_grad));
+}
+
 
 /**
  * Create a new svgtiny_diagram structure.
@@ -152,11 +175,6 @@ svgtiny_code svgtiny_parse(struct svgtiny_diagram *diagram,
 
        UNUSED(url);
 
-       state.gradient_x1 = NULL;
-       state.gradient_y1 = NULL;
-       state.gradient_x2 = NULL;
-       state.gradient_y2 = NULL;
-
        parser = dom_xml_parser_create(NULL, NULL,
                                       ignore_msg, NULL, &document);
 
@@ -253,7 +271,6 @@ svgtiny_code svgtiny_parse(struct svgtiny_diagram *diagram,
        state.fill = 0x000000;
        state.stroke = svgtiny_TRANSPARENT;
        state.stroke_width = 1;
-       state.linear_gradient_stop_count = 0;
 
        /* parse tree */
        code = svgtiny_parse_svg(svg, state);
@@ -560,7 +577,7 @@ svgtiny_code svgtiny_parse_path(dom_element *path,
                                p[i++] = last_cubic_y = last_quad_y = last_y
                                                = y;
                                s += n;
-                       } while (sscanf(s, "%f %n", &x, &n) == 1);
+                       } while (sscanf(s, "%f %n", &y, &n) == 1);
 
                /* curveto (C, c) (6 arguments) */
                } else if (sscanf(s, " %1[Cc] %f %f %f %f %f %f %n", command,
@@ -1370,13 +1387,13 @@ void svgtiny_parse_paint_attributes(dom_element *node,
        
        exc = dom_element_get_attribute(node, state->interned_fill, &attr);
        if (exc == DOM_NO_ERR && attr != NULL) {
-               svgtiny_parse_color(attr, &state->fill, state);
+               svgtiny_parse_color(attr, &state->fill, &state->fill_grad, state);
                dom_string_unref(attr);
        }
 
        exc = dom_element_get_attribute(node, state->interned_stroke, &attr);
        if (exc == DOM_NO_ERR && attr != NULL) {
-               svgtiny_parse_color(attr, &state->stroke, state);
+               svgtiny_parse_color(attr, &state->stroke, &state->stroke_grad, state);
                dom_string_unref(attr);
        }
 
@@ -1398,7 +1415,7 @@ void svgtiny_parse_paint_attributes(dom_element *node,
                        while (*s == ' ')
                                s++;
                        value = strndup(s, strcspn(s, "; "));
-                       _svgtiny_parse_color(value, &state->fill, state);
+                       _svgtiny_parse_color(value, &state->fill, &state->fill_grad, state);
                        free(value);
                }
                if ((s = strstr(style, "stroke:"))) {
@@ -1406,7 +1423,7 @@ void svgtiny_parse_paint_attributes(dom_element *node,
                        while (*s == ' ')
                                s++;
                        value = strndup(s, strcspn(s, "; "));
-                       _svgtiny_parse_color(value, &state->stroke, state);
+                       _svgtiny_parse_color(value, &state->stroke, &state->stroke_grad, state);
                        free(value);
                }
                if ((s = strstr(style, "stroke-width:"))) {
@@ -1429,6 +1446,7 @@ void svgtiny_parse_paint_attributes(dom_element *node,
  */
 
 static void _svgtiny_parse_color(const char *s, svgtiny_colour *c,
+               struct svgtiny_parse_state_gradient *grad,
                struct svgtiny_parse_state *state)
 {
        unsigned int r, g, b;
@@ -1460,19 +1478,21 @@ static void _svgtiny_parse_color(const char *s, svgtiny_colour *c,
 
        } else if (5 < len && s[0] == 'u' && s[1] == 'r' && s[2] == 'l' &&
                        s[3] == '(') {
-               if (s[4] == '#') {
+               if (grad == NULL) {
+                       *c = svgtiny_RGB(0, 0, 0);
+               } else if (s[4] == '#') {
                        id = strdup(s + 5);
                        if (!id)
                                return;
                        rparen = strchr(id, ')');
                        if (rparen)
                                *rparen = 0;
-                       svgtiny_find_gradient(id, state);
+                       svgtiny_find_gradient(id, grad, state);
                        free(id);
-                       if (state->linear_gradient_stop_count == 0)
+                       if (grad->linear_gradient_stop_count == 0)
                                *c = svgtiny_TRANSPARENT;
-                       else if (state->linear_gradient_stop_count == 1)
-                               *c = state->gradient_stop[0].color;
+                       else if (grad->linear_gradient_stop_count == 1)
+                               *c = grad->gradient_stop[0].color;
                        else
                                *c = svgtiny_LINEAR_GRADIENT;
                }
@@ -1486,11 +1506,12 @@ static void _svgtiny_parse_color(const char *s, svgtiny_colour *c,
 }
 
 void svgtiny_parse_color(dom_string *s, svgtiny_colour *c,
+               struct svgtiny_parse_state_gradient *grad,
                struct svgtiny_parse_state *state)
 {
-       char *ss = strndup(dom_string_data(s), dom_string_byte_length(s));
-       _svgtiny_parse_color(ss, c, state);
-       free(ss);
+       dom_string_ref(s);
+       _svgtiny_parse_color(dom_string_data(s), c, grad, state);
+       dom_string_unref(s);
 }
 
 /**
@@ -1571,6 +1592,7 @@ void svgtiny_parse_transform(char *s, float *ma, float *mb,
                a = d = 1;
                b = c = 0;
                e = f = 0;
+               n = 0;
                if ((sscanf(s, " matrix (%f %f %f %f %f %f ) %n",
                             &a, &b, &c, &d, &e, &f, &n) == 6) && (n > 0))
                        ;