diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 696d565d..b4eef8a7 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -1818,12 +1818,36 @@ static void _clonePostponedNodes(Array* cloneNodes) { } +static constexpr struct +{ + const char* tag; + SvgParserLengthType type; + int sz; + size_t offset; +} useTags[] = { + {"x", SvgParserLengthType::Horizontal, sizeof("x"), offsetof(SvgRectNode, x)}, + {"y", SvgParserLengthType::Vertical, sizeof("y"), offsetof(SvgRectNode, y)}, + {"width", SvgParserLengthType::Horizontal, sizeof("width"), offsetof(SvgRectNode, w)}, + {"height", SvgParserLengthType::Vertical, sizeof("height"), offsetof(SvgRectNode, h)} +}; + + static bool _attrParseUseNode(void* data, const char* key, const char* value) { SvgLoaderData* loader = (SvgLoaderData*)data; SvgNode *defs, *nodeFrom, *node = loader->svgParse->node; string* id; + SvgUseNode* use = &(node->node.use); + int sz = strlen(key); + unsigned char* array = (unsigned char*)use; + for (unsigned int i = 0; i < sizeof(useTags) / sizeof(useTags[0]); i++) { + if (useTags[i].sz - 1 == sz && !strncmp(useTags[i].tag, key, sz)) { + *((float*)(array + useTags[i].offset)) = _toFloat(loader->svgParse, value, useTags[i].type); + return true; + } + } + if (!strcmp(key, "href") || !strcmp(key, "xlink:href")) { id = _idFromHref(value); defs = _getDefsNode(node); diff --git a/src/loaders/svg/tvgSvgLoaderCommon.h b/src/loaders/svg/tvgSvgLoaderCommon.h index ae08d5c4..b7c69cd6 100644 --- a/src/loaders/svg/tvgSvgLoaderCommon.h +++ b/src/loaders/svg/tvgSvgLoaderCommon.h @@ -157,6 +157,11 @@ struct SvgDefsNode Array gradients; }; +struct SvgUseNode +{ + float x, y, w, h; +}; + struct SvgEllipseNode { @@ -334,6 +339,7 @@ struct SvgNode SvgGNode g; SvgDocNode doc; SvgDefsNode defs; + SvgUseNode use; SvgCircleNode circle; SvgEllipseNode ellipse; SvgPolygonNode polygon; diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index e62cc957..6eb5a325 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -57,6 +57,7 @@ #include static bool _appendShape(SvgNode* node, Shape* shape, float vx, float vy, float vw, float vh); +static unique_ptr _sceneBuildHelper(const SvgNode* node, float vx, float vy, float vw, float vh, const string& svgPath); /************************************************************************/ /* Internal Class Implementation */ @@ -550,6 +551,19 @@ static unique_ptr _imageBuildHelper(SvgNode* node, float vx, float vy, } +static unique_ptr _useBuildHelper(const SvgNode* node, float vx, float vy, float vw, float vh, const string& svgPath) +{ + auto scene = _sceneBuildHelper(node, vx, vy, vw, vh, svgPath); + if (node->node.use.x != 0.0f || node->node.use.y != 0.0f) { + scene->translate(node->node.use.x, node->node.use.y); + } + if (node->node.use.w > 0.0f && node->node.use.h > 0.0f) { + //TODO: handle width/height properties + } + return scene; +} + + static unique_ptr _sceneBuildHelper(const SvgNode* node, float vx, float vy, float vw, float vh, const string& svgPath) { if (_isGroupType(node->type)) { @@ -560,7 +574,10 @@ static unique_ptr _sceneBuildHelper(const SvgNode* node, float vx, float auto child = node->child.data; for (uint32_t i = 0; i < node->child.count; ++i, ++child) { if (_isGroupType((*child)->type)) { - scene->push(_sceneBuildHelper(*child, vx, vy, vw, vh, svgPath)); + if ((*child)->type == SvgNodeType::Use) + scene->push(_useBuildHelper(*child, vx, vy, vw, vh, svgPath)); + else + scene->push(_sceneBuildHelper(*child, vx, vy, vw, vh, svgPath)); } else if ((*child)->type == SvgNodeType::Image) { auto image = _imageBuildHelper(*child, vx, vy, vw, vh, svgPath); if (image) scene->push(move(image));