Skip to content

Commit 6c37117

Browse files
committed
[https://core.tcl-lang.org/tk/info/b43dbc00] nanosvg pull request 273 and 275: support svg color order and fix possible nan race condition
1 parent ecf146e commit 6c37117

File tree

2 files changed

+90
-47
lines changed

2 files changed

+90
-47
lines changed

generic/nanosvg.h

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,12 @@ enum NSVGflags {
139139
NSVG_FLAGS_VISIBLE = 0x01
140140
};
141141

142+
enum NSVGpaintOrder {
143+
NSVG_PAINT_FILL = 0x00,
144+
NSVG_PAINT_MARKERS = 0x01,
145+
NSVG_PAINT_STROKE = 0x02
146+
};
147+
142148
typedef struct NSVGgradientStop {
143149
unsigned int color;
144150
float offset;
@@ -183,6 +189,7 @@ typedef struct NSVGshape
183189
char strokeLineCap; /* Stroke cap type. */
184190
float miterLimit; /* Miter limit */
185191
char fillRule; /* Fill rule, see NSVGfillRule. */
192+
unsigned char paintOrder; /* Encoded paint order (3×2-bit fields) see NSVGpaintOrder */
186193
unsigned char flags; /* Logical or of NSVG_FLAGS_* flags */
187194
float bounds[4]; /* Tight bounding box of the shape [minx,miny,maxx,maxy]. */
188195
char fillGradient[64]; // Optional 'id' of fill gradient
@@ -475,6 +482,7 @@ typedef struct NSVGattrib
475482
char hasFill;
476483
char hasStroke;
477484
char visible;
485+
unsigned char paintOrder;
478486
} NSVGattrib;
479487

480488
typedef struct NSVGstyles
@@ -661,6 +669,10 @@ static void nsvg__curveBounds(float* bounds, float* curve)
661669
}
662670
}
663671

672+
static unsigned char nsvg__encodePaintOrder(enum NSVGpaintOrder a, enum NSVGpaintOrder b, enum NSVGpaintOrder c) {
673+
return (a & 0x03) | ((b & 0x03) << 2) | ((c & 0x03) << 4);
674+
}
675+
664676
static NSVGparser* nsvg__createParser(void)
665677
{
666678
NSVGparser* p;
@@ -688,6 +700,7 @@ static NSVGparser* nsvg__createParser(void)
688700
p->attr[0].fillRule = NSVG_FILLRULE_NONZERO;
689701
p->attr[0].hasFill = 1;
690702
p->attr[0].visible = NSVG_VIS_DISPLAY | NSVG_VIS_VISIBLE;
703+
p->attr[0].paintOrder = nsvg__encodePaintOrder(NSVG_PAINT_FILL, NSVG_PAINT_STROKE, NSVG_PAINT_MARKERS);
691704

692705
return p;
693706

@@ -1032,6 +1045,7 @@ static void nsvg__addShape(NSVGparser* p)
10321045
shape->miterLimit = attr->miterLimit;
10331046
shape->fillRule = attr->fillRule;
10341047
shape->opacity = attr->opacity;
1048+
shape->paintOrder = attr->paintOrder;
10351049

10361050
shape->paths = p->plist;
10371051
p->plist = NULL;
@@ -1810,6 +1824,24 @@ static char nsvg__parseFillRule(const char* str)
18101824
return NSVG_FILLRULE_NONZERO;
18111825
}
18121826

