diff --git a/src/nanosvg.h b/src/nanosvg.h index e5f69006..59e94758 100644 --- a/src/nanosvg.h +++ b/src/nanosvg.h @@ -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; @@ -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]; @@ -450,6 +458,7 @@ typedef struct NSVGparser int cpts; NSVGpath* plist; NSVGimage* image; + NSVGstyles* styles; NSVGgradientData* gradients; NSVGshape* shapesTail; float viewMinx, viewMiny, viewWidth, viewHeight; @@ -457,6 +466,7 @@ typedef struct NSVGparser float dpi; char pathFlag; char defsFlag; + char styleFlag; } NSVGparser; static void nsvg__xformIdentity(float* t) @@ -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) { @@ -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); @@ -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; } @@ -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': @@ -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; } @@ -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; } @@ -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; } } @@ -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) @@ -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]); } } @@ -2972,4 +3062,4 @@ void nsvgDelete(NSVGimage* image) free(image); } -#endif +#endif \ No newline at end of file