From 73b96e7f911f83b3c488eaf79e389baf19b93a67 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 23 Aug 2022 22:44:24 +0900 Subject: [PATCH 01/16] examples: fix a compilation error on windows. ../src/examples/Performance.cpp:32:8: error: 'uint' does not name a type; did you mean 'u_int'? 32 | static uint cnt = 0; | ^~~~ | u_int @Issues: https://github.com/Samsung/thorvg/issues/1247 Change-Id: I3f9ae082a89d32519517bedce68cdd5e0c21564b --- src/examples/Performance.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/examples/Performance.cpp b/src/examples/Performance.cpp index 6625aad..ddc5d78 100644 --- a/src/examples/Performance.cpp +++ b/src/examples/Performance.cpp @@ -29,7 +29,7 @@ static tvg::Picture* pPicture = nullptr; static double updateTime = 0; static double accumulateTime = 0; -static uint cnt = 0; +static uint32_t cnt = 0; void tvgDrawCmds(tvg::Canvas* canvas) { -- 2.7.4 From 36cad8169920aa026f6c3fbe77d77548aac70973 Mon Sep 17 00:00:00 2001 From: Vincent Torri Date: Wed, 24 Aug 2022 13:09:56 +0200 Subject: [PATCH 02/16] Fix compilation error on Windows Change-Id: Id9862cbce599596661bbb7d71d70f8732a32ef60 --- src/loaders/svg/tvgSvgSceneBuilder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index a3f34fd..a898473 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -49,9 +49,9 @@ */ +#include "tvgMath.h" /* to include math.h before cstring */ #include #include -#include "tvgMath.h" #include "tvgSvgLoaderCommon.h" #include "tvgSvgSceneBuilder.h" #include "tvgSvgPath.h" -- 2.7.4 From e4bd3b602f525c2151c792b89244fa7fa6df8053 Mon Sep 17 00:00:00 2001 From: jykeon Date: Tue, 14 Mar 2023 13:26:38 +0900 Subject: [PATCH 03/16] Bump up 0.8.4 Change-Id: Idb062490ebc372e629145db3d8f59592dd0081a4 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 6550177..191e285 100644 --- a/packaging/thorvg.spec +++ b/packaging/thorvg.spec @@ -1,6 +1,6 @@ Name: thorvg Summary: Thor Vector Graphics Library -Version: 0.8.3 +Version: 0.8.4 Release: 1 Group: Graphics System/Rendering Engine License: MIT -- 2.7.4 From 3e0b7543496f17c73e652b5734021f1a6822a036 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Sat, 29 Jan 2022 23:03:58 +0100 Subject: [PATCH 04/16] svg_loader: a css style node shouldn't have a parent This node is supposed to be separeted from the main tree nodes. Change-Id: I3cdfc679ef38ca8eee7750c173b7fcc87d8bdd27 --- src/loaders/svg/tvgSvgLoader.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 9013529..42bfd4d 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -2694,11 +2694,13 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content, if (!strcmp(tagName, "svg")) return; //Already loaded (SvgNodeType::Doc) tag if (loader->stack.count > 0) parent = loader->stack.data[loader->stack.count - 1]; else parent = loader->doc; - node = method(loader, parent, attrs, attrsLength, simpleXmlParseAttributes); if (!strcmp(tagName, "style")) { + node = method(loader, nullptr, attrs, attrsLength, simpleXmlParseAttributes); loader->cssStyle = node; loader->doc->node.doc.style = node; loader->style = true; + } else { + node = method(loader, parent, attrs, attrsLength, simpleXmlParseAttributes); } } -- 2.7.4 From 2c1b1520598642b531fea61c12875524331d266d Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Mon, 29 Aug 2022 00:06:52 +0200 Subject: [PATCH 05/16] svg_loader: only the first css style node is interpreted Since the css id selector is not supported in TVG, only the first style node is taken into account. Change-Id: I23775d42f03668372ccae770d9cb6164bebf2ee2 --- src/loaders/svg/tvgSvgLoader.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 42bfd4d..00c0911 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -2695,10 +2695,14 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content, if (loader->stack.count > 0) parent = loader->stack.data[loader->stack.count - 1]; else parent = loader->doc; if (!strcmp(tagName, "style")) { - node = method(loader, nullptr, attrs, attrsLength, simpleXmlParseAttributes); - loader->cssStyle = node; - loader->doc->node.doc.style = node; - loader->style = true; + // TODO: For now only the first style node is saved. After the css id selector + // is introduced this if condition shouldin't be necessary any more + if (!loader->cssStyle) { + node = method(loader, nullptr, attrs, attrsLength, simpleXmlParseAttributes); + loader->cssStyle = node; + loader->doc->node.doc.style = node; + loader->style = true; + } } else { node = method(loader, parent, attrs, attrsLength, simpleXmlParseAttributes); } -- 2.7.4 From 87beeec2192721f7b76000e248f0735f0ce2cf34 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Sun, 28 Aug 2022 23:45:29 +0200 Subject: [PATCH 06/16] svg_loader: fill and stroke paiint url were copied twice The url were copied in the _copyAttr and in the _styleCopy functions. Change-Id: Ia68f3f4be8c68e4be517d1376e0cf68e1d468bcc --- src/loaders/svg/tvgSvgLoader.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 00c0911..3b3183d 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -1992,8 +1992,6 @@ static void _copyAttr(SvgNode* to, const SvgNode* from) //Copy style attribute _styleCopy(to->style, from->style); to->style->flags = (SvgStyleFlags)((int)to->style->flags | (int)from->style->flags); - if (from->style->fill.paint.url) to->style->fill.paint.url = strdup(from->style->fill.paint.url); - if (from->style->stroke.paint.url) to->style->stroke.paint.url = strdup(from->style->stroke.paint.url); 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); -- 2.7.4 From 7a1bc9daa4e82a3b60a78c8f5fbad5c65bf86954 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Mon, 29 Aug 2022 13:32:06 +0900 Subject: [PATCH 07/16] svg_loader: If there is already set color url, it will be deleted. When setting the url for color, if there is an already set url, it will be overwritten after deletion. This prevents memory leaks. asan result) Direct leak of 2 byte(s) in 1 object(s) allocated from: #0 0x7ff1d547bc68 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x10bc68) #1 0x7ff1d4e435b4 in _idFromUrl ../src/loaders/svg/tvgSvgLoader.cpp:327 #2 0x7ff1d4e44a8e in _toColor ../src/loaders/svg/tvgSvgLoader.cpp:558 #3 0x7ff1d4e42ee9 in _parseStyleAttr ../src/loaders/svg/tvgSvgLoader.cpp:1033 #4 0x7ff1d4e7f092 in simpleXmlParseAttributes(char const*, unsigned int, bool (*)(void*, char const*, char const*), void const*) ../src/loaders/svg/tvgXmlParser.cpp:361 #5 0x7ff1d4e597d3 in _createPathNode ../src/loaders/svg/tvgSvgLoader.cpp:1363 #6 0x7ff1d4e61359 in _svgLoaderParserXmlOpen ../src/loaders/svg/tvgSvgLoader.cpp:2723 #7 0x7ff1d4e61c49 in _svgLoaderParser ../src/loaders/svg/tvgSvgLoader.cpp:2801 #8 0x7ff1d4e7f3f6 in simpleXmlParse(char const*, unsigned int, bool, bool (*)(void*, SimpleXMLType, char const*, unsigned int), void const*) ../src/loaders/svg/tvgXmlParser.cpp:429 #9 0x7ff1d4e639a1 in SvgLoader::run(unsigned int) ../src/loaders/svg/tvgSvgLoader.cpp:3121 #10 0x7ff1d4dc8b75 in tvg::Task::operator()(unsigned int) ../src/lib/tvgTaskScheduler.h:68 #11 0x7ff1d4dc8b75 in tvg::TaskSchedulerImpl::run(unsigned int) ../src/lib/tvgTaskScheduler.cpp:138 #12 0x7ff1d4dc98f7 in tvg::TaskSchedulerImpl::TaskSchedulerImpl(unsigned int)::{lambda()#1}::operator()() const ../src/lib/tvgTaskScheduler.cpp:113 #13 0x7ff1d4dc98f7 in void std::__invoke_impl(std::__invoke_other, tvg::TaskSchedulerImpl::TaskSchedulerImpl(unsigned int)::{lambda()#1}&&) /usr/include/c++/9/bits/invoke.h:60 #14 0x7ff1d4dc98f7 in std::__invoke_result::type std::__invoke(std::__invoke_result&&, (tvg::TaskSchedulerImpl::TaskSchedulerImpl(unsigned int)::{lambda()#1}&&)...) /usr/include/c++/9/bits/invoke.h:95 #15 0x7ff1d4dc98f7 in void std::thread::_Invoker >::_M_invoke<0ul>(std::_Index_tuple<0ul>) /usr/include/c++/9/thread:244 #16 0x7ff1d4dc98f7 in std::thread::_Invoker >::operator()() /usr/include/c++/9/thread:251 #17 0x7ff1d4dc98f7 in std::thread::_State_impl > >::_M_run() /usr/include/c++/9/thread:195 #18 0x7ff1d3a344bf (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0xd44bf) example) Change-Id: I14c605e7555dbda19113b9f9027954654e423f4b --- src/loaders/svg/tvgSvgCssStyle.cpp | 10 ++++++++-- src/loaders/svg/tvgSvgLoader.cpp | 25 +++++++++++++++++++++---- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/loaders/svg/tvgSvgCssStyle.cpp b/src/loaders/svg/tvgSvgCssStyle.cpp index 8f46b62..cca188e 100644 --- a/src/loaders/svg/tvgSvgCssStyle.cpp +++ b/src/loaders/svg/tvgSvgCssStyle.cpp @@ -42,7 +42,10 @@ static void _copyStyle(SvgStyleProperty* to, const SvgStyleProperty* from) to->fill.paint.color = from->fill.paint.color; to->fill.paint.none = from->fill.paint.none; to->fill.paint.curColor = from->fill.paint.curColor; - if (from->fill.paint.url) to->fill.paint.url = strdup(from->fill.paint.url); + if (from->fill.paint.url) { + if (to->fill.paint.url) free(to->fill.paint.url); + to->fill.paint.url = strdup(from->fill.paint.url); + } to->fill.flags = (SvgFillFlags)((int)to->fill.flags | (int)SvgFillFlags::Paint); to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::Fill); } @@ -61,7 +64,10 @@ static void _copyStyle(SvgStyleProperty* to, const SvgStyleProperty* from) to->stroke.paint.color = from->stroke.paint.color; to->stroke.paint.none = from->stroke.paint.none; to->stroke.paint.curColor = from->stroke.paint.curColor; - if (from->stroke.paint.url) to->stroke.paint.url = strdup(from->stroke.paint.url); + if (from->stroke.paint.url) { + if (to->stroke.paint.url) free(to->stroke.paint.url); + to->stroke.paint.url = strdup(from->stroke.paint.url); + } to->stroke.flags = (SvgStrokeFlags)((int)to->stroke.flags | (int)SvgStrokeFlags::Paint); to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::Stroke); } diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 3b3183d..8b4dc7b 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -554,6 +554,7 @@ static void _toColor(const char* str, uint8_t* r, uint8_t* g, uint8_t* b, char** } } } else if (ref && len >= 3 && !strncmp(str, "url", 3)) { + if (*ref) free(*ref); *ref = _idFromUrl((const char*)(str + 3)); } else { //Handle named color @@ -1889,7 +1890,10 @@ static void _styleInherit(SvgStyleProperty* child, const SvgStyleProperty* paren child->fill.paint.color = parent->fill.paint.color; child->fill.paint.none = parent->fill.paint.none; child->fill.paint.curColor = parent->fill.paint.curColor; - if (parent->fill.paint.url) child->fill.paint.url = _copyId(parent->fill.paint.url); + if (parent->fill.paint.url) { + if (child->fill.paint.url) free(child->fill.paint.url); + child->fill.paint.url = _copyId(parent->fill.paint.url); + } } if (!((int)child->fill.flags & (int)SvgFillFlags::Opacity)) { child->fill.opacity = parent->fill.opacity; @@ -1902,7 +1906,12 @@ static void _styleInherit(SvgStyleProperty* child, const SvgStyleProperty* paren child->stroke.paint.color = parent->stroke.paint.color; child->stroke.paint.none = parent->stroke.paint.none; child->stroke.paint.curColor = parent->stroke.paint.curColor; - child->stroke.paint.url = parent->stroke.paint.url ? _copyId(parent->stroke.paint.url) : nullptr; + if (parent->stroke.paint.url) { + if (child->stroke.paint.url) free(child->stroke.paint.url); + child->stroke.paint.url = _copyId(parent->stroke.paint.url); + } else { + child->stroke.paint.url = nullptr; + } } if (!((int)child->stroke.flags & (int)SvgStrokeFlags::Opacity)) { child->stroke.opacity = parent->stroke.opacity; @@ -1942,7 +1951,10 @@ static void _styleCopy(SvgStyleProperty* to, const SvgStyleProperty* from) to->fill.paint.color = from->fill.paint.color; to->fill.paint.none = from->fill.paint.none; to->fill.paint.curColor = from->fill.paint.curColor; - if (from->fill.paint.url) to->fill.paint.url = _copyId(from->fill.paint.url); + if (from->fill.paint.url) { + if (to->fill.paint.url) free(to->fill.paint.url); + to->fill.paint.url = _copyId(from->fill.paint.url); + } } if (((int)from->fill.flags & (int)SvgFillFlags::Opacity)) { to->fill.opacity = from->fill.opacity; @@ -1956,7 +1968,12 @@ static void _styleCopy(SvgStyleProperty* to, const SvgStyleProperty* from) to->stroke.paint.color = from->stroke.paint.color; to->stroke.paint.none = from->stroke.paint.none; to->stroke.paint.curColor = from->stroke.paint.curColor; - to->stroke.paint.url = from->stroke.paint.url ? _copyId(from->stroke.paint.url) : nullptr; + if (from->stroke.paint.url) { + if (to->stroke.paint.url) free(to->stroke.paint.url); + to->stroke.paint.url = _copyId(from->stroke.paint.url); + } else { + to->stroke.paint.url = nullptr; + } } if (((int)from->stroke.flags & (int)SvgStrokeFlags::Opacity)) { to->stroke.opacity = from->stroke.opacity; -- 2.7.4 From d817777870410167510db10c769afe8f3d06babf Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Tue, 30 Aug 2022 10:54:20 +0900 Subject: [PATCH 08/16] svg_loader: Remove unnecessary code Change-Id: Ia3e0d35ed48b3c04c2408ca24d48bf43c32cc54c --- src/loaders/svg/tvgSvgLoader.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 8b4dc7b..357d19d 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -1909,8 +1909,6 @@ static void _styleInherit(SvgStyleProperty* child, const SvgStyleProperty* paren if (parent->stroke.paint.url) { if (child->stroke.paint.url) free(child->stroke.paint.url); child->stroke.paint.url = _copyId(parent->stroke.paint.url); - } else { - child->stroke.paint.url = nullptr; } } if (!((int)child->stroke.flags & (int)SvgStrokeFlags::Opacity)) { @@ -1971,8 +1969,6 @@ static void _styleCopy(SvgStyleProperty* to, const SvgStyleProperty* from) if (from->stroke.paint.url) { if (to->stroke.paint.url) free(to->stroke.paint.url); to->stroke.paint.url = _copyId(from->stroke.paint.url); - } else { - to->stroke.paint.url = nullptr; } } if (((int)from->stroke.flags & (int)SvgStrokeFlags::Opacity)) { -- 2.7.4 From c13f371a4eb466a9b0957ed3fb3e6296383a2f6a Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Wed, 31 Aug 2022 00:21:59 +0200 Subject: [PATCH 09/16] svg_loader: prevent mem leaks A necessary check added before strdup function is called Change-Id: Ibc1cbfc29ea342d5ca31390b306943f7d5f6e25d --- src/loaders/svg/tvgSvgCssStyle.cpp | 10 ++++++++-- src/loaders/svg/tvgSvgLoader.cpp | 21 +++++++++++++++++---- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/loaders/svg/tvgSvgCssStyle.cpp b/src/loaders/svg/tvgSvgCssStyle.cpp index cca188e..478ba5d 100644 --- a/src/loaders/svg/tvgSvgCssStyle.cpp +++ b/src/loaders/svg/tvgSvgCssStyle.cpp @@ -128,8 +128,14 @@ void cssCopyStyleAttr(SvgNode* to, const SvgNode* from) //Copy style attribute _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); + if (from->style->clipPath.url) { + if (to->style->clipPath.url) free(to->style->clipPath.url); + to->style->clipPath.url = strdup(from->style->clipPath.url); + } + if (from->style->mask.url) { + if (to->style->mask.url) free(to->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 357d19d..c619fa9 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -1332,6 +1332,7 @@ static bool _attrParsePathNode(void* data, const char* key, const char* value) SvgPathNode* path = &(node->node.path); if (!strcmp(key, "d")) { + if (path->path) free(path->path); //Temporary: need to copy path->path = _copyId(value); } else if (!strcmp(key, "style")) { @@ -2005,8 +2006,14 @@ static void _copyAttr(SvgNode* to, const SvgNode* from) //Copy style attribute _styleCopy(to->style, from->style); to->style->flags = (SvgStyleFlags)((int)to->style->flags | (int)from->style->flags); - 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); + if (from->style->clipPath.url) { + if (to->style->clipPath.url) free(to->style->clipPath.url); + to->style->clipPath.url = strdup(from->style->clipPath.url); + } + if (from->style->mask.url) { + if (to->style->mask.url) free(to->style->mask.url); + to->style->mask.url = strdup(from->style->mask.url); + } //Copy node attribute switch (from->type) { @@ -2042,7 +2049,10 @@ static void _copyAttr(SvgNode* to, const SvgNode* from) break; } case SvgNodeType::Path: { - if (from->node.path.path) to->node.path.path = strdup(from->node.path.path); + if (from->node.path.path) { + if (to->node.path.path) free(to->node.path.path); + to->node.path.path = strdup(from->node.path.path); + } break; } case SvgNodeType::Polygon: { @@ -2064,7 +2074,10 @@ static void _copyAttr(SvgNode* to, const SvgNode* from) to->node.image.y = from->node.image.y; to->node.image.w = from->node.image.w; to->node.image.h = from->node.image.h; - if (from->node.image.href) to->node.image.href = strdup(from->node.image.href); + if (from->node.image.href) { + if (to->node.image.href) free(to->node.image.href); + to->node.image.href = strdup(from->node.image.href); + } break; } default: { -- 2.7.4 From 4fc79d4bbc31959ad3b2b2acf97ae04465e5a2c1 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Wed, 31 Aug 2022 18:07:40 +0900 Subject: [PATCH 10/16] svg_loader: No skip luma mask when composition node is image Improved to skip Luma Mask when conditions are the same as AlphaMask for optimization in e409bb29. If the composition node is an image, it is not skipped because it is not known for sure whether to skip it. Change-Id: I82d1c5ab0ad4bf9624913a574556ea7ae7709a7e --- 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 a898473..ae0e498 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -659,7 +659,10 @@ static unique_ptr _sceneBuildHelper(const SvgNode* node, const Box& vBox, scene->push(_sceneBuildHelper(*child, vBox, svgPath, false, isMaskWhite)); } else if ((*child)->type == SvgNodeType::Image) { auto image = _imageBuildHelper(*child, vBox, svgPath); - if (image) scene->push(move(image)); + if (image) { + scene->push(move(image)); + if (isMaskWhite) *isMaskWhite = false; + } } else if ((*child)->type != SvgNodeType::Mask) { auto shape = _shapeBuildHelper(*child, vBox, svgPath); if (shape) { -- 2.7.4 From d035143ce5858aef0ea06f6df9c7f800df818d9b Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Thu, 1 Sep 2022 20:53:39 +0200 Subject: [PATCH 11/16] svg_loader: prevent stack-overflow for nested nodes Change-Id: Ib479c8af995f2b7576503dbd182defd4a1747d9d --- src/loaders/svg/tvgSvgSceneBuilder.cpp | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index ae0e498..b4695a6 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -68,7 +68,7 @@ struct Box static bool _appendShape(SvgNode* node, Shape* shape, const Box& vBox, const string& svgPath); -static unique_ptr _sceneBuildHelper(const SvgNode* node, const Box& vBox, const string& svgPath, bool mask, bool* isMaskWhite = nullptr); +static unique_ptr _sceneBuildHelper(const SvgNode* node, const Box& vBox, const string& svgPath, bool mask, int depth, bool* isMaskWhite = nullptr); static inline bool _isGroupType(SvgNodeType type) @@ -282,7 +282,7 @@ static void _applyComposition(Paint* paint, const SvgNode* node, const Box& vBox node->style->mask.applying = true; bool isMaskWhite = true; - auto comp = _sceneBuildHelper(compNode, vBox, svgPath, true, &isMaskWhite); + auto comp = _sceneBuildHelper(compNode, vBox, svgPath, true, 0, &isMaskWhite); if (comp) { if (node->transform) comp->transform(*node->transform); @@ -560,10 +560,10 @@ 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) +static unique_ptr _useBuildHelper(const SvgNode* node, const Box& vBox, const string& svgPath, int depth, bool* isMaskWhite) { unique_ptr finalScene; - auto scene = _sceneBuildHelper(node, vBox, svgPath, false, isMaskWhite); + auto scene = _sceneBuildHelper(node, vBox, svgPath, false, depth + 1, isMaskWhite); // mUseTransform = mUseTransform * mTranslate Matrix mUseTransform = {1, 0, 0, 0, 1, 0, 0, 0, 1}; @@ -642,8 +642,15 @@ static unique_ptr _useBuildHelper(const SvgNode* node, const Box& vBox, c } -static unique_ptr _sceneBuildHelper(const SvgNode* node, const Box& vBox, const string& svgPath, bool mask, bool* isMaskWhite) +static unique_ptr _sceneBuildHelper(const SvgNode* node, const Box& vBox, const string& svgPath, bool mask, int depth, bool* isMaskWhite) { + /* Exception handling: Prevent invalid SVG data input. + The size is the arbitrary value, we need an experimental size. */ + if (depth > 2192) { + TVGERR("SVG", "Infinite recursive call - stopped after %d calls! Svg file may be incorrectly formatted.", depth); + return nullptr; + } + if (_isGroupType(node->type) || mask) { auto scene = Scene::gen(); // For a Symbol node, the viewBox transformation has to be applied first - see _useBuildHelper() @@ -654,9 +661,9 @@ static unique_ptr _sceneBuildHelper(const SvgNode* node, const Box& vBox, for (uint32_t i = 0; i < node->child.count; ++i, ++child) { if (_isGroupType((*child)->type)) { if ((*child)->type == SvgNodeType::Use) - scene->push(_useBuildHelper(*child, vBox, svgPath, isMaskWhite)); + scene->push(_useBuildHelper(*child, vBox, svgPath, depth + 1, isMaskWhite)); else - scene->push(_sceneBuildHelper(*child, vBox, svgPath, false, isMaskWhite)); + scene->push(_sceneBuildHelper(*child, vBox, svgPath, false, depth + 1, isMaskWhite)); } else if ((*child)->type == SvgNodeType::Image) { auto image = _imageBuildHelper(*child, vBox, svgPath); if (image) { @@ -696,7 +703,7 @@ unique_ptr svgSceneBuild(SvgNode* node, float vx, float vy, float vw, flo if (!node || (node->type != SvgNodeType::Doc)) return nullptr; Box vBox = {vx, vy, vw, vh}; - auto docNode = _sceneBuildHelper(node, vBox, svgPath, false); + auto docNode = _sceneBuildHelper(node, vBox, svgPath, false, 0); if (!mathEqual(w, vw) || !mathEqual(h, vh)) { auto sx = w / vw; -- 2.7.4 From 8cb427a2c0ab6272ec6e375a54aa88554f17d696 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Thu, 1 Sep 2022 01:15:59 +0200 Subject: [PATCH 12/16] svg_loader: deeper search for postponed nodes Till now the proper node was searched only among children, now all the nodes are checked. Change-Id: I46b9fa1de2de3cc5c53e327f0e6bb6b6dd415fc9 --- src/loaders/svg/tvgSvgLoader.cpp | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index c619fa9..225ebe8 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -1803,19 +1803,10 @@ static SvgNode* _getDefsNode(SvgNode* node) } -static SvgNode* _findChildById(const SvgNode* node, const char* id) +static SvgNode* _findNodeById(SvgNode *node, const char* id) { if (!node) return nullptr; - auto child = node->child.data; - for (uint32_t i = 0; i < node->child.count; ++i, ++child) { - if (((*child)->id) && !strcmp((*child)->id, id)) return (*child); - } - return nullptr; -} - -static SvgNode* _findNodeById(SvgNode *node, const char* id) -{ SvgNode* result = nullptr; if (node->id && !strcmp(node->id, id)) return node; @@ -1829,6 +1820,7 @@ static SvgNode* _findNodeById(SvgNode *node, const char* id) return result; } + static void _cloneGradStops(Array& dst, const Array& src) { for (uint32_t i = 0; i < src.count; ++i) { @@ -2117,8 +2109,8 @@ static void _clonePostponedNodes(Array* cloneNodes, SvgNode* doc) for (uint32_t i = 0; i < cloneNodes->count; ++i) { auto nodeIdPair = cloneNodes->data[i]; auto defs = _getDefsNode(nodeIdPair.node); - auto nodeFrom = _findChildById(defs, nodeIdPair.id); - if (!nodeFrom) nodeFrom = _findChildById(doc, nodeIdPair.id); + 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; @@ -2165,7 +2157,7 @@ static bool _attrParseUseNode(void* data, const char* key, const char* value) if (!strcmp(key, "href") || !strcmp(key, "xlink:href")) { id = _idFromHref(value); defs = _getDefsNode(node); - nodeFrom = _findChildById(defs, id); + nodeFrom = _findNodeById(defs, id); if (nodeFrom) { _cloneNode(nodeFrom, node, 0); if (nodeFrom->type == SvgNodeType::Symbol) use->symbol = nodeFrom; -- 2.7.4 From 795978177ab26c6ced98fd493f13e99a27c36397 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska <67589014+mgrudzinska@users.noreply.github.com> Date: Fri, 2 Sep 2022 04:59:49 +0200 Subject: [PATCH 13/16] svg_loader: preserveAspectRatio attrib handled according to the svg standard (#1249) * svg_loader: preserveAspectRatio attrib handled according to the svg standard * svg_loader: symbol fixed The correct width/height values used in the _useBuildHelper function. Bug was propageted while the preserveAspectRatio attrib was handled, now fixed. * svg_loader: refactoring code regarding the preserveAspectRatio attrib To avoid copy/paste a new function is introduced to handle the proper scaling. * svg_loader: initialize the svg loader members The 'align' and 'meetOrSlice' svg loader members were not initialized. * svg_loader: resize function forces any transformation The resize function is called after the svg image is read and scaled taking into account the proper preserveAspectRatio value. While resizing the preserveAspectRatio isn't checked any more and the image can be freely transformed. Change-Id: I5ec14b7676063f60c1fc3b12262cc06f85f64e97 --- src/lib/tvgLoadModule.h | 1 - src/loaders/svg/tvgSvgLoader.cpp | 86 +++++++++++++++--------- src/loaders/svg/tvgSvgLoader.h | 3 + src/loaders/svg/tvgSvgLoaderCommon.h | 26 +++++++- src/loaders/svg/tvgSvgSceneBuilder.cpp | 118 ++++++++++++++++++++++----------- src/loaders/svg/tvgSvgSceneBuilder.h | 2 +- 6 files changed, 165 insertions(+), 71 deletions(-) diff --git a/src/lib/tvgLoadModule.h b/src/lib/tvgLoadModule.h index bfcc165..0049831 100644 --- a/src/lib/tvgLoadModule.h +++ b/src/lib/tvgLoadModule.h @@ -36,7 +36,6 @@ public: float vw = 0; float vh = 0; float w = 0, h = 0; //default image size - bool preserveAspect = true; //keep aspect ratio by default. virtual ~LoadModule() {} diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 225ebe8..9a88853 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -115,9 +115,54 @@ static bool _parseNumber(const char** content, float* number) if ((*content) == end) return false; //Skip comma if any *content = _skipComma(end); + + return true; +} + + +static constexpr struct +{ + AspectRatioAlign align; + const char* tag; +} alignTags[] = { + { AspectRatioAlign::XMinYMin, "xMinYMin" }, + { AspectRatioAlign::XMidYMin, "xMidYMin" }, + { AspectRatioAlign::XMaxYMin, "xMaxYMin" }, + { AspectRatioAlign::XMinYMid, "xMinYMid" }, + { AspectRatioAlign::XMidYMid, "xMidYMid" }, + { AspectRatioAlign::XMaxYMid, "xMaxYMid" }, + { AspectRatioAlign::XMinYMax, "xMinYMax" }, + { AspectRatioAlign::XMidYMax, "xMidYMax" }, + { AspectRatioAlign::XMaxYMax, "xMaxYMax" }, +}; + + +static bool _parseAspectRatio(const char** content, AspectRatioAlign* align, AspectRatioMeetOrSlice* meetOrSlice) +{ + if (!strcmp(*content, "none")) { + *align = AspectRatioAlign::None; + return true; + } + + for (unsigned int i = 0; i < sizeof(alignTags) / sizeof(alignTags[0]); i++) { + if (!strncmp(*content, alignTags[i].tag, 8)) { + *align = alignTags[i].align; + *content += 8; + *content = _skipSpace(*content, nullptr); + break; + } + } + + if (!strcmp(*content, "meet")) { + *meetOrSlice = AspectRatioMeetOrSlice::Meet; + } else if (!strcmp(*content, "slice")) { + *meetOrSlice = AspectRatioMeetOrSlice::Slice; + } + return true; } + /** * According to https://www.w3.org/TR/SVG/coords.html#Units */ @@ -803,7 +848,7 @@ static bool _attrParseSvgNode(void* data, const char* key, const char* value) } loader->svgParse->global.x = (int)doc->vx; } else if (!strcmp(key, "preserveAspectRatio")) { - if (!strcmp(value, "none")) doc->preserveAspect = false; + _parseAspectRatio(&value, &doc->align, &doc->meetOrSlice); } else if (!strcmp(key, "style")) { return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader); #ifdef THORVG_LOG_ENABLED @@ -1157,7 +1202,7 @@ static bool _attrParseSymbolNode(void* data, const char* key, const char* value) symbol->h = _toFloat(loader->svgParse, value, SvgParserLengthType::Vertical); symbol->hasHeight = true; } else if (!strcmp(key, "preserveAspectRatio")) { - if (!strcmp(value, "none")) symbol->preserveAspect = false; + _parseAspectRatio(&value, &symbol->align, &symbol->meetOrSlice); } else if (!strcmp(key, "overflow")) { if (!strcmp(value, "visible")) symbol->overflowVisible = true; } else { @@ -1249,7 +1294,8 @@ static SvgNode* _createSvgNode(SvgLoaderData* loader, SvgNode* parent, const cha loader->svgParse->global.w = 0; loader->svgParse->global.h = 0; - doc->preserveAspect = true; + doc->align = AspectRatioAlign::XMidYMid; + doc->meetOrSlice = AspectRatioMeetOrSlice::Meet; func(buf, bufLength, _attrParseSvgNode, loader); if (loader->svgParse->global.w == 0) { @@ -1310,7 +1356,8 @@ static SvgNode* _createSymbolNode(SvgLoaderData* loader, SvgNode* parent, const if (!loader->svgParse->node) return nullptr; loader->svgParse->node->display = false; - loader->svgParse->node->node.symbol.preserveAspect = true; + loader->svgParse->node->node.symbol.align = AspectRatioAlign::XMidYMid; + loader->svgParse->node->node.symbol.meetOrSlice = AspectRatioMeetOrSlice::Meet; loader->svgParse->node->node.symbol.overflowVisible = false; loader->svgParse->node->node.symbol.hasViewBox = false; @@ -3147,7 +3194,7 @@ void SvgLoader::run(unsigned tid) _updateStyle(loaderData.doc, nullptr); } - root = svgSceneBuild(loaderData.doc, vx, vy, vw, vh, w, h, preserveAspect, svgPath); + root = svgSceneBuild(loaderData.doc, vx, vy, vw, vh, w, h, align, meetOrSlice, svgPath); } @@ -3180,7 +3227,8 @@ bool SvgLoader::header() if (vh < FLT_EPSILON) vh = h; } - preserveAspect = loaderData.doc->node.doc.preserveAspect; + align = loaderData.doc->node.doc.align; + meetOrSlice = loaderData.doc->node.doc.meetOrSlice; } else { TVGLOG("SVG", "No SVG File. There is no "); return false; @@ -3235,31 +3283,9 @@ bool SvgLoader::resize(Paint* paint, float w, float h) auto sx = w / this->w; auto sy = h / this->h; + Matrix m = {sx, 0, 0, 0, sy, 0, 0, 0, 1}; + paint->transform(m); - if (preserveAspect) { - //Scale - auto scale = sx < sy ? sx : sy; - paint->scale(scale); - //Align - auto tx = 0.0f; - auto ty = 0.0f; - auto tw = this->w * scale; - auto th = this->h * scale; - if (tw > th) ty -= (h - th) * 0.5f; - else tx -= (w - tw) * 0.5f; - paint->translate(-tx, -ty); - } else { - //Align - auto tx = 0.0f; - auto ty = 0.0f; - auto tw = this->w * sx; - auto th = this->h * sy; - if (tw > th) ty -= (h - th) * 0.5f; - else tx -= (w - tw) * 0.5f; - - Matrix m = {sx, 0, -tx, 0, sy, -ty, 0, 0, 1}; - paint->transform(m); - } return true; } diff --git a/src/loaders/svg/tvgSvgLoader.h b/src/loaders/svg/tvgSvgLoader.h index 093fb67..f224d1a 100644 --- a/src/loaders/svg/tvgSvgLoader.h +++ b/src/loaders/svg/tvgSvgLoader.h @@ -50,6 +50,9 @@ public: unique_ptr paint() override; private: + AspectRatioAlign align = AspectRatioAlign::XMidYMid; + AspectRatioMeetOrSlice meetOrSlice = AspectRatioMeetOrSlice::Meet; + bool header(); void clear(); void run(unsigned tid) override; diff --git a/src/loaders/svg/tvgSvgLoaderCommon.h b/src/loaders/svg/tvgSvgLoaderCommon.h index dc9ed55..c657c0e 100644 --- a/src/loaders/svg/tvgSvgLoaderCommon.h +++ b/src/loaders/svg/tvgSvgLoaderCommon.h @@ -145,6 +145,26 @@ enum class SvgParserLengthType Other }; +enum class AspectRatioAlign +{ + None, + XMinYMin, + XMidYMin, + XMaxYMin, + XMinYMid, + XMidYMid, + XMaxYMid, + XMinYMax, + XMidYMax, + XMaxYMax +}; + +enum class AspectRatioMeetOrSlice +{ + Meet, + Slice +}; + struct SvgDocNode { float w; @@ -155,7 +175,8 @@ struct SvgDocNode float vh; SvgNode* defs; SvgNode* style; - bool preserveAspect; + AspectRatioAlign align; + AspectRatioMeetOrSlice meetOrSlice; }; struct SvgGNode @@ -171,7 +192,8 @@ struct SvgSymbolNode { float w, h; float vx, vy, vw, vh; - bool preserveAspect; + AspectRatioAlign align; + AspectRatioMeetOrSlice meetOrSlice; bool overflowVisible; bool hasViewBox; bool hasWidth; diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index b4695a6..4cb4ffd 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -560,6 +560,80 @@ static unique_ptr _imageBuildHelper(SvgNode* node, const Box& vBox, con } +static Matrix _calculateAspectRatioMatrix(AspectRatioAlign align, AspectRatioMeetOrSlice meetOrSlice, float width, float height, const Box& box) +{ + auto sx = width / box.w; + auto sy = height / box.h; + auto tvx = box.x * sx; + auto tvy = box.y * sy; + + if (align == AspectRatioAlign::None) + return {sx, 0, -tvx, 0, sy, -tvy, 0, 0, 1}; + + //Scale + if (meetOrSlice == AspectRatioMeetOrSlice::Meet) { + if (sx < sy) sy = sx; + else sx = sy; + } else { + if (sx < sy) sx = sy; + else sy = sx; + } + + //Align + tvx = box.x * sx; + tvy = box.y * sy; + auto tvw = box.w * sx; + auto tvh = box.h * sy; + + switch (align) { + case AspectRatioAlign::XMinYMin: { + break; + } + case AspectRatioAlign::XMidYMin: { + tvx -= (width - tvw) * 0.5f; + break; + } + case AspectRatioAlign::XMaxYMin: { + tvx -= width - tvw; + break; + } + case AspectRatioAlign::XMinYMid: { + tvy -= (height - tvh) * 0.5f; + break; + } + case AspectRatioAlign::XMidYMid: { + tvx -= (width - tvw) * 0.5f; + tvy -= (height - tvh) * 0.5f; + break; + } + case AspectRatioAlign::XMaxYMid: { + tvx -= width - tvw; + tvy -= (height - tvh) * 0.5f; + break; + } + case AspectRatioAlign::XMinYMax: { + tvy -= height - tvh; + break; + } + case AspectRatioAlign::XMidYMax: { + tvx -= (width - tvw) * 0.5f; + tvy -= height - tvh; + break; + } + case AspectRatioAlign::XMaxYMax: { + tvx -= width - tvw; + tvy -= height - tvh; + break; + } + default: { + break; + } + } + + return {sx, 0, -tvx, 0, sy, -tvy, 0, 0, 1}; +} + + static unique_ptr _useBuildHelper(const SvgNode* node, const Box& vBox, const string& svgPath, int depth, bool* isMaskWhite) { unique_ptr finalScene; @@ -585,20 +659,8 @@ static unique_ptr _useBuildHelper(const SvgNode* node, const Box& vBox, c Matrix mViewBox = {1, 0, 0, 0, 1, 0, 0, 0, 1}; if ((!mathEqual(width, vw) || !mathEqual(height, vh)) && vw > 0 && vh > 0) { - auto sx = width / vw; - auto sy = height / vh; - if (symbol.preserveAspect) { - if (sx < sy) sy = sx; - else sx = sy; - } - - auto tvx = symbol.vx * sx; - auto tvy = symbol.vy * sy; - auto tvw = vw * sx; - auto tvh = vh * sy; - tvy -= (symbol.h - tvh) * 0.5f; - tvx -= (symbol.w - tvw) * 0.5f; - mViewBox = {sx, 0, -tvx, 0, sy, -tvy, 0, 0, 1}; + Box box = {symbol.vx, symbol.vy, vw, vh}; + mViewBox = _calculateAspectRatioMatrix(symbol.align, symbol.meetOrSlice, width, height, box); } else if (!mathZero(symbol.vx) || !mathZero(symbol.vy)) { mViewBox = {1, 0, -symbol.vx, 0, 1, -symbol.vy, 0, 0, 1}; } @@ -698,36 +760,18 @@ static unique_ptr _sceneBuildHelper(const SvgNode* node, const Box& vBox, /* External Class Implementation */ /************************************************************************/ -unique_ptr svgSceneBuild(SvgNode* node, float vx, float vy, float vw, float vh, float w, float h, bool preserveAspect, const string& svgPath) +unique_ptr svgSceneBuild(SvgNode* node, float vx, float vy, float vw, float vh, float w, float h, AspectRatioAlign align, AspectRatioMeetOrSlice meetOrSlice, const string& svgPath) { + //TODO: aspect ratio is valid only if viewBox was set + if (!node || (node->type != SvgNodeType::Doc)) return nullptr; Box vBox = {vx, vy, vw, vh}; auto docNode = _sceneBuildHelper(node, vBox, svgPath, false, 0); if (!mathEqual(w, vw) || !mathEqual(h, vh)) { - auto sx = w / vw; - auto sy = h / vh; - - if (preserveAspect) { - //Scale - auto scale = sx < sy ? sx : sy; - docNode->scale(scale); - //Align - auto tvx = vx * scale; - auto tvy = vy * scale; - auto tvw = vw * scale; - auto tvh = vh * scale; - tvx -= (w - tvw) * 0.5f; - tvy -= (h - tvh) * 0.5f; - docNode->translate(-tvx, -tvy); - } else { - //Align - auto tvx = vx * sx; - auto tvy = vy * sy; - Matrix m = {sx, 0, -tvx, 0, sy, -tvy, 0, 0, 1}; - docNode->transform(m); - } + Matrix m = _calculateAspectRatioMatrix(align, meetOrSlice, w, h, vBox); + docNode->transform(m); } else if (!mathZero(vx) || !mathZero(vy)) { docNode->translate(-vx, -vy); } diff --git a/src/loaders/svg/tvgSvgSceneBuilder.h b/src/loaders/svg/tvgSvgSceneBuilder.h index cecbbf0..311f3c8 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.h +++ b/src/loaders/svg/tvgSvgSceneBuilder.h @@ -25,6 +25,6 @@ #include "tvgCommon.h" -unique_ptr svgSceneBuild(SvgNode* node, float vx, float vy, float vw, float vh, float w, float h, bool preserveAspect, const string& svgPath); +unique_ptr svgSceneBuild(SvgNode* node, float vx, float vy, float vw, float vh, float w, float h, AspectRatioAlign align, AspectRatioMeetOrSlice meetOrSlice, const string& svgPath); #endif //_TVG_SVG_SCENE_BUILDER_H_ -- 2.7.4 From 4498ba42f4aa02b382efc5b36c663169eae8d366 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 2 Sep 2022 12:02:39 +0900 Subject: [PATCH 14/16] svg loader: remove unused logic. Please keep it simple and easy. Don't leave a chance compiler warn it. Change-Id: I48e7928131172ff50c223fb450e57fb18d237437 --- src/loaders/svg/tvgSvgLoader.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 9a88853..0c69eb8 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -137,11 +137,11 @@ static constexpr struct }; -static bool _parseAspectRatio(const char** content, AspectRatioAlign* align, AspectRatioMeetOrSlice* meetOrSlice) +static void _parseAspectRatio(const char** content, AspectRatioAlign* align, AspectRatioMeetOrSlice* meetOrSlice) { if (!strcmp(*content, "none")) { *align = AspectRatioAlign::None; - return true; + return; } for (unsigned int i = 0; i < sizeof(alignTags) / sizeof(alignTags[0]); i++) { @@ -158,8 +158,6 @@ static bool _parseAspectRatio(const char** content, AspectRatioAlign* align, Asp } else if (!strcmp(*content, "slice")) { *meetOrSlice = AspectRatioMeetOrSlice::Slice; } - - return true; } -- 2.7.4 From f9e9ee44c17db8aa6b2c0aa34e0bb55d4219b4fd Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Thu, 29 Sep 2022 11:11:34 +0900 Subject: [PATCH 15/16] SwRaster: Prevent memory issue If vv goes out of buffer, it can cause potential memory problems. Therefore, an `if condition` is added so that it does not exceed the height of the image. This is temporary fix. Test) meson -Db_sanitize=address,undefined -Dexamples=true . build $ ./build/src/examples/Texmap ==6298==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7f37fd6c2180 at pc 0x7f380d884599 bp 0x7fffb02b2db0 sp 0x7fffb02b2da0 READ of size 4 at 0x7f37fd6c2180 thread T0 #0 0x7f380d884598 in _rasterPolygonImageSegment ../src/lib/sw_engine/tvgSwRasterTexmapInternal.h:107 #1 0x7f380d887694 in _rasterPolygonImage ../src/lib/sw_engine/tvgSwRasterTexmap.h:271 #2 0x7f380d88a598 in _rasterTexmapPolygonMesh ../src/lib/sw_engine/tvgSwRasterTexmap.h:639 #3 0x7f380d89828d in _transformedRGBAImageMesh ../src/lib/sw_engine/tvgSwRaster.cpp:701 #4 0x7f380d89828d in rasterImageMesh(SwSurface*, SwImage*, tvg::Polygon const*, unsigned int, tvg::Matrix const*, SwBBox const&, unsigned int) ../src/lib/sw_engine/tvgSwRaster.cpp:1585 #5 0x7f380d89bf16 in tvg::SwRenderer::renderImageMesh(void*) ../src/lib/sw_engine/tvgSwRenderer.cpp:369 #6 0x7f380d830e7e in tvg::Paint::Impl::render(tvg::RenderMethod&) ../src/lib/tvgPaint.cpp:178 #7 0x7f380d823bd2 in tvg::Canvas::Impl::draw() (/home/junsu/dev/os/thorvg/build/src/examples/../libthorvg.so.0+0x265bd2) #8 0x7f380d821e79 in tvg::Canvas::draw() ../src/lib/tvgCanvas.cpp:60 #9 0x557d07b2d5b6 in drawSwView(void*, _Eo_Opaque*) ../src/examples/Texmap.cpp:103 #10 0x7f380cb7d2aa in evas_process_dirty_pixels ../src/lib/evas/canvas/evas_object_image.c:1894 #11 0x7f380cb7d2aa in _evas_image_pixels_get ../src/lib/evas/canvas/evas_object_image.c:2318 #12 0x7f380cb7d85e in _evas_image_render ../src/lib/evas/canvas/evas_object_image.c:2468 #13 0x7f380cb7ea0c in evas_object_image_render ../src/lib/evas/canvas/evas_object_image.c:2271 #14 0x7f380cbe51db in evas_render_mapped ../src/lib/evas/canvas/evas_render.c:2290 #15 0x7f380cbe6f15 in evas_render_updates_internal_loop ../src/lib/evas/canvas/evas_render.c:3158 #16 0x7f380cbe9912 in evas_render_updates_internal ../src/lib/evas/canvas/evas_render.c:3631 #17 0x7f380cbeb31c in _evas_canvas_render_async ../src/lib/evas/canvas/evas_render.c:4094 #18 0x7f380cb6634a in evas_canvas_render_async ../src/lib/evas/canvas/evas_canvas_eo.c:168 #19 0x7f380cb6fce5 in evas_render_async ../src/lib/evas/canvas/evas_canvas_eo.legacy.c:179 #20 0x7f37f3a81555 in _ecore_evas_x_render ../src/modules/ecore_evas/engines/x/ecore_evas_x.c:761 #21 0x7f3809677e42 in _ecore_evas_idle_enter ../src/lib/ecore_evas/ecore_evas.c:295 #22 0x7f38098a89a4 in _ecore_call_task_cb ../src/lib/ecore/ecore_private.h:456 #23 0x7f38098a89a4 in _ecore_factorized_idle_process ../src/lib/ecore/ecore_idler.c:35 #24 0x7f3809b29081 in _event_callback_call ../src/lib/eo/eo_base_class.c:2114 #25 0x7f3809b29081 in _efl_object_event_callback_call ../src/lib/eo/eo_base_class.c:2186 #26 0x7f3809b22d22 in efl_event_callback_call ../src/lib/eo/eo_base_class.c:2189 #27 0x7f38098aae44 in _ecore_main_loop_iterate_internal ../src/lib/ecore/ecore_main.c:2466 #28 0x7f38098ab689 in _ecore_main_loop_begin ../src/lib/ecore/ecore_main.c:1231 #29 0x7f38098b05e0 in _efl_loop_begin ../src/lib/ecore/efl_loop.c:57 #30 0x7f38098af77c in efl_loop_begin src/lib/ecore/efl_loop.eo.c:28 #31 0x7f38098ab755 in ecore_main_loop_begin ../src/lib/ecore/ecore_main.c:1316 #32 0x7f380d14ba1f in elm_run ../src/lib/elementary/elm_main.c:1359 #33 0x557d07b2d298 in main ../src/examples/Texmap.cpp:176 #34 0x7f380b533c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86) #35 0x557d07b2d3c9 in _start (/home/junsu/dev/os/thorvg/build/src/examples/Texmap+0xb3c9) Change-Id: I732019b5ac8aa01d200c1036e56d5a7143544c30 --- src/lib/sw_engine/tvgSwRasterTexmapInternal.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/lib/sw_engine/tvgSwRasterTexmapInternal.h b/src/lib/sw_engine/tvgSwRasterTexmapInternal.h index 5053629..ab29e8f 100644 --- a/src/lib/sw_engine/tvgSwRasterTexmapInternal.h +++ b/src/lib/sw_engine/tvgSwRasterTexmapInternal.h @@ -104,6 +104,12 @@ ab = (int)(255 * (1 - modff(v, &iptr))); iru = uu + 1; irv = vv + 1; + + //FIXME: If vv goes out of buffer, it can cause potential memory problems. + //Therefore, an `if condition` is added so that it does not exceed the height of the image. + //This is temporary fix. + if (vv >= sh) continue; + px = *(sbuf + (vv * sw) + uu); /* horizontal interpolate */ -- 2.7.4 From 7ac2eb24e7298549a90acc25816e80120efd24ec Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Tue, 4 Oct 2022 10:08:52 +0900 Subject: [PATCH 16/16] SwRaster: Remove comment Change-Id: If45195fcba8dda3d2e08a3884428e365ec6f6f9f --- src/lib/sw_engine/tvgSwRasterTexmapInternal.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRasterTexmapInternal.h b/src/lib/sw_engine/tvgSwRasterTexmapInternal.h index ab29e8f..b578f87 100644 --- a/src/lib/sw_engine/tvgSwRasterTexmapInternal.h +++ b/src/lib/sw_engine/tvgSwRasterTexmapInternal.h @@ -105,9 +105,6 @@ iru = uu + 1; irv = vv + 1; - //FIXME: If vv goes out of buffer, it can cause potential memory problems. - //Therefore, an `if condition` is added so that it does not exceed the height of the image. - //This is temporary fix. if (vv >= sh) continue; px = *(sbuf + (vv * sw) + uu); -- 2.7.4