Skip to content

Commit

Permalink
Add support for MathJax equations in nanosvg
Browse files Browse the repository at this point in the history
Allows Dillo to render Wikipedia math equations.
  • Loading branch information
rodarima committed Jul 6, 2024
1 parent bb0f4ac commit d77177b
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 3 deletions.
77 changes: 76 additions & 1 deletion src/nanosvg.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2013-14 Mikko Mononen [email protected]
* Copyright (c) 2013-14 Mikko Mononen <[email protected]>
* Copyright (c) 2024 Rodrigo Arias Mallo <[email protected]>
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
Expand Down Expand Up @@ -148,6 +149,7 @@ typedef struct NSVGshape
char strokeDashCount; // Number of dash values in dash array.
char strokeLineJoin; // Stroke join type.
char strokeLineCap; // Stroke cap type.
char virtual; // A shape from <defs> not to be drawn
float miterLimit; // Miter limit
char fillRule; // Fill rule, see NSVGfillRule.
unsigned char flags; // Logical or of NSVG_FLAGS_* flags
Expand Down Expand Up @@ -641,6 +643,8 @@ static NSVGparser* nsvg__createParser(void)
p->attr[0].fillRule = NSVG_FILLRULE_NONZERO;
p->attr[0].hasFill = 1;
p->attr[0].visible = 1;
/* TODO: Let the user change the initial value */
p->attr[0].fontSize = 40.0f;

return p;

Expand Down Expand Up @@ -972,6 +976,7 @@ static void nsvg__addShape(NSVGparser* p)
shape->miterLimit = attr->miterLimit;
shape->fillRule = attr->fillRule;
shape->opacity = attr->opacity;
shape->virtual = p->defsFlag;

shape->paths = p->plist;
p->plist = NULL;
Expand Down Expand Up @@ -1803,6 +1808,9 @@ static int nsvg__parseAttr(NSVGparser* p, const char* name, const char* value)
} else if (strncmp(value, "url(", 4) == 0) {
attr->hasFill = 2;
nsvg__parseUrl(attr->fillGradient, value);
} else if (strncmp(value, "currentColor", 12) == 0) {
attr->hasFill = 1;
attr->fillColor = 0; /* TODO: Black by default */
} else {
attr->hasFill = 1;
attr->fillColor = nsvg__parseColor(value);
Expand All @@ -1817,6 +1825,9 @@ static int nsvg__parseAttr(NSVGparser* p, const char* name, const char* value)
} else if (strncmp(value, "url(", 4) == 0) {
attr->hasStroke = 2;
nsvg__parseUrl(attr->strokeGradient, value);
} else if (strncmp(value, "currentColor", 12) == 0) {
attr->hasStroke = 1;
attr->strokeColor = 0; /* TODO: Black by default */
} else {
attr->hasStroke = 1;
attr->strokeColor = nsvg__parseColor(value);
Expand Down Expand Up @@ -2463,6 +2474,56 @@ static void nsvg__parseRect(NSVGparser* p, const char** attr)
}
}

static void nsvg__parseUse(NSVGparser* p, const char** attr)
{
const char *href = NULL;
float x0 = 0.0f;
float y0 = 0.0f;
int i;

for (i = 0; attr[i]; i += 2) {
if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
if (strcmp(attr[i], "xlink:href") == 0)
href = attr[i+1];
else if (strcmp(attr[i], "x") == 0)
x0 = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p));
else if (strcmp(attr[i], "y") == 0)
y0 = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p));
}
}

/* Only hrefs starting with # */
if (!href || href[0] != '#')
return;

/* Skip initial # */
href++;

/* Maybe use a hash table indexed with the id to speed up the search */
NSVGshape* shape = NULL;
for (shape = p->image->shapes; shape != NULL; shape = shape->next) {
if (strcmp(shape->id, href) == 0)
break;
}

/* Not found */
if (!shape)
return;

/* Read all points from the defined shape and create a new shape */
for (NSVGpath *path = shape->paths; path; path = path->next) {
nsvg__resetPath(p);
for (int i = 0; i < path->npts; i++) {
float x = path->pts[i*2+0];
float y = path->pts[i*2+1];
nsvg__addPoint(p, x + x0, y + y0);
}
nsvg__addPath(p, path->closed);
}

nsvg__addShape(p);
}

static void nsvg__parseCircle(NSVGparser* p, const char** attr)
{
float cx = 0.0f;
Expand Down Expand Up @@ -2768,13 +2829,21 @@ static void nsvg__startElement(void* ud, const char* el, const char** attr)
nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT);
} else if (strcmp(el, "stop") == 0) {
nsvg__parseGradientStop(p, attr);
} else if (strcmp(el, "path") == 0) {
nsvg__pushAttr(p);
nsvg__parsePath(p, attr);
nsvg__popAttr(p);
}
return;
}

if (strcmp(el, "g") == 0) {
nsvg__pushAttr(p);
nsvg__parseAttribs(p, attr);
} else if (strcmp(el, "use") == 0) {
nsvg__pushAttr(p);
nsvg__parseUse(p, attr);
nsvg__popAttr(p);
} else if (strcmp(el, "path") == 0) {
if (p->pathFlag) // Do not allow nested paths.
return;
Expand Down Expand Up @@ -2935,6 +3004,9 @@ static void nsvg__scaleToViewbox(NSVGparser* p, const char* units)
sy *= us;
avgs = (sx+sy) / 2.0f;
for (shape = p->image->shapes; shape != NULL; shape = shape->next) {
if (shape->virtual)
continue;

shape->bounds[0] = (shape->bounds[0] + tx) * sx;
shape->bounds[1] = (shape->bounds[1] + ty) * sy;
shape->bounds[2] = (shape->bounds[2] + tx) * sx;
Expand Down Expand Up @@ -2974,6 +3046,9 @@ static void nsvg__createGradients(NSVGparser* p)
NSVGshape* shape;

for (shape = p->image->shapes; shape != NULL; shape = shape->next) {
if (shape->virtual)
continue;

if (shape->fill.type == NSVG_PAINT_UNDEF) {
if (shape->fillGradient[0] != '\0') {
float inv[6], localBounds[4];
Expand Down
5 changes: 3 additions & 2 deletions src/nanosvgrast.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2013-14 Mikko Mononen [email protected]
* Copyright (c) 2013-14 Mikko Mononen <[email protected]>
* Copyright (c) 2024 Rodrigo Arias Mallo <[email protected]>
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
Expand Down Expand Up @@ -1406,7 +1407,7 @@ void nsvgRasterizeXY(NSVGrasterizer* r,
memset(&dst[i*stride], 0, w*4);

for (shape = image->shapes; shape != NULL; shape = shape->next) {
if (!(shape->flags & NSVG_FLAGS_VISIBLE))
if (!(shape->flags & NSVG_FLAGS_VISIBLE) || shape->virtual)
continue;

if (shape->fill.type != NSVG_PAINT_NONE) {
Expand Down

0 comments on commit d77177b

Please sign in to comment.