1 /* 2 * Copyright (c) 2009, 2010 Aggelos Economopoulos. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in 12 * the documentation and/or other materials provided with the 13 * distribution. 14 * 3. Neither the name of The DragonFly Project nor the names of its 15 * contributors may be used to endorse or promote products derived 16 * from this software without specific, prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 22 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 28 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <assert.h> 33 #include <math.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 37 #include "xml.h" 38 #include "svg.h" 39 #include "trivial.h" 40 41 enum { 42 MAX_VALSTR_LEN = 30, 43 }; 44 45 struct svg_rect { 46 struct xml_element el; 47 struct xml_attribute x, y, w, h, cl; 48 char x_val[MAX_VALSTR_LEN]; 49 char y_val[MAX_VALSTR_LEN]; 50 char w_val[MAX_VALSTR_LEN]; 51 char h_val[MAX_VALSTR_LEN]; 52 }; 53 54 struct svg_text { 55 struct xml_element el; 56 struct xml_attribute x, y, cl; 57 struct xml_attribute fontsize, transform; 58 char x_val[MAX_VALSTR_LEN]; 59 char y_val[MAX_VALSTR_LEN]; 60 char fontsize_val[MAX_VALSTR_LEN]; 61 char transform_val[MAX_VALSTR_LEN * 4]; 62 }; 63 64 struct svg_line { 65 struct xml_element el; 66 struct xml_attribute x1, y1, x2, y2, cl; 67 struct xml_attribute transform; 68 char x1_val[MAX_VALSTR_LEN], y1_val[MAX_VALSTR_LEN]; 69 char x2_val[MAX_VALSTR_LEN], y2_val[MAX_VALSTR_LEN]; 70 char transform_val[MAX_VALSTR_LEN * 6]; 71 }; 72 73 struct svg_document { 74 xml_document_t xml; 75 const char *css; 76 struct xml_element svg; 77 struct xml_attribute svg_attrs[2]; 78 struct svg_text text; 79 }; 80 81 static char default_css[] = 82 "<![CDATA[" 83 "rect.generic { fill: green; stroke: black; stroke-width: 0.01;}" 84 "rect.thread { fill: yellow; stroke: black; stroke-width: 0.01;}" 85 "rect.inactive { fill: grey; stroke: black; stroke-width: 0.01;}" 86 "text.generic { fill: black; stroke: none;}]]>"; 87 88 static 89 int 90 svg_transform_print(svg_transform_t tf, char *buf, size_t len) 91 { 92 static double eps = 0.0001; 93 char *p; 94 int c; 95 96 if (!tf) { 97 assert(len >= 1); 98 buf[0] = '\0'; 99 return 0; 100 } 101 p = buf; 102 if ((fabs(tf->tx) > eps) && (fabs(tf->ty) > eps)) { 103 c = snprintf(buf, len, "translate(%.20lf,%.20lf)", tf->tx, 104 tf->ty); 105 len -= c; 106 if (len <= 0) 107 return !0; 108 p += c; 109 } 110 if ((fabs(tf->sx - 1) > eps) && (fabs(tf->sy - 1) > eps)) { 111 c = snprintf(p, len, "%sscale(%.20lf,%.20lf)", 112 (p == buf) ? "" : " ", tf->sx, tf->sy); 113 len -= c; 114 if (len <= 0) 115 return !0; 116 p += c; 117 } 118 if (fabs(tf->rot) > eps) { 119 c = snprintf(p, len, "%srotate(%.2lf)", 120 (p == buf) ? "" : " ", tf->rot); 121 len -= c; 122 if (len <= 0) 123 return !0; 124 p += c; 125 } 126 return 0; 127 } 128 129 static 130 void 131 svg_rect_init(struct svg_rect *rect, const char *cl) 132 { 133 xml_elem_init(&rect->el, "rect"); 134 xml_attribute_init(&rect->x, "x", NULL); 135 xml_elem_set_attribute(&rect->el, &rect->x); 136 xml_attribute_init(&rect->y, "y", NULL); 137 xml_elem_set_attribute(&rect->el, &rect->y); 138 xml_attribute_init(&rect->w, "width", NULL); 139 xml_elem_set_attribute(&rect->el, &rect->w); 140 xml_attribute_init(&rect->h, "height", NULL); 141 xml_elem_set_attribute(&rect->el, &rect->h); 142 if (cl) { 143 xml_attribute_init(&rect->cl, "class", cl); 144 xml_elem_set_attribute(&rect->el, &rect->cl); 145 } 146 } 147 148 /* 149 * In the future, we might want to stick the rectangle in the 150 * <defs> element at this point and then <use> it in the rest 151 * of the document. 152 */ 153 struct svg_rect * 154 svg_rect_new(const char *cl) 155 { 156 struct svg_rect *r; 157 158 if (!(r = malloc(sizeof(*r)))) 159 return r; 160 svg_rect_init(r, cl); 161 return r; 162 } 163 164 165 int 166 svg_rect_draw(svg_document_t doc, struct svg_rect *rect, double x, 167 double y, double w, double h) 168 { 169 snprintf(&rect->x_val[0], sizeof(rect->x_val), "%.20lf", x); 170 xml_attribute_set_value(&rect->x, &rect->x_val[0]); 171 snprintf(&rect->y_val[0], sizeof(rect->y_val), "%lf", y); 172 xml_attribute_set_value(&rect->y, &rect->y_val[0]); 173 snprintf(&rect->w_val[0], sizeof(rect->w_val), "%.20lf", w); 174 xml_attribute_set_value(&rect->w, &rect->w_val[0]); 175 snprintf(&rect->h_val[0], sizeof(rect->h_val), "%lf", h); 176 xml_attribute_set_value(&rect->h, &rect->h_val[0]); 177 178 xml_elem_closed(doc->xml, &rect->el); 179 return 0; 180 } 181 182 static 183 void 184 svg_text_init(struct svg_text *text, const char *cl) 185 { 186 xml_elem_init(&text->el, "text"); 187 #if remove 188 xml_attribute_init(&text->x, "x", NULL); 189 xml_elem_set_attribute(&text->el, &text->x); 190 xml_attribute_init(&text->y, "y", NULL); 191 xml_elem_set_attribute(&text->el, &text->y); 192 #endif 193 xml_attribute_init(&text->fontsize, "font-size", NULL); 194 xml_elem_set_attribute(&text->el, &text->fontsize); 195 xml_attribute_init(&text->transform, "transform", NULL); 196 xml_elem_set_attribute(&text->el, &text->transform); 197 198 if (cl) { 199 xml_attribute_init(&text->cl, "class", cl); 200 xml_elem_set_attribute(&text->el, &text->cl); 201 } 202 203 } 204 205 struct svg_text * 206 svg_text_new(const char *cl) 207 { 208 svg_text_t text; 209 210 if (!(text = malloc(sizeof(*text)))) 211 return text; 212 svg_text_init(text, cl); 213 return text; 214 } 215 216 int 217 svg_text_draw(svg_document_t doc, svg_text_t text, svg_transform_t tf, 218 const char *str, double fontsize) 219 { 220 #if remove 221 snprintf(&text->x_val[0], sizeof(text->x_val), "%.20lf", x); 222 xml_attribute_set_value(&text->x, &text->x_val[0]); 223 snprintf(&text->y_val[0], sizeof(text->y_val), "%.20lf", y); 224 xml_attribute_set_value(&text->y, &text->y_val[0]); 225 #endif 226 snprintf(&text->fontsize_val[0], sizeof(text->fontsize_val), "%.20lf", 227 fontsize); 228 xml_attribute_set_value(&text->fontsize, &text->fontsize_val[0]); 229 if (svg_transform_print(tf, &text->transform_val[0], 230 sizeof(text->transform_val))) 231 return !0; 232 xml_attribute_set_value(&text->transform, &text->transform_val[0]); 233 xml_elem_set_value(&text->el, str); 234 235 xml_elem_closed(doc->xml, &text->el); 236 return 0; 237 } 238 239 static 240 void 241 svg_line_init(struct svg_line *line, const char *cl) 242 { 243 xml_elem_init(&line->el, "line"); 244 xml_attribute_init(&line->x1, "x1", NULL); 245 xml_elem_set_attribute(&line->el, &line->x1); 246 xml_attribute_init(&line->x2, "x2", NULL); 247 xml_elem_set_attribute(&line->el, &line->x2); 248 xml_attribute_init(&line->y1, "y1", NULL); 249 xml_elem_set_attribute(&line->el, &line->y1); 250 xml_attribute_init(&line->y2, "y2", NULL); 251 xml_elem_set_attribute(&line->el, &line->y2); 252 253 xml_attribute_init(&line->transform, "transform", NULL); 254 xml_elem_set_attribute(&line->el, &line->transform); 255 256 if (cl) { 257 xml_attribute_init(&line->cl, "class", cl); 258 xml_elem_set_attribute(&line->el, &line->cl); 259 } 260 261 } 262 263 struct svg_line * 264 svg_line_new(const char *cl) 265 { 266 svg_line_t line; 267 268 if (!(line = malloc(sizeof(*line)))) 269 return line; 270 svg_line_init(line, cl); 271 return line; 272 } 273 274 int 275 svg_line_draw(svg_document_t doc, svg_line_t line, double x1, double _y1, 276 double x2, double y2, svg_transform_t tf) 277 { 278 snprintf(&line->x1_val[0], sizeof(line->x1_val), "%.20lf", x1); 279 xml_attribute_set_value(&line->x1, &line->x1_val[0]); 280 281 snprintf(&line->x2_val[0], sizeof(line->x2_val), "%.20lf", x2); 282 xml_attribute_set_value(&line->x2, &line->x2_val[0]); 283 284 snprintf(&line->y1_val[0], sizeof(line->y1_val), "%.10lf", _y1); 285 xml_attribute_set_value(&line->y1, &line->y1_val[0]); 286 287 snprintf(&line->y2_val[0], sizeof(line->y2_val), "%.20lf", y2); 288 xml_attribute_set_value(&line->y2, &line->y2_val[0]); 289 290 xml_attribute_set_value(&line->transform, &line->transform_val[0]); 291 if (svg_transform_print(tf, 292 &line->transform_val[0], 293 sizeof(line->transform_val))) 294 return !0; 295 xml_elem_closed(doc->xml, &line->el); 296 return 0; 297 } 298 299 svg_document_t 300 svg_document_create(const char *path) 301 { 302 svg_document_t svg; 303 struct xml_element style, defs; 304 struct xml_attribute type; 305 306 if (!(svg = malloc(sizeof(*svg)))) 307 return NULL; 308 if (!(svg->xml = xml_document_create(path))) { 309 free(svg); 310 return NULL; 311 } 312 svg->css = &default_css[0]; 313 xml_attribute_init(&type, "type", "text/css"); 314 xml_elem_init(&defs, "defs"); 315 xml_elem_init(&style, "style"); 316 xml_elem_set_attribute(&style, &type); 317 xml_elem_init(&svg->svg, "svg"); 318 xml_attribute_init(&svg->svg_attrs[0], "version", "1.1"); 319 xml_elem_set_attribute(&svg->svg, &svg->svg_attrs[0]); 320 xml_attribute_init(&svg->svg_attrs[1], "xmlns", 321 "http://www.w3.org/2000/svg"); 322 xml_elem_set_attribute(&svg->svg, &svg->svg_attrs[1]); 323 xml_elem_begin(svg->xml, &svg->svg); 324 xml_elem_begin(svg->xml, &defs); 325 xml_elem_set_value(&style, svg->css); 326 xml_elem_closed(svg->xml, &style); 327 xml_elem_close(svg->xml, &defs); 328 329 return svg; 330 } 331 332 int 333 svg_document_close(svg_document_t svg) 334 { 335 xml_elem_close(svg->xml, &svg->svg); 336 xml_document_close(svg->xml); 337 return 0; 338 } 339