From 42281826df99a10ab424b580bb5cbbd55b55fa56 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 8 Apr 2021 17:39:51 +0900 Subject: [PATCH 01/16] loaders svg: fix invalid clip path result. tvg engine expects the valid clippath with valid colors, loaders set any colors values to enable it. this fixes invalid clippath behavior. --- src/loaders/svg/tvgSvgSceneBuilder.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index 9c79c3b..a3299de 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -271,6 +271,7 @@ void _applyProperty(SvgNode* node, Shape* vg, float vx, float vy, float vw, floa auto comp = Shape::gen(); auto child = compNode->child.data; for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) _appendChildShape(*child, comp.get(), vx, vy, vw, vh); + comp->fill(0, 0, 0, 255); vg->composite(move(comp), CompositeMethod::ClipPath); } } @@ -375,6 +376,7 @@ unique_ptr _sceneBuildHelper(const SvgNode* node, float vx, float vy, flo auto comp = Shape::gen(); auto child = compNode->child.data; for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) _appendChildShape(*child, comp.get(), vx, vy, vw, vh); + comp->fill(0, 0, 0, 255); scene->composite(move(comp), CompositeMethod::ClipPath); } } -- 2.7.4 From b8200bebf8a33ae52a57113024f9bf9c25ec4ab9 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 8 Apr 2021 20:47:57 +0900 Subject: [PATCH 02/16] loaders svg: code refactoring ++ clean code. --- src/loaders/svg/tvgSvgLoader.cpp | 6 +-- src/loaders/svg/tvgSvgLoaderCommon.h | 7 +--- src/loaders/svg/tvgSvgSceneBuilder.cpp | 68 +++++++++++----------------------- 3 files changed, 25 insertions(+), 56 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 1a487a7..25c7a42 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -858,8 +858,7 @@ static void _handleTransformAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node static void _handleClipPathAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value) { SvgStyleProperty* style = node->style; - style->comp.flags = (SvgCompositeFlags)((int)style->comp.flags | (int)SvgCompositeFlags::ClipPath); - + style->comp.method = CompositeMethod::ClipPath; int len = strlen(value); if (len >= 3 && !strncmp(value, "url", 3)) style->comp.url = _idFromUrl((const char*)(value + 3)); } @@ -867,8 +866,7 @@ static void _handleClipPathAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, static void _handleMaskAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value) { SvgStyleProperty* style = node->style; - style->comp.flags = (SvgCompositeFlags)((int)style->comp.flags | (int)SvgCompositeFlags::AlphaMask); - + style->comp.method = CompositeMethod::AlphaMask; int len = strlen(value); if (len >= 3 && !strncmp(value, "url", 3)) style->comp.url = _idFromUrl((const char*)(value + 3)); } diff --git a/src/loaders/svg/tvgSvgLoaderCommon.h b/src/loaders/svg/tvgSvgLoaderCommon.h index f985b24..b639efe 100644 --- a/src/loaders/svg/tvgSvgLoaderCommon.h +++ b/src/loaders/svg/tvgSvgLoaderCommon.h @@ -62,11 +62,6 @@ enum class SvgLengthType In, }; -enum class SvgCompositeFlags -{ - ClipPath = 0x01, - AlphaMask = 0x02, -}; enum class SvgFillFlags { @@ -227,7 +222,7 @@ struct SvgGradientStop struct SvgComposite { - SvgCompositeFlags flags; + CompositeMethod method; //TODO: Currently support either one method string *url; SvgNode* node; }; diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index a3299de..aa45fab 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -203,6 +203,7 @@ void _appendChildShape(SvgNode* node, Shape* shape, float vx, float vy, float vw } } + void _applyProperty(SvgNode* node, Shape* vg, float vx, float vy, float vw, float vh) { SvgStyleProperty* style = node->style; @@ -243,8 +244,9 @@ void _applyProperty(SvgNode* node, Shape* vg, float vx, float vy, float vw, floa vg->stroke(style->stroke.width); vg->stroke(style->stroke.cap); vg->stroke(style->stroke.join); - if (style->stroke.dash.array.count > 0) + if (style->stroke.dash.array.count > 0) { vg->stroke(style->stroke.dash.array.data, style->stroke.dash.array.count); + } //If stroke property is nullptr then do nothing if (style->stroke.paint.none) { @@ -256,34 +258,20 @@ void _applyProperty(SvgNode* node, Shape* vg, float vx, float vy, float vw, floa } else if (style->stroke.paint.curColor) { //Apply the current style color vg->stroke(style->r, style->g, style->b, style->stroke.opacity); - } else { //Apply the stroke color vg->stroke(style->stroke.paint.r, style->stroke.paint.g, style->stroke.paint.b, style->stroke.opacity); } //Apply composite node - if (style->comp.node) { - //Composite ClipPath - if (((int)style->comp.flags & (int)SvgCompositeFlags::ClipPath)) { - auto compNode = style->comp.node; - if (compNode->child.count > 0) { - auto comp = Shape::gen(); - auto child = compNode->child.data; - for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) _appendChildShape(*child, comp.get(), vx, vy, vw, vh); - comp->fill(0, 0, 0, 255); - vg->composite(move(comp), CompositeMethod::ClipPath); - } - } - //Composite Alpha Mask - if (((int)style->comp.flags & (int)SvgCompositeFlags::AlphaMask)) { - auto compNode = style->comp.node; - if (compNode->child.count > 0) { - auto comp = Shape::gen(); - auto child = compNode->child.data; - for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) _appendChildShape(*child, comp.get(), vx, vy, vw, vh); - vg->composite(move(comp), CompositeMethod::AlphaMask); - } + if (style->comp.node && (style->comp.method != CompositeMethod::None)) { + auto compNode = style->comp.node; + if (compNode->child.count > 0) { + auto comp = Shape::gen(); + auto child = compNode->child.data; + for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) _appendChildShape(*child, comp.get(), vx, vy, vw, vh); + if (style->comp.method == CompositeMethod::ClipPath) comp->fill(0, 0, 0, 255); + vg->composite(move(comp), style->comp.method); } } } @@ -303,8 +291,9 @@ bool _appendShape(SvgNode* node, Shape* shape, float vx, float vy, float vw, flo switch (node->type) { case SvgNodeType::Path: { if (node->node.path.path) { - if (svgPathToTvgPath(node->node.path.path->c_str(), cmds, pts)) + if (svgPathToTvgPath(node->node.path.path->c_str(), cmds, pts)) { shape->appendPath(cmds.data, cmds.count, pts.data, pts.count); + } } break; } @@ -368,27 +357,14 @@ unique_ptr _sceneBuildHelper(const SvgNode* node, float vx, float vy, flo } } //Apply composite node - if (node->style->comp.node) { - //Composite ClipPath - if (((int)node->style->comp.flags & (int)SvgCompositeFlags::ClipPath)) { - auto compNode = node->style->comp.node; - if (compNode->child.count > 0) { - auto comp = Shape::gen(); - auto child = compNode->child.data; - for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) _appendChildShape(*child, comp.get(), vx, vy, vw, vh); - comp->fill(0, 0, 0, 255); - scene->composite(move(comp), CompositeMethod::ClipPath); - } - } - //Composite AlphaMask - if (((int)node->style->comp.flags & (int)SvgCompositeFlags::AlphaMask)) { - auto compNode = node->style->comp.node; - if (compNode->child.count > 0) { - auto comp = Shape::gen(); - auto child = compNode->child.data; - for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) _appendChildShape(*child, comp.get(), vx, vy, vw, vh); - scene->composite(move(comp), CompositeMethod::AlphaMask); - } + if (node->style->comp.node && (node->style->comp.method != CompositeMethod::None)) { + auto compNode = node->style->comp.node; + if (compNode->child.count > 0) { + auto comp = Shape::gen(); + auto child = compNode->child.data; + for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) _appendChildShape(*child, comp.get(), vx, vy, vw, vh); + if (node->style->comp.method == CompositeMethod::ClipPath) comp->fill(0, 0, 0, 255); + scene->composite(move(comp), node->style->comp.method); } } scene->opacity(node->style->opacity); @@ -412,7 +388,7 @@ unique_ptr _buildRoot(const SvgNode* node, float vx, float vy, float vw, viewBoxClip->fill(0, 0, 0, 255); auto compositeLayer = Scene::gen(); - compositeLayer->composite(move(viewBoxClip), tvg::CompositeMethod::ClipPath); + compositeLayer->composite(move(viewBoxClip), CompositeMethod::ClipPath); compositeLayer->push(move(docNode)); root = Scene::gen(); -- 2.7.4 From d7ce02941efa53f543d376667a0617f1df5f7add Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 9 Apr 2021 11:02:35 +0900 Subject: [PATCH 03/16] loaders svg: ++ log info for wrong situation. if either log is printed, we need to improve the composition method. --- src/loaders/svg/tvgSvgLoader.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 25c7a42..dcb69d2 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -858,6 +858,9 @@ static void _handleTransformAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node static void _handleClipPathAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value) { SvgStyleProperty* style = node->style; +#ifdef THORVG_LOG_ENABLED + if (style->comp.method != CompositeMethod::None) printf("SVG: Multiple Composition Tried!\n"); +#endif style->comp.method = CompositeMethod::ClipPath; int len = strlen(value); if (len >= 3 && !strncmp(value, "url", 3)) style->comp.url = _idFromUrl((const char*)(value + 3)); @@ -866,6 +869,9 @@ static void _handleClipPathAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, static void _handleMaskAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value) { SvgStyleProperty* style = node->style; +#ifdef THORVG_LOG_ENABLED + if (style->comp.method != CompositeMethod::None) printf("SVG: Multiple Composition Tried!\n"); +#endif style->comp.method = CompositeMethod::AlphaMask; int len = strlen(value); if (len >= 3 && !strncmp(value, "url", 3)) style->comp.url = _idFromUrl((const char*)(value + 3)); -- 2.7.4 From d17b400e8f5542c9f88e81661343023425eea873 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 9 Apr 2021 15:34:34 +0900 Subject: [PATCH 04/16] loaders svg: code refactoring clean up code and remove unnecessary internal class. this also helps to reduce binary size by 5.5kb no logical changes. --- src/loaders/svg/tvgSvgLoader.cpp | 15 ++++---- src/loaders/svg/tvgSvgLoader.h | 3 +- src/loaders/svg/tvgSvgPath.cpp | 13 +++++-- src/loaders/svg/tvgSvgPath.h | 2 +- src/loaders/svg/tvgSvgSceneBuilder.cpp | 62 ++++++++++++++++++---------------- src/loaders/svg/tvgSvgSceneBuilder.h | 11 ++---- src/loaders/svg/tvgXmlParser.cpp | 10 ++++++ 7 files changed, 63 insertions(+), 53 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index dcb69d2..1114413 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -19,14 +19,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#include #include -#include #include #include #include "tvgLoaderMgr.h" #include "tvgXmlParser.h" #include "tvgSvgLoader.h" +#include "tvgSvgSceneBuilder.h" /************************************************************************/ /* Internal Class Implementation */ @@ -855,6 +854,7 @@ static void _handleTransformAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node node->transform = _parseTransformationMatrix(value); } + static void _handleClipPathAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value) { SvgStyleProperty* style = node->style; @@ -866,6 +866,7 @@ static void _handleClipPathAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, if (len >= 3 && !strncmp(value, "url", 3)) style->comp.url = _idFromUrl((const char*)(value + 3)); } + static void _handleMaskAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value) { SvgStyleProperty* style = node->style; @@ -877,6 +878,7 @@ static void _handleMaskAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, con if (len >= 3 && !strncmp(value, "url", 3)) style->comp.url = _idFromUrl((const char*)(value + 3)); } + static void _handleDisplayAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value) { //TODO : The display attribute can have various values as well as "none". @@ -890,12 +892,7 @@ static void _handleDisplayAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, typedef void (*styleMethod)(SvgLoaderData* loader, SvgNode* node, const char* value); - -#define STYLE_DEF(Name, Name1) \ - { \ -#Name, sizeof(#Name), _handle##Name1##Attr \ - } - +#define STYLE_DEF(Name, Name1) { #Name, sizeof(#Name), _handle##Name1##Attr } static constexpr struct { @@ -2589,7 +2586,7 @@ void SvgLoader::run(unsigned tid) _updateComposite(loaderData.doc, loaderData.doc); if (defs) _updateComposite(loaderData.doc, defs); } - root = builder.build(loaderData.doc); + root = svgSceneBuild(loaderData.doc); }; diff --git a/src/loaders/svg/tvgSvgLoader.h b/src/loaders/svg/tvgSvgLoader.h index bd442bc..29ec944 100644 --- a/src/loaders/svg/tvgSvgLoader.h +++ b/src/loaders/svg/tvgSvgLoader.h @@ -23,7 +23,7 @@ #define _TVG_SVG_LOADER_H_ #include "tvgTaskScheduler.h" -#include "tvgSvgSceneBuilder.h" +#include "tvgSvgLoaderCommon.h" class SvgLoader : public Loader, public Task { @@ -33,7 +33,6 @@ public: uint32_t size = 0; SvgLoaderData loaderData; - SvgSceneBuilder builder; unique_ptr root; SvgLoader(); diff --git a/src/loaders/svg/tvgSvgPath.cpp b/src/loaders/svg/tvgSvgPath.cpp index d7eaefc..8993314 100644 --- a/src/loaders/svg/tvgSvgPath.cpp +++ b/src/loaders/svg/tvgSvgPath.cpp @@ -19,12 +19,14 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#include #include -#include -#include +#include "tvgSvgLoaderCommon.h" #include "tvgSvgPath.h" +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + static char* _skipComma(const char* content) { while (*content && isspace(*content)) { @@ -491,6 +493,11 @@ static char* _nextCommand(char* path, char* cmd, float* arr, int* count) } +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + + bool svgPathToTvgPath(const char* svgPath, Array& cmds, Array& pts) { float numberArray[7]; diff --git a/src/loaders/svg/tvgSvgPath.h b/src/loaders/svg/tvgSvgPath.h index a3391d8..7f26c4a 100644 --- a/src/loaders/svg/tvgSvgPath.h +++ b/src/loaders/svg/tvgSvgPath.h @@ -23,7 +23,7 @@ #ifndef _TVG_SVG_PATH_H_ #define _TVG_SVG_PATH_H_ -#include "tvgSvgLoaderCommon.h" +#include bool svgPathToTvgPath(const char* svgPath, Array& cmds, Array& pts); diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index aa45fab..a1c9835 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -20,19 +20,24 @@ * SOFTWARE. */ #include -#include +#include "tvgSvgLoaderCommon.h" #include "tvgSvgSceneBuilder.h" #include "tvgSvgPath.h" -bool _appendShape(SvgNode* node, Shape* shape, float vx, float vy, float vw, float vh); +static bool _appendShape(SvgNode* node, Shape* shape, float vx, float vy, float vw, float vh); -bool _isGroupType(SvgNodeType type) +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +static inline bool _isGroupType(SvgNodeType type) { if (type == SvgNodeType::Doc || type == SvgNodeType::G || type == SvgNodeType::ClipPath) return true; return false; } -unique_ptr _applyLinearGradientProperty(SvgStyleGradient* g, const Shape* vg, float rx, float ry, float rw, float rh) + +static unique_ptr _applyLinearGradientProperty(SvgStyleGradient* g, const Shape* vg, float rx, float ry, float rw, float rh) { Fill::ColorStop* stops; int stopCount = 0; @@ -112,7 +117,7 @@ unique_ptr _applyLinearGradientProperty(SvgStyleGradient* g, con } -unique_ptr _applyRadialGradientProperty(SvgStyleGradient* g, const Shape* vg, float rx, float ry, float rw, float rh) +static unique_ptr _applyRadialGradientProperty(SvgStyleGradient* g, const Shape* vg, float rx, float ry, float rw, float rh) { Fill::ColorStop *stops; int stopCount = 0; @@ -194,7 +199,8 @@ unique_ptr _applyRadialGradientProperty(SvgStyleGradient* g, con return fillGrad; } -void _appendChildShape(SvgNode* node, Shape* shape, float vx, float vy, float vw, float vh) + +static void _appendChildShape(SvgNode* node, Shape* shape, float vx, float vy, float vw, float vh) { _appendShape(node, shape, vx, vy, vw, vh); if (node->child.count > 0) { @@ -204,7 +210,7 @@ void _appendChildShape(SvgNode* node, Shape* shape, float vx, float vy, float vw } -void _applyProperty(SvgNode* node, Shape* vg, float vx, float vy, float vw, float vh) +static void _applyProperty(SvgNode* node, Shape* vg, float vx, float vy, float vw, float vh) { SvgStyleProperty* style = node->style; @@ -276,14 +282,16 @@ void _applyProperty(SvgNode* node, Shape* vg, float vx, float vy, float vw, floa } } -unique_ptr _shapeBuildHelper(SvgNode* node, float vx, float vy, float vw, float vh) + +static unique_ptr _shapeBuildHelper(SvgNode* node, float vx, float vy, float vw, float vh) { auto shape = Shape::gen(); if (_appendShape(node, shape.get(), vx, vy, vw, vh)) return shape; else return nullptr; } -bool _appendShape(SvgNode* node, Shape* shape, float vx, float vy, float vw, float vh) + +static bool _appendShape(SvgNode* node, Shape* shape, float vx, float vy, float vw, float vh) { Array cmds; Array pts; @@ -340,7 +348,8 @@ bool _appendShape(SvgNode* node, Shape* shape, float vx, float vy, float vw, flo return true; } -unique_ptr _sceneBuildHelper(const SvgNode* node, float vx, float vy, float vw, float vh) + +static unique_ptr _sceneBuildHelper(const SvgNode* node, float vx, float vy, float vw, float vh) { if (_isGroupType(node->type)) { auto scene = Scene::gen(); @@ -374,8 +383,20 @@ unique_ptr _sceneBuildHelper(const SvgNode* node, float vx, float vy, flo return nullptr; } -unique_ptr _buildRoot(const SvgNode* node, float vx, float vy, float vw, float vh) + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +unique_ptr svgSceneBuild(SvgNode* node) { + if (!node || (node->type != SvgNodeType::Doc)) return nullptr; + + auto vx = node->node.doc.vx; + auto vy = node->node.doc.vy; + auto vw = node->node.doc.vw; + auto vh = node->node.doc.vh; + unique_ptr root; auto docNode = _sceneBuildHelper(node, vx, vy, vw, vh); float x, y, w, h; @@ -397,21 +418,4 @@ unique_ptr _buildRoot(const SvgNode* node, float vx, float vy, float vw, root = move(docNode); } return root; -} - -SvgSceneBuilder::SvgSceneBuilder() -{ -} - - -SvgSceneBuilder::~SvgSceneBuilder() -{ -} - - -unique_ptr SvgSceneBuilder::build(SvgNode* node) -{ - if (!node || (node->type != SvgNodeType::Doc)) return nullptr; - - return _buildRoot(node, node->node.doc.vx, node->node.doc.vy, node->node.doc.vw, node->node.doc.vh); -} +} \ No newline at end of file diff --git a/src/loaders/svg/tvgSvgSceneBuilder.h b/src/loaders/svg/tvgSvgSceneBuilder.h index 5456fa6..d1b8f8c 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.h +++ b/src/loaders/svg/tvgSvgSceneBuilder.h @@ -23,15 +23,8 @@ #ifndef _TVG_SVG_SCENE_BUILDER_H_ #define _TVG_SVG_SCENE_BUILDER_H_ -#include "tvgSvgLoaderCommon.h" +#include "tvgCommon.h" -class SvgSceneBuilder -{ -public: - SvgSceneBuilder(); - ~SvgSceneBuilder(); - - unique_ptr build(SvgNode* node); -}; +unique_ptr svgSceneBuild(SvgNode* node); #endif //_TVG_SVG_SCENE_BUILDER_H_ diff --git a/src/loaders/svg/tvgXmlParser.cpp b/src/loaders/svg/tvgXmlParser.cpp index c5c8e6a..1fe223a 100644 --- a/src/loaders/svg/tvgXmlParser.cpp +++ b/src/loaders/svg/tvgXmlParser.cpp @@ -22,6 +22,7 @@ #include #include + #ifdef _WIN32 #include #else @@ -30,6 +31,10 @@ #include "tvgXmlParser.h" +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + #ifdef THORVG_LOG_ENABLED #include @@ -199,6 +204,11 @@ static const char* _simpleXmlFindDoctypeChildEndTag(const char* itr, const char* } +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + + bool simpleXmlParseAttributes(const char* buf, unsigned bufLength, simpleXMLAttributeCb func, const void* data) { const char *itr = buf, *itrEnd = buf + bufLength; -- 2.7.4 From e89362505e945bb3934d4dd5ebf30356daf97ca9 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 9 Apr 2021 15:57:32 +0900 Subject: [PATCH 05/16] loaders svg: prevent composition setting if the result shape is invalid. Current loader could return invalid shapes -default, from _appendShape()- by a certain interpretation result, Though it's a wrong or exception case, we can prevent worse case by avoiding it. --- src/loaders/svg/tvgSvgSceneBuilder.cpp | 35 +++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index a1c9835..f620596 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -200,13 +200,20 @@ static unique_ptr _applyRadialGradientProperty(SvgStyleGradient* } -static void _appendChildShape(SvgNode* node, Shape* shape, float vx, float vy, float vw, float vh) +static bool _appendChildShape(SvgNode* node, Shape* shape, float vx, float vy, float vw, float vh) { - _appendShape(node, shape, vx, vy, vw, vh); + auto valid = false; + + if (_appendShape(node, shape, vx, vy, vw, vh)) valid = true; + if (node->child.count > 0) { auto child = node->child.data; - for (uint32_t i = 0; i < node->child.count; ++i, ++child) _appendChildShape(*child, shape, vx, vy, vw, vh); + for (uint32_t i = 0; i < node->child.count; ++i, ++child) { + if (_appendChildShape(*child, shape, vx, vy, vw, vh)) valid = true; + } } + + return valid; } @@ -275,9 +282,14 @@ static void _applyProperty(SvgNode* node, Shape* vg, float vx, float vy, float v if (compNode->child.count > 0) { auto comp = Shape::gen(); auto child = compNode->child.data; - for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) _appendChildShape(*child, comp.get(), vx, vy, vw, vh); - if (style->comp.method == CompositeMethod::ClipPath) comp->fill(0, 0, 0, 255); - vg->composite(move(comp), style->comp.method); + auto valid = false; //Composite only when valid shapes are existed + for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) { + if (_appendChildShape(*child, comp.get(), vx, vy, vw, vh)) valid = true; + } + if (valid) { + if (style->comp.method == CompositeMethod::ClipPath) comp->fill(0, 0, 0, 255); + vg->composite(move(comp), style->comp.method); + } } } } @@ -371,9 +383,14 @@ static unique_ptr _sceneBuildHelper(const SvgNode* node, float vx, float if (compNode->child.count > 0) { auto comp = Shape::gen(); auto child = compNode->child.data; - for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) _appendChildShape(*child, comp.get(), vx, vy, vw, vh); - if (node->style->comp.method == CompositeMethod::ClipPath) comp->fill(0, 0, 0, 255); - scene->composite(move(comp), node->style->comp.method); + auto valid = false; //Composite only when valid shapes are existed + for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) { + if (_appendChildShape(*child, comp.get(), vx, vy, vw, vh)) valid = true; + } + if (valid) { + if (node->style->comp.method == CompositeMethod::ClipPath) comp->fill(0, 0, 0, 255); + scene->composite(move(comp), node->style->comp.method); + } } } scene->opacity(node->style->opacity); -- 2.7.4 From 5e918ee1666150ad8fdaa35aa6ca5b4907cbddcb Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 9 Apr 2021 16:44:46 +0900 Subject: [PATCH 06/16] loaders svg: set default color for composition paint. not only clippath but alpha compositions might also have any valid color. Set it default and let it override values while appending shapes if it's necessary. --- src/loaders/svg/tvgSvgSceneBuilder.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index f620596..5e8da35 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -281,15 +281,13 @@ static void _applyProperty(SvgNode* node, Shape* vg, float vx, float vy, float v auto compNode = style->comp.node; if (compNode->child.count > 0) { auto comp = Shape::gen(); + comp->fill(255, 255, 255, 255); auto child = compNode->child.data; auto valid = false; //Composite only when valid shapes are existed for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) { if (_appendChildShape(*child, comp.get(), vx, vy, vw, vh)) valid = true; } - if (valid) { - if (style->comp.method == CompositeMethod::ClipPath) comp->fill(0, 0, 0, 255); - vg->composite(move(comp), style->comp.method); - } + if (valid) vg->composite(move(comp), style->comp.method); } } } @@ -382,15 +380,13 @@ static unique_ptr _sceneBuildHelper(const SvgNode* node, float vx, float auto compNode = node->style->comp.node; if (compNode->child.count > 0) { auto comp = Shape::gen(); + comp->fill(255, 255, 255, 255); auto child = compNode->child.data; auto valid = false; //Composite only when valid shapes are existed for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) { if (_appendChildShape(*child, comp.get(), vx, vy, vw, vh)) valid = true; } - if (valid) { - if (node->style->comp.method == CompositeMethod::ClipPath) comp->fill(0, 0, 0, 255); - scene->composite(move(comp), node->style->comp.method); - } + if (valid) scene->composite(move(comp), node->style->comp.method); } } scene->opacity(node->style->opacity); -- 2.7.4 From e4635d39ae0d2816aed48b1a2e6cdf8786b1262a Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Fri, 9 Apr 2021 12:34:56 +0200 Subject: [PATCH 07/16] sw_engine: fixing stroke gradient Instead of checking the stroke's fill, the shape's fill was checked. As a result the improper rastering function was called (or none). --- src/lib/sw_engine/tvgSwRaster.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index b9ab35c..b117412 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -1036,10 +1036,10 @@ bool rasterGradientStroke(SwSurface* surface, SwShape* shape, unsigned id) if (!shape->stroke->fill || !shape->strokeRle) return false; if (id == FILL_ID_LINEAR) { - if (shape->fill && shape->fill->translucent) return _rasterTranslucentLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill); + if (shape->stroke->fill->translucent) return _rasterTranslucentLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill); return _rasterOpaqueLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill); } else { - if (shape->fill && shape->fill->translucent) return _rasterTranslucentRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill); + if (shape->stroke->fill->translucent) return _rasterTranslucentRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill); return _rasterOpaqueRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill); } -- 2.7.4 From 709341fee3630598e68a74fc25e509f6cc7a6687 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 9 Apr 2021 20:50:01 +0900 Subject: [PATCH 08/16] loader svg: fix composition(mask/clip) issue. composition target missed transform of its source. That brings incorrect composition area. This fixes it. Change-Id: I7e1adc225af2c0177581b3505288de50d77cc411 --- src/loaders/svg/tvgSvgSceneBuilder.cpp | 52 ++++++++++++++++------------------ 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index 5e8da35..3b37f31 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -217,6 +217,28 @@ static bool _appendChildShape(SvgNode* node, Shape* shape, float vx, float vy, f } +static void _applyComposition(Paint* paint, const SvgNode* node, float vx, float vy, float vw, float vh) +{ + if (node->style->comp.method == CompositeMethod::None) return; + + auto compNode = node->style->comp.node; + if (!compNode || compNode->child.count == 0) return; + + auto comp = Shape::gen(); + comp->fill(255, 255, 255, 255); + if (node->transform) comp->transform(*node->transform); + + auto child = compNode->child.data; + auto valid = false; //Composite only when valid shapes are existed + + for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) { + if (_appendChildShape(*child, comp.get(), vx, vy, vw, vh)) valid = true; + } + + if (valid) paint->composite(move(comp), node->style->comp.method); +} + + static void _applyProperty(SvgNode* node, Shape* vg, float vx, float vy, float vw, float vh) { SvgStyleProperty* style = node->style; @@ -276,20 +298,7 @@ static void _applyProperty(SvgNode* node, Shape* vg, float vx, float vy, float v vg->stroke(style->stroke.paint.r, style->stroke.paint.g, style->stroke.paint.b, style->stroke.opacity); } - //Apply composite node - if (style->comp.node && (style->comp.method != CompositeMethod::None)) { - auto compNode = style->comp.node; - if (compNode->child.count > 0) { - auto comp = Shape::gen(); - comp->fill(255, 255, 255, 255); - auto child = compNode->child.data; - auto valid = false; //Composite only when valid shapes are existed - for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) { - if (_appendChildShape(*child, comp.get(), vx, vy, vw, vh)) valid = true; - } - if (valid) vg->composite(move(comp), style->comp.method); - } - } + _applyComposition(vg, node, vx, vy, vw, vh); } @@ -375,20 +384,7 @@ static unique_ptr _sceneBuildHelper(const SvgNode* node, float vx, float if (shape) scene->push(move(shape)); } } - //Apply composite node - if (node->style->comp.node && (node->style->comp.method != CompositeMethod::None)) { - auto compNode = node->style->comp.node; - if (compNode->child.count > 0) { - auto comp = Shape::gen(); - comp->fill(255, 255, 255, 255); - auto child = compNode->child.data; - auto valid = false; //Composite only when valid shapes are existed - for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) { - if (_appendChildShape(*child, comp.get(), vx, vy, vw, vh)) valid = true; - } - if (valid) scene->composite(move(comp), node->style->comp.method); - } - } + _applyComposition(scene.get(), node, vx, vy, vw, vh); scene->opacity(node->style->opacity); } return scene; -- 2.7.4 From 25c05b4be13eb01b382a56307dffcaf1115329de Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 9 Apr 2021 21:27:38 +0900 Subject: [PATCH 09/16] bump up v0.0.7 Change-Id: I3e8d10dc94f2931b2898a02c86d851a964f0acb6 --- packaging/thorvg.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/thorvg.spec b/packaging/thorvg.spec index 87ad72d..5feb7f2 100644 --- a/packaging/thorvg.spec +++ b/packaging/thorvg.spec @@ -1,6 +1,6 @@ Name: thorvg Summary: Thor Vector Graphics Library -Version: 0.0.6 +Version: 0.0.7 Release: 1 Group: Graphics System/Rendering Engine License: MIT -- 2.7.4 From f988f40e06aa008dd68e53302f9395487911ad02 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 9 Apr 2021 21:42:12 +0900 Subject: [PATCH 10/16] sync versioning 0.1.0 Change-Id: I6b4eb3d603963d68b01bcf398f59e336ad18e46d --- packaging/thorvg.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/thorvg.spec b/packaging/thorvg.spec index 5feb7f2..e0657bc 100644 --- a/packaging/thorvg.spec +++ b/packaging/thorvg.spec @@ -1,6 +1,6 @@ Name: thorvg Summary: Thor Vector Graphics Library -Version: 0.0.7 +Version: 0.1.0 Release: 1 Group: Graphics System/Rendering Engine License: MIT -- 2.7.4 From 7ad1297bf5583be6d757c61454169400f20fbacc Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 9 Apr 2021 22:18:57 +0900 Subject: [PATCH 11/16] wasm: fix compile errors. --- src/lib/sw_engine/tvgSwMath.cpp | 10 +++++----- src/lib/tvgRender.h | 8 ++++---- src/loaders/svg/tvgSvgPath.cpp | 2 ++ src/loaders/svg/tvgSvgSceneBuilder.cpp | 3 ++- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/lib/sw_engine/tvgSwMath.cpp b/src/lib/sw_engine/tvgSwMath.cpp index 77c8b8f..19c2388 100644 --- a/src/lib/sw_engine/tvgSwMath.cpp +++ b/src/lib/sw_engine/tvgSwMath.cpp @@ -458,10 +458,10 @@ bool mathUpdateOutlineBBox(const SwOutline* outline, const SwBBox& clipRegion, S renderRegion.min.y = yMin >> 6; renderRegion.max.y = (yMax + 63) >> 6; - renderRegion.max.x = min(renderRegion.max.x, clipRegion.max.x); - renderRegion.max.y = min(renderRegion.max.y, clipRegion.max.y); - renderRegion.min.x = max(renderRegion.min.x, clipRegion.min.x); - renderRegion.min.y = max(renderRegion.min.y, clipRegion.min.y); + renderRegion.max.x = (renderRegion.max.x < clipRegion.max.x) ? renderRegion.max.x : clipRegion.max.x; + renderRegion.max.y = (renderRegion.max.y < clipRegion.max.y) ? renderRegion.max.y : clipRegion.max.y; + renderRegion.min.x = (renderRegion.min.x > clipRegion.min.x) ? renderRegion.min.x : clipRegion.min.x; + renderRegion.min.y = (renderRegion.min.y > clipRegion.min.y) ? renderRegion.min.y : clipRegion.min.y; //Check valid region if (renderRegion.max.x - renderRegion.min.x < 1 && renderRegion.max.y - renderRegion.min.y < 1) return false; @@ -471,4 +471,4 @@ bool mathUpdateOutlineBBox(const SwOutline* outline, const SwBBox& clipRegion, S renderRegion.max.x <= clipRegion.min.x || renderRegion.max.y <= clipRegion.min.y) return false; return true; -} \ No newline at end of file +} diff --git a/src/lib/tvgRender.h b/src/lib/tvgRender.h index 510420e..16da972 100644 --- a/src/lib/tvgRender.h +++ b/src/lib/tvgRender.h @@ -56,10 +56,10 @@ struct RenderRegion { auto x2 = rhs.x + rhs.w; auto y2 = rhs.y + rhs.h; - x = max(x, rhs.x); - y = max(y, rhs.y); - w = min(x1, x2) - x; - h = min(y1, y2) - y; + x = (x > rhs.x) ? x : rhs.x; + y = (y > rhs.y) ? y : rhs.y; + w = ((x1 < x2) ? x1 : x2) - x; + h = ((y1 < y2) ? y1 : y2) - y; } }; diff --git a/src/loaders/svg/tvgSvgPath.cpp b/src/loaders/svg/tvgSvgPath.cpp index 8993314..08a3a54 100644 --- a/src/loaders/svg/tvgSvgPath.cpp +++ b/src/loaders/svg/tvgSvgPath.cpp @@ -20,6 +20,8 @@ * SOFTWARE. */ #include +#include +#include #include "tvgSvgLoaderCommon.h" #include "tvgSvgPath.h" diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index 3b37f31..b2be859 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -20,6 +20,7 @@ * SOFTWARE. */ #include +#include #include "tvgSvgLoaderCommon.h" #include "tvgSvgSceneBuilder.h" #include "tvgSvgPath.h" @@ -427,4 +428,4 @@ unique_ptr svgSceneBuild(SvgNode* node) root = move(docNode); } return root; -} \ No newline at end of file +} -- 2.7.4 From 400587a18d05877078874855d0d4e373b796b19a Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 13 Apr 2021 17:05:08 +0900 Subject: [PATCH 12/16] loaders svg: code refactoring. keep it clean & neat within tvg coding convention. --- src/loaders/svg/tvgSvgLoader.cpp | 66 ++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 40 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 1114413..a8a863f 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -37,15 +37,16 @@ typedef SvgStyleGradient* (*GradientFactoryMethod)(SvgLoaderData* loader, const static char* _skipSpace(const char* str, const char* end) { - while (((end != nullptr && str < end) || (end == nullptr && *str != '\0')) && isspace(*str)) + while (((end && str < end) || (!end && *str != '\0')) && isspace(*str)) { ++str; - return (char*)str; + } + return (char*) str; } static string* _copyId(const char* str) { - if (str == nullptr) return nullptr; + if (!str) return nullptr; return new string(str); } @@ -554,23 +555,19 @@ static constexpr struct }; -static void _matrixCompose(const Matrix* m1, - const Matrix* m2, - Matrix* dst) +static void _matrixCompose(const Matrix* m1, const Matrix* m2, Matrix* dst) { - float a11, a12, a13, a21, a22, a23, a31, a32, a33; - - a11 = (m1->e11 * m2->e11) + (m1->e12 * m2->e21) + (m1->e13 * m2->e31); - a12 = (m1->e11 * m2->e12) + (m1->e12 * m2->e22) + (m1->e13 * m2->e32); - a13 = (m1->e11 * m2->e13) + (m1->e12 * m2->e23) + (m1->e13 * m2->e33); + auto a11 = (m1->e11 * m2->e11) + (m1->e12 * m2->e21) + (m1->e13 * m2->e31); + auto a12 = (m1->e11 * m2->e12) + (m1->e12 * m2->e22) + (m1->e13 * m2->e32); + auto a13 = (m1->e11 * m2->e13) + (m1->e12 * m2->e23) + (m1->e13 * m2->e33); - a21 = (m1->e21 * m2->e11) + (m1->e22 * m2->e21) + (m1->e23 * m2->e31); - a22 = (m1->e21 * m2->e12) + (m1->e22 * m2->e22) + (m1->e23 * m2->e32); - a23 = (m1->e21 * m2->e13) + (m1->e22 * m2->e23) + (m1->e23 * m2->e33); + auto a21 = (m1->e21 * m2->e11) + (m1->e22 * m2->e21) + (m1->e23 * m2->e31); + auto a22 = (m1->e21 * m2->e12) + (m1->e22 * m2->e22) + (m1->e23 * m2->e32); + auto a23 = (m1->e21 * m2->e13) + (m1->e22 * m2->e23) + (m1->e23 * m2->e33); - a31 = (m1->e31 * m2->e11) + (m1->e32 * m2->e21) + (m1->e33 * m2->e31); - a32 = (m1->e31 * m2->e12) + (m1->e32 * m2->e22) + (m1->e33 * m2->e32); - a33 = (m1->e31 * m2->e13) + (m1->e32 * m2->e23) + (m1->e33 * m2->e33); + auto a31 = (m1->e31 * m2->e11) + (m1->e32 * m2->e21) + (m1->e33 * m2->e31); + auto a32 = (m1->e31 * m2->e12) + (m1->e32 * m2->e22) + (m1->e33 * m2->e32); + auto a33 = (m1->e31 * m2->e13) + (m1->e32 * m2->e23) + (m1->e33 * m2->e33); dst->e11 = a11; dst->e12 = a12; @@ -589,16 +586,17 @@ static void _matrixCompose(const Matrix* m1, */ static Matrix* _parseTransformationMatrix(const char* value) { + auto matrix = (Matrix*)malloc(sizeof(Matrix)); + if (!matrix) return nullptr; + *matrix = { 1, 0, 0, 0, 1, 0, 0, 0, 1 }; + float points[8]; int ptCount = 0; float sx, sy; MatrixState state = MatrixState::Unknown; - Matrix* matrix = (Matrix*)calloc(1, sizeof(Matrix)); char* str = (char*)value; char* end = str + strlen(str); - if (!matrix) return nullptr; - *matrix = { 1, 0, 0, 0, 1, 0, 0, 0, 1 }; while (str < end) { if (isspace(*str) || (*str == ',')) { ++str; @@ -620,54 +618,42 @@ static Matrix* _parseTransformationMatrix(const char* value) ++str; if (state == MatrixState::Matrix) { - Matrix tmp; - if (ptCount != 6) goto error; - - tmp = { points[0], points[2], points[4], points[1], points[3], points[5], 0, 0, 1 }; + Matrix tmp = {points[0], points[2], points[4], points[1], points[3], points[5], 0, 0, 1}; _matrixCompose(matrix, &tmp, matrix); } else if (state == MatrixState::Translate) { - Matrix tmp; - if (ptCount == 1) { - tmp = { 1, 0, points[0], 0, 1, 0, 0, 0, 1 }; + Matrix tmp = {1, 0, points[0], 0, 1, 0, 0, 0, 1}; _matrixCompose(matrix, &tmp, matrix); } else if (ptCount == 2) { - tmp = { 1, 0, points[0], 0, 1, points[1], 0, 0, 1 }; + Matrix tmp = {1, 0, points[0], 0, 1, points[1], 0, 0, 1}; _matrixCompose(matrix, &tmp, matrix); } else goto error; } else if (state == MatrixState::Rotate) { - Matrix tmp; - float c, s; //Transform to signed. points[0] = fmod(points[0], 360); if (points[0] < 0) points[0] += 360; - - c = cosf(points[0] * (M_PI / 180.0)); - s = sinf(points[0] * (M_PI / 180.0)); + auto c = cosf(points[0] * (M_PI / 180.0)); + auto s = sinf(points[0] * (M_PI / 180.0)); if (ptCount == 1) { - tmp = { c, -s, 0, s, c, 0, 0, 0, 1 }; + Matrix tmp = { c, -s, 0, s, c, 0, 0, 0, 1 }; _matrixCompose(matrix, &tmp, matrix); } else if (ptCount == 3) { - tmp = { 1, 0, points[1], 0, 1, points[2], 0, 0, 1 }; + Matrix tmp = { 1, 0, points[1], 0, 1, points[2], 0, 0, 1 }; _matrixCompose(matrix, &tmp, matrix); - tmp = { c, -s, 0, s, c, 0, 0, 0, 1 }; _matrixCompose(matrix, &tmp, matrix); - tmp = { 1, 0, -points[1], 0, 1, -points[2], 0, 0, 1 }; _matrixCompose(matrix, &tmp, matrix); } else { goto error; } } else if (state == MatrixState::Scale) { - Matrix tmp; if (ptCount < 1 || ptCount > 2) goto error; - sx = points[0]; sy = sx; if (ptCount == 2) sy = points[1]; - tmp = { sx, 0, 0, 0, sy, 0, 0, 0, 1 }; + Matrix tmp = { sx, 0, 0, 0, sy, 0, 0, 0, 1 }; _matrixCompose(matrix, &tmp, matrix); } } -- 2.7.4 From 5e3b67a3c77bee785e9163f1b4af2e4bbd775d80 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 13 Apr 2021 17:17:13 +0900 Subject: [PATCH 13/16] loaders svg: fix a wrongly handles the corner case. Stop the internel loop quick as possible, and state must be reset. --- src/loaders/svg/tvgSvgLoader.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index a8a863f..acb6bba 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -588,16 +588,17 @@ static Matrix* _parseTransformationMatrix(const char* value) { auto matrix = (Matrix*)malloc(sizeof(Matrix)); if (!matrix) return nullptr; - *matrix = { 1, 0, 0, 0, 1, 0, 0, 0, 1 }; + *matrix = {1, 0, 0, 0, 1, 0, 0, 0, 1}; float points[8]; int ptCount = 0; - float sx, sy; - MatrixState state = MatrixState::Unknown; char* str = (char*)value; char* end = str + strlen(str); while (str < end) { + + auto state = MatrixState::Unknown; + if (isspace(*str) || (*str == ',')) { ++str; continue; @@ -606,6 +607,7 @@ static Matrix* _parseTransformationMatrix(const char* value) if (!strncmp(matrixTags[i].tag, str, matrixTags[i].sz - 1)) { state = matrixTags[i].state; str += (matrixTags[i].sz - 1); + break; } } if (state == MatrixState::Unknown) goto error; @@ -650,8 +652,8 @@ static Matrix* _parseTransformationMatrix(const char* value) } } else if (state == MatrixState::Scale) { if (ptCount < 1 || ptCount > 2) goto error; - sx = points[0]; - sy = sx; + auto sx = points[0]; + auto sy = sx; if (ptCount == 2) sy = points[1]; Matrix tmp = { sx, 0, 0, 0, sy, 0, 0, 0, 1 }; _matrixCompose(matrix, &tmp, matrix); -- 2.7.4 From 800acd1b2f49bfe9f68750ec5c7d9665ffd420f3 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Tue, 13 Apr 2021 18:30:04 +0900 Subject: [PATCH 14/16] loader SvgLoader: return null if transform attribute invalid In transform matrix parsing, null is returned if any of the matrices are invalid. --- 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 acb6bba..2f6f5df 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -659,8 +659,10 @@ static Matrix* _parseTransformationMatrix(const char* value) _matrixCompose(matrix, &tmp, matrix); } } -error: return matrix; +error: + if (matrix) free(matrix); + return nullptr; } -- 2.7.4 From a7a1bbc7da189d62b18da6af1af0a7c750544db3 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Tue, 13 Apr 2021 18:34:14 +0900 Subject: [PATCH 15/16] loader SvgLoader: Fix for coding convention Change-Id: I0c6852eef9d19a8a58d1912ff54084a9c2b2c13d --- src/loaders/svg/tvgSvgLoader.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 2f6f5df..f359855 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -596,7 +596,6 @@ static Matrix* _parseTransformationMatrix(const char* value) char* end = str + strlen(str); while (str < end) { - auto state = MatrixState::Unknown; if (isspace(*str) || (*str == ',')) { @@ -735,7 +734,7 @@ static bool _attrParseSvgNode(void* data, const char* key, const char* value) return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); } #ifdef THORVG_LOG_ENABLED - else if (!strcmp(key, "xmlns") || !strcmp(key, "xmlns:xlink") || !strcmp (key, "xmlns:svg")) { + else if (!strcmp(key, "xmlns") || !strcmp(key, "xmlns:xlink") || !strcmp(key, "xmlns:svg")) { //No action } #endif -- 2.7.4 From 9996be4c047b5b3b9ced9fabe3c4b888ed795cff Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 14 Apr 2021 11:50:09 +0900 Subject: [PATCH 16/16] ** Temporary patch for diagnosing some hideous bugs in Tizen ** This patch puts some prints for analizing a crash issue, it must be reverted after fixing it. Change-Id: Iac2db25da27aa85dcfef19d05ced887d821584de --- packaging/thorvg.spec | 2 ++ src/lib/tvgCanvas.cpp | 8 ++++++++ src/lib/tvgCanvasImpl.h | 8 ++++++++ src/lib/tvgCommon.h | 3 +++ src/lib/tvgInitializer.cpp | 11 ++++++++++- src/lib/tvgPaint.cpp | 6 +++++- src/lib/tvgSceneImpl.h | 11 +++++++++++ src/lib/tvgTaskScheduler.cpp | 5 ++++- src/loaders/svg/tvgSvgLoader.cpp | 14 ++++++++++++++ src/loaders/svg/tvgSvgSceneBuilder.cpp | 5 +++++ src/meson.build | 3 ++- 11 files changed, 72 insertions(+), 4 deletions(-) diff --git a/packaging/thorvg.spec b/packaging/thorvg.spec index e0657bc..b24fec5 100644 --- a/packaging/thorvg.spec +++ b/packaging/thorvg.spec @@ -9,6 +9,8 @@ Source0: %{name}-%{version}.tar.gz BuildRequires: pkgconfig BuildRequires: pkgconfig(glesv2) +BuildRequires: pkgconfig(dlog) + BuildRequires: meson BuildRequires: ninja Requires(post): /sbin/ldconfig diff --git a/src/lib/tvgCanvas.cpp b/src/lib/tvgCanvas.cpp index 309e205..f886c74 100644 --- a/src/lib/tvgCanvas.cpp +++ b/src/lib/tvgCanvas.cpp @@ -51,24 +51,32 @@ Result Canvas::push(unique_ptr paint) noexcept Result Canvas::clear(bool free) noexcept { +dlog_print(DLOG_ERROR, LOG_TAG, "Canvas(%p) Clear", this); + return pImpl->clear(free); } Result Canvas::draw() noexcept { +dlog_print(DLOG_ERROR, LOG_TAG, "Canvas(%p) Draw", this); + return pImpl->draw(); } Result Canvas::update(Paint* paint) noexcept { +dlog_print(DLOG_ERROR, LOG_TAG, "Canvas(%p) Update", this); + return pImpl->update(paint, false); } Result Canvas::sync() noexcept { +dlog_print(DLOG_ERROR, LOG_TAG, "Canvas(%p) Sync", this); + if (pImpl->renderer->sync()) return Result::Success; return Result::InsufficientCondition; diff --git a/src/lib/tvgCanvasImpl.h b/src/lib/tvgCanvasImpl.h index 2772a23..b5c22c8 100644 --- a/src/lib/tvgCanvasImpl.h +++ b/src/lib/tvgCanvasImpl.h @@ -86,9 +86,11 @@ struct Canvas::Impl //Update single paint node if (paint) { + dlog_print(DLOG_ERROR, LOG_TAG, "Canvas(%p) update a paint(%p)", this, paint); paint->pImpl->update(*renderer, nullptr, 255, clips, flag); //Update all retained paint nodes } else { + dlog_print(DLOG_ERROR, LOG_TAG, "Canvas(%p) update paints count(%d)", this, paints.count); for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) { (*paint)->pImpl->update(*renderer, nullptr, 255, clips, flag); } @@ -96,6 +98,8 @@ struct Canvas::Impl refresh = false; + dlog_print(DLOG_ERROR, LOG_TAG, "Canvas(%p) update finished", this); + return Result::Success; } @@ -103,12 +107,16 @@ struct Canvas::Impl { if (!renderer || !renderer->preRender()) return Result::InsufficientCondition; + dlog_print(DLOG_ERROR, LOG_TAG, "Canvas(%p) draw paints count(%d)", this, paints.count); + for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) { if (!(*paint)->pImpl->render(*renderer)) return Result::InsufficientCondition; } if (!renderer->postRender()) return Result::InsufficientCondition; + dlog_print(DLOG_ERROR, LOG_TAG, "Canvas(%p) draw finished", this); + return Result::Success; } }; diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index f5d4a6d..8fcb681 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -22,6 +22,7 @@ #ifndef _TVG_COMMON_H_ #define _TVG_COMMON_H_ +#include #include "config.h" #include "thorvg.h" @@ -31,6 +32,8 @@ using namespace tvg; #define FILL_ID_LINEAR 0 #define FILL_ID_RADIAL 1 +#define LOG_TAG "thorvg" + #define TVG_UNUSED __attribute__ ((__unused__)) #endif //_TVG_COMMON_H_ diff --git a/src/lib/tvgInitializer.cpp b/src/lib/tvgInitializer.cpp index c91e13e..e144fb6 100644 --- a/src/lib/tvgInitializer.cpp +++ b/src/lib/tvgInitializer.cpp @@ -45,6 +45,8 @@ Result Initializer::init(CanvasEngine engine, uint32_t threads) noexcept { auto nonSupport = true; +dlog_print(DLOG_ERROR, LOG_TAG, "Inititlized!"); + if (static_cast(engine) & static_cast(CanvasEngine::Sw)) { #ifdef THORVG_SW_RASTER_SUPPORT if (!SwRenderer::init(threads)) return Result::InsufficientCondition; @@ -65,12 +67,17 @@ Result Initializer::init(CanvasEngine engine, uint32_t threads) noexcept TaskScheduler::init(threads); +dlog_print(DLOG_ERROR, LOG_TAG, "Inititlized! - Success"); + return Result::Success; } Result Initializer::term(CanvasEngine engine) noexcept { + +dlog_print(DLOG_ERROR, LOG_TAG, "Terminiated!"); + auto nonSupport = true; if (static_cast(engine) & static_cast(CanvasEngine::Sw)) { @@ -93,5 +100,7 @@ Result Initializer::term(CanvasEngine engine) noexcept if (!LoaderMgr::term()) return Result::Unknown; +dlog_print(DLOG_ERROR, LOG_TAG, "Terminiated! - Success"); + return Result::Success; -} \ No newline at end of file +} diff --git a/src/lib/tvgPaint.cpp b/src/lib/tvgPaint.cpp index aca756f..5e20587 100644 --- a/src/lib/tvgPaint.cpp +++ b/src/lib/tvgPaint.cpp @@ -164,6 +164,8 @@ bool Paint::Impl::render(RenderMethod& renderer) { Compositor* cmp = nullptr; +dlog_print(DLOG_ERROR, LOG_TAG, "render paint (%p) type(%d)", this, (int) this->type); + /* Note: only ClipPath is processed in update() step. Create a composition image. */ if (cmpTarget && cmpMethod != CompositeMethod::ClipPath) { @@ -194,6 +196,8 @@ void* Paint::Impl::update(RenderMethod& renderer, const RenderTransform* pTransf } } +dlog_print(DLOG_ERROR, LOG_TAG, "update paint (%p) type(%d)", this, (int) this->type); + /* 1. Composition Pre Processing */ void *cmpData = nullptr; RenderRegion viewport; @@ -316,4 +320,4 @@ Result Paint::opacity(uint8_t o) noexcept uint8_t Paint::opacity() const noexcept { return pImpl->opacity; -} \ No newline at end of file +} diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index 40f1e58..1ea5447 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -58,22 +58,31 @@ struct Scene::Impl void* update(RenderMethod &renderer, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flag) { +dlog_print(DLOG_ERROR, LOG_TAG, "====> Update Scene(%p), paints count(%d)", this, paints.count); + /* Overriding opacity value. If this scene is half-translucent, It must do intermeidate composition with that opacity value. */ this->opacity = static_cast(opacity); if (needComposition(opacity)) opacity = 255; + for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) { (*paint)->pImpl->update(renderer, transform, opacity, clips, static_cast(flag)); } /* FXIME: it requires to return list of children engine data This is necessary for scene composition */ + +dlog_print(DLOG_ERROR, LOG_TAG, "<==== Update Scene(%p), paints count(%d)", this, paints.count); + return nullptr; } bool render(RenderMethod& renderer) { + +dlog_print(DLOG_ERROR, LOG_TAG, "====> Render Scene(%p), paints count(%d)", this, paints.count); + Compositor* cmp = nullptr; if (needComposition(opacity)) { @@ -87,6 +96,8 @@ struct Scene::Impl if (cmp) renderer.endComposite(cmp); +dlog_print(DLOG_ERROR, LOG_TAG, "<==== Render Scene(%p), paints count(%d)", this, paints.count); + return true; } diff --git a/src/lib/tvgTaskScheduler.cpp b/src/lib/tvgTaskScheduler.cpp index 63ac4de..97eb16b 100644 --- a/src/lib/tvgTaskScheduler.cpp +++ b/src/lib/tvgTaskScheduler.cpp @@ -167,6 +167,9 @@ static TaskSchedulerImpl* inst = nullptr; void TaskScheduler::init(unsigned threads) { if (inst) return; + +dlog_print(DLOG_ERROR, LOG_TAG, "Init TaskScheduler threads = %d", threads); + inst = new TaskSchedulerImpl(threads); } @@ -189,4 +192,4 @@ unsigned TaskScheduler::threads() { if (inst) return inst->threadCnt; return 0; -} \ No newline at end of file +} diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index f359855..af0cc33 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -595,6 +595,8 @@ static Matrix* _parseTransformationMatrix(const char* value) char* str = (char*)value; char* end = str + strlen(str); + dlog_print(DLOG_ERROR, LOG_TAG, "_parseTransformationMatrix() - begin"); + while (str < end) { auto state = MatrixState::Unknown; @@ -658,9 +660,15 @@ static Matrix* _parseTransformationMatrix(const char* value) _matrixCompose(matrix, &tmp, matrix); } } + +dlog_print(DLOG_ERROR, LOG_TAG, "_parseTransformationMatrix() - end"); + return matrix; error: if (matrix) free(matrix); + +dlog_print(DLOG_ERROR, LOG_TAG, "_parseTransformationMatrix() - error"); + return nullptr; } @@ -2644,6 +2652,8 @@ bool SvgLoader::open(const string& path) this->size = filePath.size(); } + dlog_print(DLOG_ERROR, LOG_TAG, "SvgLoader open(%p) - %s", this, path.c_str()); + return header(); } @@ -2652,8 +2662,12 @@ bool SvgLoader::read() { if (!content || size == 0) return false; + dlog_print(DLOG_ERROR, LOG_TAG, "SvgLoader read(%p) - before", this); + TaskScheduler::request(this); + dlog_print(DLOG_ERROR, LOG_TAG, "SvgLoader read(%p) - after", this); + return true; } diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index b2be859..a5ddb75 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -402,6 +402,8 @@ unique_ptr svgSceneBuild(SvgNode* node) { if (!node || (node->type != SvgNodeType::Doc)) return nullptr; +dlog_print(DLOG_ERROR, LOG_TAG, "svgSceneBuild() node(%p) - begin", node); + auto vx = node->node.doc.vx; auto vy = node->node.doc.vy; auto vw = node->node.doc.vw; @@ -427,5 +429,8 @@ unique_ptr svgSceneBuild(SvgNode* node) } else { root = move(docNode); } + +dlog_print(DLOG_ERROR, LOG_TAG, "svgSceneBuild() - end"); + return root; } diff --git a/src/meson.build b/src/meson.build index 7e19d03..d386e13 100644 --- a/src/meson.build +++ b/src/meson.build @@ -17,7 +17,8 @@ subdir('loaders') subdir('bindings') thread_dep = meson.get_compiler('cpp').find_library('pthread') -thorvg_lib_dep = [common_dep, loader_dep, binding_dep, thread_dep] +dlog_dep = dependency('dlog', required: false) +thorvg_lib_dep = [common_dep, loader_dep, binding_dep, thread_dep, dlog_dep] thorvg_lib = library( 'thorvg', -- 2.7.4