diff --git a/thirdparty/README.md b/thirdparty/README.md index b9b726eb3..490c7a271 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -335,7 +335,7 @@ Collection of single-file libraries used in Godot components. ## nanosvg - Upstream: https://github.com/memononen/nanosvg -- Version: git (4c8f0139b62c6e7faa3b67ce1fbe6e63590ed148, 2022) +- Version: git (bd16c4e6b2842e1f0286dc374d21f85c659862e5, 2022) - License: zlib Files extracted from the upstream source: diff --git a/thirdparty/nanosvg/nanosvg.h b/thirdparty/nanosvg/nanosvg.h index be3fc7f28..2909d0297 100644 --- a/thirdparty/nanosvg/nanosvg.h +++ b/thirdparty/nanosvg/nanosvg.h @@ -183,8 +183,6 @@ void nsvgDelete(NSVGimage* image); #endif #endif -#endif // NANOSVG_H - #ifdef NANOSVG_IMPLEMENTATION #include @@ -1226,15 +1224,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 { @@ -1642,9 +1683,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++; } @@ -3009,4 +3050,6 @@ void nsvgDelete(NSVGimage* image) free(image); } -#endif +#endif // NANOSVG_IMPLEMENTATION + +#endif // NANOSVG_H diff --git a/thirdparty/nanosvg/nanosvgrast.h b/thirdparty/nanosvg/nanosvgrast.h index 12e2cba29..e1f9cca60 100644 --- a/thirdparty/nanosvg/nanosvgrast.h +++ b/thirdparty/nanosvg/nanosvgrast.h @@ -27,6 +27,8 @@ +#include "nanosvg.h" + #ifndef NANOSVGRAST_CPLUSPLUS #ifdef __cplusplus extern "C" { @@ -74,8 +76,6 @@ void nsvgDeleteRasterizer(NSVGrasterizer*); #endif #endif -#endif // NANOSVGRAST_H - #ifdef NANOSVGRAST_IMPLEMENTATION #include @@ -1455,4 +1455,6 @@ void nsvgRasterize(NSVGrasterizer* r, r->stride = 0; } -#endif +#endif // NANOSVGRAST_IMPLEMENTATION + +#endif // NANOSVGRAST_H