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

View file

@ -119,6 +119,35 @@ enum class SvgParserLengthType
struct SvgNode;
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
{
float w;
@ -137,7 +166,7 @@ struct SvgGNode
struct SvgDefsNode
{
vector<SvgStyleGradient *> gradients;
SvgVector<SvgStyleGradient*> gradients;
};
struct SvgArcNode
@ -240,7 +269,7 @@ struct SvgStyleGradient
SvgRadialGradient* radial;
SvgLinearGradient* linear;
Matrix* transform;
vector<Fill::ColorStop *> stops;
SvgVector<Fill::ColorStop *> stops;
bool userSpace;
bool usePercentage;
};
@ -281,7 +310,7 @@ struct SvgNode
{
SvgNodeType type;
SvgNode* parent;
vector<SvgNode*> child;
SvgVector<SvgNode*> child;
string *id;
SvgStyleProperty *style;
Matrix* transform;
@ -320,10 +349,10 @@ struct SvgParser
struct SvgLoaderData
{
vector<SvgNode *> stack;
SvgVector<SvgNode *> stack = {nullptr, 0, 0};
SvgNode* doc = nullptr;
SvgNode* def = nullptr;
vector<SvgStyleGradient*> gradients;
SvgVector<SvgStyleGradient*> gradients;
SvgStyleGradient* latestGradient = nullptr; //For stops
SvgParser* svgParse = nullptr;
int level = 0;

View file

@ -93,13 +93,13 @@ unique_ptr<LinearGradient> _applyLinearGradientProperty(SvgStyleGradient* g, Sha
fillGrad->spread(g->spread);
//Update the stops
stopCount = g->stops.size();
stopCount = g->stops.cnt;
if (stopCount > 0) {
float opacity;
float fopacity = fillOpacity / 255.0f; //fill opacity if any exists.
int i = 0;
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
opacity = ((float)colorStop->a / 255.0f) * fopacity;
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].a = colorStop->a * fopacity;
stops[i].offset = colorStop->offset;
i++;
}
fillGrad->colorStops(stops, stopCount);
free(stops);
@ -179,13 +178,13 @@ unique_ptr<RadialGradient> _applyRadialGradientProperty(SvgStyleGradient* g, Sha
fillGrad->spread(g->spread);
//Update the stops
stopCount = g->stops.size();
stopCount = g->stops.cnt;
if (stopCount > 0) {
float opacity;
float fopacity = fillOpacity / 255.0f; //fill opacity if any exists.
int i = 0;
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
opacity = ((float)colorStop->a / 255.0f) * fopacity;
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].a = colorStop->a * fopacity;
stops[i].offset = colorStop->offset;
i++;
}
fillGrad->colorStops(stops, stopCount);
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);
node->style->opacity = (node->style->opacity * parentOpacity) / 255.0f;
if (node->display) {
for (auto child : node->child) {
if (child->type == SvgNodeType::Doc || child->type == SvgNodeType::G) scene->push(_sceneBuildHelper(child, vx, vy, vw, vh, node->style->opacity));
else {
child->style->opacity = (child->style->opacity * node->style->opacity) / 255.0f;
scene->push(_shapeBuildHelper(child, vx, vy, vw, vh));
auto child = node->child.list;
for (uint32_t i = 0; i < node->child.cnt; ++i, ++child) {
if ((*child)->type == SvgNodeType::Doc || (*child)->type == SvgNodeType::G) {
scene->push(_sceneBuildHelper(*child, vx, vy, vw, vh, node->style->opacity));
} else {
(*child)->style->opacity = ((*child)->style->opacity * node->style->opacity) / 255.0f;
scene->push(_shapeBuildHelper(*child, vx, vy, vw, vh));
}
}
}