mirror of
https://github.com/QIDITECH/QIDIStudio.git
synced 2026-02-03 02:18:41 +03:00
update src
This commit is contained in:
@@ -72,6 +72,7 @@ extern "C" {
|
||||
*/
|
||||
|
||||
enum NSVGpaintType {
|
||||
NSVG_PAINT_UNDEF = -1,
|
||||
NSVG_PAINT_NONE = 0,
|
||||
NSVG_PAINT_COLOR = 1,
|
||||
NSVG_PAINT_LINEAR_GRADIENT = 2,
|
||||
@@ -119,7 +120,7 @@ typedef struct NSVGgradient {
|
||||
} NSVGgradient;
|
||||
|
||||
typedef struct NSVGpaint {
|
||||
char type;
|
||||
signed char type;
|
||||
union {
|
||||
unsigned int color;
|
||||
NSVGgradient* gradient;
|
||||
@@ -143,14 +144,17 @@ typedef struct NSVGshape
|
||||
float opacity; // Opacity of the shape.
|
||||
float strokeWidth; // Stroke width (scaled).
|
||||
float strokeDashOffset; // Stroke dash offset (scaled).
|
||||
float strokeDashArray[8]; // Stroke dash array (scaled).
|
||||
char strokeDashCount; // Number of dash values in dash array.
|
||||
float strokeDashArray[8]; // Stroke dash array (scaled).
|
||||
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].
|
||||
char fillGradient[64]; // Optional 'id' of fill gradient
|
||||
char strokeGradient[64]; // Optional 'id' of stroke gradient
|
||||
float xform[6]; // Root transformation for fill/stroke gradient
|
||||
NSVGpath* paths; // Linked list of paths in the image.
|
||||
struct NSVGshape* next; // Pointer to next shape, or NULL if last element.
|
||||
} NSVGshape;
|
||||
@@ -181,16 +185,14 @@ void nsvgDelete(NSVGimage* image);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // NANOSVG_H
|
||||
|
||||
#ifdef NANOSVG_IMPLEMENTATION
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
|
||||
#define NSVG_PI (3.14159265358979323846264338327f)
|
||||
#define NSVG_KAPPA90 (0.5522847493f) // Length proportional to radius of a cubic bezier handle for 90deg arcs.
|
||||
|
||||
@@ -227,11 +229,6 @@ static int nsvg__isdigit(char c)
|
||||
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__maxf(float a, float b) { return a > b ? a : b; }
|
||||
|
||||
@@ -402,7 +399,7 @@ typedef struct NSVGgradientData
|
||||
{
|
||||
char id[64];
|
||||
char ref[64];
|
||||
char type;
|
||||
signed char type;
|
||||
union {
|
||||
NSVGlinearData linear;
|
||||
NSVGradialData radial;
|
||||
@@ -618,7 +615,7 @@ static void nsvg__curveBounds(float* bounds, float* curve)
|
||||
}
|
||||
}
|
||||
|
||||
static NSVGparser* nsvg__createParser()
|
||||
static NSVGparser* nsvg__createParser(void)
|
||||
{
|
||||
NSVGparser* p;
|
||||
p = (NSVGparser*)malloc(sizeof(NSVGparser));
|
||||
@@ -738,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)
|
||||
@@ -810,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;
|
||||
@@ -818,28 +819,34 @@ static NSVGgradientData* nsvg__findGradientData(NSVGparser* p, const char* id)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static NSVGgradient* nsvg__createGradient(NSVGparser* p, const char* id, const float* localBounds, char* paintType)
|
||||
static NSVGgradient* nsvg__createGradient(NSVGparser* p, const char* id, const float* localBounds, float *xform, signed char* paintType)
|
||||
{
|
||||
NSVGattrib* attr = nsvg__getAttr(p);
|
||||
NSVGgradientData* data = NULL;
|
||||
NSVGgradientData* ref = NULL;
|
||||
NSVGgradientStop* stops = NULL;
|
||||
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;
|
||||
|
||||
@@ -888,7 +895,7 @@ static NSVGgradient* nsvg__createGradient(NSVGparser* p, const char* id, const f
|
||||
}
|
||||
|
||||
nsvg__xformMultiply(grad->xform, data->xform);
|
||||
nsvg__xformMultiply(grad->xform, attr->xform);
|
||||
nsvg__xformMultiply(grad->xform, xform);
|
||||
|
||||
grad->spread = data->spread;
|
||||
memcpy(grad->stops, stops, nstops*sizeof(NSVGgradientStop));
|
||||
@@ -952,6 +959,9 @@ static void nsvg__addShape(NSVGparser* p)
|
||||
memset(shape, 0, sizeof(NSVGshape));
|
||||
|
||||
memcpy(shape->id, attr->id, sizeof shape->id);
|
||||
memcpy(shape->fillGradient, attr->fillGradient, sizeof shape->fillGradient);
|
||||
memcpy(shape->strokeGradient, attr->strokeGradient, sizeof shape->strokeGradient);
|
||||
memcpy(shape->xform, attr->xform, sizeof shape->xform);
|
||||
scale = nsvg__getAverageScale(attr->xform);
|
||||
shape->strokeWidth = attr->strokeWidth * scale;
|
||||
shape->strokeDashOffset = attr->strokeDashOffset * scale;
|
||||
@@ -987,13 +997,7 @@ static void nsvg__addShape(NSVGparser* p)
|
||||
shape->fill.color = attr->fillColor;
|
||||
shape->fill.color |= (unsigned int)(attr->fillOpacity*255) << 24;
|
||||
} else if (attr->hasFill == 2) {
|
||||
float inv[6], localBounds[4];
|
||||
nsvg__xformInverse(inv, attr->xform);
|
||||
nsvg__getLocalBounds(localBounds, shape, inv);
|
||||
shape->fill.gradient = nsvg__createGradient(p, attr->fillGradient, localBounds, &shape->fill.type);
|
||||
if (shape->fill.gradient == NULL) {
|
||||
shape->fill.type = NSVG_PAINT_NONE;
|
||||
}
|
||||
shape->fill.type = NSVG_PAINT_UNDEF;
|
||||
}
|
||||
|
||||
// Set stroke
|
||||
@@ -1004,12 +1008,7 @@ static void nsvg__addShape(NSVGparser* p)
|
||||
shape->stroke.color = attr->strokeColor;
|
||||
shape->stroke.color |= (unsigned int)(attr->strokeOpacity*255) << 24;
|
||||
} else if (attr->hasStroke == 2) {
|
||||
float inv[6], localBounds[4];
|
||||
nsvg__xformInverse(inv, attr->xform);
|
||||
nsvg__getLocalBounds(localBounds, shape, inv);
|
||||
shape->stroke.gradient = nsvg__createGradient(p, attr->strokeGradient, localBounds, &shape->stroke.type);
|
||||
if (shape->stroke.gradient == NULL)
|
||||
shape->stroke.type = NSVG_PAINT_NONE;
|
||||
shape->stroke.type = NSVG_PAINT_UNDEF;
|
||||
}
|
||||
|
||||
// Set flags
|
||||
@@ -1042,6 +1041,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));
|
||||
@@ -1090,7 +1093,7 @@ 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;
|
||||
double intPart = 0.0, fracPart = 0.0;
|
||||
char hasIntPart = 0, hasFracPart = 0;
|
||||
|
||||
// Parse optional sign
|
||||
@@ -1104,9 +1107,13 @@ static double nsvg__atof(const char* s)
|
||||
// Parse integer part
|
||||
if (nsvg__isdigit(*cur)) {
|
||||
// Parse digit sequence
|
||||
#ifdef _MSC_VER
|
||||
intPart = (double)_strtoi64(cur, &end, 10);
|
||||
#else
|
||||
intPart = (double)strtoll(cur, &end, 10);
|
||||
#endif
|
||||
if (cur != end) {
|
||||
res = (double)intPart;
|
||||
res = intPart;
|
||||
hasIntPart = 1;
|
||||
cur = end;
|
||||
}
|
||||
@@ -1117,9 +1124,13 @@ static double nsvg__atof(const char* s)
|
||||
cur++; // Skip '.'
|
||||
if (nsvg__isdigit(*cur)) {
|
||||
// Parse digit sequence
|
||||
fracPart = strtoll(cur, &end, 10);
|
||||
#ifdef _MSC_VER
|
||||
fracPart = (double)_strtoi64(cur, &end, 10);
|
||||
#else
|
||||
fracPart = (double)strtoll(cur, &end, 10);
|
||||
#endif
|
||||
if (cur != end) {
|
||||
res += (double)fracPart / pow(10.0, (double)(end - cur));
|
||||
res += fracPart / pow(10.0, (double)(end - cur));
|
||||
hasFracPart = 1;
|
||||
cur = end;
|
||||
}
|
||||
@@ -1132,11 +1143,11 @@ static double nsvg__atof(const char* s)
|
||||
|
||||
// Parse optional exponent
|
||||
if (*cur == 'e' || *cur == 'E') {
|
||||
int expPart = 0;
|
||||
double expPart = 0.0;
|
||||
cur++; // skip 'E'
|
||||
expPart = strtol(cur, &end, 10); // Parse digit sequence with sign
|
||||
expPart = (double)strtol(cur, &end, 10); // Parse digit sequence with sign
|
||||
if (cur != end) {
|
||||
res *= pow(10.0, (double)expPart);
|
||||
res *= pow(10.0, expPart);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1170,7 +1181,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 == '+') {
|
||||
@@ -1187,6 +1198,20 @@ static const char* nsvg__parseNumber(const char* s, char* it, const int size)
|
||||
return s;
|
||||
}
|
||||
|
||||
static const char* nsvg__getNextPathItemWhenArcFlag(const char* s, char* it)
|
||||
{
|
||||
it[0] = '\0';
|
||||
while (*s && (nsvg__isspace(*s) || *s == ',')) s++;
|
||||
if (!*s) return s;
|
||||
if (*s == '0' || *s == '1') {
|
||||
it[0] = *s++;
|
||||
it[1] = '\0';
|
||||
return s;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
static const char* nsvg__getNextPathItem(const char* s, char* it)
|
||||
{
|
||||
it[0] = '\0';
|
||||
@@ -1207,35 +1232,66 @@ static const char* nsvg__getNextPathItem(const char* s, char* it)
|
||||
|
||||
static unsigned int nsvg__parseColorHex(const char* str)
|
||||
{
|
||||
unsigned int c = 0, r = 0, g = 0, b = 0;
|
||||
int n = 0;
|
||||
str++; // skip #
|
||||
// Calculate number of characters.
|
||||
while(str[n] && !nsvg__isspace(str[n]))
|
||||
n++;
|
||||
if (n == 6) {
|
||||
sscanf(str, "%x", &c);
|
||||
} else if (n == 3) {
|
||||
sscanf(str, "%x", &c);
|
||||
c = (c&0xf) | ((c&0xf0) << 4) | ((c&0xf00) << 8);
|
||||
c |= c<<4;
|
||||
}
|
||||
r = (c >> 16) & 0xff;
|
||||
g = (c >> 8) & 0xff;
|
||||
b = c & 0xff;
|
||||
return NSVG_RGB(r,g,b);
|
||||
unsigned int r=0, g=0, b=0;
|
||||
if (sscanf(str, "#%2x%2x%2x", &r, &g, &b) == 3 ) // 2 digit hex
|
||||
return NSVG_RGB(r, g, b);
|
||||
if (sscanf(str, "#%1x%1x%1x", &r, &g, &b) == 3 ) // 1 digit hex, e.g. #abc -> 0xccbbaa
|
||||
return NSVG_RGB(r*17, g*17, b*17); // same effect as (r<<4|r), (g<<4|g), ..
|
||||
return NSVG_RGB(128, 128, 128);
|
||||
}
|
||||
|
||||
// Parse rgb color. The pointer 'str' must point at "rgb(" (4+ characters).
|
||||
// This function returns gray (rgb(128, 128, 128) == '#808080') on parse errors
|
||||
// for backwards compatibility. Note: other image viewers return black instead.
|
||||
|
||||
static unsigned int nsvg__parseColorRGB(const char* str)
|
||||
{
|
||||
int r = -1, g = -1, b = -1;
|
||||
char s1[32]="", s2[32]="";
|
||||
sscanf(str + 4, "%d%[%%, \t]%d%[%%, \t]%d", &r, s1, &g, s2, &b);
|
||||
if (strchr(s1, '%')) {
|
||||
return NSVG_RGB((r*255)/100,(g*255)/100,(b*255)/100);
|
||||
} else {
|
||||
return NSVG_RGB(r,g,b);
|
||||
int i;
|
||||
unsigned int rgbi[3];
|
||||
float rgbf[3];
|
||||
// try decimal integers first
|
||||
if (sscanf(str, "rgb(%u, %u, %u)", &rgbi[0], &rgbi[1], &rgbi[2]) != 3) {
|
||||
// integers failed, try percent values (float, locale independent)
|
||||
const char delimiter[3] = {',', ',', ')'};
|
||||
str += 4; // skip "rgb("
|
||||
for (i = 0; i < 3; i++) {
|
||||
while (*str && (nsvg__isspace(*str))) str++; // skip leading spaces
|
||||
if (*str == '+') str++; // skip '+' (don't allow '-')
|
||||
if (!*str) break;
|
||||
rgbf[i] = nsvg__atof(str);
|
||||
|
||||
// Note 1: it would be great if nsvg__atof() returned how many
|
||||
// bytes it consumed but it doesn't. We need to skip the number,
|
||||
// the '%' character, spaces, and the delimiter ',' or ')'.
|
||||
|
||||
// Note 2: The following code does not allow values like "33.%",
|
||||
// i.e. a decimal point w/o fractional part, but this is consistent
|
||||
// with other image viewers, e.g. firefox, chrome, eog, gimp.
|
||||
|
||||
while (*str && nsvg__isdigit(*str)) str++; // skip integer part
|
||||
if (*str == '.') {
|
||||
str++;
|
||||
if (!nsvg__isdigit(*str)) break; // error: no digit after '.'
|
||||
while (*str && nsvg__isdigit(*str)) str++; // skip fractional part
|
||||
}
|
||||
if (*str == '%') str++; else break;
|
||||
while (nsvg__isspace(*str)) str++;
|
||||
if (*str == delimiter[i]) str++;
|
||||
else break;
|
||||
}
|
||||
if (i == 3) {
|
||||
rgbi[0] = roundf(rgbf[0] * 2.55f);
|
||||
rgbi[1] = roundf(rgbf[1] * 2.55f);
|
||||
rgbi[2] = roundf(rgbf[2] * 2.55f);
|
||||
} else {
|
||||
rgbi[0] = rgbi[1] = rgbi[2] = 128;
|
||||
}
|
||||
}
|
||||
// clip values as the CSS spec requires
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (rgbi[i] > 255) rgbi[i] = 255;
|
||||
}
|
||||
return NSVG_RGB(rgbi[0], rgbi[1], rgbi[2]);
|
||||
}
|
||||
|
||||
typedef struct NSVGNamedColor {
|
||||
@@ -1460,6 +1516,15 @@ 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, or start by a dot
|
||||
return (nsvg__isdigit(*s) || *s == '.');
|
||||
}
|
||||
|
||||
static NSVGcoordinate nsvg__parseCoordinateRaw(const char* str)
|
||||
{
|
||||
NSVGcoordinate coord = {0, NSVG_UNITS_USER};
|
||||
@@ -1599,25 +1664,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);
|
||||
}
|
||||
@@ -1627,9 +1699,9 @@ static void nsvg__parseUrl(char* id, const char* str)
|
||||
{
|
||||
int i = 0;
|
||||
str += 4; // "url(";
|
||||
if (*str == '#')
|
||||
if (*str && *str == '#')
|
||||
str++;
|
||||
while (i < 63 && *str != ')') {
|
||||
while (i < 63 && *str && *str != ')') {
|
||||
id[i] = *str++;
|
||||
i++;
|
||||
}
|
||||
@@ -1878,8 +1950,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)
|
||||
@@ -2160,7 +2235,12 @@ static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args,
|
||||
// The loop assumes an iteration per end point (including start and end), this +1.
|
||||
ndivs = (int)(fabsf(da) / (NSVG_PI*0.5f) + 1.0f);
|
||||
hda = (da / (float)ndivs) / 2.0f;
|
||||
kappa = fabsf(4.0f / 3.0f * (1.0f - cosf(hda)) / sinf(hda));
|
||||
// Fix for ticket #179: division by 0: avoid cotangens around 0 (infinite)
|
||||
if ((hda < 1e-3f) && (hda > -1e-3f))
|
||||
hda *= 0.5f;
|
||||
else
|
||||
hda = (1.0f - cosf(hda)) / sinf(hda);
|
||||
kappa = fabsf(4.0f / 3.0f * hda);
|
||||
if (da < 0.0f)
|
||||
kappa = -kappa;
|
||||
|
||||
@@ -2189,6 +2269,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;
|
||||
@@ -2211,13 +2292,18 @@ 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);
|
||||
item[0] = '\0';
|
||||
if ((cmd == 'A' || cmd == 'a') && (nargs == 3 || nargs == 4))
|
||||
s = nsvg__getNextPathItemWhenArcFlag(s, item);
|
||||
if (!*item)
|
||||
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)nsvg__atof(item);
|
||||
if (nargs >= rargs) {
|
||||
@@ -2230,6 +2316,7 @@ static void nsvg__parsePath(NSVGparser* p, const char** attr)
|
||||
cmd = (cmd == 'm') ? 'l' : 'L';
|
||||
rargs = nsvg__getArgsPerElement(cmd);
|
||||
cpx2 = cpx; cpy2 = cpy;
|
||||
initPoint = 1;
|
||||
break;
|
||||
case 'l':
|
||||
case 'L':
|
||||
@@ -2279,7 +2366,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)
|
||||
@@ -2288,7 +2374,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) {
|
||||
@@ -2304,6 +2394,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.
|
||||
@@ -2550,7 +2646,7 @@ static void nsvg__parseSVG(NSVGparser* p, const char** attr)
|
||||
}
|
||||
}
|
||||
|
||||
static void nsvg__parseGradient(NSVGparser* p, const char** attr, char type)
|
||||
static void nsvg__parseGradient(NSVGparser* p, const char** attr, signed char type)
|
||||
{
|
||||
int i;
|
||||
NSVGgradientData* grad = (NSVGgradientData*)malloc(sizeof(NSVGgradientData));
|
||||
@@ -2875,6 +2971,36 @@ static void nsvg__scaleToViewbox(NSVGparser* p, const char* units)
|
||||
}
|
||||
}
|
||||
|
||||
static void nsvg__createGradients(NSVGparser* p)
|
||||
{
|
||||
NSVGshape* shape;
|
||||
|
||||
for (shape = p->image->shapes; shape != NULL; shape = shape->next) {
|
||||
if (shape->fill.type == NSVG_PAINT_UNDEF) {
|
||||
if (shape->fillGradient[0] != '\0') {
|
||||
float inv[6], localBounds[4];
|
||||
nsvg__xformInverse(inv, shape->xform);
|
||||
nsvg__getLocalBounds(localBounds, shape, inv);
|
||||
shape->fill.gradient = nsvg__createGradient(p, shape->fillGradient, localBounds, shape->xform, &shape->fill.type);
|
||||
}
|
||||
if (shape->fill.type == NSVG_PAINT_UNDEF) {
|
||||
shape->fill.type = NSVG_PAINT_NONE;
|
||||
}
|
||||
}
|
||||
if (shape->stroke.type == NSVG_PAINT_UNDEF) {
|
||||
if (shape->strokeGradient[0] != '\0') {
|
||||
float inv[6], localBounds[4];
|
||||
nsvg__xformInverse(inv, shape->xform);
|
||||
nsvg__getLocalBounds(localBounds, shape, inv);
|
||||
shape->stroke.gradient = nsvg__createGradient(p, shape->strokeGradient, localBounds, shape->xform, &shape->stroke.type);
|
||||
}
|
||||
if (shape->stroke.type == NSVG_PAINT_UNDEF) {
|
||||
shape->stroke.type = NSVG_PAINT_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NSVGimage* nsvgParse(char* input, const char* units, float dpi)
|
||||
{
|
||||
NSVGparser* p;
|
||||
@@ -2888,6 +3014,9 @@ NSVGimage* nsvgParse(char* input, const char* units, float dpi)
|
||||
|
||||
nsvg__parseXML(input, nsvg__startElement, nsvg__endElement, nsvg__content, p);
|
||||
|
||||
// Create gradients after all definitions have been parsed
|
||||
nsvg__createGradients(p);
|
||||
|
||||
// Scale to viewBox
|
||||
nsvg__scaleToViewbox(p, units);
|
||||
|
||||
@@ -2899,7 +3028,10 @@ NSVGimage* nsvgParse(char* input, const char* units, float dpi)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#include <boost/nowide/cstdio.hpp>
|
||||
#if WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include "windows.h"
|
||||
#endif
|
||||
|
||||
NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi)
|
||||
{
|
||||
@@ -2908,8 +3040,17 @@ NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi)
|
||||
char* data = NULL;
|
||||
NSVGimage* image = NULL;
|
||||
|
||||
fp = boost::nowide::fopen(filename, "rb");
|
||||
if (!fp) goto error;
|
||||
#if WIN32
|
||||
int name_len = MultiByteToWideChar(CP_UTF8, NULL, filename, strlen(filename), NULL, 0);
|
||||
wchar_t w_fname[512];
|
||||
memset(w_fname, 0, sizeof(w_fname));
|
||||
MultiByteToWideChar(CP_UTF8, NULL, filename, strlen(filename), w_fname, name_len);
|
||||
w_fname[name_len] = '\0';
|
||||
fp = _wfopen(w_fname, L"rb");
|
||||
#else
|
||||
fp = fopen(filename, "rb");
|
||||
#endif
|
||||
if (!fp) goto error;
|
||||
fseek(fp, 0, SEEK_END);
|
||||
size = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
@@ -2918,9 +3059,9 @@ NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi)
|
||||
if (fread(data, 1, size, fp) != size) goto error;
|
||||
data[size] = '\0'; // Must be null terminated.
|
||||
fclose(fp);
|
||||
|
||||
image = nsvgParse(data, units, dpi);
|
||||
free(data);
|
||||
|
||||
return image;
|
||||
|
||||
error:
|
||||
@@ -2976,4 +3117,6 @@ void nsvgDelete(NSVGimage* image)
|
||||
free(image);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // NANOSVG_IMPLEMENTATION
|
||||
|
||||
#endif // NANOSVG_H
|
||||
|
||||
Reference in New Issue
Block a user