X-Git-Url: https://gitweb.michael.orlitzky.com/?a=blobdiff_plain;f=src%2Fsvgtiny.c;h=69cbcf7125b2f7ae540d5743e40be7d0edf3200f;hb=d5060009e934f2715a35601f7e4192702a473216;hp=6215b04adb316b6baa971ac13d6ba5771fdc4b38;hpb=b314f3b54da7892d9f6994ba99082b92b76cf316;p=libsvgtiny.git diff --git a/src/svgtiny.c b/src/svgtiny.c index 6215b04..69cbcf7 100644 --- a/src/svgtiny.c +++ b/src/svgtiny.c @@ -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); @@ -188,6 +206,12 @@ svgtiny_code svgtiny_parse(struct svgtiny_diagram *diagram, dom_node_unref(document); return svgtiny_LIBDOM_ERROR; } + if (svg == NULL) { + /* no root svg element */ + dom_node_unref(document); + return svgtiny_SVG_ERROR; + } + exc = dom_node_get_node_name(svg, &svg_name); if (exc != DOM_NO_ERR) { dom_node_unref(svg); @@ -247,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); @@ -473,18 +496,21 @@ svgtiny_code svgtiny_parse_path(dom_element *path, int n; /* Ensure there is sufficient space for path elements */ - if ((palloc - i) < 7) { - float *tp; - palloc = (palloc * 2) + (palloc / 2); - tp = realloc(p, sizeof p[0] * palloc); - if (tp == NULL) { - free(p); - free(path_d); - svgtiny_cleanup_state_local(&state); - return svgtiny_OUT_OF_MEMORY; - } - p = tp; - } +#define ALLOC_PATH_ELEMENTS(NUM_ELEMENTS) \ + do { \ + if ((palloc - i) < NUM_ELEMENTS) { \ + float *tp; \ + palloc = (palloc * 2) + (palloc / 2); \ + tp = realloc(p, sizeof p[0] * palloc); \ + if (tp == NULL) { \ + free(p); \ + free(path_d); \ + svgtiny_cleanup_state_local(&state); \ + return svgtiny_OUT_OF_MEMORY; \ + } \ + p = tp; \ + } \ + } while(0) /* moveto (M, m), lineto (L, l) (2 arguments) */ @@ -495,6 +521,7 @@ svgtiny_code svgtiny_parse_path(dom_element *path, else plot_command = svgtiny_PATH_LINE; do { + ALLOC_PATH_ELEMENTS(3); p[i++] = plot_command; if ('a' <= *command) { x += last_x; @@ -515,6 +542,8 @@ svgtiny_code svgtiny_parse_path(dom_element *path, /* closepath (Z, z) (no arguments) */ } else if (sscanf(s, " %1[Zz] %n", command, &n) == 1) { /*LOG(("closepath"));*/ + ALLOC_PATH_ELEMENTS(1); + p[i++] = svgtiny_PATH_CLOSE; s += n; last_cubic_x = last_quad_x = last_x = subpath_first_x; @@ -524,6 +553,8 @@ svgtiny_code svgtiny_parse_path(dom_element *path, } else if (sscanf(s, " %1[Hh] %f %n", command, &x, &n) == 2) { /*LOG(("horizontal lineto"));*/ do { + ALLOC_PATH_ELEMENTS(3); + p[i++] = svgtiny_PATH_LINE; if (*command == 'h') x += last_x; @@ -537,6 +568,8 @@ svgtiny_code svgtiny_parse_path(dom_element *path, } else if (sscanf(s, " %1[Vv] %f %n", command, &y, &n) == 2) { /*LOG(("vertical lineto"));*/ do { + ALLOC_PATH_ELEMENTS(3); + p[i++] = svgtiny_PATH_LINE; if (*command == 'v') y += last_y; @@ -544,13 +577,15 @@ 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, &x1, &y1, &x2, &y2, &x, &y, &n) == 7) { /*LOG(("curveto"));*/ do { + ALLOC_PATH_ELEMENTS(7); + p[i++] = svgtiny_PATH_BEZIER; if (*command == 'c') { x1 += last_x; @@ -575,6 +610,8 @@ svgtiny_code svgtiny_parse_path(dom_element *path, &x2, &y2, &x, &y, &n) == 5) { /*LOG(("shorthand/smooth curveto"));*/ do { + ALLOC_PATH_ELEMENTS(7); + p[i++] = svgtiny_PATH_BEZIER; x1 = last_x + (last_x - last_cubic_x); y1 = last_y + (last_y - last_cubic_y); @@ -599,6 +636,8 @@ svgtiny_code svgtiny_parse_path(dom_element *path, &x1, &y1, &x, &y, &n) == 5) { /*LOG(("quadratic Bezier curveto"));*/ do { + ALLOC_PATH_ELEMENTS(7); + p[i++] = svgtiny_PATH_BEZIER; last_quad_x = x1; last_quad_y = y1; @@ -624,6 +663,8 @@ svgtiny_code svgtiny_parse_path(dom_element *path, &x, &y, &n) == 3) { /*LOG(("shorthand/smooth quadratic Bezier curveto"));*/ do { + ALLOC_PATH_ELEMENTS(7); + p[i++] = svgtiny_PATH_BEZIER; x1 = last_x + (last_x - last_quad_x); y1 = last_y + (last_y - last_quad_y); @@ -650,6 +691,8 @@ svgtiny_code svgtiny_parse_path(dom_element *path, &rx, &ry, &rotation, &large_arc, &sweep, &x, &y, &n) == 8) { do { + ALLOC_PATH_ELEMENTS(3); + p[i++] = svgtiny_PATH_LINE; if (*command == 'a') { x += last_x; @@ -681,15 +724,15 @@ svgtiny_code svgtiny_parse_path(dom_element *path, /* resize path element array to not be over allocated */ if (palloc != i) { - float *tp; - - /* try the resize, if it fails just continue to use the old - * allocation - */ - tp = realloc(p, sizeof p[0] * i); - if (tp != NULL) { - p = tp; - } + float *tp; + + /* try the resize, if it fails just continue to use the old + * allocation + */ + tp = realloc(p, sizeof p[0] * i); + if (tp != NULL) { + p = tp; + } } err = svgtiny_add_path(p, i, &state); @@ -1344,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); } @@ -1372,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:"))) { @@ -1380,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:"))) { @@ -1403,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; @@ -1434,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; } @@ -1460,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); } /** @@ -1545,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)) ;