1827+
static unsigned char nsvg__parsePaintOrder(const char* str)
1828+
{
1829+
if (strcmp(str, "normal") == 0 || strcmp(str, "fill stroke markers") == 0)
1830+
return nsvg__encodePaintOrder(NSVG_PAINT_FILL, NSVG_PAINT_STROKE, NSVG_PAINT_MARKERS);
1831+
else if (strcmp(str, "fill markers stroke") == 0)
1832+
return nsvg__encodePaintOrder(NSVG_PAINT_FILL, NSVG_PAINT_MARKERS, NSVG_PAINT_STROKE);
1833+
else if (strcmp(str, "markers fill stroke") == 0)
1834+
return nsvg__encodePaintOrder(NSVG_PAINT_MARKERS, NSVG_PAINT_FILL, NSVG_PAINT_STROKE);
1835+
else if (strcmp(str, "markers stroke fill") == 0)
1836+
return nsvg__encodePaintOrder(NSVG_PAINT_MARKERS, NSVG_PAINT_STROKE, NSVG_PAINT_FILL);
1837+
else if (strcmp(str, "stroke fill markers") == 0)
1838+
return nsvg__encodePaintOrder(NSVG_PAINT_STROKE, NSVG_PAINT_FILL, NSVG_PAINT_MARKERS);
1839+
else if (strcmp(str, "stroke markers fill") == 0)
1840+
return nsvg__encodePaintOrder(NSVG_PAINT_STROKE, NSVG_PAINT_MARKERS, NSVG_PAINT_FILL);
1841+
/* TODO: handle inherit. */
1842+
return nsvg__encodePaintOrder(NSVG_PAINT_FILL, NSVG_PAINT_STROKE, NSVG_PAINT_MARKERS);
1843+
}
1844+
18131845
static const char* nsvg__getNextDashItem(const char* s, char* it)
18141846
{
18151847
int n = 0;
@@ -1924,6 +1956,8 @@ static int nsvg__parseAttr(NSVGparser* p, const char* name, const char* value)
19241956
attr->stopOpacity = nsvg__parseOpacity(value);
19251957
} else if (strcmp(name, "offset") == 0) {
19261958
attr->stopOffset = nsvg__parseCoordinate(p, value, 0.0f, 1.0f);
1959+
} else if (strcmp(name, "paint-order") == 0) {
1960+
attr->paintOrder = nsvg__parsePaintOrder(value);
19271961
} else if (strcmp(name, "id") == 0) {
19281962
strncpy(attr->id, value, 63);
19291963
attr->id[63] = '\0';
@@ -2716,7 +2750,7 @@ static void nsvg__parseSVG(NSVGparser* p, const char** attr)
27162750
}
27172751
}
27182752

2719-
static void nsvg__parseGradient(NSVGparser* p, const char** attr, char type)
2753+
static void nsvg__parseGradient(NSVGparser* p, const char** attr, signed char type)
27202754
{
27212755
int i;
27222756
NSVGgradientData* grad = (NSVGgradientData*)NANOSVG_malloc(sizeof(NSVGgradientData));
@@ -3152,7 +3186,7 @@ NSVGimage* nsvgParse(char* input, const char* units, float dpi)
31523186

31533187
// Create gradients after all definitions have been parsed
31543188
nsvg__createGradients(p);
3155-
3189+
31563190
/* Scale to viewBox */
31573191
nsvg__scaleToViewbox(p, units);
31583192

generic/nanosvgrast.h

Lines changed: 54 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -971,7 +971,11 @@ static void nsvg__fillActiveEdges(unsigned char* scanline, int len, NSVGactiveEd
971971
}
972972
}
973973

974-
static float nsvg__clampf(float a, float mn, float mx) { return a < mn ? mn : (a > mx ? mx : a); }
974+
static float nsvg__clampf(float a, float mn, float mx) {
975+
if (isnan(a))
976+
return mn;
977+
return a < mn ? mn : (a > mx ? mx : a);
978+
}
975979

