svg_loader: postpone cloneNode()

Some svg export software puts <defs> element at the end of the file.
If so, the <defs> element won't be found, when parsing <use>.
In such scenario, this patch postpone node cloning until the whole file
is parsed.

@issue: #568
This commit is contained in:
Michal Maciola 2021-07-07 08:34:15 +02:00 committed by GitHub
parent 90a8c9d197
commit bb19bcf64f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 37 additions and 2 deletions

View file

@ -1715,6 +1715,25 @@ static void _cloneNode(SvgNode* from, SvgNode* parent)
}
static void _postponeCloneNode(SvgLoaderData* loader, SvgNode *node, string* id) {
SvgNodeIdPair nodeIdPair;
nodeIdPair.node = node;
nodeIdPair.id = id;
loader->cloneNodes.push(nodeIdPair);
}
static void _clonePostponedNodes(Array<SvgNodeIdPair>* cloneNodes) {
for (uint32_t i = 0; i < cloneNodes->count; ++i) {
SvgNodeIdPair nodeIdPair = cloneNodes->data[i];
SvgNode *defs = _getDefsNode(nodeIdPair.node);
SvgNode *nodeFrom = _findChildById(defs, nodeIdPair.id->c_str());
_cloneNode(nodeFrom, nodeIdPair.node);
delete nodeIdPair.id;
}
}
static bool _attrParseUseNode(void* data, const char* key, const char* value)
{
SvgLoaderData* loader = (SvgLoaderData*)data;
@ -1725,8 +1744,15 @@ static bool _attrParseUseNode(void* data, const char* key, const char* value)
id = _idFromHref(value);
defs = _getDefsNode(node);
nodeFrom = _findChildById(defs, id->c_str());
_cloneNode(nodeFrom, node);
delete id;
if (nodeFrom) {
_cloneNode(nodeFrom, node);
delete id;
} else {
//some svg export software include <defs> element at the end of the file
//if so the 'from' element won't be found now and we have to repeat finding
//after the whole file is parsed
_postponeCloneNode(loader, node, id);
}
} else if (!strcmp(key, "clip-path")) {
_handleClipPathAttr(loader, node, value);
} else if (!strcmp(key, "mask")) {
@ -2682,6 +2708,8 @@ void SvgLoader::run(unsigned tid)
_updateComposite(loaderData.doc, loaderData.doc);
if (defs) _updateComposite(loaderData.doc, defs);
if (loaderData.cloneNodes.count > 0) _clonePostponedNodes(&loaderData.cloneNodes);
}
root = svgSceneBuild(loaderData.doc, vx, vy, vw, vh);
};

View file

@ -333,6 +333,12 @@ struct SvgParser
} gradient;
};
struct SvgNodeIdPair
{
SvgNode* node;
string *id;
};
struct SvgLoaderData
{
Array<SvgNode *> stack = {nullptr, 0, 0};
@ -341,6 +347,7 @@ struct SvgLoaderData
Array<SvgStyleGradient*> gradients;
SvgStyleGradient* latestGradient = nullptr; //For stops
SvgParser* svgParse = nullptr;
Array<SvgNodeIdPair> cloneNodes;
int level = 0;
bool result = false;
};