From c5f4934995f034913db8341b7dd2f18af20cb864 Mon Sep 17 00:00:00 2001 From: Albrecht Schlosser Date: Thu, 22 Dec 2022 01:12:14 +0100 Subject: [PATCH] Update bundled nanosvg library to current upstream version ... with FLTK modifications (see README.bundled-libs.txt). This fixes an issue where some svg images could not be loaded. Upstream: https://github.com/memononen/nanosvg/ commit 9da543e8329fdd81b64eb48742d8ccb09377aed1 (upstream/master) Merge: c886e50 0ce2e2b Author: Mikko Mononen Date: Sun Dec 4 17:46:22 2022 +0200 Merge pull request #236 from sezero/signed-char change struct NSVGpaint:type to signed char --- README.bundled-libs.txt | 2 +- nanosvg/README.txt | 59 ++++++++++++++++--------- nanosvg/nanosvg.h | 95 ++++++++++++++++++++++++++++++----------- nanosvg/nanosvgrast.h | 6 +-- 4 files changed, 113 insertions(+), 49 deletions(-) diff --git a/README.bundled-libs.txt b/README.bundled-libs.txt index ceeb927fb..ef90bd2b9 100644 --- a/README.bundled-libs.txt +++ b/README.bundled-libs.txt @@ -20,7 +20,7 @@ Current versions of bundled libraries (as of Sep 13, 2021): Library Version Release date FLTK Version -------------------------------------------------------------------------- jpeg jpeg-9d 2020-01-12 1.4.0 - nanosvg 06a9113e29 [1] 2022-07-09 1.4.0 + nanosvg abcd277ea4 [1] 2022-12-22 1.4.0 png libpng-1.6.37 2019-04-14 1.4.0 zlib zlib-1.2.11 2017-01-15 1.4.0 -------------------------------------------------------------------------- diff --git a/nanosvg/README.txt b/nanosvg/README.txt index ec3235e8b..31ac6b9b0 100644 --- a/nanosvg/README.txt +++ b/nanosvg/README.txt @@ -22,34 +22,53 @@ For more information see README.bundled-libs.txt in FLTK's root directory. Changes in the FLTK fork, branch 'fltk': ----------------------------------------- -$ git show --no-patch fltk_2021-09-13 -tag fltk_2021-09-13 +$ git show --no-patch fltk_2022-12-22 +tag fltk_2022-12-22 Tagger: Albrecht Schlosser -Date: Mon Sep 13 19:09:40 2021 +0200 +Date: Thu Dec 22 00:44:33 2022 +0100 -FLTK modifications as of Sep 13, 2021: +Latest nanosvg changes as of Dec 22, 2022: -$ git shortlog master..fltk -AlbrechtS (2): - Fix Visual Studio compilation error (missing long long). - Modify rasterizer to support non-square X,Y axes scaling. +$ git log -3 fltk +commit abcd277ea45e9098bed752cf9c6875b533c0892f (HEAD -> fltk) +Author: AlbrechtS +Date: Sun Feb 4 23:47:38 2018 +0100 -Greg Ercolano (1): - Clip integer RGB percent values > 100 + Modify rasterizer to support non-square X,Y axes scaling. -Latest upstream commit (master): + Add new function nsvgRasterizeXY() similar to nsvgRasterize() but with + separate scaling factors for x-axis and y-axis. -commit ccdb1995134d340a93fb20e3a3d323ccb3838dd0 -Merge: 3cdd4a9 419782d +commit 6ea21790604e7f0e84b2260fed34173ed475365e +Author: AlbrechtS +Date: Sun Feb 4 23:43:30 2018 +0100 + + Fix Visual Studio compilation error (missing long long). + + Change 'long long intPart' to 'double intPart' and replace + strtoll() with _strtoi64() when built with Visual Studio. + +commit 9da543e8329fdd81b64eb48742d8ccb09377aed1 (upstream/master) +Merge: c886e50 0ce2e2b Author: Mikko Mononen -Date: Fri Sep 3 21:24:42 2021 +0300 +Date: Sun Dec 4 17:46:22 2022 +0200 - Merge pull request #198 from ctrlcctrlv/CVE_2019_1000032 + Merge pull request #236 from sezero/signed-char - Fix decimal values in color fields (nsvg__parseColorRGB, nsvg__parseColorHex) + change struct NSVGpaint:type to signed char -commit 461ad7de70d5fd3f09fc214e4baaadb830a2a270 (HEAD -> fltk, tag: fltk_2021-09-13, origin/fltk, origin/HEAD) -Author: Greg Ercolano -Date: Mon Jan 18 15:05:13 2021 -0800 +---- - Clip integer RGB percent values > 100 +Commits abcd277ea4 and 6ea2179060 are FLTK specific, +commit 9da543e832 is the latest upstream commit + +---- End of tag ---- + +commit abcd277ea45e9098bed752cf9c6875b533c0892f (HEAD -> fltk, tag: fltk_2022-12-22) +Author: AlbrechtS +Date: Sun Feb 4 23:47:38 2018 +0100 + + Modify rasterizer to support non-square X,Y axes scaling. + + Add new function nsvgRasterizeXY() similar to nsvgRasterize() but with + separate scaling factors for x-axis and y-axis. diff --git a/nanosvg/nanosvg.h b/nanosvg/nanosvg.h index 24bdd46ce..1a1a20cb3 100644 --- a/nanosvg/nanosvg.h +++ b/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; @@ -610,7 +614,7 @@ static void nsvg__curveBounds(float* bounds, float* curve) } } -static NSVGparser* nsvg__createParser() +static NSVGparser* nsvg__createParser(void) { NSVGparser* p; p = (NSVGparser*)malloc(sizeof(NSVGparser)); @@ -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 @@ -1202,6 +1197,19 @@ static const char* nsvg__parseNumber(const char* s, char* it, const int size) return s; } +static const char* nsvg__getNextPathItemWhenArcFlag(const char* s, char* it) +{ + it[0] = '\0'; + while (*s && (nsvg__isspace(*s) || *s == ',')) s++; + if (!*s) return s; + if (*s == '0' || *s == '1') { + it[0] = *s++; + it[1] = '\0'; + return s; + } + return s; +} + static const char* nsvg__getNextPathItem(const char* s, char* it) { it[0] = '\0'; @@ -1689,9 +1697,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++; } @@ -2287,7 +2295,11 @@ static void nsvg__parsePath(NSVGparser* p, const char** attr) nargs = 0; while (*s) { - s = nsvg__getNextPathItem(s, item); + item[0] = '\0'; + if ((cmd == 'A' || cmd == 'a') && (nargs == 3 || nargs == 4)) + s = nsvg__getNextPathItemWhenArcFlag(s, item); + if (!*item) + s = nsvg__getNextPathItem(s, item); if (!*item) break; if (cmd != '\0' && nsvg__isCoordinate(item)) { if (nargs < 10) @@ -2632,7 +2644,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)); @@ -2957,6 +2969,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; @@ -2970,6 +3012,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/nanosvg/nanosvgrast.h b/nanosvg/nanosvgrast.h index 52986693e..a83db2726 100644 --- a/nanosvg/nanosvgrast.h +++ b/nanosvg/nanosvgrast.h @@ -58,7 +58,7 @@ typedef struct NSVGrasterizer NSVGrasterizer; */ // Allocated rasterizer context. -NSVGrasterizer* nsvgCreateRasterizer(); +NSVGrasterizer* nsvgCreateRasterizer(void); // Rasterizes SVG image, returns RGBA image (non-premultiplied alpha) // r - pointer to rasterizer context @@ -129,7 +129,7 @@ typedef struct NSVGmemPage { } NSVGmemPage; typedef struct NSVGcachedPaint { - char type; + signed char type; char spread; float xform[6]; unsigned int colors[256]; @@ -165,7 +165,7 @@ struct NSVGrasterizer int width, height, stride; }; -NSVGrasterizer* nsvgCreateRasterizer() +NSVGrasterizer* nsvgCreateRasterizer(void) { NSVGrasterizer* r = (NSVGrasterizer*)malloc(sizeof(NSVGrasterizer)); if (r == NULL) goto error;