976980
static unsigned int nsvg__RGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
977981
{
@@ -1391,6 +1395,8 @@ void nsvgRasterize(NSVGrasterizer* r,
13911395
NSVGedge *e = NULL;
13921396
NSVGcachedPaint cache;
13931397
int i;
1398+
int j;
1399+
unsigned char paintOrder;
13941400

13951401
r->bitmap = dst;
13961402
r->width = w;
@@ -1409,58 +1415,61 @@ void nsvgRasterize(NSVGrasterizer* r,
14091415
for (shape = image->shapes; shape != NULL; shape = shape->next) {
14101416
if (!(shape->flags & NSVG_FLAGS_VISIBLE))
14111417
continue;
1418+
for (j = 0; j < 3; j++) {
1419+
paintOrder = (shape->paintOrder >> (2 * j)) & 0x03;
1420+
1421+
if (paintOrder == NSVG_PAINT_FILL && shape->fill.type != NSVG_PAINT_NONE) {
1422+
nsvg__resetPool(r);
1423+
r->freelist = NULL;
1424+
r->nedges = 0;
1425+
1426+
nsvg__flattenShape(r, shape, scale);
1427+
1428+
/* Scale and translate edges */
1429+
for (i = 0; i < r->nedges; i++) {
1430+
e = &r->edges[i];
1431+
e->x0 = tx + e->x0;
1432+
e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES;
1433+
e->x1 = tx + e->x1;
1434+
e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES;
1435+
}
14121436

1413-
if (shape->fill.type != NSVG_PAINT_NONE) {
1414-
nsvg__resetPool(r);
1415-
r->freelist = NULL;
1416-
r->nedges = 0;
1437+
/* Rasterize edges */
1438+
if (r->nedges != 0)
1439+
qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge);
14171440

1418-
nsvg__flattenShape(r, shape, scale);
1441+
/* now, traverse the scanlines and find the intersections on each scanline, use non-zero rule */
1442+
nsvg__initPaint(&cache, &shape->fill, shape->opacity);
14191443

1420-
/* Scale and translate edges */
1421-
for (i = 0; i < r->nedges; i++) {
1422-
e = &r->edges[i];
1423-
e->x0 = tx + e->x0;
1424-
e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES;
1425-
e->x1 = tx + e->x1;
1426-
e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES;
1444+
nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, shape->fillRule);
14271445
}
1446+
if (paintOrder == NSVG_PAINT_STROKE && shape->stroke.type != NSVG_PAINT_NONE && (shape->strokeWidth * scale) > 0.01f) {
1447+
nsvg__resetPool(r);
1448+
r->freelist = NULL;
1449+
r->nedges = 0;
1450+
1451+
nsvg__flattenShapeStroke(r, shape, scale);
1452+
1453+
/* dumpEdges(r, "edge.svg"); */
1454+
1455+
/* Scale and translate edges */
1456+
for (i = 0; i < r->nedges; i++) {
1457+
e = &r->edges[i];
1458+
e->x0 = tx + e->x0;
1459+
e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES;
1460+
e->x1 = tx + e->x1;
1461+
e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES;
1462+
}
14281463

1429-
/* Rasterize edges */
1430-
if (r->nedges != 0)
1431-
qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge);
1464+
/* Rasterize edges */
1465+
if (r->nedges != 0)
1466+
qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge);
14321467

1433-
/* now, traverse the scanlines and find the intersections on each scanline, use non-zero rule */
1434-
nsvg__initPaint(&cache, &shape->fill, shape->opacity);
1468+
/* now, traverse the scanlines and find the intersections on each scanline, use non-zero rule */
1469+
nsvg__initPaint(&cache, &shape->stroke, shape->opacity);
14351470

1436-
nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, shape->fillRule);
1437-
}
1438-
if (shape->stroke.type != NSVG_PAINT_NONE && (shape->strokeWidth * scale) > 0.01f) {
1439-
nsvg__resetPool(r);
1440-
r->freelist = NULL;
1441-
r->nedges = 0;
1442-
1443-
nsvg__flattenShapeStroke(r, shape, scale);
1444-
1445-
/* dumpEdges(r, "edge.svg"); */
1446-
1447-
/* Scale and translate edges */
1448-
for (i = 0; i < r->nedges; i++) {
1449-
e = &r->edges[i];
1450-
e->x0 = tx + e->x0;
1451-
e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES;
1452-
e->x1 = tx + e->x1;
1453-
e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES;
1471+
nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, NSVG_FILLRULE_NONZERO);
14541472
}
1455-
1456-
/* Rasterize edges */
1457-
if (r->nedges != 0)
1458-
qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge);
1459-
1460-
/* now, traverse the scanlines and find the intersections on each scanline, use non-zero rule */
1461-
nsvg__initPaint(&cache, &shape->stroke, shape->opacity);
1462-
1463-
nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, NSVG_FILLRULE_NONZERO);
14641473
}
14651474
}
14661475

0 commit comments

Comments
 (0)