37 #ifndef NANOSVG_CPLUSPLUS
183 #ifndef NANOSVG_CPLUSPLUS
191 #ifdef NANOSVG_IMPLEMENTATION
198 #define NSVG_PI (3.14159265358979323846264338327)
199 #define NSVG_KAPPA90 (0.5522847493)
201 #define NSVG_ALIGN_MIN 0
202 #define NSVG_ALIGN_MID 1
203 #define NSVG_ALIGN_MAX 2
204 #define NSVG_ALIGN_NONE 0
205 #define NSVG_ALIGN_MEET 1
206 #define NSVG_ALIGN_SLICE 2
208 #define NSVG_NOTUSED(v) do { (void)(1 ? (void)0 : ( (void)(v) ) ); } while(0)
209 #define NSVG_RGB(r, g, b) ((static_cast<unsigned int>(r)) | (static_cast<unsigned int>(g) << 8) | (static_cast<unsigned int>(b) << 16))
212 #pragma warning (disable: 4996)
213 #pragma warning (disable: 4100)
215 #define NSVG_INLINE inline
220 #define NSVG_INLINE inline
224 static int nsvg__isspace(
char c)
226 return strchr(
" \t\n\v\f\r", c) !=
nullptr;
229 static int nsvg__isdigit(
char c)
231 return c >=
'0' && c <=
'9';
234 static int nsvg__isnum(
char c)
236 return strchr(
"0123456789+-.eE", c) !=
nullptr;
239 static NSVG_INLINE
double nsvg__minf(
double a,
double b) {
return a < b ? a : b; }
240 static NSVG_INLINE
double nsvg__maxf(
double a,
double b) {
return a > b ? a : b; }
245 #define NSVG_XML_TAG 1
246 #define NSVG_XML_CONTENT 2
247 #define NSVG_XML_MAX_ATTRIBS 256
249 static void nsvg__parseContent(
char* s,
250 void (*contentCb)(
void* ud,
const char* s),
254 while (*s && nsvg__isspace(*s)) s++;
261 static void nsvg__parseElement(
char* s,
262 void (*startelCb)(
void* ud,
const char* el,
const char** attr),
263 void (*endelCb)(
void* ud,
const char* el),
266 const char* attr[NSVG_XML_MAX_ATTRIBS];
274 while (*s && nsvg__isspace(*s)) s++;
285 if (!*s || *s ==
'?' || *s ==
'!')
290 while (*s && !nsvg__isspace(*s)) s++;
291 if (*s) { *s++ =
'\0'; }
294 while (!end && *s && nattr < NSVG_XML_MAX_ATTRIBS-3) {
295 char* nameAttrib =
nullptr;
296 char*
value =
nullptr;
299 while (*s && nsvg__isspace(*s)) s++;
307 while (*s && !nsvg__isspace(*s) && *s !=
'=') s++;
308 if (*s) { *s++ =
'\0'; }
310 while (*s && *s !=
'\"' && *s !=
'\'') s++;
316 while (*s && *s != quote) s++;
317 if (*s) { *s++ =
'\0'; }
320 if (nameAttrib &&
value) {
321 attr[nattr++] = nameAttrib;
322 attr[nattr++] =
value;
327 attr[nattr++] =
nullptr;
328 attr[nattr++] =
nullptr;
331 if (start && startelCb)
332 (*startelCb)(ud,
name, attr);
334 (*endelCb)(ud,
name);
337 static int nsvg__parseXML(
char*
input,
338 void (*startelCb)(
void* ud,
const char* el,
const char** attr),
339 void (*endelCb)(
void* ud,
const char* el),
340 void (*contentCb)(
void* ud,
const char* s),
345 int state = NSVG_XML_CONTENT;
347 if (*s ==
'<' && state == NSVG_XML_CONTENT) {
350 nsvg__parseContent(mark, contentCb, ud);
352 state = NSVG_XML_TAG;
353 }
else if (*s ==
'>' && state == NSVG_XML_TAG) {
356 nsvg__parseElement(mark, startelCb, endelCb, ud);
358 state = NSVG_XML_CONTENT;
370 #define NSVG_MAX_ATTR 128
372 enum NSVGgradientUnits {
374 NSVG_OBJECT_SPACE = 1
377 #define NSVG_MAX_DASHES 8
392 typedef struct NSVGcoordinate {
397 typedef struct NSVGlinearData {
398 NSVGcoordinate x1, y1, x2, y2;
401 typedef struct NSVGradialData {
402 NSVGcoordinate cx, cy, r, fx, fy;
405 typedef struct NSVGgradientData
411 NSVGlinearData linear;
412 NSVGradialData radial;
419 struct NSVGgradientData* next;
422 typedef struct NSVGattrib
426 unsigned int fillColor;
427 unsigned int strokeColor;
430 double strokeOpacity;
431 char fillGradient[64];
432 char strokeGradient[64];
434 double strokeDashOffset;
435 double strokeDashArray[NSVG_MAX_DASHES];
442 unsigned int stopColor;
450 typedef struct NSVGparser
452 NSVGattrib attr[NSVG_MAX_ATTR];
459 NSVGgradientData* gradients;
461 double viewMinx, viewMiny, viewWidth, viewHeight;
462 int alignX, alignY, alignType;
468 static void nsvg__xformIdentity(
double* t)
470 t[0] = 1.0; t[1] = 0.0;
471 t[2] = 0.0; t[3] = 1.0;
472 t[4] = 0.0; t[5] = 0.0;
475 static void nsvg__xformSetTranslation(
double* t,
double tx,
double ty)
477 t[0] = 1.0; t[1] = 0.0;
478 t[2] = 0.0; t[3] = 1.0;
479 t[4] = tx; t[5] = ty;
482 static void nsvg__xformSetScale(
double* t,
double sx,
double sy)
484 t[0] = sx; t[1] = 0.0;
485 t[2] = 0.0; t[3] = sy;
486 t[4] = 0.0; t[5] = 0.0;
489 static void nsvg__xformSetSkewX(
double* t,
double a)
491 t[0] = 1.0; t[1] = 0.0;
492 t[2] = tan(a); t[3] = 1.0;
493 t[4] = 0.0; t[5] = 0.0;
496 static void nsvg__xformSetSkewY(
double* t,
double a)
498 t[0] = 1.0; t[1] = tan(a);
499 t[2] = 0.0; t[3] = 1.0;
500 t[4] = 0.0; t[5] = 0.0;
503 static void nsvg__xformSetRotation(
double* t,
double a)
505 double cs = cos(a), sn = sin(a);
506 t[0] = cs; t[1] = sn;
507 t[2] = -sn; t[3] = cs;
508 t[4] = 0.0; t[5] = 0.0;
511 static void nsvg__xformMultiply(
double* t,
double* s)
513 double t0 = t[0] * s[0] + t[1] * s[2];
514 double t2 = t[2] * s[0] + t[3] * s[2];
515 double t4 = t[4] * s[0] + t[5] * s[2] + s[4];
516 t[1] = t[0] * s[1] + t[1] * s[3];
517 t[3] = t[2] * s[1] + t[3] * s[3];
518 t[5] = t[4] * s[1] + t[5] * s[3] + s[5];
524 static void nsvg__xformInverse(
double* inv,
double* t)
526 double invdet, det = t[0] * t[3] - t[2] * t[1];
527 if (det > -1e-6 && det < 1e-6) {
528 nsvg__xformIdentity(t);
532 inv[0] = t[3] * invdet;
533 inv[2] = -t[2] * invdet;
534 inv[4] = (t[2] * t[5] - t[3] * t[4]) * invdet;
535 inv[1] = -t[1] * invdet;
536 inv[3] = t[0] * invdet;
537 inv[5] = (t[1] * t[4] - t[0] * t[5]) * invdet;
540 static void nsvg__xformPremultiply(
double* t,
double* s)
543 memcpy(s2, s,
sizeof(
double)*6);
544 nsvg__xformMultiply(s2, t);
545 memcpy(t, s2,
sizeof(
double)*6);
548 static void nsvg__xformPoint(
double* dx,
double* dy,
double x,
double y,
double* t)
550 *dx =
x*t[0] +
y*t[2] + t[4];
551 *dy =
x*t[1] +
y*t[3] + t[5];
554 static void nsvg__xformVec(
double* dx,
double* dy,
double x,
double y,
double* t)
556 *dx =
x*t[0] +
y*t[2];
557 *dy =
x*t[1] +
y*t[3];
560 #define NSVG_EPSILON (1e-12)
562 static int nsvg__ptInBounds(
double* pt,
double* bounds)
564 return pt[0] >= bounds[0] && pt[0] <= bounds[2] && pt[1] >= bounds[1] && pt[1] <= bounds[3];
568 static double nsvg__evalBezier(
double t,
double p0,
double p1,
double p2,
double p3)
571 return it*it*it*p0 + 3.0*it*it*t*p1 + 3.0*it*t*t*p2 + t*t*t*p3;
574 static void nsvg__curveBounds(
double* bounds,
double* curve)
577 double roots[2], a, b, c, b2ac, t, v;
578 double* v0 = &curve[0];
579 double* v1 = &curve[2];
580 double* v2 = &curve[4];
581 double* v3 = &curve[6];
584 bounds[0] = nsvg__minf(v0[0], v3[0]);
585 bounds[1] = nsvg__minf(v0[1], v3[1]);
586 bounds[2] = nsvg__maxf(v0[0], v3[0]);
587 bounds[3] = nsvg__maxf(v0[1], v3[1]);
591 if (nsvg__ptInBounds(v1, bounds) && nsvg__ptInBounds(v2, bounds))
595 for (i = 0; i < 2; i++) {
596 a = -3.0 * v0[i] + 9.0 * v1[i] - 9.0 * v2[i] + 3.0 * v3[i];
597 b = 6.0 * v0[i] - 12.0 * v1[i] + 6.0 * v2[i];
598 c = 3.0 * v1[i] - 3.0 * v0[i];
600 if (fabs(a) < NSVG_EPSILON) {
601 if (fabs(b) > NSVG_EPSILON) {
603 if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON)
607 b2ac = b*b - 4.0*c*a;
608 if (b2ac > NSVG_EPSILON) {
609 t = (-b + sqrt(b2ac)) / (2.0 * a);
610 if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON)
612 t = (-b - sqrt(b2ac)) / (2.0 * a);
613 if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON)
617 for (j = 0; j <
count; j++) {
618 v = nsvg__evalBezier(roots[j], v0[i], v1[i], v2[i], v3[i]);
619 bounds[0+i] = nsvg__minf(bounds[0+i], v);
620 bounds[2+i] = nsvg__maxf(bounds[2+i], v);
625 static NSVGparser* nsvg__createParser()
628 p =
static_cast<NSVGparser*
>(malloc(
sizeof(NSVGparser)));
629 if (
p ==
nullptr)
goto error;
630 memset(
p, 0,
sizeof(NSVGparser));
633 if (
p->image ==
nullptr)
goto error;
637 nsvg__xformIdentity(
p->attr[0].xform);
638 memset(
p->attr[0].id, 0,
sizeof p->attr[0].id);
639 p->attr[0].fillColor = NSVG_RGB(0,0,0);
640 p->attr[0].strokeColor = NSVG_RGB(0,0,0);
641 p->attr[0].opacity = 1;
642 p->attr[0].fillOpacity = 1;
643 p->attr[0].strokeOpacity = 1;
644 p->attr[0].stopOpacity = 1;
645 p->attr[0].strokeWidth = 1;
648 p->attr[0].miterLimit = 4;
650 p->attr[0].hasFill = 1;
651 p->attr[0].visible = 1;
657 if (
p->image) free(
p->image);
667 if (
path->pts !=
nullptr)
674 static void nsvg__deletePaint(
NSVGpaint* paint)
680 static void nsvg__deleteGradientData(NSVGgradientData* grad)
682 NSVGgradientData* next;
683 while (grad !=
nullptr) {
691 static void nsvg__deleteParser(NSVGparser*
p)
694 nsvg__deletePaths(
p->plist);
695 nsvg__deleteGradientData(
p->gradients);
702 static void nsvg__resetPath(NSVGparser*
p)
707 static void nsvg__addPoint(NSVGparser*
p,
double x,
double y)
709 if (
p->npts+1 >
p->cpts) {
710 p->cpts =
p->cpts ?
p->cpts*2 : 8;
711 p->pts =
static_cast<double*
>(realloc(
p->pts,
p->cpts*2*
sizeof(
double)));
714 p->pts[
p->npts*2+0] =
x;
715 p->pts[
p->npts*2+1] =
y;
719 static void nsvg__moveTo(NSVGparser*
p,
double x,
double y)
722 p->pts[(
p->npts-1)*2+0] =
x;
723 p->pts[(
p->npts-1)*2+1] =
y;
725 nsvg__addPoint(
p,
x,
y);
729 static void nsvg__lineTo(NSVGparser*
p,
double x,
double y)
733 px =
p->pts[(
p->npts-1)*2+0];
734 py =
p->pts[(
p->npts-1)*2+1];
737 nsvg__addPoint(
p,
px + dx/3.0, py + dy/3.0);
738 nsvg__addPoint(
p,
x - dx/3.0,
y - dy/3.0);
739 nsvg__addPoint(
p,
x,
y);
743 static void nsvg__cubicBezTo(NSVGparser*
p,
double cpx1,
double cpy1,
double cpx2,
double cpy2,
double x,
double y)
745 nsvg__addPoint(
p, cpx1, cpy1);
746 nsvg__addPoint(
p, cpx2, cpy2);
747 nsvg__addPoint(
p,
x,
y);
750 static NSVGattrib* nsvg__getAttr(NSVGparser*
p)
752 return &
p->attr[
p->attrHead];
755 static void nsvg__pushAttr(NSVGparser*
p)
757 if (
p->attrHead < NSVG_MAX_ATTR-1) {
759 memcpy(&
p->attr[
p->attrHead], &
p->attr[
p->attrHead-1],
sizeof(NSVGattrib));
763 static void nsvg__popAttr(NSVGparser*
p)
769 static double nsvg__actualOrigX(NSVGparser*
p)
774 static double nsvg__actualOrigY(NSVGparser*
p)
779 static double nsvg__actualWidth(NSVGparser*
p)
784 static double nsvg__actualHeight(NSVGparser*
p)
786 return p->viewHeight;
789 static double nsvg__actualLength(NSVGparser*
p)
791 double w = nsvg__actualWidth(
p), h = nsvg__actualHeight(
p);
792 return sqrt(w*w + h*h) / sqrt(2.0);
795 static double nsvg__convertToPixels(NSVGparser*
p, NSVGcoordinate c,
double orig,
double length)
797 NSVGattrib* attr = nsvg__getAttr(
p);
799 case NSVG_UNITS_USER:
return c.value;
800 case NSVG_UNITS_PX:
return c.value;
801 case NSVG_UNITS_PT:
return c.value / 72.0 *
p->dpi;
802 case NSVG_UNITS_PC:
return c.value / 6.0 *
p->dpi;
803 case NSVG_UNITS_MM:
return c.value / 25.4 *
p->dpi;
804 case NSVG_UNITS_CM:
return c.value / 2.54 *
p->dpi;
805 case NSVG_UNITS_IN:
return c.value *
p->dpi;
806 case NSVG_UNITS_EM:
return c.value * attr->fontSize;
807 case NSVG_UNITS_EX:
return c.value * attr->fontSize * 0.52;
808 case NSVG_UNITS_PERCENT:
return orig + c.value / 100.0 *
length;
809 default:
return c.value;
813 static NSVGgradientData* nsvg__findGradientData(NSVGparser*
p,
const char*
id)
815 NSVGgradientData* grad =
p->gradients;
817 if (strcmp(grad->id,
id) == 0)
824 static NSVGgradient* nsvg__createGradient(NSVGparser*
p,
const char*
id,
const double* localBounds,
char* paintType)
826 NSVGattrib* attr = nsvg__getAttr(
p);
827 NSVGgradientData*
data =
nullptr;
828 NSVGgradientData*
ref =
nullptr;
831 double ox, oy, sw, sh, sl;
834 data = nsvg__findGradientData(
p,
id);
835 if (
data ==
nullptr)
return nullptr;
839 while (
ref !=
nullptr) {
840 if (stops ==
nullptr &&
ref->stops !=
nullptr) {
842 nstops =
ref->nstops;
845 ref = nsvg__findGradientData(
p,
ref->ref);
847 if (stops ==
nullptr)
return nullptr;
850 if (grad ==
nullptr)
return nullptr;
853 if (
data->units == NSVG_OBJECT_SPACE) {
856 sw = localBounds[2] - localBounds[0];
857 sh = localBounds[3] - localBounds[1];
859 ox = nsvg__actualOrigX(
p);
860 oy = nsvg__actualOrigY(
p);
861 sw = nsvg__actualWidth(
p);
862 sh = nsvg__actualHeight(
p);
864 sl = sqrt(sw*sw + sh*sh) / sqrt(2.0);
867 double x1, y1, x2, y2, dx, dy;
868 x1 = nsvg__convertToPixels(
p,
data->linear.x1, ox, sw);
869 y1 = nsvg__convertToPixels(
p,
data->linear.y1, oy, sh);
870 x2 = nsvg__convertToPixels(
p,
data->linear.x2, ox, sw);
871 y2 = nsvg__convertToPixels(
p,
data->linear.y2, oy, sh);
879 double cx, cy, fx, fy, r;
880 cx = nsvg__convertToPixels(
p,
data->radial.cx, ox, sw);
881 cy = nsvg__convertToPixels(
p,
data->radial.cy, oy, sh);
882 fx = nsvg__convertToPixels(
p,
data->radial.fx, ox, sw);
883 fy = nsvg__convertToPixels(
p,
data->radial.fy, oy, sh);
884 r = nsvg__convertToPixels(
p,
data->radial.r, 0, sl);
893 nsvg__xformMultiply(grad->
xform,
data->xform);
894 nsvg__xformMultiply(grad->
xform, attr->xform);
900 *paintType =
data->type;
905 static double nsvg__getAverageScale(
double* t)
907 double sx = sqrt(t[0]*t[0] + t[2]*t[2]);
908 double sy = sqrt(t[1]*t[1] + t[3]*t[3]);
909 return (sx + sy) * 0.5;
912 static void nsvg__getLocalBounds(
double* bounds,
NSVGshape *
shape,
double* xform)
915 double curve[4*2], curveBounds[4];
918 nsvg__xformPoint(&curve[0], &curve[1],
path->pts[0],
path->pts[1], xform);
919 for (i = 0; i <
path->npts-1; i += 3) {
920 nsvg__xformPoint(&curve[2], &curve[3],
path->pts[(i+1)*2],
path->pts[(i+1)*2+1], xform);
921 nsvg__xformPoint(&curve[4], &curve[5],
path->pts[(i+2)*2],
path->pts[(i+2)*2+1], xform);
922 nsvg__xformPoint(&curve[6], &curve[7],
path->pts[(i+3)*2],
path->pts[(i+3)*2+1], xform);
923 nsvg__curveBounds(curveBounds, curve);
925 bounds[0] = curveBounds[0];
926 bounds[1] = curveBounds[1];
927 bounds[2] = curveBounds[2];
928 bounds[3] = curveBounds[3];
931 bounds[0] = nsvg__minf(bounds[0], curveBounds[0]);
932 bounds[1] = nsvg__minf(bounds[1], curveBounds[1]);
933 bounds[2] = nsvg__maxf(bounds[2], curveBounds[2]);
934 bounds[3] = nsvg__maxf(bounds[3], curveBounds[3]);
942 static void nsvg__addShape(NSVGparser*
p)
944 NSVGattrib* attr = nsvg__getAttr(
p);
950 if (
p->plist ==
nullptr)
954 if (
shape ==
nullptr)
958 memcpy(
shape->id, attr->id,
sizeof shape->id);
959 scale = nsvg__getAverageScale(attr->xform);
960 shape->strokeWidth = attr->strokeWidth *
scale;
961 shape->strokeDashOffset = attr->strokeDashOffset *
scale;
962 shape->strokeDashCount =
static_cast<char>(attr->strokeDashCount);
963 for (i = 0; i < attr->strokeDashCount; i++)
964 shape->strokeDashArray[i] = attr->strokeDashArray[i] *
scale;
965 shape->strokeLineJoin = attr->strokeLineJoin;
966 shape->strokeLineCap = attr->strokeLineCap;
967 shape->miterLimit = attr->miterLimit;
968 shape->fillRule = attr->fillRule;
969 shape->opacity = attr->opacity;
987 if (attr->hasFill == 0) {
989 }
else if (attr->hasFill == 1) {
991 shape->fill.color = attr->fillColor;
992 shape->fill.color |=
static_cast<unsigned int>(attr->fillOpacity*255) << 24;
993 }
else if (attr->hasFill == 2) {
994 double inv[6], localBounds[4];
995 nsvg__xformInverse(inv, attr->xform);
996 nsvg__getLocalBounds(localBounds,
shape, inv);
997 shape->fill.gradient = nsvg__createGradient(
p, attr->fillGradient, localBounds, &
shape->fill.type);
998 if (
shape->fill.gradient ==
nullptr) {
1004 if (attr->hasStroke == 0) {
1006 }
else if (attr->hasStroke == 1) {
1008 shape->stroke.color = attr->strokeColor;
1009 shape->stroke.color |=
static_cast<unsigned int>(attr->strokeOpacity*255) << 24;
1010 }
else if (attr->hasStroke == 2) {
1011 double inv[6], localBounds[4];
1012 nsvg__xformInverse(inv, attr->xform);
1013 nsvg__getLocalBounds(localBounds,
shape, inv);
1014 shape->stroke.gradient = nsvg__createGradient(
p, attr->strokeGradient, localBounds, &
shape->stroke.type);
1015 if (
shape->stroke.gradient ==
nullptr)
1023 if (
p->image->shapes ==
nullptr)
1024 p->image->shapes =
shape;
1026 p->shapesTail->next =
shape;
1030 static void nsvg__addPath(NSVGparser*
p,
char closed)
1032 NSVGattrib* attr = nsvg__getAttr(
p);
1042 nsvg__lineTo(
p,
p->pts[0],
p->pts[1]);
1045 if (
path ==
nullptr)
goto error;
1048 path->pts =
static_cast<double*
>(malloc(
p->npts*2*
sizeof(
double)));
1049 if (
path->pts ==
nullptr)
goto error;
1050 path->closed = closed;
1051 path->npts =
p->npts;
1054 for (i = 0; i <
p->npts; ++i)
1055 nsvg__xformPoint(&
path->pts[i*2], &
path->pts[i*2+1],
p->pts[i*2],
p->pts[i*2+1], attr->xform);
1058 for (i = 0; i <
path->npts-1; i += 3) {
1059 curve = &
path->pts[i*2];
1060 nsvg__curveBounds(bounds, curve);
1062 path->bounds[0] = bounds[0];
1063 path->bounds[1] = bounds[1];
1064 path->bounds[2] = bounds[2];
1065 path->bounds[3] = bounds[3];
1067 path->bounds[0] = nsvg__minf(
path->bounds[0], bounds[0]);
1068 path->bounds[1] = nsvg__minf(
path->bounds[1], bounds[1]);
1069 path->bounds[2] = nsvg__maxf(
path->bounds[2], bounds[2]);
1070 path->bounds[3] = nsvg__maxf(
path->bounds[3], bounds[3]);
1074 path->next =
p->plist;
1080 if (
path !=
nullptr) {
1081 if (
path->pts !=
nullptr) free(
path->pts);
1087 static double nsvg__atof(
const char* s)
1089 const char* cur = s;
1090 char* end =
nullptr;
1091 double res = 0.0, sign = 1.0;
1092 long long intPart = 0, fracPart = 0;
1093 char hasIntPart = 0, hasFracPart = 0;
1098 }
else if (*cur ==
'-') {
1104 if (nsvg__isdigit(*cur)) {
1106 intPart = strtoll(cur, &end, 10);
1108 res =
static_cast<double>(intPart);
1117 if (nsvg__isdigit(*cur)) {
1119 fracPart = strtoll(cur, &end, 10);
1121 res +=
static_cast<double>(fracPart) / pow(10.0,
static_cast<double>(end - cur));
1129 if (!hasIntPart && !hasFracPart)
1133 if (*cur ==
'e' || *cur ==
'E') {
1136 expPart = strtol(cur, &end, 10);
1138 res *= pow(10.0,
static_cast<double>(expPart));
1146 static const char* nsvg__parseNumber(
const char* s,
char* it,
const int size)
1148 const int last =
size-1;
1152 if (*s ==
'-' || *s ==
'+') {
1153 if (i < last) it[i++] = *s;
1157 while (*s && nsvg__isdigit(*s)) {
1158 if (i < last) it[i++] = *s;
1163 if (i < last) it[i++] = *s;
1166 while (*s && nsvg__isdigit(*s)) {
1167 if (i < last) it[i++] = *s;
1172 if ((*s ==
'e' || *s ==
'E') && (s[1] !=
'm' && s[1] !=
'x')) {
1173 if (i < last) it[i++] = *s;
1175 if (*s ==
'-' || *s ==
'+') {
1176 if (i < last) it[i++] = *s;
1179 while (*s && nsvg__isdigit(*s)) {
1180 if (i < last) it[i++] = *s;
1189 static const char* nsvg__getNextPathItem(
const char* s,
char* it)
1193 while (*s && (nsvg__isspace(*s) || *s ==
',')) s++;
1195 if (*s ==
'-' || *s ==
'+' || *s ==
'.' || nsvg__isdigit(*s)) {
1196 s = nsvg__parseNumber(s, it, 64);
1207 static unsigned int nsvg__parseColorHex(
const char*
str)
1209 unsigned int c = 0, r = 0, g = 0, b = 0;
1213 while(
str[
n] && !nsvg__isspace(
str[
n]))
1216 sscanf(
str,
"%x", &c);
1217 }
else if (
n == 3) {
1218 sscanf(
str,
"%x", &c);
1219 c = (c&0xf) | ((c&0xf0) << 4) | ((c&0xf00) << 8);
1222 r = (c >> 16) & 0xff;
1223 g = (c >> 8) & 0xff;
1225 return NSVG_RGB(r,g,b);
1228 static unsigned int nsvg__parseColorRGB(
const char*
str)
1230 int r = -1, g = -1, b = -1;
1231 char s1[32]=
"", s2[32]=
"";
1232 sscanf(
str + 4,
"%d%[%%, \t]%d%[%%, \t]%d", &r, s1, &g, s2, &b);
1233 if (strchr(s1,
'%')) {
1234 return NSVG_RGB((r*255)/100,(g*255)/100,(b*255)/100);
1236 return NSVG_RGB(r,g,b);
1240 typedef struct NSVGNamedColor {
1245 NSVGNamedColor nsvg__colors[] = {
1247 {
"red", NSVG_RGB(255, 0, 0) },
1248 {
"green", NSVG_RGB( 0, 128, 0) },
1249 {
"blue", NSVG_RGB( 0, 0, 255) },
1250 {
"yellow", NSVG_RGB(255, 255, 0) },
1251 {
"cyan", NSVG_RGB( 0, 255, 255) },
1252 {
"magenta", NSVG_RGB(255, 0, 255) },
1253 {
"black", NSVG_RGB( 0, 0, 0) },
1254 {
"grey", NSVG_RGB(128, 128, 128) },
1255 {
"gray", NSVG_RGB(128, 128, 128) },
1256 {
"white", NSVG_RGB(255, 255, 255) },
1258 #ifdef NANOSVG_ALL_COLOR_KEYWORDS
1259 {
"aliceblue", NSVG_RGB(240, 248, 255) },
1260 {
"antiquewhite", NSVG_RGB(250, 235, 215) },
1261 {
"aqua", NSVG_RGB( 0, 255, 255) },
1262 {
"aquamarine", NSVG_RGB(127, 255, 212) },
1263 {
"azure", NSVG_RGB(240, 255, 255) },
1264 {
"beige", NSVG_RGB(245, 245, 220) },
1265 {
"bisque", NSVG_RGB(255, 228, 196) },
1266 {
"blanchedalmond", NSVG_RGB(255, 235, 205) },
1267 {
"blueviolet", NSVG_RGB(138, 43, 226) },
1268 {
"brown", NSVG_RGB(165, 42, 42) },
1269 {
"burlywood", NSVG_RGB(222, 184, 135) },
1270 {
"cadetblue", NSVG_RGB( 95, 158, 160) },
1271 {
"chartreuse", NSVG_RGB(127, 255, 0) },
1272 {
"chocolate", NSVG_RGB(210, 105, 30) },
1273 {
"coral", NSVG_RGB(255, 127, 80) },
1274 {
"cornflowerblue", NSVG_RGB(100, 149, 237) },
1275 {
"cornsilk", NSVG_RGB(255, 248, 220) },
1276 {
"crimson", NSVG_RGB(220, 20, 60) },
1277 {
"darkblue", NSVG_RGB( 0, 0, 139) },
1278 {
"darkcyan", NSVG_RGB( 0, 139, 139) },
1279 {
"darkgoldenrod", NSVG_RGB(184, 134, 11) },
1280 {
"darkgray", NSVG_RGB(169, 169, 169) },
1281 {
"darkgreen", NSVG_RGB( 0, 100, 0) },
1282 {
"darkgrey", NSVG_RGB(169, 169, 169) },
1283 {
"darkkhaki", NSVG_RGB(189, 183, 107) },
1284 {
"darkmagenta", NSVG_RGB(139, 0, 139) },
1285 {
"darkolivegreen", NSVG_RGB( 85, 107, 47) },
1286 {
"darkorange", NSVG_RGB(255, 140, 0) },
1287 {
"darkorchid", NSVG_RGB(153, 50, 204) },
1288 {
"darkred", NSVG_RGB(139, 0, 0) },
1289 {
"darksalmon", NSVG_RGB(233, 150, 122) },
1290 {
"darkseagreen", NSVG_RGB(143, 188, 143) },
1291 {
"darkslateblue", NSVG_RGB( 72, 61, 139) },
1292 {
"darkslategray", NSVG_RGB( 47, 79, 79) },
1293 {
"darkslategrey", NSVG_RGB( 47, 79, 79) },
1294 {
"darkturquoise", NSVG_RGB( 0, 206, 209) },
1295 {
"darkviolet", NSVG_RGB(148, 0, 211) },
1296 {
"deeppink", NSVG_RGB(255, 20, 147) },
1297 {
"deepskyblue", NSVG_RGB( 0, 191, 255) },
1298 {
"dimgray", NSVG_RGB(105, 105, 105) },
1299 {
"dimgrey", NSVG_RGB(105, 105, 105) },
1300 {
"dodgerblue", NSVG_RGB( 30, 144, 255) },
1301 {
"firebrick", NSVG_RGB(178, 34, 34) },
1302 {
"floralwhite", NSVG_RGB(255, 250, 240) },
1303 {
"forestgreen", NSVG_RGB( 34, 139, 34) },
1304 {
"fuchsia", NSVG_RGB(255, 0, 255) },
1305 {
"gainsboro", NSVG_RGB(220, 220, 220) },
1306 {
"ghostwhite", NSVG_RGB(248, 248, 255) },
1307 {
"gold", NSVG_RGB(255, 215, 0) },
1308 {
"goldenrod", NSVG_RGB(218, 165, 32) },
1309 {
"greenyellow", NSVG_RGB(173, 255, 47) },
1310 {
"honeydew", NSVG_RGB(240, 255, 240) },
1311 {
"hotpink", NSVG_RGB(255, 105, 180) },
1312 {
"indianred", NSVG_RGB(205, 92, 92) },
1313 {
"indigo", NSVG_RGB( 75, 0, 130) },
1314 {
"ivory", NSVG_RGB(255, 255, 240) },
1315 {
"khaki", NSVG_RGB(240, 230, 140) },
1316 {
"lavender", NSVG_RGB(230, 230, 250) },
1317 {
"lavenderblush", NSVG_RGB(255, 240, 245) },
1318 {
"lawngreen", NSVG_RGB(124, 252, 0) },
1319 {
"lemonchiffon", NSVG_RGB(255, 250, 205) },
1320 {
"lightblue", NSVG_RGB(173, 216, 230) },
1321 {
"lightcoral", NSVG_RGB(240, 128, 128) },
1322 {
"lightcyan", NSVG_RGB(224, 255, 255) },
1323 {
"lightgoldenrodyellow", NSVG_RGB(250, 250, 210) },
1324 {
"lightgray", NSVG_RGB(211, 211, 211) },
1325 {
"lightgreen", NSVG_RGB(144, 238, 144) },
1326 {
"lightgrey", NSVG_RGB(211, 211, 211) },
1327 {
"lightpink", NSVG_RGB(255, 182, 193) },
1328 {
"lightsalmon", NSVG_RGB(255, 160, 122) },
1329 {
"lightseagreen", NSVG_RGB( 32, 178, 170) },
1330 {
"lightskyblue", NSVG_RGB(135, 206, 250) },
1331 {
"lightslategray", NSVG_RGB(119, 136, 153) },
1332 {
"lightslategrey", NSVG_RGB(119, 136, 153) },
1333 {
"lightsteelblue", NSVG_RGB(176, 196, 222) },
1334 {
"lightyellow", NSVG_RGB(255, 255, 224) },
1335 {
"lime", NSVG_RGB( 0, 255, 0) },
1336 {
"limegreen", NSVG_RGB( 50, 205, 50) },
1337 {
"linen", NSVG_RGB(250, 240, 230) },
1338 {
"maroon", NSVG_RGB(128, 0, 0) },
1339 {
"mediumaquamarine", NSVG_RGB(102, 205, 170) },
1340 {
"mediumblue", NSVG_RGB( 0, 0, 205) },
1341 {
"mediumorchid", NSVG_RGB(186, 85, 211) },
1342 {
"mediumpurple", NSVG_RGB(147, 112, 219) },
1343 {
"mediumseagreen", NSVG_RGB( 60, 179, 113) },
1344 {
"mediumslateblue", NSVG_RGB(123, 104, 238) },
1345 {
"mediumspringgreen", NSVG_RGB( 0, 250, 154) },
1346 {
"mediumturquoise", NSVG_RGB( 72, 209, 204) },
1347 {
"mediumvioletred", NSVG_RGB(199, 21, 133) },
1348 {
"midnightblue", NSVG_RGB( 25, 25, 112) },
1349 {
"mintcream", NSVG_RGB(245, 255, 250) },
1350 {
"mistyrose", NSVG_RGB(255, 228, 225) },
1351 {
"moccasin", NSVG_RGB(255, 228, 181) },
1352 {
"navajowhite", NSVG_RGB(255, 222, 173) },
1353 {
"navy", NSVG_RGB( 0, 0, 128) },
1354 {
"oldlace", NSVG_RGB(253, 245, 230) },
1355 {
"olive", NSVG_RGB(128, 128, 0) },
1356 {
"olivedrab", NSVG_RGB(107, 142, 35) },
1357 {
"orange", NSVG_RGB(255, 165, 0) },
1358 {
"orangered", NSVG_RGB(255, 69, 0) },
1359 {
"orchid", NSVG_RGB(218, 112, 214) },
1360 {
"palegoldenrod", NSVG_RGB(238, 232, 170) },
1361 {
"palegreen", NSVG_RGB(152, 251, 152) },
1362 {
"paleturquoise", NSVG_RGB(175, 238, 238) },
1363 {
"palevioletred", NSVG_RGB(219, 112, 147) },
1364 {
"papayawhip", NSVG_RGB(255, 239, 213) },
1365 {
"peachpuff", NSVG_RGB(255, 218, 185) },
1366 {
"peru", NSVG_RGB(205, 133, 63) },
1367 {
"pink", NSVG_RGB(255, 192, 203) },
1368 {
"plum", NSVG_RGB(221, 160, 221) },
1369 {
"powderblue", NSVG_RGB(176, 224, 230) },
1370 {
"purple", NSVG_RGB(128, 0, 128) },
1371 {
"rosybrown", NSVG_RGB(188, 143, 143) },
1372 {
"royalblue", NSVG_RGB( 65, 105, 225) },
1373 {
"saddlebrown", NSVG_RGB(139, 69, 19) },
1374 {
"salmon", NSVG_RGB(250, 128, 114) },
1375 {
"sandybrown", NSVG_RGB(244, 164, 96) },
1376 {
"seagreen", NSVG_RGB( 46, 139, 87) },
1377 {
"seashell", NSVG_RGB(255, 245, 238) },
1378 {
"sienna", NSVG_RGB(160, 82, 45) },
1379 {
"silver", NSVG_RGB(192, 192, 192) },
1380 {
"skyblue", NSVG_RGB(135, 206, 235) },
1381 {
"slateblue", NSVG_RGB(106, 90, 205) },
1382 {
"slategray", NSVG_RGB(112, 128, 144) },
1383 {
"slategrey", NSVG_RGB(112, 128, 144) },
1384 {
"snow", NSVG_RGB(255, 250, 250) },
1385 {
"springgreen", NSVG_RGB( 0, 255, 127) },
1386 {
"steelblue", NSVG_RGB( 70, 130, 180) },
1387 {
"tan", NSVG_RGB(210, 180, 140) },
1388 {
"teal", NSVG_RGB( 0, 128, 128) },
1389 {
"thistle", NSVG_RGB(216, 191, 216) },
1390 {
"tomato", NSVG_RGB(255, 99, 71) },
1391 {
"turquoise", NSVG_RGB( 64, 224, 208) },
1392 {
"violet", NSVG_RGB(238, 130, 238) },
1393 {
"wheat", NSVG_RGB(245, 222, 179) },
1394 {
"whitesmoke", NSVG_RGB(245, 245, 245) },
1395 {
"yellowgreen", NSVG_RGB(154, 205, 50) },
1399 static unsigned int nsvg__parseColorName(
const char*
str)
1401 int i, ncolors =
sizeof(nsvg__colors) /
sizeof(NSVGNamedColor);
1403 for (i = 0; i < ncolors; i++) {
1404 if (strcmp(nsvg__colors[i].
name,
str) == 0) {
1405 return nsvg__colors[i].color;
1409 return NSVG_RGB(128, 128, 128);
1412 static unsigned int nsvg__parseColor(
const char*
str)
1415 while(*
str ==
' ') ++
str;
1417 if (len >= 1 && *
str ==
'#')
1418 return nsvg__parseColorHex(
str);
1419 else if (len >= 4 &&
str[0] ==
'r' &&
str[1] ==
'g' &&
str[2] ==
'b' &&
str[3] ==
'(')
1420 return nsvg__parseColorRGB(
str);
1421 return nsvg__parseColorName(
str);
1424 static double nsvg__parseOpacity(
const char*
str)
1426 double val = nsvg__atof(
str);
1427 if (
val < 0.0)
val = 0.0;
1428 if (
val > 1.0)
val = 1.0;
1432 static double nsvg__parseMiterLimit(
const char*
str)
1434 double val = nsvg__atof(
str);
1435 if (
val < 0.0)
val = 0.0;
1439 static int nsvg__parseUnits(
const char* units)
1441 if (units[0] ==
'p' && units[1] ==
'x')
1442 return NSVG_UNITS_PX;
1443 else if (units[0] ==
'p' && units[1] ==
't')
1444 return NSVG_UNITS_PT;
1445 else if (units[0] ==
'p' && units[1] ==
'c')
1446 return NSVG_UNITS_PC;
1447 else if (units[0] ==
'm' && units[1] ==
'm')
1448 return NSVG_UNITS_MM;
1449 else if (units[0] ==
'c' && units[1] ==
'm')
1450 return NSVG_UNITS_CM;
1451 else if (units[0] ==
'i' && units[1] ==
'n')
1452 return NSVG_UNITS_IN;
1453 else if (units[0] ==
'%')
1454 return NSVG_UNITS_PERCENT;
1455 else if (units[0] ==
'e' && units[1] ==
'm')
1456 return NSVG_UNITS_EM;
1457 else if (units[0] ==
'e' && units[1] ==
'x')
1458 return NSVG_UNITS_EX;
1459 return NSVG_UNITS_USER;
1462 static NSVGcoordinate nsvg__parseCoordinateRaw(
const char*
str)
1464 NSVGcoordinate coord = {0, NSVG_UNITS_USER};
1466 coord.units = nsvg__parseUnits(nsvg__parseNumber(
str, buf, 64));
1467 coord.value = nsvg__atof(buf);
1471 static NSVGcoordinate nsvg__coord(
double v,
int units)
1473 NSVGcoordinate coord = {v, units};
1477 static double nsvg__parseCoordinate(NSVGparser*
p,
const char*
str,
double orig,
double length)
1479 NSVGcoordinate coord = nsvg__parseCoordinateRaw(
str);
1480 return nsvg__convertToPixels(
p, coord, orig,
length);
1483 static int nsvg__parseTransformArgs(
const char*
str,
double* args,
int maxNa,
int* na)
1495 while (*end && *end !=
')') ++end;
1500 if (*
ptr ==
'-' || *
ptr ==
'+' || *
ptr ==
'.' || nsvg__isdigit(*
ptr)) {
1501 if (*na >= maxNa)
return 0;
1502 ptr = nsvg__parseNumber(
ptr, it, 64);
1503 args[(*na)++] = nsvg__atof(it);
1508 return static_cast<int>(end -
str);
1512 static int nsvg__parseMatrix(
double* xform,
const char*
str)
1516 int len = nsvg__parseTransformArgs(
str, t, 6, &na);
1517 if (na != 6)
return len;
1518 memcpy(xform, t,
sizeof(
double)*6);
1522 static int nsvg__parseTranslate(
double* xform,
const char*
str)
1527 int len = nsvg__parseTransformArgs(
str, args, 2, &na);
1528 if (na == 1) args[1] = 0.0;
1530 nsvg__xformSetTranslation(t, args[0], args[1]);
1531 memcpy(xform, t,
sizeof(
double)*6);
1535 static int nsvg__parseScale(
double* xform,
const char*
str)
1540 int len = nsvg__parseTransformArgs(
str, args, 2, &na);
1541 if (na == 1) args[1] = args[0];
1542 nsvg__xformSetScale(t, args[0], args[1]);
1543 memcpy(xform, t,
sizeof(
double)*6);
1547 static int nsvg__parseSkewX(
double* xform,
const char*
str)
1552 int len = nsvg__parseTransformArgs(
str, args, 1, &na);
1553 nsvg__xformSetSkewX(t, args[0]/180.0*NSVG_PI);
1554 memcpy(xform, t,
sizeof(
double)*6);
1558 static int nsvg__parseSkewY(
double* xform,
const char*
str)
1563 int len = nsvg__parseTransformArgs(
str, args, 1, &na);
1564 nsvg__xformSetSkewY(t, args[0]/180.0*NSVG_PI);
1565 memcpy(xform, t,
sizeof(
double)*6);
1569 static int nsvg__parseRotate(
double* xform,
const char*
str)
1575 int len = nsvg__parseTransformArgs(
str, args, 3, &na);
1577 args[1] = args[2] = 0.0;
1578 nsvg__xformIdentity(m);
1581 nsvg__xformSetTranslation(t, -args[1], -args[2]);
1582 nsvg__xformMultiply(m, t);
1585 nsvg__xformSetRotation(t, args[0]/180.0*NSVG_PI);
1586 nsvg__xformMultiply(m, t);
1589 nsvg__xformSetTranslation(t, args[1], args[2]);
1590 nsvg__xformMultiply(m, t);
1593 memcpy(xform, m,
sizeof(
double)*6);
1598 static void nsvg__parseTransform(
double* xform,
const char*
str)
1601 nsvg__xformIdentity(xform);
1604 if (strncmp(
str,
"matrix", 6) == 0)
1605 str += nsvg__parseMatrix(t,
str);
1606 else if (strncmp(
str,
"translate", 9) == 0)
1607 str += nsvg__parseTranslate(t,
str);
1608 else if (strncmp(
str,
"scale", 5) == 0)
1609 str += nsvg__parseScale(t,
str);
1610 else if (strncmp(
str,
"rotate", 6) == 0)
1611 str += nsvg__parseRotate(t,
str);
1612 else if (strncmp(
str,
"skewX", 5) == 0)
1613 str += nsvg__parseSkewX(t,
str);
1614 else if (strncmp(
str,
"skewY", 5) == 0)
1615 str += nsvg__parseSkewY(t,
str);
1621 nsvg__xformPremultiply(xform, t);
1625 static void nsvg__parseUrl(
char*
id,
const char*
str)
1631 while (i < 63 && *
str !=
')') {
1638 static char nsvg__parseLineCap(
const char*
str)
1640 if (strcmp(
str,
"butt") == 0)
1642 else if (strcmp(
str,
"round") == 0)
1644 else if (strcmp(
str,
"square") == 0)
1650 static char nsvg__parseLineJoin(
const char*
str)
1652 if (strcmp(
str,
"miter") == 0)
1654 else if (strcmp(
str,
"round") == 0)
1656 else if (strcmp(
str,
"bevel") == 0)
1662 static char nsvg__parseFillRule(
const char*
str)
1664 if (strcmp(
str,
"nonzero") == 0)
1666 else if (strcmp(
str,
"evenodd") == 0)
1672 static const char* nsvg__getNextDashItem(
const char* s,
char* it)
1677 while (*s && (nsvg__isspace(*s) || *s ==
',')) s++;
1679 while (*s && (!nsvg__isspace(*s) && *s !=
',')) {
1688 static int nsvg__parseStrokeDashArray(NSVGparser*
p,
const char*
str,
double* strokeDashArray)
1702 if (
count < NSVG_MAX_DASHES)
1703 strokeDashArray[
count++] = fabs(nsvg__parseCoordinate(
p,
item, 0.0, nsvg__actualLength(
p)));
1706 for (i = 0; i <
count; i++)
1707 sum += strokeDashArray[i];
1714 static void nsvg__parseStyle(NSVGparser*
p,
const char*
str);
1716 static int nsvg__parseAttr(NSVGparser*
p,
const char*
name,
const char*
value)
1719 NSVGattrib* attr = nsvg__getAttr(
p);
1720 if (!attr)
return 0;
1722 if (strcmp(
name,
"style") == 0) {
1723 nsvg__parseStyle(
p,
value);
1724 }
else if (strcmp(
name,
"display") == 0) {
1725 if (strcmp(
value,
"none") == 0)
1729 }
else if (strcmp(
name,
"fill") == 0) {
1730 if (strcmp(
value,
"none") == 0) {
1732 }
else if (strncmp(
value,
"url(", 4) == 0) {
1734 nsvg__parseUrl(attr->fillGradient,
value);
1737 attr->fillColor = nsvg__parseColor(
value);
1739 }
else if (strcmp(
name,
"opacity") == 0) {
1740 attr->opacity = nsvg__parseOpacity(
value);
1741 }
else if (strcmp(
name,
"fill-opacity") == 0) {
1742 attr->fillOpacity = nsvg__parseOpacity(
value);
1743 }
else if (strcmp(
name,
"stroke") == 0) {
1744 if (strcmp(
value,
"none") == 0) {
1745 attr->hasStroke = 0;
1746 }
else if (strncmp(
value,
"url(", 4) == 0) {
1747 attr->hasStroke = 2;
1748 nsvg__parseUrl(attr->strokeGradient,
value);
1750 attr->hasStroke = 1;
1751 attr->strokeColor = nsvg__parseColor(
value);
1753 }
else if (strcmp(
name,
"stroke-width") == 0) {
1754 attr->strokeWidth = nsvg__parseCoordinate(
p,
value, 0.0, nsvg__actualLength(
p));
1755 }
else if (strcmp(
name,
"stroke-dasharray") == 0) {
1756 attr->strokeDashCount = nsvg__parseStrokeDashArray(
p,
value, attr->strokeDashArray);
1757 }
else if (strcmp(
name,
"stroke-dashoffset") == 0) {
1758 attr->strokeDashOffset = nsvg__parseCoordinate(
p,
value, 0.0, nsvg__actualLength(
p));
1759 }
else if (strcmp(
name,
"stroke-opacity") == 0) {
1760 attr->strokeOpacity = nsvg__parseOpacity(
value);
1761 }
else if (strcmp(
name,
"stroke-linecap") == 0) {
1762 attr->strokeLineCap = nsvg__parseLineCap(
value);
1763 }
else if (strcmp(
name,
"stroke-linejoin") == 0) {
1764 attr->strokeLineJoin = nsvg__parseLineJoin(
value);
1765 }
else if (strcmp(
name,
"stroke-miterlimit") == 0) {
1766 attr->miterLimit = nsvg__parseMiterLimit(
value);
1767 }
else if (strcmp(
name,
"fill-rule") == 0) {
1768 attr->fillRule = nsvg__parseFillRule(
value);
1769 }
else if (strcmp(
name,
"font-size") == 0) {
1770 attr->fontSize = nsvg__parseCoordinate(
p,
value, 0.0, nsvg__actualLength(
p));
1771 }
else if (strcmp(
name,
"transform") == 0) {
1772 nsvg__parseTransform(xform,
value);
1773 nsvg__xformPremultiply(attr->xform, xform);
1774 }
else if (strcmp(
name,
"stop-color") == 0) {
1775 attr->stopColor = nsvg__parseColor(
value);
1776 }
else if (strcmp(
name,
"stop-opacity") == 0) {
1777 attr->stopOpacity = nsvg__parseOpacity(
value);
1778 }
else if (strcmp(
name,
"offset") == 0) {
1779 attr->stopOffset = nsvg__parseCoordinate(
p,
value, 0.0, 1.0);
1780 }
else if (strcmp(
name,
"id") == 0) {
1781 strncpy(attr->id,
value, 63);
1782 attr->id[63] =
'\0';
1789 static int nsvg__parseNameValue(NSVGparser*
p,
const char* start,
const char* end)
1803 while (
str > start && (*
str ==
':' || nsvg__isspace(*
str))) --
str;
1806 n =
static_cast<int>(
str - start);
1807 if (
n > 511)
n = 511;
1808 if (
n) memcpy(
name, start,
n);
1811 while (
val < end && (*
val ==
':' || nsvg__isspace(*
val))) ++
val;
1813 n =
static_cast<int>(end -
val);
1814 if (
n > 511)
n = 511;
1821 static void nsvg__parseStyle(NSVGparser*
p,
const char*
str)
1828 while(*
str && nsvg__isspace(*
str)) ++
str;
1834 while (end > start && (*end ==
';' || nsvg__isspace(*end))) --end;
1837 nsvg__parseNameValue(
p, start, end);
1842 static void nsvg__parseAttribs(NSVGparser*
p,
const char** attr)
1845 for (i = 0; attr[i]; i += 2)
1847 if (strcmp(attr[i],
"style") == 0)
1848 nsvg__parseStyle(
p, attr[i + 1]);
1850 nsvg__parseAttr(
p, attr[i], attr[i + 1]);
1854 static int nsvg__getArgsPerElement(
char cmd)
1884 static void nsvg__pathMoveTo(NSVGparser*
p,
double* cpx,
double* cpy,
double* args,
int rel)
1893 nsvg__moveTo(
p, *cpx, *cpy);
1896 static void nsvg__pathLineTo(NSVGparser*
p,
double* cpx,
double* cpy,
double* args,
int rel)
1905 nsvg__lineTo(
p, *cpx, *cpy);
1908 static void nsvg__pathHLineTo(NSVGparser*
p,
double* cpx,
double* cpy,
double* args,
int rel)
1914 nsvg__lineTo(
p, *cpx, *cpy);
1917 static void nsvg__pathVLineTo(NSVGparser*
p,
double* cpx,
double* cpy,
double* args,
int rel)
1923 nsvg__lineTo(
p, *cpx, *cpy);
1926 static void nsvg__pathCubicBezTo(NSVGparser*
p,
double* cpx,
double* cpy,
1927 double* cpx2,
double* cpy2,
double* args,
int rel)
1929 double x2, y2, cx1, cy1, cx2, cy2;
1932 cx1 = *cpx + args[0];
1933 cy1 = *cpy + args[1];
1934 cx2 = *cpx + args[2];
1935 cy2 = *cpy + args[3];
1936 x2 = *cpx + args[4];
1937 y2 = *cpy + args[5];
1947 nsvg__cubicBezTo(
p, cx1,cy1, cx2,cy2, x2,y2);
1955 static void nsvg__pathCubicBezShortTo(NSVGparser*
p,
double* cpx,
double* cpy,
1956 double* cpx2,
double* cpy2,
double* args,
int rel)
1958 double x1, y1, x2, y2, cx1, cy1, cx2, cy2;
1963 cx2 = *cpx + args[0];
1964 cy2 = *cpy + args[1];
1965 x2 = *cpx + args[2];
1966 y2 = *cpy + args[3];
1977 nsvg__cubicBezTo(
p, cx1,cy1, cx2,cy2, x2,y2);
1985 static void nsvg__pathQuadBezTo(NSVGparser*
p,
double* cpx,
double* cpy,
1986 double* cpx2,
double* cpy2,
double* args,
int rel)
1988 double x1, y1, x2, y2, cx, cy;
1989 double cx1, cy1, cx2, cy2;
1994 cx = *cpx + args[0];
1995 cy = *cpy + args[1];
1996 x2 = *cpx + args[2];
1997 y2 = *cpy + args[3];
2006 cx1 = x1 + 2.0/3.0*(cx - x1);
2007 cy1 = y1 + 2.0/3.0*(cy - y1);
2008 cx2 = x2 + 2.0/3.0*(cx - x2);
2009 cy2 = y2 + 2.0/3.0*(cy - y2);
2011 nsvg__cubicBezTo(
p, cx1,cy1, cx2,cy2, x2,y2);
2019 static void nsvg__pathQuadBezShortTo(NSVGparser*
p,
double* cpx,
double* cpy,
2020 double* cpx2,
double* cpy2,
double* args,
int rel)
2022 double x1, y1, x2, y2, cx, cy;
2023 double cx1, cy1, cx2, cy2;
2028 x2 = *cpx + args[0];
2029 y2 = *cpy + args[1];
2039 cx1 = x1 + 2.0/3.0*(cx - x1);
2040 cy1 = y1 + 2.0/3.0*(cy - y1);
2041 cx2 = x2 + 2.0/3.0*(cx - x2);
2042 cy2 = y2 + 2.0/3.0*(cy - y2);
2044 nsvg__cubicBezTo(
p, cx1,cy1, cx2,cy2, x2,y2);
2052 static double nsvg__sqr(
double x) {
return x*
x; }
2053 static double nsvg__vmag(
double x,
double y) {
return sqrt(
x*
x +
y*
y); }
2055 static double nsvg__vecrat(
double ux,
double uy,
double vx,
double vy)
2057 return (ux*vx + uy*vy) / (nsvg__vmag(ux,uy) * nsvg__vmag(vx,vy));
2060 static double nsvg__vecang(
double ux,
double uy,
double vx,
double vy)
2062 double r = nsvg__vecrat(ux,uy, vx,vy);
2063 if (r < -1.0) r = -1.0;
2064 if (r > 1.0) r = 1.0;
2065 return ((ux*vy < uy*vx) ? -1.0 : 1.0) * acos(r);
2068 static void nsvg__pathArcTo(NSVGparser*
p,
double* cpx,
double* cpy,
double* args,
int rel)
2071 double rx, ry, rotx;
2072 double x1, y1, x2, y2, cx, cy, dx, dy, d;
2073 double x1p, y1p, cxp, cyp, s, sa, sb;
2074 double ux, uy, vx, vy,
a1, da;
2075 double x,
y, tanx, tany, a,
px = 0, py = 0, ptanx = 0, ptany = 0, t[6];
2076 double sinrx, cosrx;
2083 rotx = args[2] / 180.0 * NSVG_PI;
2084 fa = fabs(args[3]) > 1e-6 ? 1 : 0;
2085 fs = fabs(args[4]) > 1e-6 ? 1 : 0;
2089 x2 = *cpx + args[5];
2090 y2 = *cpy + args[6];
2098 d = sqrt(dx*dx + dy*dy);
2099 if (d < 1e-6 || rx < 1e-6 || ry < 1e-6) {
2101 nsvg__lineTo(
p, x2, y2);
2113 x1p = cosrx * dx / 2.0 + sinrx * dy / 2.0;
2114 y1p = -sinrx * dx / 2.0 + cosrx * dy / 2.0;
2115 d = nsvg__sqr(x1p)/nsvg__sqr(rx) + nsvg__sqr(y1p)/nsvg__sqr(ry);
2123 sa = nsvg__sqr(rx)*nsvg__sqr(ry) - nsvg__sqr(rx)*nsvg__sqr(y1p) - nsvg__sqr(ry)*nsvg__sqr(x1p);
2124 sb = nsvg__sqr(rx)*nsvg__sqr(y1p) + nsvg__sqr(ry)*nsvg__sqr(x1p);
2125 if (sa < 0.0) sa = 0.0;
2130 cxp = s * rx * y1p / ry;
2131 cyp = s * -ry * x1p / rx;
2134 cx = (x1 + x2)/2.0 + cosrx*cxp - sinrx*cyp;
2135 cy = (y1 + y2)/2.0 + sinrx*cxp + cosrx*cyp;
2138 ux = (x1p - cxp) / rx;
2139 uy = (y1p - cyp) / ry;
2140 vx = (-x1p - cxp) / rx;
2141 vy = (-y1p - cyp) / ry;
2142 a1 = nsvg__vecang(1.0,0.0, ux,uy);
2143 da = nsvg__vecang(ux,uy, vx,vy);
2148 if (fs == 0 && da > 0)
2150 else if (fs == 1 && da < 0)
2154 t[0] = cosrx; t[1] = sinrx;
2155 t[2] = -sinrx; t[3] = cosrx;
2156 t[4] = cx; t[5] = cy;
2160 ndivs =
static_cast<int>(fabs(da) / (NSVG_PI*0.5) + 1.0);
2161 hda = (da /
static_cast<double>(ndivs)) / 2.0;
2162 kappa = fabs(4.0 / 3.0 * (1.0 - cos(hda)) / sin(hda));
2166 for (i = 0; i <= ndivs; i++) {
2167 a =
a1 + da * (
static_cast<double>(i) /
static_cast<double>(ndivs));
2170 nsvg__xformPoint(&
x, &
y, dx*rx, dy*ry, t);
2171 nsvg__xformVec(&tanx, &tany, -dy*rx * kappa, dx*ry * kappa, t);
2173 nsvg__cubicBezTo(
p,
px+ptanx,py+ptany,
x-tanx,
y-tany,
x,
y);
2184 static void nsvg__parsePath(NSVGparser*
p,
const char** attr)
2186 const char* s =
nullptr;
2191 double cpx, cpy, cpx2, cpy2;
2197 for (i = 0; attr[i]; i += 2) {
2198 if (strcmp(attr[i],
"d") == 0) {
2202 tmp[1] = attr[i + 1];
2205 nsvg__parseAttribs(
p, tmp);
2217 s = nsvg__getNextPathItem(s,
item);
2219 if (nsvg__isnum(
item[0])) {
2221 args[nargs++] = nsvg__atof(
item);
2222 if (nargs >= rargs) {
2226 nsvg__pathMoveTo(
p, &cpx, &cpy, args, cmd ==
'm' ? 1 : 0);
2229 cmd = (cmd ==
'm') ?
'l' :
'L';
2230 rargs = nsvg__getArgsPerElement(cmd);
2231 cpx2 = cpx; cpy2 = cpy;
2235 nsvg__pathLineTo(
p, &cpx, &cpy, args, cmd ==
'l' ? 1 : 0);
2236 cpx2 = cpx; cpy2 = cpy;
2240 nsvg__pathHLineTo(
p, &cpx, &cpy, args, cmd ==
'h' ? 1 : 0);
2241 cpx2 = cpx; cpy2 = cpy;
2245 nsvg__pathVLineTo(
p, &cpx, &cpy, args, cmd ==
'v' ? 1 : 0);
2246 cpx2 = cpx; cpy2 = cpy;
2250 nsvg__pathCubicBezTo(
p, &cpx, &cpy, &cpx2, &cpy2, args, cmd ==
'c' ? 1 : 0);
2254 nsvg__pathCubicBezShortTo(
p, &cpx, &cpy, &cpx2, &cpy2, args, cmd ==
's' ? 1 : 0);
2258 nsvg__pathQuadBezTo(
p, &cpx, &cpy, &cpx2, &cpy2, args, cmd ==
'q' ? 1 : 0);
2262 nsvg__pathQuadBezShortTo(
p, &cpx, &cpy, &cpx2, &cpy2, args, cmd ==
't' ? 1 : 0);
2266 nsvg__pathArcTo(
p, &cpx, &cpy, args, cmd ==
'a' ? 1 : 0);
2267 cpx2 = cpx; cpy2 = cpy;
2271 cpx = args[nargs-2];
2272 cpy = args[nargs-1];
2273 cpx2 = cpx; cpy2 = cpy;
2281 rargs = nsvg__getArgsPerElement(cmd);
2282 if (cmd ==
'M' || cmd ==
'm') {
2285 nsvg__addPath(
p, closedFlag);
2290 }
else if (cmd ==
'Z' || cmd ==
'z') {
2297 cpx2 = cpx; cpy2 = cpy;
2298 nsvg__addPath(
p, closedFlag);
2302 nsvg__moveTo(
p, cpx, cpy);
2310 nsvg__addPath(
p, closedFlag);
2316 static void nsvg__parseRect(NSVGparser*
p,
const char** attr)
2326 for (i = 0; attr[i]; i += 2) {
2327 if (!nsvg__parseAttr(
p, attr[i], attr[i + 1])) {
2328 if (strcmp(attr[i],
"x") == 0)
x = nsvg__parseCoordinate(
p, attr[i+1], nsvg__actualOrigX(
p), nsvg__actualWidth(
p));
2329 if (strcmp(attr[i],
"y") == 0)
y = nsvg__parseCoordinate(
p, attr[i+1], nsvg__actualOrigY(
p), nsvg__actualHeight(
p));
2330 if (strcmp(attr[i],
"width") == 0) w = nsvg__parseCoordinate(
p, attr[i+1], 0.0, nsvg__actualWidth(
p));
2331 if (strcmp(attr[i],
"height") == 0) h = nsvg__parseCoordinate(
p, attr[i+1], 0.0, nsvg__actualHeight(
p));
2332 if (strcmp(attr[i],
"rx") == 0) rx = fabs(nsvg__parseCoordinate(
p, attr[i+1], 0.0, nsvg__actualWidth(
p)));
2333 if (strcmp(attr[i],
"ry") == 0) ry = fabs(nsvg__parseCoordinate(
p, attr[i+1], 0.0, nsvg__actualHeight(
p)));
2337 if (rx < 0.0 && ry > 0.0) rx = ry;
2338 if (ry < 0.0 && rx > 0.0) ry = rx;
2339 if (rx < 0.0) rx = 0.0;
2340 if (ry < 0.0) ry = 0.0;
2341 if (rx > w/2.0) rx = w/2.0;
2342 if (ry > h/2.0) ry = h/2.0;
2344 #pragma GCC diagnostic push
2345 #pragma GCC diagnostic ignored "-Wfloat-equal"
2346 if (w != 0.0 && h != 0.0) {
2347 #pragma GCC diagnostic pop
2350 if (rx < 0.00001 || ry < 0.0001) {
2351 nsvg__moveTo(
p,
x,
y);
2352 nsvg__lineTo(
p,
x+w,
y);
2353 nsvg__lineTo(
p,
x+w,
y+h);
2354 nsvg__lineTo(
p,
x,
y+h);
2357 nsvg__moveTo(
p,
x+rx,
y);
2358 nsvg__lineTo(
p,
x+w-rx,
y);
2359 nsvg__cubicBezTo(
p,
x+w-rx*(1-NSVG_KAPPA90),
y,
x+w,
y+ry*(1-NSVG_KAPPA90),
x+w,
y+ry);
2360 nsvg__lineTo(
p,
x+w,
y+h-ry);
2361 nsvg__cubicBezTo(
p,
x+w,
y+h-ry*(1-NSVG_KAPPA90),
x+w-rx*(1-NSVG_KAPPA90),
y+h,
x+w-rx,
y+h);
2362 nsvg__lineTo(
p,
x+rx,
y+h);
2363 nsvg__cubicBezTo(
p,
x+rx*(1-NSVG_KAPPA90),
y+h,
x,
y+h-ry*(1-NSVG_KAPPA90),
x,
y+h-ry);
2364 nsvg__lineTo(
p,
x,
y+ry);
2365 nsvg__cubicBezTo(
p,
x,
y+ry*(1-NSVG_KAPPA90),
x+rx*(1-NSVG_KAPPA90),
y,
x+rx,
y);
2368 nsvg__addPath(
p, 1);
2374 static void nsvg__parseCircle(NSVGparser*
p,
const char** attr)
2381 for (i = 0; attr[i]; i += 2) {
2382 if (!nsvg__parseAttr(
p, attr[i], attr[i + 1])) {
2383 if (strcmp(attr[i],
"cx") == 0) cx = nsvg__parseCoordinate(
p, attr[i+1], nsvg__actualOrigX(
p), nsvg__actualWidth(
p));
2384 if (strcmp(attr[i],
"cy") == 0) cy = nsvg__parseCoordinate(
p, attr[i+1], nsvg__actualOrigY(
p), nsvg__actualHeight(
p));
2385 if (strcmp(attr[i],
"r") == 0) r = fabs(nsvg__parseCoordinate(
p, attr[i+1], 0.0, nsvg__actualLength(
p)));
2392 nsvg__moveTo(
p, cx+r, cy);
2393 nsvg__cubicBezTo(
p, cx+r, cy+r*NSVG_KAPPA90, cx+r*NSVG_KAPPA90, cy+r, cx, cy+r);
2394 nsvg__cubicBezTo(
p, cx-r*NSVG_KAPPA90, cy+r, cx-r, cy+r*NSVG_KAPPA90, cx-r, cy);
2395 nsvg__cubicBezTo(
p, cx-r, cy-r*NSVG_KAPPA90, cx-r*NSVG_KAPPA90, cy-r, cx, cy-r);
2396 nsvg__cubicBezTo(
p, cx+r*NSVG_KAPPA90, cy-r, cx+r, cy-r*NSVG_KAPPA90, cx+r, cy);
2398 nsvg__addPath(
p, 1);
2404 static void nsvg__parseEllipse(NSVGparser*
p,
const char** attr)
2412 for (i = 0; attr[i]; i += 2) {
2413 if (!nsvg__parseAttr(
p, attr[i], attr[i + 1])) {
2414 if (strcmp(attr[i],
"cx") == 0) cx = nsvg__parseCoordinate(
p, attr[i+1], nsvg__actualOrigX(
p), nsvg__actualWidth(
p));
2415 if (strcmp(attr[i],
"cy") == 0) cy = nsvg__parseCoordinate(
p, attr[i+1], nsvg__actualOrigY(
p), nsvg__actualHeight(
p));
2416 if (strcmp(attr[i],
"rx") == 0) rx = fabs(nsvg__parseCoordinate(
p, attr[i+1], 0.0, nsvg__actualWidth(
p)));
2417 if (strcmp(attr[i],
"ry") == 0) ry = fabs(nsvg__parseCoordinate(
p, attr[i+1], 0.0, nsvg__actualHeight(
p)));
2421 if (rx > 0.0 && ry > 0.0) {
2425 nsvg__moveTo(
p, cx+rx, cy);
2426 nsvg__cubicBezTo(
p, cx+rx, cy+ry*NSVG_KAPPA90, cx+rx*NSVG_KAPPA90, cy+ry, cx, cy+ry);
2427 nsvg__cubicBezTo(
p, cx-rx*NSVG_KAPPA90, cy+ry, cx-rx, cy+ry*NSVG_KAPPA90, cx-rx, cy);
2428 nsvg__cubicBezTo(
p, cx-rx, cy-ry*NSVG_KAPPA90, cx-rx*NSVG_KAPPA90, cy-ry, cx, cy-ry);
2429 nsvg__cubicBezTo(
p, cx+rx*NSVG_KAPPA90, cy-ry, cx+rx, cy-ry*NSVG_KAPPA90, cx+rx, cy);
2431 nsvg__addPath(
p, 1);
2437 static void nsvg__parseLine(NSVGparser*
p,
const char** attr)
2445 for (i = 0; attr[i]; i += 2) {
2446 if (!nsvg__parseAttr(
p, attr[i], attr[i + 1])) {
2447 if (strcmp(attr[i],
"x1") == 0) x1 = nsvg__parseCoordinate(
p, attr[i + 1], nsvg__actualOrigX(
p), nsvg__actualWidth(
p));
2448 if (strcmp(attr[i],
"y1") == 0) y1 = nsvg__parseCoordinate(
p, attr[i + 1], nsvg__actualOrigY(
p), nsvg__actualHeight(
p));
2449 if (strcmp(attr[i],
"x2") == 0) x2 = nsvg__parseCoordinate(
p, attr[i + 1], nsvg__actualOrigX(
p), nsvg__actualWidth(
p));
2450 if (strcmp(attr[i],
"y2") == 0) y2 = nsvg__parseCoordinate(
p, attr[i + 1], nsvg__actualOrigY(
p), nsvg__actualHeight(
p));
2456 nsvg__moveTo(
p, x1, y1);
2457 nsvg__lineTo(
p, x2, y2);
2459 nsvg__addPath(
p, 0);
2464 static void nsvg__parsePoly(NSVGparser*
p,
const char** attr,
int closeFlag)
2469 int nargs, npts = 0;
2474 for (i = 0; attr[i]; i += 2) {
2475 if (!nsvg__parseAttr(
p, attr[i], attr[i + 1])) {
2476 if (strcmp(attr[i],
"points") == 0) {
2480 s = nsvg__getNextPathItem(s,
item);
2481 args[nargs++] = nsvg__atof(
item);
2484 nsvg__moveTo(
p, args[0], args[1]);
2486 nsvg__lineTo(
p, args[0], args[1]);
2495 nsvg__addPath(
p,
static_cast<char>(closeFlag));
2500 static void nsvg__parseSVG(NSVGparser*
p,
const char** attr)
2503 for (i = 0; attr[i]; i += 2) {
2504 if (!nsvg__parseAttr(
p, attr[i], attr[i + 1])) {
2505 if (strcmp(attr[i],
"width") == 0) {
2506 p->image->width = nsvg__parseCoordinate(
p, attr[i + 1], 0.0, 0.0);
2507 }
else if (strcmp(attr[i],
"height") == 0) {
2508 p->image->height = nsvg__parseCoordinate(
p, attr[i + 1], 0.0, 0.0);
2509 }
else if (strcmp(attr[i],
"viewBox") == 0) {
2510 const char *s = attr[i + 1];
2512 s = nsvg__parseNumber(s, buf, 64);
2513 p->viewMinx = nsvg__atof(buf);
2514 while (*s && (nsvg__isspace(*s) || *s ==
'%' || *s ==
',')) s++;
2516 s = nsvg__parseNumber(s, buf, 64);
2517 p->viewMiny = nsvg__atof(buf);
2518 while (*s && (nsvg__isspace(*s) || *s ==
'%' || *s ==
',')) s++;
2520 s = nsvg__parseNumber(s, buf, 64);
2521 p->viewWidth = nsvg__atof(buf);
2522 while (*s && (nsvg__isspace(*s) || *s ==
'%' || *s ==
',')) s++;
2524 s = nsvg__parseNumber(s, buf, 64);
2525 p->viewHeight = nsvg__atof(buf);
2526 }
else if (strcmp(attr[i],
"preserveAspectRatio") == 0) {
2527 if (strstr(attr[i + 1],
"none") !=
nullptr) {
2529 p->alignType = NSVG_ALIGN_NONE;
2532 if (strstr(attr[i + 1],
"xMin") !=
nullptr)
2533 p->alignX = NSVG_ALIGN_MIN;
2534 else if (strstr(attr[i + 1],
"xMid") !=
nullptr)
2535 p->alignX = NSVG_ALIGN_MID;
2536 else if (strstr(attr[i + 1],
"xMax") !=
nullptr)
2537 p->alignX = NSVG_ALIGN_MAX;
2539 if (strstr(attr[i + 1],
"yMin") !=
nullptr)
2540 p->alignY = NSVG_ALIGN_MIN;
2541 else if (strstr(attr[i + 1],
"yMid") !=
nullptr)
2542 p->alignY = NSVG_ALIGN_MID;
2543 else if (strstr(attr[i + 1],
"yMax") !=
nullptr)
2544 p->alignY = NSVG_ALIGN_MAX;
2546 p->alignType = NSVG_ALIGN_MEET;
2547 if (strstr(attr[i + 1],
"slice") !=
nullptr)
2548 p->alignType = NSVG_ALIGN_SLICE;
2555 static void nsvg__parseGradient(NSVGparser*
p,
const char** attr,
char type)
2558 NSVGgradientData* grad =
static_cast<NSVGgradientData*
>(malloc(
sizeof(NSVGgradientData)));
2559 if (grad ==
nullptr)
return;
2560 memset(grad, 0,
sizeof(NSVGgradientData));
2561 grad->units = NSVG_OBJECT_SPACE;
2564 grad->linear.x1 = nsvg__coord(0.0, NSVG_UNITS_PERCENT);
2565 grad->linear.y1 = nsvg__coord(0.0, NSVG_UNITS_PERCENT);
2566 grad->linear.x2 = nsvg__coord(100.0, NSVG_UNITS_PERCENT);
2567 grad->linear.y2 = nsvg__coord(0.0, NSVG_UNITS_PERCENT);
2569 grad->radial.cx = nsvg__coord(50.0, NSVG_UNITS_PERCENT);
2570 grad->radial.cy = nsvg__coord(50.0, NSVG_UNITS_PERCENT);
2571 grad->radial.r = nsvg__coord(50.0, NSVG_UNITS_PERCENT);
2574 nsvg__xformIdentity(grad->xform);
2576 for (i = 0; attr[i]; i += 2) {
2577 if (strcmp(attr[i],
"id") == 0) {
2578 strncpy(grad->id, attr[i+1], 63);
2579 grad->id[63] =
'\0';
2580 }
else if (!nsvg__parseAttr(
p, attr[i], attr[i + 1])) {
2581 if (strcmp(attr[i],
"gradientUnits") == 0) {
2582 if (strcmp(attr[i+1],
"objectBoundingBox") == 0)
2583 grad->units = NSVG_OBJECT_SPACE;
2585 grad->units = NSVG_USER_SPACE;
2586 }
else if (strcmp(attr[i],
"gradientTransform") == 0) {
2587 nsvg__parseTransform(grad->xform, attr[i + 1]);
2588 }
else if (strcmp(attr[i],
"cx") == 0) {
2589 grad->radial.cx = nsvg__parseCoordinateRaw(attr[i + 1]);
2590 }
else if (strcmp(attr[i],
"cy") == 0) {
2591 grad->radial.cy = nsvg__parseCoordinateRaw(attr[i + 1]);
2592 }
else if (strcmp(attr[i],
"r") == 0) {
2593 grad->radial.r = nsvg__parseCoordinateRaw(attr[i + 1]);
2594 }
else if (strcmp(attr[i],
"fx") == 0) {
2595 grad->radial.fx = nsvg__parseCoordinateRaw(attr[i + 1]);
2596 }
else if (strcmp(attr[i],
"fy") == 0) {
2597 grad->radial.fy = nsvg__parseCoordinateRaw(attr[i + 1]);
2598 }
else if (strcmp(attr[i],
"x1") == 0) {
2599 grad->linear.x1 = nsvg__parseCoordinateRaw(attr[i + 1]);
2600 }
else if (strcmp(attr[i],
"y1") == 0) {
2601 grad->linear.y1 = nsvg__parseCoordinateRaw(attr[i + 1]);
2602 }
else if (strcmp(attr[i],
"x2") == 0) {
2603 grad->linear.x2 = nsvg__parseCoordinateRaw(attr[i + 1]);
2604 }
else if (strcmp(attr[i],
"y2") == 0) {
2605 grad->linear.y2 = nsvg__parseCoordinateRaw(attr[i + 1]);
2606 }
else if (strcmp(attr[i],
"spreadMethod") == 0) {
2607 if (strcmp(attr[i+1],
"pad") == 0)
2609 else if (strcmp(attr[i+1],
"reflect") == 0)
2611 else if (strcmp(attr[i+1],
"repeat") == 0)
2613 }
else if (strcmp(attr[i],
"xlink:href") == 0) {
2614 const char *href = attr[i+1];
2615 strncpy(grad->ref, href+1, 62);
2616 grad->ref[62] =
'\0';
2621 grad->next =
p->gradients;
2622 p->gradients = grad;
2625 static void nsvg__parseGradientStop(NSVGparser*
p,
const char** attr)
2627 NSVGattrib* curAttr = nsvg__getAttr(
p);
2628 NSVGgradientData* grad;
2632 curAttr->stopOffset = 0;
2633 curAttr->stopColor = 0;
2634 curAttr->stopOpacity = 1.0;
2636 for (i = 0; attr[i]; i += 2) {
2637 nsvg__parseAttr(
p, attr[i], attr[i + 1]);
2641 grad =
p->gradients;
2642 if (grad ==
nullptr)
return;
2646 if (grad->stops ==
nullptr)
return;
2649 idx = grad->nstops-1;
2650 for (i = 0; i < grad->nstops-1; i++) {
2651 if (curAttr->stopOffset < grad->stops[i].offset) {
2656 if (idx != grad->nstops-1) {
2657 for (i = grad->nstops-1; i > idx; i--)
2658 grad->stops[i] = grad->stops[i-1];
2661 stop = &grad->stops[idx];
2662 stop->color = curAttr->stopColor;
2663 stop->color |=
static_cast<unsigned int>(curAttr->stopOpacity*255) << 24;
2664 stop->offset = curAttr->stopOffset;
2667 static void nsvg__startElement(
void* ud,
const char* el,
const char** attr)
2669 NSVGparser*
p =
static_cast<NSVGparser*
>(ud);
2673 if (strcmp(el,
"linearGradient") == 0) {
2675 }
else if (strcmp(el,
"radialGradient") == 0) {
2677 }
else if (strcmp(el,
"stop") == 0) {
2678 nsvg__parseGradientStop(
p, attr);
2683 if (strcmp(el,
"g") == 0) {
2685 nsvg__parseAttribs(
p, attr);
2686 }
else if (strcmp(el,
"path") == 0) {
2690 nsvg__parsePath(
p, attr);
2692 }
else if (strcmp(el,
"rect") == 0) {
2694 nsvg__parseRect(
p, attr);
2696 }
else if (strcmp(el,
"circle") == 0) {
2698 nsvg__parseCircle(
p, attr);
2700 }
else if (strcmp(el,
"ellipse") == 0) {
2702 nsvg__parseEllipse(
p, attr);
2704 }
else if (strcmp(el,
"line") == 0) {
2706 nsvg__parseLine(
p, attr);
2708 }
else if (strcmp(el,
"polyline") == 0) {
2710 nsvg__parsePoly(
p, attr, 0);
2712 }
else if (strcmp(el,
"polygon") == 0) {
2714 nsvg__parsePoly(
p, attr, 1);
2716 }
else if (strcmp(el,
"linearGradient") == 0) {
2718 }
else if (strcmp(el,
"radialGradient") == 0) {
2720 }
else if (strcmp(el,
"stop") == 0) {
2721 nsvg__parseGradientStop(
p, attr);
2722 }
else if (strcmp(el,
"defs") == 0) {
2724 }
else if (strcmp(el,
"svg") == 0) {
2725 nsvg__parseSVG(
p, attr);
2729 static void nsvg__endElement(
void* ud,
const char* el)
2731 NSVGparser*
p =
static_cast<NSVGparser*
>(ud);
2733 if (strcmp(el,
"g") == 0) {
2735 }
else if (strcmp(el,
"path") == 0) {
2737 }
else if (strcmp(el,
"defs") == 0) {
2742 static void nsvg__content(
void* ud,
const char* s)
2744 #pragma GCC diagnostic push
2745 #pragma GCC diagnostic ignored "-Wduplicated-branches"
2748 #pragma GCC diagnostic pop
2752 static void nsvg__imageBounds(NSVGparser*
p,
double* bounds)
2755 shape =
p->image->shapes;
2756 if (
shape ==
nullptr) {
2757 bounds[0] = bounds[1] = bounds[2] = bounds[3] = 0.0;
2760 bounds[0] =
shape->bounds[0];
2761 bounds[1] =
shape->bounds[1];
2762 bounds[2] =
shape->bounds[2];
2763 bounds[3] =
shape->bounds[3];
2765 bounds[0] = nsvg__minf(bounds[0],
shape->bounds[0]);
2766 bounds[1] = nsvg__minf(bounds[1],
shape->bounds[1]);
2767 bounds[2] = nsvg__maxf(bounds[2],
shape->bounds[2]);
2768 bounds[3] = nsvg__maxf(bounds[3],
shape->bounds[3]);
2772 static double nsvg__viewAlign(
double content,
double container,
int type)
2774 if (type == NSVG_ALIGN_MIN)
2776 else if (type == NSVG_ALIGN_MAX)
2777 return container - content;
2779 return (container - content) * 0.5;
2782 static void nsvg__scaleGradient(
NSVGgradient* grad,
double tx,
double ty,
double sx,
double sy)
2785 nsvg__xformSetTranslation(t, tx, ty);
2786 nsvg__xformMultiply (grad->
xform, t);
2788 nsvg__xformSetScale(t, sx, sy);
2789 nsvg__xformMultiply (grad->
xform, t);
2792 static void nsvg__scaleToViewbox(NSVGparser*
p,
const char* units)
2796 double tx, ty, sx, sy, us, bounds[4], t[6], avgs;
2801 nsvg__imageBounds(
p, bounds);
2803 #pragma GCC diagnostic push
2804 #pragma GCC diagnostic ignored "-Wfloat-equal"
2805 if (
p->viewWidth == 0) {
2806 if (
p->image->width > 0) {
2807 p->viewWidth =
p->image->width;
2809 p->viewMinx = bounds[0];
2810 p->viewWidth = bounds[2] - bounds[0];
2813 if (
p->viewHeight == 0) {
2814 if (
p->image->height > 0) {
2815 p->viewHeight =
p->image->height;
2817 p->viewMiny = bounds[1];
2818 p->viewHeight = bounds[3] - bounds[1];
2821 if (
p->image->width == 0)
2822 p->image->width =
p->viewWidth;
2823 if (
p->image->height == 0)
2824 #pragma GCC diagnostic pop
2825 p->image->height =
p->viewHeight;
2829 sx =
p->viewWidth > 0 ?
p->image->width /
p->viewWidth : 0;
2830 sy =
p->viewHeight > 0 ?
p->image->height /
p->viewHeight : 0;
2832 us = 1.0 / nsvg__convertToPixels(
p, nsvg__coord(1.0, nsvg__parseUnits(units)), 0.0, 1.0);
2835 if (
p->alignType == NSVG_ALIGN_MEET) {
2837 sx = sy = nsvg__minf(sx, sy);
2838 tx += nsvg__viewAlign(
p->viewWidth*sx,
p->image->width,
p->alignX) / sx;
2839 ty += nsvg__viewAlign(
p->viewHeight*sy,
p->image->height,
p->alignY) / sy;
2840 }
else if (
p->alignType == NSVG_ALIGN_SLICE) {
2842 sx = sy = nsvg__maxf(sx, sy);
2843 tx += nsvg__viewAlign(
p->viewWidth*sx,
p->image->width,
p->alignX) / sx;
2844 ty += nsvg__viewAlign(
p->viewHeight*sy,
p->image->height,
p->alignY) / sy;
2850 avgs = (sx+sy) / 2.0;
2852 shape->bounds[0] = (
shape->bounds[0] + tx) * sx;
2853 shape->bounds[1] = (
shape->bounds[1] + ty) * sy;
2854 shape->bounds[2] = (
shape->bounds[2] + tx) * sx;
2855 shape->bounds[3] = (
shape->bounds[3] + ty) * sy;
2857 path->bounds[0] = (
path->bounds[0] + tx) * sx;
2858 path->bounds[1] = (
path->bounds[1] + ty) * sy;
2859 path->bounds[2] = (
path->bounds[2] + tx) * sx;
2860 path->bounds[3] = (
path->bounds[3] + ty) * sy;
2861 for (i =0; i <
path->npts; i++) {
2862 pt = &
path->pts[i*2];
2863 pt[0] = (pt[0] + tx) * sx;
2864 pt[1] = (pt[1] + ty) * sy;
2869 nsvg__scaleGradient(
shape->fill.gradient, tx,ty, sx,sy);
2870 memcpy(t,
shape->fill.gradient->xform,
sizeof(
double)*6);
2871 nsvg__xformInverse(
shape->fill.gradient->xform, t);
2874 nsvg__scaleGradient(
shape->stroke.gradient, tx,ty, sx,sy);
2875 memcpy(t,
shape->stroke.gradient->xform,
sizeof(
double)*6);
2876 nsvg__xformInverse(
shape->stroke.gradient->xform, t);
2879 shape->strokeWidth *= avgs;
2880 shape->strokeDashOffset *= avgs;
2881 for (i = 0; i <
shape->strokeDashCount; i++)
2882 shape->strokeDashArray[i] *= avgs;
2891 p = nsvg__createParser();
2897 nsvg__parseXML(
input, nsvg__startElement, nsvg__endElement, nsvg__content,
p);
2900 nsvg__scaleToViewbox(
p, units);
2905 nsvg__deleteParser(
p);
2914 char*
data =
nullptr;
2918 if (!fp)
goto error;
2919 fseek(fp, 0, SEEK_END);
2921 fseek(fp, 0, SEEK_SET);
2922 data =
static_cast<char*
>(malloc(
size+1));
2923 if (
data ==
nullptr)
goto error;
2946 if (res ==
nullptr)
goto error;
2949 res->
pts =
static_cast<double*
>(malloc(
p->npts*2*
sizeof(
double)));
2950 if (res->
pts ==
nullptr)
goto error;
2951 memcpy(res->
pts,
p->pts,
p->npts *
sizeof(
double) * 2);
2952 res->
npts =
p->npts;
2954 memcpy(res->
bounds,
p->bounds,
sizeof(
p->bounds));
2961 if (res !=
nullptr) {
2971 if (image ==
nullptr)
return;
2973 while (
shape !=
nullptr) {
2974 snext =
shape->next;
2975 nsvg__deletePaths(
shape->paths);
2976 nsvg__deletePaint(&
shape->fill);
2977 nsvg__deletePaint(&
shape->stroke);
static int ptr
Definition: bcm.cpp:17
ucs4_t int n
Definition: big5.h:4148
const char * filename
Definition: epng.h:36
const char int int int float scale
Definition: epng.h:39
void shape(std::vector< unsigned long > &string, const std::vector< unsigned long > &text)
Definition: font_arabic.cpp:218
unsigned char length
Definition: hdmi_cec.h:1
unsigned char data[256]
Definition: hdmi_cec.h:2
FILE * fopen(const char *pathname, const char *mode)
Definition: libopen.c:126
size
Definition: Plugins/SystemPlugins/PositionerSetup/log.py:16
name
Definition: newplugin.py:9
bool stop
Definition: newplugin.py:43
int count
Definition: newplugin.py:14
list ref
Definition: create_picon_e1_to_e2.py:17
str
Definition: enigma_py_patcher.py:14
def px(x)
Definition: svg2skin.py:36
p
Definition: upgrade.py:63
struct NSVGgradient NSVGgradient
NSVGfillRule
Definition: nanosvg.h:104
@ NSVG_FILLRULE_NONZERO
Definition: nanosvg.h:105
@ NSVG_FILLRULE_EVENODD
Definition: nanosvg.h:106
NSVGlineCap
Definition: nanosvg.h:98
@ NSVG_CAP_SQUARE
Definition: nanosvg.h:101
@ NSVG_CAP_BUTT
Definition: nanosvg.h:99
@ NSVG_CAP_ROUND
Definition: nanosvg.h:100
struct NSVGgradientStop NSVGgradientStop
NSVGflags
Definition: nanosvg.h:109
@ NSVG_FLAGS_VISIBLE
Definition: nanosvg.h:110
NSVGpaintType
Definition: nanosvg.h:79
@ NSVG_PAINT_NONE
Definition: nanosvg.h:80
@ NSVG_PAINT_COLOR
Definition: nanosvg.h:81
@ NSVG_PAINT_RADIAL_GRADIENT
Definition: nanosvg.h:83
@ NSVG_PAINT_LINEAR_GRADIENT
Definition: nanosvg.h:82
struct NSVGshape NSVGshape
NSVGimage * nsvgParse(char *input, const char *units, double dpi)
struct NSVGpaint NSVGpaint
struct NSVGimage NSVGimage
NSVGimage * nsvgParseFromFile(const char *filename, const char *units, double dpi)
void nsvgDelete(NSVGimage *image)
NSVGpath * nsvgDuplicatePath(NSVGpath *p)
NSVGspreadType
Definition: nanosvg.h:86
@ NSVG_SPREAD_REPEAT
Definition: nanosvg.h:89
@ NSVG_SPREAD_PAD
Definition: nanosvg.h:87
@ NSVG_SPREAD_REFLECT
Definition: nanosvg.h:88
NSVGlineJoin
Definition: nanosvg.h:92
@ NSVG_JOIN_BEVEL
Definition: nanosvg.h:95
@ NSVG_JOIN_ROUND
Definition: nanosvg.h:94
@ NSVG_JOIN_MITER
Definition: nanosvg.h:93
std::string int int y
Definition: picload.cpp:1503
std::string int x
Definition: picload.cpp:1503
#define a1
Definition: rotor_calc.cpp:148
Definition: nanosvg.h:118
double xform[6]
Definition: nanosvg.h:119
int nstops
Definition: nanosvg.h:122
char spread
Definition: nanosvg.h:120
double fy
Definition: nanosvg.h:121
NSVGgradientStop stops[1]
Definition: nanosvg.h:123
double fx
Definition: nanosvg.h:121
Definition: nanosvg.h:113
unsigned int color
Definition: nanosvg.h:114
double offset
Definition: nanosvg.h:115
Definition: nanosvg.h:164
double width
Definition: nanosvg.h:165
double height
Definition: nanosvg.h:166
NSVGshape * shapes
Definition: nanosvg.h:167
Definition: nanosvg.h:126
char type
Definition: nanosvg.h:127
unsigned int color
Definition: nanosvg.h:129
NSVGgradient * gradient
Definition: nanosvg.h:130
Definition: nanosvg.h:135
double bounds[4]
Definition: nanosvg.h:139
char closed
Definition: nanosvg.h:138
int npts
Definition: nanosvg.h:137
struct NSVGpath * next
Definition: nanosvg.h:140
double * pts
Definition: nanosvg.h:136
Definition: nanosvg.h:144
NSVGpath * paths
Definition: nanosvg.h:159
double strokeWidth
Definition: nanosvg.h:149
double miterLimit
Definition: nanosvg.h:155
char strokeLineCap
Definition: nanosvg.h:154
char strokeDashCount
Definition: nanosvg.h:152
NSVGpaint fill
Definition: nanosvg.h:146
double bounds[4]
Definition: nanosvg.h:158
struct NSVGshape * next
Definition: nanosvg.h:160
double strokeDashOffset
Definition: nanosvg.h:150
char strokeLineJoin
Definition: nanosvg.h:153
double opacity
Definition: nanosvg.h:148
unsigned char flags
Definition: nanosvg.h:157
NSVGpaint stroke
Definition: nanosvg.h:147
char fillRule
Definition: nanosvg.h:156
double strokeDashArray[8]
Definition: nanosvg.h:151
Definition: picload.cpp:163