* This file is part of Libsvgtiny
* Licensed under the MIT License,
* http://opensource.org/licenses/mit-license.php
- * Copyright 2008 James Bursa <james@semichrome.net>
+ * Copyright 2008-2009 James Bursa <james@semichrome.net>
*/
#define _GNU_SOURCE /* for strndup */
#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);
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,
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)
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) */
} 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);
}
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;
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 <ellipse> 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;
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] == '%') {
} 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;
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(
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;
}