KiCad PCB EDA Suite
nanosvg.cpp
Go to the documentation of this file.
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 #include "nanosvg.h"
30 
31 #include <string.h>
32 #include <stdlib.h>
33 #include <math.h>
34 
35 #define NSVG_PI (3.14159265358979323846264338327f)
36 #define NSVG_KAPPA90 (0.5522847493f) // Length proportional to radius of a cubic bezier handle for 90deg arcs.
37 
38 #define NSVG_ALIGN_MIN 0
39 #define NSVG_ALIGN_MID 1
40 #define NSVG_ALIGN_MAX 2
41 #define NSVG_ALIGN_NONE 0
42 #define NSVG_ALIGN_MEET 1
43 #define NSVG_ALIGN_SLICE 2
44 
45 #define NSVG_NOTUSED( v ) do { (void) ( 1 ? (void) 0 : ( (void) (v) ) ); } \
46  while( 0 )
47 #define NSVG_RGB( r, g, \
48  b ) ( ( (unsigned int) r ) | ( (unsigned int) g << 8 ) | \
49  ( (unsigned int) b << 16 ) )
50 
51 #ifdef _MSC_VER
52  #pragma warning (disable: 4996) // Switch off security warnings
53  #pragma warning (disable: 4100) // Switch off unreferenced formal parameter warnings
54  #ifdef __cplusplus
55  #define NSVG_INLINE inline
56  #else
57  #define NSVG_INLINE
58  #endif
59 #else
60  #define NSVG_INLINE inline
61 #endif
62 
63 
64 static int nsvg__isspace( char c )
65 {
66  return strchr( " \t\n\v\f\r", c ) != 0;
67 }
68 
69 
70 static int nsvg__isdigit( char c )
71 {
72  return c >= '0' && c <= '9';
73 }
74 
75 
76 static int nsvg__isnum( char c )
77 {
78  return strchr( "0123456789+-.eE", c ) != 0;
79 }
80 
81 
82 static NSVG_INLINE float nsvg__minf( float a, float b )
83 {
84  return a < b ? a : b;
85 }
86 
87 
88 static NSVG_INLINE float nsvg__maxf( float a, float b )
89 {
90  return a > b ? a : b;
91 }
92 
93 
94 // Simple XML parser
95 
96 #define NSVG_XML_TAG 1
97 #define NSVG_XML_CONTENT 2
98 #define NSVG_XML_MAX_ATTRIBS 256
99 
100 static void nsvg__parseContent( char* s,
101  void (* contentCb)( void* ud, const char* s ),
102  void* ud )
103 {
104  // Trim start white spaces
105  while( *s && nsvg__isspace( *s ) )
106  s++;
107 
108  if( !*s )
109  return;
110 
111  if( contentCb )
112  (*contentCb)( ud, s );
113 }
114 
115 
116 static void nsvg__parseElement( char* s,
117  void (* startelCb)( void* ud, const char* el, const char** attr ),
118  void (* endelCb)( void* ud, const char* el ),
119  void* ud )
120 {
121  const char* attr[NSVG_XML_MAX_ATTRIBS];
122  int nattr = 0;
123  char* e_name;
124  int start = 0;
125  int end = 0;
126  char quote;
127 
128  // Skip white space after the '<'
129  while( *s && nsvg__isspace( *s ) )
130  s++;
131 
132  // Check if the tag is end tag
133  if( *s == '/' )
134  {
135  s++;
136  end = 1;
137  }
138  else
139  {
140  start = 1;
141  }
142 
143  // Skip comments, data and preprocessor stuff.
144  if( !*s || *s == '?' || *s == '!' )
145  return;
146 
147  // Get tag name
148  e_name = s;
149 
150  while( *s && !nsvg__isspace( *s ) )
151  s++;
152 
153  if( *s )
154  {
155  *s++ = '\0';
156  }
157 
158  // Get attribs
159  while( !end && *s && nattr < NSVG_XML_MAX_ATTRIBS - 3 )
160  {
161  char* name = NULL;
162  char* value = NULL;
163 
164  // Skip white space before the attrib name
165  while( *s && nsvg__isspace( *s ) )
166  s++;
167 
168  if( !*s )
169  break;
170 
171  if( *s == '/' )
172  {
173  end = 1;
174  break;
175  }
176 
177  name = s;
178 
179  // Find end of the attrib name.
180  while( *s && !nsvg__isspace( *s ) && *s != '=' )
181  s++;
182 
183  if( *s )
184  {
185  *s++ = '\0';
186  }
187 
188  // Skip until the beginning of the value.
189  while( *s && *s != '\"' && *s != '\'' )
190  s++;
191 
192  if( !*s )
193  break;
194 
195  quote = *s;
196  s++;
197  // Store value and find the end of it.
198  value = s;
199 
200  while( *s && *s != quote )
201  s++;
202 
203  if( *s )
204  {
205  *s++ = '\0';
206  }
207 
208  // Store only well formed attributes
209  if( name && value )
210  {
211  attr[nattr++] = name;
212  attr[nattr++] = value;
213  }
214  }
215 
216  // List terminator
217  attr[nattr++] = 0;
218  attr[nattr++] = 0;
219 
220  // Call callbacks.
221  if( start && startelCb )
222  (*startelCb)( ud, e_name, attr );
223 
224  if( end && endelCb )
225  (*endelCb)( ud, e_name );
226 }
227 
228 
229 int nsvg__parseXML( char* input,
230  void (* startelCb)( void* ud, const char* el, const char** attr ),
231  void (* endelCb)( void* ud, const char* el ),
232  void (* contentCb)( void* ud, const char* s ),
233  void* ud )
234 {
235  char* s = input;
236  char* mark = s;
237  int state = NSVG_XML_CONTENT;
238 
239  while( *s )
240  {
241  if( *s == '<' && state == NSVG_XML_CONTENT )
242  {
243  // Start of a tag
244  *s++ = '\0';
245  nsvg__parseContent( mark, contentCb, ud );
246  mark = s;
247  state = NSVG_XML_TAG;
248  }
249  else if( *s == '>' && state == NSVG_XML_TAG )
250  {
251  // Start of a content or new tag.
252  *s++ = '\0';
253  nsvg__parseElement( mark, startelCb, endelCb, ud );
254  mark = s;
255  state = NSVG_XML_CONTENT;
256  }
257  else
258  {
259  s++;
260  }
261  }
262 
263  return 1;
264 }
265 
266 
267 /* Simple SVG parser. */
268 
269 #define NSVG_MAX_ATTR 128
270 
272 {
275 };
276 
277 #define NSVG_MAX_DASHES 8
278 
280 {
291 };
292 
293 typedef struct NSVGcoordinate
294 {
295  float value;
296  int units;
298 
299 typedef struct NSVGlinearData
300 {
301  NSVGcoordinate x1, y1, x2, y2;
303 
304 typedef struct NSVGradialData
305 {
306  NSVGcoordinate cx, cy, r, fx, fy;
308 
309 typedef struct NSVGgradientData
310 {
311  char id[64];
312  char ref[64];
313  char type;
314  union
315  {
318  };
319  char spread;
320  char units;
321  float xform[6];
322  int nstops;
326 
327 typedef struct NSVGattrib
328 {
329  char id[64];
330  float xform[6];
331  unsigned int fillColor;
332  unsigned int strokeColor;
333  float opacity;
334  float fillOpacity;
336  char fillGradient[64];
337  char strokeGradient[64];
338  float strokeWidth;
340  float strokeDashArray[NSVG_MAX_DASHES];
344  float miterLimit;
345  char fillRule;
346  float fontSize;
347  unsigned int stopColor;
348  float stopOpacity;
349  float stopOffset;
350  char hasFill;
351  char hasStroke;
352  char visible;
353 } NSVGattrib;
354 
355 typedef struct NSVGparser
356 {
358  int attrHead;
359  float* pts;
360  int npts;
361  int cpts;
366  float viewMinx, viewMiny, viewWidth, viewHeight;
367  int alignX, alignY, alignType;
368  float dpi;
369  char pathFlag;
370  char defsFlag;
371 } NSVGparser;
372 
373 static void nsvg__xformIdentity( float* t )
374 {
375  t[0] = 1.0f; t[1] = 0.0f;
376  t[2] = 0.0f; t[3] = 1.0f;
377  t[4] = 0.0f; t[5] = 0.0f;
378 }
379 
380 
381 static void nsvg__xformSetTranslation( float* t, float tx, float ty )
382 {
383  t[0] = 1.0f; t[1] = 0.0f;
384  t[2] = 0.0f; t[3] = 1.0f;
385  t[4] = tx; t[5] = ty;
386 }
387 
388 
389 static void nsvg__xformSetScale( float* t, float sx, float sy )
390 {
391  t[0] = sx; t[1] = 0.0f;
392  t[2] = 0.0f; t[3] = sy;
393  t[4] = 0.0f; t[5] = 0.0f;
394 }
395 
396 
397 static void nsvg__xformSetSkewX( float* t, float a )
398 {
399  t[0] = 1.0f; t[1] = 0.0f;
400  t[2] = tanf( a ); t[3] = 1.0f;
401  t[4] = 0.0f; t[5] = 0.0f;
402 }
403 
404 
405 static void nsvg__xformSetSkewY( float* t, float a )
406 {
407  t[0] = 1.0f; t[1] = tanf( a );
408  t[2] = 0.0f; t[3] = 1.0f;
409  t[4] = 0.0f; t[5] = 0.0f;
410 }
411 
412 
413 static void nsvg__xformSetRotation( float* t, float a )
414 {
415  float cs = cosf( a ), sn = sinf( a );
416 
417  t[0] = cs; t[1] = sn;
418  t[2] = -sn; t[3] = cs;
419  t[4] = 0.0f; t[5] = 0.0f;
420 }
421 
422 
423 static void nsvg__xformMultiply( float* t, float* s )
424 {
425  float t0 = t[0] * s[0] + t[1] * s[2];
426  float t2 = t[2] * s[0] + t[3] * s[2];
427  float t4 = t[4] * s[0] + t[5] * s[2] + s[4];
428 
429  t[1] = t[0] * s[1] + t[1] * s[3];
430  t[3] = t[2] * s[1] + t[3] * s[3];
431  t[5] = t[4] * s[1] + t[5] * s[3] + s[5];
432  t[0] = t0;
433  t[2] = t2;
434  t[4] = t4;
435 }
436 
437 
438 static void nsvg__xformInverse( float* inv, float* t )
439 {
440  double invdet, det = (double) t[0] * t[3] - (double) t[2] * t[1];
441 
442  if( det > -1e-6 && det < 1e-6 )
443  {
444  nsvg__xformIdentity( t );
445  return;
446  }
447 
448  invdet = 1.0 / det;
449  inv[0] = (float) (t[3] * invdet);
450  inv[2] = (float) (-t[2] * invdet);
451  inv[4] = (float) ( ( (double) t[2] * t[5] - (double) t[3] * t[4] ) * invdet );
452  inv[1] = (float) (-t[1] * invdet);
453  inv[3] = (float) (t[0] * invdet);
454  inv[5] = (float) ( ( (double) t[1] * t[4] - (double) t[0] * t[5] ) * invdet );
455 }
456 
457 
458 static void nsvg__xformPremultiply( float* t, float* s )
459 {
460  float s2[6];
461 
462  memcpy( s2, s, sizeof(float) * 6 );
463  nsvg__xformMultiply( s2, t );
464  memcpy( t, s2, sizeof(float) * 6 );
465 }
466 
467 
468 static void nsvg__xformPoint( float* dx, float* dy, float x, float y, float* t )
469 {
470  *dx = x * t[0] + y * t[2] + t[4];
471  *dy = x * t[1] + y * t[3] + t[5];
472 }
473 
474 
475 static void nsvg__xformVec( float* dx, float* dy, float x, float y, float* t )
476 {
477  *dx = x * t[0] + y * t[2];
478  *dy = x * t[1] + y * t[3];
479 }
480 
481 
482 #define NSVG_EPSILON (1e-12)
483 
484 static int nsvg__ptInBounds( float* pt, float* bounds )
485 {
486  return pt[0] >= bounds[0] && pt[0] <= bounds[2] && pt[1] >= bounds[1] && pt[1] <= bounds[3];
487 }
488 
489 
490 static double nsvg__evalBezier( double t, double p0, double p1, double p2, double p3 )
491 {
492  double it = 1.0 - t;
493 
494  return it * it * it * p0 + 3.0 * it * it * t * p1 + 3.0 * it * t * t * p2 + t * t * t * p3;
495 }
496 
497 
498 static void nsvg__curveBounds( float* bounds, float* curve )
499 {
500  int i, j, count;
501  double roots[2], a, b, c, b2ac, t, v;
502  float* v0 = &curve[0];
503  float* v1 = &curve[2];
504  float* v2 = &curve[4];
505  float* v3 = &curve[6];
506 
507  // Start the bounding box by end points
508  bounds[0] = nsvg__minf( v0[0], v3[0] );
509  bounds[1] = nsvg__minf( v0[1], v3[1] );
510  bounds[2] = nsvg__maxf( v0[0], v3[0] );
511  bounds[3] = nsvg__maxf( v0[1], v3[1] );
512 
513  // Bezier curve fits inside the convex hull of it's control points.
514  // If control points are inside the bounds, we're done.
515  if( nsvg__ptInBounds( v1, bounds ) && nsvg__ptInBounds( v2, bounds ) )
516  return;
517 
518  // Add bezier curve inflection points in X and Y.
519  for( i = 0; i < 2; i++ )
520  {
521  a = -3.0 * v0[i] + 9.0 * v1[i] - 9.0 * v2[i] + 3.0 * v3[i];
522  b = 6.0 * v0[i] - 12.0 * v1[i] + 6.0 * v2[i];
523  c = 3.0 * v1[i] - 3.0 * v0[i];
524  count = 0;
525 
526  if( fabs( a ) < NSVG_EPSILON )
527  {
528  if( fabs( b ) > NSVG_EPSILON )
529  {
530  t = -c / b;
531 
532  if( t > NSVG_EPSILON && t < 1.0 - NSVG_EPSILON )
533  roots[count++] = t;
534  }
535  }
536  else
537  {
538  b2ac = b * b - 4.0 * c * a;
539 
540  if( b2ac > NSVG_EPSILON )
541  {
542  t = ( -b + sqrt( b2ac ) ) / (2.0 * a);
543 
544  if( t > NSVG_EPSILON && t < 1.0 - NSVG_EPSILON )
545  roots[count++] = t;
546 
547  t = ( -b - sqrt( b2ac ) ) / (2.0 * a);
548 
549  if( t > NSVG_EPSILON && t < 1.0 - NSVG_EPSILON )
550  roots[count++] = t;
551  }
552  }
553 
554  for( j = 0; j < count; j++ )
555  {
556  v = nsvg__evalBezier( roots[j], v0[i], v1[i], v2[i], v3[i] );
557  bounds[0 + i] = nsvg__minf( bounds[0 + i], (float) v );
558  bounds[2 + i] = nsvg__maxf( bounds[2 + i], (float) v );
559  }
560  }
561 }
562 
563 
565 {
566  NSVGparser* p;
567 
568  p = (NSVGparser*) malloc( sizeof(NSVGparser) );
569 
570  if( p == NULL )
571  goto error;
572 
573  memset( p, 0, sizeof(NSVGparser) );
574 
575  p->image = (NSVGimage*) malloc( sizeof(NSVGimage) );
576 
577  if( p->image == NULL )
578  goto error;
579 
580  memset( p->image, 0, sizeof(NSVGimage) );
581 
582  // Init style
583  nsvg__xformIdentity( p->attr[0].xform );
584  memset( p->attr[0].id, 0, sizeof p->attr[0].id );
585  p->attr[0].fillColor = NSVG_RGB( 0, 0, 0 );
586  p->attr[0].strokeColor = NSVG_RGB( 0, 0, 0 );
587  p->attr[0].opacity = 1;
588  p->attr[0].fillOpacity = 1;
589  p->attr[0].strokeOpacity = 1;
590  p->attr[0].stopOpacity = 1;
591  p->attr[0].strokeWidth = 1;
594  p->attr[0].miterLimit = 4;
596  p->attr[0].hasFill = 1;
597  p->attr[0].visible = 1;
598 
599  return p;
600 
601 error:
602 
603  if( p )
604  {
605  if( p->image )
606  free( p->image );
607 
608  free( p );
609  }
610 
611  return NULL;
612 }
613 
614 
615 static void nsvg__deletePaths( NSVGpath* path )
616 {
617  while( path )
618  {
619  NSVGpath* next = path->next;
620 
621  if( path->pts != NULL )
622  free( path->pts );
623 
624  free( path );
625  path = next;
626  }
627 }
628 
629 
630 static void nsvg__deletePaint( NSVGpaint* paint )
631 {
633  free( paint->gradient );
634 }
635 
636 
638 {
640 
641  while( grad != NULL )
642  {
643  next = grad->next;
644  free( grad->stops );
645  free( grad );
646  grad = next;
647  }
648 }
649 
650 
652 {
653  if( p != NULL )
654  {
655  nsvg__deletePaths( p->plist );
657  nsvgDelete( p->image );
658  free( p->pts );
659  free( p );
660  }
661 }
662 
663 
664 static void nsvg__resetPath( NSVGparser* p )
665 {
666  p->npts = 0;
667 }
668 
669 
670 static void nsvg__addPoint( NSVGparser* p, float x, float y )
671 {
672  if( p->npts + 1 > p->cpts )
673  {
674  p->cpts = p->cpts ? p->cpts * 2 : 8;
675  p->pts = (float*) realloc( p->pts, p->cpts * 2 * sizeof(float) );
676 
677  if( !p->pts )
678  return;
679  }
680 
681  p->pts[p->npts * 2 + 0] = x;
682  p->pts[p->npts * 2 + 1] = y;
683  p->npts++;
684 }
685 
686 
687 static void nsvg__moveTo( NSVGparser* p, float x, float y )
688 {
689  if( p->npts > 0 )
690  {
691  p->pts[(p->npts - 1) * 2 + 0] = x;
692  p->pts[(p->npts - 1) * 2 + 1] = y;
693  }
694  else
695  {
696  nsvg__addPoint( p, x, y );
697  }
698 }
699 
700 
701 static void nsvg__lineTo( NSVGparser* p, float x, float y )
702 {
703  float px, py, dx, dy;
704 
705  if( p->npts > 0 )
706  {
707  px = p->pts[(p->npts - 1) * 2 + 0];
708  py = p->pts[(p->npts - 1) * 2 + 1];
709  dx = x - px;
710  dy = y - py;
711  nsvg__addPoint( p, px + dx / 3.0f, py + dy / 3.0f );
712  nsvg__addPoint( p, x - dx / 3.0f, y - dy / 3.0f );
713  nsvg__addPoint( p, x, y );
714  }
715 }
716 
717 
718 static void nsvg__cubicBezTo( NSVGparser* p,
719  float cpx1,
720  float cpy1,
721  float cpx2,
722  float cpy2,
723  float x,
724  float y )
725 {
726  nsvg__addPoint( p, cpx1, cpy1 );
727  nsvg__addPoint( p, cpx2, cpy2 );
728  nsvg__addPoint( p, x, y );
729 }
730 
731 
733 {
734  return &p->attr[p->attrHead];
735 }
736 
737 
738 static void nsvg__pushAttr( NSVGparser* p )
739 {
740  if( p->attrHead < NSVG_MAX_ATTR - 1 )
741  {
742  p->attrHead++;
743  memcpy( &p->attr[p->attrHead], &p->attr[p->attrHead - 1], sizeof(NSVGattrib) );
744  }
745 }
746 
747 
748 static void nsvg__popAttr( NSVGparser* p )
749 {
750  if( p->attrHead > 0 )
751  p->attrHead--;
752 }
753 
754 
755 static float nsvg__actualOrigX( NSVGparser* p )
756 {
757  return p->viewMinx;
758 }
759 
760 
761 static float nsvg__actualOrigY( NSVGparser* p )
762 {
763  return p->viewMiny;
764 }
765 
766 
767 static float nsvg__actualWidth( NSVGparser* p )
768 {
769  return p->viewWidth;
770 }
771 
772 
773 static float nsvg__actualHeight( NSVGparser* p )
774 {
775  return p->viewHeight;
776 }
777 
778 
779 static float nsvg__actualLength( NSVGparser* p )
780 {
781  float w = nsvg__actualWidth( p ), h = nsvg__actualHeight( p );
782 
783  return sqrtf( w * w + h * h ) / sqrtf( 2.0f );
784 }
785 
786 
787 static float nsvg__convertToPixels( NSVGparser* p, NSVGcoordinate c, float orig, float length )
788 {
789  NSVGattrib* attr = nsvg__getAttr( p );
790 
791  switch( c.units )
792  {
793  case NSVG_UNITS_USER:
794  return c.value;
795 
796  case NSVG_UNITS_PX:
797  return c.value;
798 
799  case NSVG_UNITS_PT:
800  return c.value / 72.0f * p->dpi;
801 
802  case NSVG_UNITS_PC:
803  return c.value / 6.0f * p->dpi;
804 
805  case NSVG_UNITS_MM:
806  return c.value / 25.4f * p->dpi;
807 
808  case NSVG_UNITS_CM:
809  return c.value / 2.54f * p->dpi;
810 
811  case NSVG_UNITS_IN:
812  return c.value * p->dpi;
813 
814  case NSVG_UNITS_EM:
815  return c.value * attr->fontSize;
816 
817  case NSVG_UNITS_EX:
818  return c.value * attr->fontSize * 0.52f; // x-height of Helvetica.
819 
820  case NSVG_UNITS_PERCENT:
821  return orig + c.value / 100.0f * length;
822 
823  default:
824  return c.value;
825  }
826 
827  return c.value;
828 }
829 
830 
832 {
833  NSVGgradientData* grad = p->gradients;
834 
835  while( grad )
836  {
837  if( strcmp( grad->id, id ) == 0 )
838  return grad;
839 
840  grad = grad->next;
841  }
842 
843  return NULL;
844 }
845 
846 
848  const char* id,
849  const float* localBounds,
850  char* paintType )
851 {
852  NSVGattrib* attr = nsvg__getAttr( p );
853  NSVGgradientData* data = NULL;
854  NSVGgradientData* ref = NULL;
855  NSVGgradientStop* stops = NULL;
856  NSVGgradient* grad;
857  float ox, oy, sw, sh, sl;
858  int nstops = 0;
859 
860  data = nsvg__findGradientData( p, id );
861 
862  if( data == NULL )
863  return NULL;
864 
865  // TODO: use ref to fill in all unset values too.
866  ref = data;
867 
868  while( ref != NULL )
869  {
870  if( stops == NULL && ref->stops != NULL )
871  {
872  stops = ref->stops;
873  nstops = ref->nstops;
874  break;
875  }
876 
877  ref = nsvg__findGradientData( p, ref->ref );
878  }
879 
880  if( stops == NULL )
881  return NULL;
882 
883  grad = (NSVGgradient*) malloc( sizeof(NSVGgradient) + sizeof(NSVGgradientStop) * (nstops - 1) );
884 
885  if( grad == NULL )
886  return NULL;
887 
888  // The shape width and height.
889  if( data->units == NSVG_OBJECT_SPACE )
890  {
891  ox = localBounds[0];
892  oy = localBounds[1];
893  sw = localBounds[2] - localBounds[0];
894  sh = localBounds[3] - localBounds[1];
895  }
896  else
897  {
898  ox = nsvg__actualOrigX( p );
899  oy = nsvg__actualOrigY( p );
900  sw = nsvg__actualWidth( p );
901  sh = nsvg__actualHeight( p );
902  }
903 
904  sl = sqrtf( sw * sw + sh * sh ) / sqrtf( 2.0f );
905 
906  if( data->type == NSVG_PAINT_LINEAR_GRADIENT )
907  {
908  float x1, y1, x2, y2, dx, dy;
909  x1 = nsvg__convertToPixels( p, data->linear.x1, ox, sw );
910  y1 = nsvg__convertToPixels( p, data->linear.y1, oy, sh );
911  x2 = nsvg__convertToPixels( p, data->linear.x2, ox, sw );
912  y2 = nsvg__convertToPixels( p, data->linear.y2, oy, sh );
913  // Calculate transform aligned to the line
914  dx = x2 - x1;
915  dy = y2 - y1;
916  grad->xform[0] = dy; grad->xform[1] = -dx;
917  grad->xform[2] = dx; grad->xform[3] = dy;
918  grad->xform[4] = x1; grad->xform[5] = y1;
919  }
920  else
921  {
922  float cx, cy, fx, fy, r;
923  cx = nsvg__convertToPixels( p, data->radial.cx, ox, sw );
924  cy = nsvg__convertToPixels( p, data->radial.cy, oy, sh );
925  fx = nsvg__convertToPixels( p, data->radial.fx, ox, sw );
926  fy = nsvg__convertToPixels( p, data->radial.fy, oy, sh );
927  r = nsvg__convertToPixels( p, data->radial.r, 0, sl );
928  // Calculate transform aligned to the circle
929  grad->xform[0] = r; grad->xform[1] = 0;
930  grad->xform[2] = 0; grad->xform[3] = r;
931  grad->xform[4] = cx; grad->xform[5] = cy;
932  grad->fx = fx / r;
933  grad->fy = fy / r;
934  }
935 
936  nsvg__xformMultiply( grad->xform, data->xform );
937  nsvg__xformMultiply( grad->xform, attr->xform );
938 
939  grad->spread = data->spread;
940  memcpy( grad->stops, stops, nstops * sizeof(NSVGgradientStop) );
941  grad->nstops = nstops;
942 
943  *paintType = data->type;
944 
945  return grad;
946 }
947 
948 
949 static float nsvg__getAverageScale( float* t )
950 {
951  float sx = sqrtf( t[0] * t[0] + t[2] * t[2] );
952  float sy = sqrtf( t[1] * t[1] + t[3] * t[3] );
953 
954  return (sx + sy) * 0.5f;
955 }
956 
957 
958 static void nsvg__getLocalBounds( float* bounds, NSVGshape* shape, float* xform )
959 {
960  NSVGpath* path;
961  float curve[4 * 2], curveBounds[4];
962  int i, first = 1;
963 
964  for( path = shape->paths; path != NULL; path = path->next )
965  {
966  nsvg__xformPoint( &curve[0], &curve[1], path->pts[0], path->pts[1], xform );
967 
968  for( i = 0; i < path->npts - 1; i += 3 )
969  {
970  nsvg__xformPoint( &curve[2], &curve[3], path->pts[(i + 1) * 2],
971  path->pts[(i + 1) * 2 + 1], xform );
972  nsvg__xformPoint( &curve[4], &curve[5], path->pts[(i + 2) * 2],
973  path->pts[(i + 2) * 2 + 1], xform );
974  nsvg__xformPoint( &curve[6], &curve[7], path->pts[(i + 3) * 2],
975  path->pts[(i + 3) * 2 + 1], xform );
976  nsvg__curveBounds( curveBounds, curve );
977 
978  if( first )
979  {
980  bounds[0] = curveBounds[0];
981  bounds[1] = curveBounds[1];
982  bounds[2] = curveBounds[2];
983  bounds[3] = curveBounds[3];
984  first = 0;
985  }
986  else
987  {
988  bounds[0] = nsvg__minf( bounds[0], curveBounds[0] );
989  bounds[1] = nsvg__minf( bounds[1], curveBounds[1] );
990  bounds[2] = nsvg__maxf( bounds[2], curveBounds[2] );
991  bounds[3] = nsvg__maxf( bounds[3], curveBounds[3] );
992  }
993 
994  curve[0] = curve[6];
995  curve[1] = curve[7];
996  }
997  }
998 }
999 
1000 
1001 static void nsvg__addShape( NSVGparser* p )
1002 {
1003  NSVGattrib* attr = nsvg__getAttr( p );
1004  float scale = 1.0f;
1005  NSVGshape* shape;
1006  NSVGpath* path;
1007  int i;
1008 
1009  if( p->plist == NULL )
1010  return;
1011 
1012  shape = (NSVGshape*) malloc( sizeof(NSVGshape) );
1013 
1014  if( shape == NULL )
1015  goto error;
1016 
1017  memset( shape, 0, sizeof(NSVGshape) );
1018 
1019  memcpy( shape->id, attr->id, sizeof shape->id );
1020  scale = nsvg__getAverageScale( attr->xform );
1021  shape->strokeWidth = attr->strokeWidth * scale;
1022  shape->strokeDashOffset = attr->strokeDashOffset * scale;
1023  shape->strokeDashCount = (char) attr->strokeDashCount;
1024 
1025  for( i = 0; i < attr->strokeDashCount; i++ )
1026  shape->strokeDashArray[i] = attr->strokeDashArray[i] * scale;
1027 
1028  shape->strokeLineJoin = attr->strokeLineJoin;
1029  shape->strokeLineCap = attr->strokeLineCap;
1030  shape->miterLimit = attr->miterLimit;
1031  shape->fillRule = attr->fillRule;
1032  shape->opacity = attr->opacity;
1033 
1034  shape->paths = p->plist;
1035  p->plist = NULL;
1036 
1037  // Calculate shape bounds
1038  shape->bounds[0] = shape->paths->bounds[0];
1039  shape->bounds[1] = shape->paths->bounds[1];
1040  shape->bounds[2] = shape->paths->bounds[2];
1041  shape->bounds[3] = shape->paths->bounds[3];
1042 
1043  for( path = shape->paths->next; path != NULL; path = path->next )
1044  {
1045  shape->bounds[0] = nsvg__minf( shape->bounds[0], path->bounds[0] );
1046  shape->bounds[1] = nsvg__minf( shape->bounds[1], path->bounds[1] );
1047  shape->bounds[2] = nsvg__maxf( shape->bounds[2], path->bounds[2] );
1048  shape->bounds[3] = nsvg__maxf( shape->bounds[3], path->bounds[3] );
1049  }
1050 
1051  // Set fill
1052  if( attr->hasFill == 0 )
1053  {
1054  shape->fill.type = NSVG_PAINT_NONE;
1055  }
1056  else if( attr->hasFill == 1 )
1057  {
1058  shape->fill.type = NSVG_PAINT_COLOR;
1059  shape->fill.color = attr->fillColor;
1060  shape->fill.color |= (unsigned int) (attr->fillOpacity * 255) << 24;
1061  }
1062  else if( attr->hasFill == 2 )
1063  {
1064  float inv[6], localBounds[4];
1065  nsvg__xformInverse( inv, attr->xform );
1066  nsvg__getLocalBounds( localBounds, shape, inv );
1067  shape->fill.gradient = nsvg__createGradient( p,
1068  attr->fillGradient,
1069  localBounds,
1070  &shape->fill.type );
1071 
1072  if( shape->fill.gradient == NULL )
1073  {
1074  shape->fill.type = NSVG_PAINT_NONE;
1075  }
1076  }
1077 
1078  // Set stroke
1079  if( attr->hasStroke == 0 )
1080  {
1081  shape->stroke.type = NSVG_PAINT_NONE;
1082  }
1083  else if( attr->hasStroke == 1 )
1084  {
1085  shape->stroke.type = NSVG_PAINT_COLOR;
1086  shape->stroke.color = attr->strokeColor;
1087  shape->stroke.color |= (unsigned int) (attr->strokeOpacity * 255) << 24;
1088  }
1089  else if( attr->hasStroke == 2 )
1090  {
1091  float inv[6], localBounds[4];
1092  nsvg__xformInverse( inv, attr->xform );
1093  nsvg__getLocalBounds( localBounds, shape, inv );
1094  shape->stroke.gradient = nsvg__createGradient( p,
1095  attr->strokeGradient,
1096  localBounds,
1097  &shape->stroke.type );
1098 
1099  if( shape->stroke.gradient == NULL )
1100  shape->stroke.type = NSVG_PAINT_NONE;
1101  }
1102 
1103  // Set flags
1104  shape->flags = (attr->visible ? NSVG_FLAGS_VISIBLE : 0x00);
1105 
1106  // Add to tail
1107  if( p->image->shapes == NULL )
1108  p->image->shapes = shape;
1109  else
1110  p->shapesTail->next = shape;
1111 
1112  p->shapesTail = shape;
1113 
1114  return;
1115 
1116 error:
1117 
1118  if( shape )
1119  free( shape );
1120 }
1121 
1122 
1123 static void nsvg__addPath( NSVGparser* p, char closed )
1124 {
1125  NSVGattrib* attr = nsvg__getAttr( p );
1126  NSVGpath* path = NULL;
1127  float bounds[4];
1128  float* curve;
1129  int i;
1130 
1131  if( p->npts < 4 )
1132  return;
1133 
1134  if( closed )
1135  nsvg__lineTo( p, p->pts[0], p->pts[1] );
1136 
1137  path = (NSVGpath*) malloc( sizeof(NSVGpath) );
1138 
1139  if( path == NULL )
1140  goto error;
1141 
1142  memset( path, 0, sizeof(NSVGpath) );
1143 
1144  path->pts = (float*) malloc( p->npts * 2 * sizeof(float) );
1145 
1146  if( path->pts == NULL )
1147  goto error;
1148 
1149  path->closed = closed;
1150  path->npts = p->npts;
1151 
1152  // Transform path.
1153  for( i = 0; i < p->npts; ++i )
1154  nsvg__xformPoint( &path->pts[i * 2],
1155  &path->pts[i * 2 + 1],
1156  p->pts[i * 2],
1157  p->pts[i * 2 + 1],
1158  attr->xform );
1159 
1160  // Find bounds
1161  for( i = 0; i < path->npts - 1; i += 3 )
1162  {
1163  curve = &path->pts[i * 2];
1164  nsvg__curveBounds( bounds, curve );
1165 
1166  if( i == 0 )
1167  {
1168  path->bounds[0] = bounds[0];
1169  path->bounds[1] = bounds[1];
1170  path->bounds[2] = bounds[2];
1171  path->bounds[3] = bounds[3];
1172  }
1173  else
1174  {
1175  path->bounds[0] = nsvg__minf( path->bounds[0], bounds[0] );
1176  path->bounds[1] = nsvg__minf( path->bounds[1], bounds[1] );
1177  path->bounds[2] = nsvg__maxf( path->bounds[2], bounds[2] );
1178  path->bounds[3] = nsvg__maxf( path->bounds[3], bounds[3] );
1179  }
1180  }
1181 
1182  path->next = p->plist;
1183  p->plist = path;
1184 
1185  return;
1186 
1187 error:
1188 
1189  if( path != NULL )
1190  {
1191  if( path->pts != NULL )
1192  free( path->pts );
1193 
1194  free( path );
1195  }
1196 }
1197 
1198 
1199 // We roll our own string to float because the std library one uses locale and messes things up.
1200 static double nsvg__atof( const char* s )
1201 {
1202  char* cur = (char*) s;
1203  char* end = NULL;
1204  double res = 0.0, sign = 1.0;
1205  long long intPart = 0, fracPart = 0;
1206  char hasIntPart = 0, hasFracPart = 0;
1207 
1208  // Parse optional sign
1209  if( *cur == '+' )
1210  {
1211  cur++;
1212  }
1213  else if( *cur == '-' )
1214  {
1215  sign = -1;
1216  cur++;
1217  }
1218 
1219  // Parse integer part
1220  if( nsvg__isdigit( *cur ) )
1221  {
1222  // Parse digit sequence
1223  intPart = (double) strtoll( cur, &end, 10 );
1224 
1225  if( cur != end )
1226  {
1227  res = (double) intPart;
1228  hasIntPart = 1;
1229  cur = end;
1230  }
1231  }
1232 
1233  // Parse fractional part.
1234  if( *cur == '.' )
1235  {
1236  cur++; // Skip '.'
1237 
1238  if( nsvg__isdigit( *cur ) )
1239  {
1240  // Parse digit sequence
1241  fracPart = strtoll( cur, &end, 10 );
1242 
1243  if( cur != end )
1244  {
1245  res += (double) fracPart / pow( 10.0, (double) (end - cur) );
1246  hasFracPart = 1;
1247  cur = end;
1248  }
1249  }
1250  }
1251 
1252  // A valid number should have integer or fractional part.
1253  if( !hasIntPart && !hasFracPart )
1254  return 0.0;
1255 
1256  // Parse optional exponent
1257  if( *cur == 'e' || *cur == 'E' )
1258  {
1259  int expPart = 0;
1260  cur++; // skip 'E'
1261  expPart = strtol( cur, &end, 10 ); // Parse digit sequence with sign
1262 
1263  if( cur != end )
1264  {
1265  res *= pow( 10.0, (double) expPart );
1266  }
1267  }
1268 
1269  return res * sign;
1270 }
1271 
1272 
1273 static const char* nsvg__parseNumber( const char* s, char* it, const int size )
1274 {
1275  const int last = size - 1;
1276  int i = 0;
1277 
1278  // sign
1279  if( *s == '-' || *s == '+' )
1280  {
1281  if( i < last )
1282  it[i++] = *s;
1283 
1284  s++;
1285  }
1286 
1287  // integer part
1288  while( *s && nsvg__isdigit( *s ) )
1289  {
1290  if( i < last )
1291  it[i++] = *s;
1292 
1293  s++;
1294  }
1295 
1296  if( *s == '.' )
1297  {
1298  // decimal point
1299  if( i < last )
1300  it[i++] = *s;
1301 
1302  s++;
1303 
1304  // fraction part
1305  while( *s && nsvg__isdigit( *s ) )
1306  {
1307  if( i < last )
1308  it[i++] = *s;
1309 
1310  s++;
1311  }
1312  }
1313 
1314  // exponent
1315  if( *s == 'e' || *s == 'E' )
1316  {
1317  if( i < last )
1318  it[i++] = *s;
1319 
1320  s++;
1321 
1322  if( *s == '-' || *s == '+' )
1323  {
1324  if( i < last )
1325  it[i++] = *s;
1326 
1327  s++;
1328  }
1329 
1330  while( *s && nsvg__isdigit( *s ) )
1331  {
1332  if( i < last )
1333  it[i++] = *s;
1334 
1335  s++;
1336  }
1337  }
1338 
1339  it[i] = '\0';
1340 
1341  return s;
1342 }
1343 
1344 
1345 static const char* nsvg__getNextPathItem( const char* s, char* it )
1346 {
1347  it[0] = '\0';
1348 
1349  // Skip white spaces and commas
1350  while( *s && (nsvg__isspace( *s ) || *s == ',') )
1351  s++;
1352 
1353  if( !*s )
1354  return s;
1355 
1356  if( *s == '-' || *s == '+' || *s == '.' || nsvg__isdigit( *s ) )
1357  {
1358  s = nsvg__parseNumber( s, it, 64 );
1359  }
1360  else
1361  {
1362  // Parse command
1363  it[0] = *s++;
1364  it[1] = '\0';
1365  return s;
1366  }
1367 
1368  return s;
1369 }
1370 
1371 
1372 static unsigned int nsvg__parseColorHex( const char* str )
1373 {
1374  unsigned int c = 0, r = 0, g = 0, b = 0;
1375  int n = 0;
1376 
1377  str++; // skip #
1378 
1379  // Calculate number of characters.
1380  while( str[n] && !nsvg__isspace( str[n] ) )
1381  n++;
1382 
1383  if( n == 6 )
1384  {
1385  sscanf( str, "%x", &c );
1386  }
1387  else if( n == 3 )
1388  {
1389  sscanf( str, "%x", &c );
1390  c = (c & 0xf) | ( (c & 0xf0) << 4 ) | ( (c & 0xf00) << 8 );
1391  c |= c << 4;
1392  }
1393 
1394  r = (c >> 16) & 0xff;
1395  g = (c >> 8) & 0xff;
1396  b = c & 0xff;
1397  return NSVG_RGB( r, g, b );
1398 }
1399 
1400 
1401 static unsigned int nsvg__parseColorRGB( const char* str )
1402 {
1403  int r = -1, g = -1, b = -1;
1404  char s1[32] = "", s2[32] = "";
1405 
1406  sscanf( str + 4, "%d%[%%, \t]%d%[%%, \t]%d", &r, s1, &g, s2, &b );
1407 
1408  if( strchr( s1, '%' ) )
1409  {
1410  return NSVG_RGB( (r * 255) / 100, (g * 255) / 100, (b * 255) / 100 );
1411  }
1412  else
1413  {
1414  return NSVG_RGB( r, g, b );
1415  }
1416 }
1417 
1418 
1419 typedef struct NSVGNamedColor
1420 {
1421  const char* name;
1422  unsigned int color;
1423 } NSVGNamedColor;
1424 
1426 {
1427  { "red", NSVG_RGB( 255, 0, 0 ) },
1428  { "green", NSVG_RGB( 0, 128, 0 ) },
1429  { "blue", NSVG_RGB( 0, 0, 255 ) },
1430  { "yellow", NSVG_RGB( 255, 255, 0 ) },
1431  { "cyan", NSVG_RGB( 0, 255, 255 ) },
1432  { "magenta", NSVG_RGB( 255, 0, 255 ) },
1433  { "black", NSVG_RGB( 0, 0, 0 ) },
1434  { "grey", NSVG_RGB( 128, 128, 128 ) },
1435  { "gray", NSVG_RGB( 128, 128, 128 ) },
1436  { "white", NSVG_RGB( 255, 255, 255 ) },
1437 
1438 #ifdef NANOSVG_ALL_COLOR_KEYWORDS
1439  { "aliceblue", NSVG_RGB( 240, 248, 255 ) },
1440  { "antiquewhite", NSVG_RGB( 250, 235, 215 ) },
1441  { "aqua", NSVG_RGB( 0, 255, 255 ) },
1442  { "aquamarine", NSVG_RGB( 127, 255, 212 ) },
1443  { "azure", NSVG_RGB( 240, 255, 255 ) },
1444  { "beige", NSVG_RGB( 245, 245, 220 ) },
1445  { "bisque", NSVG_RGB( 255, 228, 196 ) },
1446  { "blanchedalmond", NSVG_RGB( 255, 235, 205 ) },
1447  { "blueviolet", NSVG_RGB( 138, 43, 226 ) },
1448  { "brown", NSVG_RGB( 165, 42, 42 ) },
1449  { "burlywood", NSVG_RGB( 222, 184, 135 ) },
1450  { "cadetblue", NSVG_RGB( 95, 158, 160 ) },
1451  { "chartreuse", NSVG_RGB( 127, 255, 0 ) },
1452  { "chocolate", NSVG_RGB( 210, 105, 30 ) },
1453  { "coral", NSVG_RGB( 255, 127, 80 ) },
1454  { "cornflowerblue", NSVG_RGB( 100, 149, 237 ) },
1455  { "cornsilk", NSVG_RGB( 255, 248, 220 ) },
1456  { "crimson", NSVG_RGB( 220, 20, 60 ) },
1457  { "darkblue", NSVG_RGB( 0, 0, 139 ) },
1458  { "darkcyan", NSVG_RGB( 0, 139, 139 ) },
1459  { "darkgoldenrod", NSVG_RGB( 184, 134, 11 ) },
1460  { "darkgray", NSVG_RGB( 169, 169, 169 ) },
1461  { "darkgreen", NSVG_RGB( 0, 100, 0 ) },
1462  { "darkgrey", NSVG_RGB( 169, 169, 169 ) },
1463  { "darkkhaki", NSVG_RGB( 189, 183, 107 ) },
1464  { "darkmagenta", NSVG_RGB( 139, 0, 139 ) },
1465  { "darkolivegreen", NSVG_RGB( 85, 107, 47 ) },
1466  { "darkorange", NSVG_RGB( 255, 140, 0 ) },
1467  { "darkorchid", NSVG_RGB( 153, 50, 204 ) },
1468  { "darkred", NSVG_RGB( 139, 0, 0 ) },
1469  { "darksalmon", NSVG_RGB( 233, 150, 122 ) },
1470  { "darkseagreen", NSVG_RGB( 143, 188, 143 ) },
1471  { "darkslateblue", NSVG_RGB( 72, 61, 139 ) },
1472  { "darkslategray", NSVG_RGB( 47, 79, 79 ) },
1473  { "darkslategrey", NSVG_RGB( 47, 79, 79 ) },
1474  { "darkturquoise", NSVG_RGB( 0, 206, 209 ) },
1475  { "darkviolet", NSVG_RGB( 148, 0, 211 ) },
1476  { "deeppink", NSVG_RGB( 255, 20, 147 ) },
1477  { "deepskyblue", NSVG_RGB( 0, 191, 255 ) },
1478  { "dimgray", NSVG_RGB( 105, 105, 105 ) },
1479  { "dimgrey", NSVG_RGB( 105, 105, 105 ) },
1480  { "dodgerblue", NSVG_RGB( 30, 144, 255 ) },
1481  { "firebrick", NSVG_RGB( 178, 34, 34 ) },
1482  { "floralwhite", NSVG_RGB( 255, 250, 240 ) },
1483  { "forestgreen", NSVG_RGB( 34, 139, 34 ) },
1484  { "fuchsia", NSVG_RGB( 255, 0, 255 ) },
1485  { "gainsboro", NSVG_RGB( 220, 220, 220 ) },
1486  { "ghostwhite", NSVG_RGB( 248, 248, 255 ) },
1487  { "gold", NSVG_RGB( 255, 215, 0 ) },
1488  { "goldenrod", NSVG_RGB( 218, 165, 32 ) },
1489  { "greenyellow", NSVG_RGB( 173, 255, 47 ) },
1490  { "honeydew", NSVG_RGB( 240, 255, 240 ) },
1491  { "hotpink", NSVG_RGB( 255, 105, 180 ) },
1492  { "indianred", NSVG_RGB( 205, 92, 92 ) },
1493  { "indigo", NSVG_RGB( 75, 0, 130 ) },
1494  { "ivory", NSVG_RGB( 255, 255, 240 ) },
1495  { "khaki", NSVG_RGB( 240, 230, 140 ) },
1496  { "lavender", NSVG_RGB( 230, 230, 250 ) },
1497  { "lavenderblush", NSVG_RGB( 255, 240, 245 ) },
1498  { "lawngreen", NSVG_RGB( 124, 252, 0 ) },
1499  { "lemonchiffon", NSVG_RGB( 255, 250, 205 ) },
1500  { "lightblue", NSVG_RGB( 173, 216, 230 ) },
1501  { "lightcoral", NSVG_RGB( 240, 128, 128 ) },
1502  { "lightcyan", NSVG_RGB( 224, 255, 255 ) },
1503  { "lightgoldenrodyellow", NSVG_RGB( 250, 250, 210 ) },
1504  { "lightgray", NSVG_RGB( 211, 211, 211 ) },
1505  { "lightgreen", NSVG_RGB( 144, 238, 144 ) },
1506  { "lightgrey", NSVG_RGB( 211, 211, 211 ) },
1507  { "lightpink", NSVG_RGB( 255, 182, 193 ) },
1508  { "lightsalmon", NSVG_RGB( 255, 160, 122 ) },
1509  { "lightseagreen", NSVG_RGB( 32, 178, 170 ) },
1510  { "lightskyblue", NSVG_RGB( 135, 206, 250 ) },
1511  { "lightslategray", NSVG_RGB( 119, 136, 153 ) },
1512  { "lightslategrey", NSVG_RGB( 119, 136, 153 ) },
1513  { "lightsteelblue", NSVG_RGB( 176, 196, 222 ) },
1514  { "lightyellow", NSVG_RGB( 255, 255, 224 ) },
1515  { "lime", NSVG_RGB( 0, 255, 0 ) },
1516  { "limegreen", NSVG_RGB( 50, 205, 50 ) },
1517  { "linen", NSVG_RGB( 250, 240, 230 ) },
1518  { "maroon", NSVG_RGB( 128, 0, 0 ) },
1519  { "mediumaquamarine", NSVG_RGB( 102, 205, 170 ) },
1520  { "mediumblue", NSVG_RGB( 0, 0, 205 ) },
1521  { "mediumorchid", NSVG_RGB( 186, 85, 211 ) },
1522  { "mediumpurple", NSVG_RGB( 147, 112, 219 ) },
1523  { "mediumseagreen", NSVG_RGB( 60, 179, 113 ) },
1524  { "mediumslateblue", NSVG_RGB( 123, 104, 238 ) },
1525  { "mediumspringgreen", NSVG_RGB( 0, 250, 154 ) },
1526  { "mediumturquoise", NSVG_RGB( 72, 209, 204 ) },
1527  { "mediumvioletred", NSVG_RGB( 199, 21, 133 ) },
1528  { "midnightblue", NSVG_RGB( 25, 25, 112 ) },
1529  { "mintcream", NSVG_RGB( 245, 255, 250 ) },
1530  { "mistyrose", NSVG_RGB( 255, 228, 225 ) },
1531  { "moccasin", NSVG_RGB( 255, 228, 181 ) },
1532  { "navajowhite", NSVG_RGB( 255, 222, 173 ) },
1533  { "navy", NSVG_RGB( 0, 0, 128 ) },
1534  { "oldlace", NSVG_RGB( 253, 245, 230 ) },
1535  { "olive", NSVG_RGB( 128, 128, 0 ) },
1536  { "olivedrab", NSVG_RGB( 107, 142, 35 ) },
1537  { "orange", NSVG_RGB( 255, 165, 0 ) },
1538  { "orangered", NSVG_RGB( 255, 69, 0 ) },
1539  { "orchid", NSVG_RGB( 218, 112, 214 ) },
1540  { "palegoldenrod", NSVG_RGB( 238, 232, 170 ) },
1541  { "palegreen", NSVG_RGB( 152, 251, 152 ) },
1542  { "paleturquoise", NSVG_RGB( 175, 238, 238 ) },
1543  { "palevioletred", NSVG_RGB( 219, 112, 147 ) },
1544  { "papayawhip", NSVG_RGB( 255, 239, 213 ) },
1545  { "peachpuff", NSVG_RGB( 255, 218, 185 ) },
1546  { "peru", NSVG_RGB( 205, 133, 63 ) },
1547  { "pink", NSVG_RGB( 255, 192, 203 ) },
1548  { "plum", NSVG_RGB( 221, 160, 221 ) },
1549  { "powderblue", NSVG_RGB( 176, 224, 230 ) },
1550  { "purple", NSVG_RGB( 128, 0, 128 ) },
1551  { "rosybrown", NSVG_RGB( 188, 143, 143 ) },
1552  { "royalblue", NSVG_RGB( 65, 105, 225 ) },
1553  { "saddlebrown", NSVG_RGB( 139, 69, 19 ) },
1554  { "salmon", NSVG_RGB( 250, 128, 114 ) },
1555  { "sandybrown", NSVG_RGB( 244, 164, 96 ) },
1556  { "seagreen", NSVG_RGB( 46, 139, 87 ) },
1557  { "seashell", NSVG_RGB( 255, 245, 238 ) },
1558  { "sienna", NSVG_RGB( 160, 82, 45 ) },
1559  { "silver", NSVG_RGB( 192, 192, 192 ) },
1560  { "skyblue", NSVG_RGB( 135, 206, 235 ) },
1561  { "slateblue", NSVG_RGB( 106, 90, 205 ) },
1562  { "slategray", NSVG_RGB( 112, 128, 144 ) },
1563  { "slategrey", NSVG_RGB( 112, 128, 144 ) },
1564  { "snow", NSVG_RGB( 255, 250, 250 ) },
1565  { "springgreen", NSVG_RGB( 0, 255, 127 ) },
1566  { "steelblue", NSVG_RGB( 70, 130, 180 ) },
1567  { "tan", NSVG_RGB( 210, 180, 140 ) },
1568  { "teal", NSVG_RGB( 0, 128, 128 ) },
1569  { "thistle", NSVG_RGB( 216, 191, 216 ) },
1570  { "tomato", NSVG_RGB( 255, 99, 71 ) },
1571  { "turquoise", NSVG_RGB( 64, 224, 208 ) },
1572  { "violet", NSVG_RGB( 238, 130, 238 ) },
1573  { "wheat", NSVG_RGB( 245, 222, 179 ) },
1574  { "whitesmoke", NSVG_RGB( 245, 245, 245 ) },
1575  { "yellowgreen", NSVG_RGB( 154, 205, 50 ) },
1576 #endif
1577 };
1578 
1579 static unsigned int nsvg__parseColorName( const char* str )
1580 {
1581  int i, ncolors = sizeof(nsvg__colors) / sizeof(NSVGNamedColor);
1582 
1583  for( i = 0; i < ncolors; i++ )
1584  {
1585  if( strcmp( nsvg__colors[i].name, str ) == 0 )
1586  {
1587  return nsvg__colors[i].color;
1588  }
1589  }
1590 
1591  return NSVG_RGB( 128, 128, 128 );
1592 }
1593 
1594 
1595 static unsigned int nsvg__parseColor( const char* str )
1596 {
1597  size_t len = 0;
1598 
1599  while( *str == ' ' )
1600  ++str;
1601 
1602  len = strlen( str );
1603 
1604  if( len >= 1 && *str == '#' )
1605  return nsvg__parseColorHex( str );
1606  else if( len >= 4 && str[0] == 'r' && str[1] == 'g' && str[2] == 'b' && str[3] == '(' )
1607  return nsvg__parseColorRGB( str );
1608 
1609  return nsvg__parseColorName( str );
1610 }
1611 
1612 
1613 static float nsvg__parseOpacity( const char* str )
1614 {
1615  float val = 0;
1616 
1617  sscanf( str, "%f", &val );
1618 
1619  if( val < 0.0f )
1620  val = 0.0f;
1621 
1622  if( val > 1.0f )
1623  val = 1.0f;
1624 
1625  return val;
1626 }
1627 
1628 
1629 static float nsvg__parseMiterLimit( const char* str )
1630 {
1631  float val = 0;
1632 
1633  sscanf( str, "%f", &val );
1634 
1635  if( val < 0.0f )
1636  val = 0.0f;
1637 
1638  return val;
1639 }
1640 
1641 
1642 static int nsvg__parseUnits( const char* units )
1643 {
1644  if( units[0] == 'p' && units[1] == 'x' )
1645  return NSVG_UNITS_PX;
1646  else if( units[0] == 'p' && units[1] == 't' )
1647  return NSVG_UNITS_PT;
1648  else if( units[0] == 'p' && units[1] == 'c' )
1649  return NSVG_UNITS_PC;
1650  else if( units[0] == 'm' && units[1] == 'm' )
1651  return NSVG_UNITS_MM;
1652  else if( units[0] == 'c' && units[1] == 'm' )
1653  return NSVG_UNITS_CM;
1654  else if( units[0] == 'i' && units[1] == 'n' )
1655  return NSVG_UNITS_IN;
1656  else if( units[0] == '%' )
1657  return NSVG_UNITS_PERCENT;
1658  else if( units[0] == 'e' && units[1] == 'm' )
1659  return NSVG_UNITS_EM;
1660  else if( units[0] == 'e' && units[1] == 'x' )
1661  return NSVG_UNITS_EX;
1662 
1663  return NSVG_UNITS_USER;
1664 }
1665 
1666 
1668 {
1669  NSVGcoordinate coord = { 0, NSVG_UNITS_USER };
1670  char units[32] = "";
1671 
1672  sscanf( str, "%f%31s", &coord.value, units );
1673  coord.units = nsvg__parseUnits( units );
1674  return coord;
1675 }
1676 
1677 
1678 static NSVGcoordinate nsvg__coord( float v, int units )
1679 {
1680  NSVGcoordinate coord = { v, units };
1681 
1682  return coord;
1683 }
1684 
1685 
1686 static float nsvg__parseCoordinate( NSVGparser* p, const char* str, float orig, float length )
1687 {
1689 
1690  return nsvg__convertToPixels( p, coord, orig, length );
1691 }
1692 
1693 
1694 static int nsvg__parseTransformArgs( const char* str, float* args, int maxNa, int* na )
1695 {
1696  const char* end;
1697  const char* ptr;
1698  char it[64];
1699 
1700  *na = 0;
1701  ptr = str;
1702 
1703  while( *ptr && *ptr != '(' )
1704  ++ptr;
1705 
1706  if( *ptr == 0 )
1707  return 1;
1708 
1709  end = ptr;
1710 
1711  while( *end && *end != ')' )
1712  ++end;
1713 
1714  if( *end == 0 )
1715  return 1;
1716 
1717  while( ptr < end )
1718  {
1719  if( *ptr == '-' || *ptr == '+' || *ptr == '.' || nsvg__isdigit( *ptr ) )
1720  {
1721  if( *na >= maxNa )
1722  return 0;
1723 
1724  ptr = nsvg__parseNumber( ptr, it, 64 );
1725  args[(*na)++] = (float) nsvg__atof( it );
1726  }
1727  else
1728  {
1729  ++ptr;
1730  }
1731  }
1732 
1733  return (int) (end - str);
1734 }
1735 
1736 
1737 static int nsvg__parseMatrix( float* xform, const char* str )
1738 {
1739  float t[6];
1740  int na = 0;
1741  int len = nsvg__parseTransformArgs( str, t, 6, &na );
1742 
1743  if( na != 6 )
1744  return len;
1745 
1746  memcpy( xform, t, sizeof(float) * 6 );
1747  return len;
1748 }
1749 
1750 
1751 static int nsvg__parseTranslate( float* xform, const char* str )
1752 {
1753  float args[2];
1754  float t[6];
1755  int na = 0;
1756  int len = nsvg__parseTransformArgs( str, args, 2, &na );
1757 
1758  if( na == 1 )
1759  args[1] = 0.0;
1760 
1761  nsvg__xformSetTranslation( t, args[0], args[1] );
1762  memcpy( xform, t, sizeof(float) * 6 );
1763  return len;
1764 }
1765 
1766 
1767 static int nsvg__parseScale( float* xform, const char* str )
1768 {
1769  float args[2];
1770  int na = 0;
1771  float t[6];
1772  int len = nsvg__parseTransformArgs( str, args, 2, &na );
1773 
1774  if( na == 1 )
1775  args[1] = args[0];
1776 
1777  nsvg__xformSetScale( t, args[0], args[1] );
1778  memcpy( xform, t, sizeof(float) * 6 );
1779  return len;
1780 }
1781 
1782 
1783 static int nsvg__parseSkewX( float* xform, const char* str )
1784 {
1785  float args[1];
1786  int na = 0;
1787  float t[6];
1788  int len = nsvg__parseTransformArgs( str, args, 1, &na );
1789 
1790  nsvg__xformSetSkewX( t, args[0] / 180.0f * NSVG_PI );
1791  memcpy( xform, t, sizeof(float) * 6 );
1792  return len;
1793 }
1794 
1795 
1796 static int nsvg__parseSkewY( float* xform, const char* str )
1797 {
1798  float args[1];
1799  int na = 0;
1800  float t[6];
1801  int len = nsvg__parseTransformArgs( str, args, 1, &na );
1802 
1803  nsvg__xformSetSkewY( t, args[0] / 180.0f * NSVG_PI );
1804  memcpy( xform, t, sizeof(float) * 6 );
1805  return len;
1806 }
1807 
1808 
1809 static int nsvg__parseRotate( float* xform, const char* str )
1810 {
1811  float args[3];
1812  int na = 0;
1813  float m[6];
1814  float t[6];
1815  int len = nsvg__parseTransformArgs( str, args, 3, &na );
1816 
1817  if( na == 1 )
1818  args[1] = args[2] = 0.0f;
1819 
1820  nsvg__xformIdentity( m );
1821 
1822  if( na > 1 )
1823  {
1824  nsvg__xformSetTranslation( t, -args[1], -args[2] );
1825  nsvg__xformMultiply( m, t );
1826  }
1827 
1828  nsvg__xformSetRotation( t, args[0] / 180.0f * NSVG_PI );
1829  nsvg__xformMultiply( m, t );
1830 
1831  if( na > 1 )
1832  {
1833  nsvg__xformSetTranslation( t, args[1], args[2] );
1834  nsvg__xformMultiply( m, t );
1835  }
1836 
1837  memcpy( xform, m, sizeof(float) * 6 );
1838 
1839  return len;
1840 }
1841 
1842 
1843 static void nsvg__parseTransform( float* xform, const char* str )
1844 {
1845  float t[6];
1846 
1847  nsvg__xformIdentity( xform );
1848 
1849  while( *str )
1850  {
1851  if( strncmp( str, "matrix", 6 ) == 0 )
1852  str += nsvg__parseMatrix( t, str );
1853  else if( strncmp( str, "translate", 9 ) == 0 )
1854  str += nsvg__parseTranslate( t, str );
1855  else if( strncmp( str, "scale", 5 ) == 0 )
1856  str += nsvg__parseScale( t, str );
1857  else if( strncmp( str, "rotate", 6 ) == 0 )
1858  str += nsvg__parseRotate( t, str );
1859  else if( strncmp( str, "skewX", 5 ) == 0 )
1860  str += nsvg__parseSkewX( t, str );
1861  else if( strncmp( str, "skewY", 5 ) == 0 )
1862  str += nsvg__parseSkewY( t, str );
1863  else
1864  {
1865  ++str;
1866  continue;
1867  }
1868 
1869  nsvg__xformPremultiply( xform, t );
1870  }
1871 }
1872 
1873 
1874 static void nsvg__parseUrl( char* id, const char* str )
1875 {
1876  int i = 0;
1877 
1878  str += 4; // "url(";
1879 
1880  if( *str == '#' )
1881  str++;
1882 
1883  while( i < 63 && *str != ')' )
1884  {
1885  id[i] = *str++;
1886  i++;
1887  }
1888 
1889  id[i] = '\0';
1890 }
1891 
1892 
1893 static char nsvg__parseLineCap( const char* str )
1894 {
1895  if( strcmp( str, "butt" ) == 0 )
1896  return NSVG_CAP_BUTT;
1897  else if( strcmp( str, "round" ) == 0 )
1898  return NSVG_CAP_ROUND;
1899  else if( strcmp( str, "square" ) == 0 )
1900  return NSVG_CAP_SQUARE;
1901 
1902  // TODO: handle inherit.
1903  return NSVG_CAP_BUTT;
1904 }
1905 
1906 
1907 static char nsvg__parseLineJoin( const char* str )
1908 {
1909  if( strcmp( str, "miter" ) == 0 )
1910  return NSVG_JOIN_MITER;
1911  else if( strcmp( str, "round" ) == 0 )
1912  return NSVG_JOIN_ROUND;
1913  else if( strcmp( str, "bevel" ) == 0 )
1914  return NSVG_JOIN_BEVEL;
1915 
1916  // TODO: handle inherit.
1917  return NSVG_JOIN_MITER;
1918 }
1919 
1920 
1921 static char nsvg__parseFillRule( const char* str )
1922 {
1923  if( strcmp( str, "nonzero" ) == 0 )
1924  return NSVG_FILLRULE_NONZERO;
1925  else if( strcmp( str, "evenodd" ) == 0 )
1926  return NSVG_FILLRULE_EVENODD;
1927 
1928  // TODO: handle inherit.
1929  return NSVG_FILLRULE_NONZERO;
1930 }
1931 
1932 
1933 static const char* nsvg__getNextDashItem( const char* s, char* it )
1934 {
1935  int n = 0;
1936 
1937  it[0] = '\0';
1938 
1939  // Skip white spaces and commas
1940  while( *s && (nsvg__isspace( *s ) || *s == ',') )
1941  s++;
1942 
1943  // Advance until whitespace, comma or end.
1944  while( *s && (!nsvg__isspace( *s ) && *s != ',') )
1945  {
1946  if( n < 63 )
1947  it[n++] = *s;
1948 
1949  s++;
1950  }
1951 
1952  it[n++] = '\0';
1953  return s;
1954 }
1955 
1956 
1957 static int nsvg__parseStrokeDashArray( NSVGparser* p, const char* str, float* strokeDashArray )
1958 {
1959  char item[64];
1960  int count = 0, i;
1961  float sum = 0.0f;
1962 
1963  // Handle "none"
1964  if( str[0] == 'n' )
1965  return 0;
1966 
1967  // Parse dashes
1968  while( *str )
1969  {
1970  str = nsvg__getNextDashItem( str, item );
1971 
1972  if( !*item )
1973  break;
1974 
1975  if( count < NSVG_MAX_DASHES )
1976  strokeDashArray[count++] =
1977  fabsf( nsvg__parseCoordinate( p, item, 0.0f, nsvg__actualLength( p ) ) );
1978  }
1979 
1980  for( i = 0; i < count; i++ )
1981  sum += strokeDashArray[i];
1982 
1983  if( sum <= 1e-6f )
1984  count = 0;
1985 
1986  return count;
1987 }
1988 
1989 
1990 static void nsvg__parseStyle( NSVGparser* p, const char* str );
1991 
1992 static int nsvg__parseAttr( NSVGparser* p, const char* name, const char* value )
1993 {
1994  float xform[6];
1995  NSVGattrib* attr = nsvg__getAttr( p );
1996 
1997  if( !attr )
1998  return 0;
1999 
2000  if( strcmp( name, "style" ) == 0 )
2001  {
2002  nsvg__parseStyle( p, value );
2003  }
2004  else if( strcmp( name, "display" ) == 0 )
2005  {
2006  if( strcmp( value, "none" ) == 0 )
2007  attr->visible = 0;
2008 
2009  // Don't reset ->visible on display:inline, one display:none hides the whole subtree
2010  }
2011  else if( strcmp( name, "fill" ) == 0 )
2012  {
2013  if( strcmp( value, "none" ) == 0 )
2014  {
2015  attr->hasFill = 0;
2016  }
2017  else if( strncmp( value, "url(", 4 ) == 0 )
2018  {
2019  attr->hasFill = 2;
2020  nsvg__parseUrl( attr->fillGradient, value );
2021  }
2022  else
2023  {
2024  attr->hasFill = 1;
2025  attr->fillColor = nsvg__parseColor( value );
2026  }
2027  }
2028  else if( strcmp( name, "opacity" ) == 0 )
2029  {
2030  attr->opacity = nsvg__parseOpacity( value );
2031  }
2032  else if( strcmp( name, "fill-opacity" ) == 0 )
2033  {
2034  attr->fillOpacity = nsvg__parseOpacity( value );
2035  }
2036  else if( strcmp( name, "stroke" ) == 0 )
2037  {
2038  if( strcmp( value, "none" ) == 0 )
2039  {
2040  attr->hasStroke = 0;
2041  }
2042  else if( strncmp( value, "url(", 4 ) == 0 )
2043  {
2044  attr->hasStroke = 2;
2045  nsvg__parseUrl( attr->strokeGradient, value );
2046  }
2047  else
2048  {
2049  attr->hasStroke = 1;
2050  attr->strokeColor = nsvg__parseColor( value );
2051  }
2052  }
2053  else if( strcmp( name, "stroke-width" ) == 0 )
2054  {
2055  attr->strokeWidth = nsvg__parseCoordinate( p, value, 0.0f, nsvg__actualLength( p ) );
2056  }
2057  else if( strcmp( name, "stroke-dasharray" ) == 0 )
2058  {
2059  attr->strokeDashCount = nsvg__parseStrokeDashArray( p, value, attr->strokeDashArray );
2060  }
2061  else if( strcmp( name, "stroke-dashoffset" ) == 0 )
2062  {
2063  attr->strokeDashOffset = nsvg__parseCoordinate( p, value, 0.0f, nsvg__actualLength( p ) );
2064  }
2065  else if( strcmp( name, "stroke-opacity" ) == 0 )
2066  {
2067  attr->strokeOpacity = nsvg__parseOpacity( value );
2068  }
2069  else if( strcmp( name, "stroke-linecap" ) == 0 )
2070  {
2071  attr->strokeLineCap = nsvg__parseLineCap( value );
2072  }
2073  else if( strcmp( name, "stroke-linejoin" ) == 0 )
2074  {
2075  attr->strokeLineJoin = nsvg__parseLineJoin( value );
2076  }
2077  else if( strcmp( name, "stroke-miterlimit" ) == 0 )
2078  {
2079  attr->miterLimit = nsvg__parseMiterLimit( value );
2080  }
2081  else if( strcmp( name, "fill-rule" ) == 0 )
2082  {
2083  attr->fillRule = nsvg__parseFillRule( value );
2084  }
2085  else if( strcmp( name, "font-size" ) == 0 )
2086  {
2087  attr->fontSize = nsvg__parseCoordinate( p, value, 0.0f, nsvg__actualLength( p ) );
2088  }
2089  else if( strcmp( name, "transform" ) == 0 )
2090  {
2091  nsvg__parseTransform( xform, value );
2092  nsvg__xformPremultiply( attr->xform, xform );
2093  }
2094  else if( strcmp( name, "stop-color" ) == 0 )
2095  {
2096  attr->stopColor = nsvg__parseColor( value );
2097  }
2098  else if( strcmp( name, "stop-opacity" ) == 0 )
2099  {
2100  attr->stopOpacity = nsvg__parseOpacity( value );
2101  }
2102  else if( strcmp( name, "offset" ) == 0 )
2103  {
2104  attr->stopOffset = nsvg__parseCoordinate( p, value, 0.0f, 1.0f );
2105  }
2106  else if( strcmp( name, "id" ) == 0 )
2107  {
2108  strncpy( attr->id, value, 63 );
2109  attr->id[63] = '\0';
2110  }
2111  else
2112  {
2113  return 0;
2114  }
2115 
2116  return 1;
2117 }
2118 
2119 
2120 static int nsvg__parseNameValue( NSVGparser* p, const char* start, const char* end )
2121 {
2122  const char* str;
2123  const char* val;
2124  char name[512];
2125  char value[512];
2126  int n;
2127 
2128  str = start;
2129 
2130  while( str < end && *str != ':' )
2131  ++str;
2132 
2133  val = str;
2134 
2135  // Right Trim
2136  while( str > start && ( *str == ':' || nsvg__isspace( *str ) ) )
2137  --str;
2138 
2139  ++str;
2140 
2141  n = (int) (str - start);
2142 
2143  if( n > 511 )
2144  n = 511;
2145 
2146  if( n )
2147  memcpy( name, start, n );
2148 
2149  name[n] = 0;
2150 
2151  while( val < end && ( *val == ':' || nsvg__isspace( *val ) ) )
2152  ++val;
2153 
2154  n = (int) (end - val);
2155 
2156  if( n > 511 )
2157  n = 511;
2158 
2159  if( n )
2160  memcpy( value, val, n );
2161 
2162  value[n] = 0;
2163 
2164  return nsvg__parseAttr( p, name, value );
2165 }
2166 
2167 
2168 static void nsvg__parseStyle( NSVGparser* p, const char* str )
2169 {
2170  const char* start;
2171  const char* end;
2172 
2173  while( *str )
2174  {
2175  // Left Trim
2176  while( *str && nsvg__isspace( *str ) )
2177  ++str;
2178 
2179  start = str;
2180 
2181  while( *str && *str != ';' )
2182  ++str;
2183 
2184  end = str;
2185 
2186  // Right Trim
2187  while( end > start && ( *end == ';' || nsvg__isspace( *end ) ) )
2188  --end;
2189 
2190  ++end;
2191 
2192  nsvg__parseNameValue( p, start, end );
2193 
2194  if( *str )
2195  ++str;
2196  }
2197 }
2198 
2199 
2200 static void nsvg__parseAttribs( NSVGparser* p, const char** attr )
2201 {
2202  int i;
2203 
2204  for( i = 0; attr[i]; i += 2 )
2205  {
2206  if( strcmp( attr[i], "style" ) == 0 )
2207  nsvg__parseStyle( p, attr[i + 1] );
2208  else
2209  nsvg__parseAttr( p, attr[i], attr[i + 1] );
2210  }
2211 }
2212 
2213 
2214 static int nsvg__getArgsPerElement( char cmd )
2215 {
2216  switch( cmd )
2217  {
2218  case 'v':
2219  case 'V':
2220  case 'h':
2221  case 'H':
2222  return 1;
2223 
2224  case 'm':
2225  case 'M':
2226  case 'l':
2227  case 'L':
2228  case 't':
2229  case 'T':
2230  return 2;
2231 
2232  case 'q':
2233  case 'Q':
2234  case 's':
2235  case 'S':
2236  return 4;
2237 
2238  case 'c':
2239  case 'C':
2240  return 6;
2241 
2242  case 'a':
2243  case 'A':
2244  return 7;
2245  }
2246 
2247  return 0;
2248 }
2249 
2250 
2251 static void nsvg__pathMoveTo( NSVGparser* p, float* cpx, float* cpy, float* args, int rel )
2252 {
2253  if( rel )
2254  {
2255  *cpx += args[0];
2256  *cpy += args[1];
2257  }
2258  else
2259  {
2260  *cpx = args[0];
2261  *cpy = args[1];
2262  }
2263 
2264  nsvg__moveTo( p, *cpx, *cpy );
2265 }
2266 
2267 
2268 static void nsvg__pathLineTo( NSVGparser* p, float* cpx, float* cpy, float* args, int rel )
2269 {
2270  if( rel )
2271  {
2272  *cpx += args[0];
2273  *cpy += args[1];
2274  }
2275  else
2276  {
2277  *cpx = args[0];
2278  *cpy = args[1];
2279  }
2280 
2281  nsvg__lineTo( p, *cpx, *cpy );
2282 }
2283 
2284 
2285 static void nsvg__pathHLineTo( NSVGparser* p, float* cpx, float* cpy, float* args, int rel )
2286 {
2287  if( rel )
2288  *cpx += args[0];
2289  else
2290  *cpx = args[0];
2291 
2292  nsvg__lineTo( p, *cpx, *cpy );
2293 }
2294 
2295 
2296 static void nsvg__pathVLineTo( NSVGparser* p, float* cpx, float* cpy, float* args, int rel )
2297 {
2298  if( rel )
2299  *cpy += args[0];
2300  else
2301  *cpy = args[0];
2302 
2303  nsvg__lineTo( p, *cpx, *cpy );
2304 }
2305 
2306 
2307 static void nsvg__pathCubicBezTo( NSVGparser* p, float* cpx, float* cpy,
2308  float* cpx2, float* cpy2, float* args, int rel )
2309 {
2310  float x2, y2, cx1, cy1, cx2, cy2;
2311 
2312  if( rel )
2313  {
2314  cx1 = *cpx + args[0];
2315  cy1 = *cpy + args[1];
2316  cx2 = *cpx + args[2];
2317  cy2 = *cpy + args[3];
2318  x2 = *cpx + args[4];
2319  y2 = *cpy + args[5];
2320  }
2321  else
2322  {
2323  cx1 = args[0];
2324  cy1 = args[1];
2325  cx2 = args[2];
2326  cy2 = args[3];
2327  x2 = args[4];
2328  y2 = args[5];
2329  }
2330 
2331  nsvg__cubicBezTo( p, cx1, cy1, cx2, cy2, x2, y2 );
2332 
2333  *cpx2 = cx2;
2334  *cpy2 = cy2;
2335  *cpx = x2;
2336  *cpy = y2;
2337 }
2338 
2339 
2340 static void nsvg__pathCubicBezShortTo( NSVGparser* p, float* cpx, float* cpy,
2341  float* cpx2, float* cpy2, float* args, int rel )
2342 {
2343  float x1, y1, x2, y2, cx1, cy1, cx2, cy2;
2344 
2345  x1 = *cpx;
2346  y1 = *cpy;
2347 
2348  if( rel )
2349  {
2350  cx2 = *cpx + args[0];
2351  cy2 = *cpy + args[1];
2352  x2 = *cpx + args[2];
2353  y2 = *cpy + args[3];
2354  }
2355  else
2356  {
2357  cx2 = args[0];
2358  cy2 = args[1];
2359  x2 = args[2];
2360  y2 = args[3];
2361  }
2362 
2363  cx1 = 2 * x1 - *cpx2;
2364  cy1 = 2 * y1 - *cpy2;
2365 
2366  nsvg__cubicBezTo( p, cx1, cy1, cx2, cy2, x2, y2 );
2367 
2368  *cpx2 = cx2;
2369  *cpy2 = cy2;
2370  *cpx = x2;
2371  *cpy = y2;
2372 }
2373 
2374 
2375 static void nsvg__pathQuadBezTo( NSVGparser* p, float* cpx, float* cpy,
2376  float* cpx2, float* cpy2, float* args, int rel )
2377 {
2378  float x1, y1, x2, y2, cx, cy;
2379  float cx1, cy1, cx2, cy2;
2380 
2381  x1 = *cpx;
2382  y1 = *cpy;
2383 
2384  if( rel )
2385  {
2386  cx = *cpx + args[0];
2387  cy = *cpy + args[1];
2388  x2 = *cpx + args[2];
2389  y2 = *cpy + args[3];
2390  }
2391  else
2392  {
2393  cx = args[0];
2394  cy = args[1];
2395  x2 = args[2];
2396  y2 = args[3];
2397  }
2398 
2399  // Convert to cubic bezier
2400  cx1 = x1 + 2.0f / 3.0f * (cx - x1);
2401  cy1 = y1 + 2.0f / 3.0f * (cy - y1);
2402  cx2 = x2 + 2.0f / 3.0f * (cx - x2);
2403  cy2 = y2 + 2.0f / 3.0f * (cy - y2);
2404 
2405  nsvg__cubicBezTo( p, cx1, cy1, cx2, cy2, x2, y2 );
2406 
2407  *cpx2 = cx;
2408  *cpy2 = cy;
2409  *cpx = x2;
2410  *cpy = y2;
2411 }
2412 
2413 
2414 static void nsvg__pathQuadBezShortTo( NSVGparser* p, float* cpx, float* cpy,
2415  float* cpx2, float* cpy2, float* args, int rel )
2416 {
2417  float x1, y1, x2, y2, cx, cy;
2418  float cx1, cy1, cx2, cy2;
2419 
2420  x1 = *cpx;
2421  y1 = *cpy;
2422 
2423  if( rel )
2424  {
2425  x2 = *cpx + args[0];
2426  y2 = *cpy + args[1];
2427  }
2428  else
2429  {
2430  x2 = args[0];
2431  y2 = args[1];
2432  }
2433 
2434  cx = 2 * x1 - *cpx2;
2435  cy = 2 * y1 - *cpy2;
2436 
2437  // Convert to cubix bezier
2438  cx1 = x1 + 2.0f / 3.0f * (cx - x1);
2439  cy1 = y1 + 2.0f / 3.0f * (cy - y1);
2440  cx2 = x2 + 2.0f / 3.0f * (cx - x2);
2441  cy2 = y2 + 2.0f / 3.0f * (cy - y2);
2442 
2443  nsvg__cubicBezTo( p, cx1, cy1, cx2, cy2, x2, y2 );
2444 
2445  *cpx2 = cx;
2446  *cpy2 = cy;
2447  *cpx = x2;
2448  *cpy = y2;
2449 }
2450 
2451 
2452 static float nsvg__sqr( float x )
2453 {
2454  return x * x;
2455 }
2456 
2457 
2458 static float nsvg__vmag( float x, float y )
2459 {
2460  return sqrtf( x * x + y * y );
2461 }
2462 
2463 
2464 static float nsvg__vecrat( float ux, float uy, float vx, float vy )
2465 {
2466  return (ux * vx + uy * vy) / ( nsvg__vmag( ux, uy ) * nsvg__vmag( vx, vy ) );
2467 }
2468 
2469 
2470 static float nsvg__vecang( float ux, float uy, float vx, float vy )
2471 {
2472  float r = nsvg__vecrat( ux, uy, vx, vy );
2473 
2474  if( r < -1.0f )
2475  r = -1.0f;
2476 
2477  if( r > 1.0f )
2478  r = 1.0f;
2479 
2480  return ( (ux * vy < uy * vx) ? -1.0f : 1.0f ) * acosf( r );
2481 }
2482 
2483 
2484 static void nsvg__pathArcTo( NSVGparser* p, float* cpx, float* cpy, float* args, int rel )
2485 {
2486  // Ported from canvg (https://code.google.com/p/canvg/)
2487  float rx, ry, rotx;
2488  float x1, y1, x2, y2, cx, cy, dx, dy, d;
2489  float x1p, y1p, cxp, cyp, s, sa, sb;
2490  float ux, uy, vx, vy, a1, da;
2491  float x, y, tanx, tany, a, px = 0, py = 0, ptanx = 0, ptany = 0, t[6];
2492  float sinrx, cosrx;
2493  int fa, fs;
2494  int i, ndivs;
2495  float hda, kappa;
2496 
2497  rx = fabsf( args[0] ); // y radius
2498  ry = fabsf( args[1] ); // x radius
2499  rotx = args[2] / 180.0f * NSVG_PI; // x rotation angle
2500  fa = fabsf( args[3] ) > 1e-6 ? 1 : 0; // Large arc
2501  fs = fabsf( args[4] ) > 1e-6 ? 1 : 0; // Sweep direction
2502  x1 = *cpx; // start point
2503  y1 = *cpy;
2504 
2505  if( rel ) // end point
2506  {
2507  x2 = *cpx + args[5];
2508  y2 = *cpy + args[6];
2509  }
2510  else
2511  {
2512  x2 = args[5];
2513  y2 = args[6];
2514  }
2515 
2516  dx = x1 - x2;
2517  dy = y1 - y2;
2518  d = sqrtf( dx * dx + dy * dy );
2519 
2520  if( d < 1e-6f || rx < 1e-6f || ry < 1e-6f )
2521  {
2522  // The arc degenerates to a line
2523  nsvg__lineTo( p, x2, y2 );
2524  *cpx = x2;
2525  *cpy = y2;
2526  return;
2527  }
2528 
2529  sinrx = sinf( rotx );
2530  cosrx = cosf( rotx );
2531 
2532  // Convert to center point parameterization.
2533  // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
2534  // 1) Compute x1', y1'
2535  x1p = cosrx * dx / 2.0f + sinrx * dy / 2.0f;
2536  y1p = -sinrx * dx / 2.0f + cosrx * dy / 2.0f;
2537  d = nsvg__sqr( x1p ) / nsvg__sqr( rx ) + nsvg__sqr( y1p ) / nsvg__sqr( ry );
2538 
2539  if( d > 1 )
2540  {
2541  d = sqrtf( d );
2542  rx *= d;
2543  ry *= d;
2544  }
2545 
2546  // 2) Compute cx', cy'
2547  s = 0.0f;
2548  sa = nsvg__sqr( rx ) * nsvg__sqr( ry ) - nsvg__sqr( rx ) * nsvg__sqr( y1p ) - nsvg__sqr( ry ) *
2549  nsvg__sqr( x1p );
2550  sb = nsvg__sqr( rx ) * nsvg__sqr( y1p ) + nsvg__sqr( ry ) * nsvg__sqr( x1p );
2551 
2552  if( sa < 0.0f )
2553  sa = 0.0f;
2554 
2555  if( sb > 0.0f )
2556  s = sqrtf( sa / sb );
2557 
2558  if( fa == fs )
2559  s = -s;
2560 
2561  cxp = s * rx * y1p / ry;
2562  cyp = s * -ry * x1p / rx;
2563 
2564  // 3) Compute cx,cy from cx',cy'
2565  cx = (x1 + x2) / 2.0f + cosrx * cxp - sinrx * cyp;
2566  cy = (y1 + y2) / 2.0f + sinrx * cxp + cosrx * cyp;
2567 
2568  // 4) Calculate theta1, and delta theta.
2569  ux = (x1p - cxp) / rx;
2570  uy = (y1p - cyp) / ry;
2571  vx = (-x1p - cxp) / rx;
2572  vy = (-y1p - cyp) / ry;
2573  a1 = nsvg__vecang( 1.0f, 0.0f, ux, uy ); // Initial angle
2574  da = nsvg__vecang( ux, uy, vx, vy ); // Delta angle
2575 
2576 // if (vecrat(ux,uy,vx,vy) <= -1.0f) da = NSVG_PI;
2577 // if (vecrat(ux,uy,vx,vy) >= 1.0f) da = 0;
2578 
2579  if( fs == 0 && da > 0 )
2580  da -= 2 * NSVG_PI;
2581  else if( fs == 1 && da < 0 )
2582  da += 2 * NSVG_PI;
2583 
2584  // Approximate the arc using cubic spline segments.
2585  t[0] = cosrx; t[1] = sinrx;
2586  t[2] = -sinrx; t[3] = cosrx;
2587  t[4] = cx; t[5] = cy;
2588 
2589  // Split arc into max 90 degree segments.
2590  // The loop assumes an iteration per end point (including start and end), this +1.
2591  ndivs = (int) (fabsf( da ) / (NSVG_PI * 0.5f) + 1.0f);
2592  hda = (da / (float) ndivs) / 2.0f;
2593  kappa = fabsf( 4.0f / 3.0f * ( 1.0f - cosf( hda ) ) / sinf( hda ) );
2594 
2595  if( da < 0.0f )
2596  kappa = -kappa;
2597 
2598  for( i = 0; i <= ndivs; i++ )
2599  {
2600  a = a1 + da * ( (float) i / (float) ndivs );
2601  dx = cosf( a );
2602  dy = sinf( a );
2603  nsvg__xformPoint( &x, &y, dx * rx, dy * ry, t ); // position
2604  nsvg__xformVec( &tanx, &tany, -dy * rx * kappa, dx * ry * kappa, t ); // tangent
2605 
2606  if( i > 0 )
2607  nsvg__cubicBezTo( p, px + ptanx, py + ptany, x - tanx, y - tany, x, y );
2608 
2609  px = x;
2610  py = y;
2611  ptanx = tanx;
2612  ptany = tany;
2613  }
2614 
2615  *cpx = x2;
2616  *cpy = y2;
2617 }
2618 
2619 
2620 static void nsvg__parsePath( NSVGparser* p, const char** attr )
2621 {
2622  const char* s = NULL;
2623  char cmd = '\0';
2624  float args[10];
2625  int nargs;
2626  int rargs = 0;
2627  float cpx, cpy, cpx2, cpy2;
2628  const char* tmp[4];
2629  char closedFlag;
2630  int i;
2631  char item[64];
2632 
2633  for( i = 0; attr[i]; i += 2 )
2634  {
2635  if( strcmp( attr[i], "d" ) == 0 )
2636  {
2637  s = attr[i + 1];
2638  }
2639  else
2640  {
2641  tmp[0] = attr[i];
2642  tmp[1] = attr[i + 1];
2643  tmp[2] = 0;
2644  tmp[3] = 0;
2645  nsvg__parseAttribs( p, tmp );
2646  }
2647  }
2648 
2649  if( s )
2650  {
2651  nsvg__resetPath( p );
2652  cpx = 0; cpy = 0;
2653  cpx2 = 0; cpy2 = 0;
2654  closedFlag = 0;
2655  nargs = 0;
2656 
2657  while( *s )
2658  {
2659  s = nsvg__getNextPathItem( s, item );
2660 
2661  if( !*item )
2662  break;
2663 
2664  if( nsvg__isnum( item[0] ) )
2665  {
2666  if( nargs < 10 )
2667  args[nargs++] = (float) nsvg__atof( item );
2668 
2669  if( nargs >= rargs )
2670  {
2671  switch( cmd )
2672  {
2673  case 'm':
2674  case 'M':
2675  nsvg__pathMoveTo( p, &cpx, &cpy, args, cmd == 'm' ? 1 : 0 );
2676  // Moveto can be followed by multiple coordinate pairs,
2677  // which should be treated as linetos.
2678  cmd = (cmd == 'm') ? 'l' : 'L';
2679  rargs = nsvg__getArgsPerElement( cmd );
2680  cpx2 = cpx; cpy2 = cpy;
2681  break;
2682 
2683  case 'l':
2684  case 'L':
2685  nsvg__pathLineTo( p, &cpx, &cpy, args, cmd == 'l' ? 1 : 0 );
2686  cpx2 = cpx; cpy2 = cpy;
2687  break;
2688 
2689  case 'H':
2690  case 'h':
2691  nsvg__pathHLineTo( p, &cpx, &cpy, args, cmd == 'h' ? 1 : 0 );
2692  cpx2 = cpx; cpy2 = cpy;
2693  break;
2694 
2695  case 'V':
2696  case 'v':
2697  nsvg__pathVLineTo( p, &cpx, &cpy, args, cmd == 'v' ? 1 : 0 );
2698  cpx2 = cpx; cpy2 = cpy;
2699  break;
2700 
2701  case 'C':
2702  case 'c':
2703  nsvg__pathCubicBezTo( p, &cpx, &cpy, &cpx2, &cpy2, args,
2704  cmd == 'c' ? 1 : 0 );
2705  break;
2706 
2707  case 'S':
2708  case 's':
2710  &cpx,
2711  &cpy,
2712  &cpx2,
2713  &cpy2,
2714  args,
2715  cmd == 's' ? 1 : 0 );
2716  break;
2717 
2718  case 'Q':
2719  case 'q':
2720  nsvg__pathQuadBezTo( p, &cpx, &cpy, &cpx2, &cpy2, args,
2721  cmd == 'q' ? 1 : 0 );
2722  break;
2723 
2724  case 'T':
2725  case 't':
2727  &cpx,
2728  &cpy,
2729  &cpx2,
2730  &cpy2,
2731  args,
2732  cmd == 't' ? 1 : 0 );
2733  break;
2734 
2735  case 'A':
2736  case 'a':
2737  nsvg__pathArcTo( p, &cpx, &cpy, args, cmd == 'a' ? 1 : 0 );
2738  cpx2 = cpx; cpy2 = cpy;
2739  break;
2740 
2741  default:
2742 
2743  if( nargs >= 2 )
2744  {
2745  cpx = args[nargs - 2];
2746  cpy = args[nargs - 1];
2747  cpx2 = cpx; cpy2 = cpy;
2748  }
2749 
2750  break;
2751  }
2752 
2753  nargs = 0;
2754  }
2755  }
2756  else
2757  {
2758  cmd = item[0];
2759  rargs = nsvg__getArgsPerElement( cmd );
2760 
2761  if( cmd == 'M' || cmd == 'm' )
2762  {
2763  // Commit path.
2764  if( p->npts > 0 )
2765  nsvg__addPath( p, closedFlag );
2766 
2767  // Start new subpath.
2768  nsvg__resetPath( p );
2769  closedFlag = 0;
2770  nargs = 0;
2771  }
2772  else if( cmd == 'Z' || cmd == 'z' )
2773  {
2774  closedFlag = 1;
2775 
2776  // Commit path.
2777  if( p->npts > 0 )
2778  {
2779  // Move current point to first point
2780  cpx = p->pts[0];
2781  cpy = p->pts[1];
2782  cpx2 = cpx; cpy2 = cpy;
2783  nsvg__addPath( p, closedFlag );
2784  }
2785 
2786  // Start new subpath.
2787  nsvg__resetPath( p );
2788  nsvg__moveTo( p, cpx, cpy );
2789  closedFlag = 0;
2790  nargs = 0;
2791  }
2792  }
2793  }
2794 
2795  // Commit path.
2796  if( p->npts )
2797  nsvg__addPath( p, closedFlag );
2798  }
2799 
2800  nsvg__addShape( p );
2801 }
2802 
2803 
2804 static void nsvg__parseRect( NSVGparser* p, const char** attr )
2805 {
2806  float x = 0.0f;
2807  float y = 0.0f;
2808  float w = 0.0f;
2809  float h = 0.0f;
2810  float rx = -1.0f; // marks not set
2811  float ry = -1.0f;
2812  int i;
2813 
2814  for( i = 0; attr[i]; i += 2 )
2815  {
2816  if( !nsvg__parseAttr( p, attr[i], attr[i + 1] ) )
2817  {
2818  if( strcmp( attr[i], "x" ) == 0 )
2819  x = nsvg__parseCoordinate( p, attr[i + 1], nsvg__actualOrigX(
2820  p ), nsvg__actualWidth( p ) );
2821 
2822  if( strcmp( attr[i], "y" ) == 0 )
2823  y = nsvg__parseCoordinate( p, attr[i + 1], nsvg__actualOrigY(
2824  p ), nsvg__actualHeight( p ) );
2825 
2826  if( strcmp( attr[i], "width" ) == 0 )
2827  w = nsvg__parseCoordinate( p, attr[i + 1], 0.0f, nsvg__actualWidth( p ) );
2828 
2829  if( strcmp( attr[i], "height" ) == 0 )
2830  h = nsvg__parseCoordinate( p, attr[i + 1], 0.0f, nsvg__actualHeight( p ) );
2831 
2832  if( strcmp( attr[i], "rx" ) == 0 )
2833  rx = fabsf( nsvg__parseCoordinate( p, attr[i + 1], 0.0f, nsvg__actualWidth( p ) ) );
2834 
2835 
2836  if( strcmp( attr[i], "ry" ) == 0 )
2837  ry =
2838  fabsf( nsvg__parseCoordinate( p, attr[i + 1], 0.0f, nsvg__actualHeight( p ) ) );
2839 
2840  }
2841  }
2842 
2843  if( rx < 0.0f && ry > 0.0f )
2844  rx = ry;
2845 
2846  if( ry < 0.0f && rx > 0.0f )
2847  ry = rx;
2848 
2849  if( rx < 0.0f )
2850  rx = 0.0f;
2851 
2852  if( ry < 0.0f )
2853  ry = 0.0f;
2854 
2855  if( rx > w / 2.0f )
2856  rx = w / 2.0f;
2857 
2858  if( ry > h / 2.0f )
2859  ry = h / 2.0f;
2860 
2861  if( w != 0.0f && h != 0.0f )
2862  {
2863  nsvg__resetPath( p );
2864 
2865  if( rx < 0.00001f || ry < 0.0001f )
2866  {
2867  nsvg__moveTo( p, x, y );
2868  nsvg__lineTo( p, x + w, y );
2869  nsvg__lineTo( p, x + w, y + h );
2870  nsvg__lineTo( p, x, y + h );
2871  }
2872  else
2873  {
2874  // Rounded rectangle
2875  nsvg__moveTo( p, x + rx, y );
2876  nsvg__lineTo( p, x + w - rx, y );
2877  nsvg__cubicBezTo( p, x + w - rx * (1 - NSVG_KAPPA90), y, x + w,
2878  y + ry * (1 - NSVG_KAPPA90), x + w, y + ry );
2879  nsvg__lineTo( p, x + w, y + h - ry );
2880  nsvg__cubicBezTo( p, x + w, y + h - ry * (1 - NSVG_KAPPA90),
2881  x + w - rx * (1 - NSVG_KAPPA90), y + h, x + w - rx, y + h );
2882  nsvg__lineTo( p, x + rx, y + h );
2883  nsvg__cubicBezTo( p, x + rx * (1 - NSVG_KAPPA90), y + h, x,
2884  y + h - ry * (1 - NSVG_KAPPA90), x, y + h - ry );
2885  nsvg__lineTo( p, x, y + ry );
2886  nsvg__cubicBezTo( p,
2887  x,
2888  y + ry * (1 - NSVG_KAPPA90),
2889  x + rx * (1 - NSVG_KAPPA90),
2890  y,
2891  x + rx,
2892  y );
2893  }
2894 
2895  nsvg__addPath( p, 1 );
2896 
2897  nsvg__addShape( p );
2898  }
2899 }
2900 
2901 
2902 static void nsvg__parseCircle( NSVGparser* p, const char** attr )
2903 {
2904  float cx = 0.0f;
2905  float cy = 0.0f;
2906  float r = 0.0f;
2907  int i;
2908 
2909  for( i = 0; attr[i]; i += 2 )
2910  {
2911  if( !nsvg__parseAttr( p, attr[i], attr[i + 1] ) )
2912  {
2913  if( strcmp( attr[i], "cx" ) == 0 )
2914  cx = nsvg__parseCoordinate( p, attr[i + 1], nsvg__actualOrigX(
2915  p ), nsvg__actualWidth( p ) );
2916 
2917  if( strcmp( attr[i], "cy" ) == 0 )
2918  cy = nsvg__parseCoordinate( p, attr[i + 1], nsvg__actualOrigY(
2919  p ), nsvg__actualHeight( p ) );
2920 
2921  if( strcmp( attr[i], "r" ) == 0 )
2922  r = fabsf( nsvg__parseCoordinate( p, attr[i + 1], 0.0f, nsvg__actualLength( p ) ) );
2923 
2924  }
2925  }
2926 
2927  if( r > 0.0f )
2928  {
2929  nsvg__resetPath( p );
2930 
2931  nsvg__moveTo( p, cx + r, cy );
2932  nsvg__cubicBezTo( p,
2933  cx + r,
2934  cy + r * NSVG_KAPPA90,
2935  cx + r * NSVG_KAPPA90,
2936  cy + r,
2937  cx,
2938  cy + r );
2939  nsvg__cubicBezTo( p,
2940  cx - r * NSVG_KAPPA90,
2941  cy + r,
2942  cx - r,
2943  cy + r * NSVG_KAPPA90,
2944  cx - r,
2945  cy );
2946  nsvg__cubicBezTo( p,
2947  cx - r,
2948  cy - r * NSVG_KAPPA90,
2949  cx - r * NSVG_KAPPA90,
2950  cy - r,
2951  cx,
2952  cy - r );
2953  nsvg__cubicBezTo( p,
2954  cx + r * NSVG_KAPPA90,
2955  cy - r,
2956  cx + r,
2957  cy - r * NSVG_KAPPA90,
2958  cx + r,
2959  cy );
2960 
2961  nsvg__addPath( p, 1 );
2962 
2963  nsvg__addShape( p );
2964  }
2965 }
2966 
2967 
2968 static void nsvg__parseEllipse( NSVGparser* p, const char** attr )
2969 {
2970  float cx = 0.0f;
2971  float cy = 0.0f;
2972  float rx = 0.0f;
2973  float ry = 0.0f;
2974  int i;
2975 
2976  for( i = 0; attr[i]; i += 2 )
2977  {
2978  if( !nsvg__parseAttr( p, attr[i], attr[i + 1] ) )
2979  {
2980  if( strcmp( attr[i], "cx" ) == 0 )
2981  cx = nsvg__parseCoordinate( p, attr[i + 1], nsvg__actualOrigX(
2982  p ), nsvg__actualWidth( p ) );
2983 
2984  if( strcmp( attr[i], "cy" ) == 0 )
2985  cy = nsvg__parseCoordinate( p, attr[i + 1], nsvg__actualOrigY(
2986  p ), nsvg__actualHeight( p ) );
2987 
2988  if( strcmp( attr[i], "rx" ) == 0 )
2989  rx = fabsf( nsvg__parseCoordinate( p, attr[i + 1], 0.0f, nsvg__actualWidth( p ) ) );
2990 
2991 
2992  if( strcmp( attr[i], "ry" ) == 0 )
2993  ry =
2994  fabsf( nsvg__parseCoordinate( p, attr[i + 1], 0.0f, nsvg__actualHeight( p ) ) );
2995 
2996  }
2997  }
2998 
2999  if( rx > 0.0f && ry > 0.0f )
3000  {
3001  nsvg__resetPath( p );
3002 
3003  nsvg__moveTo( p, cx + rx, cy );
3004  nsvg__cubicBezTo( p,
3005  cx + rx,
3006  cy + ry * NSVG_KAPPA90,
3007  cx + rx * NSVG_KAPPA90,
3008  cy + ry,
3009  cx,
3010  cy + ry );
3011  nsvg__cubicBezTo( p,
3012  cx - rx * NSVG_KAPPA90,
3013  cy + ry,
3014  cx - rx,
3015  cy + ry * NSVG_KAPPA90,
3016  cx - rx,
3017  cy );
3018  nsvg__cubicBezTo( p,
3019  cx - rx,
3020  cy - ry * NSVG_KAPPA90,
3021  cx - rx * NSVG_KAPPA90,
3022  cy - ry,
3023  cx,
3024  cy - ry );
3025  nsvg__cubicBezTo( p,
3026  cx + rx * NSVG_KAPPA90,
3027  cy - ry,
3028  cx + rx,
3029  cy - ry * NSVG_KAPPA90,
3030  cx + rx,
3031  cy );
3032 
3033  nsvg__addPath( p, 1 );
3034 
3035  nsvg__addShape( p );
3036  }
3037 }
3038 
3039 
3040 static void nsvg__parseLine( NSVGparser* p, const char** attr )
3041 {
3042  float x1 = 0.0;
3043  float y1 = 0.0;
3044  float x2 = 0.0;
3045  float y2 = 0.0;
3046  int i;
3047 
3048  for( i = 0; attr[i]; i += 2 )
3049  {
3050  if( !nsvg__parseAttr( p, attr[i], attr[i + 1] ) )
3051  {
3052  if( strcmp( attr[i], "x1" ) == 0 )
3053  x1 = nsvg__parseCoordinate( p, attr[i + 1], nsvg__actualOrigX(
3054  p ), nsvg__actualWidth( p ) );
3055 
3056  if( strcmp( attr[i], "y1" ) == 0 )
3057  y1 = nsvg__parseCoordinate( p, attr[i + 1], nsvg__actualOrigY(
3058  p ), nsvg__actualHeight( p ) );
3059 
3060  if( strcmp( attr[i], "x2" ) == 0 )
3061  x2 = nsvg__parseCoordinate( p, attr[i + 1], nsvg__actualOrigX(
3062  p ), nsvg__actualWidth( p ) );
3063 
3064  if( strcmp( attr[i], "y2" ) == 0 )
3065  y2 = nsvg__parseCoordinate( p, attr[i + 1], nsvg__actualOrigY(
3066  p ), nsvg__actualHeight( p ) );
3067  }
3068  }
3069 
3070  nsvg__resetPath( p );
3071 
3072  nsvg__moveTo( p, x1, y1 );
3073  nsvg__lineTo( p, x2, y2 );
3074 
3075  nsvg__addPath( p, 0 );
3076 
3077  nsvg__addShape( p );
3078 }
3079 
3080 
3081 static void nsvg__parsePoly( NSVGparser* p, const char** attr, int closeFlag )
3082 {
3083  int i;
3084  const char* s;
3085  float args[2];
3086  int nargs, npts = 0;
3087  char item[64];
3088 
3089  nsvg__resetPath( p );
3090 
3091  for( i = 0; attr[i]; i += 2 )
3092  {
3093  if( !nsvg__parseAttr( p, attr[i], attr[i + 1] ) )
3094  {
3095  if( strcmp( attr[i], "points" ) == 0 )
3096  {
3097  s = attr[i + 1];
3098  nargs = 0;
3099 
3100  while( *s )
3101  {
3102  s = nsvg__getNextPathItem( s, item );
3103  args[nargs++] = (float) nsvg__atof( item );
3104 
3105  if( nargs >= 2 )
3106  {
3107  if( npts == 0 )
3108  nsvg__moveTo( p, args[0], args[1] );
3109  else
3110  nsvg__lineTo( p, args[0], args[1] );
3111 
3112  nargs = 0;
3113  npts++;
3114  }
3115  }
3116  }
3117  }
3118  }
3119 
3120  nsvg__addPath( p, (char) closeFlag );
3121 
3122  nsvg__addShape( p );
3123 }
3124 
3125 
3126 static void nsvg__parseSVG( NSVGparser* p, const char** attr )
3127 {
3128  int i;
3129 
3130  for( i = 0; attr[i]; i += 2 )
3131  {
3132  if( !nsvg__parseAttr( p, attr[i], attr[i + 1] ) )
3133  {
3134  if( strcmp( attr[i], "width" ) == 0 )
3135  {
3136  p->image->width = nsvg__parseCoordinate( p, attr[i + 1], 0.0f, 0.0f );
3137  }
3138  else if( strcmp( attr[i], "height" ) == 0 )
3139  {
3140  p->image->height = nsvg__parseCoordinate( p, attr[i + 1], 0.0f, 0.0f );
3141  }
3142  else if( strcmp( attr[i], "viewBox" ) == 0 )
3143  {
3144  sscanf( attr[i + 1],
3145  "%f%*[%%, \t]%f%*[%%, \t]%f%*[%%, \t]%f",
3146  &p->viewMinx,
3147  &p->viewMiny,
3148  &p->viewWidth,
3149  &p->viewHeight );
3150  }
3151  else if( strcmp( attr[i], "preserveAspectRatio" ) == 0 )
3152  {
3153  if( strstr( attr[i + 1], "none" ) != 0 )
3154  {
3155  // No uniform scaling
3157  }
3158  else
3159  {
3160  // Parse X align
3161  if( strstr( attr[i + 1], "xMin" ) != 0 )
3162  p->alignX = NSVG_ALIGN_MIN;
3163  else if( strstr( attr[i + 1], "xMid" ) != 0 )
3164  p->alignX = NSVG_ALIGN_MID;
3165  else if( strstr( attr[i + 1], "xMax" ) != 0 )
3166  p->alignX = NSVG_ALIGN_MAX;
3167 
3168  // Parse X align
3169  if( strstr( attr[i + 1], "yMin" ) != 0 )
3170  p->alignY = NSVG_ALIGN_MIN;
3171  else if( strstr( attr[i + 1], "yMid" ) != 0 )
3172  p->alignY = NSVG_ALIGN_MID;
3173  else if( strstr( attr[i + 1], "yMax" ) != 0 )
3174  p->alignY = NSVG_ALIGN_MAX;
3175 
3176  // Parse meet/slice
3178 
3179  if( strstr( attr[i + 1], "slice" ) != 0 )
3181  }
3182  }
3183  }
3184  }
3185 }
3186 
3187 
3188 static void nsvg__parseGradient( NSVGparser* p, const char** attr, char type )
3189 {
3190  int i;
3191  NSVGgradientData* grad = (NSVGgradientData*) malloc( sizeof(NSVGgradientData) );
3192 
3193  if( grad == NULL )
3194  return;
3195 
3196  memset( grad, 0, sizeof(NSVGgradientData) );
3197  grad->units = NSVG_OBJECT_SPACE;
3198  grad->type = type;
3199 
3200  if( grad->type == NSVG_PAINT_LINEAR_GRADIENT )
3201  {
3202  grad->linear.x1 = nsvg__coord( 0.0f, NSVG_UNITS_PERCENT );
3203  grad->linear.y1 = nsvg__coord( 0.0f, NSVG_UNITS_PERCENT );
3204  grad->linear.x2 = nsvg__coord( 100.0f, NSVG_UNITS_PERCENT );
3205  grad->linear.y2 = nsvg__coord( 0.0f, NSVG_UNITS_PERCENT );
3206  }
3207  else if( grad->type == NSVG_PAINT_RADIAL_GRADIENT )
3208  {
3209  grad->radial.cx = nsvg__coord( 50.0f, NSVG_UNITS_PERCENT );
3210  grad->radial.cy = nsvg__coord( 50.0f, NSVG_UNITS_PERCENT );
3211  grad->radial.r = nsvg__coord( 50.0f, NSVG_UNITS_PERCENT );
3212  }
3213 
3214  nsvg__xformIdentity( grad->xform );
3215 
3216  for( i = 0; attr[i]; i += 2 )
3217  {
3218  if( strcmp( attr[i], "id" ) == 0 )
3219  {
3220  strncpy( grad->id, attr[i + 1], 63 );
3221  grad->id[63] = '\0';
3222  }
3223  else if( !nsvg__parseAttr( p, attr[i], attr[i + 1] ) )
3224  {
3225  if( strcmp( attr[i], "gradientUnits" ) == 0 )
3226  {
3227  if( strcmp( attr[i + 1], "objectBoundingBox" ) == 0 )
3228  grad->units = NSVG_OBJECT_SPACE;
3229  else
3230  grad->units = NSVG_USER_SPACE;
3231  }
3232  else if( strcmp( attr[i], "gradientTransform" ) == 0 )
3233  {
3234  nsvg__parseTransform( grad->xform, attr[i + 1] );
3235  }
3236  else if( strcmp( attr[i], "cx" ) == 0 )
3237  {
3238  grad->radial.cx = nsvg__parseCoordinateRaw( attr[i + 1] );
3239  }
3240  else if( strcmp( attr[i], "cy" ) == 0 )
3241  {
3242  grad->radial.cy = nsvg__parseCoordinateRaw( attr[i + 1] );
3243  }
3244  else if( strcmp( attr[i], "r" ) == 0 )
3245  {
3246  grad->radial.r = nsvg__parseCoordinateRaw( attr[i + 1] );
3247  }
3248  else if( strcmp( attr[i], "fx" ) == 0 )
3249  {
3250  grad->radial.fx = nsvg__parseCoordinateRaw( attr[i + 1] );
3251  }
3252  else if( strcmp( attr[i], "fy" ) == 0 )
3253  {
3254  grad->radial.fy = nsvg__parseCoordinateRaw( attr[i + 1] );
3255  }
3256  else if( strcmp( attr[i], "x1" ) == 0 )
3257  {
3258  grad->linear.x1 = nsvg__parseCoordinateRaw( attr[i + 1] );
3259  }
3260  else if( strcmp( attr[i], "y1" ) == 0 )
3261  {
3262  grad->linear.y1 = nsvg__parseCoordinateRaw( attr[i + 1] );
3263  }
3264  else if( strcmp( attr[i], "x2" ) == 0 )
3265  {
3266  grad->linear.x2 = nsvg__parseCoordinateRaw( attr[i + 1] );
3267  }
3268  else if( strcmp( attr[i], "y2" ) == 0 )
3269  {
3270  grad->linear.y2 = nsvg__parseCoordinateRaw( attr[i + 1] );
3271  }
3272  else if( strcmp( attr[i], "spreadMethod" ) == 0 )
3273  {
3274  if( strcmp( attr[i + 1], "pad" ) == 0 )
3275  grad->spread = NSVG_SPREAD_PAD;
3276  else if( strcmp( attr[i + 1], "reflect" ) == 0 )
3277  grad->spread = NSVG_SPREAD_REFLECT;
3278  else if( strcmp( attr[i + 1], "repeat" ) == 0 )
3279  grad->spread = NSVG_SPREAD_REPEAT;
3280  }
3281  else if( strcmp( attr[i], "xlink:href" ) == 0 )
3282  {
3283  const char* href = attr[i + 1];
3284  strncpy( grad->ref, href + 1, 62 );
3285  grad->ref[62] = '\0';
3286  }
3287  }
3288  }
3289 
3290  grad->next = p->gradients;
3291  p->gradients = grad;
3292 }
3293 
3294 
3295 static void nsvg__parseGradientStop( NSVGparser* p, const char** attr )
3296 {
3297  NSVGattrib* curAttr = nsvg__getAttr( p );
3298  NSVGgradientData* grad;
3299  NSVGgradientStop* stop;
3300  int i, idx;
3301 
3302  curAttr->stopOffset = 0;
3303  curAttr->stopColor = 0;
3304  curAttr->stopOpacity = 1.0f;
3305 
3306  for( i = 0; attr[i]; i += 2 )
3307  {
3308  nsvg__parseAttr( p, attr[i], attr[i + 1] );
3309  }
3310 
3311  // Add stop to the last gradient.
3312  grad = p->gradients;
3313 
3314  if( grad == NULL )
3315  return;
3316 
3317  grad->nstops++;
3318  grad->stops =
3319  (NSVGgradientStop*) realloc( grad->stops, sizeof(NSVGgradientStop) * grad->nstops );
3320 
3321  if( grad->stops == NULL )
3322  return;
3323 
3324  // Insert
3325  idx = grad->nstops - 1;
3326 
3327  for( i = 0; i < grad->nstops - 1; i++ )
3328  {
3329  if( curAttr->stopOffset < grad->stops[i].offset )
3330  {
3331  idx = i;
3332  break;
3333  }
3334  }
3335 
3336  if( idx != grad->nstops - 1 )
3337  {
3338  for( i = grad->nstops - 1; i > idx; i-- )
3339  grad->stops[i] = grad->stops[i - 1];
3340  }
3341 
3342  stop = &grad->stops[idx];
3343  stop->color = curAttr->stopColor;
3344  stop->color |= (unsigned int) (curAttr->stopOpacity * 255) << 24;
3345  stop->offset = curAttr->stopOffset;
3346 }
3347 
3348 
3349 static void nsvg__startElement( void* ud, const char* el, const char** attr )
3350 {
3351  NSVGparser* p = (NSVGparser*) ud;
3352 
3353  if( p->defsFlag )
3354  {
3355  // Skip everything but gradients in defs
3356  if( strcmp( el, "linearGradient" ) == 0 )
3357  {
3359  }
3360  else if( strcmp( el, "radialGradient" ) == 0 )
3361  {
3363  }
3364  else if( strcmp( el, "stop" ) == 0 )
3365  {
3366  nsvg__parseGradientStop( p, attr );
3367  }
3368 
3369  return;
3370  }
3371 
3372  if( strcmp( el, "g" ) == 0 )
3373  {
3374  nsvg__pushAttr( p );
3375  nsvg__parseAttribs( p, attr );
3376  }
3377  else if( strcmp( el, "path" ) == 0 )
3378  {
3379  if( p->pathFlag ) // Do not allow nested paths.
3380  return;
3381 
3382  nsvg__pushAttr( p );
3383  nsvg__parsePath( p, attr );
3384  nsvg__popAttr( p );
3385  }
3386  else if( strcmp( el, "rect" ) == 0 )
3387  {
3388  nsvg__pushAttr( p );
3389  nsvg__parseRect( p, attr );
3390  nsvg__popAttr( p );
3391  }
3392  else if( strcmp( el, "circle" ) == 0 )
3393  {
3394  nsvg__pushAttr( p );
3395  nsvg__parseCircle( p, attr );
3396  nsvg__popAttr( p );
3397  }
3398  else if( strcmp( el, "ellipse" ) == 0 )
3399  {
3400  nsvg__pushAttr( p );
3401  nsvg__parseEllipse( p, attr );
3402  nsvg__popAttr( p );
3403  }
3404  else if( strcmp( el, "line" ) == 0 )
3405  {
3406  nsvg__pushAttr( p );
3407  nsvg__parseLine( p, attr );
3408  nsvg__popAttr( p );
3409  }
3410  else if( strcmp( el, "polyline" ) == 0 )
3411  {
3412  nsvg__pushAttr( p );
3413  nsvg__parsePoly( p, attr, 0 );
3414  nsvg__popAttr( p );
3415  }
3416  else if( strcmp( el, "polygon" ) == 0 )
3417  {
3418  nsvg__pushAttr( p );
3419  nsvg__parsePoly( p, attr, 1 );
3420  nsvg__popAttr( p );
3421  }
3422  else if( strcmp( el, "linearGradient" ) == 0 )
3423  {
3425  }
3426  else if( strcmp( el, "radialGradient" ) == 0 )
3427  {
3429  }
3430  else if( strcmp( el, "stop" ) == 0 )
3431  {
3432  nsvg__parseGradientStop( p, attr );
3433  }
3434  else if( strcmp( el, "defs" ) == 0 )
3435  {
3436  p->defsFlag = 1;
3437  }
3438  else if( strcmp( el, "svg" ) == 0 )
3439  {
3440  nsvg__parseSVG( p, attr );
3441  }
3442 }
3443 
3444 
3445 static void nsvg__endElement( void* ud, const char* el )
3446 {
3447  NSVGparser* p = (NSVGparser*) ud;
3448 
3449  if( strcmp( el, "g" ) == 0 )
3450  {
3451  nsvg__popAttr( p );
3452  }
3453  else if( strcmp( el, "path" ) == 0 )
3454  {
3455  p->pathFlag = 0;
3456  }
3457  else if( strcmp( el, "defs" ) == 0 )
3458  {
3459  p->defsFlag = 0;
3460  }
3461 }
3462 
3463 
3464 static void nsvg__content( void* ud, const char* s )
3465 {
3466  NSVG_NOTUSED( ud );
3467  NSVG_NOTUSED( s );
3468  // empty
3469 }
3470 
3471 
3472 static void nsvg__imageBounds( NSVGparser* p, float* bounds )
3473 {
3474  NSVGshape* shape;
3475 
3476  shape = p->image->shapes;
3477 
3478  if( shape == NULL )
3479  {
3480  bounds[0] = bounds[1] = bounds[2] = bounds[3] = 0.0;
3481  return;
3482  }
3483 
3484  bounds[0] = shape->bounds[0];
3485  bounds[1] = shape->bounds[1];
3486  bounds[2] = shape->bounds[2];
3487  bounds[3] = shape->bounds[3];
3488 
3489  for( shape = shape->next; shape != NULL; shape = shape->next )
3490  {
3491  bounds[0] = nsvg__minf( bounds[0], shape->bounds[0] );
3492  bounds[1] = nsvg__minf( bounds[1], shape->bounds[1] );
3493  bounds[2] = nsvg__maxf( bounds[2], shape->bounds[2] );
3494  bounds[3] = nsvg__maxf( bounds[3], shape->bounds[3] );
3495  }
3496 }
3497 
3498 
3499 static float nsvg__viewAlign( float content, float container, int type )
3500 {
3501  if( type == NSVG_ALIGN_MIN )
3502  return 0;
3503  else if( type == NSVG_ALIGN_MAX )
3504  return container - content;
3505 
3506  // mid
3507  return (container - content) * 0.5f;
3508 }
3509 
3510 
3511 static void nsvg__scaleGradient( NSVGgradient* grad, float tx, float ty, float sx, float sy )
3512 {
3513  float t[6];
3514 
3515  nsvg__xformSetTranslation( t, tx, ty );
3516  nsvg__xformMultiply( grad->xform, t );
3517 
3518  nsvg__xformSetScale( t, sx, sy );
3519  nsvg__xformMultiply( grad->xform, t );
3520 }
3521 
3522 
3523 static void nsvg__scaleToViewbox( NSVGparser* p, const char* units )
3524 {
3525  NSVGshape* shape;
3526  NSVGpath* path;
3527  float tx, ty, sx, sy, us, bounds[4], t[6], avgs;
3528  int i;
3529  float* pt;
3530 
3531  // Guess image size if not set completely.
3532  nsvg__imageBounds( p, bounds );
3533 
3534  if( p->viewWidth == 0 )
3535  {
3536  if( p->image->width > 0 )
3537  {
3538  p->viewWidth = p->image->width;
3539  }
3540  else
3541  {
3542  p->viewMinx = bounds[0];
3543  p->viewWidth = bounds[2] - bounds[0];
3544  }
3545  }
3546 
3547  if( p->viewHeight == 0 )
3548  {
3549  if( p->image->height > 0 )
3550  {
3551  p->viewHeight = p->image->height;
3552  }
3553  else
3554  {
3555  p->viewMiny = bounds[1];
3556  p->viewHeight = bounds[3] - bounds[1];
3557  }
3558  }
3559 
3560  if( p->image->width == 0 )
3561  p->image->width = p->viewWidth;
3562 
3563  if( p->image->height == 0 )
3564  p->image->height = p->viewHeight;
3565 
3566  tx = -p->viewMinx;
3567  ty = -p->viewMiny;
3568  sx = p->viewWidth > 0 ? p->image->width / p->viewWidth : 0;
3569  sy = p->viewHeight > 0 ? p->image->height / p->viewHeight : 0;
3570  // Unit scaling
3571  us = 1.0f /
3572  nsvg__convertToPixels( p, nsvg__coord( 1.0f, nsvg__parseUnits( units ) ), 0.0f, 1.0f );
3573 
3574  // Fix aspect ratio
3575  if( p->alignType == NSVG_ALIGN_MEET )
3576  {
3577  // fit whole image into viewbox
3578  sx = sy = nsvg__minf( sx, sy );
3579  tx += nsvg__viewAlign( p->viewWidth * sx, p->image->width, p->alignX ) / sx;
3580  ty += nsvg__viewAlign( p->viewHeight * sy, p->image->height, p->alignY ) / sy;
3581  }
3582  else if( p->alignType == NSVG_ALIGN_SLICE )
3583  {
3584  // fill whole viewbox with image
3585  sx = sy = nsvg__maxf( sx, sy );
3586  tx += nsvg__viewAlign( p->viewWidth * sx, p->image->width, p->alignX ) / sx;
3587  ty += nsvg__viewAlign( p->viewHeight * sy, p->image->height, p->alignY ) / sy;
3588  }
3589 
3590  // Transform
3591  sx *= us;
3592  sy *= us;
3593  avgs = (sx + sy) / 2.0f;
3594 
3595  for( shape = p->image->shapes; shape != NULL; shape = shape->next )
3596  {
3597  shape->bounds[0] = (shape->bounds[0] + tx) * sx;
3598  shape->bounds[1] = (shape->bounds[1] + ty) * sy;
3599  shape->bounds[2] = (shape->bounds[2] + tx) * sx;
3600  shape->bounds[3] = (shape->bounds[3] + ty) * sy;
3601 
3602  for( path = shape->paths; path != NULL; path = path->next )
3603  {
3604  path->bounds[0] = (path->bounds[0] + tx) * sx;
3605  path->bounds[1] = (path->bounds[1] + ty) * sy;
3606  path->bounds[2] = (path->bounds[2] + tx) * sx;
3607  path->bounds[3] = (path->bounds[3] + ty) * sy;
3608 
3609  for( i = 0; i < path->npts; i++ )
3610  {
3611  pt = &path->pts[i * 2];
3612  pt[0] = (pt[0] + tx) * sx;
3613  pt[1] = (pt[1] + ty) * sy;
3614  }
3615  }
3616 
3617  if( shape->fill.type == NSVG_PAINT_LINEAR_GRADIENT
3618  || shape->fill.type == NSVG_PAINT_RADIAL_GRADIENT )
3619  {
3620  nsvg__scaleGradient( shape->fill.gradient, tx, ty, sx, sy );
3621  memcpy( t, shape->fill.gradient->xform, sizeof(float) * 6 );
3622  nsvg__xformInverse( shape->fill.gradient->xform, t );
3623  }
3624 
3625  if( shape->stroke.type == NSVG_PAINT_LINEAR_GRADIENT
3626  || shape->stroke.type == NSVG_PAINT_RADIAL_GRADIENT )
3627  {
3628  nsvg__scaleGradient( shape->stroke.gradient, tx, ty, sx, sy );
3629  memcpy( t, shape->stroke.gradient->xform, sizeof(float) * 6 );
3630  nsvg__xformInverse( shape->stroke.gradient->xform, t );
3631  }
3632 
3633  shape->strokeWidth *= avgs;
3634  shape->strokeDashOffset *= avgs;
3635 
3636  for( i = 0; i < shape->strokeDashCount; i++ )
3637  shape->strokeDashArray[i] *= avgs;
3638  }
3639 }
3640 
3641 
3642 NSVGimage* nsvgParse( char* input, const char* units, float dpi )
3643 {
3644  NSVGparser* p;
3645  NSVGimage* ret = 0;
3646 
3647  p = nsvg__createParser();
3648 
3649  if( p == NULL )
3650  {
3651  return NULL;
3652  }
3653 
3654  p->dpi = dpi;
3655 
3657 
3658  // Scale to viewBox
3659  nsvg__scaleToViewbox( p, units );
3660 
3661  ret = p->image;
3662  p->image = NULL;
3663 
3664  nsvg__deleteParser( p );
3665 
3666  return ret;
3667 }
3668 
3669 
3670 NSVGimage* nsvgParseFromFile( FILE *fp, const char* units, float dpi )
3671 {
3672  size_t size;
3673  char* data = NULL;
3674  NSVGimage* image = NULL;
3675 
3676  if( !fp )
3677  return NULL;
3678 
3679  fseek( fp, 0, SEEK_END );
3680  size = ftell( fp );
3681  fseek( fp, 0, SEEK_SET );
3682  data = (char*) malloc( size + 1 );
3683 
3684  if( data == NULL )
3685  goto error;
3686 
3687  if( fread( data, 1, size, fp ) != size )
3688  goto error;
3689 
3690  data[size] = '\0'; // Must be null terminated.
3691  fclose( fp );
3692  image = nsvgParse( data, units, dpi );
3693  free( data );
3694 
3695  return image;
3696 
3697 error:
3698 
3699  if( fp )
3700  fclose( fp );
3701 
3702  if( data )
3703  free( data );
3704 
3705  if( image )
3706  nsvgDelete( image );
3707 
3708  return NULL;
3709 }
3710 
3711 
3713 {
3714  NSVGpath* res = NULL;
3715 
3716  if( p == NULL )
3717  return NULL;
3718 
3719  res = (NSVGpath*) malloc( sizeof(NSVGpath) );
3720 
3721  if( res == NULL )
3722  goto error;
3723 
3724  memset( res, 0, sizeof(NSVGpath) );
3725 
3726  res->pts = (float*) malloc( p->npts * 2 * sizeof(float) );
3727 
3728  if( res->pts == NULL )
3729  goto error;
3730 
3731  memcpy( res->pts, p->pts, p->npts * sizeof(float) * 2 );
3732  res->npts = p->npts;
3733 
3734  memcpy( res->bounds, p->bounds, sizeof(p->bounds) );
3735 
3736  res->closed = p->closed;
3737 
3738  return res;
3739 
3740 error:
3741 
3742  if( res != NULL )
3743  {
3744  free( res->pts );
3745  free( res );
3746  }
3747 
3748  return NULL;
3749 }
3750 
3751 
3752 void nsvgDelete( NSVGimage* image )
3753 {
3754  NSVGshape* snext, * shape;
3755 
3756  if( image == NULL )
3757  return;
3758 
3759  shape = image->shapes;
3760 
3761  while( shape != NULL )
3762  {
3763  snext = shape->next;
3764  nsvg__deletePaths( shape->paths );
3765  nsvg__deletePaint( &shape->fill );
3766  nsvg__deletePaint( &shape->stroke );
3767  free( shape );
3768  shape = snext;
3769  }
3770 
3771  free( image );
3772 }
NSVGimage * nsvgParseFromFile(FILE *fp, const char *units, float dpi)
Definition: nanosvg.cpp:3670
struct NSVGpath * next
Definition: nanosvg.h:132
CITER next(CITER it)
Definition: ptree.cpp:130
static void nsvg__pathQuadBezShortTo(NSVGparser *p, float *cpx, float *cpy, float *cpx2, float *cpy2, float *args, int rel)
Definition: nanosvg.cpp:2414
static void nsvg__xformSetRotation(float *t, float a)
Definition: nanosvg.cpp:413
struct NSVGgradientData NSVGgradientData
char strokeDashCount
Definition: nanosvg.h:144
NSVGcoordinate fx
Definition: nanosvg.cpp:306
static float nsvg__vecrat(float ux, float uy, float vx, float vy)
Definition: nanosvg.cpp:2464
NSVGradialData radial
Definition: nanosvg.cpp:317
static NSVGgradient * nsvg__createGradient(NSVGparser *p, const char *id, const float *localBounds, char *paintType)
Definition: nanosvg.cpp:847
NSVGgradientStop stops[1]
Definition: nanosvg.h:115
char visible
Definition: nanosvg.cpp:352
static NSVG_INLINE float nsvg__minf(float a, float b)
Definition: nanosvg.cpp:82
struct NSVGlinearData NSVGlinearData
static float nsvg__parseOpacity(const char *str)
Definition: nanosvg.cpp:1613
static void nsvg__pathVLineTo(NSVGparser *p, float *cpx, float *cpy, float *args, int rel)
Definition: nanosvg.cpp:2296
NSVGlinearData linear
Definition: nanosvg.cpp:316
#define NSVG_ALIGN_SLICE
Definition: nanosvg.cpp:43
#define NSVG_ALIGN_NONE
Definition: nanosvg.cpp:41
int nsvg__parseXML(char *input, void(*startelCb)(void *ud, const char *el, const char **attr), void(*endelCb)(void *ud, const char *el), void(*contentCb)(void *ud, const char *s), void *ud)
Definition: nanosvg.cpp:229
static double nsvg__evalBezier(double t, double p0, double p1, double p2, double p3)
Definition: nanosvg.cpp:490
#define NSVG_XML_TAG
Definition: nanosvg.cpp:96
int alignY
Definition: nanosvg.cpp:367
float strokeWidth
Definition: nanosvg.cpp:338
static unsigned int nsvg__parseColor(const char *str)
Definition: nanosvg.cpp:1595
int alignX
Definition: nanosvg.cpp:367
static void nsvg__imageBounds(NSVGparser *p, float *bounds)
Definition: nanosvg.cpp:3472
static void nsvg__addPoint(NSVGparser *p, float x, float y)
Definition: nanosvg.cpp:670
NSVGcoordinate y2
Definition: nanosvg.cpp:301
float strokeDashArray[NSVG_MAX_DASHES]
Definition: nanosvg.cpp:340
float stopOffset
Definition: nanosvg.cpp:349
static void nsvg__parsePath(NSVGparser *p, const char **attr)
Definition: nanosvg.cpp:2620
#define NSVG_MAX_DASHES
Definition: nanosvg.cpp:277
char strokeLineCap
Definition: nanosvg.cpp:343
unsigned int strokeColor
Definition: nanosvg.cpp:332
static int nsvg__parseNameValue(NSVGparser *p, const char *start, const char *end)
Definition: nanosvg.cpp:2120
static int nsvg__ptInBounds(float *pt, float *bounds)
Definition: nanosvg.cpp:484
static float nsvg__convertToPixels(NSVGparser *p, NSVGcoordinate c, float orig, float length)
Definition: nanosvg.cpp:787
static float nsvg__parseCoordinate(NSVGparser *p, const char *str, float orig, float length)
Definition: nanosvg.cpp:1686
static char nsvg__parseFillRule(const char *str)
Definition: nanosvg.cpp:1921
float viewMiny
Definition: nanosvg.cpp:366
unsigned int color
Definition: nanosvg.h:106
static void nsvg__parseSVG(NSVGparser *p, const char **attr)
Definition: nanosvg.cpp:3126
static void nsvg__addShape(NSVGparser *p)
Definition: nanosvg.cpp:1001
NSVGgradient * gradient
Definition: nanosvg.h:122
float miterLimit
Definition: nanosvg.h:147
const char * name
Definition: nanosvg.cpp:1421
NSVGcoordinate fy
Definition: nanosvg.cpp:306
float * pts
Definition: nanosvg.cpp:359
NSVGpath * paths
Definition: nanosvg.h:151
static float nsvg__actualWidth(NSVGparser *p)
Definition: nanosvg.cpp:767
char hasStroke
Definition: nanosvg.cpp:351
static void nsvg__parseGradient(NSVGparser *p, const char **attr, char type)
Definition: nanosvg.cpp:3188
static unsigned int nsvg__parseColorHex(const char *str)
Definition: nanosvg.cpp:1372
NSVGpaint fill
Definition: nanosvg.h:138
static int nsvg__parseAttr(NSVGparser *p, const char *name, const char *value)
Definition: nanosvg.cpp:1992
unsigned int stopColor
Definition: nanosvg.cpp:347
NSVGcoordinate r
Definition: nanosvg.cpp:306
#define NSVG_ALIGN_MID
Definition: nanosvg.cpp:39
NSVGcoordinate cy
Definition: nanosvg.cpp:306
NSVGcoordinate x1
Definition: nanosvg.cpp:301
unsigned int color
Definition: nanosvg.cpp:1422
static int nsvg__parseSkewX(float *xform, const char *str)
Definition: nanosvg.cpp:1783
char fillGradient[64]
Definition: nanosvg.cpp:336
NSVGshape * shapesTail
Definition: nanosvg.cpp:365
static int nsvg__isdigit(char c)
Definition: nanosvg.cpp:70
#define NSVG_ALIGN_MAX
Definition: nanosvg.cpp:40
static void nsvg__parseEllipse(NSVGparser *p, const char **attr)
Definition: nanosvg.cpp:2968
struct NSVGshape * next
Definition: nanosvg.h:152
static void nsvg__popAttr(NSVGparser *p)
Definition: nanosvg.cpp:748
char spread
Definition: nanosvg.h:112
static void nsvg__resetPath(NSVGparser *p)
Definition: nanosvg.cpp:664
const string & str
Definition: json11.cpp:596
#define NSVG_XML_MAX_ATTRIBS
Definition: nanosvg.cpp:98
char strokeGradient[64]
Definition: nanosvg.cpp:337
float xform[6]
Definition: nanosvg.cpp:321
static int nsvg__parseScale(float *xform, const char *str)
Definition: nanosvg.cpp:1767
char ref[64]
Definition: nanosvg.cpp:312
float fx
Definition: nanosvg.h:113
static void nsvg__cubicBezTo(NSVGparser *p, float cpx1, float cpy1, float cpx2, float cpy2, float x, float y)
Definition: nanosvg.cpp:718
static void nsvg__parseCircle(NSVGparser *p, const char **attr)
Definition: nanosvg.cpp:2902
static NSVG_INLINE float nsvg__maxf(float a, float b)
Definition: nanosvg.cpp:88
ITERATOR end(int aType=UNDEFINED_TYPE)
Definition: multivector.h:189
static float nsvg__vecang(float ux, float uy, float vx, float vy)
Definition: nanosvg.cpp:2470
static double nsvg__atof(const char *s)
Definition: nanosvg.cpp:1200
char type
Definition: nanosvg.h:119
static void nsvg__xformSetTranslation(float *t, float tx, float ty)
Definition: nanosvg.cpp:381
float strokeWidth
Definition: nanosvg.h:141
unsigned char flags
Definition: nanosvg.h:149
#define NSVG_MAX_ATTR
Definition: nanosvg.cpp:269
float fontSize
Definition: nanosvg.cpp:346
static void nsvg__deletePaint(NSVGpaint *paint)
Definition: nanosvg.cpp:630
float xform[6]
Definition: nanosvg.h:111
unsigned int color
Definition: nanosvg.h:121
static int nsvg__parseStrokeDashArray(NSVGparser *p, const char *str, float *strokeDashArray)
Definition: nanosvg.cpp:1957
static void nsvg__xformSetScale(float *t, float sx, float sy)
Definition: nanosvg.cpp:389
struct NSVGgradientData * next
Definition: nanosvg.cpp:324
static void nsvg__parseElement(char *s, void(*startelCb)(void *ud, const char *el, const char **attr), void(*endelCb)(void *ud, const char *el), void *ud)
Definition: nanosvg.cpp:116
float * pts
Definition: nanosvg.h:128
static void nsvg__xformSetSkewY(float *t, float a)
Definition: nanosvg.cpp:405
struct NSVGNamedColor NSVGNamedColor
static char nsvg__parseLineCap(const char *str)
Definition: nanosvg.cpp:1893
static int nsvg__parseRotate(float *xform, const char *str)
Definition: nanosvg.cpp:1809
static float nsvg__actualOrigX(NSVGparser *p)
Definition: nanosvg.cpp:755
struct NSVGcoordinate NSVGcoordinate
float strokeDashOffset
Definition: nanosvg.cpp:339
NSVGattrib attr[NSVG_MAX_ATTR]
Definition: nanosvg.cpp:357
struct NSVGgradientStop NSVGgradientStop
float viewMinx
Definition: nanosvg.cpp:366
static void nsvg__content(void *ud, const char *s)
Definition: nanosvg.cpp:3464
static void nsvg__startElement(void *ud, const char *el, const char **attr)
Definition: nanosvg.cpp:3349
char fillRule
Definition: nanosvg.cpp:345
#define NSVG_XML_CONTENT
Definition: nanosvg.cpp:97
char hasFill
Definition: nanosvg.cpp:350
static void nsvg__parseRect(NSVGparser *p, const char **attr)
Definition: nanosvg.cpp:2804
static void nsvg__scaleToViewbox(NSVGparser *p, const char *units)
Definition: nanosvg.cpp:3523
NSVGimage * image
Definition: nanosvg.cpp:363
static int nsvg__getArgsPerElement(char cmd)
Definition: nanosvg.cpp:2214
float fillOpacity
Definition: nanosvg.cpp:334
#define NSVG_KAPPA90
Definition: nanosvg.cpp:36
static int nsvg__parseUnits(const char *units)
Definition: nanosvg.cpp:1642
static float nsvg__getAverageScale(float *t)
Definition: nanosvg.cpp:949
static void nsvg__parseUrl(char *id, const char *str)
Definition: nanosvg.cpp:1874
static void nsvg__pathCubicBezTo(NSVGparser *p, float *cpx, float *cpy, float *cpx2, float *cpy2, float *args, int rel)
Definition: nanosvg.cpp:2307
NSVGpaint stroke
Definition: nanosvg.h:139
static void nsvg__addPath(NSVGparser *p, char closed)
Definition: nanosvg.cpp:1123
float strokeDashArray[8]
Definition: nanosvg.h:143
int npts
Definition: nanosvg.h:129
NSVGpath * plist
Definition: nanosvg.cpp:362
static void nsvg__scaleGradient(NSVGgradient *grad, float tx, float ty, float sx, float sy)
Definition: nanosvg.cpp:3511
char id[64]
Definition: nanosvg.h:137
struct NSVGparser NSVGparser
NSVGimage * nsvgParse(char *input, const char *units, float dpi)
Definition: nanosvg.cpp:3642
static void nsvg__xformMultiply(float *t, float *s)
Definition: nanosvg.cpp:423
float viewWidth
Definition: nanosvg.cpp:366
char strokeLineJoin
Definition: nanosvg.cpp:342
static NSVGattrib * nsvg__getAttr(NSVGparser *p)
Definition: nanosvg.cpp:732
char defsFlag
Definition: nanosvg.cpp:370
int strokeDashCount
Definition: nanosvg.cpp:341
void nsvgDelete(NSVGimage *image)
Definition: nanosvg.cpp:3752
static void nsvg__pushAttr(NSVGparser *p)
Definition: nanosvg.cpp:738
NSVGshape * shapes
Definition: nanosvg.h:159
NSVGgradientUnits
Definition: nanosvg.cpp:271
static void nsvg__parseStyle(NSVGparser *p, const char *str)
Definition: nanosvg.cpp:2168
NSVGcoordinate y1
Definition: nanosvg.cpp:301
static void nsvg__pathLineTo(NSVGparser *p, float *cpx, float *cpy, float *args, int rel)
Definition: nanosvg.cpp:2268
static int nsvg__isnum(char c)
Definition: nanosvg.cpp:76
static const char * nsvg__getNextDashItem(const char *s, char *it)
Definition: nanosvg.cpp:1933
static void nsvg__deleteParser(NSVGparser *p)
Definition: nanosvg.cpp:651
#define NSVG_NOTUSED(v)
Definition: nanosvg.cpp:45
static void nsvg__deleteGradientData(NSVGgradientData *grad)
Definition: nanosvg.cpp:637
static void nsvg__parseLine(NSVGparser *p, const char **attr)
Definition: nanosvg.cpp:3040
static void nsvg__parsePoly(NSVGparser *p, const char **attr, int closeFlag)
Definition: nanosvg.cpp:3081
static void nsvg__xformInverse(float *inv, float *t)
Definition: nanosvg.cpp:438
static void nsvg__deletePaths(NSVGpath *path)
Definition: nanosvg.cpp:615
static float nsvg__actualHeight(NSVGparser *p)
Definition: nanosvg.cpp:773
static float nsvg__actualLength(NSVGparser *p)
Definition: nanosvg.cpp:779
static float nsvg__vmag(float x, float y)
Definition: nanosvg.cpp:2458
float bounds[4]
Definition: nanosvg.h:150
static void nsvg__curveBounds(float *bounds, float *curve)
Definition: nanosvg.cpp:498
static void nsvg__getLocalBounds(float *bounds, NSVGshape *shape, float *xform)
Definition: nanosvg.cpp:958
NSVGNamedColor nsvg__colors[]
Definition: nanosvg.cpp:1425
static void nsvg__pathMoveTo(NSVGparser *p, float *cpx, float *cpy, float *args, int rel)
Definition: nanosvg.cpp:2251
static NSVGcoordinate nsvg__coord(float v, int units)
Definition: nanosvg.cpp:1678
static unsigned int nsvg__parseColorName(const char *str)
Definition: nanosvg.cpp:1579
float fy
Definition: nanosvg.h:113
static void nsvg__xformSetSkewX(float *t, float a)
Definition: nanosvg.cpp:397
unsigned int fillColor
Definition: nanosvg.cpp:331
static int nsvg__parseMatrix(float *xform, const char *str)
Definition: nanosvg.cpp:1737
char id[64]
Definition: nanosvg.cpp:329
const int scale
float opacity
Definition: nanosvg.h:140
struct NSVGradialData NSVGradialData
char strokeLineCap
Definition: nanosvg.h:146
#define NSVG_RGB(r, g, b)
Definition: nanosvg.cpp:47
static void nsvg__xformPremultiply(float *t, float *s)
Definition: nanosvg.cpp:458
const char * name
Definition: DXF_plotter.cpp:61
float strokeOpacity
Definition: nanosvg.cpp:335
float height
Definition: nanosvg.h:158
static void nsvg__parseTransform(float *xform, const char *str)
Definition: nanosvg.cpp:1843
static void nsvg__parseAttribs(NSVGparser *p, const char **attr)
Definition: nanosvg.cpp:2200
#define NSVG_EPSILON
Definition: nanosvg.cpp:482
static float nsvg__actualOrigY(NSVGparser *p)
Definition: nanosvg.cpp:761
float stopOpacity
Definition: nanosvg.cpp:348
NSVGgradientStop * stops
Definition: nanosvg.cpp:323
static void nsvg__xformVec(float *dx, float *dy, float x, float y, float *t)
Definition: nanosvg.cpp:475
size_t i
Definition: json11.cpp:597
static void nsvg__xformPoint(float *dx, float *dy, float x, float y, float *t)
Definition: nanosvg.cpp:468
static NSVGcoordinate nsvg__parseCoordinateRaw(const char *str)
Definition: nanosvg.cpp:1667
static void nsvg__pathCubicBezShortTo(NSVGparser *p, float *cpx, float *cpy, float *cpx2, float *cpy2, float *args, int rel)
Definition: nanosvg.cpp:2340
static void nsvg__lineTo(NSVGparser *p, float x, float y)
Definition: nanosvg.cpp:701
static void nsvg__parseContent(char *s, void(*contentCb)(void *ud, const char *s), void *ud)
Definition: nanosvg.cpp:100
static int nsvg__parseTransformArgs(const char *str, float *args, int maxNa, int *na)
Definition: nanosvg.cpp:1694
static unsigned int nsvg__parseColorRGB(const char *str)
Definition: nanosvg.cpp:1401
static void nsvg__pathArcTo(NSVGparser *p, float *cpx, float *cpy, float *args, int rel)
Definition: nanosvg.cpp:2484
#define NSVG_PI
Definition: nanosvg.cpp:35
static void nsvg__pathQuadBezTo(NSVGparser *p, float *cpx, float *cpy, float *cpx2, float *cpy2, float *args, int rel)
Definition: nanosvg.cpp:2375
static float nsvg__sqr(float x)
Definition: nanosvg.cpp:2452
NSVGgradientData * gradients
Definition: nanosvg.cpp:364
char fillRule
Definition: nanosvg.h:148
int alignType
Definition: nanosvg.cpp:367
static char nsvg__parseLineJoin(const char *str)
Definition: nanosvg.cpp:1907
NSVGpath * nsvgDuplicatePath(NSVGpath *p)
Definition: nanosvg.cpp:3712
NSVGcoordinate cx
Definition: nanosvg.cpp:306
NSVGunits
Definition: nanosvg.cpp:279
static int nsvg__isspace(char c)
Definition: nanosvg.cpp:64
struct NSVGattrib NSVGattrib
char strokeLineJoin
Definition: nanosvg.h:145
static const char * nsvg__parseNumber(const char *s, char *it, const int size)
Definition: nanosvg.cpp:1273
static void nsvg__xformIdentity(float *t)
Definition: nanosvg.cpp:373
static const char * nsvg__getNextPathItem(const char *s, char *it)
Definition: nanosvg.cpp:1345
NSVGcoordinate x2
Definition: nanosvg.cpp:301
static float nsvg__parseMiterLimit(const char *str)
Definition: nanosvg.cpp:1629
static void nsvg__endElement(void *ud, const char *el)
Definition: nanosvg.cpp:3445
static int nsvg__parseSkewY(float *xform, const char *str)
Definition: nanosvg.cpp:1796
int attrHead
Definition: nanosvg.cpp:358
static int nsvg__parseTranslate(float *xform, const char *str)
Definition: nanosvg.cpp:1751
static NSVGgradientData * nsvg__findGradientData(NSVGparser *p, const char *id)
Definition: nanosvg.cpp:831
#define NSVG_ALIGN_MEET
Definition: nanosvg.cpp:42
static void nsvg__moveTo(NSVGparser *p, float x, float y)
Definition: nanosvg.cpp:687
float bounds[4]
Definition: nanosvg.h:131
char closed
Definition: nanosvg.h:130
float width
Definition: nanosvg.h:157
float miterLimit
Definition: nanosvg.cpp:344
float viewHeight
Definition: nanosvg.cpp:366
static NSVGparser * nsvg__createParser()
Definition: nanosvg.cpp:564
int nstops
Definition: nanosvg.h:114
float dpi
Definition: nanosvg.cpp:368
#define NSVG_INLINE
Definition: nanosvg.cpp:60
#define NSVG_ALIGN_MIN
Definition: nanosvg.cpp:38
static float nsvg__viewAlign(float content, float container, int type)
Definition: nanosvg.cpp:3499
float opacity
Definition: nanosvg.cpp:333
float strokeDashOffset
Definition: nanosvg.h:142
char pathFlag
Definition: nanosvg.cpp:369
static void nsvg__parseGradientStop(NSVGparser *p, const char **attr)
Definition: nanosvg.cpp:3295
int sign(T val)
Definition: math_util.h:44
float xform[6]
Definition: nanosvg.cpp:330
static void nsvg__pathHLineTo(NSVGparser *p, float *cpx, float *cpy, float *args, int rel)
Definition: nanosvg.cpp:2285