diff --git a/thirdparty/README.md b/thirdparty/README.md index 1b1892526ab..35357596f51 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -400,7 +400,7 @@ Collection of single-file libraries used in Godot components. ## nanosvg - Upstream: https://github.com/memononen/nanosvg -- Version: git (f0a3e1034dd22e2e87e5db22401e44998383124e, 2022) +- Version: git (93ce879dc4c04a3ef1758428ec80083c38610b1f, 2023) - License: zlib Files extracted from the upstream source: diff --git a/thirdparty/nanosvg/nanosvg.h b/thirdparty/nanosvg/nanosvg.h index 30b74392319..60a323820cb 100644 --- a/thirdparty/nanosvg/nanosvg.h +++ b/thirdparty/nanosvg/nanosvg.h @@ -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; @@ -394,7 +398,7 @@ typedef struct NSVGgradientData { char id[64]; char ref[64]; - char type; + signed char type; union { NSVGlinearData linear; NSVGradialData radial; @@ -814,9 +818,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; @@ -891,7 +894,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)); @@ -955,6 +958,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; @@ -990,13 +996,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 @@ -1007,12 +1007,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 @@ -2641,7 +2636,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)); @@ -2966,6 +2961,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; @@ -2979,6 +3004,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); diff --git a/thirdparty/nanosvg/nanosvgrast.h b/thirdparty/nanosvg/nanosvgrast.h index 6e23acb7b04..90d42e92869 100644 --- a/thirdparty/nanosvg/nanosvgrast.h +++ b/thirdparty/nanosvg/nanosvgrast.h @@ -114,7 +114,7 @@ typedef struct NSVGmemPage { } NSVGmemPage; typedef struct NSVGcachedPaint { - char type; + signed char type; char spread; float xform[6]; unsigned int colors[256]; @@ -331,6 +331,7 @@ static float nsvg__normalize(float *x, float* y) } static float nsvg__absf(float x) { return x < 0 ? -x : x; } +static float nsvg__roundf(float x) { return (x >= 0) ? floorf(x + 0.5) : ceilf(x - 0.5); } static void nsvg__flattenCubicBez(NSVGrasterizer* r, float x1, float y1, float x2, float y2, @@ -353,8 +354,8 @@ static void nsvg__flattenCubicBez(NSVGrasterizer* r, dx = x4 - x1; dy = y4 - y1; - d2 = nsvg__absf(((x2 - x4) * dy - (y2 - y4) * dx)); - d3 = nsvg__absf(((x3 - x4) * dy - (y3 - y4) * dx)); + d2 = nsvg__absf((x2 - x4) * dy - (y2 - y4) * dx); + d3 = nsvg__absf((x3 - x4) * dy - (y3 - y4) * dx); if ((d2 + d3)*(d2 + d3) < r->tessTol * (dx*dx + dy*dy)) { nsvg__addPathPoint(r, x4, y4, type); @@ -872,10 +873,10 @@ static NSVGactiveEdge* nsvg__addActive(NSVGrasterizer* r, NSVGedge* e, float sta // STBTT_assert(e->y0 <= start_point); // round dx down to avoid going too far if (dxdy < 0) - z->dx = (int)(-floorf(NSVG__FIX * -dxdy)); + z->dx = (int)(-nsvg__roundf(NSVG__FIX * -dxdy)); else - z->dx = (int)floorf(NSVG__FIX * dxdy); - z->x = (int)floorf(NSVG__FIX * (e->x0 + dxdy * (startPoint - e->y0))); + z->dx = (int)nsvg__roundf(NSVG__FIX * dxdy); + z->x = (int)nsvg__roundf(NSVG__FIX * (e->x0 + dxdy * (startPoint - e->y0))); // z->x -= off_x * FIX; z->ey = e->y1; z->next = 0; @@ -1282,9 +1283,10 @@ static void nsvg__initPaint(NSVGcachedPaint* cache, NSVGpaint* paint, float opac if (grad->nstops == 0) { for (i = 0; i < 256; i++) cache->colors[i] = 0; - } if (grad->nstops == 1) { + } else if (grad->nstops == 1) { + unsigned int color = nsvg__applyOpacity(grad->stops[0].color, opacity); for (i = 0; i < 256; i++) - cache->colors[i] = nsvg__applyOpacity(grad->stops[i].color, opacity); + cache->colors[i] = color; } else { unsigned int ca, cb = 0; float ua, ub, du, u;