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.
This commit is contained in:
Vas Crabb 2020-10-05 22:18:22 +11:00
parent a89f9b274e
commit f390ea1004
7 changed files with 288 additions and 121 deletions

View File

@ -1,9 +1,11 @@
*This project is not actively maintained.*
Nano SVG Nano SVG
========== ==========
## Parser ## 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. 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 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. 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. 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. If you don't know or care about the units stuff, "px" and 96 should get you going.
@ -97,4 +99,4 @@ $ ./example
# License # License
The library is licensed under [zlib license](LICENSE.txt) The library is licensed under [zlib license](LICENSE.txt)

View File

@ -32,7 +32,7 @@ int main()
NSVGrasterizer *rast = NULL; NSVGrasterizer *rast = NULL;
unsigned char* img = NULL; unsigned char* img = NULL;
int w, h; int w, h;
const char* filename = "../example/_test.svg"; const char* filename = "../example/23.svg";
printf("parsing %s\n", filename); printf("parsing %s\n", filename);
image = nsvgParseFromFile(filename, "px", 96.0f); image = nsvgParseFromFile(filename, "px", 96.0f);

View File

@ -14,7 +14,7 @@ solution "nanosvg"
targetdir("build") targetdir("build")
configuration { "linux" } configuration { "linux" }
links { "X11","Xrandr", "rt", "GL", "GLU", "pthread" } links { "X11","Xrandr", "rt", "GL", "GLU", "pthread", "glfw" }
configuration { "windows" } configuration { "windows" }
links { "glu32","opengl32", "gdi32", "winmm", "user32" } links { "glu32","opengl32", "gdi32", "winmm", "user32" }

View File

