From 72ac998028633702024dd063cff46ef73d2c841c Mon Sep 17 00:00:00 2001 From: Vincent Torri Date: Sat, 20 Aug 2022 10:55:16 +0200 Subject: [PATCH 01/16] fix compilation of svg2png on Windows Change-Id: I9d7dda51a99d0112357bb61cb19f9b55ce802ac1 --- src/bin/svg2png/svg2png.cpp | 88 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 67 insertions(+), 21 deletions(-) diff --git a/src/bin/svg2png/svg2png.cpp b/src/bin/svg2png/svg2png.cpp index 0699545..71bc1c0 100644 --- a/src/bin/svg2png/svg2png.cpp +++ b/src/bin/svg2png/svg2png.cpp @@ -25,9 +25,17 @@ #include #include #include "lodepng.h" -#include -#include -#include +#ifdef _WIN32 + #include + #ifndef PATH_MAX + #define PATH_MAX MAX_PATH + #endif +#else + #include + #include + #include + #include +#endif using namespace std; @@ -229,11 +237,10 @@ public: for (auto path : paths) { auto real_path = realFile(path); if (real_path) { - DIR* dir = opendir(real_path); - if (dir) { + if (isDirectory(real_path)) { //load from directory cout << "Trying load from directory \"" << real_path << "\"." << endl; - if ((ret = handleDirectory(real_path, dir))) break; + if ((ret = handleDirectory(real_path))) break; } else if (svgFile(path)) { //load single file @@ -286,6 +293,25 @@ private: return path; } + bool isDirectory(const char* path) + { +#ifdef _WIN32 + DWORD attr = GetFileAttributes(path); + if (attr == INVALID_FILE_ATTRIBUTES) + return false; + + return attr & FILE_ATTRIBUTE_DIRECTORY; +#else + struct stat buf; + + if (stat(path, &buf) != 0) { + return false; + } + + return S_ISDIR(buf.st_mode); +#endif + } + int renderFile(const char* path) { if (!path) return 1; @@ -299,15 +325,42 @@ private: return renderer.render(path, width, height, dst, bgColor); } - int handleDirectory(const string& path, DIR* dir) + int handleDirectory(const string& path) { //open directory - if (!dir) { - dir = opendir(path.c_str()); - if (!dir) { - cout << "Couldn't open directory \"" << path.c_str() << "\"." << endl; - return 1; +#ifdef _WIN32 + WIN32_FIND_DATA fd; + HANDLE h = FindFirstFileEx((path + "\\*").c_str(), FindExInfoBasic, &fd, FindExSearchNameMatch, NULL, 0); + if (h == INVALID_HANDLE_VALUE) { + cout << "Couldn't open directory \"" << path.c_str() << "\"." << endl; + return 1; + } + int ret = 0; + do { + if (*fd.cFileName == '.' || *fd.cFileName == '$') continue; + if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + string subpath = string(path); + subpath += '\\'; + subpath += fd.cFileName; + ret = handleDirectory(subpath); + if (ret) break; + + } else { + if (!svgFile(fd.cFileName)) continue; + string fullpath = string(path); + fullpath += '\\'; + fullpath += fd.cFileName; + ret = renderFile(fullpath.c_str()); + if (ret) break; } + } while (FindNextFile(h, &fd)); + + FindClose(h); +#else + DIR* dir = opendir(path.c_str()); + if (!dir) { + cout << "Couldn't open directory \"" << path.c_str() << "\"." << endl; + return 1; } //list directory @@ -317,29 +370,22 @@ private: if (*entry->d_name == '.' || *entry->d_name == '$') continue; if (entry->d_type == DT_DIR) { string subpath = string(path); -#ifdef _WIN32 - subpath += '\\'; -#else subpath += '/'; -#endif subpath += entry->d_name; - ret = handleDirectory(subpath, nullptr); + ret = handleDirectory(subpath); if (ret) break; } else { if (!svgFile(entry->d_name)) continue; string fullpath = string(path); -#ifdef _WIN32 - fullpath += '\\'; -#else fullpath += '/'; -#endif fullpath += entry->d_name; ret = renderFile(fullpath.c_str()); if (ret) break; } } closedir(dir); +#endif return ret; } }; -- 2.7.4 From 73b96e7f911f83b3c488eaf79e389baf19b93a67 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 23 Aug 2022 22:44:24 +0900 Subject: [PATCH 02/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 03/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 04/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 05/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 06/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 07/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 08/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 09/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 10/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 11/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 12/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 13/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 14/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 15/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 13498752a43d407fb268df153d702546aa46cf21 Mon Sep 17 00:00:00 2001 From: jykeon Date: Tue, 14 Mar 2023 17:05:15 +0900 Subject: [PATCH 16/16] Bump up 0.8.5 Change-Id: I8be041ac09cf457cc85d976ac2093b1886b45497 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 191e285..a82c42b 100644 --- a/packaging/thorvg.spec +++ b/packaging/thorvg.spec @@ -1,6 +1,6 @@ Name: thorvg Summary: Thor Vector Graphics Library -Version: 0.8.4 +Version: 0.8.5 Release: 1 Group: Graphics System/Rendering Engine License: MIT -- 2.7.4