summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2020-10-05 22:18:22 +1100
committer Vas Crabb <vas@vastheman.com>2020-10-05 22:18:22 +1100
commitf390ea1004a4563bb79912a1a13d5de70c2e316b (patch)
tree51f3367173c2c8088a9514cfb084b34967587763
parenta89f9b274e9968aab7fde58110c3cb72378c4843 (diff)
3rdparty/nanosvg: Re-base on latest upstream.
Now based on upstream cc6c08d3a80f1a305021af3d6394cdf1535d02a2. Among other things, this version is supposed to be less sensitive to the global locale.
-rw-r--r--3rdparty/nanosvg/README.md8
-rw-r--r--3rdparty/nanosvg/example/example2.c2
-rw-r--r--3rdparty/nanosvg/premake4.lua2
-rw-r--r--3rdparty/nanosvg/src/nanosvg.h331
-rw-r--r--3rdparty/nanosvg/src/nanosvgrast.h43
-rw-r--r--src/emu/screen.cpp17
-rw-r--r--src/lib/util/nanosvg.cpp6
7 files changed, 288 insertions, 121 deletions
diff --git a/3rdparty/nanosvg/README.md b/3rdparty/nanosvg/README.md
index a672d6f60e6..0865cbe2673 100644
--- a/3rdparty/nanosvg/README.md
+++ b/3rdparty/nanosvg/README.md
@@ -1,9 +1,11 @@
+*This project is not actively maintained.*
+
Nano SVG
==========
## Parser
-![screenshot of some splines rendered witht the sample program](/example/screenshot-1.png?raw=true)
+![screenshot of some splines rendered with the sample program](/example/screenshot-1.png?raw=true)
NanoSVG is a simple stupid single-header-file SVG parse. The output of the parser is a list of cubic bezier shapes.
@@ -17,7 +19,7 @@ That is, you should get the same looking data as your designed in your favorite
NanoSVG can return the paths in few different units. For example if you want to render an image, you may choose
to get the paths in pixels, or if you are feeding the data into a CNC-cutter, you may want to use millimeters.
-The units passed to NanoVG should be one of: 'px', 'pt', 'pc' 'mm', 'cm', or 'in'.
+The units passed to NanoSVG should be one of: 'px', 'pt', 'pc' 'mm', 'cm', or 'in'.
DPI (dots-per-inch) controls how the unit conversion is done.
If you don't know or care about the units stuff, "px" and 96 should get you going.
@@ -97,4 +99,4 @@ $ ./example
# License
-The library is licensed under [zlib license](LICENSE.txt) \ No newline at end of file
+The library is licensed under [zlib license](LICENSE.txt)
diff --git a/3rdparty/nanosvg/example/example2.c b/3rdparty/nanosvg/example/example2.c
index 50fe2a4e12b..9ae9b5952fe 100644
--- a/3rdparty/nanosvg/example/example2.c
+++ b/3rdparty/nanosvg/example/example2.c
@@ -32,7 +32,7 @@ int main()
NSVGrasterizer *rast = NULL;
unsigned char* img = NULL;
int w, h;
- const char* filename = "../example/_test.svg";
+ const char* filename = "../example/23.svg";
printf("parsing %s\n", filename);
image = nsvgParseFromFile(filename, "px", 96.0f);
diff --git a/3rdparty/nanosvg/premake4.lua b/3rdparty/nanosvg/premake4.lua
index 2c6cfd4210e..8befd82ef3e 100644
--- a/3rdparty/nanosvg/premake4.lua
+++ b/3rdparty/nanosvg/premake4.lua
@@ -14,7 +14,7 @@ solution "nanosvg"
targetdir("build")
configuration { "linux" }
- links { "X11","Xrandr", "rt", "GL", "GLU", "pthread" }
+ links { "X11","Xrandr", "rt", "GL", "GLU", "pthread", "glfw" }
configuration { "windows" }
links { "glu32","opengl32", "gdi32", "winmm", "user32" }
diff --git a/3rdparty/nanosvg/src/nanosvg.h b/3rdparty/nanosvg/src/nanosvg.h
index e41e093a97c..22edd71d735 100644
--- a/3rdparty/nanosvg/src/nanosvg.h
+++ b/3rdparty/nanosvg/src/nanosvg.h
@@ -29,9 +29,11 @@
#ifndef NANOSVG_H
#define NANOSVG_H
+#ifndef NANOSVG_CPLUSPLUS
#ifdef __cplusplus
extern "C" {
#endif
+#endif
// NanoSVG is a simple stupid single-header-file SVG parse. The output of the parser is a list of cubic bezier shapes.
//
@@ -45,15 +47,15 @@ extern "C" {
// NanoSVG can return the paths in few different units. For example if you want to render an image, you may choose
// to get the paths in pixels, or if you are feeding the data into a CNC-cutter, you may want to use millimeters.
//
-// The units passed to NanoVG should be one of: 'px', 'pt', 'pc' 'mm', 'cm', or 'in'.
+// The units passed to NanoSVG should be one of: 'px', 'pt', 'pc' 'mm', 'cm', or 'in'.
// DPI (dots-per-inch) controls how the unit conversion is done.
//
// If you don't know or care about the units stuff, "px" and 96 should get you going.
/* Example Usage:
- // Load
- NSVGImage* image;
+ // Load SVG
+ NSVGimage* image;
image = nsvgParseFromFile("test.svg", "px", 96);
printf("size: %f x %f\n", image->width, image->height);
// Use...
@@ -73,30 +75,30 @@ enum NSVGpaintType {
NSVG_PAINT_NONE = 0,
NSVG_PAINT_COLOR = 1,
NSVG_PAINT_LINEAR_GRADIENT = 2,
- NSVG_PAINT_RADIAL_GRADIENT = 3,
+ NSVG_PAINT_RADIAL_GRADIENT = 3
};
enum NSVGspreadType {
NSVG_SPREAD_PAD = 0,
NSVG_SPREAD_REFLECT = 1,
- NSVG_SPREAD_REPEAT = 2,
+ NSVG_SPREAD_REPEAT = 2
};
enum NSVGlineJoin {
NSVG_JOIN_MITER = 0,
NSVG_JOIN_ROUND = 1,
- NSVG_JOIN_BEVEL = 2,
+ NSVG_JOIN_BEVEL = 2
};
enum NSVGlineCap {
NSVG_CAP_BUTT = 0,
NSVG_CAP_ROUND = 1,
- NSVG_CAP_SQUARE = 2,
+ NSVG_CAP_SQUARE = 2
};
enum NSVGfillRule {
NSVG_FILLRULE_NONZERO = 0,
- NSVG_FILLRULE_EVENODD = 1,
+ NSVG_FILLRULE_EVENODD = 1
};
enum NSVGflags {
@@ -146,6 +148,7 @@ typedef struct NSVGshape
char strokeDashCount; // Number of dash values in dash array.
char strokeLineJoin; // Stroke join type.
char strokeLineCap; // Stroke cap type.
+ float miterLimit; // Miter limit
char fillRule; // Fill rule, see NSVGfillRule.
unsigned char flags; // Logical or of NSVG_FLAGS_* flags
float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy].
@@ -167,24 +170,28 @@ NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi)
// Important note: changes the string.
NSVGimage* nsvgParse(char* input, const char* units, float dpi);
-// Deletes list of paths.
+// Duplicates a path.
+NSVGpath* nsvgDuplicatePath(NSVGpath* p);
+
+// Deletes an image.
void nsvgDelete(NSVGimage* image);
+#ifndef NANOSVG_CPLUSPLUS
#ifdef __cplusplus
-};
+}
+#endif
#endif
#endif // NANOSVG_H
#ifdef NANOSVG_IMPLEMENTATION
-#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#define NSVG_PI (3.14159265358979323846264338327f)
-#define NSVG_KAPPA90 (0.5522847493f) // Lenght proportional to radius of a cubic bezier handle for 90deg arcs.
+#define NSVG_KAPPA90 (0.5522847493f) // Length proportional to radius of a cubic bezier handle for 90deg arcs.
#define NSVG_ALIGN_MIN 0
#define NSVG_ALIGN_MID 1
@@ -216,12 +223,7 @@ static int nsvg__isspace(char c)
static int nsvg__isdigit(char c)
{
- return strchr("0123456789", c) != 0;
-}
-
-static int nsvg__isnum(char c)
-{
- return strchr("0123456789+-.eE", c) != 0;
+ return c >= '0' && c <= '9';
}
static NSVG_INLINE float nsvg__minf(float a, float b) { return a < b ? a : b; }
@@ -280,6 +282,9 @@ static void nsvg__parseElement(char* s,
// Get attribs
while (!end && *s && nattr < NSVG_XML_MAX_ATTRIBS-3) {
+ char* name = NULL;
+ char* value = NULL;
+
// Skip white space before the attrib name
while (*s && nsvg__isspace(*s)) s++;
if (!*s) break;
@@ -287,7 +292,7 @@ static void nsvg__parseElement(char* s,
end = 1;
break;
}
- attr[nattr++] = s;
+ name = s;
// Find end of the attrib name.
while (*s && !nsvg__isspace(*s) && *s != '=') s++;
if (*s) { *s++ = '\0'; }
@@ -297,9 +302,15 @@ static void nsvg__parseElement(char* s,
quote = *s;
s++;
// Store value and find the end of it.
- attr[nattr++] = s;
+ value = s;
while (*s && *s != quote) s++;
if (*s) { *s++ = '\0'; }
+
+ // Store only well formed attributes
+ if (name && value) {
+ attr[nattr++] = name;
+ attr[nattr++] = value;
+ }
}
// List terminator
@@ -350,7 +361,7 @@ int nsvg__parseXML(char* input,
enum NSVGgradientUnits {
NSVG_USER_SPACE = 0,
- NSVG_OBJECT_SPACE = 1,
+ NSVG_OBJECT_SPACE = 1
};
#define NSVG_MAX_DASHES 8
@@ -365,7 +376,7 @@ enum NSVGunits {
NSVG_UNITS_IN,
NSVG_UNITS_PERCENT,
NSVG_UNITS_EM,
- NSVG_UNITS_EX,
+ NSVG_UNITS_EX
};
typedef struct NSVGcoordinate {
@@ -416,6 +427,7 @@ typedef struct NSVGattrib
int strokeDashCount;
char strokeLineJoin;
char strokeLineCap;
+ float miterLimit;
char fillRule;
float fontSize;
unsigned int stopColor;
@@ -436,6 +448,7 @@ typedef struct NSVGparser
NSVGpath* plist;
NSVGimage* image;
NSVGgradientData* gradients;
+ NSVGshape* shapesTail;
float viewMinx, viewMiny, viewWidth, viewHeight;
int alignX, alignY, alignType;
float dpi;
@@ -625,6 +638,7 @@ static NSVGparser* nsvg__createParser()
p->attr[0].strokeWidth = 1;
p->attr[0].strokeLineJoin = NSVG_JOIN_MITER;
p->attr[0].strokeLineCap = NSVG_CAP_BUTT;
+ p->attr[0].miterLimit = 4;
p->attr[0].fillRule = NSVG_FILLRULE_NONZERO;
p->attr[0].hasFill = 1;
p->attr[0].visible = 1;
@@ -721,9 +735,11 @@ static void nsvg__lineTo(NSVGparser* p, float x, float y)
static void nsvg__cubicBezTo(NSVGparser* p, float cpx1, float cpy1, float cpx2, float cpy2, float x, float y)
{
- nsvg__addPoint(p, cpx1, cpy1);
- nsvg__addPoint(p, cpx2, cpy2);
- nsvg__addPoint(p, x, y);
+ if (p->npts > 0) {
+ nsvg__addPoint(p, cpx1, cpy1);
+ nsvg__addPoint(p, cpx2, cpy2);
+ nsvg__addPoint(p, x, y);
+ }
}
static NSVGattrib* nsvg__getAttr(NSVGparser* p)
@@ -793,7 +809,9 @@ static float nsvg__convertToPixels(NSVGparser* p, NSVGcoordinate c, float orig,
static NSVGgradientData* nsvg__findGradientData(NSVGparser* p, const char* id)
{
NSVGgradientData* grad = p->gradients;
- while (grad) {
+ if (id == NULL || *id == '\0')
+ return NULL;
+ while (grad != NULL) {
if (strcmp(grad->id, id) == 0)
return grad;
grad = grad->next;
@@ -810,19 +828,26 @@ static NSVGgradient* nsvg__createGradient(NSVGparser* p, const char* id, const f
NSVGgradient* grad;
float ox, oy, sw, sh, sl;
int nstops = 0;
+ int refIter;
data = nsvg__findGradientData(p, id);
if (data == NULL) return NULL;
// TODO: use ref to fill in all unset values too.
ref = data;
+ refIter = 0;
while (ref != NULL) {
+ NSVGgradientData* nextRef = NULL;
if (stops == NULL && ref->stops != NULL) {
stops = ref->stops;
nstops = ref->nstops;
break;
}
- ref = nsvg__findGradientData(p, ref->ref);
+ nextRef = nsvg__findGradientData(p, ref->ref);
+ if (nextRef == ref) break; // prevent infite loops on malformed data
+ ref = nextRef;
+ refIter++;
+ if (refIter > 32) break; // prevent infite loops on malformed data
}
if (stops == NULL) return NULL;
@@ -923,7 +948,7 @@ static void nsvg__addShape(NSVGparser* p)
{
NSVGattrib* attr = nsvg__getAttr(p);
float scale = 1.0f;
- NSVGshape *shape, *cur, *prev;
+ NSVGshape* shape;
NSVGpath* path;
int i;
@@ -939,11 +964,12 @@ static void nsvg__addShape(NSVGparser* p)
scale = nsvg__getAverageScale(attr->xform);
shape->strokeWidth = attr->strokeWidth * scale;
shape->strokeDashOffset = attr->strokeDashOffset * scale;
- shape->strokeDashCount = attr->strokeDashCount;
+ shape->strokeDashCount = (char)attr->strokeDashCount;
for (i = 0; i < attr->strokeDashCount; i++)
shape->strokeDashArray[i] = attr->strokeDashArray[i] * scale;
shape->strokeLineJoin = attr->strokeLineJoin;
shape->strokeLineCap = attr->strokeLineCap;
+ shape->miterLimit = attr->miterLimit;
shape->fillRule = attr->fillRule;
shape->opacity = attr->opacity;
@@ -999,16 +1025,11 @@ static void nsvg__addShape(NSVGparser* p)
shape->flags = (attr->visible ? NSVG_FLAGS_VISIBLE : 0x00);
// Add to tail
- prev = NULL;
- cur = p->image->shapes;
- while (cur != NULL) {
- prev = cur;
- cur = cur->next;
- }
- if (prev == NULL)
+ if (p->image->shapes == NULL)
p->image->shapes = shape;
else
- prev->next = shape;
+ p->shapesTail->next = shape;
+ p->shapesTail = shape;
return;
@@ -1030,6 +1051,10 @@ static void nsvg__addPath(NSVGparser* p, char closed)
if (closed)
nsvg__lineTo(p, p->pts[0], p->pts[1]);
+ // Expect 1 + N*3 points (N = number of cubic bezier segments).
+ if ((p->npts % 3) != 1)
+ return;
+
path = (NSVGpath*)malloc(sizeof(NSVGpath));
if (path == NULL) goto error;
memset(path, 0, sizeof(NSVGpath));
@@ -1072,6 +1097,66 @@ error:
}
}
+// We roll our own string to float because the std library one uses locale and messes things up.
+static double nsvg__atof(const char* s)
+{
+ char* cur = (char*)s;
+ char* end = NULL;
+ double res = 0.0, sign = 1.0;
+ long long intPart = 0, fracPart = 0;
+ char hasIntPart = 0, hasFracPart = 0;
+
+ // Parse optional sign
+ if (*cur == '+') {
+ cur++;
+ } else if (*cur == '-') {
+ sign = -1;
+ cur++;
+ }
+
+ // Parse integer part
+ if (nsvg__isdigit(*cur)) {
+ // Parse digit sequence
+ intPart = strtoll(cur, &end, 10);
+ if (cur != end) {
+ res = (double)intPart;
+ hasIntPart = 1;
+ cur = end;
+ }
+ }
+
+ // Parse fractional part.
+ if (*cur == '.') {
+ cur++; // Skip '.'
+ if (nsvg__isdigit(*cur)) {
+ // Parse digit sequence
+ fracPart = strtoll(cur, &end, 10);
+ if (cur != end) {
+ res += (double)fracPart / pow(10.0, (double)(end - cur));
+ hasFracPart = 1;
+ cur = end;
+ }
+ }
+ }
+
+ // A valid number should have integer or fractional part.
+ if (!hasIntPart && !hasFracPart)
+ return 0.0;
+
+ // Parse optional exponent
+ if (*cur == 'e' || *cur == 'E') {
+ long expPart = 0;
+ cur++; // skip 'E'
+ expPart = strtol(cur, &end, 10); // Parse digit sequence with sign
+ if (cur != end) {
+ res *= pow(10.0, (double)expPart);
+ }
+ }
+
+ return res * sign;
+}
+
+
static const char* nsvg__parseNumber(const char* s, char* it, const int size)
{
const int last = size-1;
@@ -1098,7 +1183,7 @@ static const char* nsvg__parseNumber(const char* s, char* it, const int size)
}
}
// exponent
- if (*s == 'e' || *s == 'E') {
+ if ((*s == 'e' || *s == 'E') && (s[1] != 'm' && s[1] != 'x')) {
if (i < last) it[i++] = *s;
s++;
if (*s == '-' || *s == '+') {
@@ -1352,13 +1437,19 @@ static unsigned int nsvg__parseColor(const char* str)
static float nsvg__parseOpacity(const char* str)
{
- float val = 0;
- sscanf(str, "%f", &val);
+ float val = nsvg__atof(str);
if (val < 0.0f) val = 0.0f;
if (val > 1.0f) val = 1.0f;
return val;
}
+static float nsvg__parseMiterLimit(const char* str)
+{
+ float val = nsvg__atof(str);
+ if (val < 0.0f) val = 0.0f;
+ return val;
+}
+
static int nsvg__parseUnits(const char* units)
{
if (units[0] == 'p' && units[1] == 'x')
@@ -1382,12 +1473,21 @@ static int nsvg__parseUnits(const char* units)
return NSVG_UNITS_USER;
}
+static int nsvg__isCoordinate(const char* s)
+{
+ // optional sign
+ if (*s == '-' || *s == '+')
+ s++;
+ // must have at least one digit
+ return nsvg__isdigit(*s);
+}
+
static NSVGcoordinate nsvg__parseCoordinateRaw(const char* str)
{
NSVGcoordinate coord = {0, NSVG_UNITS_USER};
- char units[32]="";
- sscanf(str, "%f%s", &coord.value, units);
- coord.units = nsvg__parseUnits(units);
+ char buf[64];
+ coord.units = nsvg__parseUnits(nsvg__parseNumber(str, buf, 64));
+ coord.value = nsvg__atof(buf);
return coord;
}
@@ -1423,7 +1523,7 @@ static int nsvg__parseTransformArgs(const char* str, float* args, int maxNa, int
if (*ptr == '-' || *ptr == '+' || *ptr == '.' || nsvg__isdigit(*ptr)) {
if (*na >= maxNa) return 0;
ptr = nsvg__parseNumber(ptr, it, 64);
- args[(*na)++] = (float)atof(it);
+ args[(*na)++] = (float)nsvg__atof(it);
} else {
++ptr;
}
@@ -1521,25 +1621,32 @@ static int nsvg__parseRotate(float* xform, const char* str)
static void nsvg__parseTransform(float* xform, const char* str)
{
float t[6];
+ int len;
nsvg__xformIdentity(xform);
while (*str)
{
if (strncmp(str, "matrix", 6) == 0)
- str += nsvg__parseMatrix(t, str);
+ len = nsvg__parseMatrix(t, str);
else if (strncmp(str, "translate", 9) == 0)
- str += nsvg__parseTranslate(t, str);
+ len = nsvg__parseTranslate(t, str);
else if (strncmp(str, "scale", 5) == 0)
- str += nsvg__parseScale(t, str);
+ len = nsvg__parseScale(t, str);
else if (strncmp(str, "rotate", 6) == 0)
- str += nsvg__parseRotate(t, str);
+ len = nsvg__parseRotate(t, str);
else if (strncmp(str, "skewX", 5) == 0)
- str += nsvg__parseSkewX(t, str);
+ len = nsvg__parseSkewX(t, str);
else if (strncmp(str, "skewY", 5) == 0)
- str += nsvg__parseSkewY(t, str);
+ len = nsvg__parseSkewY(t, str);
else{
++str;
continue;
}
+ if (len != 0) {
+ str += len;
+ } else {
+ ++str;
+ continue;
+ }
nsvg__xformPremultiply(xform, t);
}
@@ -1579,7 +1686,7 @@ static char nsvg__parseLineJoin(const char* str)
else if (strcmp(str, "bevel") == 0)
return NSVG_JOIN_BEVEL;
// TODO: handle inherit.
- return NSVG_CAP_BUTT;
+ return NSVG_JOIN_MITER;
}
static char nsvg__parseFillRule(const char* str)
@@ -1685,6 +1792,8 @@ static int nsvg__parseAttr(NSVGparser* p, const char* name, const char* value)
attr->strokeLineCap = nsvg__parseLineCap(value);
} else if (strcmp(name, "stroke-linejoin") == 0) {
attr->strokeLineJoin = nsvg__parseLineJoin(value);
+ } else if (strcmp(name, "stroke-miterlimit") == 0) {
+ attr->miterLimit = nsvg__parseMiterLimit(value);
} else if (strcmp(name, "fill-rule") == 0) {
attr->fillRule = nsvg__parseFillRule(value);
} else if (strcmp(name, "font-size") == 0) {
@@ -1798,8 +1907,11 @@ static int nsvg__getArgsPerElement(char cmd)
case 'a':
case 'A':
return 7;
+ case 'z':
+ case 'Z':
+ return 0;
}
- return 0;
+ return -1;
}
static void nsvg__pathMoveTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)
@@ -2001,7 +2113,7 @@ static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args,
rx = fabsf(args[0]); // y radius
ry = fabsf(args[1]); // x radius
- rotx = args[2] / 180.0f * NSVG_PI; // x rotation engle
+ rotx = args[2] / 180.0f * NSVG_PI; // x rotation angle
fa = fabsf(args[3]) > 1e-6 ? 1 : 0; // Large arc
fs = fabsf(args[4]) > 1e-6 ? 1 : 0; // Sweep direction
x1 = *cpx; // start point
@@ -2066,13 +2178,10 @@ static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args,
// if (vecrat(ux,uy,vx,vy) <= -1.0f) da = NSVG_PI;
// if (vecrat(ux,uy,vx,vy) >= 1.0f) da = 0;
- if (fa) {
- // Choose large arc
- if (da > 0.0f)
- da = da - 2*NSVG_PI;
- else
- da = 2*NSVG_PI + da;
- }
+ if (fs == 0 && da > 0)
+ da -= 2 * NSVG_PI;
+ else if (fs == 1 && da < 0)
+ da += 2 * NSVG_PI;
// Approximate the arc using cubic spline segments.
t[0] = cosrx; t[1] = sinrx;
@@ -2088,7 +2197,7 @@ static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args,
kappa = -kappa;
for (i = 0; i <= ndivs; i++) {
- a = a1 + da * (i/(float)ndivs);
+ a = a1 + da * ((float)i/(float)ndivs);
dx = cosf(a);
dy = sinf(a);
nsvg__xformPoint(&x, &y, dx*rx, dy*ry, t); // position
@@ -2112,6 +2221,7 @@ static void nsvg__parsePath(NSVGparser* p, const char** attr)
float args[10];
int nargs;
int rargs = 0;
+ char initPoint;
float cpx, cpy, cpx2, cpy2;
const char* tmp[4];
char closedFlag;
@@ -2134,15 +2244,16 @@ static void nsvg__parsePath(NSVGparser* p, const char** attr)
nsvg__resetPath(p);
cpx = 0; cpy = 0;
cpx2 = 0; cpy2 = 0;
+ initPoint = 0;
closedFlag = 0;
nargs = 0;
while (*s) {
s = nsvg__getNextPathItem(s, item);
if (!*item) break;
- if (nsvg__isnum(item[0])) {
+ if (cmd != '\0' && nsvg__isCoordinate(item)) {
if (nargs < 10)
- args[nargs++] = (float)atof(item);
+ args[nargs++] = (float)nsvg__atof(item);
if (nargs >= rargs) {
switch (cmd) {
case 'm':
@@ -2151,23 +2262,24 @@ static void nsvg__parsePath(NSVGparser* p, const char** attr)
// Moveto can be followed by multiple coordinate pairs,
// which should be treated as linetos.
cmd = (cmd == 'm') ? 'l' : 'L';
- rargs = nsvg__getArgsPerElement(cmd);
- cpx2 = cpx; cpy2 = cpy;
+ rargs = nsvg__getArgsPerElement(cmd);
+ cpx2 = cpx; cpy2 = cpy;
+ initPoint = 1;
break;
case 'l':
case 'L':
nsvg__pathLineTo(p, &cpx, &cpy, args, cmd == 'l' ? 1 : 0);
- cpx2 = cpx; cpy2 = cpy;
+ cpx2 = cpx; cpy2 = cpy;
break;
case 'H':
case 'h':
nsvg__pathHLineTo(p, &cpx, &cpy, args, cmd == 'h' ? 1 : 0);
- cpx2 = cpx; cpy2 = cpy;
+ cpx2 = cpx; cpy2 = cpy;
break;
case 'V':
case 'v':
nsvg__pathVLineTo(p, &cpx, &cpy, args, cmd == 'v' ? 1 : 0);
- cpx2 = cpx; cpy2 = cpy;
+ cpx2 = cpx; cpy2 = cpy;
break;
case 'C':
case 'c':
@@ -2188,13 +2300,13 @@ static void nsvg__parsePath(NSVGparser* p, const char** attr)
case 'A':
case 'a':
nsvg__pathArcTo(p, &cpx, &cpy, args, cmd == 'a' ? 1 : 0);
- cpx2 = cpx; cpy2 = cpy;
+ cpx2 = cpx; cpy2 = cpy;
break;
default:
if (nargs >= 2) {
cpx = args[nargs-2];
cpy = args[nargs-1];
- cpx2 = cpx; cpy2 = cpy;
+ cpx2 = cpx; cpy2 = cpy;
}
break;
}
@@ -2202,7 +2314,6 @@ static void nsvg__parsePath(NSVGparser* p, const char** attr)
}
} else {
cmd = item[0];
- rargs = nsvg__getArgsPerElement(cmd);
if (cmd == 'M' || cmd == 'm') {
// Commit path.
if (p->npts > 0)
@@ -2211,7 +2322,11 @@ static void nsvg__parsePath(NSVGparser* p, const char** attr)
nsvg__resetPath(p);
closedFlag = 0;
nargs = 0;
- } else if (cmd == 'Z' || cmd == 'z') {
+ } else if (initPoint == 0) {
+ // Do not allow other commands until initial point has been set (moveTo called once).
+ cmd = '\0';
+ }
+ if (cmd == 'Z' || cmd == 'z') {
closedFlag = 1;
// Commit path.
if (p->npts > 0) {
@@ -2227,6 +2342,12 @@ static void nsvg__parsePath(NSVGparser* p, const char** attr)
closedFlag = 0;
nargs = 0;
}
+ rargs = nsvg__getArgsPerElement(cmd);
+ if (rargs == -1) {
+ // Command not recognized
+ cmd = '\0';
+ rargs = 0;
+ }
}
}
// Commit path.
@@ -2399,7 +2520,7 @@ static void nsvg__parsePoly(NSVGparser* p, const char** attr, int closeFlag)
nargs = 0;
while (*s) {
s = nsvg__getNextPathItem(s, item);
- args[nargs++] = (float)atof(item);
+ args[nargs++] = (float)nsvg__atof(item);
if (nargs >= 2) {
if (npts == 0)
nsvg__moveTo(p, args[0], args[1]);
@@ -2424,11 +2545,26 @@ static void nsvg__parseSVG(NSVGparser* p, const char** attr)
for (i = 0; attr[i]; i += 2) {
if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
if (strcmp(attr[i], "width") == 0) {
- p->image->width = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 1.0f);
+ p->image->width = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f);
} else if (strcmp(attr[i], "height") == 0) {
- p->image->height = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 1.0f);
+ p->image->height = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f);
} else if (strcmp(attr[i], "viewBox") == 0) {
- sscanf(attr[i + 1], "%f%*[%%, \t]%f%*[%%, \t]%f%*[%%, \t]%f", &p->viewMinx, &p->viewMiny, &p->viewWidth, &p->viewHeight);
+ const char *s = attr[i + 1];
+ char buf[64];
+ s = nsvg__parseNumber(s, buf, 64);
+ p->viewMinx = nsvg__atof(buf);
+ while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++;
+ if (!*s) return;
+ s = nsvg__parseNumber(s, buf, 64);
+ p->viewMiny = nsvg__atof(buf);
+ while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++;
+ if (!*s) return;
+ s = nsvg__parseNumber(s, buf, 64);
+ p->viewWidth = nsvg__atof(buf);
+ while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++;
+ if (!*s) return;
+ s = nsvg__parseNumber(s, buf, 64);
+ p->viewHeight = nsvg__atof(buf);
} else if (strcmp(attr[i], "preserveAspectRatio") == 0) {
if (strstr(attr[i + 1], "none") != 0) {
// No uniform scaling
@@ -2593,7 +2729,6 @@ static void nsvg__startElement(void* ud, const char* el, const char** attr)
if (p->pathFlag) // Do not allow nested paths.
return;
nsvg__pushAttr(p);
- p->pathFlag = 1;
p->shapeFlag = 1;
nsvg__parsePath(p, attr);
nsvg__popAttr(p);
@@ -2721,12 +2856,12 @@ static float nsvg__viewAlign(float content, float container, int type)
static void nsvg__scaleGradient(NSVGgradient* grad, float tx, float ty, float sx, float sy)
{
- grad->xform[0] *= sx;
- grad->xform[1] *= sx;
- grad->xform[2] *= sy;
- grad->xform[3] *= sy;
- grad->xform[4] += tx*sx;
- grad->xform[5] += ty*sx;
+ float t[6];
+ nsvg__xformSetTranslation(t, tx, ty);
+ nsvg__xformMultiply (grad->xform, t);
+
+ nsvg__xformSetScale(t, sx, sy);
+ nsvg__xformMultiply (grad->xform, t);
}
static void nsvg__scaleToViewbox(NSVGparser* p, const char* units)
@@ -2873,6 +3008,36 @@ error:
return NULL;
}
+NSVGpath* nsvgDuplicatePath(NSVGpath* p)
+{
+ NSVGpath* res = NULL;
+
+ if (p == NULL)
+ return NULL;
+
+ res = (NSVGpath*)malloc(sizeof(NSVGpath));
+ if (res == NULL) goto error;
+ memset(res, 0, sizeof(NSVGpath));
+
+ res->pts = (float*)malloc(p->npts*2*sizeof(float));
+ if (res->pts == NULL) goto error;
+ memcpy(res->pts, p->pts, p->npts * sizeof(float) * 2);
+ res->npts = p->npts;
+
+ memcpy(res->bounds, p->bounds, sizeof(p->bounds));
+
+ res->closed = p->closed;
+
+ return res;
+
+error:
+ if (res != NULL) {
+ free(res->pts);
+ free(res);
+ }
+ return NULL;
+}
+
void nsvgDelete(NSVGimage* image)
{
NSVGshape *snext, *shape;
diff --git a/3rdparty/nanosvg/src/nanosvgrast.h b/3rdparty/nanosvg/src/nanosvgrast.h
index c71d7b4a7c1..b740c316ca2 100644
--- a/3rdparty/nanosvg/src/nanosvgrast.h
+++ b/3rdparty/nanosvg/src/nanosvgrast.h
@@ -25,15 +25,18 @@
#ifndef NANOSVGRAST_H
#define NANOSVGRAST_H
+#ifndef NANOSVGRAST_CPLUSPLUS
#ifdef __cplusplus
extern "C" {
#endif
+#endif
typedef struct NSVGrasterizer NSVGrasterizer;
/* Example Usage:
// Load SVG
- struct SNVGImage* image = nsvgParseFromFile("test.svg.");
+ NSVGimage* image;
+ image = nsvgParseFromFile("test.svg", "px", 96);
// Create rasterizer (can be used to render multiple images).
struct NSVGrasterizer* rast = nsvgCreateRasterizer();
@@ -63,8 +66,10 @@ void nsvgRasterize(NSVGrasterizer* r,
void nsvgDeleteRasterizer(NSVGrasterizer*);
+#ifndef NANOSVGRAST_CPLUSPLUS
#ifdef __cplusplus
-};
+}
+#endif
#endif
#endif // NANOSVGRAST_H
@@ -239,7 +244,7 @@ static void nsvg__addPathPoint(NSVGrasterizer* r, float x, float y, int flags)
if (r->npoints > 0) {
pt = &r->points[r->npoints-1];
if (nsvg__ptEquals(pt->x,pt->y, x,y, r->distTol)) {
- pt->flags |= flags;
+ pt->flags = (unsigned char)(pt->flags | flags);
return;
}
}
@@ -388,7 +393,7 @@ enum NSVGpointFlags
{
NSVG_PT_CORNER = 0x01,
NSVG_PT_BEVEL = 0x02,
- NSVG_PT_LEFT = 0x04,
+ NSVG_PT_LEFT = 0x04
};
static void nsvg__initClosed(NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth)
@@ -454,7 +459,7 @@ static void nsvg__roundCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right,
float lx = 0, ly = 0, rx = 0, ry = 0, prevx = 0, prevy = 0;
for (i = 0; i < ncap; i++) {
- float a = i/(float)(ncap-1)*NSVG_PI;
+ float a = (float)i/(float)(ncap-1)*NSVG_PI;
float ax = cosf(a) * w, ay = sinf(a) * w;
float x = px - dlx*ax - dx*ay;
float y = py - dly*ax - dy*ay;
@@ -551,7 +556,7 @@ static void nsvg__roundJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right
if (da < NSVG_PI) da += NSVG_PI*2;
if (da > NSVG_PI) da -= NSVG_PI*2;
- n = (int)ceilf((nsvg__absf(da) / NSVG_PI) * ncap);
+ n = (int)ceilf((nsvg__absf(da) / NSVG_PI) * (float)ncap);
if (n < 2) n = 2;
if (n > ncap) n = ncap;
@@ -561,7 +566,7 @@ static void nsvg__roundJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right
ry = right->y;
for (i = 0; i < n; i++) {
- float u = i/(float)(n-1);
+ float u = (float)i/(float)(n-1);
float a = a0 + u*da;
float ax = cosf(a) * w, ay = sinf(a) * w;
float lx1 = p1->x - ax, ly1 = p1->y - ay;
@@ -732,7 +737,7 @@ static void nsvg__flattenShapeStroke(NSVGrasterizer* r, NSVGshape* shape, float
int i, j, closed;
NSVGpath* path;
NSVGpoint* p0, *p1;
- float miterLimit = 4;
+ float miterLimit = shape->miterLimit;
int lineJoin = shape->strokeLineJoin;
int lineCap = shape->strokeLineCap;
float lineWidth = shape->strokeWidth * scale;
@@ -838,8 +843,8 @@ static void nsvg__flattenShapeStroke(NSVGrasterizer* r, NSVGshape* shape, float
static int nsvg__cmpEdge(const void *p, const void *q)
{
- NSVGedge* a = (NSVGedge*)p;
- NSVGedge* b = (NSVGedge*)q;
+ const NSVGedge* a = (const NSVGedge*)p;
+ const NSVGedge* b = (const NSVGedge*)q;
if (a->y0 < b->y0) return -1;
if (a->y0 > b->y0) return 1;
@@ -892,20 +897,20 @@ static void nsvg__fillScanline(unsigned char* scanline, int len, int x0, int x1,
if (i < len && j >= 0) {
if (i == j) {
// x0,x1 are the same pixel, so compute combined coverage
- scanline[i] += (unsigned char)((x1 - x0) * maxWeight >> NSVG__FIXSHIFT);
+ scanline[i] = (unsigned char)(scanline[i] + ((x1 - x0) * maxWeight >> NSVG__FIXSHIFT));
} else {
if (i >= 0) // add antialiasing for x0
- scanline[i] += (unsigned char)(((NSVG__FIX - (x0 & NSVG__FIXMASK)) * maxWeight) >> NSVG__FIXSHIFT);
+ scanline[i] = (unsigned char)(scanline[i] + (((NSVG__FIX - (x0 & NSVG__FIXMASK)) * maxWeight) >> NSVG__FIXSHIFT));
else
i = -1; // clip
if (j < len) // add antialiasing for x1
- scanline[j] += (unsigned char)(((x1 & NSVG__FIXMASK) * maxWeight) >> NSVG__FIXSHIFT);
+ scanline[j] = (unsigned char)(scanline[j] + (((x1 & NSVG__FIXMASK) * maxWeight) >> NSVG__FIXSHIFT));
else
j = len; // clip
for (++i; i < j; ++i) // fill pixels between x0 and x1
- scanline[i] += (unsigned char)maxWeight;
+ scanline[i] = (unsigned char)(scanline[i] + maxWeight);
}
}
}
@@ -1021,8 +1026,8 @@ static void nsvg__scanlineSolid(unsigned char* dst, int count, unsigned char* co
int i, cr, cg, cb, ca;
unsigned int c;
- fx = (x - tx) / scale;
- fy = (y - ty) / scale;
+ fx = ((float)x - tx) / scale;
+ fy = ((float)y - ty) / scale;
dx = 1.0f / scale;
for (i = 0; i < count; i++) {
@@ -1066,8 +1071,8 @@ static void nsvg__scanlineSolid(unsigned char* dst, int count, unsigned char* co
int i, cr, cg, cb, ca;
unsigned int c;
- fx = (x - tx) / scale;
- fy = (y - ty) / scale;
+ fx = ((float)x - tx) / scale;
+ fy = ((float)y - ty) / scale;
dx = 1.0f / scale;
for (i = 0; i < count; i++) {
@@ -1121,7 +1126,7 @@ static void nsvg__rasterizeSortedEdges(NSVGrasterizer *r, float tx, float ty, fl
xmax = 0;
for (s = 0; s < NSVG__SUBSAMPLES; ++s) {
// find center of pixel for this scanline
- float scany = y*NSVG__SUBSAMPLES + s + 0.5f;
+ float scany = (float)(y*NSVG__SUBSAMPLES + s) + 0.5f;
NSVGactiveEdge **step = &active;
// update all active edges;
diff --git a/src/emu/screen.cpp b/src/emu/screen.cpp
index cacd16d5982..c1e575819db 100644
--- a/src/emu/screen.cpp
+++ b/src/emu/screen.cpp
@@ -94,19 +94,10 @@ private:
screen_device::svg_renderer::svg_renderer(memory_region *region)
{
- // nanosvg makes assumptions about the global locale
- {
- const std::unique_ptr<char []> s(new char[region->bytes() + 1]);
- memcpy(s.get(), region->base(), region->bytes());
- s[region->bytes()] = 0;
- const std::string lcctype(std::setlocale(LC_CTYPE, nullptr));
- const std::string lcnumeric(std::setlocale(LC_NUMERIC, nullptr));
- std::setlocale(LC_CTYPE, "C");
- std::setlocale(LC_NUMERIC, "C");
- m_image = nsvgParse(s.get(), "px", 72);
- std::setlocale(LC_CTYPE, lcctype.c_str());
- std::setlocale(LC_NUMERIC, lcnumeric.c_str());
- }
+ const std::unique_ptr<char []> s(new char[region->bytes() + 1]);
+ memcpy(s.get(), region->base(), region->bytes());
+ s[region->bytes()] = 0;
+ m_image = nsvgParse(s.get(), "px", 72);
m_rasterizer = nsvgCreateRasterizer();
m_key_count = 0;
diff --git a/src/lib/util/nanosvg.cpp b/src/lib/util/nanosvg.cpp
index 09973865675..0cb05308d19 100644
--- a/src/lib/util/nanosvg.cpp
+++ b/src/lib/util/nanosvg.cpp
@@ -1,6 +1,10 @@
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#define NANOSVG_ALL_COLOR_KEYWORDS
#define NANOSVG_IMPLEMENTATION
#define NANOSVGRAST_IMPLEMENTATION
-#define NANOSVG_ALL_COLOR_KEYWORDS
#include <nanosvg/src/nanosvg.h>
#include <nanosvg/src/nanosvgrast.h>