@ -29,9 +29,11 @@
#ifndef NANOSVG_H #ifndef NANOSVG_H
#define NANOSVG_H #define NANOSVG_H
#ifndef NANOSVG_CPLUSPLUS
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#endif
// NanoSVG is a simple stupid single-header-file SVG parse. The output of the parser is a list of cubic bezier shapes. // 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 // 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. // 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. // 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. // If you don't know or care about the units stuff, "px" and 96 should get you going.
/* Example Usage: /* Example Usage:
// Load // Load SVG
NSVGImage* image; NSVGimage* image;
image = nsvgParseFromFile("test.svg", "px", 96); image = nsvgParseFromFile("test.svg", "px", 96);
printf("size: %f x %f\n", image->width, image->height); printf("size: %f x %f\n", image->width, image->height);
// Use... // Use...
@ -73,30 +75,30 @@ enum NSVGpaintType {
NSVG_PAINT_NONE = 0, NSVG_PAINT_NONE = 0,
NSVG_PAINT_COLOR = 1, NSVG_PAINT_COLOR = 1,
NSVG_PAINT_LINEAR_GRADIENT = 2, NSVG_PAINT_LINEAR_GRADIENT = 2,
NSVG_PAINT_RADIAL_GRADIENT = 3, NSVG_PAINT_RADIAL_GRADIENT = 3
}; };
enum NSVGspreadType { enum NSVGspreadType {
NSVG_SPREAD_PAD = 0, NSVG_SPREAD_PAD = 0,
NSVG_SPREAD_REFLECT = 1, NSVG_SPREAD_REFLECT = 1,
NSVG_SPREAD_REPEAT = 2, NSVG_SPREAD_REPEAT = 2
}; };
enum NSVGlineJoin { enum NSVGlineJoin {
NSVG_JOIN_MITER = 0, NSVG_JOIN_MITER = 0,
NSVG_JOIN_ROUND = 1, NSVG_JOIN_ROUND = 1,
NSVG_JOIN_BEVEL = 2, NSVG_JOIN_BEVEL = 2
}; };
enum NSVGlineCap { enum NSVGlineCap {
NSVG_CAP_BUTT = 0, NSVG_CAP_BUTT = 0,
NSVG_CAP_ROUND = 1, NSVG_CAP_ROUND = 1,
NSVG_CAP_SQUARE = 2, NSVG_CAP_SQUARE = 2
}; };
enum NSVGfillRule { enum NSVGfillRule {
NSVG_FILLRULE_NONZERO = 0, NSVG_FILLRULE_NONZERO = 0,
NSVG_FILLRULE_EVENODD = 1, NSVG_FILLRULE_EVENODD = 1
}; };
enum NSVGflags { enum NSVGflags {
@ -146,6 +148,7 @@ typedef struct NSVGshape
char strokeDashCount; // Number of dash values in dash array. char strokeDashCount; // Number of dash values in dash array.
char strokeLineJoin; // Stroke join type. char strokeLineJoin; // Stroke join type.
char strokeLineCap; // Stroke cap type. char strokeLineCap; // Stroke cap type.
float miterLimit; // Miter limit
char fillRule; // Fill rule, see NSVGfillRule. char fillRule; // Fill rule, see NSVGfillRule.
unsigned char flags; // Logical or of NSVG_FLAGS_* flags unsigned char flags; // Logical or of NSVG_FLAGS_* flags
float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. 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. // Important note: changes the string.
NSVGimage* nsvgParse(char* input, const char* units, float dpi); 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); void nsvgDelete(NSVGimage* image);
#ifndef NANOSVG_CPLUSPLUS
#ifdef __cplusplus #ifdef __cplusplus
}; }
#endif
#endif #endif
#endif // NANOSVG_H #endif // NANOSVG_H
#ifdef NANOSVG_IMPLEMENTATION #ifdef NANOSVG_IMPLEMENTATION
#include <stdio.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <math.h> #include <math.h>
#define NSVG_PI (3.14159265358979323846264338327f) #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_MIN 0
#define NSVG_ALIGN_MID 1 #define NSVG_ALIGN_MID 1
@ -216,12 +223,7 @@ static int nsvg__isspace(char c)
static int nsvg__isdigit(char c) static int nsvg__isdigit(char c)
{ {
return strchr("0123456789", c) != 0; return c >= '0' && c <= '9';
}
static int nsvg__isnum(char c)
{
return strchr("0123456789+-.eE", c) != 0;
} }
static NSVG_INLINE float nsvg__minf(float a, float b) { return a < b ? a : b; } 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 // Get attribs
while (!end && *s && nattr < NSVG_XML_MAX_ATTRIBS-3) { while (!end && *s && nattr < NSVG_XML_MAX_ATTRIBS-3) {
char* name = NULL;
char* value = NULL;
// Skip white space before the attrib name // Skip white space before the attrib name
while (*s && nsvg__isspace(*s)) s++; while (*s && nsvg__isspace(*s)) s++;
if (!*s) break; if (!*s) break;
@ -287,7 +292,7 @@ static void nsvg__parseElement(char* s,
end = 1; end = 1;
break; break;
} }
attr[nattr++] = s; name = s;
// Find end of the attrib name. // Find end of the attrib name.
while (*s && !nsvg__isspace(*s) && *s != '=') s++; while (*s && !nsvg__isspace(*s) && *s != '=') s++;
if (*s) { *s++ = '\0'; } if (*s) { *s++ = '\0'; }
@ -297,9 +302,15 @@ static void nsvg__parseElement(char* s,
quote = *s; quote = *s;
s++; s++;
// Store value and find the end of it. // Store value and find the end of it.
attr[nattr++] = s; value = s;
while (*s && *s != quote) s++; while (*s && *s != quote) s++;
if (*s) { *s++ = '\0'; } if (*s) { *s++ = '\0'; }
// Store only well formed attributes
if (name && value) {
attr[nattr++] = name;
attr[nattr++] = value;
}
} }
// List terminator // List terminator
@ -350,7 +361,7 @@ int nsvg__parseXML(char* input,
enum NSVGgradientUnits { enum NSVGgradientUnits {
NSVG_USER_SPACE = 0, NSVG_USER_SPACE = 0,
NSVG_OBJECT_SPACE = 1, NSVG_OBJECT_SPACE = 1
}; };
#define NSVG_MAX_DASHES 8 #define NSVG_MAX_DASHES 8
@ -365,7 +376,7 @@ enum NSVGunits {
NSVG_UNITS_IN, NSVG_UNITS_IN,
NSVG_UNITS_PERCENT, NSVG_UNITS_PERCENT,
NSVG_UNITS_EM, NSVG_UNITS_EM,
NSVG_UNITS_EX, NSVG_UNITS_EX
}; };
typedef struct NSVGcoordinate { typedef struct NSVGcoordinate {
@ -416,6 +427,7 @@ typedef struct NSVGattrib
int strokeDashCount; int strokeDashCount;
char strokeLineJoin; char strokeLineJoin;
char strokeLineCap; char strokeLineCap;
float miterLimit;
char fillRule; char fillRule;
float fontSize; float fontSize;
unsigned int stopColor; unsigned int stopColor;
@ -436,6 +448,7 @@ typedef struct NSVGparser
NSVGpath* plist; NSVGpath* plist;
NSVGimage* image; NSVGimage* image;
NSVGgradientData* gradients; NSVGgradientData* gradients;
NSVGshape* shapesTail;
float viewMinx, viewMiny, viewWidth, viewHeight; float viewMinx, viewMiny, viewWidth, viewHeight;
int alignX, alignY, alignType; int alignX, alignY, alignType;
float dpi; float dpi;
@ -625,6 +638,7 @@ static NSVGparser* nsvg__createParser()
p->attr[0].strokeWidth = 1; p->attr[0].strokeWidth = 1;
p->attr[0].strokeLineJoin = NSVG_JOIN_MITER; p->attr[0].strokeLineJoin = NSVG_JOIN_MITER;
p->attr[0].strokeLineCap = NSVG_CAP_BUTT; p->attr[0].strokeLineCap = NSVG_CAP_BUTT;
p->attr[0].miterLimit = 4;
p->attr[0].fillRule = NSVG_FILLRULE_NONZERO; p->attr[0].fillRule = NSVG_FILLRULE_NONZERO;
p->attr[0].hasFill = 1; p->attr[0].hasFill = 1;
p->attr[0].visible = 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) static void nsvg__cubicBezTo(NSVGparser* p, float cpx1, float cpy1, float cpx2, float cpy2, float x, float y)
{ {
nsvg__addPoint(p, cpx1, cpy1); if (p->npts > 0) {
nsvg__addPoint(p, cpx2, cpy2); nsvg__addPoint(p, cpx1, cpy1);
nsvg__addPoint(p, x, y); nsvg__addPoint(p, cpx2, cpy2);
nsvg__addPoint(p, x, y);
}
} }
static NSVGattrib* nsvg__getAttr(NSVGparser* p) 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) static NSVGgradientData* nsvg__findGradientData(NSVGparser* p, const char* id)
{ {
NSVGgradientData* grad = p->gradients; NSVGgradientData* grad = p->gradients;
while (grad) { if (id == NULL || *id == '\0')
return NULL;
while (grad != NULL) {
if (strcmp(grad->id, id) == 0) if (strcmp(grad->id, id) == 0)
return grad; return grad;
grad = grad->next; grad = grad->next;
@ -810,19 +828,26 @@ static NSVGgradient* nsvg__createGradient(NSVGparser* p, const char* id, const f
NSVGgradient* grad; NSVGgradient* grad;
float ox, oy, sw, sh, sl; float ox, oy, sw, sh, sl;
int nstops = 0; int nstops = 0;
int refIter;
data = nsvg__findGradientData(p, id); data = nsvg__findGradientData(p, id);
if (data == NULL) return NULL; if (data == NULL) return NULL;
// TODO: use ref to fill in all unset values too. // TODO: use ref to fill in all unset values too.
ref = data; ref = data;
refIter = 0;
while (ref != NULL) { while (ref != NULL) {
NSVGgradientData* nextRef = NULL;
if (stops == NULL && ref->stops != NULL) { if (stops == NULL && ref->stops != NULL) {
stops = ref->stops; stops = ref->stops;
nstops = ref->nstops; nstops = ref->nstops;
break; 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; if (stops == NULL) return NULL;
@ -923,7 +948,7 @@ static void nsvg__addShape(NSVGparser* p)
{ {
NSVGattrib* attr = nsvg__getAttr(p); NSVGattrib* attr = nsvg__getAttr(p);
float scale = 1.0f; float scale = 1.0f;
NSVGshape *shape, *cur, *prev; NSVGshape* shape;
NSVGpath* path; NSVGpath* path;
int i; int i;
@ -939,11 +964,12 @@ static void nsvg__addShape(NSVGparser* p)
scale = nsvg__getAverageScale(attr->xform); scale = nsvg__getAverageScale(attr->xform);
shape->strokeWidth = attr->strokeWidth * scale; shape->strokeWidth = attr->strokeWidth * scale;
shape->strokeDashOffset = attr->strokeDashOffset * scale; shape->strokeDashOffset = attr->strokeDashOffset * scale;
shape->strokeDashCount = attr->strokeDashCount; shape->strokeDashCount = (char)attr->strokeDashCount;
for (i = 0; i < attr->strokeDashCount; i++) for (i = 0; i < attr->strokeDashCount; i++)
shape->strokeDashArray[i] = attr->strokeDashArray[i] * scale; shape->strokeDashArray[i] = attr->strokeDashArray[i] * scale;
shape->strokeLineJoin = attr->strokeLineJoin; shape->strokeLineJoin = attr->strokeLineJoin;
shape->strokeLineCap = attr->strokeLineCap; shape->strokeLineCap = attr->strokeLineCap;
shape->miterLimit = attr->miterLimit;
shape->fillRule = attr->fillRule; shape->fillRule = attr->fillRule;
shape->opacity = attr->opacity; shape->opacity = attr->opacity;
@ -999,16 +1025,11 @@ static void nsvg__addShape(NSVGparser* p)
shape->flags = (attr->visible ? NSVG_FLAGS_VISIBLE : 0x00); shape->flags = (attr->visible ? NSVG_FLAGS_VISIBLE : 0x00);
// Add to tail // Add to tail
prev = NULL; if (p->image->shapes == NULL)
cur = p->image->shapes;
while (cur != NULL) {
prev = cur;
cur = cur->next;
}
if (prev == NULL)
p->image->shapes = shape; p->image->shapes = shape;
else else
prev->next = shape; p->shapesTail->next = shape;
p->shapesTail = shape;
return; return;
@ -1030,6 +1051,10 @@ static void nsvg__addPath(NSVGparser* p, char closed)
if (closed) if (closed)
nsvg__lineTo(p, p->pts[0], p->pts[1]); 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)); path = (NSVGpath*)malloc(sizeof(NSVGpath));
if (path == NULL) goto error; if (path == NULL) goto error;
memset(path, 0, sizeof(NSVGpath)); 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) static const char* nsvg__parseNumber(const char* s, char* it, const int size)
{ {
const int last = size-1; const int last = size-1;
@ -1098,7 +1183,7 @@ static const char* nsvg__parseNumber(const char* s, char* it, const int size)
} }
} }
// exponent // exponent
if (*s == 'e' || *s == 'E') { if ((*s == 'e' || *s == 'E') && (s[1] != 'm' && s[1] != 'x')) {
if (i < last) it[i++] = *s; if (i < last) it[i++] = *s;
s++; s++;
if (*s == '-' || *s == '+') { if (*s == '-' || *s == '+') {
@ -1352,13 +1437,19 @@ static unsigned int nsvg__parseColor(const char* str)
static float nsvg__parseOpacity(const char* str) static float nsvg__parseOpacity(const char* str)
{ {
float val = 0; float val = nsvg__atof(str);
sscanf(str, "%f", &val);
if (val < 0.0f) val = 0.0f; if (val < 0.0f) val = 0.0f;
if (val > 1.0f) val = 1.0f; if (val > 1.0f) val = 1.0f;
return val; 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) static int nsvg__parseUnits(const char* units)
{ {
if (units[0] == 'p' && units[1] == 'x') if (units[0] == 'p' && units[1] == 'x')
@ -1382,12 +1473,21 @@ static int nsvg__parseUnits(const char* units)
return NSVG_UNITS_USER; 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) static NSVGcoordinate nsvg__parseCoordinateRaw(const char* str)
{ {
NSVGcoordinate coord = {0, NSVG_UNITS_USER}; NSVGcoordinate coord = {0, NSVG_UNITS_USER};
char units[32]=""; char buf[64];
sscanf(str, "%f%s", &coord.value, units); coord.units = nsvg__parseUnits(nsvg__parseNumber(str, buf, 64));
coord.units = nsvg__parseUnits(units); coord.value = nsvg__atof(buf);
return coord; 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 (*ptr == '-' || *ptr == '+' || *ptr == '.' || nsvg__isdigit(*ptr)) {
if (*na >= maxNa) return 0; if (*na >= maxNa) return 0;
ptr = nsvg__parseNumber(ptr, it, 64); ptr = nsvg__parseNumber(ptr, it, 64);
args[(*na)++] = (float)atof(it); args[(*na)++] = (float)nsvg__atof(it);
} else { } else {
++ptr; ++ptr;
} }
@ -1521,25 +1621,32 @@ static int nsvg__parseRotate(float* xform, const char* str)
static void nsvg__parseTransform(float* xform, const char* str) static void nsvg__parseTransform(float* xform, const char* str)
{ {
float t[6]; float t[6];
int len;
nsvg__xformIdentity(xform); nsvg__xformIdentity(xform);
while (*str) while (*str)
{ {
if (strncmp(str, "matrix", 6) == 0) if (strncmp(str, "matrix", 6) == 0)
str += nsvg__parseMatrix(t, str); len = nsvg__parseMatrix(t, str);
else if (strncmp(str, "translate", 9) == 0) else if (strncmp(str, "translate", 9) == 0)
str += nsvg__parseTranslate(t, str); len = nsvg__parseTranslate(t, str);
else if (strncmp(str, "scale", 5) == 0) else if (strncmp(str, "scale", 5) == 0)
str += nsvg__parseScale(t, str); len = nsvg__parseScale(t, str);
else if (strncmp(str, "rotate", 6) == 0) else if (strncmp(str, "rotate", 6) == 0)
str += nsvg__parseRotate(t, str); len = nsvg__parseRotate(t, str);
else if (strncmp(str, "skewX", 5) == 0) else if (strncmp(str, "skewX", 5) == 0)
str += nsvg__parseSkewX(t, str); len = nsvg__parseSkewX(t, str);
else if (strncmp(str, "skewY", 5) == 0) else if (strncmp(str, "skewY", 5) == 0)
str += nsvg__parseSkewY(t, str); len = nsvg__parseSkewY(t, str);
else{ else{
++str; ++str;
continue; continue;
} }
if (len != 0) {
str += len;
} else {
++str;
continue;
}
nsvg__xformPremultiply(xform, t); nsvg__xformPremultiply(xform, t);
} }
@ -1579,7 +1686,7 @@ static char nsvg__parseLineJoin(const char* str)
else if (strcmp(str, "bevel") == 0) else if (strcmp(str, "bevel") == 0)
return NSVG_JOIN_BEVEL; return NSVG_JOIN_BEVEL;
// TODO: handle inherit. // TODO: handle inherit.
return NSVG_CAP_BUTT; return NSVG_JOIN_MITER;
} }
static char nsvg__parseFillRule(const char* str) 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); attr->strokeLineCap = nsvg__parseLineCap(value);
} else if (strcmp(name, "stroke-linejoin") == 0) { } else if (strcmp(name, "stroke-linejoin") == 0) {
attr->strokeLineJoin = nsvg__parseLineJoin(value); attr->strokeLineJoin = nsvg__parseLineJoin(value);
} else if (strcmp(name, "stroke-miterlimit") == 0) {
attr->miterLimit = nsvg__parseMiterLimit(value);
} else if (strcmp(name, "fill-rule") == 0) { } else if (strcmp(name, "fill-rule") == 0) {
attr->fillRule = nsvg__parseFillRule(value); attr->fillRule = nsvg__parseFillRule(value);
} else if (strcmp(name, "font-size") == 0) { } else if (strcmp(name, "font-size") == 0) {
@ -1798,8 +1907,11 @@ static int nsvg__getArgsPerElement(char cmd)
case 'a': case 'a':
case 'A': case 'A':
return 7; 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) 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 rx = fabsf(args[0]); // y radius
ry = fabsf(args[1]); // x 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 fa = fabsf(args[3]) > 1e-6 ? 1 : 0; // Large arc
fs = fabsf(args[4]) > 1e-6 ? 1 : 0; // Sweep direction fs = fabsf(args[4]) > 1e-6 ? 1 : 0; // Sweep direction
x1 = *cpx; // start point 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 = NSVG_PI;
// if (vecrat(ux,uy,vx,vy) >= 1.0f) da = 0; // if (vecrat(ux,uy,vx,vy) >= 1.0f) da = 0;
if (fa) { if (fs == 0 && da > 0)
// Choose large arc da -= 2 * NSVG_PI;
if (da > 0.0f) else if (fs == 1 && da < 0)
da = da - 2*NSVG_PI; da += 2 * NSVG_PI;
else
da = 2*NSVG_PI + da;
}
// Approximate the arc using cubic spline segments. // Approximate the arc using cubic spline segments.
t[0] = cosrx; t[1] = sinrx; t[0] = cosrx; t[1] = sinrx;
@ -2088,7 +2197,7 @@ static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args,
kappa = -kappa; kappa = -kappa;
for (i = 0; i <= ndivs; i++) { for (i = 0; i <= ndivs; i++) {
a = a1 + da * (i/(float)ndivs); a = a1 + da * ((float)i/(float)ndivs);
dx = cosf(a); dx = cosf(a);
dy = sinf(a); dy = sinf(a);
nsvg__xformPoint(&x, &y, dx*rx, dy*ry, t); // position 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]; float args[10];
int nargs; int nargs;
int rargs = 0; int rargs = 0;
char initPoint;
float cpx, cpy, cpx2, cpy2; float cpx, cpy, cpx2, cpy2;
const char* tmp[4]; const char* tmp[4];
char closedFlag; char closedFlag;
@ -2134,15 +2244,16 @@ static void nsvg__parsePath(NSVGparser* p, const char** attr)
nsvg__resetPath(p); nsvg__resetPath(p);
cpx = 0; cpy = 0; cpx = 0; cpy = 0;
cpx2 = 0; cpy2 = 0; cpx2 = 0; cpy2 = 0;
initPoint = 0;
closedFlag = 0; closedFlag = 0;
nargs = 0; nargs = 0;
while (*s) { while (*s) {
s = nsvg__getNextPathItem(s, item); s = nsvg__getNextPathItem(s, item);
if (!*item) break; if (!*item) break;
if (nsvg__isnum(item[0])) { if (cmd != '\0' && nsvg__isCoordinate(item)) {
if (nargs < 10) if (nargs < 10)
args[nargs++] = (float)atof(item); args[nargs++] = (float)nsvg__atof(item);
if (nargs >= rargs) { if (nargs >= rargs) {
switch (cmd) { switch (cmd) {
case 'm': case 'm':
@ -2151,23 +2262,24 @@ static void nsvg__parsePath(NSVGparser* p, const char** attr)
// Moveto can be followed by multiple coordinate pairs, // Moveto can be followed by multiple coordinate pairs,
// which should be treated as linetos. // which should be treated as linetos.
cmd = (cmd == 'm') ? 'l' : 'L'; cmd = (cmd == 'm') ? 'l' : 'L';
rargs = nsvg__getArgsPerElement(cmd); rargs = nsvg__getArgsPerElement(cmd);
cpx2 = cpx; cpy2 = cpy; cpx2 = cpx; cpy2 = cpy;
initPoint = 1;
break; break;
case 'l': case 'l':
case 'L': case 'L':
nsvg__pathLineTo(p, &cpx, &cpy, args, cmd == 'l' ? 1 : 0); nsvg__pathLineTo(p, &cpx, &cpy, args, cmd == 'l' ? 1 : 0);
cpx2 = cpx; cpy2 = cpy; cpx2 = cpx; cpy2 = cpy;
break; break;
case 'H': case 'H':
case 'h': case 'h':
nsvg__pathHLineTo(p, &cpx, &cpy, args, cmd == 'h' ? 1 : 0); nsvg__pathHLineTo(p, &cpx, &cpy, args, cmd == 'h' ? 1 : 0);
cpx2 = cpx; cpy2 = cpy; cpx2 = cpx; cpy2 = cpy;
break; break;
case 'V': case 'V':
case 'v': case 'v':
nsvg__pathVLineTo(p, &cpx, &cpy, args, cmd == 'v' ? 1 : 0); nsvg__pathVLineTo(p, &cpx, &cpy, args, cmd == 'v' ? 1 : 0);
cpx2 = cpx; cpy2 = cpy; cpx2 = cpx; cpy2 = cpy;
break; break;
case 'C': case 'C':
case 'c': case 'c':
@ -2188,13 +2300,13 @@ static void nsvg__parsePath(NSVGparser* p, const char** attr)
case 'A': case 'A':
case 'a': case 'a':
nsvg__pathArcTo(p, &cpx, &cpy, args, cmd == 'a' ? 1 : 0); nsvg__pathArcTo(p, &cpx, &cpy, args, cmd == 'a' ? 1 : 0);
cpx2 = cpx; cpy2 = cpy; cpx2 = cpx; cpy2 = cpy;
break; break;
default: default:
if (nargs >= 2) { if (nargs >= 2) {
cpx = args[nargs-2]; cpx = args[nargs-2];
cpy = args[nargs-1]; cpy = args[nargs-1];
cpx2 = cpx; cpy2 = cpy; cpx2 = cpx; cpy2 = cpy;
} }
break; break;
} }
@ -2202,7 +2314,6 @@ static void nsvg__parsePath(NSVGparser* p, const char** attr)
} }
} else { } else {
cmd = item[0]; cmd = item[0];
rargs = nsvg__getArgsPerElement(cmd);
if (cmd == 'M' || cmd == 'm') { if (cmd == 'M' || cmd == 'm') {
// Commit path. // Commit path.
if (p->npts > 0) if (p->npts > 0)
@ -2211,7 +2322,11 @@ static void nsvg__parsePath(NSVGparser* p, const char** attr)
nsvg__resetPath(p); nsvg__resetPath(p);
closedFlag = 0; closedFlag = 0;
nargs = 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; closedFlag = 1;
// Commit path. // Commit path.
if (p->npts > 0) { if (p->npts > 0) {
@ -2227,6 +2342,12 @@ static void nsvg__parsePath(NSVGparser* p, const char** attr)
closedFlag = 0; closedFlag = 0;
nargs = 0; nargs = 0;
} }
rargs = nsvg__getArgsPerElement(cmd);
if (rargs == -1) {
// Command not recognized
cmd = '\0';
rargs = 0;
}
} }
} }
// Commit path. // Commit path.
@ -2399,7 +2520,7 @@ static void nsvg__parsePoly(NSVGparser* p, const char** attr, int closeFlag)
nargs = 0; nargs = 0;
while (*s) { while (*s) {
s = nsvg__getNextPathItem(s, item); s = nsvg__getNextPathItem(s, item);
args[nargs++] = (float)atof(item); args[nargs++] = (float)nsvg__atof(item);
if (nargs >= 2) { if (nargs >= 2) {
if (npts == 0) if (npts == 0)
nsvg__moveTo(p, args[0], args[1]); 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) { for (i = 0; attr[i]; i += 2) {
if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
if (strcmp(attr[i], "width") == 0) { 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) { } 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) { } 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) { } else if (strcmp(attr[i], "preserveAspectRatio") == 0) {
if (strstr(attr[i + 1], "none") != 0) { if (strstr(attr[i + 1], "none") != 0) {
// No uniform scaling // 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. if (p->pathFlag) // Do not allow nested paths.
return; return;
nsvg__pushAttr(p); nsvg__pushAttr(p);
p->pathFlag = 1;
p->shapeFlag = 1; p->shapeFlag = 1;
nsvg__parsePath(p, attr); nsvg__parsePath(p, attr);
nsvg__popAttr(p); 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) static void nsvg__scaleGradient(NSVGgradient* grad, float tx, float ty, float sx, float sy)
{ {
grad->xform[0] *= sx; float t[6];
grad->xform[1] *= sx; nsvg__xformSetTranslation(t, tx, ty);
grad->xform[2] *= sy; nsvg__xformMultiply (grad->xform, t);
grad->xform[3] *= sy;
grad->xform[4] += tx*sx; nsvg__xformSetScale(t, sx, sy);
grad->xform[5] += ty*sx; nsvg__xformMultiply (grad->xform, t);
} }
static void nsvg__scaleToViewbox(NSVGparser* p, const char* units) static void nsvg__scaleToViewbox(NSVGparser* p, const char* units)
@ -2873,6 +3008,36 @@ error:
return NULL; 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) void nsvgDelete(NSVGimage* image)
{ {
NSVGshape *snext, *shape; NSVGshape *snext, *shape;

View File

@ -25,15 +25,18 @@
#ifndef NANOSVGRAST_H #ifndef NANOSVGRAST_H
#define NANOSVGRAST_H #define NANOSVGRAST_H
#ifndef NANOSVGRAST_CPLUSPLUS
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#endif
typedef struct NSVGrasterizer NSVGrasterizer; typedef struct NSVGrasterizer NSVGrasterizer;
/* Example Usage: /* Example Usage:
// Load SVG // 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). // Create rasterizer (can be used to render multiple images).
struct NSVGrasterizer* rast = nsvgCreateRasterizer(); struct NSVGrasterizer* rast = nsvgCreateRasterizer();
@ -63,8 +66,10 @@ void nsvgRasterize(NSVGrasterizer* r,
void nsvgDeleteRasterizer(NSVGrasterizer*); void nsvgDeleteRasterizer(NSVGrasterizer*);
#ifndef NANOSVGRAST_CPLUSPLUS
#ifdef __cplusplus #ifdef __cplusplus
}; }
#endif
#endif #endif
#endif // NANOSVGRAST_H #endif // NANOSVGRAST_H
@ -239,7 +244,7 @@ static void nsvg__addPathPoint(NSVGrasterizer* r, float x, float y, int flags)
if (r->npoints > 0) { if (r->npoints > 0) {
pt = &r->points[r->npoints-1]; pt = &r->points[r->npoints-1];
if (nsvg__ptEquals(pt->x,pt->y, x,y, r->distTol)) { if (nsvg__ptEquals(pt->x,pt->y, x,y, r->distTol)) {
pt->flags |= flags; pt->flags = (unsigned char)(pt->flags | flags);
return; return;
} }
} }
@ -388,7 +393,7 @@ enum NSVGpointFlags
{ {
NSVG_PT_CORNER = 0x01, NSVG_PT_CORNER = 0x01,
NSVG_PT_BEVEL = 0x02, 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) 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; float lx = 0, ly = 0, rx = 0, ry = 0, prevx = 0, prevy = 0;
for (i = 0; i < ncap; i++) { 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 ax = cosf(a) * w, ay = sinf(a) * w;
float x = px - dlx*ax - dx*ay; float x = px - dlx*ax - dx*ay;
float y = py - dly*ax - dy*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;
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 < 2) n = 2;
if (n > ncap) n = ncap; if (n > ncap) n = ncap;
@ -561,7 +566,7 @@ static void nsvg__roundJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right
ry = right->y; ry = right->y;
for (i = 0; i < n; i++) { 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 a = a0 + u*da;
float ax = cosf(a) * w, ay = sinf(a) * w; float ax = cosf(a) * w, ay = sinf(a) * w;
float lx1 = p1->x - ax, ly1 = p1->y - ay; 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; int i, j, closed;
NSVGpath* path; NSVGpath* path;
NSVGpoint* p0, *p1; NSVGpoint* p0, *p1;
float miterLimit = 4; float miterLimit = shape->miterLimit;
int lineJoin = shape->strokeLineJoin; int lineJoin = shape->strokeLineJoin;
int lineCap = shape->strokeLineCap; int lineCap = shape->strokeLineCap;
float lineWidth = shape->strokeWidth * scale; 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) static int nsvg__cmpEdge(const void *p, const void *q)
{ {
NSVGedge* a = (NSVGedge*)p; const NSVGedge* a = (const NSVGedge*)p;
NSVGedge* b = (NSVGedge*)q; const NSVGedge* b = (const NSVGedge*)q;
if (a->y0 < b->y0) return -1; if (a->y0 < b->y0) return -1;
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 < len && j >= 0) {
if (i == j) { if (i == j) {
// x0,x1 are the same pixel, so compute combined coverage // 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 { } else {
if (i >= 0) // add antialiasing for x0 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 else
i = -1; // clip i = -1; // clip
if (j < len) // add antialiasing for x1 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 else
j = len; // clip j = len; // clip
for (++i; i < j; ++i) // fill pixels between x0 and x1 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; int i, cr, cg, cb, ca;
unsigned int c; unsigned int c;
fx = (x - tx) / scale; fx = ((float)x - tx) / scale;
fy = (y - ty) / scale; fy = ((float)y - ty) / scale;
dx = 1.0f / scale; dx = 1.0f / scale;
for (i = 0; i < count; i++) { 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; int i, cr, cg, cb, ca;
unsigned int c; unsigned int c;
fx = (x - tx) / scale; fx = ((float)x - tx) / scale;
fy = (y - ty) / scale; fy = ((float)y - ty) / scale;
dx = 1.0f / scale; dx = 1.0f / scale;
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
@ -1121,7 +1126,7 @@ static void nsvg__rasterizeSortedEdges(NSVGrasterizer *r, float tx, float ty, fl
xmax = 0; xmax = 0;
for (s = 0; s < NSVG__SUBSAMPLES; ++s) { for (s = 0; s < NSVG__SUBSAMPLES; ++s) {
// find center of pixel for this scanline // 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; NSVGactiveEdge **step = &active;
// update all active edges; // update all active edges;

View File

@ -94,19 +94,10 @@ private:
screen_device::svg_renderer::svg_renderer(memory_region *region) 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());
const std::unique_ptr<char []> s(new char[region->bytes() + 1]); s[region->bytes()] = 0;
memcpy(s.get(), region->base(), region->bytes()); m_image = nsvgParse(s.get(), "px", 72);
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());
}
m_rasterizer = nsvgCreateRasterizer(); m_rasterizer = nsvgCreateRasterizer();
m_key_count = 0; m_key_count = 0;

View File

@ -1,6 +1,10 @@
#include <stdio.h>
#include <string.h>
#include <math.h>
#define NANOSVG_ALL_COLOR_KEYWORDS
#define NANOSVG_IMPLEMENTATION #define NANOSVG_IMPLEMENTATION
#define NANOSVGRAST_IMPLEMENTATION #define NANOSVGRAST_IMPLEMENTATION
#define NANOSVG_ALL_COLOR_KEYWORDS
#include <nanosvg/src/nanosvg.h> #include <nanosvg/src/nanosvg.h>
#include <nanosvg/src/nanosvgrast.h> #include <nanosvg/src/nanosvgrast.h>