nanosvg.h
author Ozkan Sezer <sezeroz@gmail.com>
Thu, 18 Oct 2018 11:57:19 +0300
changeset 612 ca95d0e31aec
parent 583 5fa46fcf9499
child 645 93332afa1831
permissions -rw-r--r--
use less ancient versions of autofoo scripts
     1 /*
     2  * Copyright (c) 2013-14 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  *
     8  * Permission is granted to anyone to use this software for any purpose,
     9  * including commercial applications, and to alter it and redistribute it
    10  * freely, subject to the following restrictions:
    11  *
    12  * 1. The origin of this software must not be misrepresented; you must not
    13  * claim that you wrote the original software. If you use this software
    14  * in a product, an acknowledgment in the product documentation would be
    15  * appreciated but is not required.
    16  * 2. Altered source versions must be plainly marked as such, and must not be
    17  * misrepresented as being the original software.
    18  * 3. This notice may not be removed or altered from any source distribution.
    19  *
    20  * The SVG parser is based on Anti-Grain Geometry 2.4 SVG example
    21  * Copyright (C) 2002-2004 Maxim Shemanarev (McSeem) (http://www.antigrain.com/)
    22  *
    23  * Arc calculation code based on canvg (https://code.google.com/p/canvg/)
    24  *
    25  * Bounding box calculation based on http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html
    26  *
    27  */
    28 
    29 #ifndef NANOSVG_H
    30 #define NANOSVG_H
    31 
    32 #ifdef __cplusplus
    33 extern "C" {
    34 #endif
    35 
    36 // NanoSVG is a simple stupid single-header-file SVG parse. The output of the parser is a list of cubic bezier shapes.
    37 //
    38 // The library suits well for anything from rendering scalable icons in your editor application to prototyping a game.
    39 //
    40 // NanoSVG supports a wide range of SVG features, but something may be missing, feel free to create a pull request!
    41 //
    42 // The shapes in the SVG images are transformed by the viewBox and converted to specified units.
    43 // That is, you should get the same looking data as your designed in your favorite app.
    44 //
    45 // NanoSVG can return the paths in few different units. For example if you want to render an image, you may choose
    46 // to get the paths in pixels, or if you are feeding the data into a CNC-cutter, you may want to use millimeters.
    47 //
    48 // The units passed to NanoVG should be one of: 'px', 'pt', 'pc' 'mm', 'cm', or 'in'.
    49 // DPI (dots-per-inch) controls how the unit conversion is done.
    50 //
    51 // If you don't know or care about the units stuff, "px" and 96 should get you going.
    52 
    53 
    54 /* Example Usage:
    55 	// Load
    56 	NSVGImage* image;
    57 	image = nsvgParseFromFile("test.svg", "px", 96);
    58 	printf("size: %f x %f\n", image->width, image->height);
    59 	// Use...
    60 	for (NSVGshape *shape = image->shapes; shape != NULL; shape = shape->next) {
    61 		for (NSVGpath *path = shape->paths; path != NULL; path = path->next) {
    62 			for (int i = 0; i < path->npts-1; i += 3) {
    63 				float* p = &path->pts[i*2];
    64 				drawCubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7]);
    65 			}
    66 		}
    67 	}
    68 	// Delete
    69 	nsvgDelete(image);
    70 */
    71 
    72 enum NSVGpaintType {
    73 	NSVG_PAINT_NONE = 0,
    74 	NSVG_PAINT_COLOR = 1,
    75 	NSVG_PAINT_LINEAR_GRADIENT = 2,
    76 	NSVG_PAINT_RADIAL_GRADIENT = 3
    77 };
    78 
    79 enum NSVGspreadType {
    80 	NSVG_SPREAD_PAD = 0,
    81 	NSVG_SPREAD_REFLECT = 1,
    82 	NSVG_SPREAD_REPEAT = 2
    83 };
    84 
    85 enum NSVGlineJoin {
    86 	NSVG_JOIN_MITER = 0,
    87 	NSVG_JOIN_ROUND = 1,
    88 	NSVG_JOIN_BEVEL = 2
    89 };
    90 
    91 enum NSVGlineCap {
    92 	NSVG_CAP_BUTT = 0,
    93 	NSVG_CAP_ROUND = 1,
    94 	NSVG_CAP_SQUARE = 2
    95 };
    96 
    97 enum NSVGfillRule {
    98 	NSVG_FILLRULE_NONZERO = 0,
    99 	NSVG_FILLRULE_EVENODD = 1
   100 };
   101 
   102 enum NSVGflags {
   103 	NSVG_FLAGS_VISIBLE = 0x01
   104 };
   105 
   106 typedef struct NSVGgradientStop {
   107 	unsigned int color;
   108 	float offset;
   109 } NSVGgradientStop;
   110 
   111 typedef struct NSVGgradient {
   112 	float xform[6];
   113 	char spread;
   114 	float fx, fy;
   115 	int nstops;
   116 	NSVGgradientStop stops[1];
   117 } NSVGgradient;
   118 
   119 typedef struct NSVGpaint {
   120 	char type;
   121 	union {
   122 		unsigned int color;
   123 		NSVGgradient* gradient;
   124 	};
   125 } NSVGpaint;
   126 
   127 typedef struct NSVGpath
   128 {
   129 	float* pts;					// Cubic bezier points: x0,y0, [cpx1,cpx1,cpx2,cpy2,x1,y1], ...
   130 	int npts;					// Total number of bezier points.
   131 	char closed;				// Flag indicating if shapes should be treated as closed.
   132 	float bounds[4];			// Tight bounding box of the shape [minx,miny,maxx,maxy].
   133 	struct NSVGpath* next;		// Pointer to next path, or NULL if last element.
   134 } NSVGpath;
   135 
   136 typedef struct NSVGshape
   137 {
   138 	char id[64];				// Optional 'id' attr of the shape or its group
   139 	NSVGpaint fill;				// Fill paint
   140 	NSVGpaint stroke;			// Stroke paint
   141 	float opacity;				// Opacity of the shape.
   142 	float strokeWidth;			// Stroke width (scaled).
   143 	float strokeDashOffset;		// Stroke dash offset (scaled).
   144 	float strokeDashArray[8];			// Stroke dash array (scaled).
   145 	char strokeDashCount;				// Number of dash values in dash array.
   146 	char strokeLineJoin;		// Stroke join type.
   147 	char strokeLineCap;			// Stroke cap type.
   148 	float miterLimit;			// Miter limit
   149 	char fillRule;				// Fill rule, see NSVGfillRule.
   150 	unsigned char flags;		// Logical or of NSVG_FLAGS_* flags
   151 	float bounds[4];			// Tight bounding box of the shape [minx,miny,maxx,maxy].
   152 	NSVGpath* paths;			// Linked list of paths in the image.
   153 	struct NSVGshape* next;		// Pointer to next shape, or NULL if last element.
   154 } NSVGshape;
   155 
   156 typedef struct NSVGimage
   157 {
   158 	float width;				// Width of the image.
   159 	float height;				// Height of the image.
   160 	NSVGshape* shapes;			// Linked list of shapes in the image.
   161 } NSVGimage;
   162 
   163 // Parses SVG file from a file, returns SVG image as paths.
   164 NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi);
   165 
   166 // Parses SVG file from a null terminated string, returns SVG image as paths.
   167 // Important note: changes the string.
   168 NSVGimage* nsvgParse(char* input, const char* units, float dpi);
   169 
   170 // Deletes list of paths.
   171 void nsvgDelete(NSVGimage* image);
   172 
   173 #ifdef __cplusplus
   174 }
   175 #endif
   176 
   177 #endif // NANOSVG_H
   178 
   179 #ifdef NANOSVG_IMPLEMENTATION
   180 
   181 /*
   182 #include <string.h>
   183 #include <stdlib.h>
   184 #include <math.h>
   185 */
   186 
   187 #define NSVG_PI (3.14159265358979323846264338327f)
   188 #define NSVG_KAPPA90 (0.5522847493f)	// Length proportional to radius of a cubic bezier handle for 90deg arcs.
   189 
   190 #define NSVG_ALIGN_MIN 0
   191 #define NSVG_ALIGN_MID 1
   192 #define NSVG_ALIGN_MAX 2
   193 #define NSVG_ALIGN_NONE 0
   194 #define NSVG_ALIGN_MEET 1
   195 #define NSVG_ALIGN_SLICE 2
   196 
   197 #define NSVG_NOTUSED(v) do { (void)(1 ? (void)0 : ( (void)(v) ) ); } while(0)
   198 #define NSVG_RGB(r, g, b) (((unsigned int)r) | ((unsigned int)g << 8) | ((unsigned int)b << 16))
   199 
   200 #ifdef _MSC_VER
   201 	#pragma warning (disable: 4996) // Switch off security warnings
   202 	#pragma warning (disable: 4100) // Switch off unreferenced formal parameter warnings
   203 	#ifdef __cplusplus
   204 	#define NSVG_INLINE inline
   205 	#else
   206 	#define NSVG_INLINE
   207 	#endif
   208 #else
   209 	#define NSVG_INLINE inline
   210 #endif
   211 
   212 
   213 static int nsvg__isspace(char c)
   214 {
   215 	return strchr(" \t\n\v\f\r", c) != 0;
   216 }
   217 
   218 static int nsvg__isdigit(char c)
   219 {
   220 	return c >= '0' && c <= '9';
   221 }
   222 
   223 static int nsvg__isnum(char c)
   224 {
   225 	return strchr("0123456789+-.eE", c) != 0;
   226 }
   227 
   228 static NSVG_INLINE float nsvg__minf(float a, float b) { return a < b ? a : b; }
   229 static NSVG_INLINE float nsvg__maxf(float a, float b) { return a > b ? a : b; }
   230 
   231 
   232 // Simple XML parser
   233 
   234 #define NSVG_XML_TAG 1
   235 #define NSVG_XML_CONTENT 2
   236 #define NSVG_XML_MAX_ATTRIBS 256
   237 
   238 static void nsvg__parseContent(char* s,
   239 							   void (*contentCb)(void* ud, const char* s),
   240 							   void* ud)
   241 {
   242 	// Trim start white spaces
   243 	while (*s && nsvg__isspace(*s)) s++;
   244 	if (!*s) return;
   245 
   246 	if (contentCb)
   247 		(*contentCb)(ud, s);
   248 }
   249 
   250 static void nsvg__parseElement(char* s,
   251 							   void (*startelCb)(void* ud, const char* el, const char** attr),
   252 							   void (*endelCb)(void* ud, const char* el),
   253 							   void* ud)
   254 {
   255 	const char* attr[NSVG_XML_MAX_ATTRIBS];
   256 	int nattr = 0;
   257 	char* name;
   258 	int start = 0;
   259 	int end = 0;
   260 	char quote;
   261 
   262 	// Skip white space after the '<'
   263 	while (*s && nsvg__isspace(*s)) s++;
   264 
   265 	// Check if the tag is end tag
   266 	if (*s == '/') {
   267 		s++;
   268 		end = 1;
   269 	} else {
   270 		start = 1;
   271 	}
   272 
   273 	// Skip comments, data and preprocessor stuff.
   274 	if (!*s || *s == '?' || *s == '!')
   275 		return;
   276 
   277 	// Get tag name
   278 	name = s;
   279 	while (*s && !nsvg__isspace(*s)) s++;
   280 	if (*s) { *s++ = '\0'; }
   281 
   282 	// Get attribs
   283 	while (!end && *s && nattr < NSVG_XML_MAX_ATTRIBS-3) {
   284 		char* name = NULL;
   285 		char* value = NULL;
   286 
   287 		// Skip white space before the attrib name
   288 		while (*s && nsvg__isspace(*s)) s++;
   289 		if (!*s) break;
   290 		if (*s == '/') {
   291 			end = 1;
   292 			break;
   293 		}
   294 		name = s;
   295 		// Find end of the attrib name.
   296 		while (*s && !nsvg__isspace(*s) && *s != '=') s++;
   297 		if (*s) { *s++ = '\0'; }
   298 		// Skip until the beginning of the value.
   299 		while (*s && *s != '\"' && *s != '\'') s++;
   300 		if (!*s) break;
   301 		quote = *s;
   302 		s++;
   303 		// Store value and find the end of it.
   304 		value = s;
   305 		while (*s && *s != quote) s++;
   306 		if (*s) { *s++ = '\0'; }
   307 
   308 		// Store only well formed attributes
   309 		if (name && value) {
   310 			attr[nattr++] = name;
   311 			attr[nattr++] = value;
   312 		}
   313 	}
   314 
   315 	// List terminator
   316 	attr[nattr++] = 0;
   317 	attr[nattr++] = 0;
   318 
   319 	// Call callbacks.
   320 	if (start && startelCb)
   321 		(*startelCb)(ud, name, attr);
   322 	if (end && endelCb)
   323 		(*endelCb)(ud, name);
   324 }
   325 
   326 int nsvg__parseXML(char* input,
   327 				   void (*startelCb)(void* ud, const char* el, const char** attr),
   328 				   void (*endelCb)(void* ud, const char* el),
   329 				   void (*contentCb)(void* ud, const char* s),
   330 				   void* ud)
   331 {
   332 	char* s = input;
   333 	char* mark = s;
   334 	int state = NSVG_XML_CONTENT;
   335 	while (*s) {
   336 		if (*s == '<' && state == NSVG_XML_CONTENT) {
   337 			// Start of a tag
   338 			*s++ = '\0';
   339 			nsvg__parseContent(mark, contentCb, ud);
   340 			mark = s;
   341 			state = NSVG_XML_TAG;
   342 		} else if (*s == '>' && state == NSVG_XML_TAG) {
   343 			// Start of a content or new tag.
   344 			*s++ = '\0';
   345 			nsvg__parseElement(mark, startelCb, endelCb, ud);
   346 			mark = s;
   347 			state = NSVG_XML_CONTENT;
   348 		} else {
   349 			s++;
   350 		}
   351 	}
   352 
   353 	return 1;
   354 }
   355 
   356 
   357 /* Simple SVG parser. */
   358 
   359 #define NSVG_MAX_ATTR 128
   360 
   361 enum NSVGgradientUnits {
   362 	NSVG_USER_SPACE = 0,
   363 	NSVG_OBJECT_SPACE = 1
   364 };
   365 
   366 #define NSVG_MAX_DASHES 8
   367 
   368 enum NSVGunits {
   369 	NSVG_UNITS_USER,
   370 	NSVG_UNITS_PX,
   371 	NSVG_UNITS_PT,
   372 	NSVG_UNITS_PC,
   373 	NSVG_UNITS_MM,
   374 	NSVG_UNITS_CM,
   375 	NSVG_UNITS_IN,
   376 	NSVG_UNITS_PERCENT,
   377 	NSVG_UNITS_EM,
   378 	NSVG_UNITS_EX
   379 };
   380 
   381 typedef struct NSVGcoordinate {
   382 	float value;
   383 	int units;
   384 } NSVGcoordinate;
   385 
   386 typedef struct NSVGlinearData {
   387 	NSVGcoordinate x1, y1, x2, y2;
   388 } NSVGlinearData;
   389 
   390 typedef struct NSVGradialData {
   391 	NSVGcoordinate cx, cy, r, fx, fy;
   392 } NSVGradialData;
   393 
   394 typedef struct NSVGgradientData
   395 {
   396 	char id[64];
   397 	char ref[64];
   398 	char type;
   399 	union {
   400 		NSVGlinearData linear;
   401 		NSVGradialData radial;
   402 	};
   403 	char spread;
   404 	char units;
   405 	float xform[6];
   406 	int nstops;
   407 	NSVGgradientStop* stops;
   408 	struct NSVGgradientData* next;
   409 } NSVGgradientData;
   410 
   411 typedef struct NSVGattrib
   412 {
   413 	char id[64];
   414 	float xform[6];
   415 	unsigned int fillColor;
   416 	unsigned int strokeColor;
   417 	float opacity;
   418 	float fillOpacity;
   419 	float strokeOpacity;
   420 	char fillGradient[64];
   421 	char strokeGradient[64];
   422 	float strokeWidth;
   423 	float strokeDashOffset;
   424 	float strokeDashArray[NSVG_MAX_DASHES];
   425 	int strokeDashCount;
   426 	char strokeLineJoin;
   427 	char strokeLineCap;
   428 	float miterLimit;
   429 	char fillRule;
   430 	float fontSize;
   431 	unsigned int stopColor;
   432 	float stopOpacity;
   433 	float stopOffset;
   434 	char hasFill;
   435 	char hasStroke;
   436 	char visible;
   437 } NSVGattrib;
   438 
   439 typedef struct NSVGstyles
   440 {
   441 	char*	name;
   442 	char* description;
   443 	struct NSVGstyles* next;
   444 } NSVGstyles;
   445 
   446 typedef struct NSVGparser
   447 {
   448 	NSVGattrib attr[NSVG_MAX_ATTR];
   449 	int attrHead;
   450 	float* pts;
   451 	int npts;
   452 	int cpts;
   453 	NSVGpath* plist;
   454 	NSVGimage* image;
   455 	NSVGstyles* styles;
   456 	NSVGgradientData* gradients;
   457 	NSVGshape* shapesTail;
   458 	float viewMinx, viewMiny, viewWidth, viewHeight;
   459 	int alignX, alignY, alignType;
   460 	float dpi;
   461 	char pathFlag;
   462 	char defsFlag;
   463 	char styleFlag;
   464 } NSVGparser;
   465 
   466 static void nsvg__xformIdentity(float* t)
   467 {
   468 	t[0] = 1.0f; t[1] = 0.0f;
   469 	t[2] = 0.0f; t[3] = 1.0f;
   470 	t[4] = 0.0f; t[5] = 0.0f;
   471 }
   472 
   473 static void nsvg__xformSetTranslation(float* t, float tx, float ty)
   474 {
   475 	t[0] = 1.0f; t[1] = 0.0f;
   476 	t[2] = 0.0f; t[3] = 1.0f;
   477 	t[4] = tx; t[5] = ty;
   478 }
   479 
   480 static void nsvg__xformSetScale(float* t, float sx, float sy)
   481 {
   482 	t[0] = sx; t[1] = 0.0f;
   483 	t[2] = 0.0f; t[3] = sy;
   484 	t[4] = 0.0f; t[5] = 0.0f;
   485 }
   486 
   487 static void nsvg__xformSetSkewX(float* t, float a)
   488 {
   489 	t[0] = 1.0f; t[1] = 0.0f;
   490 	t[2] = tanf(a); t[3] = 1.0f;
   491 	t[4] = 0.0f; t[5] = 0.0f;
   492 }
   493 
   494 static void nsvg__xformSetSkewY(float* t, float a)
   495 {
   496 	t[0] = 1.0f; t[1] = tanf(a);
   497 	t[2] = 0.0f; t[3] = 1.0f;
   498 	t[4] = 0.0f; t[5] = 0.0f;
   499 }
   500 
   501 static void nsvg__xformSetRotation(float* t, float a)
   502 {
   503 	float cs = cosf(a), sn = sinf(a);
   504 	t[0] = cs; t[1] = sn;
   505 	t[2] = -sn; t[3] = cs;
   506 	t[4] = 0.0f; t[5] = 0.0f;
   507 }
   508 
   509 static void nsvg__xformMultiply(float* t, float* s)
   510 {
   511 	float t0 = t[0] * s[0] + t[1] * s[2];
   512 	float t2 = t[2] * s[0] + t[3] * s[2];
   513 	float t4 = t[4] * s[0] + t[5] * s[2] + s[4];
   514 	t[1] = t[0] * s[1] + t[1] * s[3];
   515 	t[3] = t[2] * s[1] + t[3] * s[3];
   516 	t[5] = t[4] * s[1] + t[5] * s[3] + s[5];
   517 	t[0] = t0;
   518 	t[2] = t2;
   519 	t[4] = t4;
   520 }
   521 
   522 static void nsvg__xformInverse(float* inv, float* t)
   523 {
   524 	double invdet, det = (double)t[0] * t[3] - (double)t[2] * t[1];
   525 	if (det > -1e-6 && det < 1e-6) {
   526 		nsvg__xformIdentity(t);
   527 		return;
   528 	}
   529 	invdet = 1.0 / det;
   530 	inv[0] = (float)(t[3] * invdet);
   531 	inv[2] = (float)(-t[2] * invdet);
   532 	inv[4] = (float)(((double)t[2] * t[5] - (double)t[3] * t[4]) * invdet);
   533 	inv[1] = (float)(-t[1] * invdet);
   534 	inv[3] = (float)(t[0] * invdet);
   535 	inv[5] = (float)(((double)t[1] * t[4] - (double)t[0] * t[5]) * invdet);
   536 }
   537 
   538 static void nsvg__xformPremultiply(float* t, float* s)
   539 {
   540 	float s2[6];
   541 	memcpy(s2, s, sizeof(float)*6);
   542 	nsvg__xformMultiply(s2, t);
   543 	memcpy(t, s2, sizeof(float)*6);
   544 }
   545 
   546 static void nsvg__xformPoint(float* dx, float* dy, float x, float y, float* t)
   547 {
   548 	*dx = x*t[0] + y*t[2] + t[4];
   549 	*dy = x*t[1] + y*t[3] + t[5];
   550 }
   551 
   552 static void nsvg__xformVec(float* dx, float* dy, float x, float y, float* t)
   553 {
   554 	*dx = x*t[0] + y*t[2];
   555 	*dy = x*t[1] + y*t[3];
   556 }
   557 
   558 #define NSVG_EPSILON (1e-12)
   559 
   560 static int nsvg__ptInBounds(float* pt, float* bounds)
   561 {
   562 	return pt[0] >= bounds[0] && pt[0] <= bounds[2] && pt[1] >= bounds[1] && pt[1] <= bounds[3];
   563 }
   564 
   565 
   566 static double nsvg__evalBezier(double t, double p0, double p1, double p2, double p3)
   567 {
   568 	double it = 1.0-t;
   569 	return it*it*it*p0 + 3.0*it*it*t*p1 + 3.0*it*t*t*p2 + t*t*t*p3;
   570 }
   571 
   572 static void nsvg__curveBounds(float* bounds, float* curve)
   573 {
   574 	int i, j, count;
   575 	double roots[2], a, b, c, b2ac, t, v;
   576 	float* v0 = &curve[0];
   577 	float* v1 = &curve[2];
   578 	float* v2 = &curve[4];
   579 	float* v3 = &curve[6];
   580 
   581 	// Start the bounding box by end points
   582 	bounds[0] = nsvg__minf(v0[0], v3[0]);
   583 	bounds[1] = nsvg__minf(v0[1], v3[1]);
   584 	bounds[2] = nsvg__maxf(v0[0], v3[0]);
   585 	bounds[3] = nsvg__maxf(v0[1], v3[1]);
   586 
   587 	// Bezier curve fits inside the convex hull of it's control points.
   588 	// If control points are inside the bounds, we're done.
   589 	if (nsvg__ptInBounds(v1, bounds) && nsvg__ptInBounds(v2, bounds))
   590 		return;
   591 
   592 	// Add bezier curve inflection points in X and Y.
   593 	for (i = 0; i < 2; i++) {
   594 		a = -3.0 * v0[i] + 9.0 * v1[i] - 9.0 * v2[i] + 3.0 * v3[i];
   595 		b = 6.0 * v0[i] - 12.0 * v1[i] + 6.0 * v2[i];
   596 		c = 3.0 * v1[i] - 3.0 * v0[i];
   597 		count = 0;
   598 		if (fabs(a) < NSVG_EPSILON) {
   599 			if (fabs(b) > NSVG_EPSILON) {
   600 				t = -c / b;
   601 				if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON)
   602 					roots[count++] = t;
   603 			}
   604 		} else {
   605 			b2ac = b*b - 4.0*c*a;
   606 			if (b2ac > NSVG_EPSILON) {
   607 				t = (-b + sqrt(b2ac)) / (2.0 * a);
   608 				if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON)
   609 					roots[count++] = t;
   610 				t = (-b - sqrt(b2ac)) / (2.0 * a);
   611 				if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON)
   612 					roots[count++] = t;
   613 			}
   614 		}
   615 		for (j = 0; j < count; j++) {
   616 			v = nsvg__evalBezier(roots[j], v0[i], v1[i], v2[i], v3[i]);
   617 			bounds[0+i] = nsvg__minf(bounds[0+i], (float)v);
   618 			bounds[2+i] = nsvg__maxf(bounds[2+i], (float)v);
   619 		}
   620 	}
   621 }
   622 
   623 static NSVGparser* nsvg__createParser()
   624 {
   625 	NSVGparser* p;
   626 	p = (NSVGparser*)malloc(sizeof(NSVGparser));
   627 	if (p == NULL) goto error;
   628 	memset(p, 0, sizeof(NSVGparser));
   629 
   630 	p->image = (NSVGimage*)malloc(sizeof(NSVGimage));
   631 	if (p->image == NULL) goto error;
   632 	memset(p->image, 0, sizeof(NSVGimage));
   633 
   634 	// Init style
   635 	nsvg__xformIdentity(p->attr[0].xform);
   636 	memset(p->attr[0].id, 0, sizeof p->attr[0].id);
   637 	p->attr[0].fillColor = NSVG_RGB(0,0,0);
   638 	p->attr[0].strokeColor = NSVG_RGB(0,0,0);
   639 	p->attr[0].opacity = 1;
   640 	p->attr[0].fillOpacity = 1;
   641 	p->attr[0].strokeOpacity = 1;
   642 	p->attr[0].stopOpacity = 1;
   643 	p->attr[0].strokeWidth = 1;
   644 	p->attr[0].strokeLineJoin = NSVG_JOIN_MITER;
   645 	p->attr[0].strokeLineCap = NSVG_CAP_BUTT;
   646 	p->attr[0].miterLimit = 4;
   647 	p->attr[0].fillRule = NSVG_FILLRULE_NONZERO;
   648 	p->attr[0].hasFill = 1;
   649 	p->attr[0].visible = 1;
   650 
   651 	return p;
   652 
   653 error:
   654 	if (p) {
   655 		if (p->image) free(p->image);
   656 		free(p);
   657 	}
   658 	return NULL;
   659 }
   660 static void nsvg__deleteStyles(NSVGstyles* style) {
   661 	while (style) {
   662 		NSVGstyles *next = style->next;
   663 		if (style->name!= NULL)
   664 			free(style->name);
   665 		if (style->description != NULL)
   666 			free(style->description);
   667 		free(style);
   668 		style = next;
   669 	}
   670 }
   671 
   672 static void nsvg__deletePaths(NSVGpath* path)
   673 {
   674 	while (path) {
   675 		NSVGpath *next = path->next;
   676 		if (path->pts != NULL)
   677 			free(path->pts);
   678 		free(path);
   679 		path = next;
   680 	}
   681 }
   682 
   683 static void nsvg__deletePaint(NSVGpaint* paint)
   684 {
   685 	if (paint->type == NSVG_PAINT_LINEAR_GRADIENT || paint->type == NSVG_PAINT_RADIAL_GRADIENT)
   686 		free(paint->gradient);
   687 }
   688 
   689 static void nsvg__deleteGradientData(NSVGgradientData* grad)
   690 {
   691 	NSVGgradientData* next;
   692 	while (grad != NULL) {
   693 		next = grad->next;
   694 		free(grad->stops);
   695 		free(grad);
   696 		grad = next;
   697 	}
   698 }
   699 
   700 static void nsvg__deleteParser(NSVGparser* p)
   701 {
   702 	if (p != NULL) {
   703 		nsvg__deleteStyles(p->styles);
   704 		nsvg__deletePaths(p->plist);
   705 		nsvg__deleteGradientData(p->gradients);
   706 		nsvgDelete(p->image);
   707 		free(p->pts);
   708 		free(p);
   709 	}
   710 }
   711 
   712 static void nsvg__resetPath(NSVGparser* p)
   713 {
   714 	p->npts = 0;
   715 }
   716 
   717 static void nsvg__addPoint(NSVGparser* p, float x, float y)
   718 {
   719 	if (p->npts+1 > p->cpts) {
   720 		p->cpts = p->cpts ? p->cpts*2 : 8;
   721 		p->pts = (float*)realloc(p->pts, p->cpts*2*sizeof(float));
   722 		if (!p->pts) return;
   723 	}
   724 	p->pts[p->npts*2+0] = x;
   725 	p->pts[p->npts*2+1] = y;
   726 	p->npts++;
   727 }
   728 
   729 static void nsvg__moveTo(NSVGparser* p, float x, float y)
   730 {
   731 	if (p->npts > 0) {
   732 		p->pts[(p->npts-1)*2+0] = x;
   733 		p->pts[(p->npts-1)*2+1] = y;
   734 	} else {
   735 		nsvg__addPoint(p, x, y);
   736 	}
   737 }
   738 
   739 static void nsvg__lineTo(NSVGparser* p, float x, float y)
   740 {
   741 	float px,py, dx,dy;
   742 	if (p->npts > 0) {
   743 		px = p->pts[(p->npts-1)*2+0];
   744 		py = p->pts[(p->npts-1)*2+1];
   745 		dx = x - px;
   746 		dy = y - py;
   747 		nsvg__addPoint(p, px + dx/3.0f, py + dy/3.0f);
   748 		nsvg__addPoint(p, x - dx/3.0f, y - dy/3.0f);
   749 		nsvg__addPoint(p, x, y);
   750 	}
   751 }
   752 
   753 static void nsvg__cubicBezTo(NSVGparser* p, float cpx1, float cpy1, float cpx2, float cpy2, float x, float y)
   754 {
   755 	nsvg__addPoint(p, cpx1, cpy1);
   756 	nsvg__addPoint(p, cpx2, cpy2);
   757 	nsvg__addPoint(p, x, y);
   758 }
   759 
   760 static NSVGattrib* nsvg__getAttr(NSVGparser* p)
   761 {
   762 	return &p->attr[p->attrHead];
   763 }
   764 
   765 static void nsvg__pushAttr(NSVGparser* p)
   766 {
   767 	if (p->attrHead < NSVG_MAX_ATTR-1) {
   768 		p->attrHead++;
   769 		memcpy(&p->attr[p->attrHead], &p->attr[p->attrHead-1], sizeof(NSVGattrib));
   770 	}
   771 }
   772 
   773 static void nsvg__popAttr(NSVGparser* p)
   774 {
   775 	if (p->attrHead > 0)
   776 		p->attrHead--;
   777 }
   778 
   779 static float nsvg__actualOrigX(NSVGparser* p)
   780 {
   781 	return p->viewMinx;
   782 }
   783 
   784 static float nsvg__actualOrigY(NSVGparser* p)
   785 {
   786 	return p->viewMiny;
   787 }
   788 
   789 static float nsvg__actualWidth(NSVGparser* p)
   790 {
   791 	return p->viewWidth;
   792 }
   793 
   794 static float nsvg__actualHeight(NSVGparser* p)
   795 {
   796 	return p->viewHeight;
   797 }
   798 
   799 static float nsvg__actualLength(NSVGparser* p)
   800 {
   801 	float w = nsvg__actualWidth(p), h = nsvg__actualHeight(p);
   802 	return sqrtf(w*w + h*h) / sqrtf(2.0f);
   803 }
   804 
   805 static float nsvg__convertToPixels(NSVGparser* p, NSVGcoordinate c, float orig, float length)
   806 {
   807 	NSVGattrib* attr = nsvg__getAttr(p);
   808 	switch (c.units) {
   809 		case NSVG_UNITS_USER:		return c.value;
   810 		case NSVG_UNITS_PX:			return c.value;
   811 		case NSVG_UNITS_PT:			return c.value / 72.0f * p->dpi;
   812 		case NSVG_UNITS_PC:			return c.value / 6.0f * p->dpi;
   813 		case NSVG_UNITS_MM:			return c.value / 25.4f * p->dpi;
   814 		case NSVG_UNITS_CM:			return c.value / 2.54f * p->dpi;
   815 		case NSVG_UNITS_IN:			return c.value * p->dpi;
   816 		case NSVG_UNITS_EM:			return c.value * attr->fontSize;
   817 		case NSVG_UNITS_EX:			return c.value * attr->fontSize * 0.52f; // x-height of Helvetica.
   818 		case NSVG_UNITS_PERCENT:	return orig + c.value / 100.0f * length;
   819 		default:					return c.value;
   820 	}
   821 	return c.value;
   822 }
   823 
   824 static NSVGgradientData* nsvg__findGradientData(NSVGparser* p, const char* id)
   825 {
   826 	NSVGgradientData* grad = p->gradients;
   827 	while (grad) {
   828 		if (strcmp(grad->id, id) == 0)
   829 			return grad;
   830 		grad = grad->next;
   831 	}
   832 	return NULL;
   833 }
   834 
   835 static NSVGgradient* nsvg__createGradient(NSVGparser* p, const char* id, const float* localBounds, char* paintType)
   836 {
   837 	NSVGattrib* attr = nsvg__getAttr(p);
   838 	NSVGgradientData* data = NULL;
   839 	NSVGgradientData* ref = NULL;
   840 	NSVGgradientStop* stops = NULL;
   841 	NSVGgradient* grad;
   842 	float ox, oy, sw, sh, sl;
   843 	int nstops = 0;
   844 
   845 	data = nsvg__findGradientData(p, id);
   846 	if (data == NULL) return NULL;
   847 
   848 	// TODO: use ref to fill in all unset values too.
   849 	ref = data;
   850 	while (ref != NULL) {
   851 		if (stops == NULL && ref->stops != NULL) {
   852 			stops = ref->stops;
   853 			nstops = ref->nstops;
   854 			break;
   855 		}
   856 		ref = nsvg__findGradientData(p, ref->ref);
   857 	}
   858 	if (stops == NULL) return NULL;
   859 
   860 	grad = (NSVGgradient*)malloc(sizeof(NSVGgradient) + sizeof(NSVGgradientStop)*(nstops-1));
   861 	if (grad == NULL) return NULL;
   862 
   863 	// The shape width and height.
   864 	if (data->units == NSVG_OBJECT_SPACE) {
   865 		ox = localBounds[0];
   866 		oy = localBounds[1];
   867 		sw = localBounds[2] - localBounds[0];
   868 		sh = localBounds[3] - localBounds[1];
   869 	} else {
   870 		ox = nsvg__actualOrigX(p);
   871 		oy = nsvg__actualOrigY(p);
   872 		sw = nsvg__actualWidth(p);
   873 		sh = nsvg__actualHeight(p);
   874 	}
   875 	sl = sqrtf(sw*sw + sh*sh) / sqrtf(2.0f);
   876 
   877 	if (data->type == NSVG_PAINT_LINEAR_GRADIENT) {
   878 		float x1, y1, x2, y2, dx, dy;
   879 		x1 = nsvg__convertToPixels(p, data->linear.x1, ox, sw);
   880 		y1 = nsvg__convertToPixels(p, data->linear.y1, oy, sh);
   881 		x2 = nsvg__convertToPixels(p, data->linear.x2, ox, sw);
   882 		y2 = nsvg__convertToPixels(p, data->linear.y2, oy, sh);
   883 		// Calculate transform aligned to the line
   884 		dx = x2 - x1;
   885 		dy = y2 - y1;
   886 		grad->xform[0] = dy; grad->xform[1] = -dx;
   887 		grad->xform[2] = dx; grad->xform[3] = dy;
   888 		grad->xform[4] = x1; grad->xform[5] = y1;
   889 	} else {
   890 		float cx, cy, fx, fy, r;
   891 		cx = nsvg__convertToPixels(p, data->radial.cx, ox, sw);
   892 		cy = nsvg__convertToPixels(p, data->radial.cy, oy, sh);
   893 		fx = nsvg__convertToPixels(p, data->radial.fx, ox, sw);
   894 		fy = nsvg__convertToPixels(p, data->radial.fy, oy, sh);
   895 		r = nsvg__convertToPixels(p, data->radial.r, 0, sl);
   896 		// Calculate transform aligned to the circle
   897 		grad->xform[0] = r; grad->xform[1] = 0;
   898 		grad->xform[2] = 0; grad->xform[3] = r;
   899 		grad->xform[4] = cx; grad->xform[5] = cy;
   900 		grad->fx = fx / r;
   901 		grad->fy = fy / r;
   902 	}
   903 
   904 	nsvg__xformMultiply(grad->xform, data->xform);
   905 	nsvg__xformMultiply(grad->xform, attr->xform);
   906 
   907 	grad->spread = data->spread;
   908 	memcpy(grad->stops, stops, nstops*sizeof(NSVGgradientStop));
   909 	grad->nstops = nstops;
   910 
   911 	*paintType = data->type;
   912 
   913 	return grad;
   914 }
   915 
   916 static float nsvg__getAverageScale(float* t)
   917 {
   918 	float sx = sqrtf(t[0]*t[0] + t[2]*t[2]);
   919 	float sy = sqrtf(t[1]*t[1] + t[3]*t[3]);
   920 	return (sx + sy) * 0.5f;
   921 }
   922 
   923 static void nsvg__getLocalBounds(float* bounds, NSVGshape *shape, float* xform)
   924 {
   925 	NSVGpath* path;
   926 	float curve[4*2], curveBounds[4];
   927 	int i, first = 1;
   928 	for (path = shape->paths; path != NULL; path = path->next) {
   929 		nsvg__xformPoint(&curve[0], &curve[1], path->pts[0], path->pts[1], xform);
   930 		for (i = 0; i < path->npts-1; i += 3) {
   931 			nsvg__xformPoint(&curve[2], &curve[3], path->pts[(i+1)*2], path->pts[(i+1)*2+1], xform);
   932 			nsvg__xformPoint(&curve[4], &curve[5], path->pts[(i+2)*2], path->pts[(i+2)*2+1], xform);
   933 			nsvg__xformPoint(&curve[6], &curve[7], path->pts[(i+3)*2], path->pts[(i+3)*2+1], xform);
   934 			nsvg__curveBounds(curveBounds, curve);
   935 			if (first) {
   936 				bounds[0] = curveBounds[0];
   937 				bounds[1] = curveBounds[1];
   938 				bounds[2] = curveBounds[2];
   939 				bounds[3] = curveBounds[3];
   940 				first = 0;
   941 			} else {
   942 				bounds[0] = nsvg__minf(bounds[0], curveBounds[0]);
   943 				bounds[1] = nsvg__minf(bounds[1], curveBounds[1]);
   944 				bounds[2] = nsvg__maxf(bounds[2], curveBounds[2]);
   945 				bounds[3] = nsvg__maxf(bounds[3], curveBounds[3]);
   946 			}
   947 			curve[0] = curve[6];
   948 			curve[1] = curve[7];
   949 		}
   950 	}
   951 }
   952 
   953 static void nsvg__addShape(NSVGparser* p)
   954 {
   955 	NSVGattrib* attr = nsvg__getAttr(p);
   956 	float scale = 1.0f;
   957 	NSVGshape* shape;
   958 	NSVGpath* path;
   959 	int i;
   960 
   961 	if (p->plist == NULL)
   962 		return;
   963 
   964 	shape = (NSVGshape*)malloc(sizeof(NSVGshape));
   965 	if (shape == NULL) goto error;
   966 	memset(shape, 0, sizeof(NSVGshape));
   967 
   968 	memcpy(shape->id, attr->id, sizeof shape->id);
   969 	scale = nsvg__getAverageScale(attr->xform);
   970 	shape->strokeWidth = attr->strokeWidth * scale;
   971 	shape->strokeDashOffset = attr->strokeDashOffset * scale;
   972 	shape->strokeDashCount = (char)attr->strokeDashCount;
   973 	for (i = 0; i < attr->strokeDashCount; i++)
   974 		shape->strokeDashArray[i] = attr->strokeDashArray[i] * scale;
   975 	shape->strokeLineJoin = attr->strokeLineJoin;
   976 	shape->strokeLineCap = attr->strokeLineCap;
   977 	shape->miterLimit = attr->miterLimit;
   978 	shape->fillRule = attr->fillRule;
   979 	shape->opacity = attr->opacity;
   980 
   981 	shape->paths = p->plist;
   982 	p->plist = NULL;
   983 
   984 	// Calculate shape bounds
   985 	shape->bounds[0] = shape->paths->bounds[0];
   986 	shape->bounds[1] = shape->paths->bounds[1];
   987 	shape->bounds[2] = shape->paths->bounds[2];
   988 	shape->bounds[3] = shape->paths->bounds[3];
   989 	for (path = shape->paths->next; path != NULL; path = path->next) {
   990 		shape->bounds[0] = nsvg__minf(shape->bounds[0], path->bounds[0]);
   991 		shape->bounds[1] = nsvg__minf(shape->bounds[1], path->bounds[1]);
   992 		shape->bounds[2] = nsvg__maxf(shape->bounds[2], path->bounds[2]);
   993 		shape->bounds[3] = nsvg__maxf(shape->bounds[3], path->bounds[3]);
   994 	}
   995 
   996 	// Set fill
   997 	if (attr->hasFill == 0) {
   998 		shape->fill.type = NSVG_PAINT_NONE;
   999 	} else if (attr->hasFill == 1) {
  1000 		shape->fill.type = NSVG_PAINT_COLOR;
  1001 		shape->fill.color = attr->fillColor;
  1002 		shape->fill.color |= (unsigned int)(attr->fillOpacity*255) << 24;
  1003 	} else if (attr->hasFill == 2) {
  1004 		float inv[6], localBounds[4];
  1005 		nsvg__xformInverse(inv, attr->xform);
  1006 		nsvg__getLocalBounds(localBounds, shape, inv);
  1007 		shape->fill.gradient = nsvg__createGradient(p, attr->fillGradient, localBounds, &shape->fill.type);
  1008 		if (shape->fill.gradient == NULL) {
  1009 			shape->fill.type = NSVG_PAINT_NONE;
  1010 		}
  1011 	}
  1012 
  1013 	// Set stroke
  1014 	if (attr->hasStroke == 0) {
  1015 		shape->stroke.type = NSVG_PAINT_NONE;
  1016 	} else if (attr->hasStroke == 1) {
  1017 		shape->stroke.type = NSVG_PAINT_COLOR;
  1018 		shape->stroke.color = attr->strokeColor;
  1019 		shape->stroke.color |= (unsigned int)(attr->strokeOpacity*255) << 24;
  1020 	} else if (attr->hasStroke == 2) {
  1021 		float inv[6], localBounds[4];
  1022 		nsvg__xformInverse(inv, attr->xform);
  1023 		nsvg__getLocalBounds(localBounds, shape, inv);
  1024 		shape->stroke.gradient = nsvg__createGradient(p, attr->strokeGradient, localBounds, &shape->stroke.type);
  1025 		if (shape->stroke.gradient == NULL)
  1026 			shape->stroke.type = NSVG_PAINT_NONE;
  1027 	}
  1028 
  1029 	// Set flags
  1030 	shape->flags = (attr->visible ? NSVG_FLAGS_VISIBLE : 0x00);
  1031 
  1032 	// Add to tail
  1033 	if (p->image->shapes == NULL)
  1034 		p->image->shapes = shape;
  1035 	else
  1036 		p->shapesTail->next = shape;
  1037 	p->shapesTail = shape;
  1038 
  1039 	return;
  1040 
  1041 error:
  1042 	if (shape) free(shape);
  1043 }
  1044 
  1045 static void nsvg__addPath(NSVGparser* p, char closed)
  1046 {
  1047 	NSVGattrib* attr = nsvg__getAttr(p);
  1048 	NSVGpath* path = NULL;
  1049 	float bounds[4];
  1050 	float* curve;
  1051 	int i;
  1052 
  1053 	if (p->npts < 4)
  1054 		return;
  1055 
  1056 	if (closed)
  1057 		nsvg__lineTo(p, p->pts[0], p->pts[1]);
  1058 
  1059 	path = (NSVGpath*)malloc(sizeof(NSVGpath));
  1060 	if (path == NULL) goto error;
  1061 	memset(path, 0, sizeof(NSVGpath));
  1062 
  1063 	path->pts = (float*)malloc(p->npts*2*sizeof(float));
  1064 	if (path->pts == NULL) goto error;
  1065 	path->closed = closed;
  1066 	path->npts = p->npts;
  1067 
  1068 	// Transform path.
  1069 	for (i = 0; i < p->npts; ++i)
  1070 		nsvg__xformPoint(&path->pts[i*2], &path->pts[i*2+1], p->pts[i*2], p->pts[i*2+1], attr->xform);
  1071 
  1072 	// Find bounds
  1073 	for (i = 0; i < path->npts-1; i += 3) {
  1074 		curve = &path->pts[i*2];
  1075 		nsvg__curveBounds(bounds, curve);
  1076 		if (i == 0) {
  1077 			path->bounds[0] = bounds[0];
  1078 			path->bounds[1] = bounds[1];
  1079 			path->bounds[2] = bounds[2];
  1080 			path->bounds[3] = bounds[3];
  1081 		} else {
  1082 			path->bounds[0] = nsvg__minf(path->bounds[0], bounds[0]);
  1083 			path->bounds[1] = nsvg__minf(path->bounds[1], bounds[1]);
  1084 			path->bounds[2] = nsvg__maxf(path->bounds[2], bounds[2]);
  1085 			path->bounds[3] = nsvg__maxf(path->bounds[3], bounds[3]);
  1086 		}
  1087 	}
  1088 
  1089 	path->next = p->plist;
  1090 	p->plist = path;
  1091 
  1092 	return;
  1093 
  1094 error:
  1095 	if (path != NULL) {
  1096 		if (path->pts != NULL) free(path->pts);
  1097 		free(path);
  1098 	}
  1099 }
  1100 
  1101 // We roll our own string to float because the std library one uses locale and messes things up.
  1102 static double nsvg__atof(const char* s)
  1103 {
  1104 	char* cur = (char*)s;
  1105 	char* end = NULL;
  1106 	double res = 0.0, sign = 1.0;
  1107 	long long intPart = 0, fracPart = 0;
  1108 	char hasIntPart = 0, hasFracPart = 0;
  1109 
  1110 	// Parse optional sign
  1111 	if (*cur == '+') {
  1112 		cur++;
  1113 	} else if (*cur == '-') {
  1114 		sign = -1;
  1115 		cur++;
  1116 	}
  1117 
  1118 	// Parse integer part
  1119 	if (nsvg__isdigit(*cur)) {
  1120 		// Parse digit sequence
  1121 		intPart = strtoll(cur, &end, 10);
  1122 		if (cur != end) {
  1123 			res = (double)intPart;
  1124 			hasIntPart = 1;
  1125 			cur = end;
  1126 		}
  1127 	}
  1128 
  1129 	// Parse fractional part.
  1130 	if (*cur == '.') {
  1131 		cur++; // Skip '.'
  1132 		if (nsvg__isdigit(*cur)) {
  1133 			// Parse digit sequence
  1134 			fracPart = strtoll(cur, &end, 10);
  1135 			if (cur != end) {
  1136 				res += (double)fracPart / pow(10.0, (double)(end - cur));
  1137 				hasFracPart = 1;
  1138 				cur = end;
  1139 			}
  1140 		}
  1141 	}
  1142 
  1143 	// A valid number should have integer or fractional part.
  1144 	if (!hasIntPart && !hasFracPart)
  1145 		return 0.0;
  1146 
  1147 	// Parse optional exponent
  1148 	if (*cur == 'e' || *cur == 'E') {
  1149 		int expPart = 0;
  1150 		cur++; // skip 'E'
  1151 		expPart = (int)strtol(cur, &end, 10); // Parse digit sequence with sign
  1152 		if (cur != end) {
  1153 			res *= pow(10.0, (double)expPart);
  1154 		}
  1155 	}
  1156 
  1157 	return res * sign;
  1158 }
  1159 
  1160 
  1161 static const char* nsvg__parseNumber(const char* s, char* it, const int size)
  1162 {
  1163 	const int last = size-1;
  1164 	int i = 0;
  1165 
  1166 	// sign
  1167 	if (*s == '-' || *s == '+') {
  1168 		if (i < last) it[i++] = *s;
  1169 		s++;
  1170 	}
  1171 	// integer part
  1172 	while (*s && nsvg__isdigit(*s)) {
  1173 		if (i < last) it[i++] = *s;
  1174 		s++;
  1175 	}
  1176 	if (*s == '.') {
  1177 		// decimal point
  1178 		if (i < last) it[i++] = *s;
  1179 		s++;
  1180 		// fraction part
  1181 		while (*s && nsvg__isdigit(*s)) {
  1182 			if (i < last) it[i++] = *s;
  1183 			s++;
  1184 		}
  1185 	}
  1186 	// exponent
  1187 	if (*s == 'e' || *s == 'E') {
  1188 		if (i < last) it[i++] = *s;
  1189 		s++;
  1190 		if (*s == '-' || *s == '+') {
  1191 			if (i < last) it[i++] = *s;
  1192 			s++;
  1193 		}
  1194 		while (*s && nsvg__isdigit(*s)) {
  1195 			if (i < last) it[i++] = *s;
  1196 			s++;
  1197 		}
  1198 	}
  1199 	it[i] = '\0';
  1200 
  1201 	return s;
  1202 }
  1203 
  1204 static const char* nsvg__getNextPathItem(const char* s, char* it)
  1205 {
  1206 	it[0] = '\0';
  1207 	// Skip white spaces and commas
  1208 	while (*s && (nsvg__isspace(*s) || *s == ',')) s++;
  1209 	if (!*s) return s;
  1210 	if (*s == '-' || *s == '+' || *s == '.' || nsvg__isdigit(*s)) {
  1211 		s = nsvg__parseNumber(s, it, 64);
  1212 	} else {
  1213 		// Parse command
  1214 		it[0] = *s++;
  1215 		it[1] = '\0';
  1216 		return s;
  1217 	}
  1218 
  1219 	return s;
  1220 }
  1221 
  1222 static unsigned int nsvg__parseColorHex(const char* str)
  1223 {
  1224 	unsigned int c = 0, r = 0, g = 0, b = 0;
  1225 	int n = 0;
  1226 	str++; // skip #
  1227 	// Calculate number of characters.
  1228 	while(str[n] && !nsvg__isspace(str[n]))
  1229 		n++;
  1230 	if (n == 6) {
  1231 		sscanf(str, "%x", &c);
  1232 	} else if (n == 3) {
  1233 		sscanf(str, "%x", &c);
  1234 		c = (c&0xf) | ((c&0xf0) << 4) | ((c&0xf00) << 8);
  1235 		c |= c<<4;
  1236 	}
  1237 	r = (c >> 16) & 0xff;
  1238 	g = (c >> 8) & 0xff;
  1239 	b = c & 0xff;
  1240 	return NSVG_RGB(r,g,b);
  1241 }
  1242 
  1243 static unsigned int nsvg__parseColorRGB(const char* str)
  1244 {
  1245 	int r = -1, g = -1, b = -1;
  1246 	char s1[32]="", s2[32]="";
  1247 	sscanf(str + 4, "%d%[%%, \t]%d%[%%, \t]%d", &r, s1, &g, s2, &b);
  1248 	if (strchr(s1, '%')) {
  1249 		return NSVG_RGB((r*255)/100,(g*255)/100,(b*255)/100);
  1250 	} else {
  1251 		return NSVG_RGB(r,g,b);
  1252 	}
  1253 }
  1254 
  1255 typedef struct NSVGNamedColor {
  1256 	const char* name;
  1257 	unsigned int color;
  1258 } NSVGNamedColor;
  1259 
  1260 NSVGNamedColor nsvg__colors[] = {
  1261 
  1262 	{ "red", NSVG_RGB(255, 0, 0) },
  1263 	{ "green", NSVG_RGB( 0, 128, 0) },
  1264 	{ "blue", NSVG_RGB( 0, 0, 255) },
  1265 	{ "yellow", NSVG_RGB(255, 255, 0) },
  1266 	{ "cyan", NSVG_RGB( 0, 255, 255) },
  1267 	{ "magenta", NSVG_RGB(255, 0, 255) },
  1268 	{ "black", NSVG_RGB( 0, 0, 0) },
  1269 	{ "grey", NSVG_RGB(128, 128, 128) },
  1270 	{ "gray", NSVG_RGB(128, 128, 128) },
  1271 	{ "white", NSVG_RGB(255, 255, 255) },
  1272 
  1273 #ifdef NANOSVG_ALL_COLOR_KEYWORDS
  1274 	{ "aliceblue", NSVG_RGB(240, 248, 255) },
  1275 	{ "antiquewhite", NSVG_RGB(250, 235, 215) },
  1276 	{ "aqua", NSVG_RGB( 0, 255, 255) },
  1277 	{ "aquamarine", NSVG_RGB(127, 255, 212) },
  1278 	{ "azure", NSVG_RGB(240, 255, 255) },
  1279 	{ "beige", NSVG_RGB(245, 245, 220) },
  1280 	{ "bisque", NSVG_RGB(255, 228, 196) },
  1281 	{ "blanchedalmond", NSVG_RGB(255, 235, 205) },
  1282 	{ "blueviolet", NSVG_RGB(138, 43, 226) },
  1283 	{ "brown", NSVG_RGB(165, 42, 42) },
  1284 	{ "burlywood", NSVG_RGB(222, 184, 135) },
  1285 	{ "cadetblue", NSVG_RGB( 95, 158, 160) },
  1286 	{ "chartreuse", NSVG_RGB(127, 255, 0) },
  1287 	{ "chocolate", NSVG_RGB(210, 105, 30) },
  1288 	{ "coral", NSVG_RGB(255, 127, 80) },
  1289 	{ "cornflowerblue", NSVG_RGB(100, 149, 237) },
  1290 	{ "cornsilk", NSVG_RGB(255, 248, 220) },
  1291 	{ "crimson", NSVG_RGB(220, 20, 60) },
  1292 	{ "darkblue", NSVG_RGB( 0, 0, 139) },
  1293 	{ "darkcyan", NSVG_RGB( 0, 139, 139) },
  1294 	{ "darkgoldenrod", NSVG_RGB(184, 134, 11) },
  1295 	{ "darkgray", NSVG_RGB(169, 169, 169) },
  1296 	{ "darkgreen", NSVG_RGB( 0, 100, 0) },
  1297 	{ "darkgrey", NSVG_RGB(169, 169, 169) },
  1298 	{ "darkkhaki", NSVG_RGB(189, 183, 107) },
  1299 	{ "darkmagenta", NSVG_RGB(139, 0, 139) },
  1300 	{ "darkolivegreen", NSVG_RGB( 85, 107, 47) },
  1301 	{ "darkorange", NSVG_RGB(255, 140, 0) },
  1302 	{ "darkorchid", NSVG_RGB(153, 50, 204) },
  1303 	{ "darkred", NSVG_RGB(139, 0, 0) },
  1304 	{ "darksalmon", NSVG_RGB(233, 150, 122) },
  1305 	{ "darkseagreen", NSVG_RGB(143, 188, 143) },
  1306 	{ "darkslateblue", NSVG_RGB( 72, 61, 139) },
  1307 	{ "darkslategray", NSVG_RGB( 47, 79, 79) },
  1308 	{ "darkslategrey", NSVG_RGB( 47, 79, 79) },
  1309 	{ "darkturquoise", NSVG_RGB( 0, 206, 209) },
  1310 	{ "darkviolet", NSVG_RGB(148, 0, 211) },
  1311 	{ "deeppink", NSVG_RGB(255, 20, 147) },
  1312 	{ "deepskyblue", NSVG_RGB( 0, 191, 255) },
  1313 	{ "dimgray", NSVG_RGB(105, 105, 105) },
  1314 	{ "dimgrey", NSVG_RGB(105, 105, 105) },
  1315 	{ "dodgerblue", NSVG_RGB( 30, 144, 255) },
  1316 	{ "firebrick", NSVG_RGB(178, 34, 34) },
  1317 	{ "floralwhite", NSVG_RGB(255, 250, 240) },
  1318 	{ "forestgreen", NSVG_RGB( 34, 139, 34) },
  1319 	{ "fuchsia", NSVG_RGB(255, 0, 255) },
  1320 	{ "gainsboro", NSVG_RGB(220, 220, 220) },
  1321 	{ "ghostwhite", NSVG_RGB(248, 248, 255) },
  1322 	{ "gold", NSVG_RGB(255, 215, 0) },
  1323 	{ "goldenrod", NSVG_RGB(218, 165, 32) },
  1324 	{ "greenyellow", NSVG_RGB(173, 255, 47) },
  1325 	{ "honeydew", NSVG_RGB(240, 255, 240) },
  1326 	{ "hotpink", NSVG_RGB(255, 105, 180) },
  1327 	{ "indianred", NSVG_RGB(205, 92, 92) },
  1328 	{ "indigo", NSVG_RGB( 75, 0, 130) },
  1329 	{ "ivory", NSVG_RGB(255, 255, 240) },
  1330 	{ "khaki", NSVG_RGB(240, 230, 140) },
  1331 	{ "lavender", NSVG_RGB(230, 230, 250) },
  1332 	{ "lavenderblush", NSVG_RGB(255, 240, 245) },
  1333 	{ "lawngreen", NSVG_RGB(124, 252, 0) },
  1334 	{ "lemonchiffon", NSVG_RGB(255, 250, 205) },
  1335 	{ "lightblue", NSVG_RGB(173, 216, 230) },
  1336 	{ "lightcoral", NSVG_RGB(240, 128, 128) },
  1337 	{ "lightcyan", NSVG_RGB(224, 255, 255) },
  1338 	{ "lightgoldenrodyellow", NSVG_RGB(250, 250, 210) },
  1339 	{ "lightgray", NSVG_RGB(211, 211, 211) },
  1340 	{ "lightgreen", NSVG_RGB(144, 238, 144) },
  1341 	{ "lightgrey", NSVG_RGB(211, 211, 211) },
  1342 	{ "lightpink", NSVG_RGB(255, 182, 193) },
  1343 	{ "lightsalmon", NSVG_RGB(255, 160, 122) },
  1344 	{ "lightseagreen", NSVG_RGB( 32, 178, 170) },
  1345 	{ "lightskyblue", NSVG_RGB(135, 206, 250) },
  1346 	{ "lightslategray", NSVG_RGB(119, 136, 153) },
  1347 	{ "lightslategrey", NSVG_RGB(119, 136, 153) },
  1348 	{ "lightsteelblue", NSVG_RGB(176, 196, 222) },
  1349 	{ "lightyellow", NSVG_RGB(255, 255, 224) },
  1350 	{ "lime", NSVG_RGB( 0, 255, 0) },
  1351 	{ "limegreen", NSVG_RGB( 50, 205, 50) },
  1352 	{ "linen", NSVG_RGB(250, 240, 230) },
  1353 	{ "maroon", NSVG_RGB(128, 0, 0) },
  1354 	{ "mediumaquamarine", NSVG_RGB(102, 205, 170) },
  1355 	{ "mediumblue", NSVG_RGB( 0, 0, 205) },
  1356 	{ "mediumorchid", NSVG_RGB(186, 85, 211) },
  1357 	{ "mediumpurple", NSVG_RGB(147, 112, 219) },
  1358 	{ "mediumseagreen", NSVG_RGB( 60, 179, 113) },
  1359 	{ "mediumslateblue", NSVG_RGB(123, 104, 238) },
  1360 	{ "mediumspringgreen", NSVG_RGB( 0, 250, 154) },
  1361 	{ "mediumturquoise", NSVG_RGB( 72, 209, 204) },
  1362 	{ "mediumvioletred", NSVG_RGB(199, 21, 133) },
  1363 	{ "midnightblue", NSVG_RGB( 25, 25, 112) },
  1364 	{ "mintcream", NSVG_RGB(245, 255, 250) },
  1365 	{ "mistyrose", NSVG_RGB(255, 228, 225) },
  1366 	{ "moccasin", NSVG_RGB(255, 228, 181) },
  1367 	{ "navajowhite", NSVG_RGB(255, 222, 173) },
  1368 	{ "navy", NSVG_RGB( 0, 0, 128) },
  1369 	{ "oldlace", NSVG_RGB(253, 245, 230) },
  1370 	{ "olive", NSVG_RGB(128, 128, 0) },
  1371 	{ "olivedrab", NSVG_RGB(107, 142, 35) },
  1372 	{ "orange", NSVG_RGB(255, 165, 0) },
  1373 	{ "orangered", NSVG_RGB(255, 69, 0) },
  1374 	{ "orchid", NSVG_RGB(218, 112, 214) },
  1375 	{ "palegoldenrod", NSVG_RGB(238, 232, 170) },
  1376 	{ "palegreen", NSVG_RGB(152, 251, 152) },
  1377 	{ "paleturquoise", NSVG_RGB(175, 238, 238) },
  1378 	{ "palevioletred", NSVG_RGB(219, 112, 147) },
  1379 	{ "papayawhip", NSVG_RGB(255, 239, 213) },
  1380 	{ "peachpuff", NSVG_RGB(255, 218, 185) },
  1381 	{ "peru", NSVG_RGB(205, 133, 63) },
  1382 	{ "pink", NSVG_RGB(255, 192, 203) },
  1383 	{ "plum", NSVG_RGB(221, 160, 221) },
  1384 	{ "powderblue", NSVG_RGB(176, 224, 230) },
  1385 	{ "purple", NSVG_RGB(128, 0, 128) },
  1386 	{ "rosybrown", NSVG_RGB(188, 143, 143) },
  1387 	{ "royalblue", NSVG_RGB( 65, 105, 225) },
  1388 	{ "saddlebrown", NSVG_RGB(139, 69, 19) },
  1389 	{ "salmon", NSVG_RGB(250, 128, 114) },
  1390 	{ "sandybrown", NSVG_RGB(244, 164, 96) },
  1391 	{ "seagreen", NSVG_RGB( 46, 139, 87) },
  1392 	{ "seashell", NSVG_RGB(255, 245, 238) },
  1393 	{ "sienna", NSVG_RGB(160, 82, 45) },
  1394 	{ "silver", NSVG_RGB(192, 192, 192) },
  1395 	{ "skyblue", NSVG_RGB(135, 206, 235) },
  1396 	{ "slateblue", NSVG_RGB(106, 90, 205) },
  1397 	{ "slategray", NSVG_RGB(112, 128, 144) },
  1398 	{ "slategrey", NSVG_RGB(112, 128, 144) },
  1399 	{ "snow", NSVG_RGB(255, 250, 250) },
  1400 	{ "springgreen", NSVG_RGB( 0, 255, 127) },
  1401 	{ "steelblue", NSVG_RGB( 70, 130, 180) },
  1402 	{ "tan", NSVG_RGB(210, 180, 140) },
  1403 	{ "teal", NSVG_RGB( 0, 128, 128) },
  1404 	{ "thistle", NSVG_RGB(216, 191, 216) },
  1405 	{ "tomato", NSVG_RGB(255, 99, 71) },
  1406 	{ "turquoise", NSVG_RGB( 64, 224, 208) },
  1407 	{ "violet", NSVG_RGB(238, 130, 238) },
  1408 	{ "wheat", NSVG_RGB(245, 222, 179) },
  1409 	{ "whitesmoke", NSVG_RGB(245, 245, 245) },
  1410 	{ "yellowgreen", NSVG_RGB(154, 205, 50) },
  1411 #endif
  1412 };
  1413 
  1414 static unsigned int nsvg__parseColorName(const char* str)
  1415 {
  1416 	int i, ncolors = sizeof(nsvg__colors) / sizeof(NSVGNamedColor);
  1417 
  1418 	for (i = 0; i < ncolors; i++) {
  1419 		if (strcmp(nsvg__colors[i].name, str) == 0) {
  1420 			return nsvg__colors[i].color;
  1421 		}
  1422 	}
  1423 
  1424 	return NSVG_RGB(128, 128, 128);
  1425 }
  1426 
  1427 static unsigned int nsvg__parseColor(const char* str)
  1428 {
  1429 	size_t len = 0;
  1430 	while(*str == ' ') ++str;
  1431 	len = strlen(str);
  1432 	if (len >= 1 && *str == '#')
  1433 		return nsvg__parseColorHex(str);
  1434 	else if (len >= 4 && str[0] == 'r' && str[1] == 'g' && str[2] == 'b' && str[3] == '(')
  1435 		return nsvg__parseColorRGB(str);
  1436 	return nsvg__parseColorName(str);
  1437 }
  1438 
  1439 static float nsvg__parseOpacity(const char* str)
  1440 {
  1441 	float val = 0;
  1442 	sscanf(str, "%f", &val);
  1443 	if (val < 0.0f) val = 0.0f;
  1444 	if (val > 1.0f) val = 1.0f;
  1445 	return val;
  1446 }
  1447 
  1448 static float nsvg__parseMiterLimit(const char* str)
  1449 {
  1450 	float val = 0;
  1451 	sscanf(str, "%f", &val);
  1452 	if (val < 0.0f) val = 0.0f;
  1453 	return val;
  1454 }
  1455 
  1456 static int nsvg__parseUnits(const char* units)
  1457 {
  1458 	if (units[0] == 'p' && units[1] == 'x')
  1459 		return NSVG_UNITS_PX;
  1460 	else if (units[0] == 'p' && units[1] == 't')
  1461 		return NSVG_UNITS_PT;
  1462 	else if (units[0] == 'p' && units[1] == 'c')
  1463 		return NSVG_UNITS_PC;
  1464 	else if (units[0] == 'm' && units[1] == 'm')
  1465 		return NSVG_UNITS_MM;
  1466 	else if (units[0] == 'c' && units[1] == 'm')
  1467 		return NSVG_UNITS_CM;
  1468 	else if (units[0] == 'i' && units[1] == 'n')
  1469 		return NSVG_UNITS_IN;
  1470 	else if (units[0] == '%')
  1471 		return NSVG_UNITS_PERCENT;
  1472 	else if (units[0] == 'e' && units[1] == 'm')
  1473 		return NSVG_UNITS_EM;
  1474 	else if (units[0] == 'e' && units[1] == 'x')
  1475 		return NSVG_UNITS_EX;
  1476 	return NSVG_UNITS_USER;
  1477 }
  1478 
  1479 static NSVGcoordinate nsvg__parseCoordinateRaw(const char* str)
  1480 {
  1481 	NSVGcoordinate coord = {0, NSVG_UNITS_USER};
  1482 	char units[32]="";
  1483 	sscanf(str, "%f%31s", &coord.value, units);
  1484 	coord.units = nsvg__parseUnits(units);
  1485 	return coord;
  1486 }
  1487 
  1488 static NSVGcoordinate nsvg__coord(float v, int units)
  1489 {
  1490 	NSVGcoordinate coord ;
  1491 	coord.value = v;
  1492 	coord.units = units;
  1493 	return coord;
  1494 }
  1495 
  1496 static float nsvg__parseCoordinate(NSVGparser* p, const char* str, float orig, float length)
  1497 {
  1498 	NSVGcoordinate coord = nsvg__parseCoordinateRaw(str);
  1499 	return nsvg__convertToPixels(p, coord, orig, length);
  1500 }
  1501 
  1502 static int nsvg__parseTransformArgs(const char* str, float* args, int maxNa, int* na)
  1503 {
  1504 	const char* end;
  1505 	const char* ptr;
  1506 	char it[64];
  1507 
  1508 	*na = 0;
  1509 	ptr = str;
  1510 	while (*ptr && *ptr != '(') ++ptr;
  1511 	if (*ptr == 0)
  1512 		return 1;
  1513 	end = ptr;
  1514 	while (*end && *end != ')') ++end;
  1515 	if (*end == 0)
  1516 		return 1;
  1517 
  1518 	while (ptr < end) {
  1519 		if (*ptr == '-' || *ptr == '+' || *ptr == '.' || nsvg__isdigit(*ptr)) {
  1520 			if (*na >= maxNa) return 0;
  1521 			ptr = nsvg__parseNumber(ptr, it, 64);
  1522 			args[(*na)++] = (float)nsvg__atof(it);
  1523 		} else {
  1524 			++ptr;
  1525 		}
  1526 	}
  1527 	return (int)(end - str);
  1528 }
  1529 
  1530 
  1531 static int nsvg__parseMatrix(float* xform, const char* str)
  1532 {
  1533 	float t[6];
  1534 	int na = 0;
  1535 	int len = nsvg__parseTransformArgs(str, t, 6, &na);
  1536 	if (na != 6) return len;
  1537 	memcpy(xform, t, sizeof(float)*6);
  1538 	return len;
  1539 }
  1540 
  1541 static int nsvg__parseTranslate(float* xform, const char* str)
  1542 {
  1543 	float args[2];
  1544 	float t[6];
  1545 	int na = 0;
  1546 	int len = nsvg__parseTransformArgs(str, args, 2, &na);
  1547 	if (na == 1) args[1] = 0.0;
  1548 
  1549 	nsvg__xformSetTranslation(t, args[0], args[1]);
  1550 	memcpy(xform, t, sizeof(float)*6);
  1551 	return len;
  1552 }
  1553 
  1554 static int nsvg__parseScale(float* xform, const char* str)
  1555 {
  1556 	float args[2];
  1557 	int na = 0;
  1558 	float t[6];
  1559 	int len = nsvg__parseTransformArgs(str, args, 2, &na);
  1560 	if (na == 1) args[1] = args[0];
  1561 	nsvg__xformSetScale(t, args[0], args[1]);
  1562 	memcpy(xform, t, sizeof(float)*6);
  1563 	return len;
  1564 }
  1565 
  1566 static int nsvg__parseSkewX(float* xform, const char* str)
  1567 {
  1568 	float args[1];
  1569 	int na = 0;
  1570 	float t[6];
  1571 	int len = nsvg__parseTransformArgs(str, args, 1, &na);
  1572 	nsvg__xformSetSkewX(t, args[0]/180.0f*NSVG_PI);
  1573 	memcpy(xform, t, sizeof(float)*6);
  1574 	return len;
  1575 }
  1576 
  1577 static int nsvg__parseSkewY(float* xform, const char* str)
  1578 {
  1579 	float args[1];
  1580 	int na = 0;
  1581 	float t[6];
  1582 	int len = nsvg__parseTransformArgs(str, args, 1, &na);
  1583 	nsvg__xformSetSkewY(t, args[0]/180.0f*NSVG_PI);
  1584 	memcpy(xform, t, sizeof(float)*6);
  1585 	return len;
  1586 }
  1587 
  1588 static int nsvg__parseRotate(float* xform, const char* str)
  1589 {
  1590 	float args[3];
  1591 	int na = 0;
  1592 	float m[6];
  1593 	float t[6];
  1594 	int len = nsvg__parseTransformArgs(str, args, 3, &na);
  1595 	if (na == 1)
  1596 		args[1] = args[2] = 0.0f;
  1597 	nsvg__xformIdentity(m);
  1598 
  1599 	if (na > 1) {
  1600 		nsvg__xformSetTranslation(t, -args[1], -args[2]);
  1601 		nsvg__xformMultiply(m, t);
  1602 	}
  1603 
  1604 	nsvg__xformSetRotation(t, args[0]/180.0f*NSVG_PI);
  1605 	nsvg__xformMultiply(m, t);
  1606 
  1607 	if (na > 1) {
  1608 		nsvg__xformSetTranslation(t, args[1], args[2]);
  1609 		nsvg__xformMultiply(m, t);
  1610 	}
  1611 
  1612 	memcpy(xform, m, sizeof(float)*6);
  1613 
  1614 	return len;
  1615 }
  1616 
  1617 static void nsvg__parseTransform(float* xform, const char* str)
  1618 {
  1619 	float t[6];
  1620 	nsvg__xformIdentity(xform);
  1621 	while (*str)
  1622 	{
  1623 		if (strncmp(str, "matrix", 6) == 0)
  1624 			str += nsvg__parseMatrix(t, str);
  1625 		else if (strncmp(str, "translate", 9) == 0)
  1626 			str += nsvg__parseTranslate(t, str);
  1627 		else if (strncmp(str, "scale", 5) == 0)
  1628 			str += nsvg__parseScale(t, str);
  1629 		else if (strncmp(str, "rotate", 6) == 0)
  1630 			str += nsvg__parseRotate(t, str);
  1631 		else if (strncmp(str, "skewX", 5) == 0)
  1632 			str += nsvg__parseSkewX(t, str);
  1633 		else if (strncmp(str, "skewY", 5) == 0)
  1634 			str += nsvg__parseSkewY(t, str);
  1635 		else{
  1636 			++str;
  1637 			continue;
  1638 		}
  1639 
  1640 		nsvg__xformPremultiply(xform, t);
  1641 	}
  1642 }
  1643 
  1644 static void nsvg__parseUrl(char* id, const char* str)
  1645 {
  1646 	int i = 0;
  1647 	str += 4; // "url(";
  1648 	if (*str == '#')
  1649 		str++;
  1650 	while (i < 63 && *str != ')') {
  1651 		id[i] = *str++;
  1652 		i++;
  1653 	}
  1654 	id[i] = '\0';
  1655 }
  1656 
  1657 static char nsvg__parseLineCap(const char* str)
  1658 {
  1659 	if (strcmp(str, "butt") == 0)
  1660 		return NSVG_CAP_BUTT;
  1661 	else if (strcmp(str, "round") == 0)
  1662 		return NSVG_CAP_ROUND;
  1663 	else if (strcmp(str, "square") == 0)
  1664 		return NSVG_CAP_SQUARE;
  1665 	// TODO: handle inherit.
  1666 	return NSVG_CAP_BUTT;
  1667 }
  1668 
  1669 static char nsvg__parseLineJoin(const char* str)
  1670 {
  1671 	if (strcmp(str, "miter") == 0)
  1672 		return NSVG_JOIN_MITER;
  1673 	else if (strcmp(str, "round") == 0)
  1674 		return NSVG_JOIN_ROUND;
  1675 	else if (strcmp(str, "bevel") == 0)
  1676 		return NSVG_JOIN_BEVEL;
  1677 	// TODO: handle inherit.
  1678 	return NSVG_CAP_BUTT;
  1679 }
  1680 
  1681 static char nsvg__parseFillRule(const char* str)
  1682 {
  1683 	if (strcmp(str, "nonzero") == 0)
  1684 		return NSVG_FILLRULE_NONZERO;
  1685 	else if (strcmp(str, "evenodd") == 0)
  1686 		return NSVG_FILLRULE_EVENODD;
  1687 	// TODO: handle inherit.
  1688 	return NSVG_FILLRULE_NONZERO;
  1689 }
  1690 
  1691 static const char* nsvg__getNextDashItem(const char* s, char* it)
  1692 {
  1693 	int n = 0;
  1694 	it[0] = '\0';
  1695 	// Skip white spaces and commas
  1696 	while (*s && (nsvg__isspace(*s) || *s == ',')) s++;
  1697 	// Advance until whitespace, comma or end.
  1698 	while (*s && (!nsvg__isspace(*s) && *s != ',')) {
  1699 		if (n < 63)
  1700 			it[n++] = *s;
  1701 		s++;
  1702 	}
  1703 	it[n++] = '\0';
  1704 	return s;
  1705 }
  1706 
  1707 static int nsvg__parseStrokeDashArray(NSVGparser* p, const char* str, float* strokeDashArray)
  1708 {
  1709 	char item[64];
  1710 	int count = 0, i;
  1711 	float sum = 0.0f;
  1712 
  1713 	// Handle "none"
  1714 	if (str[0] == 'n')
  1715 		return 0;
  1716 
  1717 	// Parse dashes
  1718 	while (*str) {
  1719 		str = nsvg__getNextDashItem(str, item);
  1720 		if (!*item) break;
  1721 		if (count < NSVG_MAX_DASHES)
  1722 			strokeDashArray[count++] = fabsf(nsvg__parseCoordinate(p, item, 0.0f, nsvg__actualLength(p)));
  1723 	}
  1724 
  1725 	for (i = 0; i < count; i++)
  1726 		sum += strokeDashArray[i];
  1727 	if (sum <= 1e-6f)
  1728 		count = 0;
  1729 
  1730 	return count;
  1731 }
  1732 
  1733 static void nsvg__parseStyle(NSVGparser* p, const char* str);
  1734 
  1735 static int nsvg__parseAttr(NSVGparser* p, const char* name, const char* value)
  1736 {
  1737 	float xform[6];
  1738 	NSVGattrib* attr = nsvg__getAttr(p);
  1739 	if (!attr) return 0;
  1740 
  1741 	if (strcmp(name, "style") == 0) {
  1742 		nsvg__parseStyle(p, value);
  1743 	} else if (strcmp(name, "display") == 0) {
  1744 		if (strcmp(value, "none") == 0)
  1745 			attr->visible = 0;
  1746 		// Don't reset ->visible on display:inline, one display:none hides the whole subtree
  1747 
  1748 	} else if (strcmp(name, "fill") == 0) {
  1749 		if (strcmp(value, "none") == 0) {
  1750 			attr->hasFill = 0;
  1751 		} else if (strncmp(value, "url(", 4) == 0) {
  1752 			attr->hasFill = 2;
  1753 			nsvg__parseUrl(attr->fillGradient, value);
  1754 		} else {
  1755 			attr->hasFill = 1;
  1756 			attr->fillColor = nsvg__parseColor(value);
  1757 		}
  1758 	} else if (strcmp(name, "opacity") == 0) {
  1759 		attr->opacity = nsvg__parseOpacity(value);
  1760 	} else if (strcmp(name, "fill-opacity") == 0) {
  1761 		attr->fillOpacity = nsvg__parseOpacity(value);
  1762 	} else if (strcmp(name, "stroke") == 0) {
  1763 		if (strcmp(value, "none") == 0) {
  1764 			attr->hasStroke = 0;
  1765 		} else if (strncmp(value, "url(", 4) == 0) {
  1766 			attr->hasStroke = 2;
  1767 			nsvg__parseUrl(attr->strokeGradient, value);
  1768 		} else {
  1769 			attr->hasStroke = 1;
  1770 			attr->strokeColor = nsvg__parseColor(value);
  1771 		}
  1772 	} else if (strcmp(name, "stroke-width") == 0) {
  1773 		attr->strokeWidth = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p));
  1774 	} else if (strcmp(name, "stroke-dasharray") == 0) {
  1775 		attr->strokeDashCount = nsvg__parseStrokeDashArray(p, value, attr->strokeDashArray);
  1776 	} else if (strcmp(name, "stroke-dashoffset") == 0) {
  1777 		attr->strokeDashOffset = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p));
  1778 	} else if (strcmp(name, "stroke-opacity") == 0) {
  1779 		attr->strokeOpacity = nsvg__parseOpacity(value);
  1780 	} else if (strcmp(name, "stroke-linecap") == 0) {
  1781 		attr->strokeLineCap = nsvg__parseLineCap(value);
  1782 	} else if (strcmp(name, "stroke-linejoin") == 0) {
  1783 		attr->strokeLineJoin = nsvg__parseLineJoin(value);
  1784 	} else if (strcmp(name, "stroke-miterlimit") == 0) {
  1785 		attr->miterLimit = nsvg__parseMiterLimit(value);
  1786 	} else if (strcmp(name, "fill-rule") == 0) {
  1787 		attr->fillRule = nsvg__parseFillRule(value);
  1788 	} else if (strcmp(name, "font-size") == 0) {
  1789 		attr->fontSize = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p));
  1790 	} else if (strcmp(name, "transform") == 0) {
  1791 		nsvg__parseTransform(xform, value);
  1792 		nsvg__xformPremultiply(attr->xform, xform);
  1793 	} else if (strcmp(name, "stop-color") == 0) {
  1794 		attr->stopColor = nsvg__parseColor(value);
  1795 	} else if (strcmp(name, "stop-opacity") == 0) {
  1796 		attr->stopOpacity = nsvg__parseOpacity(value);
  1797 	} else if (strcmp(name, "offset") == 0) {
  1798 		attr->stopOffset = nsvg__parseCoordinate(p, value, 0.0f, 1.0f);
  1799 	} else if (strcmp(name, "id") == 0) {
  1800 		strncpy(attr->id, value, 63);
  1801 		attr->id[63] = '\0';
  1802 	} else if (strcmp(name, "class") == 0) {
  1803 		NSVGstyles* style = p->styles;
  1804 		while (style) {
  1805 			if (strcmp(style->name + 1, value) == 0) {
  1806 				break;
  1807 			}
  1808 			style = style->next;
  1809 		}
  1810 		if (style) {
  1811 			nsvg__parseStyle(p, style->description);
  1812 		}
  1813 	} 
  1814 	else {
  1815 		return 0;
  1816 	} 
  1817 	return 1;
  1818 }
  1819 
  1820 static int nsvg__parseNameValue(NSVGparser* p, const char* start, const char* end)
  1821 {
  1822 	const char* str;
  1823 	const char* val;
  1824 	char name[512];
  1825 	char value[512];
  1826 	int n;
  1827 
  1828 	str = start;
  1829 	while (str < end && *str != ':') ++str;
  1830 
  1831 	val = str;
  1832 
  1833 	// Right Trim
  1834 	while (str > start &&  (*str == ':' || nsvg__isspace(*str))) --str;
  1835 	++str;
  1836 
  1837 	n = (int)(str - start);
  1838 	if (n > 511) n = 511;
  1839 	if (n) memcpy(name, start, n);
  1840 	name[n] = 0;
  1841 
  1842 	while (val < end && (*val == ':' || nsvg__isspace(*val))) ++val;
  1843 
  1844 	n = (int)(end - val);
  1845 	if (n > 511) n = 511;
  1846 	if (n) memcpy(value, val, n);
  1847 	value[n] = 0;
  1848 
  1849 	return nsvg__parseAttr(p, name, value);
  1850 }
  1851 
  1852 static void nsvg__parseStyle(NSVGparser* p, const char* str)
  1853 {
  1854 	const char* start;
  1855 	const char* end;
  1856 
  1857 	while (*str) {
  1858 		// Left Trim
  1859 		while(*str && nsvg__isspace(*str)) ++str;
  1860 		start = str;
  1861 		while(*str && *str != ';') ++str;
  1862 		end = str;
  1863 
  1864 		// Right Trim
  1865 		while (end > start &&  (*end == ';' || nsvg__isspace(*end))) --end;
  1866 		++end;
  1867 
  1868 		nsvg__parseNameValue(p, start, end);
  1869 		if (*str) ++str;
  1870 	}
  1871 }
  1872 
  1873 static void nsvg__parseAttribs(NSVGparser* p, const char** attr)
  1874 {
  1875 	int i;
  1876 	for (i = 0; attr[i]; i += 2)
  1877 	{
  1878 		if (strcmp(attr[i], "style") == 0)
  1879 			nsvg__parseStyle(p, attr[i + 1]);
  1880 		else
  1881 			nsvg__parseAttr(p, attr[i], attr[i + 1]);
  1882 	}
  1883 }
  1884 
  1885 static int nsvg__getArgsPerElement(char cmd)
  1886 {
  1887 	switch (cmd) {
  1888 		case 'v':
  1889 		case 'V':
  1890 		case 'h':
  1891 		case 'H':
  1892 			return 1;
  1893 		case 'm':
  1894 		case 'M':
  1895 		case 'l':
  1896 		case 'L':
  1897 		case 't':
  1898 		case 'T':
  1899 			return 2;
  1900 		case 'q':
  1901 		case 'Q':
  1902 		case 's':
  1903 		case 'S':
  1904 			return 4;
  1905 		case 'c':
  1906 		case 'C':
  1907 			return 6;
  1908 		case 'a':
  1909 		case 'A':
  1910 			return 7;
  1911 	}
  1912 	return 0;
  1913 }
  1914 
  1915 static void nsvg__pathMoveTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)
  1916 {
  1917 	if (rel) {
  1918 		*cpx += args[0];
  1919 		*cpy += args[1];
  1920 	} else {
  1921 		*cpx = args[0];
  1922 		*cpy = args[1];
  1923 	}
  1924 	nsvg__moveTo(p, *cpx, *cpy);
  1925 }
  1926 
  1927 static void nsvg__pathLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)
  1928 {
  1929 	if (rel) {
  1930 		*cpx += args[0];
  1931 		*cpy += args[1];
  1932 	} else {
  1933 		*cpx = args[0];
  1934 		*cpy = args[1];
  1935 	}
  1936 	nsvg__lineTo(p, *cpx, *cpy);
  1937 }
  1938 
  1939 static void nsvg__pathHLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)
  1940 {
  1941 	if (rel)
  1942 		*cpx += args[0];
  1943 	else
  1944 		*cpx = args[0];
  1945 	nsvg__lineTo(p, *cpx, *cpy);
  1946 }
  1947 
  1948 static void nsvg__pathVLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)
  1949 {
  1950 	if (rel)
  1951 		*cpy += args[0];
  1952 	else
  1953 		*cpy = args[0];
  1954 	nsvg__lineTo(p, *cpx, *cpy);
  1955 }
  1956 
  1957 static void nsvg__pathCubicBezTo(NSVGparser* p, float* cpx, float* cpy,
  1958 								 float* cpx2, float* cpy2, float* args, int rel)
  1959 {
  1960 	float x2, y2, cx1, cy1, cx2, cy2;
  1961 
  1962 	if (rel) {
  1963 		cx1 = *cpx + args[0];
  1964 		cy1 = *cpy + args[1];
  1965 		cx2 = *cpx + args[2];
  1966 		cy2 = *cpy + args[3];
  1967 		x2 = *cpx + args[4];
  1968 		y2 = *cpy + args[5];
  1969 	} else {
  1970 		cx1 = args[0];
  1971 		cy1 = args[1];
  1972 		cx2 = args[2];
  1973 		cy2 = args[3];
  1974 		x2 = args[4];
  1975 		y2 = args[5];
  1976 	}
  1977 
  1978 	nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2);
  1979 
  1980 	*cpx2 = cx2;
  1981 	*cpy2 = cy2;
  1982 	*cpx = x2;
  1983 	*cpy = y2;
  1984 }
  1985 
  1986 static void nsvg__pathCubicBezShortTo(NSVGparser* p, float* cpx, float* cpy,
  1987 									  float* cpx2, float* cpy2, float* args, int rel)
  1988 {
  1989 	float x1, y1, x2, y2, cx1, cy1, cx2, cy2;
  1990 
  1991 	x1 = *cpx;
  1992 	y1 = *cpy;
  1993 	if (rel) {
  1994 		cx2 = *cpx + args[0];
  1995 		cy2 = *cpy + args[1];
  1996 		x2 = *cpx + args[2];
  1997 		y2 = *cpy + args[3];
  1998 	} else {
  1999 		cx2 = args[0];
  2000 		cy2 = args[1];
  2001 		x2 = args[2];
  2002 		y2 = args[3];
  2003 	}
  2004 
  2005 	cx1 = 2*x1 - *cpx2;
  2006 	cy1 = 2*y1 - *cpy2;
  2007 
  2008 	nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2);
  2009 
  2010 	*cpx2 = cx2;
  2011 	*cpy2 = cy2;
  2012 	*cpx = x2;
  2013 	*cpy = y2;
  2014 }
  2015 
  2016 static void nsvg__pathQuadBezTo(NSVGparser* p, float* cpx, float* cpy,
  2017 								float* cpx2, float* cpy2, float* args, int rel)
  2018 {
  2019 	float x1, y1, x2, y2, cx, cy;
  2020 	float cx1, cy1, cx2, cy2;
  2021 
  2022 	x1 = *cpx;
  2023 	y1 = *cpy;
  2024 	if (rel) {
  2025 		cx = *cpx + args[0];
  2026 		cy = *cpy + args[1];
  2027 		x2 = *cpx + args[2];
  2028 		y2 = *cpy + args[3];
  2029 	} else {
  2030 		cx = args[0];
  2031 		cy = args[1];
  2032 		x2 = args[2];
  2033 		y2 = args[3];
  2034 	}
  2035 
  2036 	// Convert to cubic bezier
  2037 	cx1 = x1 + 2.0f/3.0f*(cx - x1);
  2038 	cy1 = y1 + 2.0f/3.0f*(cy - y1);
  2039 	cx2 = x2 + 2.0f/3.0f*(cx - x2);
  2040 	cy2 = y2 + 2.0f/3.0f*(cy - y2);
  2041 
  2042 	nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2);
  2043 
  2044 	*cpx2 = cx;
  2045 	*cpy2 = cy;
  2046 	*cpx = x2;
  2047 	*cpy = y2;
  2048 }
  2049 
  2050 static void nsvg__pathQuadBezShortTo(NSVGparser* p, float* cpx, float* cpy,
  2051 									 float* cpx2, float* cpy2, float* args, int rel)
  2052 {
  2053 	float x1, y1, x2, y2, cx, cy;
  2054 	float cx1, cy1, cx2, cy2;
  2055 
  2056 	x1 = *cpx;
  2057 	y1 = *cpy;
  2058 	if (rel) {
  2059 		x2 = *cpx + args[0];
  2060 		y2 = *cpy + args[1];
  2061 	} else {
  2062 		x2 = args[0];
  2063 		y2 = args[1];
  2064 	}
  2065 
  2066 	cx = 2*x1 - *cpx2;
  2067 	cy = 2*y1 - *cpy2;
  2068 
  2069 	// Convert to cubix bezier
  2070 	cx1 = x1 + 2.0f/3.0f*(cx - x1);
  2071 	cy1 = y1 + 2.0f/3.0f*(cy - y1);
  2072 	cx2 = x2 + 2.0f/3.0f*(cx - x2);
  2073 	cy2 = y2 + 2.0f/3.0f*(cy - y2);
  2074 
  2075 	nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2);
  2076 
  2077 	*cpx2 = cx;
  2078 	*cpy2 = cy;
  2079 	*cpx = x2;
  2080 	*cpy = y2;
  2081 }
  2082 
  2083 static float nsvg__sqr(float x) { return x*x; }
  2084 static float nsvg__vmag(float x, float y) { return sqrtf(x*x + y*y); }
  2085 
  2086 static float nsvg__vecrat(float ux, float uy, float vx, float vy)
  2087 {
  2088 	return (ux*vx + uy*vy) / (nsvg__vmag(ux,uy) * nsvg__vmag(vx,vy));
  2089 }
  2090 
  2091 static float nsvg__vecang(float ux, float uy, float vx, float vy)
  2092 {
  2093 	float r = nsvg__vecrat(ux,uy, vx,vy);
  2094 	if (r < -1.0f) r = -1.0f;
  2095 	if (r > 1.0f) r = 1.0f;
  2096 	return ((ux*vy < uy*vx) ? -1.0f : 1.0f) * acosf(r);
  2097 }
  2098 
  2099 static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)
  2100 {
  2101 	// Ported from canvg (https://code.google.com/p/canvg/)
  2102 	float rx, ry, rotx;
  2103 	float x1, y1, x2, y2, cx, cy, dx, dy, d;
  2104 	float x1p, y1p, cxp, cyp, s, sa, sb;
  2105 	float ux, uy, vx, vy, a1, da;
  2106 	float x, y, tanx, tany, a, px = 0, py = 0, ptanx = 0, ptany = 0, t[6];
  2107 	float sinrx, cosrx;
  2108 	int fa, fs;
  2109 	int i, ndivs;
  2110 	float hda, kappa;
  2111 
  2112 	rx = fabsf(args[0]);				// y radius
  2113 	ry = fabsf(args[1]);				// x radius
  2114 	rotx = args[2] / 180.0f * NSVG_PI;		// x rotation angle
  2115 	fa = fabsf(args[3]) > 1e-6 ? 1 : 0;	// Large arc
  2116 	fs = fabsf(args[4]) > 1e-6 ? 1 : 0;	// Sweep direction
  2117 	x1 = *cpx;							// start point
  2118 	y1 = *cpy;
  2119 	if (rel) {							// end point
  2120 		x2 = *cpx + args[5];
  2121 		y2 = *cpy + args[6];
  2122 	} else {
  2123 		x2 = args[5];
  2124 		y2 = args[6];
  2125 	}
  2126 
  2127 	dx = x1 - x2;
  2128 	dy = y1 - y2;
  2129 	d = sqrtf(dx*dx + dy*dy);
  2130 	if (d < 1e-6f || rx < 1e-6f || ry < 1e-6f) {
  2131 		// The arc degenerates to a line
  2132 		nsvg__lineTo(p, x2, y2);
  2133 		*cpx = x2;
  2134 		*cpy = y2;
  2135 		return;
  2136 	}
  2137 
  2138 	sinrx = sinf(rotx);
  2139 	cosrx = cosf(rotx);
  2140 
  2141 	// Convert to center point parameterization.
  2142 	// http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
  2143 	// 1) Compute x1', y1'
  2144 	x1p = cosrx * dx / 2.0f + sinrx * dy / 2.0f;
  2145 	y1p = -sinrx * dx / 2.0f + cosrx * dy / 2.0f;
  2146 	d = nsvg__sqr(x1p)/nsvg__sqr(rx) + nsvg__sqr(y1p)/nsvg__sqr(ry);
  2147 	if (d > 1) {
  2148 		d = sqrtf(d);
  2149 		rx *= d;
  2150 		ry *= d;
  2151 	}
  2152 	// 2) Compute cx', cy'
  2153 	s = 0.0f;
  2154 	sa = nsvg__sqr(rx)*nsvg__sqr(ry) - nsvg__sqr(rx)*nsvg__sqr(y1p) - nsvg__sqr(ry)*nsvg__sqr(x1p);
  2155 	sb = nsvg__sqr(rx)*nsvg__sqr(y1p) + nsvg__sqr(ry)*nsvg__sqr(x1p);
  2156 	if (sa < 0.0f) sa = 0.0f;
  2157 	if (sb > 0.0f)
  2158 		s = sqrtf(sa / sb);
  2159 	if (fa == fs)
  2160 		s = -s;
  2161 	cxp = s * rx * y1p / ry;
  2162 	cyp = s * -ry * x1p / rx;
  2163 
  2164 	// 3) Compute cx,cy from cx',cy'
  2165 	cx = (x1 + x2)/2.0f + cosrx*cxp - sinrx*cyp;
  2166 	cy = (y1 + y2)/2.0f + sinrx*cxp + cosrx*cyp;
  2167 
  2168 	// 4) Calculate theta1, and delta theta.
  2169 	ux = (x1p - cxp) / rx;
  2170 	uy = (y1p - cyp) / ry;
  2171 	vx = (-x1p - cxp) / rx;
  2172 	vy = (-y1p - cyp) / ry;
  2173 	a1 = nsvg__vecang(1.0f,0.0f, ux,uy);	// Initial angle
  2174 	da = nsvg__vecang(ux,uy, vx,vy);		// Delta angle
  2175 
  2176 //	if (vecrat(ux,uy,vx,vy) <= -1.0f) da = NSVG_PI;
  2177 //	if (vecrat(ux,uy,vx,vy) >= 1.0f) da = 0;
  2178 
  2179 	if (fs == 0 && da > 0)
  2180 		da -= 2 * NSVG_PI;
  2181 	else if (fs == 1 && da < 0)
  2182 		da += 2 * NSVG_PI;
  2183 
  2184 	// Approximate the arc using cubic spline segments.
  2185 	t[0] = cosrx; t[1] = sinrx;
  2186 	t[2] = -sinrx; t[3] = cosrx;
  2187 	t[4] = cx; t[5] = cy;
  2188 
  2189 	// Split arc into max 90 degree segments.
  2190 	// The loop assumes an iteration per end point (including start and end), this +1.
  2191 	ndivs = (int)(fabsf(da) / (NSVG_PI*0.5f) + 1.0f);
  2192 	hda = (da / (float)ndivs) / 2.0f;
  2193 	kappa = fabsf(4.0f / 3.0f * (1.0f - cosf(hda)) / sinf(hda));
  2194 	if (da < 0.0f)
  2195 		kappa = -kappa;
  2196 
  2197 	for (i = 0; i <= ndivs; i++) {
  2198 		a = a1 + da * ((float)i/(float)ndivs);
  2199 		dx = cosf(a);
  2200 		dy = sinf(a);
  2201 		nsvg__xformPoint(&x, &y, dx*rx, dy*ry, t); // position
  2202 		nsvg__xformVec(&tanx, &tany, -dy*rx * kappa, dx*ry * kappa, t); // tangent
  2203 		if (i > 0)
  2204 			nsvg__cubicBezTo(p, px+ptanx,py+ptany, x-tanx, y-tany, x, y);
  2205 		px = x;
  2206 		py = y;
  2207 		ptanx = tanx;
  2208 		ptany = tany;
  2209 	}
  2210 
  2211 	*cpx = x2;
  2212 	*cpy = y2;
  2213 }
  2214 
  2215 static void nsvg__parsePath(NSVGparser* p, const char** attr)
  2216 {
  2217 	const char* s = NULL;
  2218 	char cmd = '\0';
  2219 	float args[10];
  2220 	int nargs;
  2221 	int rargs = 0;
  2222 	float cpx, cpy, cpx2, cpy2;
  2223 	const char* tmp[4];
  2224 	char closedFlag;
  2225 	int i;
  2226 	char item[64];
  2227 
  2228 	for (i = 0; attr[i]; i += 2) {
  2229 		if (strcmp(attr[i], "d") == 0) {
  2230 			s = attr[i + 1];
  2231 		} else {
  2232 			tmp[0] = attr[i];
  2233 			tmp[1] = attr[i + 1];
  2234 			tmp[2] = 0;
  2235 			tmp[3] = 0;
  2236 			nsvg__parseAttribs(p, tmp);
  2237 		}
  2238 	}
  2239 
  2240 	if (s) {
  2241 		nsvg__resetPath(p);
  2242 		cpx = 0; cpy = 0;
  2243 		cpx2 = 0; cpy2 = 0;
  2244 		closedFlag = 0;
  2245 		nargs = 0;
  2246 
  2247 		while (*s) {
  2248 			s = nsvg__getNextPathItem(s, item);
  2249 			if (!*item) break;
  2250 			if (nsvg__isnum(item[0])) {
  2251 				if (nargs < 10)
  2252 					args[nargs++] = (float)nsvg__atof(item);
  2253 				if (nargs >= rargs) {
  2254 					switch (cmd) {
  2255 						case 'm':
  2256 						case 'M':
  2257 							nsvg__pathMoveTo(p, &cpx, &cpy, args, cmd == 'm' ? 1 : 0);
  2258 							// Moveto can be followed by multiple coordinate pairs,
  2259 							// which should be treated as linetos.
  2260 							cmd = (cmd == 'm') ? 'l' : 'L';
  2261 							rargs = nsvg__getArgsPerElement(cmd);
  2262 							cpx2 = cpx; cpy2 = cpy;
  2263 							break;
  2264 						case 'l':
  2265 						case 'L':
  2266 							nsvg__pathLineTo(p, &cpx, &cpy, args, cmd == 'l' ? 1 : 0);
  2267 							cpx2 = cpx; cpy2 = cpy;
  2268 							break;
  2269 						case 'H':
  2270 						case 'h':
  2271 							nsvg__pathHLineTo(p, &cpx, &cpy, args, cmd == 'h' ? 1 : 0);
  2272 							cpx2 = cpx; cpy2 = cpy;
  2273 							break;
  2274 						case 'V':
  2275 						case 'v':
  2276 							nsvg__pathVLineTo(p, &cpx, &cpy, args, cmd == 'v' ? 1 : 0);
  2277 							cpx2 = cpx; cpy2 = cpy;
  2278 							break;
  2279 						case 'C':
  2280 						case 'c':
  2281 							nsvg__pathCubicBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'c' ? 1 : 0);
  2282 							break;
  2283 						case 'S':
  2284 						case 's':
  2285 							nsvg__pathCubicBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 's' ? 1 : 0);
  2286 							break;
  2287 						case 'Q':
  2288 						case 'q':
  2289 							nsvg__pathQuadBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'q' ? 1 : 0);
  2290 							break;
  2291 						case 'T':
  2292 						case 't':
  2293 							nsvg__pathQuadBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 't' ? 1 : 0);
  2294 							break;
  2295 						case 'A':
  2296 						case 'a':
  2297 							nsvg__pathArcTo(p, &cpx, &cpy, args, cmd == 'a' ? 1 : 0);
  2298 							cpx2 = cpx; cpy2 = cpy;
  2299 							break;
  2300 						default:
  2301 							if (nargs >= 2) {
  2302 								cpx = args[nargs-2];
  2303 								cpy = args[nargs-1];
  2304 								cpx2 = cpx; cpy2 = cpy;
  2305 							}
  2306 							break;
  2307 					}
  2308 					nargs = 0;
  2309 				}
  2310 			} else {
  2311 				cmd = item[0];
  2312 				rargs = nsvg__getArgsPerElement(cmd);
  2313 				if (cmd == 'M' || cmd == 'm') {
  2314 					// Commit path.
  2315 					if (p->npts > 0)
  2316 						nsvg__addPath(p, closedFlag);
  2317 					// Start new subpath.
  2318 					nsvg__resetPath(p);
  2319 					closedFlag = 0;
  2320 					nargs = 0;
  2321 				} else if (cmd == 'Z' || cmd == 'z') {
  2322 					closedFlag = 1;
  2323 					// Commit path.
  2324 					if (p->npts > 0) {
  2325 						// Move current point to first point
  2326 						cpx = p->pts[0];
  2327 						cpy = p->pts[1];
  2328 						cpx2 = cpx; cpy2 = cpy;
  2329 						nsvg__addPath(p, closedFlag);
  2330 					}
  2331 					// Start new subpath.
  2332 					nsvg__resetPath(p);
  2333 					nsvg__moveTo(p, cpx, cpy);
  2334 					closedFlag = 0;
  2335 					nargs = 0;
  2336 				}
  2337 			}
  2338 		}
  2339 		// Commit path.
  2340 		if (p->npts)
  2341 			nsvg__addPath(p, closedFlag);
  2342 	}
  2343 
  2344 	nsvg__addShape(p);
  2345 }
  2346 
  2347 static void nsvg__parseRect(NSVGparser* p, const char** attr)
  2348 {
  2349 	float x = 0.0f;
  2350 	float y = 0.0f;
  2351 	float w = 0.0f;
  2352 	float h = 0.0f;
  2353 	float rx = -1.0f; // marks not set
  2354 	float ry = -1.0f;
  2355 	int i;
  2356 
  2357 	for (i = 0; attr[i]; i += 2) {
  2358 		if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
  2359 			if (strcmp(attr[i], "x") == 0) x = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p));
  2360 			if (strcmp(attr[i], "y") == 0) y = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p));
  2361 			if (strcmp(attr[i], "width") == 0) w = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p));
  2362 			if (strcmp(attr[i], "height") == 0) h = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p));
  2363 			if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p)));
  2364 			if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p)));
  2365 		}
  2366 	}
  2367 
  2368 	if (rx < 0.0f && ry > 0.0f) rx = ry;
  2369 	if (ry < 0.0f && rx > 0.0f) ry = rx;
  2370 	if (rx < 0.0f) rx = 0.0f;
  2371 	if (ry < 0.0f) ry = 0.0f;
  2372 	if (rx > w/2.0f) rx = w/2.0f;
  2373 	if (ry > h/2.0f) ry = h/2.0f;
  2374 
  2375 	if (w != 0.0f && h != 0.0f) {
  2376 		nsvg__resetPath(p);
  2377 
  2378 		if (rx < 0.00001f || ry < 0.0001f) {
  2379 			nsvg__moveTo(p, x, y);
  2380 			nsvg__lineTo(p, x+w, y);
  2381 			nsvg__lineTo(p, x+w, y+h);
  2382 			nsvg__lineTo(p, x, y+h);
  2383 		} else {
  2384 			// Rounded rectangle
  2385 			nsvg__moveTo(p, x+rx, y);
  2386 			nsvg__lineTo(p, x+w-rx, y);
  2387 			nsvg__cubicBezTo(p, x+w-rx*(1-NSVG_KAPPA90), y, x+w, y+ry*(1-NSVG_KAPPA90), x+w, y+ry);
  2388 			nsvg__lineTo(p, x+w, y+h-ry);
  2389 			nsvg__cubicBezTo(p, x+w, y+h-ry*(1-NSVG_KAPPA90), x+w-rx*(1-NSVG_KAPPA90), y+h, x+w-rx, y+h);
  2390 			nsvg__lineTo(p, x+rx, y+h);
  2391 			nsvg__cubicBezTo(p, x+rx*(1-NSVG_KAPPA90), y+h, x, y+h-ry*(1-NSVG_KAPPA90), x, y+h-ry);
  2392 			nsvg__lineTo(p, x, y+ry);
  2393 			nsvg__cubicBezTo(p, x, y+ry*(1-NSVG_KAPPA90), x+rx*(1-NSVG_KAPPA90), y, x+rx, y);
  2394 		}
  2395 
  2396 		nsvg__addPath(p, 1);
  2397 
  2398 		nsvg__addShape(p);
  2399 	}
  2400 }
  2401 
  2402 static void nsvg__parseCircle(NSVGparser* p, const char** attr)
  2403 {
  2404 	float cx = 0.0f;
  2405 	float cy = 0.0f;
  2406 	float r = 0.0f;
  2407 	int i;
  2408 
  2409 	for (i = 0; attr[i]; i += 2) {
  2410 		if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
  2411 			if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p));
  2412 			if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p));
  2413 			if (strcmp(attr[i], "r") == 0) r = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualLength(p)));
  2414 		}
  2415 	}
  2416 
  2417 	if (r > 0.0f) {
  2418 		nsvg__resetPath(p);
  2419 
  2420 		nsvg__moveTo(p, cx+r, cy);
  2421 		nsvg__cubicBezTo(p, cx+r, cy+r*NSVG_KAPPA90, cx+r*NSVG_KAPPA90, cy+r, cx, cy+r);
  2422 		nsvg__cubicBezTo(p, cx-r*NSVG_KAPPA90, cy+r, cx-r, cy+r*NSVG_KAPPA90, cx-r, cy);
  2423 		nsvg__cubicBezTo(p, cx-r, cy-r*NSVG_KAPPA90, cx-r*NSVG_KAPPA90, cy-r, cx, cy-r);
  2424 		nsvg__cubicBezTo(p, cx+r*NSVG_KAPPA90, cy-r, cx+r, cy-r*NSVG_KAPPA90, cx+r, cy);
  2425 
  2426 		nsvg__addPath(p, 1);
  2427 
  2428 		nsvg__addShape(p);
  2429 	}
  2430 }
  2431 
  2432 static void nsvg__parseEllipse(NSVGparser* p, const char** attr)
  2433 {
  2434 	float cx = 0.0f;
  2435 	float cy = 0.0f;
  2436 	float rx = 0.0f;
  2437 	float ry = 0.0f;
  2438 	int i;
  2439 
  2440 	for (i = 0; attr[i]; i += 2) {
  2441 		if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
  2442 			if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p));
  2443 			if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p));
  2444 			if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p)));
  2445 			if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p)));
  2446 		}
  2447 	}
  2448 
  2449 	if (rx > 0.0f && ry > 0.0f) {
  2450 
  2451 		nsvg__resetPath(p);
  2452 
  2453 		nsvg__moveTo(p, cx+rx, cy);
  2454 		nsvg__cubicBezTo(p, cx+rx, cy+ry*NSVG_KAPPA90, cx+rx*NSVG_KAPPA90, cy+ry, cx, cy+ry);
  2455 		nsvg__cubicBezTo(p, cx-rx*NSVG_KAPPA90, cy+ry, cx-rx, cy+ry*NSVG_KAPPA90, cx-rx, cy);
  2456 		nsvg__cubicBezTo(p, cx-rx, cy-ry*NSVG_KAPPA90, cx-rx*NSVG_KAPPA90, cy-ry, cx, cy-ry);
  2457 		nsvg__cubicBezTo(p, cx+rx*NSVG_KAPPA90, cy-ry, cx+rx, cy-ry*NSVG_KAPPA90, cx+rx, cy);
  2458 
  2459 		nsvg__addPath(p, 1);
  2460 
  2461 		nsvg__addShape(p);
  2462 	}
  2463 }
  2464 
  2465 static void nsvg__parseLine(NSVGparser* p, const char** attr)
  2466 {
  2467 	float x1 = 0.0;
  2468 	float y1 = 0.0;
  2469 	float x2 = 0.0;
  2470 	float y2 = 0.0;
  2471 	int i;
  2472 
  2473 	for (i = 0; attr[i]; i += 2) {
  2474 		if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
  2475 			if (strcmp(attr[i], "x1") == 0) x1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p));
  2476 			if (strcmp(attr[i], "y1") == 0) y1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p));
  2477 			if (strcmp(attr[i], "x2") == 0) x2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p));
  2478 			if (strcmp(attr[i], "y2") == 0) y2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p));
  2479 		}
  2480 	}
  2481 
  2482 	nsvg__resetPath(p);
  2483 
  2484 	nsvg__moveTo(p, x1, y1);
  2485 	nsvg__lineTo(p, x2, y2);
  2486 
  2487 	nsvg__addPath(p, 0);
  2488 
  2489 	nsvg__addShape(p);
  2490 }
  2491 
  2492 static void nsvg__parsePoly(NSVGparser* p, const char** attr, int closeFlag)
  2493 {
  2494 	int i;
  2495 	const char* s;
  2496 	float args[2];
  2497 	int nargs, npts = 0;
  2498 	char item[64];
  2499 
  2500 	nsvg__resetPath(p);
  2501 
  2502 	for (i = 0; attr[i]; i += 2) {
  2503 		if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
  2504 			if (strcmp(attr[i], "points") == 0) {
  2505 				s = attr[i + 1];
  2506 				nargs = 0;
  2507 				while (*s) {
  2508 					s = nsvg__getNextPathItem(s, item);
  2509 					args[nargs++] = (float)nsvg__atof(item);
  2510 					if (nargs >= 2) {
  2511 						if (npts == 0)
  2512 							nsvg__moveTo(p, args[0], args[1]);
  2513 						else
  2514 							nsvg__lineTo(p, args[0], args[1]);
  2515 						nargs = 0;
  2516 						npts++;
  2517 					}
  2518 				}
  2519 			}
  2520 		}
  2521 	}
  2522 
  2523 	nsvg__addPath(p, (char)closeFlag);
  2524 
  2525 	nsvg__addShape(p);
  2526 }
  2527 
  2528 static void nsvg__parseSVG(NSVGparser* p, const char** attr)
  2529 {
  2530 	int i;
  2531 	for (i = 0; attr[i]; i += 2) {
  2532 		if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
  2533 			if (strcmp(attr[i], "width") == 0) {
  2534 				p->image->width = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 1.0f);
  2535 			} else if (strcmp(attr[i], "height") == 0) {
  2536 				p->image->height = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 1.0f);
  2537 			} else if (strcmp(attr[i], "viewBox") == 0) {
  2538 				sscanf(attr[i + 1], "%f%*[%%, \t]%f%*[%%, \t]%f%*[%%, \t]%f", &p->viewMinx, &p->viewMiny, &p->viewWidth, &p->viewHeight);
  2539 			} else if (strcmp(attr[i], "preserveAspectRatio") == 0) {
  2540 				if (strstr(attr[i + 1], "none") != 0) {
  2541 					// No uniform scaling
  2542 					p->alignType = NSVG_ALIGN_NONE;
  2543 				} else {
  2544 					// Parse X align
  2545 					if (strstr(attr[i + 1], "xMin") != 0)
  2546 						p->alignX = NSVG_ALIGN_MIN;
  2547 					else if (strstr(attr[i + 1], "xMid") != 0)
  2548 						p->alignX = NSVG_ALIGN_MID;
  2549 					else if (strstr(attr[i + 1], "xMax") != 0)
  2550 						p->alignX = NSVG_ALIGN_MAX;
  2551 					// Parse X align
  2552 					if (strstr(attr[i + 1], "yMin") != 0)
  2553 						p->alignY = NSVG_ALIGN_MIN;
  2554 					else if (strstr(attr[i + 1], "yMid") != 0)
  2555 						p->alignY = NSVG_ALIGN_MID;
  2556 					else if (strstr(attr[i + 1], "yMax") != 0)
  2557 						p->alignY = NSVG_ALIGN_MAX;
  2558 					// Parse meet/slice
  2559 					p->alignType = NSVG_ALIGN_MEET;
  2560 					if (strstr(attr[i + 1], "slice") != 0)
  2561 						p->alignType = NSVG_ALIGN_SLICE;
  2562 				}
  2563 			}
  2564 		}
  2565 	}
  2566 }
  2567 
  2568 static void nsvg__parseGradient(NSVGparser* p, const char** attr, char type)
  2569 {
  2570 	int i;
  2571 	NSVGgradientData* grad = (NSVGgradientData*)malloc(sizeof(NSVGgradientData));
  2572 	if (grad == NULL) return;
  2573 	memset(grad, 0, sizeof(NSVGgradientData));
  2574 	grad->units = NSVG_OBJECT_SPACE;
  2575 	grad->type = type;
  2576 	if (grad->type == NSVG_PAINT_LINEAR_GRADIENT) {
  2577 		grad->linear.x1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT);
  2578 		grad->linear.y1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT);
  2579 		grad->linear.x2 = nsvg__coord(100.0f, NSVG_UNITS_PERCENT);
  2580 		grad->linear.y2 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT);
  2581 	} else if (grad->type == NSVG_PAINT_RADIAL_GRADIENT) {
  2582 		grad->radial.cx = nsvg__coord(50.0f, NSVG_UNITS_PERCENT);
  2583 		grad->radial.cy = nsvg__coord(50.0f, NSVG_UNITS_PERCENT);
  2584 		grad->radial.r = nsvg__coord(50.0f, NSVG_UNITS_PERCENT);
  2585 	}
  2586 
  2587 	nsvg__xformIdentity(grad->xform);
  2588 
  2589 	for (i = 0; attr[i]; i += 2) {
  2590 		if (strcmp(attr[i], "id") == 0) {
  2591 			strncpy(grad->id, attr[i+1], 63);
  2592 			grad->id[63] = '\0';
  2593 		} else if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
  2594 			if (strcmp(attr[i], "gradientUnits") == 0) {
  2595 				if (strcmp(attr[i+1], "objectBoundingBox") == 0)
  2596 					grad->units = NSVG_OBJECT_SPACE;
  2597 				else
  2598 					grad->units = NSVG_USER_SPACE;
  2599 			} else if (strcmp(attr[i], "gradientTransform") == 0) {
  2600 				nsvg__parseTransform(grad->xform, attr[i + 1]);
  2601 			} else if (strcmp(attr[i], "cx") == 0) {
  2602 				grad->radial.cx = nsvg__parseCoordinateRaw(attr[i + 1]);
  2603 			} else if (strcmp(attr[i], "cy") == 0) {
  2604 				grad->radial.cy = nsvg__parseCoordinateRaw(attr[i + 1]);
  2605 			} else if (strcmp(attr[i], "r") == 0) {
  2606 				grad->radial.r = nsvg__parseCoordinateRaw(attr[i + 1]);
  2607 			} else if (strcmp(attr[i], "fx") == 0) {
  2608 				grad->radial.fx = nsvg__parseCoordinateRaw(attr[i + 1]);
  2609 			} else if (strcmp(attr[i], "fy") == 0) {
  2610 				grad->radial.fy = nsvg__parseCoordinateRaw(attr[i + 1]);
  2611 			} else if (strcmp(attr[i], "x1") == 0) {
  2612 				grad->linear.x1 = nsvg__parseCoordinateRaw(attr[i + 1]);
  2613 			} else if (strcmp(attr[i], "y1") == 0) {
  2614 				grad->linear.y1 = nsvg__parseCoordinateRaw(attr[i + 1]);
  2615 			} else if (strcmp(attr[i], "x2") == 0) {
  2616 				grad->linear.x2 = nsvg__parseCoordinateRaw(attr[i + 1]);
  2617 			} else if (strcmp(attr[i], "y2") == 0) {
  2618 				grad->linear.y2 = nsvg__parseCoordinateRaw(attr[i + 1]);
  2619 			} else if (strcmp(attr[i], "spreadMethod") == 0) {
  2620 				if (strcmp(attr[i+1], "pad") == 0)
  2621 					grad->spread = NSVG_SPREAD_PAD;
  2622 				else if (strcmp(attr[i+1], "reflect") == 0)
  2623 					grad->spread = NSVG_SPREAD_REFLECT;
  2624 				else if (strcmp(attr[i+1], "repeat") == 0)
  2625 					grad->spread = NSVG_SPREAD_REPEAT;
  2626 			} else if (strcmp(attr[i], "xlink:href") == 0) {
  2627 				const char *href = attr[i+1];
  2628 				strncpy(grad->ref, href+1, 62);
  2629 				grad->ref[62] = '\0';
  2630 			}
  2631 		}
  2632 	}
  2633 
  2634 	grad->next = p->gradients;
  2635 	p->gradients = grad;
  2636 }
  2637 
  2638 static void nsvg__parseGradientStop(NSVGparser* p, const char** attr)
  2639 {
  2640 	NSVGattrib* curAttr = nsvg__getAttr(p);
  2641 	NSVGgradientData* grad;
  2642 	NSVGgradientStop* stop;
  2643 	int i, idx;
  2644 
  2645 	curAttr->stopOffset = 0;
  2646 	curAttr->stopColor = 0;
  2647 	curAttr->stopOpacity = 1.0f;
  2648 
  2649 	for (i = 0; attr[i]; i += 2) {
  2650 		nsvg__parseAttr(p, attr[i], attr[i + 1]);
  2651 	}
  2652 
  2653 	// Add stop to the last gradient.
  2654 	grad = p->gradients;
  2655 	if (grad == NULL) return;
  2656 
  2657 	grad->nstops++;
  2658 	grad->stops = (NSVGgradientStop*)realloc(grad->stops, sizeof(NSVGgradientStop)*grad->nstops);
  2659 	if (grad->stops == NULL) return;
  2660 
  2661 	// Insert
  2662 	idx = grad->nstops-1;
  2663 	for (i = 0; i < grad->nstops-1; i++) {
  2664 		if (curAttr->stopOffset < grad->stops[i].offset) {
  2665 			idx = i;
  2666 			break;
  2667 		}
  2668 	}
  2669 	if (idx != grad->nstops-1) {
  2670 		for (i = grad->nstops-1; i > idx; i--)
  2671 			grad->stops[i] = grad->stops[i-1];
  2672 	}
  2673 
  2674 	stop = &grad->stops[idx];
  2675 	stop->color = curAttr->stopColor;
  2676 	stop->color |= (unsigned int)(curAttr->stopOpacity*255) << 24;
  2677 	stop->offset = curAttr->stopOffset;
  2678 }
  2679 
  2680 static void nsvg__startElement(void* ud, const char* el, const char** attr)
  2681 {
  2682 	NSVGparser* p = (NSVGparser*)ud;
  2683 
  2684 	if (p->defsFlag) {
  2685 		// Skip everything but gradients in defs
  2686 		if (strcmp(el, "linearGradient") == 0) {
  2687 			nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT);
  2688 		} else if (strcmp(el, "radialGradient") == 0) {
  2689 			nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT);
  2690 		} else if (strcmp(el, "stop") == 0) {
  2691 			nsvg__parseGradientStop(p, attr);
  2692 		}
  2693 		return;
  2694 	}
  2695 
  2696 	if (strcmp(el, "g") == 0) {
  2697 		nsvg__pushAttr(p);
  2698 		nsvg__parseAttribs(p, attr);
  2699 	} else if (strcmp(el, "path") == 0) {
  2700 		if (p->pathFlag)	// Do not allow nested paths.
  2701 			return;
  2702 		nsvg__pushAttr(p);
  2703 		nsvg__parsePath(p, attr);
  2704 		nsvg__popAttr(p);
  2705 	} else if (strcmp(el, "rect") == 0) {
  2706 		nsvg__pushAttr(p);
  2707 		nsvg__parseRect(p, attr);
  2708 		nsvg__popAttr(p);
  2709 	} else if (strcmp(el, "circle") == 0) {
  2710 		nsvg__pushAttr(p);
  2711 		nsvg__parseCircle(p, attr);
  2712 		nsvg__popAttr(p);
  2713 	} else if (strcmp(el, "ellipse") == 0) {
  2714 		nsvg__pushAttr(p);
  2715 		nsvg__parseEllipse(p, attr);
  2716 		nsvg__popAttr(p);
  2717 	} else if (strcmp(el, "line") == 0)  {
  2718 		nsvg__pushAttr(p);
  2719 		nsvg__parseLine(p, attr);
  2720 		nsvg__popAttr(p);
  2721 	} else if (strcmp(el, "polyline") == 0)  {
  2722 		nsvg__pushAttr(p);
  2723 		nsvg__parsePoly(p, attr, 0);
  2724 		nsvg__popAttr(p);
  2725 	} else if (strcmp(el, "polygon") == 0)  {
  2726 		nsvg__pushAttr(p);
  2727 		nsvg__parsePoly(p, attr, 1);
  2728 		nsvg__popAttr(p);
  2729 	} else  if (strcmp(el, "linearGradient") == 0) {
  2730 		nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT);
  2731 	} else if (strcmp(el, "radialGradient") == 0) {
  2732 		nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT);
  2733 	} else if (strcmp(el, "stop") == 0) {
  2734 		nsvg__parseGradientStop(p, attr);
  2735 	} else if (strcmp(el, "defs") == 0) {
  2736 		p->defsFlag = 1;
  2737 	} else if (strcmp(el, "svg") == 0) {
  2738 		nsvg__parseSVG(p, attr);
  2739 	} else if (strcmp(el, "style") == 0) {
  2740 		p->styleFlag = 1;
  2741 	}
  2742 }
  2743 
  2744 static void nsvg__endElement(void* ud, const char* el)
  2745 {
  2746 	NSVGparser* p = (NSVGparser*)ud;
  2747 
  2748 	if (strcmp(el, "g") == 0) {
  2749 		nsvg__popAttr(p);
  2750 	} else if (strcmp(el, "path") == 0) {
  2751 		p->pathFlag = 0;
  2752 	} else if (strcmp(el, "defs") == 0) {
  2753 		p->defsFlag = 0;
  2754 	} else if (strcmp(el, "style") == 0) {
  2755 		p->styleFlag = 0;
  2756 	}
  2757 }
  2758 
  2759 static char *nsvg__strndup(const char *s, size_t n)
  2760 {
  2761 	char *result;
  2762 	size_t len = strlen(s);
  2763 
  2764 	if (n < len)
  2765 		len = n;
  2766 
  2767 	result = (char *)malloc(len + 1);
  2768 	if (!result)
  2769 		return 0;
  2770 
  2771 	result[len] = '\0';
  2772 	return (char *)memcpy(result, s, len);
  2773 }
  2774 
  2775 static void nsvg__content(void* ud, const char* s)
  2776 {
  2777 	NSVGparser* p = (NSVGparser*)ud;
  2778 	if (p->styleFlag) {
  2779 
  2780 		int state = 0;
  2781 		const char* start;		
  2782 		while (*s) {
  2783 			char c = *s;
  2784 			if (nsvg__isspace(c) || c == '{') {
  2785 				if (state == 1) {
  2786 					NSVGstyles* next = p->styles;
  2787 
  2788 					p->styles = (NSVGstyles*)malloc(sizeof(NSVGstyles));
  2789 					p->styles->next = next;
  2790 					p->styles->name = nsvg__strndup(start, (size_t)(s - start));
  2791 					start = s + 1;
  2792 					state = 2;
  2793 				}				
  2794 			} else if (state == 2 && c == '}') {
  2795 				p->styles->description = nsvg__strndup(start, (size_t)(s - start));
  2796 				state = 0;
  2797 			}
  2798 			else if (state == 0) {
  2799 				start = s;
  2800 				state = 1;
  2801 			}  
  2802 			s++;
  2803 		}
  2804 		//	if (*s == '{' && state == NSVG_XML_CONTENT) {
  2805 		//		// Start of a tag
  2806 		//		*s++ = '\0';
  2807 		//		nsvg__parseContent(mark, contentCb, ud);
  2808 		//		mark = s;
  2809 		//		state = NSVG_XML_TAG;
  2810 		//	}
  2811 		//	else if (*s == '>' && state == NSVG_XML_TAG) {
  2812 		//		// Start of a content or new tag.
  2813 		//		*s++ = '\0';
  2814 		//		nsvg__parseElement(mark, startelCb, endelCb, ud);
  2815 		//		mark = s;
  2816 		//		state = NSVG_XML_CONTENT;
  2817 		//	}
  2818 		//	else {
  2819 		//		s++;
  2820 		//	}
  2821 		//}
  2822 
  2823 	}
  2824 	// empty
  2825 }
  2826 
  2827 static void nsvg__imageBounds(NSVGparser* p, float* bounds)
  2828 {
  2829 	NSVGshape* shape;
  2830 	int count = 0;
  2831 	shape = p->image->shapes;
  2832 
  2833 	bounds[0] = FLT_MAX;
  2834 	bounds[1] = FLT_MAX;
  2835 	bounds[2] = -FLT_MAX;
  2836 	bounds[3] = -FLT_MAX;
  2837 
  2838 	for (; shape != NULL; shape = shape->next) {
  2839 		if ( (shape->flags & NSVG_FLAGS_VISIBLE) == NSVG_FLAGS_VISIBLE) {
  2840 			bounds[0] = nsvg__minf(bounds[0], shape->bounds[0]);
  2841 			bounds[1] = nsvg__minf(bounds[1], shape->bounds[1]);
  2842 			bounds[2] = nsvg__maxf(bounds[2], shape->bounds[2]);
  2843 			bounds[3] = nsvg__maxf(bounds[3], shape->bounds[3]);
  2844 			++count;
  2845 		}
  2846 	}
  2847 
  2848 	if (count == 0) {
  2849 		bounds[0] = bounds[1] = bounds[2] = bounds[3] = 0.0;
  2850 	}
  2851 }
  2852 
  2853 static float nsvg__viewAlign(float content, float container, int type)
  2854 {
  2855 	if (type == NSVG_ALIGN_MIN)
  2856 		return 0;
  2857 	else if (type == NSVG_ALIGN_MAX)
  2858 		return container - content;
  2859 	// mid
  2860 	return (container - content) * 0.5f;
  2861 }
  2862 
  2863 static void nsvg__scaleGradient(NSVGgradient* grad, float tx, float ty, float sx, float sy)
  2864 {
  2865 	float t[6];
  2866 	nsvg__xformSetTranslation(t, tx, ty);
  2867 	nsvg__xformMultiply (grad->xform, t);
  2868 
  2869 	nsvg__xformSetScale(t, sx, sy);
  2870 	nsvg__xformMultiply (grad->xform, t);
  2871 }
  2872 
  2873 static void nsvg__scaleToViewbox(NSVGparser* p, const char* units)
  2874 {
  2875 	NSVGshape* shape;
  2876 	NSVGpath* path;
  2877 	float tx, ty, sx, sy, us, bounds[4], t[6], avgs;
  2878 	int i;
  2879 	float* pt;
  2880 
  2881 	// Guess image size if not set completely.
  2882 	nsvg__imageBounds(p, bounds);
  2883 
  2884 	if (p->viewWidth == 0) {
  2885 		if (p->image->width > 0) {
  2886 			p->viewWidth = p->image->width;
  2887 		} else {
  2888 			p->viewMinx = bounds[0];
  2889 			p->viewWidth = bounds[2] - bounds[0];
  2890 		}
  2891 	}
  2892 	if (p->viewHeight == 0) {
  2893 		if (p->image->height > 0) {
  2894 			p->viewHeight = p->image->height;
  2895 		} else {
  2896 			p->viewMiny = bounds[1];
  2897 			p->viewHeight = bounds[3] - bounds[1];
  2898 		}
  2899 	}
  2900 	if (p->image->width == 0)
  2901 		p->image->width = p->viewWidth;
  2902 	if (p->image->height == 0)
  2903 		p->image->height = p->viewHeight;
  2904 
  2905 	tx = -p->viewMinx;
  2906 	ty = -p->viewMiny;
  2907 	sx = p->viewWidth > 0 ? p->image->width / p->viewWidth : 0;
  2908 	sy = p->viewHeight > 0 ? p->image->height / p->viewHeight : 0;
  2909 	// Unit scaling
  2910 	us = 1.0f / nsvg__convertToPixels(p, nsvg__coord(1.0f, nsvg__parseUnits(units)), 0.0f, 1.0f);
  2911 
  2912 	// Fix aspect ratio
  2913 	if (p->alignType == NSVG_ALIGN_MEET) {
  2914 		// fit whole image into viewbox
  2915 		sx = sy = nsvg__minf(sx, sy);
  2916 		tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx;
  2917 		ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy;
  2918 	} else if (p->alignType == NSVG_ALIGN_SLICE) {
  2919 		// fill whole viewbox with image
  2920 		sx = sy = nsvg__maxf(sx, sy);
  2921 		tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx;
  2922 		ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy;
  2923 	}
  2924 
  2925 	// Transform
  2926 	sx *= us;
  2927 	sy *= us;
  2928 	avgs = (sx+sy) / 2.0f;
  2929 	for (shape = p->image->shapes; shape != NULL; shape = shape->next) {
  2930 		shape->bounds[0] = (shape->bounds[0] + tx) * sx;
  2931 		shape->bounds[1] = (shape->bounds[1] + ty) * sy;
  2932 		shape->bounds[2] = (shape->bounds[2] + tx) * sx;
  2933 		shape->bounds[3] = (shape->bounds[3] + ty) * sy;
  2934 		for (path = shape->paths; path != NULL; path = path->next) {
  2935 			path->bounds[0] = (path->bounds[0] + tx) * sx;
  2936 			path->bounds[1] = (path->bounds[1] + ty) * sy;
  2937 			path->bounds[2] = (path->bounds[2] + tx) * sx;
  2938 			path->bounds[3] = (path->bounds[3] + ty) * sy;
  2939 			for (i =0; i < path->npts; i++) {
  2940 				pt = &path->pts[i*2];
  2941 				pt[0] = (pt[0] + tx) * sx;
  2942 				pt[1] = (pt[1] + ty) * sy;
  2943 			}
  2944 		}
  2945 
  2946 		if (shape->fill.type == NSVG_PAINT_LINEAR_GRADIENT || shape->fill.type == NSVG_PAINT_RADIAL_GRADIENT) {
  2947 			nsvg__scaleGradient(shape->fill.gradient, tx,ty, sx,sy);
  2948 			memcpy(t, shape->fill.gradient->xform, sizeof(float)*6);
  2949 			nsvg__xformInverse(shape->fill.gradient->xform, t);
  2950 		}
  2951 		if (shape->stroke.type == NSVG_PAINT_LINEAR_GRADIENT || shape->stroke.type == NSVG_PAINT_RADIAL_GRADIENT) {
  2952 			nsvg__scaleGradient(shape->stroke.gradient, tx,ty, sx,sy);
  2953 			memcpy(t, shape->stroke.gradient->xform, sizeof(float)*6);
  2954 			nsvg__xformInverse(shape->stroke.gradient->xform, t);
  2955 		}
  2956 
  2957 		shape->strokeWidth *= avgs;
  2958 		shape->strokeDashOffset *= avgs;
  2959 		for (i = 0; i < shape->strokeDashCount; i++)
  2960 			shape->strokeDashArray[i] *= avgs;
  2961 	}
  2962 }
  2963 
  2964 NSVGimage* nsvgParse(char* input, const char* units, float dpi)
  2965 {
  2966 	NSVGparser* p;
  2967 	NSVGimage* ret = 0;
  2968 
  2969 	p = nsvg__createParser();
  2970 	if (p == NULL) {
  2971 		return NULL;
  2972 	}
  2973 	p->dpi = dpi;
  2974 
  2975 	nsvg__parseXML(input, nsvg__startElement, nsvg__endElement, nsvg__content, p);
  2976 
  2977 	// Scale to viewBox
  2978 	nsvg__scaleToViewbox(p, units);
  2979 
  2980 	ret = p->image;
  2981 	p->image = NULL;
  2982 
  2983 	nsvg__deleteParser(p);
  2984 
  2985 	return ret;
  2986 }
  2987 
  2988 #ifdef HAVE_STDIO_H
  2989 NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi)
  2990 {
  2991 	FILE* fp = NULL;
  2992 	size_t size;
  2993 	char* data = NULL;
  2994 	NSVGimage* image = NULL;
  2995 
  2996 	fp = fopen(filename, "rb");
  2997 	if (!fp) goto error;
  2998 	fseek(fp, 0, SEEK_END);
  2999 	size = ftell(fp);
  3000 	fseek(fp, 0, SEEK_SET);
  3001 	data = (char*)malloc(size+1);
  3002 	if (data == NULL) goto error;
  3003 	if (fread(data, 1, size, fp) != size) goto error;
  3004 	data[size] = '\0';	// Must be null terminated.
  3005 	fclose(fp);
  3006 	image = nsvgParse(data, units, dpi);
  3007 	free(data);
  3008 
  3009 	return image;
  3010 
  3011 error:
  3012 	if (fp) fclose(fp);
  3013 	if (data) free(data);
  3014 	if (image) nsvgDelete(image);
  3015 	return NULL;
  3016 }
  3017 #endif /* HAVE_STDIO_H */
  3018 
  3019 void nsvgDelete(NSVGimage* image)
  3020 {
  3021 	NSVGshape *snext, *shape;
  3022 	if (image == NULL) return;
  3023 	shape = image->shapes;
  3024 	while (shape != NULL) {
  3025 		snext = shape->next;
  3026 		nsvg__deletePaths(shape->paths);
  3027 		nsvg__deletePaint(&shape->fill);
  3028 		nsvg__deletePaint(&shape->stroke);
  3029 		free(shape);
  3030 		shape = snext;
  3031 	}
  3032 	free(image);
  3033 }
  3034 
  3035 #endif