svg_loader: fix vector memory leaks.

vector is designed for c++ syntaxes,
it works properly when c++ memory allocator is applied,

Here svg_loader uses c style structures which allocated using malloc()/calloc().
That brings the memory broken of stl vectors.

So, we replaced it with our customized SvgVector to easily fix it.
This commit is contained in:
Hermet Park 2020-09-01 20:13:07 +09:00 committed by Hermet Park
parent 6bd56e26c7
commit 6f962151b4
3 changed files with 107 additions and 67 deletions

View file

@ -944,7 +944,7 @@ static SvgNode* _createNode(SvgNode* parent, SvgNodeType type)
node->parent = parent; node->parent = parent;
node->type = type; node->type = type;
if (parent) parent->child.push_back(node); if (parent) parent->child.push(node);
return node; return node;
} }
@ -1334,22 +1334,22 @@ static SvgNode* _getDefsNode(SvgNode* node)
static SvgNode* _findChildById(SvgNode* node, const char* id) static SvgNode* _findChildById(SvgNode* node, const char* id)
{ {
if (!node) return nullptr; if (!node) return nullptr;
for (vector<SvgNode*>::iterator itrChild = node->child.begin(); itrChild != node->child.end(); itrChild++) { auto child = node->child.list;
if (((*itrChild)->id != nullptr) && !strcmp((*itrChild)->id->c_str(), id)) return *itrChild; for (uint32_t i = 0; i < node->child.cnt; ++i, ++child) {
if (((*child)->id != nullptr) && !strcmp((*child)->id->c_str(), id)) return (*child);
} }
return nullptr; return nullptr;
} }
static void _cloneGradStops(vector<Fill::ColorStop*> *dst, vector<Fill::ColorStop*> src) static void _cloneGradStops(SvgVector<Fill::ColorStop*>* dst, SvgVector<Fill::ColorStop*>* src)
{ {
for (auto colorStop : src) { for (uint32_t i = 0; i < src->cnt; ++i) {
auto stop = static_cast<Fill::ColorStop *>(malloc(sizeof(Fill::ColorStop))); auto stop = static_cast<Fill::ColorStop *>(malloc(sizeof(Fill::ColorStop)));
*stop = *colorStop; *stop = *src->list[i];
dst->push_back(stop); dst->push(stop);
} }
} }
@ -1379,7 +1379,7 @@ static SvgStyleGradient* _cloneGradient(SvgStyleGradient* from)
memcpy(grad->radial, from->radial, sizeof(SvgRadialGradient)); memcpy(grad->radial, from->radial, sizeof(SvgRadialGradient));
} }
_cloneGradStops(&(grad->stops), from->stops); _cloneGradStops(&grad->stops, &from->stops);
return grad; return grad;
} }
@ -1454,8 +1454,9 @@ static void _cloneNode(SvgNode* from, SvgNode* parent)
newNode = _createNode(parent, from->type); newNode = _createNode(parent, from->type);
_copyAttr(newNode, from); _copyAttr(newNode, from);
for (auto child : from->child) { auto child = from->child.list;
_cloneNode(child, newNode); for (uint32_t i = 0; i < from->child.cnt; ++i, ++child) {
_cloneNode(*child, newNode);
} }
_freeNode(newNode); _freeNode(newNode);
@ -1907,7 +1908,7 @@ static void _svgLoaderParerXmlClose(SvgLoaderData* loader, const char* content)
for (i = 0; i < sizeof(popArray) / sizeof(popArray[0]); i++) { for (i = 0; i < sizeof(popArray) / sizeof(popArray[0]); i++) {
if (!strncmp(content, popArray[i].tag, popArray[i].sz - 1)) { if (!strncmp(content, popArray[i].tag, popArray[i].sz - 1)) {
loader->stack.pop_back(); loader->stack.pop();
break; break;
} }
} }
@ -1951,17 +1952,17 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content,
loader->doc = node; loader->doc = node;
} else { } else {
if (!strcmp(tagName, "svg")) return; //Already loadded <svg>(SvgNodeType::Doc) tag if (!strcmp(tagName, "svg")) return; //Already loadded <svg>(SvgNodeType::Doc) tag
if (loader->stack.size() > 0) parent = loader->stack.at(loader->stack.size() - 1); if (loader->stack.cnt > 0) parent = loader->stack.list[loader->stack.cnt - 1];
node = method(loader, parent, attrs, attrsLength); node = method(loader, parent, attrs, attrsLength);
} }
loader->stack.push_back(node); loader->stack.push(node);
if (node->type == SvgNodeType::Defs) { if (node->type == SvgNodeType::Defs) {
loader->doc->node.doc.defs = node; loader->doc->node.doc.defs = node;
loader->def = node; loader->def = node;
} }
} else if ((method = _findGraphicsFactory(tagName))) { } else if ((method = _findGraphicsFactory(tagName))) {
parent = loader->stack.at(loader->stack.size() - 1); parent = loader->stack.list[loader->stack.cnt - 1];
node = method(loader, parent, attrs, attrsLength); node = method(loader, parent, attrs, attrsLength);
} else if ((gradientMethod = _findGradientFactory(tagName))) { } else if ((gradientMethod = _findGradientFactory(tagName))) {
SvgStyleGradient* gradient; SvgStyleGradient* gradient;
@ -1973,9 +1974,9 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content,
// This is only to support this when multiple gradients are declared, even if no defs are declared. // This is only to support this when multiple gradients are declared, even if no defs are declared.
// refer to: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/defs // refer to: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/defs
if (loader->doc->node.doc.defs) { if (loader->doc->node.doc.defs) {
loader->def->node.defs.gradients.push_back(gradient); loader->def->node.defs.gradients.push(gradient);
} else { } else {
loader->gradients.push_back(gradient); loader->gradients.push(gradient);
} }
loader->latestGradient = gradient; loader->latestGradient = gradient;
} else if (!strcmp(tagName, "stop")) { } else if (!strcmp(tagName, "stop")) {
@ -1985,7 +1986,7 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content,
stop->a = 255; stop->a = 255;
simpleXmlParseAttributes(attrs, attrsLength, _attrParseStops, loader); simpleXmlParseAttributes(attrs, attrsLength, _attrParseStops, loader);
if (loader->latestGradient) { if (loader->latestGradient) {
loader->latestGradient->stops.push_back(stop); loader->latestGradient->stops.push(stop);
} }
} }
} }
@ -2074,32 +2075,38 @@ static void _updateStyle(SvgNode* node, SvgStyleProperty* parentStyle)
{ {
_styleInherit(node->style, parentStyle); _styleInherit(node->style, parentStyle);
for (vector<SvgNode*>::iterator itrChild = node->child.begin(); itrChild != node->child.end(); itrChild++) { auto child = node->child.list;
_updateStyle(*itrChild, node->style); for (uint32_t i = 0; i < node->child.cnt; ++i, ++child) {
_updateStyle(*child, node->style);
} }
} }
static SvgStyleGradient* _gradientDup(vector<SvgStyleGradient*> gradList, string* id) static SvgStyleGradient* _gradientDup(SvgVector<SvgStyleGradient*>* gradients, string* id)
{ {
SvgStyleGradient* result = nullptr; SvgStyleGradient* result = nullptr;
for (vector<SvgStyleGradient*>::iterator itrGrad = gradList.begin(); itrGrad != gradList.end(); itrGrad++) { auto gradList = gradients->list;
if (!((*itrGrad)->id->compare(*id))) {
result = _cloneGradient(*itrGrad); for (uint32_t i = 0; i < gradients->cnt; ++i) {
if (!((*gradList)->id->compare(*id))) {
result = _cloneGradient(*gradList);
break; break;
} }
++gradList;
} }
if (result && result->ref) { if (result && result->ref) {
for (vector<SvgStyleGradient*>::iterator itrGrad = gradList.begin(); itrGrad != gradList.end(); itrGrad++) { gradList = gradients->list;
if (!((*itrGrad)->id->compare(*result->ref))) { for (uint32_t i = 0; i < gradients->cnt; ++i) {
if (!result->stops.empty()) { if (!((*gradList)->id->compare(*result->ref))) {
_cloneGradStops(&(result->stops), (*itrGrad)->stops); if (result->stops.cnt > 0) {
_cloneGradStops(&result->stops, &(*gradList)->stops);
} }
//TODO: Properly inherit other property //TODO: Properly inherit other property
break; break;
} }
++gradList;
} }
} }
@ -2107,15 +2114,16 @@ static SvgStyleGradient* _gradientDup(vector<SvgStyleGradient*> gradList, string
} }
static void _updateGradient(SvgNode* node, vector<SvgStyleGradient*> gradList) static void _updateGradient(SvgNode* node, SvgVector<SvgStyleGradient*>* gradidents)
{ {
if (!node->child.empty()) { if (node->child.cnt > 0) {
for (vector<SvgNode*>::iterator itrChild = node->child.begin(); itrChild != node->child.end(); itrChild++) { auto child = node->child.list;
_updateGradient(*itrChild, gradList); for (uint32_t i = 0; i < node->child.cnt; ++i, ++child) {
_updateGradient(*child, gradidents);
} }
} else { } else {
if (node->style->fill.paint.url) { if (node->style->fill.paint.url) {
node->style->fill.paint.gradient = _gradientDup(gradList, node->style->fill.paint.url); node->style->fill.paint.gradient = _gradientDup(gradidents, node->style->fill.paint.url);
} else if (node->style->stroke.paint.url) { } else if (node->style->stroke.paint.url) {
//node->style->stroke.paint.gradient = _gradientDup(gradList, node->style->stroke.paint.url); //node->style->stroke.paint.gradient = _gradientDup(gradList, node->style->stroke.paint.url);
} }
@ -2132,8 +2140,11 @@ static void _freeGradientStyle(SvgStyleGradient* grad)
free(grad->linear); free(grad->linear);
if (grad->transform) free(grad->transform); if (grad->transform) free(grad->transform);
for (auto colorStop : grad->stops) free(colorStop); for (uint32_t i = 0; i < grad->stops.cnt; ++i) {
auto colorStop = grad->stops.list[i];
free(colorStop);
}
grad->stops.clear();
free(grad); free(grad);
} }
@ -2152,8 +2163,9 @@ static void _freeNode(SvgNode* node)
{ {
if (!node) return; if (!node) return;
for(auto child : node->child) { auto child = node->child.list;
_freeNode(child); for (uint32_t i = 0; i < node->child.cnt; ++i, ++child) {
_freeNode(*child);
} }
node->child.clear(); node->child.clear();
@ -2178,9 +2190,12 @@ static void _freeNode(SvgNode* node)
break; break;
} }
case SvgNodeType::Defs: { case SvgNodeType::Defs: {
for(vector<SvgStyleGradient*>::iterator itrGrad = node->node.defs.gradients.begin(); itrGrad != node->node.defs.gradients.end(); itrGrad++) { auto gradients = node->node.defs.gradients.list;
_freeGradientStyle(*itrGrad); for (size_t i = 0; i < node->node.defs.gradients.cnt; ++i) {
_freeGradientStyle(*gradients);
++gradients;
} }
node->node.defs.gradients.clear();
break; break;
} }
default: { default: {
@ -2221,7 +2236,7 @@ static bool _svgLoaderParserForValidCheckXmlOpen(SvgLoaderData* loader, const ch
if (strcmp(tagName, "svg")) return true; //Not a valid svg document if (strcmp(tagName, "svg")) return true; //Not a valid svg document
node = method(loader, nullptr, attrs, attrsLength); node = method(loader, nullptr, attrs, attrsLength);
loader->doc = node; loader->doc = node;
loader->stack.push_back(node); loader->stack.push(node);
return false; return false;
} }
} }
@ -2257,15 +2272,10 @@ void SvgTask::run()
if (loader->loaderData.doc) { if (loader->loaderData.doc) {
_updateStyle(loader->loaderData.doc, nullptr); _updateStyle(loader->loaderData.doc, nullptr);
auto defs = loader->loaderData.doc->node.doc.defs; auto defs = loader->loaderData.doc->node.doc.defs;
if (defs) _updateGradient(loader->loaderData.doc, defs->node.defs.gradients); if (defs) _updateGradient(loader->loaderData.doc, &defs->node.defs.gradients);
else { else {
if (!loader->loaderData.gradients.empty()) { if (loader->loaderData.gradients.cnt > 0) {
vector<SvgStyleGradient*> gradientList; _updateGradient(loader->loaderData.doc, &loader->loaderData.gradients);
for (auto gradient : loader->loaderData.gradients) {
gradientList.push_back(gradient);
}
_updateGradient(loader->loaderData.doc, gradientList);
gradientList.clear();
} }
} }
} }
@ -2368,6 +2378,7 @@ bool SvgLoader::close()
} }
_freeNode(loaderData.doc); _freeNode(loaderData.doc);
loaderData.doc = nullptr; loaderData.doc = nullptr;
loaderData.stack.clear();
return true; return true;
} }

