1 //
2 // Copyright (c) 2009 Mikko Mononen memon@inside.org
3 //
4 // This software is provided 'as-is', without any express or implied
5 // warranty. In no event will the authors be held liable for any damages
6 // arising from the use of this software.
7 // Permission is granted to anyone to use this software for any purpose,
8 // including commercial applications, and to alter it and redistribute it
9 // freely, subject to the following restrictions:
10 // 1. The origin of this software must not be misrepresented; you must not
11 // claim that you wrote the original software. If you use this software
12 // in a product, an acknowledgment in the product documentation would be
13 // appreciated but is not required.
14 // 2. Altered source versions must be plainly marked as such, and must not be
15 // misrepresented as being the original software.
16 // 3. This notice may not be removed or altered from any source distribution.
17 //
18
19 // The SVG parser is based on Anti-Graim Geometry SVG example
20 // Copyright (C) 2002-2004 Maxim Shemanarev (McSeem)
21
22 #include "nanosvg.h"
23 #include <string.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <math.h>
27 #include <ctype.h>
28
29 #ifndef M_PI
30 #define M_PI 3.14159265358979323846264338327
31 #endif
32
33 #ifdef _MSC_VER
34 #pragma warning (disable: 4996) // Switch off security warnings
35 #endif
36
37 // Simple XML parser
38
39 #define TAG 1
40 #define CONTENT 2
41 #define MAX_ATTRIBS 256
42
parseContent(char * s,void (* contentCb)(void * ud,const char * s),void * ud)43 static void parseContent(char* s,
44 void (*contentCb)(void* ud, const char* s),
45 void* ud)
46 {
47 // Trim start white spaces
48 while (*s && isspace(*s)) s++;
49 if (!*s) return;
50
51 if (contentCb)
52 (*contentCb)(ud, s);
53 }
54
parseElement(char * s,void (* startelCb)(void * ud,const char * el,const char ** attr),void (* endelCb)(void * ud,const char * el),void * ud)55 static void parseElement(char* s,
56 void (*startelCb)(void* ud, const char* el, const char** attr),
57 void (*endelCb)(void* ud, const char* el),
58 void* ud)
59 {
60 const char* attr[MAX_ATTRIBS];
61 int nattr = 0;
62 char* name;
63 int start = 0;
64 int end = 0;
65
66 // Skip white space after the '<'
67 while (*s && isspace(*s)) s++;
68
69 // Check if the tag is end tag
70 if (*s == '/')
71 {
72 s++;
73 end = 1;
74 }
75 else
76 {
77 start = 1;
78 }
79
80 // Skip comments, data and preprocessor stuff.
81 if (!*s || *s == '?' || *s == '!')
82 return;
83
84 // Get tag name
85 name = s;
86 while (*s && !isspace(*s)) s++;
87 if (*s) { *s++ = '\0'; }
88
89 // Get attribs
90 while (!end && *s && nattr < MAX_ATTRIBS-1)
91 {
92 // Skip white space before the attrib name
93 while (*s && isspace(*s)) s++;
94 if (!*s) break;
95 if (*s == '/')
96 {
97 end = 1;
98 break;
99 }
100 attr[nattr++] = s;
101 // Find end of the attrib name.
102 while (*s && !isspace(*s) && *s != '=') s++;
103 if (*s) { *s++ = '\0'; }
104 // Skip until the beginning of the value.
105 while (*s && *s != '\"') s++;
106 if (!*s) break;
107 s++;
108 // Store value and find the end of it.
109 attr[nattr++] = s;
110 while (*s && *s != '\"') s++;
111 if (*s) { *s++ = '\0'; }
112 }
113
114 // List terminator
115 attr[nattr++] = 0;
116 attr[nattr++] = 0;
117
118 // Call callbacks.
119 if (start && startelCb)
120 (*startelCb)(ud, name, attr);
121 if (end && endelCb)
122 (*endelCb)(ud, name);
123 }
124
parsexml(char * input,void (* startelCb)(void * ud,const char * el,const char ** attr),void (* endelCb)(void * ud,const char * el),void (* contentCb)(void * ud,const char * s),void * ud)125 int parsexml(char* input,
126 void (*startelCb)(void* ud, const char* el, const char** attr),
127 void (*endelCb)(void* ud, const char* el),
128 void (*contentCb)(void* ud, const char* s),
129 void* ud)
130 {
131 char* s = input;
132 char* mark = s;
133 int state = CONTENT;
134 while (*s)
135 {
136 if (*s == '<' && state == CONTENT)
137 {
138 // Start of a tag
139 *s++ = '\0';
140 parseContent(mark, contentCb, ud);
141 mark = s;
142 state = TAG;
143 }
144 else if (*s == '>' && state == TAG)
145 {
146 // Start of a content or new tag.
147 *s++ = '\0';
148 parseElement(mark, startelCb, endelCb, ud);
149 mark = s;
150 state = CONTENT;
151 }
152 else
153 s++;
154 }
155
156 return 1;
157 }
158
159
160 /* Simple SVG parser. */
161
162 #define SVG_MAX_ATTR 128
163
164 struct SVGAttrib
165 {
166 float xform[6];
167 unsigned int fillColor;
168 unsigned int strokeColor;
169 float fillOpacity;
170 float strokeOpacity;
171 float strokeWidth;
172 char hasFill;
173 char hasStroke;
174 char visible;
175 };
176
177 struct SVGParser
178 {
179 struct SVGAttrib attr[SVG_MAX_ATTR];
180 int attrHead;
181 float* buf;
182 int nbuf;
183 int cbuf;
184 struct SVGPath* plist;
185 char pathFlag;
186 char defsFlag;
187 float tol;
188 };
189
xformSetIdentity(float * t)190 static void xformSetIdentity(float* t)
191 {
192 t[0] = 1.0f; t[1] = 0.0f;
193 t[2] = 0.0f; t[3] = 1.0f;
194 t[4] = 0.0f; t[5] = 0.0f;
195 }
196
xformSetTranslation(float * t,float tx,float ty)197 static void xformSetTranslation(float* t, float tx, float ty)
198 {
199 t[0] = 1.0f; t[1] = 0.0f;
200 t[2] = 0.0f; t[3] = 1.0f;
201 t[4] = tx; t[5] = ty;
202 }
203
xformSetScale(float * t,float sx,float sy)204 static void xformSetScale(float* t, float sx, float sy)
205 {
206 t[0] = sx; t[1] = 0.0f;
207 t[2] = 0.0f; t[3] = sy;
208 t[4] = 0.0f; t[5] = 0.0f;
209 }
210
xformMultiply(float * t,float * s)211 static void xformMultiply(float* t, float* s)
212 {
213 float t0 = t[0] * s[0] + t[1] * s[2];
214 float t2 = t[2] * s[0] + t[3] * s[2];
215 float t4 = t[4] * s[0] + t[5] * s[2] + s[4];
216 t[1] = t[0] * s[1] + t[1] * s[3];
217 t[3] = t[2] * s[1] + t[3] * s[3];
218 t[5] = t[4] * s[1] + t[5] * s[3] + s[5];
219 t[0] = t0;
220 t[2] = t2;
221 t[4] = t4;
222 }
223
xformPremultiply(float * t,float * s)224 static void xformPremultiply(float* t, float* s)
225 {
226 float s2[6];
227 memcpy(s2, s, sizeof(float)*6);
228 xformMultiply(s2, t);
229 memcpy(t, s2, sizeof(float)*6);
230 }
231
svgCreateParser()232 static struct SVGParser* svgCreateParser()
233 {
234 struct SVGParser* p;
235 p = (struct SVGParser*)malloc(sizeof(struct SVGParser));
236 if (!p)
237 return NULL;
238 memset(p, 0, sizeof(struct SVGParser));
239
240 // Init style
241 xformSetIdentity(p->attr[0].xform);
242 p->attr[0].fillColor = 0;
243 p->attr[0].strokeColor = 0;
244 p->attr[0].fillOpacity = 1;
245 p->attr[0].strokeOpacity = 1;
246 p->attr[0].strokeWidth = 1;
247 p->attr[0].hasFill = 0;
248 p->attr[0].hasStroke = 0;
249 p->attr[0].visible = 1;
250
251 return p;
252 }
253
svgDeleteParser(struct SVGParser * p)254 static void svgDeleteParser(struct SVGParser* p)
255 {
256 struct SVGPath* path;
257 struct SVGPath* next;
258 path = p->plist;
259 while (path)
260 {
261 next = path->next;
262 if (path->pts)
263 free(path->pts);
264 free(path);
265 path = next;
266 }
267 if (p->buf)
268 free(p->buf);
269 free(p);
270 }
271
svgResetPath(struct SVGParser * p)272 static void svgResetPath(struct SVGParser* p)
273 {
274 p->nbuf = 0;
275 }
276
svgPathPoint(struct SVGParser * p,float x,float y)277 static void svgPathPoint(struct SVGParser* p, float x, float y)
278 {
279 int cap;
280 float* buf;
281 if (p->nbuf+1 > p->cbuf)
282 {
283 cap = p->cbuf ? p->cbuf*2 : 8;
284 buf = (float*)malloc(cap*2*sizeof(float));
285 if (!buf) return;
286 if (p->nbuf)
287 memcpy(buf, p->buf, p->nbuf*2*sizeof(float));
288 if (p->buf)
289 free(p->buf);
290 p->buf = buf;
291 p->cbuf = cap;
292 }
293 p->buf[p->nbuf*2+0] = x;
294 p->buf[p->nbuf*2+1] = y;
295 p->nbuf++;
296 }
297
svgGetAttr(struct SVGParser * p)298 static struct SVGAttrib* svgGetAttr(struct SVGParser* p)
299 {
300 return &p->attr[p->attrHead];
301 }
302
svgPushAttr(struct SVGParser * p)303 static void svgPushAttr(struct SVGParser* p)
304 {
305 if (p->attrHead < SVG_MAX_ATTR-1)
306 {
307 p->attrHead++;
308 memcpy(&p->attr[p->attrHead], &p->attr[p->attrHead-1], sizeof(struct SVGAttrib));
309 }
310 }
311
svgPopAttr(struct SVGParser * p)312 static void svgPopAttr(struct SVGParser* p)
313 {
314 if (p->attrHead > 0)
315 p->attrHead--;
316 }
317
svgCreatePath(struct SVGParser * p,char closed)318 static void svgCreatePath(struct SVGParser* p, char closed)
319 {
320 float* t;
321 float* pt;
322 struct SVGAttrib* attr;
323 struct SVGPath* path;
324 int i;
325
326 if (!p)
327 return;
328
329 if (!p->nbuf)
330 {
331 return;
332 }
333
334 attr = svgGetAttr(p);
335
336 path = (struct SVGPath*)malloc(sizeof(struct SVGPath));
337 if (!path)
338 return;
339 memset(path, 0, sizeof(struct SVGPath));
340 path->pts = (float*)malloc(p->nbuf*2*sizeof(float));
341 if (!path->pts)
342 {
343 free(path);
344 return;
345 }
346 path->closed = closed;
347 path->npts = p->nbuf;
348
349 path->next = p->plist;
350 p->plist = path;
351
352 // Transform path.
353 t = attr->xform;
354 for (i = 0; i < p->nbuf; ++i)
355 {
356 pt = &p->buf[i*2];
357 path->pts[i*2+0] = pt[0]*t[0] + pt[1]*t[2] + t[4];
358 path->pts[i*2+1] = pt[0]*t[1] + pt[1]*t[3] + t[5];
359 }
360
361 path->hasFill = attr->hasFill;
362 path->hasStroke = attr->hasStroke;
363 path->strokeWidth = attr->strokeWidth * t[0];
364
365 path->fillColor = attr->fillColor;
366 if (path->hasFill)
367 path->fillColor |= (unsigned int)(attr->fillOpacity*255) << 24;
368
369 path->strokeColor = attr->strokeColor;
370 if (path->hasStroke)
371 path->strokeColor |= (unsigned int)(attr->strokeOpacity*255) << 24;
372 }
373
isnum(char c)374 static int isnum(char c)
375 {
376 return strchr("0123456789+-.eE", c) != 0;
377 }
378
379 /*static const char* parsePathFloats(const char* s, float* arg, int n)
380 {
381 char num[64];
382 const char* start;
383 int nnum;
384 int i = 0;
385 while (*s && i < n)
386 {
387 // Skip white spaces and commas
388 while (*s && (isspace(*s) || *s == ',')) s++;
389 if (!*s) break;
390 start = s;
391 nnum = 0;
392 while (*s && isnum(*s))
393 {
394 if (nnum < 63) num[nnum++] = *s;
395 s++;
396 }
397 num[nnum] = '\0';
398 arg[i++] = (float)atof(num);
399 }
400 return s;
401 }*/
402
403
getNextPathItem(const char * s,char * it)404 static const char* getNextPathItem(const char* s, char* it)
405 {
406 int i = 0;
407 it[0] = '\0';
408 // Skip white spaces and commas
409 while (*s && (isspace(*s) || *s == ',')) s++;
410 if (!*s) return s;
411 if (*s == '-' || *s == '+' || isnum(*s))
412 {
413 while (*s == '-' || *s == '+')
414 {
415 if (i < 63) it[i++] = *s;
416 s++;
417 }
418 while (*s && *s != '-' && *s != '+' && isnum(*s))
419 {
420 if (i < 63) it[i++] = *s;
421 s++;
422 }
423 it[i] = '\0';
424 }
425 else
426 {
427 it[0] = *s++;
428 it[1] = '\0';
429 return s;
430 }
431 return s;
432 }
433
434
parseColor(const char * str)435 static unsigned int parseColor(const char* str)
436 {
437 unsigned c = 0;
438 while(*str == ' ') ++str;
439 if (*str == '#')
440 sscanf(str + 1, "%x", &c);
441 return c;
442 }
443
parseFloat(const char * str)444 static float parseFloat(const char* str)
445 {
446 while (*str == ' ') ++str;
447 return (float)atof(str);
448 }
449
parseTransformArgs(const char * str,float * args,int maxNa,int * na)450 static int parseTransformArgs(const char* str, float* args, int maxNa, int* na)
451 {
452 const char* end;
453 const char* ptr;
454
455 *na = 0;
456 ptr = str;
457 while (*ptr && *ptr != '(') ++ptr;
458 if (*ptr == 0)
459 return 1;
460 end = ptr;
461 while (*end && *end != ')') ++end;
462 if (*end == 0)
463 return 1;
464
465 while (ptr < end)
466 {
467 if (isnum(*ptr))
468 {
469 if (*na >= maxNa) return 0;
470 args[(*na)++] = (float)atof(ptr);
471 while (ptr < end && isnum(*ptr)) ++ptr;
472 }
473 else
474 {
475 ++ptr;
476 }
477 }
478 return (int)(end - str);
479 }
480
svgParseMatrix(struct SVGParser * p,const char * str)481 static int svgParseMatrix(struct SVGParser* p, const char* str)
482 {
483 float t[6];
484 int na = 0;
485 int len = parseTransformArgs(str, t, 6, &na);
486 if (na != 6) return len;
487 xformPremultiply(svgGetAttr(p)->xform, t);
488 return len;
489 }
490
svgParseTranslate(struct SVGParser * p,const char * str)491 static int svgParseTranslate(struct SVGParser* p, const char* str)
492 {
493 float args[2];
494 float t[6];
495 int na = 0;
496 int len = parseTransformArgs(str, args, 2, &na);
497 if (na == 1) args[1] = 0.0;
498 xformSetTranslation(t, args[0], args[1]);
499 xformPremultiply(svgGetAttr(p)->xform, t);
500 return len;
501 }
502
svgParseScale(struct SVGParser * p,const char * str)503 static int svgParseScale(struct SVGParser* p, const char* str)
504 {
505 float args[2];
506 int na = 0;
507 float t[6];
508 int len = parseTransformArgs(str, args, 2, &na);
509 if (na == 1) args[1] = args[0];
510 xformSetScale(t, args[0], args[1]);
511 xformPremultiply(svgGetAttr(p)->xform, t);
512 return len;
513 }
514
svgParseTransform(struct SVGParser * p,const char * str)515 static void svgParseTransform(struct SVGParser* p, const char* str)
516 {
517 while (*str)
518 {
519 if (strncmp(str, "matrix", 6) == 0)
520 str += svgParseMatrix(p, str);
521 else if (strncmp(str, "translate", 9) == 0)
522 str += svgParseTranslate(p, str);
523 else if (strncmp(str, "scale", 5) == 0)
524 str += svgParseScale(p, str);
525 else
526 ++str;
527 }
528 }
529
530 static void svgParseStyle(struct SVGParser* p, const char* str);
531
svgParseAttr(struct SVGParser * p,const char * name,const char * value)532 static int svgParseAttr(struct SVGParser* p, const char* name, const char* value)
533 {
534 struct SVGAttrib* attr = svgGetAttr(p);
535 if (!attr) return 0;
536
537 if (strcmp(name, "style") == 0)
538 {
539 svgParseStyle(p, value);
540 }
541 else if (strcmp(name, "display") == 0)
542 {
543 if (strcmp(value, "none") == 0)
544 attr->visible = 0;
545 else
546 attr->visible = 1;
547 }
548 else if (strcmp(name, "fill") == 0)
549 {
550 if (strcmp(value, "none") == 0)
551 {
552 attr->hasFill = 0;
553 }
554 else
555 {
556 attr->hasFill = 1;
557 attr->fillColor = parseColor(value);
558 }
559 }
560 else if (strcmp(name, "fill-opacity") == 0)
561 {
562 attr->fillOpacity = parseFloat(value);
563 }
564 else if (strcmp(name, "stroke") == 0)
565 {
566 if (strcmp(value, "none") == 0)
567 {
568 attr->hasStroke = 0;
569 }
570 else
571 {
572 attr->hasStroke = 1;
573 attr->strokeColor = parseColor(value);
574 }
575 }
576 else if (strcmp(name, "stroke-width") == 0)
577 {
578 attr->strokeWidth = parseFloat(value);
579 }
580 else if (strcmp(name, "stroke-opacity") == 0)
581 {
582 attr->strokeOpacity = parseFloat(value);
583 }
584 else if (strcmp(name, "transform") == 0)
585 {
586 svgParseTransform(p, value);
587 }
588 else
589 {
590 return 0;
591 }
592 return 1;
593 }
594
svgParseNameValue(struct SVGParser * p,const char * start,const char * end)595 static int svgParseNameValue(struct SVGParser* p, const char* start, const char* end)
596 {
597 const char* str;
598 const char* val;
599 char name[512];
600 char value[512];
601 int n;
602
603 str = start;
604 while (str < end && *str != ':') ++str;
605
606 val = str;
607
608 // Right Trim
609 while (str > start && (*str == ':' || isspace(*str))) --str;
610 ++str;
611
612 n = (int)(str - start);
613 if (n > 511) n = 511;
614 if (n) memcpy(name, start, n);
615 name[n] = 0;
616
617 while (val < end && (*val == ':' || isspace(*val))) ++val;
618
619 n = (int)(end - val);
620 if (n > 511) n = 511;
621 if (n) memcpy(value, val, n);
622 value[n] = 0;
623
624 return svgParseAttr(p, name, value);
625 }
626
svgParseStyle(struct SVGParser * p,const char * str)627 static void svgParseStyle(struct SVGParser* p, const char* str)
628 {
629 const char* start;
630 const char* end;
631
632 while (*str)
633 {
634 // Left Trim
635 while(*str && isspace(*str)) ++str;
636 start = str;
637 while(*str && *str != ';') ++str;
638 end = str;
639
640 // Right Trim
641 while (end > start && (*end == ';' || isspace(*end))) --end;
642 ++end;
643
644 svgParseNameValue(p, start, end);
645 if (*str) ++str;
646 }
647 }
648
svgParseAttribs(struct SVGParser * p,const char ** attr)649 static void svgParseAttribs(struct SVGParser* p, const char** attr)
650 {
651 int i;
652 for (i = 0; attr[i]; i += 2)
653 {
654 if (strcmp(attr[i], "style") == 0)
655 svgParseStyle(p, attr[i + 1]);
656 else
657 svgParseAttr(p, attr[i], attr[i + 1]);
658 }
659 }
660
getArgsPerElement(char cmd)661 static int getArgsPerElement(char cmd)
662 {
663 switch (tolower(cmd))
664 {
665 case 'v':
666 case 'h':
667 return 1;
668 case 'm':
669 case 'l':
670 case 't':
671 return 2;
672 case 'q':
673 case 's':
674 return 4;
675 case 'c':
676 return 6;
677 case 'a':
678 return 7;
679 }
680 return 0;
681 }
682
distPtSeg(float x,float y,float px,float py,float qx,float qy)683 static float distPtSeg(float x, float y, float px, float py, float qx, float qy)
684 {
685 float pqx, pqy, dx, dy, d, t;
686 pqx = qx-px;
687 pqy = qy-py;
688 dx = x-px;
689 dy = y-py;
690 d = pqx*pqx + pqy*pqy;
691 t = pqx*dx + pqy*dy;
692 if (d > 0) t /= d;
693 if (t < 0) t = 0;
694 else if (t > 1) t = 1;
695 dx = px + t*pqx - x;
696 dy = py + t*pqy - y;
697 return dx*dx + dy*dy;
698 }
699
cubicBezRec(struct SVGParser * p,float x1,float y1,float x2,float y2,float x3,float y3,float x4,float y4,int level)700 static void cubicBezRec(struct SVGParser* p,
701 float x1, float y1, float x2, float y2,
702 float x3, float y3, float x4, float y4,
703 int level)
704 {
705 float x12,y12,x23,y23,x34,y34,x123,y123,x234,y234,x1234,y1234;
706 float d;
707
708 if (level > 12) return;
709
710 x12 = (x1+x2)*0.5f;
711 y12 = (y1+y2)*0.5f;
712 x23 = (x2+x3)*0.5f;
713 y23 = (y2+y3)*0.5f;
714 x34 = (x3+x4)*0.5f;
715 y34 = (y3+y4)*0.5f;
716 x123 = (x12+x23)*0.5f;
717 y123 = (y12+y23)*0.5f;
718 x234 = (x23+x34)*0.5f;
719 y234 = (y23+y34)*0.5f;
720 x1234 = (x123+x234)*0.5f;
721 y1234 = (y123+y234)*0.5f;
722
723 d = distPtSeg(x1234, y1234, x1,y1, x4,y4);
724 if (level > 0 && d < p->tol*p->tol)
725 {
726 svgPathPoint(p, x1234, y1234);
727 return;
728 }
729
730 cubicBezRec(p, x1,y1, x12,y12, x123,y123, x1234,y1234, level+1);
731 cubicBezRec(p, x1234,y1234, x234,y234, x34,y34, x4,y4, level+1);
732 }
733
cubicBez(struct SVGParser * p,float x1,float y1,float cx1,float cy1,float cx2,float cy2,float x2,float y2)734 static void cubicBez(struct SVGParser* p,
735 float x1, float y1, float cx1, float cy1,
736 float cx2, float cy2, float x2, float y2)
737 {
738 cubicBezRec(p, x1,y1, cx1,cy1, cx2,cy2, x2,y2, 0);
739 svgPathPoint(p, x2, y2);
740 }
741
quadBezRec(struct SVGParser * p,float x1,float y1,float x2,float y2,float x3,float y3,int level)742 static void quadBezRec(struct SVGParser* p,
743 float x1, float y1, float x2, float y2, float x3, float y3,
744 int level)
745 {
746 float x12,y12,x23,y23,x123,y123,d;
747
748 if (level > 12) return;
749
750 x12 = (x1+x2)*0.5f;
751 y12 = (y1+y2)*0.5f;
752 x23 = (x2+x3)*0.5f;
753 y23 = (y2+y3)*0.5f;
754 x123 = (x12+x23)*0.5f;
755 y123 = (y12+y23)*0.5f;
756
757 d = distPtSeg(x123, y123, x1,y1, x3,y3);
758 if (level > 0 && d < p->tol*p->tol)
759 {
760 svgPathPoint(p, x123, y123);
761 return;
762 }
763
764 quadBezRec(p, x1,y1, x12,y12, x123,y123, level+1);
765 quadBezRec(p, x123,y123, x23,y23, x3,y3, level+1);
766 }
767
quadBez(struct SVGParser * p,float x1,float y1,float cx,float cy,float x2,float y2)768 static void quadBez(struct SVGParser* p,
769 float x1, float y1, float cx, float cy, float x2, float y2)
770 {
771 quadBezRec(p, x1,y1, cx,cy, x2,y2, 0);
772 svgPathPoint(p, x2, y2);
773 }
774
pathLineTo(struct SVGParser * p,float * cpx,float * cpy,float * args,int rel)775 static void pathLineTo(struct SVGParser* p, float* cpx, float* cpy, float* args, int rel)
776 {
777 if (rel)
778 {
779 *cpx += args[0];
780 *cpy += args[1];
781 }
782 else
783 {
784 *cpx = args[0];
785 *cpy = args[1];
786 }
787 svgPathPoint(p, *cpx, *cpy);
788 }
789
pathHLineTo(struct SVGParser * p,float * cpx,float * cpy,float * args,int rel)790 static void pathHLineTo(struct SVGParser* p, float* cpx, float* cpy, float* args, int rel)
791 {
792 if (rel)
793 *cpx += args[0];
794 else
795 *cpx = args[0];
796 svgPathPoint(p, *cpx, *cpy);
797 }
798
pathVLineTo(struct SVGParser * p,float * cpx,float * cpy,float * args,int rel)799 static void pathVLineTo(struct SVGParser* p, float* cpx, float* cpy, float* args, int rel)
800 {
801 if (rel)
802 *cpy += args[0];
803 else
804 *cpy = args[0];
805 svgPathPoint(p, *cpx, *cpy);
806 }
807
pathCubicBezTo(struct SVGParser * p,float * cpx,float * cpy,float * cpx2,float * cpy2,float * args,int rel)808 static void pathCubicBezTo(struct SVGParser* p, float* cpx, float* cpy,
809 float* cpx2, float* cpy2, float* args, int rel)
810 {
811 float x1, y1, x2, y2, cx1, cy1, cx2, cy2;
812
813 x1 = *cpx;
814 y1 = *cpy;
815 if (rel)
816 {
817 cx1 = *cpx + args[0];
818 cy1 = *cpy + args[1];
819 cx2 = *cpx + args[2];
820 cy2 = *cpy + args[3];
821 x2 = *cpx + args[4];
822 y2 = *cpy + args[5];
823 }
824 else
825 {
826 cx1 = args[0];
827 cy1 = args[1];
828 cx2 = args[2];
829 cy2 = args[3];
830 x2 = args[4];
831 y2 = args[5];
832 }
833
834 cubicBez(p, x1,y1, cx1,cy1, cx2,cy2, x2,y2);
835
836 *cpx2 = cx2;
837 *cpy2 = cy2;
838 *cpx = x2;
839 *cpy = y2;
840 }
841
pathCubicBezShortTo(struct SVGParser * p,float * cpx,float * cpy,float * cpx2,float * cpy2,float * args,int rel)842 static void pathCubicBezShortTo(struct SVGParser* p, float* cpx, float* cpy,
843 float* cpx2, float* cpy2, float* args, int rel)
844 {
845 float x1, y1, x2, y2, cx1, cy1, cx2, cy2;
846
847 x1 = *cpx;
848 y1 = *cpy;
849 if (rel)
850 {
851 cx2 = *cpx + args[0];
852 cy2 = *cpy + args[1];
853 x2 = *cpx + args[2];
854 y2 = *cpy + args[3];
855 }
856 else
857 {
858 cx2 = args[0];
859 cy2 = args[1];
860 x2 = args[2];
861 y2 = args[3];
862 }
863
864 cx1 = 2*x1 - *cpx2;
865 cy1 = 2*y1 - *cpy2;
866
867 cubicBez(p, x1,y1, cx1,cy1, cx2,cy2, x2,y2);
868
869 *cpx2 = cx2;
870 *cpy2 = cy2;
871 *cpx = x2;
872 *cpy = y2;
873 }
874
pathQuadBezTo(struct SVGParser * p,float * cpx,float * cpy,float * cpx2,float * cpy2,float * args,int rel)875 static void pathQuadBezTo(struct SVGParser* p, float* cpx, float* cpy,
876 float* cpx2, float* cpy2, float* args, int rel)
877 {
878 float x1, y1, x2, y2, cx, cy;
879
880 x1 = *cpx;
881 y1 = *cpy;
882 if (rel)
883 {
884 cx = *cpx + args[0];
885 cy = *cpy + args[1];
886 x2 = *cpx + args[2];
887 y2 = *cpy + args[3];
888 }
889 else
890 {
891 cx = args[0];
892 cy = args[1];
893 x2 = args[2];
894 y2 = args[3];
895 }
896
897 quadBez(p, x1,y1, cx,cy, x2,y2);
898
899 *cpx2 = cx;
900 *cpy2 = cy;
901 *cpx = x2;
902 *cpy = y2;
903 }
904
pathQuadBezShortTo(struct SVGParser * p,float * cpx,float * cpy,float * cpx2,float * cpy2,float * args,int rel)905 static void pathQuadBezShortTo(struct SVGParser* p, float* cpx, float* cpy,
906 float* cpx2, float* cpy2, float* args, int rel)
907 {
908 float x1, y1, x2, y2, cx, cy;
909
910 x1 = *cpx;
911 y1 = *cpy;
912 if (rel)
913 {
914 x2 = *cpx + args[0];
915 y2 = *cpy + args[1];
916 }
917 else
918 {
919 x2 = args[0];
920 y2 = args[1];
921 }
922
923 cx = 2*x1 - *cpx2;
924 cy = 2*y1 - *cpy2;
925
926 quadBez(p, x1,y1, cx,cy, x2,y2);
927
928 *cpx2 = cx;
929 *cpy2 = cy;
930 *cpx = x2;
931 *cpy = y2;
932 }
933
svgParsePath(struct SVGParser * p,const char ** attr)934 static void svgParsePath(struct SVGParser* p, const char** attr)
935 {
936 const char* s;
937 char cmd;
938 float args[10];
939 int nargs;
940 int rargs;
941 float cpx, cpy, cpx2, cpy2;
942 const char* tmp[4];
943 char closedFlag;
944 int i;
945 char item[64];
946
947 for (i = 0; attr[i]; i += 2)
948 {
949 if (strcmp(attr[i], "d") == 0)
950 {
951 s = attr[i + 1];
952
953 svgResetPath(p);
954 closedFlag = 0;
955 nargs = 0;
956
957 while (*s)
958 {
959 s = getNextPathItem(s, item);
960 if (!*item) break;
961
962 if (isnum(item[0]))
963 {
964 if (nargs < 10)
965 args[nargs++] = (float)atof(item);
966 if (nargs >= rargs)
967 {
968 switch (cmd)
969 {
970 case 'm':
971 case 'M':
972 case 'l':
973 case 'L':
974 pathLineTo(p, &cpx, &cpy, args, (cmd == 'm' || cmd == 'l') ? 1 : 0);
975 break;
976 case 'H':
977 case 'h':
978 pathHLineTo(p, &cpx, &cpy, args, cmd == 'h' ? 1 : 0);
979 break;
980 case 'V':
981 case 'v':
982 pathVLineTo(p, &cpx, &cpy, args, cmd == 'v' ? 1 : 0);
983 break;
984 case 'C':
985 case 'c':
986 pathCubicBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'c' ? 1 : 0);
987 break;
988 case 'S':
989 case 's':
990 pathCubicBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 's' ? 1 : 0);
991 break;
992 case 'Q':
993 case 'q':
994 pathQuadBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'q' ? 1 : 0);
995 break;
996 case 'T':
997 case 't':
998 pathQuadBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 's' ? 1 : 0);
999 break;
1000 default:
1001 if (nargs >= 2)
1002 {
1003 cpx = args[nargs-2];
1004 cpy = args[nargs-1];
1005 }
1006 break;
1007 }
1008 nargs = 0;
1009 }
1010 }
1011 else
1012 {
1013 cmd = item[0];
1014 rargs = getArgsPerElement(cmd);
1015 if (cmd == 'M' || cmd == 'm')
1016 {
1017 // Commit path.
1018 if (p->nbuf)
1019 svgCreatePath(p, closedFlag);
1020 // Start new subpath.
1021 svgResetPath(p);
1022 closedFlag = 0;
1023 nargs = 0;
1024 cpx = 0; cpy = 0;
1025 }
1026 else if (cmd == 'Z' || cmd == 'z')
1027 {
1028 closedFlag = 1;
1029 // Commit path.
1030 if (p->nbuf)
1031 svgCreatePath(p, closedFlag);
1032 // Start new subpath.
1033 svgResetPath(p);
1034 closedFlag = 0;
1035 nargs = 0;
1036 }
1037 }
1038 }
1039
1040 // Commit path.
1041 if (p->nbuf)
1042 svgCreatePath(p, closedFlag);
1043
1044 }
1045 else
1046 {
1047 tmp[0] = attr[i];
1048 tmp[1] = attr[i + 1];
1049 tmp[2] = 0;
1050 tmp[3] = 0;
1051 svgParseAttribs(p, tmp);
1052 }
1053 }
1054 }
1055
svgParseRect(struct SVGParser * p,const char ** attr)1056 static void svgParseRect(struct SVGParser* p, const char** attr)
1057 {
1058 float x = 0.0f;
1059 float y = 0.0f;
1060 float w = 0.0f;
1061 float h = 0.0f;
1062 int i;
1063
1064 for (i = 0; attr[i]; i += 2)
1065 {
1066 if (!svgParseAttr(p, attr[i], attr[i + 1]))
1067 {
1068 if (strcmp(attr[i], "x") == 0) x = parseFloat(attr[i+1]);
1069 if (strcmp(attr[i], "y") == 0) y = parseFloat(attr[i+1]);
1070 if (strcmp(attr[i], "width") == 0) w = parseFloat(attr[i+1]);
1071 if (strcmp(attr[i], "height") == 0) h = parseFloat(attr[i+1]);
1072 }
1073 }
1074
1075 if (w != 0.0f && h != 0.0f)
1076 {
1077 svgResetPath(p);
1078
1079 svgPathPoint(p, x, y);
1080 svgPathPoint(p, x+w, y);
1081 svgPathPoint(p, x+w, y+h);
1082 svgPathPoint(p, x, y+h);
1083
1084 svgCreatePath(p, 1);
1085 }
1086 }
1087
svgParseCircle(struct SVGParser * p,const char ** attr)1088 static void svgParseCircle(struct SVGParser* p, const char** attr)
1089 {
1090 float cx = 0.0f;
1091 float cy = 0.0f;
1092 float r = 0.0f;
1093 float da;
1094 int i,n;
1095 float x,y,u;
1096
1097 for (i = 0; attr[i]; i += 2)
1098 {
1099 if (!svgParseAttr(p, attr[i], attr[i + 1]))
1100 {
1101 if (strcmp(attr[i], "cx") == 0) cx = parseFloat(attr[i+1]);
1102 if (strcmp(attr[i], "cy") == 0) cy = parseFloat(attr[i+1]);
1103 if (strcmp(attr[i], "r") == 0) r = fabsf(parseFloat(attr[i+1]));
1104 }
1105 }
1106
1107 if (r != 0.0f)
1108 {
1109 svgResetPath(p);
1110
1111 da = acosf(r/(r+p->tol))*2;
1112 n = (int)ceilf(M_PI*2/da);
1113
1114 da = (float)(M_PI*2)/n;
1115 for (i = 0; i < n; ++i)
1116 {
1117 u = i*da;
1118 x = cx + cosf(u)*r;
1119 y = cy + sinf(u)*r;
1120 svgPathPoint(p, x, y);
1121 }
1122
1123 svgCreatePath(p, 1);
1124 }
1125 }
1126
svgParseLine(struct SVGParser * p,const char ** attr)1127 static void svgParseLine(struct SVGParser* p, const char** attr)
1128 {
1129 float x1 = 0.0;
1130 float y1 = 0.0;
1131 float x2 = 0.0;
1132 float y2 = 0.0;
1133 int i;
1134
1135 for (i = 0; attr[i]; i += 2)
1136 {
1137 if (!svgParseAttr(p, attr[i], attr[i + 1]))
1138 {
1139 if (strcmp(attr[i], "x1") == 0) x1 = parseFloat(attr[i + 1]);
1140 if (strcmp(attr[i], "y1") == 0) y1 = parseFloat(attr[i + 1]);
1141 if (strcmp(attr[i], "x2") == 0) x2 = parseFloat(attr[i + 1]);
1142 if (strcmp(attr[i], "y2") == 0) y2 = parseFloat(attr[i + 1]);
1143 }
1144 }
1145
1146 svgResetPath(p);
1147
1148 svgPathPoint(p, x1, y1);
1149 svgPathPoint(p, x2, y2);
1150
1151 svgCreatePath(p, 0);
1152 }
1153
svgParsePoly(struct SVGParser * p,const char ** attr,int closeFlag)1154 static void svgParsePoly(struct SVGParser* p, const char** attr, int closeFlag)
1155 {
1156 int i;
1157 const char* s;
1158 float args[2];
1159 int nargs;
1160 char item[64];
1161
1162 svgResetPath(p);
1163
1164 for (i = 0; attr[i]; i += 2)
1165 {
1166 if (!svgParseAttr(p, attr[i], attr[i + 1]))
1167 {
1168 if (strcmp(attr[i], "points") == 0)
1169 {
1170 s = attr[i + 1];
1171 nargs = 0;
1172 while (*s)
1173 {
1174 s = getNextPathItem(s, item);
1175 args[nargs++] = (float)atof(item);
1176 if (nargs >= 2)
1177 {
1178 svgPathPoint(p, args[0], args[1]);
1179 nargs = 0;
1180 }
1181 }
1182 }
1183 }
1184 }
1185
1186 svgCreatePath(p, closeFlag);
1187 }
1188
svgStartElement(void * ud,const char * el,const char ** attr)1189 static void svgStartElement(void* ud, const char* el, const char** attr)
1190 {
1191 struct SVGParser* p = (struct SVGParser*)ud;
1192
1193 // Skip everything in defs
1194 if (p->defsFlag)
1195 return;
1196
1197 if (strcmp(el, "g") == 0)
1198 {
1199 svgPushAttr(p);
1200 svgParseAttribs(p, attr);
1201 }
1202 else if (strcmp(el, "path") == 0)
1203 {
1204 if (p->pathFlag) // Do not allow nested paths.
1205 return;
1206 svgPushAttr(p);
1207 svgParsePath(p, attr);
1208 p->pathFlag = 1;
1209 svgPopAttr(p);
1210 }
1211 else if (strcmp(el, "rect") == 0)
1212 {
1213 svgPushAttr(p);
1214 svgParseRect(p, attr);
1215 svgPopAttr(p);
1216 }
1217 else if (strcmp(el, "circle") == 0)
1218 {
1219 svgPushAttr(p);
1220 svgParseCircle(p, attr);
1221 svgPopAttr(p);
1222 }
1223 else if (strcmp(el, "line") == 0)
1224 {
1225 svgPushAttr(p);
1226 svgParseLine(p, attr);
1227 svgPopAttr(p);
1228 }
1229 else if (strcmp(el, "polyline") == 0)
1230 {
1231 svgPushAttr(p);
1232 svgParsePoly(p, attr, 0);
1233 svgPopAttr(p);
1234 }
1235 else if (strcmp(el, "polygon") == 0)
1236 {
1237 svgPushAttr(p);
1238 svgParsePoly(p, attr, 1);
1239 svgPopAttr(p);
1240 }
1241 else if (strcmp(el, "defs") == 0)
1242 {
1243 p->defsFlag = 1;
1244 }
1245 }
1246
svgEndElement(void * ud,const char * el)1247 static void svgEndElement(void* ud, const char* el)
1248 {
1249 struct SVGParser* p = (struct SVGParser*)ud;
1250
1251 if (strcmp(el, "g") == 0)
1252 {
1253 svgPopAttr(p);
1254 }
1255 else if (strcmp(el, "path") == 0)
1256 {
1257 p->pathFlag = 0;
1258 }
1259 else if (strcmp(el, "defs") == 0)
1260 {
1261 p->defsFlag = 0;
1262 }
1263 }
1264
svgContent(void * ud,const char * s)1265 static void svgContent(void* ud, const char* s)
1266 {
1267 // empty
1268 }
1269
svgParse(char * input)1270 struct SVGPath* svgParse(char* input)
1271 {
1272 struct SVGParser* p;
1273 struct SVGPath* ret = 0;
1274
1275 p = svgCreateParser();
1276 if (!p)
1277 return 0;
1278
1279 p->tol = 1.0f;
1280
1281 parsexml(input, svgStartElement, svgEndElement, svgContent, p);
1282
1283 if (p->buf)
1284 {
1285 free(p->buf);
1286 p->buf = NULL;
1287 p->nbuf = 0;
1288 p->cbuf = 0;
1289 }
1290
1291 ret = p->plist;
1292 p->plist = 0;
1293
1294 svgDeleteParser(p);
1295
1296 return ret;
1297 }
1298
svgParseFromFile(const char * filename)1299 struct SVGPath* svgParseFromFile(const char* filename)
1300 {
1301 FILE* fp;
1302 int size;
1303 char* data;
1304 struct SVGPath* plist;
1305
1306 fp = fopen(filename, "rb");
1307 if (!fp) return 0;
1308 fseek(fp, 0, SEEK_END);
1309 size = ftell(fp);
1310 fseek(fp, 0, SEEK_SET);
1311 data = (char*)malloc(size+1);
1312 fread(data, size, 1, fp);
1313 data[size] = '\0'; // Must be null terminated.
1314 fclose(fp);
1315 plist = svgParse(data);
1316 free(data);
1317 return plist;
1318 }
1319
svgDelete(struct SVGPath * plist)1320 void svgDelete(struct SVGPath* plist)
1321 {
1322 struct SVGPath* path;
1323 struct SVGPath* next;
1324 if (!plist)
1325 return;
1326 path = plist;
1327 while (path)
1328 {
1329 next = path->next;
1330 if (path->pts)
1331 free(path->pts);
1332 free(path);
1333 path = next;
1334 }
1335 }
1336