Skip to content

Commit

Permalink
nanosvg: sync with mainstream:
Browse files Browse the repository at this point in the history
  • Loading branch information
sezero authored and slouken committed Dec 4, 2022
1 parent 1ef7f65 commit b633019
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 36 deletions.
152 changes: 120 additions & 32 deletions nanosvg.h
Expand Up @@ -76,6 +76,7 @@ extern "C" {
*/

enum NSVGpaintType {
NSVG_PAINT_UNDEF = -1,
NSVG_PAINT_NONE = 0,
NSVG_PAINT_COLOR = 1,
NSVG_PAINT_LINEAR_GRADIENT = 2,
Expand Down Expand Up @@ -123,7 +124,7 @@ typedef struct NSVGgradient {
} NSVGgradient;

typedef struct NSVGpaint {
char type;
signed char type;
union {
unsigned int color;
NSVGgradient* gradient;
Expand All @@ -147,14 +148,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;
Expand Down Expand Up @@ -403,7 +407,7 @@ typedef struct NSVGgradientData
{
char id[64];
char ref[64];
char type;
signed char type;
union {
NSVGlinearData linear;
NSVGradialData radial;
Expand Down Expand Up @@ -845,9 +849,8 @@ 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;
Expand Down Expand Up @@ -922,7 +925,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));
Expand Down Expand Up @@ -986,6 +989,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;
Expand Down Expand Up @@ -1021,13 +1027,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
Expand All @@ -1038,12 +1038,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
Expand Down Expand Up @@ -1225,6 +1220,19 @@ 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';
Expand Down Expand Up @@ -1253,15 +1261,58 @@ static unsigned int nsvg__parseColorHex(const char* str)
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)
{
unsigned int r=0, g=0, b=0;
float rf=0, gf=0, bf=0;
if (sscanf(str, "rgb(%u, %u, %u)", &r, &g, &b) == 3) // decimal integers
return NSVG_RGB(r, g, b);
if (sscanf(str, "rgb(%f%%, %f%%, %f%%)", &rf, &gf, &bf) == 3) // decimal integer percentage
return NSVG_RGB(roundf(rf*2.55f), roundf(gf*2.55f), roundf(bf*2.55f)); // (255 / 100.0f)
return NSVG_RGB(128, 128, 128);
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 {
Expand Down Expand Up @@ -1671,9 +1722,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++;
}
Expand Down Expand Up @@ -2277,7 +2328,11 @@ static void nsvg__parsePath(NSVGparser* p, const char** attr)
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 (cmd != '\0' && nsvg__isCoordinate(item)) {
if (nargs < 10)
Expand Down Expand Up @@ -2622,7 +2677,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));
Expand Down Expand Up @@ -3006,6 +3061,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;
}
}
}
}

NSVG_EXPORT NSVGimage* nsvgParse(char* input, const char* units, float dpi)
{
NSVGparser* p;
Expand All @@ -3019,6 +3104,9 @@ NSVG_EXPORT 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);

Expand Down Expand Up @@ -3109,6 +3197,6 @@ NSVG_EXPORT void nsvgDelete(NSVGimage* image)
free(image);
}

#endif
#endif // NANOSVG_IMPLEMENTATION

#endif // NANOSVG_H
8 changes: 4 additions & 4 deletions nanosvgrast.h
Expand Up @@ -63,8 +63,8 @@ NSVG_EXPORT NSVGrasterizer* nsvgCreateRasterizer(void);
// h - height of the image to render
// stride - number of bytes per scaleline in the destination buffer
NSVG_EXPORT void nsvgRasterize(NSVGrasterizer* r,
NSVGimage* image, float tx, float ty, float scale,
unsigned char* dst, int w, int h, int stride);
NSVGimage* image, float tx, float ty, float scale,
unsigned char* dst, int w, int h, int stride);

// Deletes rasterizer context.
NSVG_EXPORT void nsvgDeleteRasterizer(NSVGrasterizer*);
Expand Down Expand Up @@ -116,7 +116,7 @@ typedef struct NSVGmemPage {
} NSVGmemPage;

typedef struct NSVGcachedPaint {
char type;
signed char type;
char spread;
float xform[6];
unsigned int colors[256];
Expand Down Expand Up @@ -1460,6 +1460,6 @@ NSVG_EXPORT void nsvgRasterize(NSVGrasterizer* r,
r->stride = 0;
}

#endif
#endif // NANOSVGRAST_IMPLEMENTATION

#endif // NANOSVGRAST_H

0 comments on commit b633019

Please sign in to comment.