From 3f2d3b2d57b943b2de2e53e05f0625b3a43bbd15 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Sat, 29 Jan 2022 23:08:53 +0100 Subject: [PATCH 01/16] svg_loader: fixing css style for group selectors, clips/masks The css styling has to be applied as the first step of the node updates. Whereas the updateStyle function should be called as the last step, after all other node updates are made. Change-Id: I59d11f6d372ff4f32c22b067edff90b552900ef8 --- src/loaders/svg/tvgSvgCssStyle.cpp | 3 +-- src/loaders/svg/tvgSvgLoader.cpp | 9 +++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/loaders/svg/tvgSvgCssStyle.cpp b/src/loaders/svg/tvgSvgCssStyle.cpp index 60edf92..67fb39c 100644 --- a/src/loaders/svg/tvgSvgCssStyle.cpp +++ b/src/loaders/svg/tvgSvgCssStyle.cpp @@ -101,7 +101,6 @@ static void _cssStyleCopy(SvgStyleProperty* to, const SvgStyleProperty* from) to->opacity = from->opacity; to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::Opacity); } - //TODO: support clip-path, mask, mask-type, display } @@ -121,7 +120,7 @@ void copyCssStyleAttr(SvgNode* to, const SvgNode* from) } //Copy style attribute _cssStyleCopy(to->style, from->style); - //TODO: clips and masks are not supported yet in css style + if (from->style->clipPath.url) to->style->clipPath.url = strdup(from->style->clipPath.url); if (from->style->mask.url) to->style->mask.url = strdup(from->style->mask.url); } diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 196de4d..0fdd883 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -2688,7 +2688,7 @@ static void _svgLoaderParserXmlCssStyle(SvgLoaderData* loader, const char* conte while (auto next = simpleXmlParseCSSAttribute(content, length, &tag, &name, &attrs, &attrsLength)) { if ((method = _findGroupFactory(tag))) { - TVGLOG("SVG", "Unsupported elements used in the internal CSS style sheets [Elements: %s]", tag); + if ((node = method(loader, loader->cssStyle, attrs, attrsLength, simpleXmlParseW3CAttribute))) node->id = _copyId(name); } else if ((method = _findGraphicsFactory(tag))) { if ((node = method(loader, loader->cssStyle, attrs, attrsLength, simpleXmlParseW3CAttribute))) node->id = _copyId(name); } else if ((gradientMethod = _findGradientFactory(tag))) { @@ -3043,9 +3043,11 @@ void SvgLoader::run(unsigned tid) if (!simpleXmlParse(content, size, true, _svgLoaderParser, &(loaderData))) return; if (loaderData.doc) { - _updateStyle(loaderData.doc, nullptr); auto defs = loaderData.doc->node.doc.defs; + if (loaderData.nodesToStyle.count > 0) stylePostponedNodes(&loaderData.nodesToStyle, loaderData.cssStyle); + if (loaderData.cssStyle) updateCssStyle(loaderData.doc, loaderData.cssStyle); + _updateComposite(loaderData.doc, loaderData.doc); if (defs) _updateComposite(loaderData.doc, defs); @@ -3054,8 +3056,7 @@ void SvgLoader::run(unsigned tid) if (loaderData.gradients.count > 0) _updateGradient(loaderData.doc, &loaderData.gradients); if (defs) _updateGradient(loaderData.doc, &defs->node.defs.gradients); - if (loaderData.nodesToStyle.count > 0) stylePostponedNodes(&loaderData.nodesToStyle, loaderData.cssStyle); - if (loaderData.cssStyle) updateCssStyle(loaderData.doc, loaderData.cssStyle); + _updateStyle(loaderData.doc, nullptr); } root = svgSceneBuild(loaderData.doc, vx, vy, vw, vh, w, h, preserveAspect, svgPath); } -- 2.7.4 From fc155c8096b701a26c031a9ba52d8a4d46da7f8c Mon Sep 17 00:00:00 2001 From: jykeon Date: Mon, 27 Feb 2023 19:12:37 +0900 Subject: [PATCH 02/16] Bump up 0.7.8 Change-Id: Ib9bd24a04afecb67ba77e560119dddc7b0b2219a Signed-off-by: jykeon --- packaging/thorvg.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/thorvg.spec b/packaging/thorvg.spec index 1519072..2f5fab7 100644 --- a/packaging/thorvg.spec +++ b/packaging/thorvg.spec @@ -1,6 +1,6 @@ Name: thorvg Summary: Thor Vector Graphics Library -Version: 0.7.7 +Version: 0.7.8 Release: 1 Group: Graphics System/Rendering Engine License: MIT -- 2.7.4 From 742aac04b5d27ada809aed95768f9005cf22bcac Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Tue, 25 Jan 2022 12:38:49 +0100 Subject: [PATCH 03/16] example: cssStyle.svg add For now it's a simple file used to check the styling precedence and overall correctness. After the css stylling will be fully introduced a more complex file can be used, Change-Id: I10fe2b7d4c201e29893ab6a919d132a2e2a47e24 --- src/examples/images/cssStyle.svg | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/examples/images/cssStyle.svg diff --git a/src/examples/images/cssStyle.svg b/src/examples/images/cssStyle.svg new file mode 100644 index 0000000..53d071f --- /dev/null +++ b/src/examples/images/cssStyle.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + -- 2.7.4 From 68f20ef932abde4a057d7634dc030de177cebd4e Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 8 Feb 2022 18:02:20 +0900 Subject: [PATCH 04/16] example: just renamed the svg file. Change-Id: Ib880280971d5d2d93cab3b59938e94e230b7a4f5 --- src/examples/images/{cssStyle.svg => css-style.svg} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/examples/images/{cssStyle.svg => css-style.svg} (100%) diff --git a/src/examples/images/cssStyle.svg b/src/examples/images/css-style.svg similarity index 100% rename from src/examples/images/cssStyle.svg rename to src/examples/images/css-style.svg -- 2.7.4 From f168e9636a0cc6e345f521a44e57eb4177d7cac2 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 8 Feb 2022 18:43:03 +0900 Subject: [PATCH 05/16] svg_loader: code refactoring. follow strict coding-style. no logic changes. Change-Id: Iab335dbafe4a32f321244f7df8068176f069d2c9 --- src/loaders/svg/tvgSvgCssStyle.cpp | 54 ++++++++++++++++++-------------------- src/loaders/svg/tvgSvgCssStyle.h | 10 +++---- src/loaders/svg/tvgSvgLoader.cpp | 31 ++++++++++------------ 3 files changed, 45 insertions(+), 50 deletions(-) diff --git a/src/loaders/svg/tvgSvgCssStyle.cpp b/src/loaders/svg/tvgSvgCssStyle.cpp index 67fb39c..e537cfa 100644 --- a/src/loaders/svg/tvgSvgCssStyle.cpp +++ b/src/loaders/svg/tvgSvgCssStyle.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved. + * Copyright (c) 2022 Samsung Electronics Co., Ltd. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,14 +20,13 @@ * SOFTWARE. */ -#include #include "tvgSvgCssStyle.h" /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ -static void _cssStyleCopy(SvgStyleProperty* to, const SvgStyleProperty* from) +static void _copyStyle(SvgStyleProperty* to, const SvgStyleProperty* from) { if (from == nullptr) return; //Copy the properties of 'from' only if they were explicitly set (not the default ones). @@ -108,7 +107,7 @@ static void _cssStyleCopy(SvgStyleProperty* to, const SvgStyleProperty* from) /* External Class Implementation */ /************************************************************************/ -void copyCssStyleAttr(SvgNode* to, const SvgNode* from) +void cssCopyStyleAttr(SvgNode* to, const SvgNode* from) { //Copy matrix attribute if (from->transform && !((int)to->style->flags & (int)SvgStyleFlags::Transform)) { @@ -119,19 +118,19 @@ void copyCssStyleAttr(SvgNode* to, const SvgNode* from) } } //Copy style attribute - _cssStyleCopy(to->style, from->style); + _copyStyle(to->style, from->style); if (from->style->clipPath.url) to->style->clipPath.url = strdup(from->style->clipPath.url); if (from->style->mask.url) to->style->mask.url = strdup(from->style->mask.url); } -SvgNode* findCssStyleNode(const SvgNode* cssStyle, const char* title, SvgNodeType type) +SvgNode* cssFindStyleNode(const SvgNode* style, const char* title, SvgNodeType type) { - if (!cssStyle) return nullptr; + if (!style) return nullptr; - auto child = cssStyle->child.data; - for (uint32_t i = 0; i < cssStyle->child.count; ++i, ++child) { + auto child = style->child.data; + for (uint32_t i = 0; i < style->child.count; ++i, ++child) { if ((*child)->type == type) { if ((!title && !(*child)->id) || (title && (*child)->id && !strcmp((*child)->id, title))) return (*child); } @@ -140,12 +139,12 @@ SvgNode* findCssStyleNode(const SvgNode* cssStyle, const char* title, SvgNodeTyp } -SvgNode* findCssStyleNode(const SvgNode* cssStyle, const char* title) +SvgNode* cssFindStyleNode(const SvgNode* style, const char* title) { - if (!cssStyle) return nullptr; + if (!style) return nullptr; - auto child = cssStyle->child.data; - for (uint32_t i = 0; i < cssStyle->child.count; ++i, ++child) { + auto child = style->child.data; + for (uint32_t i = 0; i < style->child.count; ++i, ++child) { if ((*child)->type == SvgNodeType::CssStyle) { if ((title && (*child)->id && !strcmp((*child)->id, title))) return (*child); } @@ -154,35 +153,34 @@ SvgNode* findCssStyleNode(const SvgNode* cssStyle, const char* title) } -void updateCssStyle(SvgNode* doc, SvgNode* cssStyle) +void cssUpdateStyle(SvgNode* doc, SvgNode* style) { if (doc->child.count > 0) { auto child = doc->child.data; for (uint32_t i = 0; i < doc->child.count; ++i, ++child) { - if (auto cssNode = findCssStyleNode(cssStyle, nullptr, (*child)->type)) { - copyCssStyleAttr(*child, cssNode); + if (auto cssNode = cssFindStyleNode(style, nullptr, (*child)->type)) { + cssCopyStyleAttr(*child, cssNode); } - if (auto cssNode = findCssStyleNode(cssStyle, nullptr)) { - copyCssStyleAttr(*child, cssNode); + if (auto cssNode = cssFindStyleNode(style, nullptr)) { + cssCopyStyleAttr(*child, cssNode); } - updateCssStyle(*child, cssStyle); + cssUpdateStyle(*child, style); } } } -void stylePostponedNodes(Array* nodesToStyle, SvgNode* cssStyle) +void cssApplyStyleToPostponeds(Array& postponeds, SvgNode* style) { - for (uint32_t i = 0; i < nodesToStyle->count; ++i) { - auto nodeIdPair = nodesToStyle->data[i]; + for (uint32_t i = 0; i < postponeds.count; ++i) { + auto nodeIdPair = postponeds.data[i]; //css styling: tag.name has higher priority than .name - if (auto cssNode = findCssStyleNode(cssStyle, nodeIdPair.id, nodeIdPair.node->type)) { - copyCssStyleAttr(nodeIdPair.node, cssNode); + if (auto cssNode = cssFindStyleNode(style, nodeIdPair.id, nodeIdPair.node->type)) { + cssCopyStyleAttr(nodeIdPair.node, cssNode); } - if (auto cssNode = findCssStyleNode(cssStyle, nodeIdPair.id)) { - copyCssStyleAttr(nodeIdPair.node, cssNode); + if (auto cssNode = cssFindStyleNode(style, nodeIdPair.id)) { + cssCopyStyleAttr(nodeIdPair.node, cssNode); } } -} - +} \ No newline at end of file diff --git a/src/loaders/svg/tvgSvgCssStyle.h b/src/loaders/svg/tvgSvgCssStyle.h index 90fbcbf..66477c1 100644 --- a/src/loaders/svg/tvgSvgCssStyle.h +++ b/src/loaders/svg/tvgSvgCssStyle.h @@ -25,10 +25,10 @@ #include "tvgSvgLoaderCommon.h" -void copyCssStyleAttr(SvgNode* to, const SvgNode* from); -SvgNode* findCssStyleNode(const SvgNode* cssStyle, const char* title, SvgNodeType type); -SvgNode* findCssStyleNode(const SvgNode* cssStyle, const char* title); -void updateCssStyle(SvgNode* doc, SvgNode* cssStyle); -void stylePostponedNodes(Array* nodesToStyle, SvgNode* cssStyle); +void cssCopyStyleAttr(SvgNode* to, const SvgNode* from); +SvgNode* cssFindStyleNode(const SvgNode* style, const char* title, SvgNodeType type); +SvgNode* cssFindStyleNode(const SvgNode* style, const char* title); +void cssUpdateStyle(SvgNode* doc, SvgNode* style); +void cssApplyStyleToPostponeds(Array& postponeds, SvgNode* style); #endif //_TVG_SVG_CSS_STYLE_H_ diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 0fdd883..39ee166 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -80,9 +80,6 @@ typedef bool (*parseAttributes)(const char* buf, unsigned bufLength, simpleXMLAt typedef SvgNode* (*FactoryMethod)(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func); typedef SvgStyleGradient* (*GradientFactoryMethod)(SvgLoaderData* loader, const char* buf, unsigned bufLength); -static void _postponeCloneNode(Array* nodes, SvgNode *node, char* id); - - static char* _skipSpace(const char* str, const char* end) { while (((end && str < end) || (!end && *str != '\0')) && isspace(*str)) { @@ -737,6 +734,12 @@ error: } +static void _postpone(Array& nodes, SvgNode *node, char* id) +{ + nodes.push({node, id}); +} + + /* // TODO - remove? static constexpr struct @@ -960,16 +963,16 @@ static void _handleCssClassAttr(SvgLoaderData* loader, SvgNode* node, const char bool cssClassFound = false; //css styling: tag.name has higher priority than .name - if (auto cssNode = findCssStyleNode(loader->cssStyle, *cssClass, node->type)) { + if (auto cssNode = cssFindStyleNode(loader->cssStyle, *cssClass, node->type)) { cssClassFound = true; - copyCssStyleAttr(node, cssNode); + cssCopyStyleAttr(node, cssNode); } - if (auto cssNode = findCssStyleNode(loader->cssStyle, *cssClass)) { + if (auto cssNode = cssFindStyleNode(loader->cssStyle, *cssClass)) { cssClassFound = true; - copyCssStyleAttr(node, cssNode); + cssCopyStyleAttr(node, cssNode); } - if (!cssClassFound) _postponeCloneNode(&loader->nodesToStyle, node, *cssClass); + if (!cssClassFound) _postpone(loader->nodesToStyle, node, *cssClass); } @@ -2031,12 +2034,6 @@ static void _cloneNode(SvgNode* from, SvgNode* parent, int depth) } -static void _postponeCloneNode(Array* nodes, SvgNode *node, char* id) -{ - nodes->push({node, id}); -} - - static void _clonePostponedNodes(Array* cloneNodes, SvgNode* doc) { for (uint32_t i = 0; i < cloneNodes->count; ++i) { @@ -2091,7 +2088,7 @@ static bool _attrParseUseNode(void* data, const char* key, const char* value) //some svg export software include 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->cloneNodes, node, id); + _postpone(loader->cloneNodes, node, id); } } else { return _attrParseGNode(data, key, value); @@ -3045,8 +3042,8 @@ void SvgLoader::run(unsigned tid) if (loaderData.doc) { auto defs = loaderData.doc->node.doc.defs; - if (loaderData.nodesToStyle.count > 0) stylePostponedNodes(&loaderData.nodesToStyle, loaderData.cssStyle); - if (loaderData.cssStyle) updateCssStyle(loaderData.doc, loaderData.cssStyle); + if (loaderData.nodesToStyle.count > 0) cssApplyStyleToPostponeds(loaderData.nodesToStyle, loaderData.cssStyle); + if (loaderData.cssStyle) cssUpdateStyle(loaderData.doc, loaderData.cssStyle); _updateComposite(loaderData.doc, loaderData.doc); if (defs) _updateComposite(loaderData.doc, defs); -- 2.7.4 From 9143d88ec76ce479cabdccc15e8db1d8b28e0e5c Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Tue, 1 Feb 2022 23:34:41 +0100 Subject: [PATCH 06/16] svg_loader: fixing the used mask-type For the performance reasons, regardless of the set/default mask-type value, if the mask is white, the alpha masking is used. To qualify a mask as white, not only its fill has to be checked, but its stroke as well. The second was missing. Change-Id: I407ec17f1b8dfd8fda5948319cf11bd609e7ab91 --- src/loaders/svg/tvgSvgSceneBuilder.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index e9b8f42..9abcc6a 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -594,7 +594,10 @@ static unique_ptr _sceneBuildHelper(const SvgNode* node, const Box& vBox, if (isMaskWhite) { uint8_t r, g, b; shape->fillColor(&r, &g, &b, nullptr); - if (shape->fill() || r < 255 || g < 255 || b < 255) *isMaskWhite = false; + if (shape->fill() || r < 255 || g < 255 || b < 255 || shape->strokeFill() || + (shape->strokeColor(&r, &g, &b, nullptr) == Result::Success && (r < 255 || g < 255 || b < 255))) { + *isMaskWhite = false; + } } scene->push(move(shape)); } -- 2.7.4 From d3c640ded06cb48dc01bec5dd3302617a29946be Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Fri, 4 Feb 2022 18:59:00 +0100 Subject: [PATCH 07/16] svg_loader: the 'use' node properly transformed The translation of the use node shouldn't overwrite its transformation. Change-Id: Ibc6761404bc98bd5a82ac1c2d76bf664a98e5d91 --- src/loaders/svg/tvgSvgSceneBuilder.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index 9abcc6a..ed9576b 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -540,7 +540,7 @@ static unique_ptr _imageBuildHelper(SvgNode* node, const Box& vBox, con string imagePath = href; if (strncmp(href, "/", 1)) { auto last = svgPath.find_last_of("/"); - imagePath = svgPath.substr(0, (last == string::npos ? 0 : last + 1 )) + imagePath; + imagePath = svgPath.substr(0, (last == string::npos ? 0 : last + 1)) + imagePath; } if (picture->load(imagePath) != Result::Success) return nullptr; } @@ -561,12 +561,17 @@ static unique_ptr _imageBuildHelper(SvgNode* node, const Box& vBox, con static unique_ptr _useBuildHelper(const SvgNode* node, const Box& vBox, const string& svgPath, bool* isMaskWhite) { auto scene = _sceneBuildHelper(node, vBox, svgPath, false, isMaskWhite); + if (node->node.use.x != 0.0f || node->node.use.y != 0.0f) { - scene->translate(node->node.use.x, node->node.use.y); + Matrix m = {1, 0, node->node.use.x, 0, 1, node->node.use.y, 0, 0, 1}; + Matrix transform = scene->transform(); + m = mathMultiply(&transform, &m); + scene->transform(m); } if (node->node.use.w > 0.0f && node->node.use.h > 0.0f) { //TODO: handle width/height properties } + return scene; } -- 2.7.4 From 8917e3cfdafceefc76ec76112e2597ffbaea0623 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Mon, 7 Feb 2022 02:39:48 +0100 Subject: [PATCH 08/16] svg_loader: proper image transformation One of the image's attributes can be a transformation matrix. Now it's applied. Change-Id: I7056aa0a5deff519bf60e5fd99b4786c2a6cb8bf --- src/loaders/svg/tvgSvgLoader.cpp | 2 ++ src/loaders/svg/tvgSvgSceneBuilder.cpp | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 39ee166..adc8de8 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -1715,6 +1715,8 @@ static bool _attrParseImageNode(void* data, const char* key, const char* value) _handleClipPathAttr(loader, node, value); } else if (!strcmp(key, "mask")) { _handleMaskAttr(loader, node, value); + } else if (!strcmp(key, "transform")) { + node->transform = _parseTransformationMatrix(value); } else { return _parseStyleAttr(loader, key, value); } diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index ed9576b..737d99b 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -546,12 +546,14 @@ static unique_ptr _imageBuildHelper(SvgNode* node, const Box& vBox, con } float w, h; + Matrix m = {1, 0, 0, 0, 1, 0, 0, 0, 1}; if (picture->size(&w, &h) == Result::Success && w > 0 && h > 0) { auto sx = node->node.image.w / w; auto sy = node->node.image.h / h; - Matrix m = {sx, 0, node->node.image.x, 0, sy, node->node.image.y, 0, 0, 1}; - picture->transform(m); + m = {sx, 0, node->node.image.x, 0, sy, node->node.image.y, 0, 0, 1}; } + if (node->transform) m = mathMultiply(node->transform, &m); + picture->transform(m); _applyComposition(picture.get(), node, vBox, svgPath); return picture; -- 2.7.4 From cb813767473f619f779b9307fa235a5452cc6802 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Wed, 9 Feb 2022 19:39:08 +0100 Subject: [PATCH 09/16] svg_loader: preventing invalid log msg Change-Id: I3f93189028debb1c9449bc085d2849c3156c035d --- src/loaders/svg/tvgSvgLoader.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index adc8de8..f597942 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -2295,8 +2295,8 @@ static bool _attrParseRadialGradientNode(void* data, const char* key, const char } else if (!strcmp(key, "href") || !strcmp(key, "xlink:href")) { if (grad->ref && value) free(grad->ref); grad->ref = _idFromHref(value); - } else if (!strcmp(key, "gradientUnits") && !strcmp(value, "userSpaceOnUse")) { - grad->userSpace = true; + } else if (!strcmp(key, "gradientUnits")) { + if (!strcmp(value, "userSpaceOnUse")) grad->userSpace = true; } else if (!strcmp(key, "gradientTransform")) { grad->transform = _parseTransformationMatrix(value); } else { @@ -2485,8 +2485,8 @@ static bool _attrParseLinearGradientNode(void* data, const char* key, const char } else if (!strcmp(key, "href") || !strcmp(key, "xlink:href")) { if (grad->ref && value) free(grad->ref); grad->ref = _idFromHref(value); - } else if (!strcmp(key, "gradientUnits") && !strcmp(value, "userSpaceOnUse")) { - grad->userSpace = true; + } else if (!strcmp(key, "gradientUnits")) { + if (!strcmp(value, "userSpaceOnUse")) grad->userSpace = true; } else if (!strcmp(key, "gradientTransform")) { grad->transform = _parseTransformationMatrix(value); } else { -- 2.7.4 From 41106dd0a3ffb4878452b402f1998e59f4f1af27 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Wed, 9 Feb 2022 17:50:57 -0800 Subject: [PATCH 10/16] infra: Disable unit test in window CI Symbol file generation for compiling test code in CI fails. It's not caused by recent patches. We don't test until we know the exact cause. However, loader test is added to check the safety of window build. Error Log [45/68] Generating symbol file src/thorvg-0.dll.p/thorvg-0.dll.symbols FAILED: src/thorvg-0.dll.p/thorvg-0.dll.symbols "C:\hostedtoolcache\windows\Python\3.7.9\x64\Scripts\meson" "--internal" "symbolextractor" "D:\a\thorvg\thorvg\build" src/thorvg-0.dll "src\thorvg.lib" src/thorvg-0.dll.p/thorvg-0.dll.symbols Change-Id: I03401e691d7a21b59ab2f1a2e40ddbdf4062be08 --- .github/workflows/build_win.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build_win.yml b/.github/workflows/build_win.yml index f1b38b0..be9f23c 100644 --- a/.github/workflows/build_win.yml +++ b/.github/workflows/build_win.yml @@ -28,7 +28,7 @@ jobs: name: result path: build/src\thorvg* - unit_test: + build_loaders: runs-on: windows-latest steps: - uses: actions/checkout@v2 @@ -39,7 +39,7 @@ jobs: - name: Build run: | - meson --backend=ninja build -Dloaders="svg, tvg, png, jpg" -Dsavers="tvg" -Dbindings="capi" -Dtests=true + meson --backend=ninja build -Dloaders="svg, tvg, png, jpg" -Dsavers="tvg" -Dbindings="capi" where link - ninja -C build test + ninja -C build install -- 2.7.4 From 176f8f4261400c76c110c10c4384b18e4d6075f5 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Wed, 9 Feb 2022 19:25:00 +0100 Subject: [PATCH 11/16] svg_loader: fixing memory leak The css style node was improperly freed. Change-Id: I362ea9d30d974a65ddc45e167ef755b260722d56 --- src/loaders/svg/tvgSvgLoader.cpp | 2 ++ src/loaders/svg/tvgSvgLoaderCommon.h | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index f597942..05d67f7 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -2632,6 +2632,7 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content, node = method(loader, parent, attrs, attrsLength, simpleXmlParseAttributes); if (!strcmp(tagName, "style")) { loader->cssStyle = node; + loader->doc->node.doc.style = node; loader->style = true; } } @@ -2929,6 +2930,7 @@ static void _freeNode(SvgNode* node) } case SvgNodeType::Doc: { _freeNode(node->node.doc.defs); + _freeNode(node->node.doc.style); break; } case SvgNodeType::Defs: { diff --git a/src/loaders/svg/tvgSvgLoaderCommon.h b/src/loaders/svg/tvgSvgLoaderCommon.h index 364ec15..d9e9828 100644 --- a/src/loaders/svg/tvgSvgLoaderCommon.h +++ b/src/loaders/svg/tvgSvgLoaderCommon.h @@ -153,6 +153,7 @@ struct SvgDocNode float vw; float vh; SvgNode* defs; + SvgNode* style; bool preserveAspect; }; @@ -405,7 +406,7 @@ struct SvgNodeIdPair struct SvgLoaderData { - Array stack = {nullptr, 0, 0}; + Array stack = {nullptr, 0, 0}; SvgNode* doc = nullptr; SvgNode* def = nullptr; SvgNode* cssStyle = nullptr; -- 2.7.4 From 5705cbfc44594c63e0d8b6de874c5db88b89d612 Mon Sep 17 00:00:00 2001 From: jykeon Date: Thu, 2 Mar 2023 10:31:00 +0900 Subject: [PATCH 12/16] Bump up 0.7.9 Change-Id: Iaacfb1959ac48a334562dea752c14af8c530e434 Signed-off-by: jykeon --- packaging/thorvg.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/thorvg.spec b/packaging/thorvg.spec index 2f5fab7..b7226fb 100644 --- a/packaging/thorvg.spec +++ b/packaging/thorvg.spec @@ -1,6 +1,6 @@ Name: thorvg Summary: Thor Vector Graphics Library -Version: 0.7.8 +Version: 0.7.9 Release: 1 Group: Graphics System/Rendering Engine License: MIT -- 2.7.4 From be6b1495c1e85771ead45f7458129fe2b6b2afbd Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 14 Feb 2022 14:38:03 +0900 Subject: [PATCH 13/16] examples: adds a new sample svg Change-Id: I541117f38dee2fbf11d3fc9a7fd5c255d0e17ed5 --- ...932619-bd3d6921-72df-4f09-856b-f9743ae32a14.svg | 130 +++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 src/examples/images/152932619-bd3d6921-72df-4f09-856b-f9743ae32a14.svg diff --git a/src/examples/images/152932619-bd3d6921-72df-4f09-856b-f9743ae32a14.svg b/src/examples/images/152932619-bd3d6921-72df-4f09-856b-f9743ae32a14.svg new file mode 100644 index 0000000..17f444f --- /dev/null +++ b/src/examples/images/152932619-bd3d6921-72df-4f09-856b-f9743ae32a14.svg @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file -- 2.7.4 From 9cbe0aad58fe802cb97ec985d886f410091dc0cf Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 16 Feb 2022 12:22:53 +0900 Subject: [PATCH 14/16] jpeg_loader: resolve the asan bug report. fix the invalid negative shift operations. @Issue: https://github.com/Samsung/thorvg/issues/1172 Change-Id: I36aac7ecc1869464a5be9cbabf69cd3120d894a2 --- src/loaders/jpg/tvgJpgd.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/loaders/jpg/tvgJpgd.cpp b/src/loaders/jpg/tvgJpgd.cpp index b80516a..dacd45e 100644 --- a/src/loaders/jpg/tvgJpgd.cpp +++ b/src/loaders/jpg/tvgJpgd.cpp @@ -382,8 +382,8 @@ struct Row const int tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065); const int tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865); - const int tmp0 = (ACCESS_COL(0) + ACCESS_COL(4)) << CONST_BITS; - const int tmp1 = (ACCESS_COL(0) - ACCESS_COL(4)) << CONST_BITS; + const int tmp0 = static_cast(ACCESS_COL(0) + ACCESS_COL(4)) << CONST_BITS; + const int tmp1 = static_cast(ACCESS_COL(0) - ACCESS_COL(4)) << CONST_BITS; const int tmp10 = tmp0 + tmp3, tmp13 = tmp0 - tmp3, tmp11 = tmp1 + tmp2, tmp12 = tmp1 - tmp2; @@ -461,8 +461,8 @@ struct Col const int tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065); const int tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865); - const int tmp0 = (ACCESS_ROW(0) + ACCESS_ROW(4)) << CONST_BITS; - const int tmp1 = (ACCESS_ROW(0) - ACCESS_ROW(4)) << CONST_BITS; + const int tmp0 = static_cast(ACCESS_ROW(0) + ACCESS_ROW(4)) << CONST_BITS; + const int tmp1 = static_cast(ACCESS_ROW(0) - ACCESS_ROW(4)) << CONST_BITS; const int tmp10 = tmp0 + tmp3, tmp13 = tmp0 - tmp3, tmp11 = tmp1 + tmp2, tmp12 = tmp1 - tmp2; @@ -2557,7 +2557,7 @@ void jpeg_decoder::decode_block_dc_first(jpeg_decoder *pD, int component_id, int s = JPGD_HUFF_EXTEND(r, s); } pD->m_last_dc_val[component_id] = (s += pD->m_last_dc_val[component_id]); - p[0] = static_cast(s << pD->m_successive_low); + p[0] = static_cast(static_cast(s) << pD->m_successive_low); } @@ -2588,7 +2588,7 @@ void jpeg_decoder::decode_block_ac_first(jpeg_decoder *pD, int component_id, int if ((k += r) > 63) pD->stop_decoding(JPGD_DECODE_ERROR); r = pD->get_bits_no_markers(s); s = JPGD_HUFF_EXTEND(r, s); - p[g_ZAG[k]] = static_cast(s << pD->m_successive_low); + p[g_ZAG[k]] = static_cast(static_cast(s) << pD->m_successive_low); } else { if (r == 15) { if ((k += 15) > 63) pD->stop_decoding(JPGD_DECODE_ERROR); @@ -2607,7 +2607,7 @@ void jpeg_decoder::decode_block_ac_refine(jpeg_decoder *pD, int component_id, in { int s, k, r; int p1 = 1 << pD->m_successive_low; - int m1 = (-1) << pD->m_successive_low; + int m1 = static_cast(-1) << pD->m_successive_low; jpgd_block_t *p = pD->coeff_buf_getp(pD->m_ac_coeffs[component_id], block_x, block_y); JPGD_ASSERT(pD->m_spectral_end <= 63); -- 2.7.4 From af7fe3339dc30ee0ff06537fe378dfdc5c4d7fdb Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Tue, 1 Feb 2022 20:55:15 +0100 Subject: [PATCH 15/16] svg_loader: symbol tag implemented The 'symbol' tag introduced. It can be used to define graphical template objects which can be instantiated by a 'use' tag. Change-Id: I48c000156e764c039a9d27e5a205a226909d2edf --- src/loaders/svg/tvgSvgLoader.cpp | 72 +++++++++++++++++++++++++++++----- src/loaders/svg/tvgSvgLoaderCommon.h | 12 +++++- src/loaders/svg/tvgSvgSceneBuilder.cpp | 65 +++++++++++++++++++++++++++--- src/loaders/svg/tvgXmlParser.cpp | 1 + 4 files changed, 134 insertions(+), 16 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 05d67f7..a16b2b2 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -61,6 +61,7 @@ #include "tvgSvgSceneBuilder.h" #include "tvgSvgUtil.h" #include "tvgSvgCssStyle.h" +#include "tvgMath.h" /************************************************************************/ /* Internal Class Implementation */ @@ -801,13 +802,11 @@ static bool _attrParseSvgNode(void* data, const char* key, const char* value) if (!strcmp(value, "none")) doc->preserveAspect = false; } else if (!strcmp(key, "style")) { return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader); - } #ifdef THORVG_LOG_ENABLED - else if ((!strcmp(key, "x") || !strcmp(key, "y")) && fabsf(svgUtilStrtof(value, nullptr)) > FLT_EPSILON) { + } else if ((!strcmp(key, "x") || !strcmp(key, "y")) && fabsf(svgUtilStrtof(value, nullptr)) > FLT_EPSILON) { TVGLOG("SVG", "Unsupported attributes used [Elements type: Svg][Attribute: %s][Value: %s]", key, value); - } #endif - else { + } else { return _parseStyleAttr(loader, key, value, false); } return true; @@ -1137,6 +1136,36 @@ static bool _attrParseCssStyleNode(void* data, const char* key, const char* valu } +static bool _attrParseSymbolNode(void* data, const char* key, const char* value) +{ + SvgLoaderData* loader = (SvgLoaderData*)data; + SvgNode* node = loader->svgParse->node; + SvgSymbolNode* symbol = &(node->node.symbol); + + if (!strcmp(key, "viewBox")) { + if (_parseNumber(&value, &symbol->vx)) { + if (_parseNumber(&value, &symbol->vy)) { + if (_parseNumber(&value, &symbol->vw)) { + _parseNumber(&value, &symbol->vh); + } + } + } + } else if (!strcmp(key, "width")) { + symbol->w = _toFloat(loader->svgParse, value, SvgParserLengthType::Horizontal); + } else if (!strcmp(key, "height")) { + symbol->h = _toFloat(loader->svgParse, value, SvgParserLengthType::Vertical); + } else if (!strcmp(key, "preserveAspectRatio")) { + if (!strcmp(value, "none")) symbol->preserveAspect = false; + } else if (!strcmp(key, "overflow")) { + if (!strcmp(value, "visible")) symbol->overflowVisible = true; + } else { + return _attrParseGNode(data, key, value); + } + + return true; +} + + static SvgNode* _createNode(SvgNode* parent, SvgNodeType type) { SvgNode* node = (SvgNode*)calloc(1, sizeof(SvgNode)); @@ -1268,6 +1297,21 @@ static SvgNode* _createCssStyleNode(SvgLoaderData* loader, SvgNode* parent, cons if (!loader->svgParse->node) return nullptr; func(buf, bufLength, _attrParseCssStyleNode, loader); + + return loader->svgParse->node; +} + + +static SvgNode* _createSymbolNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func) +{ + loader->svgParse->node = _createNode(parent, SvgNodeType::Symbol); + if (!loader->svgParse->node) return nullptr; + + loader->svgParse->node->display = false; + loader->svgParse->node->node.symbol.preserveAspect = true; + + func(buf, bufLength, _attrParseSymbolNode, loader); + return loader->svgParse->node; } @@ -2044,6 +2088,9 @@ static void _clonePostponedNodes(Array* cloneNodes, SvgNode* doc) auto nodeFrom = _findChildById(defs, nodeIdPair.id); if (!nodeFrom) nodeFrom = _findChildById(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; + } free(nodeIdPair.id); } } @@ -2085,6 +2132,7 @@ static bool _attrParseUseNode(void* data, const char* key, const char* value) nodeFrom = _findChildById(defs, id); if (nodeFrom) { _cloneNode(nodeFrom, node, 0); + if (nodeFrom->type == SvgNodeType::Symbol) use->symbol = nodeFrom; free(id); } else { //some svg export software include element at the end of the file @@ -2092,6 +2140,10 @@ static bool _attrParseUseNode(void* data, const char* key, const char* value) //after the whole file is parsed _postpone(loader->cloneNodes, node, id); } +#ifdef THORVG_LOG_ENABLED + } else if ((!strcmp(key, "width") || !strcmp(key, "height")) && fabsf(svgUtilStrtof(value, nullptr)) > FLT_EPSILON) { + TVGLOG("SVG", "Unsupported attributes used [Elements type: Use][Attribute: %s][Value: %s]", key, value); +#endif } else { return _attrParseGNode(data, key, value); } @@ -2140,7 +2192,8 @@ static constexpr struct {"svg", sizeof("svg"), _createSvgNode}, {"mask", sizeof("mask"), _createMaskNode}, {"clipPath", sizeof("clipPath"), _createClipPathNode}, - {"style", sizeof("style"), _createCssStyleNode} + {"style", sizeof("style"), _createCssStyleNode}, + {"symbol", sizeof("symbol"), _createSymbolNode} }; @@ -2571,7 +2624,8 @@ static constexpr struct {"defs", sizeof("defs")}, {"mask", sizeof("mask")}, {"clipPath", sizeof("clipPath")}, - {"style", sizeof("style")} + {"style", sizeof("style")}, + {"symbol", sizeof("symbol")} }; @@ -2755,7 +2809,7 @@ static void _inefficientNodeCheck(TVG_UNUSED SvgNode* node) #ifdef THORVG_LOG_ENABLED auto type = simpleXmlNodeTypeToString(node->type); - if (!node->display && node->type != SvgNodeType::ClipPath) TVGLOG("SVG", "Inefficient elements used [Display is none][Node Type : %s]", type); + if (!node->display && node->type != SvgNodeType::ClipPath && node->type != SvgNodeType::Symbol) TVGLOG("SVG", "Inefficient elements used [Display is none][Node Type : %s]", type); if (node->style->opacity == 0) TVGLOG("SVG", "Inefficient elements used [Opacity is zero][Node Type : %s]", type); if (node->style->fill.opacity == 0 && node->style->stroke.opacity == 0) TVGLOG("SVG", "Inefficient elements used [Fill opacity and stroke opacity are zero][Node Type : %s]", type); @@ -3049,11 +3103,11 @@ void SvgLoader::run(unsigned tid) if (loaderData.nodesToStyle.count > 0) cssApplyStyleToPostponeds(loaderData.nodesToStyle, loaderData.cssStyle); if (loaderData.cssStyle) cssUpdateStyle(loaderData.doc, loaderData.cssStyle); + if (loaderData.cloneNodes.count > 0) _clonePostponedNodes(&loaderData.cloneNodes, loaderData.doc); + _updateComposite(loaderData.doc, loaderData.doc); if (defs) _updateComposite(loaderData.doc, defs); - if (loaderData.cloneNodes.count > 0) _clonePostponedNodes(&loaderData.cloneNodes, loaderData.doc); - if (loaderData.gradients.count > 0) _updateGradient(loaderData.doc, &loaderData.gradients); if (defs) _updateGradient(loaderData.doc, &defs->node.defs.gradients); diff --git a/src/loaders/svg/tvgSvgLoaderCommon.h b/src/loaders/svg/tvgSvgLoaderCommon.h index d9e9828..1bb5405 100644 --- a/src/loaders/svg/tvgSvgLoaderCommon.h +++ b/src/loaders/svg/tvgSvgLoaderCommon.h @@ -52,6 +52,7 @@ enum class SvgNodeType ClipPath, Mask, CssStyle, + Symbol, Unknown }; @@ -166,12 +167,20 @@ struct SvgDefsNode Array gradients; }; +struct SvgSymbolNode +{ + float w, h; + float vx, vy, vw, vh; + bool preserveAspect; + bool overflowVisible; +}; + struct SvgUseNode { float x, y, w, h; + SvgNode* symbol; }; - struct SvgEllipseNode { float cx; @@ -375,6 +384,7 @@ struct SvgNode SvgMaskNode mask; SvgClipNode clip; SvgCssStyleNode cssStyle; + SvgSymbolNode symbol; } node; bool display; ~SvgNode(); diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index 737d99b..2646c48 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -73,7 +73,7 @@ static unique_ptr _sceneBuildHelper(const SvgNode* node, const Box& vBox, static inline bool _isGroupType(SvgNodeType type) { - if (type == SvgNodeType::Doc || type == SvgNodeType::G || type == SvgNodeType::Use || type == SvgNodeType::ClipPath) return true; + if (type == SvgNodeType::Doc || type == SvgNodeType::G || type == SvgNodeType::Use || type == SvgNodeType::ClipPath || type == SvgNodeType::Symbol) return true; return false; } @@ -562,19 +562,72 @@ static unique_ptr _imageBuildHelper(SvgNode* node, const Box& vBox, con static unique_ptr _useBuildHelper(const SvgNode* node, const Box& vBox, const string& svgPath, bool* isMaskWhite) { + unique_ptr finalScene; auto scene = _sceneBuildHelper(node, vBox, svgPath, false, isMaskWhite); + // mUseTransform = mUseTransform * mTranslate + Matrix mUseTransform = {1, 0, 0, 0, 1, 0, 0, 0, 1}; + if (node->transform) mUseTransform = *node->transform; if (node->node.use.x != 0.0f || node->node.use.y != 0.0f) { - Matrix m = {1, 0, node->node.use.x, 0, 1, node->node.use.y, 0, 0, 1}; - Matrix transform = scene->transform(); - m = mathMultiply(&transform, &m); - scene->transform(m); + Matrix mTranslate = {1, 0, node->node.use.x, 0, 1, node->node.use.y, 0, 0, 1}; + mUseTransform = mathMultiply(&mUseTransform, &mTranslate); } + + if (node->node.use.symbol && !node->node.use.symbol->node.symbol.overflowVisible) { + auto symbol = node->node.use.symbol->node.symbol; + + Matrix mViewBox = {1, 0, 0, 0, 1, 0, 0, 0, 1}; + if ((!mathEqual(symbol.w, symbol.vw) || !mathEqual(symbol.h, symbol.vh)) && symbol.vw > 0 && symbol.vh > 0) { + auto sx = symbol.w / symbol.vw; + auto sy = symbol.h / symbol.vh; + if (symbol.preserveAspect) { + if (sx < sy) sy = sx; + else sx = sy; + } + + auto tvx = symbol.vx * sx; + auto tvy = symbol.vy * sy; + auto tvw = symbol.vw * sx; + auto tvh = symbol.vh * sy; + if (tvw > tvh) tvy -= (symbol.h - tvh) * 0.5f; + else tvx -= (symbol.w - tvw) * 0.5f; + + mViewBox = {sx, 0, -tvx, 0, sy, -tvy, 0, 0, 1}; + } else if (!mathZero(symbol.vx) || !mathZero(symbol.vy)) { + mViewBox = {1, 0, -symbol.vx, 0, 1, -symbol.vy, 0, 0, 1}; + } + + // mSceneTransform = mUseTransform * mViewBox + Matrix mSceneTransform = mathMultiply(&mUseTransform, &mViewBox); + scene->transform(mSceneTransform); + + auto viewBoxClip = Shape::gen(); + viewBoxClip->appendRect(0, 0, symbol.w, symbol.h, 0, 0); + // mClipTransform = mUseTransform * mSymbolTransform + Matrix mClipTransform = mUseTransform; + if (node->node.use.symbol->transform) { + mClipTransform = mathMultiply(&mUseTransform, node->node.use.symbol->transform); + } + viewBoxClip->transform(mClipTransform); + + auto compositeLayer = Scene::gen(); + compositeLayer->composite(move(viewBoxClip), CompositeMethod::ClipPath); + compositeLayer->push(move(scene)); + + auto root = Scene::gen(); + root->push(move(compositeLayer)); + + finalScene = move(root); + } else if (node->node.use.x != 0.0f || node->node.use.y != 0.0f) { + scene->transform(mUseTransform); + finalScene = move(scene); + } + if (node->node.use.w > 0.0f && node->node.use.h > 0.0f) { //TODO: handle width/height properties } - return scene; + return finalScene; } diff --git a/src/loaders/svg/tvgXmlParser.cpp b/src/loaders/svg/tvgXmlParser.cpp index aa93870..a12689c 100644 --- a/src/loaders/svg/tvgXmlParser.cpp +++ b/src/loaders/svg/tvgXmlParser.cpp @@ -272,6 +272,7 @@ const char* simpleXmlNodeTypeToString(TVG_UNUSED SvgNodeType type) "Video", "ClipPath", "Mask", + "Symbol", "Unknown", }; return TYPE_NAMES[(int) type]; -- 2.7.4 From 78801e6f52b970f4cbbf3cc660d140df262f5fae Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Wed, 16 Feb 2022 01:45:26 +0100 Subject: [PATCH 16/16] svg_loader: symbol++ - The initial value of the overflow attribute was missing - overflow="visible" was missing scaling Change-Id: I25b68a37ba154878a6c966b6c38e0214040bbc35 --- src/loaders/svg/tvgSvgLoader.cpp | 1 + src/loaders/svg/tvgSvgSceneBuilder.cpp | 34 +++++++++++++++++++--------------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index a16b2b2..1ec9732 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -1309,6 +1309,7 @@ static SvgNode* _createSymbolNode(SvgLoaderData* loader, SvgNode* parent, const loader->svgParse->node->display = false; loader->svgParse->node->node.symbol.preserveAspect = true; + loader->svgParse->node->node.symbol.overflowVisible = false; func(buf, bufLength, _attrParseSymbolNode, loader); diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index 2646c48..591355a 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -573,7 +573,7 @@ static unique_ptr _useBuildHelper(const SvgNode* node, const Box& vBox, c mUseTransform = mathMultiply(&mUseTransform, &mTranslate); } - if (node->node.use.symbol && !node->node.use.symbol->node.symbol.overflowVisible) { + if (node->node.use.symbol) { auto symbol = node->node.use.symbol->node.symbol; Matrix mViewBox = {1, 0, 0, 0, 1, 0, 0, 0, 1}; @@ -601,23 +601,27 @@ static unique_ptr _useBuildHelper(const SvgNode* node, const Box& vBox, c Matrix mSceneTransform = mathMultiply(&mUseTransform, &mViewBox); scene->transform(mSceneTransform); - auto viewBoxClip = Shape::gen(); - viewBoxClip->appendRect(0, 0, symbol.w, symbol.h, 0, 0); - // mClipTransform = mUseTransform * mSymbolTransform - Matrix mClipTransform = mUseTransform; - if (node->node.use.symbol->transform) { - mClipTransform = mathMultiply(&mUseTransform, node->node.use.symbol->transform); - } - viewBoxClip->transform(mClipTransform); + if (node->node.use.symbol->node.symbol.overflowVisible) { + finalScene = move(scene); + } else { + auto viewBoxClip = Shape::gen(); + viewBoxClip->appendRect(0, 0, symbol.w, symbol.h, 0, 0); + // mClipTransform = mUseTransform * mSymbolTransform + Matrix mClipTransform = mUseTransform; + if (node->node.use.symbol->transform) { + mClipTransform = mathMultiply(&mUseTransform, node->node.use.symbol->transform); + } + viewBoxClip->transform(mClipTransform); - auto compositeLayer = Scene::gen(); - compositeLayer->composite(move(viewBoxClip), CompositeMethod::ClipPath); - compositeLayer->push(move(scene)); + auto compositeLayer = Scene::gen(); + compositeLayer->composite(move(viewBoxClip), CompositeMethod::ClipPath); + compositeLayer->push(move(scene)); - auto root = Scene::gen(); - root->push(move(compositeLayer)); + auto root = Scene::gen(); + root->push(move(compositeLayer)); - finalScene = move(root); + finalScene = move(root); + } } else if (node->node.use.x != 0.0f || node->node.use.y != 0.0f) { scene->transform(mUseTransform); finalScene = move(scene); -- 2.7.4