X-Git-Url: https://gitweb.michael.orlitzky.com/?a=blobdiff_plain;f=src%2Fsvgtiny.c;h=be20b20abf1201d356291e313297bdf0bf747592;hb=43b139ddfae30cb636790cd84279f58fe1f4a996;hp=ab6b6dd5ea30f282320fa33bcccd5fff437a5be3;hpb=15cdb30e3125ce542289fe385f559799e5abf220;p=libsvgtiny.git diff --git a/src/svgtiny.c b/src/svgtiny.c index ab6b6dd..be20b20 100644 --- a/src/svgtiny.c +++ b/src/svgtiny.c @@ -2,7 +2,7 @@ * This file is part of Libsvgtiny * Licensed under the MIT License, * http://opensource.org/licenses/mit-license.php - * Copyright 2008 James Bursa + * Copyright 2008-2009 James Bursa */ #define _GNU_SOURCE /* for strndup */ @@ -18,6 +18,11 @@ #include "svgtiny.h" #include "svgtiny_internal.h" +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#define KAPPA 0.5522847498 static svgtiny_code svgtiny_parse_svg(xmlNode *svg, struct svgtiny_parse_state state); @@ -27,6 +32,8 @@ static svgtiny_code svgtiny_parse_rect(xmlNode *rect, struct svgtiny_parse_state state); static svgtiny_code svgtiny_parse_circle(xmlNode *circle, struct svgtiny_parse_state state); +static svgtiny_code svgtiny_parse_ellipse(xmlNode *ellipse, + struct svgtiny_parse_state state); static svgtiny_code svgtiny_parse_line(xmlNode *line, struct svgtiny_parse_state state); static svgtiny_code svgtiny_parse_poly(xmlNode *poly, @@ -183,6 +190,8 @@ svgtiny_code svgtiny_parse_svg(xmlNode *svg, code = svgtiny_parse_rect(child, state); else if (strcmp(name, "circle") == 0) code = svgtiny_parse_circle(child, state); + else if (strcmp(name, "ellipse") == 0) + code = svgtiny_parse_ellipse(child, state); else if (strcmp(name, "line") == 0) code = svgtiny_parse_line(child, state); else if (strcmp(name, "polyline") == 0) @@ -240,7 +249,7 @@ svgtiny_code svgtiny_parse_path(xmlNode *path, while (*s) { char command[2]; int plot_command; - float x, y, x1, y1, x2, y2; + float x, y, x1, y1, x2, y2, rx, ry, rotation, large_arc, sweep; int n; /* moveto (M, m), lineto (L, l) (2 arguments) */ @@ -395,14 +404,39 @@ svgtiny_code svgtiny_parse_path(xmlNode *path, } while (sscanf(s, "%f %f %n", &x, &y, &n) == 2); + /* elliptical arc (A, a) (7 arguments) */ + } else if (sscanf(s, " %1[Aa] %f %f %f %f %f %f %f %n", command, + &rx, &ry, &rotation, &large_arc, &sweep, + &x, &y, &n) == 8) { + do { + p[i++] = svgtiny_PATH_LINE; + if (*command == 'a') { + x += last_x; + y += last_y; + } + p[i++] = last_cubic_x = last_quad_x = last_x + = x; + p[i++] = last_cubic_y = last_quad_y = last_y + = y; + s += n; + } while (sscanf(s, "%f %f %f %f %f %f %f %n", + &rx, &ry, &rotation, &large_arc, &sweep, + &x, &y, &n) == 7); + } else { - /*LOG(("parse failed at \"%s\"", s));*/ + fprintf(stderr, "parse failed at \"%s\"\n", s); break; } } xmlFree(path_d); + if (i <= 4) { + /* no real segments in path */ + free(p); + return svgtiny_OK; + } + return svgtiny_add_path(p, i, &state); } @@ -452,8 +486,7 @@ svgtiny_code svgtiny_parse_rect(xmlNode *rect, svgtiny_code svgtiny_parse_circle(xmlNode *circle, struct svgtiny_parse_state state) { - float x = 0, y = 0, r = 0; - const float kappa = 0.5522847498; + float x = 0, y = 0, r = -1; for (xmlAttr *attr = circle->properties; attr; attr = attr->next) { const char *name = (const char *) attr->name; @@ -471,40 +504,126 @@ svgtiny_code svgtiny_parse_circle(xmlNode *circle, svgtiny_parse_paint_attributes(circle, &state); svgtiny_parse_transform_attributes(circle, &state); + if (r < 0) { + state.diagram->error_line = circle->line; + state.diagram->error_message = "circle: r missing or negative"; + return svgtiny_SVG_ERROR; + } + if (r == 0) + return svgtiny_OK; + float *p = malloc(32 * sizeof p[0]); if (!p) return svgtiny_OUT_OF_MEMORY; p[0] = svgtiny_PATH_MOVE; - p[1] = x - r; + p[1] = x + r; p[2] = y; p[3] = svgtiny_PATH_BEZIER; - p[4] = x - r; - p[5] = y + r * kappa; - p[6] = x - r * kappa; + p[4] = x + r; + p[5] = y + r * KAPPA; + p[6] = x + r * KAPPA; p[7] = y + r; p[8] = x; p[9] = y + r; p[10] = svgtiny_PATH_BEZIER; - p[11] = x + r * kappa; + p[11] = x - r * KAPPA; p[12] = y + r; - p[13] = x + r; - p[14] = y + r * kappa; - p[15] = x + r; + p[13] = x - r; + p[14] = y + r * KAPPA; + p[15] = x - r; p[16] = y; p[17] = svgtiny_PATH_BEZIER; - p[18] = x + r; - p[19] = y - r * kappa; - p[20] = x + r * kappa; + p[18] = x - r; + p[19] = y - r * KAPPA; + p[20] = x - r * KAPPA; p[21] = y - r; p[22] = x; p[23] = y - r; p[24] = svgtiny_PATH_BEZIER; - p[25] = x - r * kappa; + p[25] = x + r * KAPPA; p[26] = y - r; - p[27] = x - r; - p[28] = y - r * kappa; - p[29] = x - r; + p[27] = x + r; + p[28] = y - r * KAPPA; + p[29] = x + r; + p[30] = y; + p[31] = svgtiny_PATH_CLOSE; + + return svgtiny_add_path(p, 32, &state); +} + + +/** + * Parse an element node. + */ + +svgtiny_code svgtiny_parse_ellipse(xmlNode *ellipse, + struct svgtiny_parse_state state) +{ + float x = 0, y = 0, rx = -1, ry = -1; + + for (xmlAttr *attr = ellipse->properties; attr; attr = attr->next) { + const char *name = (const char *) attr->name; + const char *content = (const char *) attr->children->content; + if (strcmp(name, "cx") == 0) + x = svgtiny_parse_length(content, + state.viewport_width, state); + else if (strcmp(name, "cy") == 0) + y = svgtiny_parse_length(content, + state.viewport_height, state); + else if (strcmp(name, "rx") == 0) + rx = svgtiny_parse_length(content, + state.viewport_width, state); + else if (strcmp(name, "ry") == 0) + ry = svgtiny_parse_length(content, + state.viewport_width, state); + } + svgtiny_parse_paint_attributes(ellipse, &state); + svgtiny_parse_transform_attributes(ellipse, &state); + + if (rx < 0 || ry < 0) { + state.diagram->error_line = ellipse->line; + state.diagram->error_message = "ellipse: rx or ry missing " + "or negative"; + return svgtiny_SVG_ERROR; + } + if (rx == 0 || ry == 0) + return svgtiny_OK; + + float *p = malloc(32 * sizeof p[0]); + if (!p) + return svgtiny_OUT_OF_MEMORY; + + p[0] = svgtiny_PATH_MOVE; + p[1] = x + rx; + p[2] = y; + p[3] = svgtiny_PATH_BEZIER; + p[4] = x + rx; + p[5] = y + ry * KAPPA; + p[6] = x + rx * KAPPA; + p[7] = y + ry; + p[8] = x; + p[9] = y + ry; + p[10] = svgtiny_PATH_BEZIER; + p[11] = x - rx * KAPPA; + p[12] = y + ry; + p[13] = x - rx; + p[14] = y + ry * KAPPA; + p[15] = x - rx; + p[16] = y; + p[17] = svgtiny_PATH_BEZIER; + p[18] = x - rx; + p[19] = y - ry * KAPPA; + p[20] = x - rx * KAPPA; + p[21] = y - ry; + p[22] = x; + p[23] = y - ry; + p[24] = svgtiny_PATH_BEZIER; + p[25] = x + rx * KAPPA; + p[26] = y - ry; + p[27] = x + rx; + p[28] = y - ry * KAPPA; + p[29] = x + rx; p[30] = y; p[31] = svgtiny_PATH_CLOSE; @@ -709,6 +828,8 @@ float svgtiny_parse_length(const char *s, int viewport_size, float n = atof((const char *) s); float font_size = 20; /*css_len2px(&state.style.font_size.value.length, 0);*/ + UNUSED(state); + if (unit[0] == 0) { return n; } else if (unit[0] == '%') { @@ -807,7 +928,7 @@ void svgtiny_parse_color(const char *s, svgtiny_colour *c, } else if (10 <= len && s[0] == 'r' && s[1] == 'g' && s[2] == 'b' && s[3] == '(' && s[len - 1] == ')') { - if (sscanf(s + 4, "%i,%i,%i", &r, &g, &b) == 3) + if (sscanf(s + 4, "%u,%u,%u", &r, &g, &b) == 3) *c = svgtiny_RGB(r, g, b); else if (sscanf(s + 4, "%f%%,%f%%,%f%%", &rf, &gf, &bf) == 3) { b = bf * 255 / 100; @@ -856,6 +977,8 @@ void svgtiny_parse_color(const char *s, svgtiny_colour *c, void svgtiny_parse_font_attributes(const xmlNode *node, struct svgtiny_parse_state *state) { + UNUSED(state); + for (const xmlAttr *attr = node->properties; attr; attr = attr->next) { if (strcmp((const char *) attr->name, "font-size") == 0) { /*if (css_parse_length( @@ -1014,8 +1137,10 @@ struct svgtiny_shape *svgtiny_add_shape(struct svgtiny_parse_state *state) shape->text = 0; shape->fill = state->fill; shape->stroke = state->stroke; - shape->stroke_width = state->stroke_width * - (state->ctm.a + state->ctm.d) / 2; + shape->stroke_width = lroundf((float) state->stroke_width * + (state->ctm.a + state->ctm.d) / 2.0); + if (0 < state->stroke_width && shape->stroke_width == 0) + shape->stroke_width = 1; return shape; }