Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic style sheets support #175

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 108 additions & 18 deletions src/nanosvg.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ typedef struct NSVGshape
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].

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 @@ -441,6 +442,13 @@ typedef struct NSVGattrib
char visible;
} NSVGattrib;

typedef struct NSVGstyles
{
char* name;
char* description;
struct NSVGstyles* next;
} NSVGstyles;

typedef struct NSVGparser
{
NSVGattrib attr[NSVG_MAX_ATTR];
Expand All @@ -450,13 +458,15 @@ typedef struct NSVGparser
int cpts;
NSVGpath* plist;
NSVGimage* image;
NSVGstyles* styles;
NSVGgradientData* gradients;
NSVGshape* shapesTail;
float viewMinx, viewMiny, viewWidth, viewHeight;
int alignX, alignY, alignType;
float dpi;
char pathFlag;
char defsFlag;
char styleFlag;
} NSVGparser;

static void nsvg__xformIdentity(float* t)
Expand Down Expand Up @@ -653,6 +663,17 @@ static NSVGparser* nsvg__createParser()
}
return NULL;
}
static void nsvg__deleteStyles(NSVGstyles* style) {
while (style) {
NSVGstyles *next = style->next;
if (style->name!= NULL)
free(style->name);
if (style->description != NULL)
free(style->description);
free(style);
style = next;
}
}

static void nsvg__deletePaths(NSVGpath* path)
{
Expand Down Expand Up @@ -685,6 +706,7 @@ static void nsvg__deleteGradientData(NSVGgradientData* grad)
static void nsvg__deleteParser(NSVGparser* p)
{
if (p != NULL) {
nsvg__deleteStyles(p->styles);
nsvg__deletePaths(p->plist);
nsvg__deleteGradientData(p->gradients);
nsvgDelete(p->image);
Expand Down Expand Up @@ -1779,9 +1801,18 @@ static int nsvg__parseAttr(NSVGparser* p, const char* name, const char* value)
} else if (strcmp(name, "id") == 0) {
strncpy(attr->id, value, 63);
attr->id[63] = '\0';
} else {
} else if (strcmp(name, "class") == 0) {
NSVGstyles* style = p->styles;
while (style) {
if (strcmp(style->name + 1, value) == 0) {
nsvg__parseStyle(p, style->description);
}
style = style->next;
}
}
else {
return 0;
}
}
return 1;
}

Expand Down Expand Up @@ -2226,23 +2257,23 @@ 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;
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':
Expand All @@ -2263,13 +2294,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;
}
Expand Down Expand Up @@ -2665,13 +2696,15 @@ static void nsvg__startElement(void* ud, const char* el, const char** attr)
NSVGparser* p = (NSVGparser*)ud;

if (p->defsFlag) {
// Skip everything but gradients in defs
// Skip everything but gradients and styles in defs
if (strcmp(el, "linearGradient") == 0) {
nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT);
} else if (strcmp(el, "radialGradient") == 0) {
nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT);
} else if (strcmp(el, "stop") == 0) {
nsvg__parseGradientStop(p, attr);
} else if (strcmp(el, "style") == 0) {
p->styleFlag = 1;
}
return;
}
Expand Down Expand Up @@ -2719,6 +2752,8 @@ static void nsvg__startElement(void* ud, const char* el, const char** attr)
p->defsFlag = 1;
} else if (strcmp(el, "svg") == 0) {
nsvg__parseSVG(p, attr);
} else if (strcmp(el, "style") == 0) {
p->styleFlag = 1;
}
}

Expand All @@ -2732,14 +2767,69 @@ static void nsvg__endElement(void* ud, const char* el)
p->pathFlag = 0;
} else if (strcmp(el, "defs") == 0) {
p->defsFlag = 0;
} else if (strcmp(el, "style") == 0) {
p->styleFlag = 0;
}
}

static char *nsvg__strndup(const char *s, size_t n)
{
char *result;
size_t len = strlen(s);

if (n < len)
len = n;

result = (char *)malloc(len + 1);
if (!result)
return 0;

result[len] = '\0';
return (char *)memcpy(result, s, len);
}

static void nsvg__content(void* ud, const char* s)
{
NSVG_NOTUSED(ud);
NSVG_NOTUSED(s);
// empty
NSVGparser* p = (NSVGparser*)ud;
if (p->styleFlag) {

int state = 0;
int class_count = 0;
const char* start = s;
while (*s) {
char c = *s;
if (state == 2) {
if (c == '{') {
start = s + 1;
} else if (c == '}') {
NSVGstyles *style = p->styles;
while (class_count > 0) {
style->description = nsvg__strndup(start, (size_t)(s - start));
style = style->next;
--class_count;
}
state = 0;
}
} else if (nsvg__isspace(c) || c == '{' || c == ',') {
if (state == 1) {
if (*start == '.') {
NSVGstyles* next = p->styles;
p->styles = (NSVGstyles*)malloc(sizeof(NSVGstyles));
p->styles->description = NULL;
p->styles->next = next;
p->styles->name = nsvg__strndup(start, (size_t)(s - start));
++class_count;
}
start = s + 1;
state = c == ',' ? 0 : 2;
}
} else if (state == 0) {
start = s;
state = 1;
}
s++;
}
}
}

static void nsvg__imageBounds(NSVGparser* p, float* bounds)
Expand All @@ -2755,10 +2845,10 @@ static void nsvg__imageBounds(NSVGparser* p, float* bounds)
bounds[2] = shape->bounds[2];
bounds[3] = shape->bounds[3];
for (shape = shape->next; shape != NULL; shape = shape->next) {
bounds[0] = nsvg__minf(bounds[0], shape->bounds[0]);
bounds[1] = nsvg__minf(bounds[1], shape->bounds[1]);
bounds[2] = nsvg__maxf(bounds[2], shape->bounds[2]);
bounds[3] = nsvg__maxf(bounds[3], shape->bounds[3]);
bounds[0] = nsvg__minf(bounds[0], shape->bounds[0]);
bounds[1] = nsvg__minf(bounds[1], shape->bounds[1]);
bounds[2] = nsvg__maxf(bounds[2], shape->bounds[2]);
bounds[3] = nsvg__maxf(bounds[3], shape->bounds[3]);
}
}

Expand Down Expand Up @@ -2972,4 +3062,4 @@ void nsvgDelete(NSVGimage* image)
free(image);
}

#endif
#endif