From fdebb15dcb82b6153cf6ee884e5a05bd20d82ef8 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Thu, 21 Mar 2024 20:22:55 +0900 Subject: [PATCH] loader/svg: Check whether href id of use is parent or not MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When finding the 'nodeFrom' referenced by ``, if it is the parent, it is not referenced. https://www.w3.org/TR/SVG2/struct.html#UseElement Specification: If the referenced element is a (shadow-including) ancestor of the ‘use’ element, then this is an invalid circular reference and the ‘use’ element is in error. related issue: https://github.com/thorvg/thorvg/issues/2078 SVG_FILE_65171.svg SVG_FILE_65172.svg --- src/loaders/svg/tvgSvgLoader.cpp | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index e9cd3bc1..79530d3c 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -1919,6 +1919,19 @@ static SvgNode* _findNodeById(SvgNode *node, const char* id) } +static SvgNode* _findParentById(SvgNode* node, char* id, SvgNode* doc) +{ + SvgNode *parent = node->parent; + while (parent != nullptr && parent != doc) { + if (parent->id && !strcmp(parent->id, id)) { + return parent; + } + parent = parent->parent; + } + return nullptr; +} + + static constexpr struct { const char* tag; @@ -1959,8 +1972,12 @@ static bool _attrParseUseNode(void* data, const char* key, const char* value) defs = _getDefsNode(node); nodeFrom = _findNodeById(defs, id); if (nodeFrom) { - _cloneNode(nodeFrom, node, 0); - if (nodeFrom->type == SvgNodeType::Symbol) use->symbol = nodeFrom; + if (!_findParentById(node, id, loader->doc)) { + _cloneNode(nodeFrom, node, 0); + if (nodeFrom->type == SvgNodeType::Symbol) use->symbol = nodeFrom; + } else { + TVGLOG("SVG", "%s is ancestor element. This reference is invalid.", id); + } free(id); } else { //some svg export software include element at the end of the file @@ -3024,9 +3041,13 @@ static void _clonePostponedNodes(Array* cloneNodes, SvgNode* doc) auto defs = _getDefsNode(nodeIdPair.node); auto nodeFrom = _findNodeById(defs, nodeIdPair.id); if (!nodeFrom) nodeFrom = _findNodeById(doc, nodeIdPair.id); - _cloneNode(nodeFrom, nodeIdPair.node, 0); - if (nodeFrom && nodeFrom->type == SvgNodeType::Symbol && nodeIdPair.node->type == SvgNodeType::Use) { - nodeIdPair.node->node.use.symbol = nodeFrom; + if (!_findParentById(nodeIdPair.node, nodeIdPair.id, doc)) { + _cloneNode(nodeFrom, nodeIdPair.node, 0); + if (nodeFrom && nodeFrom->type == SvgNodeType::Symbol && nodeIdPair.node->type == SvgNodeType::Use) { + nodeIdPair.node->node.use.symbol = nodeFrom; + } + } else { + TVGLOG("SVG", "%s is ancestor element. This reference is invalid.", nodeIdPair.id); } free(nodeIdPair.id); }