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