SDL_image: nanosvg: sync with mainstream:

From acfe4770cdcddf37457f90980e55fe658773a070 Mon Sep 17 00:00:00 2001
From: Ozkan Sezer <[EMAIL REDACTED]>
Date: Fri, 27 May 2022 17:29:50 +0300
Subject: [PATCH] nanosvg: sync with mainstream:

This imports the following four commits from mainstream nanosvg:
https://github.com/memononen/nanosvg/commit/3cdd4a9d788695699799b37d492e45e2c3625790
https://github.com/memononen/nanosvg/commit/ccdb1995134d340a93fb20e3a3d323ccb3838dd0
https://github.com/memononen/nanosvg/commit/214cf85efcdc67524335ad0e2a2d5982246b6a72
https://github.com/memononen/nanosvg/commit/3bcdf2f3cdc1bf9197c2dce81368bfc6f99205a7

This adds roundf() as a new dependency: Since SDL_roundf() requires
SDL >= 2.0.16, invented a tiny local SDLIMAGE_roundf() function for
it instead.
---
 IMG_svg.c     |  5 ++++
 nanosvg.h     | 69 ++++++++++++++++++++++-----------------------------
 nanosvgrast.h |  4 +--
 3 files changed, 36 insertions(+), 42 deletions(-)

diff --git a/IMG_svg.c b/IMG_svg.c
index e834c7db..03f281da 100644
--- a/IMG_svg.c
+++ b/IMG_svg.c
@@ -27,6 +27,10 @@
 
 #ifdef LOAD_SVG
 
+static float SDLCALL SDLIMAGE_roundf(float x) {
+    return (x >= 0.0f) ? SDL_floorf(x + 0.5f) : SDL_ceilf(x - 0.5f);
+}
+
 /* Replace C runtime functions with SDL C runtime functions for building on Windows */
 #define free    SDL_free
 #define malloc  SDL_malloc
@@ -63,6 +67,7 @@
 #define sqrt    SDL_sqrt
 #define sqrtf   SDL_sqrtf
 #define tanf    SDL_tanf
+#define roundf  SDLIMAGE_roundf
 #ifndef FLT_MAX
 #define FLT_MAX     3.402823466e+38F
 #endif
diff --git a/nanosvg.h b/nanosvg.h
index bc45cfb2..0ceb2c75 100644
--- a/nanosvg.h
+++ b/nanosvg.h
@@ -189,8 +189,6 @@ NSVG_EXPORT void nsvgDelete(NSVGimage* image);
 #endif
 #endif
 
-#endif // NANOSVG_H
-
 #ifdef NANOSVG_IMPLEMENTATION
 
 /*
@@ -1246,35 +1244,23 @@ 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);
 }
 
 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);
-	}
+	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);
 }
 
 typedef struct NSVGNamedColor {
@@ -1849,10 +1835,9 @@ static int nsvg__parseAttr(NSVGparser* p, const char* name, const char* value)
 		if (style) {
 			nsvg__parseStyle(p, style->description);
 		}
-	} 
-	else {
+	} else {
 		return 0;
-	} 
+	}
 	return 1;
 }
 
@@ -2232,7 +2217,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;
 
@@ -2844,10 +2834,10 @@ static char *nsvg__strndup(const char *s, size_t n)
 static void nsvg__content(void* ud, const char* s)
 {
 	NSVGparser* p = (NSVGparser*)ud;
-	if (p->styleFlag) {
 
+	if (p->styleFlag) {
 		int state = 0;
-		const char* start = s;		
+		const char* start = s;
 		while (*s) {
 			char c = *s;
 			if (nsvg__isspace(c) || c == '{') {
@@ -2859,15 +2849,14 @@ static void nsvg__content(void* ud, const char* s)
 					p->styles->name = nsvg__strndup(start, (size_t)(s - start));
 					start = s + 1;
 					state = 2;
-				}				
+				}
 			} else if (state == 2 && c == '}') {
 				p->styles->description = nsvg__strndup(start, (size_t)(s - start));
 				state = 0;
-			}
-			else if (state == 0) {
+			} else if (state == 0) {
 				start = s;
 				state = 1;
-			}  
+			}
 			s++;
 		}
 		//	if (*s == '{' && state == NSVG_XML_CONTENT) {
@@ -2888,9 +2877,7 @@ static void nsvg__content(void* ud, const char* s)
 		//		s++;
 		//	}
 		//}
-
 	}
-	// empty
 }
 
 static void nsvg__imageBounds(NSVGparser* p, float* bounds)
@@ -3109,7 +3096,7 @@ NSVG_EXPORT NSVGpath* nsvgDuplicatePath(NSVGpath* p)
     }
     return NULL;
 }
-#endif // 0
+#endif
 
 NSVG_EXPORT void nsvgDelete(NSVGimage* image)
 {
@@ -3128,3 +3115,5 @@ NSVG_EXPORT void nsvgDelete(NSVGimage* image)
 }
 
 #endif
+
+#endif // NANOSVG_H
diff --git a/nanosvgrast.h b/nanosvgrast.h
index b45430ac..b2a7cf59 100644
--- a/nanosvgrast.h
+++ b/nanosvgrast.h
@@ -76,8 +76,6 @@ NSVG_EXPORT void nsvgDeleteRasterizer(NSVGrasterizer*);
 #endif
 #endif
 
-#endif // NANOSVGRAST_H
-
 #ifdef NANOSVGRAST_IMPLEMENTATION
 
 /*
@@ -1463,3 +1461,5 @@ NSVG_EXPORT void nsvgRasterize(NSVGrasterizer* r,
 }
 
 #endif
+
+#endif // NANOSVGRAST_H