View file

@ -119,6 +119,35 @@ enum class SvgParserLengthType
struct SvgNode; struct SvgNode;
struct SvgStyleGradient; struct SvgStyleGradient;
template<class T>
struct SvgVector
{
T* list;
uint32_t cnt;
uint32_t reserved;
void push(T element)
{
if (cnt + 1 > reserved) {
reserved = (cnt + 1) * 2;
list = static_cast<T*>(realloc(list, sizeof(T) * reserved));
}
list[cnt++] = element;
}
void pop()
{
if (cnt > 0) --cnt;
}
void clear()
{
if (list) free(list);
list = nullptr;
cnt = reserved = 0;
}
};
struct SvgDocNode struct SvgDocNode
{ {
float w; float w;
@ -137,7 +166,7 @@ struct SvgGNode
struct SvgDefsNode struct SvgDefsNode
{ {
vector<SvgStyleGradient *> gradients; SvgVector<SvgStyleGradient*> gradients;
}; };
struct SvgArcNode struct SvgArcNode
@ -240,7 +269,7 @@ struct SvgStyleGradient
SvgRadialGradient* radial; SvgRadialGradient* radial;
SvgLinearGradient* linear; SvgLinearGradient* linear;
Matrix* transform; Matrix* transform;
vector<Fill::ColorStop *> stops; SvgVector<Fill::ColorStop *> stops;
bool userSpace; bool userSpace;
bool usePercentage; bool usePercentage;
}; };
@ -281,7 +310,7 @@ struct SvgNode
{ {
SvgNodeType type; SvgNodeType type;
SvgNode* parent; SvgNode* parent;
vector<SvgNode*> child; SvgVector<SvgNode*> child;
string *id; string *id;
SvgStyleProperty *style; SvgStyleProperty *style;
Matrix* transform; Matrix* transform;
@ -320,10 +349,10 @@ struct SvgParser
struct SvgLoaderData struct SvgLoaderData
{ {
vector<SvgNode *> stack; SvgVector<SvgNode *> stack = {nullptr, 0, 0};
SvgNode* doc = nullptr; SvgNode* doc = nullptr;
SvgNode* def = nullptr; SvgNode* def = nullptr;
vector<SvgStyleGradient*> gradients; SvgVector<SvgStyleGradient*> gradients;
SvgStyleGradient* latestGradient = nullptr; //For stops SvgStyleGradient* latestGradient = nullptr; //For stops
SvgParser* svgParse = nullptr; SvgParser* svgParse = nullptr;
int level = 0; int level = 0;

View file

@ -93,13 +93,13 @@ unique_ptr<LinearGradient> _applyLinearGradientProperty(SvgStyleGradient* g, Sha
fillGrad->spread(g->spread); fillGrad->spread(g->spread);
//Update the stops //Update the stops
stopCount = g->stops.size(); stopCount = g->stops.cnt;
if (stopCount > 0) { if (stopCount > 0) {
float opacity; float opacity;
float fopacity = fillOpacity / 255.0f; //fill opacity if any exists. float fopacity = fillOpacity / 255.0f; //fill opacity if any exists.
int i = 0;
stops = (Fill::ColorStop*)calloc(stopCount, sizeof(Fill::ColorStop)); stops = (Fill::ColorStop*)calloc(stopCount, sizeof(Fill::ColorStop));
for (auto colorStop : g->stops) { for (uint32_t i = 0; i < g->stops.cnt; ++i) {
auto colorStop = g->stops.list[i];
//Use premultiplied color //Use premultiplied color
opacity = ((float)colorStop->a / 255.0f) * fopacity; opacity = ((float)colorStop->a / 255.0f) * fopacity;
stops[i].r = colorStop->r * opacity; stops[i].r = colorStop->r * opacity;
@ -107,7 +107,6 @@ unique_ptr<LinearGradient> _applyLinearGradientProperty(SvgStyleGradient* g, Sha
stops[i].b = colorStop->b * opacity; stops[i].b = colorStop->b * opacity;
stops[i].a = colorStop->a * fopacity; stops[i].a = colorStop->a * fopacity;
stops[i].offset = colorStop->offset; stops[i].offset = colorStop->offset;
i++;
} }
fillGrad->colorStops(stops, stopCount); fillGrad->colorStops(stops, stopCount);
free(stops); free(stops);
@ -179,13 +178,13 @@ unique_ptr<RadialGradient> _applyRadialGradientProperty(SvgStyleGradient* g, Sha
fillGrad->spread(g->spread); fillGrad->spread(g->spread);
//Update the stops //Update the stops
stopCount = g->stops.size(); stopCount = g->stops.cnt;
if (stopCount > 0) { if (stopCount > 0) {
float opacity; float opacity;
float fopacity = fillOpacity / 255.0f; //fill opacity if any exists. float fopacity = fillOpacity / 255.0f; //fill opacity if any exists.
int i = 0;
stops = (Fill::ColorStop*)calloc(stopCount, sizeof(Fill::ColorStop)); stops = (Fill::ColorStop*)calloc(stopCount, sizeof(Fill::ColorStop));
for (auto colorStop : g->stops) { for (uint32_t i = 0; i < g->stops.cnt; ++i) {
auto colorStop = g->stops.list[i];
//Use premultiplied color //Use premultiplied color
opacity = ((float)colorStop->a / 255.0f) * fopacity; opacity = ((float)colorStop->a / 255.0f) * fopacity;
stops[i].r = colorStop->r * opacity; stops[i].r = colorStop->r * opacity;
@ -193,7 +192,6 @@ unique_ptr<RadialGradient> _applyRadialGradientProperty(SvgStyleGradient* g, Sha
stops[i].b = colorStop->b * opacity; stops[i].b = colorStop->b * opacity;
stops[i].a = colorStop->a * fopacity; stops[i].a = colorStop->a * fopacity;
stops[i].offset = colorStop->offset; stops[i].offset = colorStop->offset;
i++;
} }
fillGrad->colorStops(stops, stopCount); fillGrad->colorStops(stops, stopCount);
free(stops); free(stops);
@ -335,11 +333,13 @@ unique_ptr<Scene> _sceneBuildHelper(SvgNode* node, float vx, float vy, float vw,
if (node->transform) scene->transform(*node->transform); if (node->transform) scene->transform(*node->transform);
node->style->opacity = (node->style->opacity * parentOpacity) / 255.0f; node->style->opacity = (node->style->opacity * parentOpacity) / 255.0f;
if (node->display) { if (node->display) {
for (auto child : node->child) { auto child = node->child.list;
if (child->type == SvgNodeType::Doc || child->type == SvgNodeType::G) scene->push(_sceneBuildHelper(child, vx, vy, vw, vh, node->style->opacity)); for (uint32_t i = 0; i < node->child.cnt; ++i, ++child) {
else { if ((*child)->type == SvgNodeType::Doc || (*child)->type == SvgNodeType::G) {
child->style->opacity = (child->style->opacity * node->style->opacity) / 255.0f; scene->push(_sceneBuildHelper(*child, vx, vy, vw, vh, node->style->opacity));
scene->push(_shapeBuildHelper(child, vx, vy, vw, vh)); } else {
(*child)->style->opacity = ((*child)->style->opacity * node->style->opacity) / 255.0f;
scene->push(_shapeBuildHelper(*child, vx, vy, vw, vh));
} }
} }
} }