From e1a88e73467cc3fadccb8cbb42700d127f7b4632 Mon Sep 17 00:00:00 2001 From: Michal Maciola <71131832+mmaciola@users.noreply.github.com> Date: Thu, 30 Dec 2021 15:56:25 +0100 Subject: [PATCH 01/16] example: added LumaMasking.cpp (#621) Added an example LumaMasking.cpp that tests CompositeMethod::LumaMask Change-Id: I30d6fde4a209b8a818ad2240025832f44b8d4f84 --- src/examples/LumaMasking.cpp | 217 +++++++++++++++++++++++++++++++++++++++++++ src/examples/meson.build | 1 + 2 files changed, 218 insertions(+) create mode 100644 src/examples/LumaMasking.cpp diff --git a/src/examples/LumaMasking.cpp b/src/examples/LumaMasking.cpp new file mode 100644 index 0000000..8b4c4fb --- /dev/null +++ b/src/examples/LumaMasking.cpp @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "Common.h" +#include + +/************************************************************************/ +/* Drawing Commands */ +/************************************************************************/ + +void tvgDrawCmds(tvg::Canvas* canvas) +{ + if (!canvas) return; + + //Solid Rectangle + auto shape = tvg::Shape::gen(); + shape->appendRect(0, 0, 400, 400, 0, 0); + shape->fill(255, 0, 0, 255); + + //Mask + auto mask = tvg::Shape::gen(); + mask->appendCircle(200, 200, 125, 125); + mask->fill(255, 0, 0, 255); + shape->composite(move(mask), tvg::CompositeMethod::LumaMask); + canvas->push(move(shape)); + + //SVG + auto svg = tvg::Picture::gen(); + if (svg->load(EXAMPLE_DIR"/cartman.svg") != tvg::Result::Success) return; + svg->opacity(100); + svg->scale(3); + svg->translate(50, 400); + + //Mask2 + auto mask2 = tvg::Shape::gen(); + mask2->appendCircle(150, 500, 75, 75); + mask2->appendRect(150, 500, 200, 200, 30, 30); + mask2->fill(255, 255, 255, 255); + svg->composite(move(mask2), tvg::CompositeMethod::LumaMask); + if (canvas->push(move(svg)) != tvg::Result::Success) return; + + //Star + auto star = tvg::Shape::gen(); + star->fill(80, 80, 80, 255); + star->moveTo(599, 34); + star->lineTo(653, 143); + star->lineTo(774, 160); + star->lineTo(687, 244); + star->lineTo(707, 365); + star->lineTo(599, 309); + star->lineTo(497, 365); + star->lineTo(512, 245); + star->lineTo(426, 161); + star->lineTo(546, 143); + star->close(); + star->stroke(10); + star->stroke(255, 255, 255, 255); + + //Mask3 + auto mask3 = tvg::Shape::gen(); + mask3->appendCircle(600, 200, 125, 125); + mask3->fill(0, 255, 255, 255); + star->composite(move(mask3), tvg::CompositeMethod::LumaMask); + if (canvas->push(move(star)) != tvg::Result::Success) return; + + //Image + ifstream file(EXAMPLE_DIR"/rawimage_200x300.raw"); + if (!file.is_open()) return; + auto data = (uint32_t*) malloc(sizeof(uint32_t) * (200 * 300)); + file.read(reinterpret_cast(data), sizeof (uint32_t) * 200 * 300); + file.close(); + + auto image = tvg::Picture::gen(); + if (image->load(data, 200, 300, true) != tvg::Result::Success) return; + image->translate(500, 400); + + //Mask4 + auto mask4 = tvg::Scene::gen(); + auto mask4_rect = tvg::Shape::gen(); + mask4_rect->appendRect(500, 400, 200, 300, 0, 0); + mask4_rect->fill(255, 255, 255, 255); + auto mask4_circle = tvg::Shape::gen(); + mask4_circle->appendCircle(600, 550, 125, 125); + mask4_circle->fill(128, 0, 128, 224); + if (mask4->push(move(mask4_rect)) != tvg::Result::Success) return; + if (mask4->push(move(mask4_circle)) != tvg::Result::Success) return; + image->composite(move(mask4), tvg::CompositeMethod::LumaMask); + if (canvas->push(move(image)) != tvg::Result::Success) return; + + free(data); +} + + +/************************************************************************/ +/* Sw Engine Test Code */ +/************************************************************************/ + +static unique_ptr swCanvas; + +void tvgSwTest(uint32_t* buffer) +{ + //Create a Canvas + swCanvas = tvg::SwCanvas::gen(); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); + + /* Push the shape into the Canvas drawing list + When this shape is into the canvas list, the shape could update & prepare + internal data asynchronously for coming rendering. + Canvas keeps this shape node unless user call canvas->clear() */ + tvgDrawCmds(swCanvas.get()); +} + +void drawSwView(void* data, Eo* obj) +{ + if (swCanvas->draw() == tvg::Result::Success) { + swCanvas->sync(); + } +} + + +/************************************************************************/ +/* GL Engine Test Code */ +/************************************************************************/ + +static unique_ptr glCanvas; + +void initGLview(Evas_Object *obj) +{ + static constexpr auto BPP = 4; + + //Create a Canvas + glCanvas = tvg::GlCanvas::gen(); + glCanvas->target(nullptr, WIDTH * BPP, WIDTH, HEIGHT); + + /* Push the shape into the Canvas drawing list + When this shape is into the canvas list, the shape could update & prepare + internal data asynchronously for coming rendering. + Canvas keeps this shape node unless user call canvas->clear() */ + tvgDrawCmds(glCanvas.get()); +} + +void drawGLview(Evas_Object *obj) +{ + auto gl = elm_glview_gl_api_get(obj); + gl->glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + gl->glClear(GL_COLOR_BUFFER_BIT); + + if (glCanvas->draw() == tvg::Result::Success) { + glCanvas->sync(); + } +} + + +/************************************************************************/ +/* Main Code */ +/************************************************************************/ + +int main(int argc, char **argv) +{ + tvg::CanvasEngine tvgEngine = tvg::CanvasEngine::Sw; + + if (argc > 1) { + if (!strcmp(argv[1], "gl")) tvgEngine = tvg::CanvasEngine::Gl; + } + + //Initialize ThorVG Engine + if (tvgEngine == tvg::CanvasEngine::Sw) { + cout << "tvg engine: software" << endl; + } else { + cout << "tvg engine: opengl" << endl; + } + + //Threads Count + auto threads = std::thread::hardware_concurrency(); + if (threads > 0) --threads; //Allow the designated main thread capacity + + //Initialize ThorVG Engine + if (tvg::Initializer::init(tvgEngine, threads) == tvg::Result::Success) { + + elm_init(argc, argv); + + if (tvgEngine == tvg::CanvasEngine::Sw) { + createSwView(); + } else { + createGlView(); + } + + elm_run(); + elm_shutdown(); + + //Terminate ThorVG Engine + tvg::Initializer::term(tvg::CanvasEngine::Sw); + + } else { + cout << "engine is not supported" << endl; + } + return 0; +} diff --git a/src/examples/meson.build b/src/examples/meson.build index 31331c8..778bc2c 100644 --- a/src/examples/meson.build +++ b/src/examples/meson.build @@ -18,6 +18,7 @@ source_file = [ 'ImageScaleUp.cpp', 'InvMasking.cpp', 'LinearGradient.cpp', + 'LumaMasking.cpp', 'Masking.cpp', 'MultiCanvas.cpp', 'MultiShapes.cpp', -- 2.7.4 From e9014711363ee7dce9da5b89eb633158ef59ff30 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Fri, 31 Dec 2021 12:00:15 +0100 Subject: [PATCH 02/16] svg_loader: composite node splitted on mask and clip nodes The SvgCompositeNode is replaced by the SvgMaskNode and SvgClipNode. This is needed for using Luma/AlphaMask in the svg loader and in the future, when we introduce other mask's features. Change-Id: Ieb90615da7dedcabe296950af20b59ac5d81e6ba --- src/loaders/svg/tvgSvgLoader.cpp | 12 ++++++------ src/loaders/svg/tvgSvgLoaderCommon.h | 10 ++++++++-- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index def8ae1..24aba19 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -1029,7 +1029,7 @@ static bool _attrParseClipPathNode(void* data, const char* key, const char* valu { SvgLoaderData* loader = (SvgLoaderData*)data; SvgNode* node = loader->svgParse->node; - SvgCompositeNode* comp = &(node->node.comp); + SvgClipNode* clip = &(node->node.clip); if (!strcmp(key, "style")) { return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); @@ -1039,7 +1039,7 @@ static bool _attrParseClipPathNode(void* data, const char* key, const char* valu if (node->id && value) free(node->id); node->id = _copyId(value); } else if (!strcmp(key, "clipPathUnits")) { - if (!strcmp(value, "objectBoundingBox")) comp->userSpace = false; + if (!strcmp(value, "objectBoundingBox")) clip->userSpace = false; } else { return _parseStyleAttr(loader, key, value, false); } @@ -1051,7 +1051,7 @@ static bool _attrParseMaskNode(void* data, const char* key, const char* value) { SvgLoaderData* loader = (SvgLoaderData*)data; SvgNode* node = loader->svgParse->node; - SvgCompositeNode* comp = &(node->node.comp); + SvgMaskNode* mask = &(node->node.mask); if (!strcmp(key, "style")) { return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); @@ -1061,7 +1061,7 @@ static bool _attrParseMaskNode(void* data, const char* key, const char* value) if (node->id && value) free(node->id); node->id = _copyId(value); } else if (!strcmp(key, "maskContentUnits")) { - if (!strcmp(value, "objectBoundingBox")) comp->userSpace = false; + if (!strcmp(value, "objectBoundingBox")) mask->userSpace = false; } else { return _parseStyleAttr(loader, key, value, false); } @@ -1171,7 +1171,7 @@ static SvgNode* _createMaskNode(SvgLoaderData* loader, SvgNode* parent, TVG_UNUS loader->svgParse->node = _createNode(parent, SvgNodeType::Mask); if (!loader->svgParse->node) return nullptr; - loader->svgParse->node->node.comp.userSpace = true; + loader->svgParse->node->node.mask.userSpace = true; simpleXmlParseAttributes(buf, bufLength, _attrParseMaskNode, loader); @@ -1185,7 +1185,7 @@ static SvgNode* _createClipPathNode(SvgLoaderData* loader, SvgNode* parent, cons if (!loader->svgParse->node) return nullptr; loader->svgParse->node->display = false; - loader->svgParse->node->node.comp.userSpace = true; + loader->svgParse->node->node.clip.userSpace = true; simpleXmlParseAttributes(buf, bufLength, _attrParseClipPathNode, loader); diff --git a/src/loaders/svg/tvgSvgLoaderCommon.h b/src/loaders/svg/tvgSvgLoaderCommon.h index cceef91..585e4e1 100644 --- a/src/loaders/svg/tvgSvgLoaderCommon.h +++ b/src/loaders/svg/tvgSvgLoaderCommon.h @@ -215,7 +215,12 @@ struct SvgPolygonNode float* points; }; -struct SvgCompositeNode +struct SvgClipNode +{ + bool userSpace; +}; + +struct SvgMaskNode { bool userSpace; }; @@ -352,7 +357,8 @@ struct SvgNode SvgPathNode path; SvgLineNode line; SvgImageNode image; - SvgCompositeNode comp; + SvgMaskNode mask; + SvgClipNode clip; } node; bool display; ~SvgNode(); -- 2.7.4 From 0e76934e3e3209f55e8a79a4c01ae2b591c3c0f8 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Tue, 4 Jan 2022 17:42:41 -0800 Subject: [PATCH 03/16] sw_engine SwRaster: Initialize uninitialized transform value Change-Id: I12e6a63cebbd765c19e83194587722a19db06fa2 --- src/lib/sw_engine/tvgSwRaster.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 6b5e00a..c51fda9 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -500,9 +500,8 @@ static bool _scaledRleRGBAImage(SwSurface* surface, const SwImage* image, const { Matrix itransform; - if (transform) { - if (!mathInverse(transform, &itransform)) return false; - } else mathIdentity(&itransform); + if (transform && !mathInverse(transform, &itransform)) return false; + else mathIdentity(&itransform); auto halfScale = _halfScale(image->scale); @@ -848,9 +847,8 @@ static bool _scaledRGBAImage(SwSurface* surface, const SwImage* image, const Mat { Matrix itransform; - if (transform) { - if (!mathInverse(transform, &itransform)) return false; - } else mathIdentity(&itransform); + if (transform && !mathInverse(transform, &itransform)) return false; + else mathIdentity(&itransform); auto halfScale = _halfScale(image->scale); -- 2.7.4 From b3b39593237fb02e80ac8636ed8b4cda7cd3901e Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 6 Jan 2022 12:32:16 +0900 Subject: [PATCH 04/16] sw_engine raster: fix a regression bug. Picture example were broken by 90fa26b7bb75cb938290170882e65da8d9fc5d9e the correct condition must be like this change. Change-Id: Ib3119a832118221c115cbc6ba9cf5f96ab7625b4 --- src/lib/sw_engine/tvgSwRaster.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index c51fda9..6b5e00a 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -500,8 +500,9 @@ static bool _scaledRleRGBAImage(SwSurface* surface, const SwImage* image, const { Matrix itransform; - if (transform && !mathInverse(transform, &itransform)) return false; - else mathIdentity(&itransform); + if (transform) { + if (!mathInverse(transform, &itransform)) return false; + } else mathIdentity(&itransform); auto halfScale = _halfScale(image->scale); @@ -847,8 +848,9 @@ static bool _scaledRGBAImage(SwSurface* surface, const SwImage* image, const Mat { Matrix itransform; - if (transform && !mathInverse(transform, &itransform)) return false; - else mathIdentity(&itransform); + if (transform) { + if (!mathInverse(transform, &itransform)) return false; + } else mathIdentity(&itransform); auto halfScale = _halfScale(image->scale); -- 2.7.4 From c2a0e6405fdf09fdd45c883abadfccfa29b8ebbf Mon Sep 17 00:00:00 2001 From: jykeon Date: Thu, 23 Feb 2023 17:41:58 +0900 Subject: [PATCH 05/16] Bump up 0.7.1 Change-Id: I3410b3abbbebcb42a71a8c24bf392001da65290f 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 f958ea5..5f1ea32 100644 --- a/packaging/thorvg.spec +++ b/packaging/thorvg.spec @@ -1,6 +1,6 @@ Name: thorvg Summary: Thor Vector Graphics Library -Version: 0.7.0 +Version: 0.7.1 Release: 1 Group: Graphics System/Rendering Engine License: MIT -- 2.7.4 From c53a728d699b8474e5d93775d2686c435891ac35 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 6 Jan 2022 12:40:52 +0900 Subject: [PATCH 06/16] svg_loader: ++robustness prevent a crash with an exceptional handling. @Issue: https://github.com/Samsung/thorvg/issues/1131 Change-Id: If45a5ae201165ba97f087cdeb8c6e35d97adca72 --- src/loaders/svg/tvgSvgLoader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 24aba19..5a9eae2 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -540,7 +540,7 @@ static void _toColor(const char* str, uint8_t* r, uint8_t* g, uint8_t* b, char** } } } - } else if (len >= 3 && !strncmp(str, "url", 3)) { + } else if (ref && len >= 3 && !strncmp(str, "url", 3)) { *ref = _idFromUrl((const char*)(str + 3)); } else { //Handle named color -- 2.7.4 From bb04761a9af81f986b83bdfba022881574bf3a11 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Sun, 2 Jan 2022 02:23:11 +0100 Subject: [PATCH 07/16] svg_loader: mask-type attribute introduced In an svg file the mask-type attribute can be specified. It takes one of the two values: Luminosity or Alpha. After the LumaMask is introduced into TVG, this attribute can be properly read by the svg loader. Change-Id: I8de1c94aed6bc0e7b31c1026b57f3336f29c2e30 --- src/loaders/svg/tvgSvgLoader.cpp | 18 ++++++++++++++++++ src/loaders/svg/tvgSvgLoaderCommon.h | 10 +++++++++- src/loaders/svg/tvgSvgSceneBuilder.cpp | 9 +++++++-- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 5a9eae2..aef549e 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -199,6 +199,14 @@ static int _toOpacity(const char* str) } +static SvgMaskType _toMaskType(const char* str) +{ + if (!strcmp(str, "Alpha")) return SvgMaskType::Alpha; + + return SvgMaskType::Luminance; +} + + #define _PARSE_TAG(Type, Name, Name1, Tags_Array, Default) \ static Type _to##Name1(const char* str) \ { \ @@ -921,6 +929,12 @@ static void _handleMaskAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, con } +static void _handleMaskTypeAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value) +{ + node->node.mask.type = _toMaskType(value); +} + + static void _handleDisplayAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value) { //TODO : The display attribute can have various values as well as "none". @@ -958,6 +972,7 @@ static constexpr struct STYLE_DEF(transform, Transform, SvgStyleFlags::Transform), STYLE_DEF(clip-path, ClipPath, SvgStyleFlags::ClipPath), STYLE_DEF(mask, Mask, SvgStyleFlags::Mask), + STYLE_DEF(mask-type, MaskType, SvgStyleFlags::MaskType), STYLE_DEF(display, Display, SvgStyleFlags::Display) }; @@ -1062,6 +1077,8 @@ static bool _attrParseMaskNode(void* data, const char* key, const char* value) node->id = _copyId(value); } else if (!strcmp(key, "maskContentUnits")) { if (!strcmp(value, "objectBoundingBox")) mask->userSpace = false; + } else if (!strcmp(key, "mask-type")) { + mask->type = _toMaskType(value); } else { return _parseStyleAttr(loader, key, value, false); } @@ -1172,6 +1189,7 @@ static SvgNode* _createMaskNode(SvgLoaderData* loader, SvgNode* parent, TVG_UNUS if (!loader->svgParse->node) return nullptr; loader->svgParse->node->node.mask.userSpace = true; + loader->svgParse->node->node.mask.type = SvgMaskType::Luminance; simpleXmlParseAttributes(buf, bufLength, _attrParseMaskNode, loader); diff --git a/src/loaders/svg/tvgSvgLoaderCommon.h b/src/loaders/svg/tvgSvgLoaderCommon.h index 585e4e1..bf94beb 100644 --- a/src/loaders/svg/tvgSvgLoaderCommon.h +++ b/src/loaders/svg/tvgSvgLoaderCommon.h @@ -111,7 +111,8 @@ enum class SvgStyleFlags Transform = 0x800, ClipPath = 0x1000, Mask = 0x2000, - Display = 0x4000 + MaskType = 0x4000, + Display = 0x8000 }; enum class SvgStopStyleFlags @@ -127,6 +128,12 @@ enum class SvgFillRule OddEven = 1 }; +enum class SvgMaskType +{ + Luminance = 0, + Alpha +}; + //Length type to recalculate %, pt, pc, mm, cm etc enum class SvgParserLengthType { @@ -222,6 +229,7 @@ struct SvgClipNode struct SvgMaskNode { + SvgMaskType type; bool userSpace; }; diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index 8701fe3..b6b581a 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -275,7 +275,7 @@ static void _applyComposition(Paint* paint, const SvgNode* node, const Box& vBox Composition can be applied recursively if its children nodes have composition target to this one. */ if (node->style->mask.applying) { TVGLOG("SVG", "Multiple Composition Tried! Check out Circular dependency?"); - } else { + } else { auto compNode = node->style->mask.node; if (compNode && compNode->child.count > 0) { node->style->mask.applying = true; @@ -283,7 +283,12 @@ static void _applyComposition(Paint* paint, const SvgNode* node, const Box& vBox auto comp = _sceneBuildHelper(compNode, vBox, svgPath, true); if (comp) { if (node->transform) comp->transform(*node->transform); - paint->composite(move(comp), CompositeMethod::AlphaMask); + + if (compNode->node.mask.type == SvgMaskType::Luminance) { + paint->composite(move(comp), CompositeMethod::LumaMask); + } else { + paint->composite(move(comp), CompositeMethod::AlphaMask); + } } node->style->mask.applying = false; -- 2.7.4 From 0a891ea82bf9dd8d8d8b6aa777413c0b095be27e Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Sat, 8 Jan 2022 00:31:32 +0100 Subject: [PATCH 08/16] svg_loader: typo fixed _svgLoaderParerXmlClose -> _svgLoaderParserXmlClose Change-Id: I24a3fc61e52c74507dc6dd62ddda63f97ed3d05f --- src/loaders/svg/tvgSvgLoader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index aef549e..252a901 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -2380,7 +2380,7 @@ static constexpr struct }; -static void _svgLoaderParerXmlClose(SvgLoaderData* loader, const char* content) +static void _svgLoaderParserXmlClose(SvgLoaderData* loader, const char* content) { content = _skipSpace(content, nullptr); @@ -2488,7 +2488,7 @@ static bool _svgLoaderParser(void* data, SimpleXMLType type, const char* content break; } case SimpleXMLType::Close: { - _svgLoaderParerXmlClose(loader, content); + _svgLoaderParserXmlClose(loader, content); break; } case SimpleXMLType::Data: -- 2.7.4 From 038dcb0883a6d9553029571046a7abbb1f761554 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Sat, 8 Jan 2022 02:17:44 +0100 Subject: [PATCH 09/16] svg_loader: LumaMask used only for masks other than white For the performance reasons, the LumaMask is used only when it's necessary - when the mask color is other than white. Otherwise the AlphaMask is enough. Change-Id: Ia97fb753854435e2e58eeb1ead40dbb3a5ead7cc --- src/loaders/svg/tvgSvgSceneBuilder.cpp | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index b6b581a..2c0d4e4 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -67,7 +67,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); +static unique_ptr _sceneBuildHelper(const SvgNode* node, const Box& vBox, const string& svgPath, bool mask, bool* isMaskWhite = nullptr); static inline bool _isGroupType(SvgNodeType type) @@ -280,11 +280,12 @@ static void _applyComposition(Paint* paint, const SvgNode* node, const Box& vBox if (compNode && compNode->child.count > 0) { node->style->mask.applying = true; - auto comp = _sceneBuildHelper(compNode, vBox, svgPath, true); + bool isMaskWhite = true; + auto comp = _sceneBuildHelper(compNode, vBox, svgPath, true, &isMaskWhite); if (comp) { if (node->transform) comp->transform(*node->transform); - if (compNode->node.mask.type == SvgMaskType::Luminance) { + if (compNode->node.mask.type == SvgMaskType::Luminance && !isMaskWhite) { paint->composite(move(comp), CompositeMethod::LumaMask); } else { paint->composite(move(comp), CompositeMethod::AlphaMask); @@ -556,9 +557,9 @@ static unique_ptr _imageBuildHelper(SvgNode* node, const Box& vBox, con } -static unique_ptr _useBuildHelper(const SvgNode* node, const Box& vBox, const string& svgPath) +static unique_ptr _useBuildHelper(const SvgNode* node, const Box& vBox, const string& svgPath, bool* isMaskWhite) { - auto scene = _sceneBuildHelper(node, vBox, svgPath, false); + auto scene = _sceneBuildHelper(node, vBox, svgPath, false, isMaskWhite); if (node->node.use.x != 0.0f || node->node.use.y != 0.0f) { scene->translate(node->node.use.x, node->node.use.y); } @@ -569,7 +570,7 @@ 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) +static unique_ptr _sceneBuildHelper(const SvgNode* node, const Box& vBox, const string& svgPath, bool mask, bool* isMaskWhite) { if (_isGroupType(node->type) || mask) { auto scene = Scene::gen(); @@ -580,15 +581,22 @@ 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)); + scene->push(_useBuildHelper(*child, vBox, svgPath, isMaskWhite)); else - scene->push(_sceneBuildHelper(*child, vBox, svgPath, false)); + 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)); } else if ((*child)->type != SvgNodeType::Mask) { auto shape = _shapeBuildHelper(*child, vBox, svgPath); - if (shape) scene->push(move(shape)); + if (shape) { + if (isMaskWhite) { + uint8_t r, g, b; + shape->fillColor(&r, &g, &b, nullptr); + if (shape->fill() || r < 255 || g < 255 || b < 255) *isMaskWhite = false; + } + scene->push(move(shape)); + } } } _applyComposition(scene.get(), node, vBox, svgPath); -- 2.7.4 From a370e322662de0e46bf679966a3297b4030f14fd Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Sat, 8 Jan 2022 23:47:38 +0100 Subject: [PATCH 10/16] svg_loader: preventing memory leak A memory leak occured when the 'id' attribute was given multiple times for a given gradient element. Fixed. Change-Id: I386565d016c23172dc6b2628ef0f0c158a461417 --- src/loaders/svg/tvgSvgLoader.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 252a901..42f85a8 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -2098,6 +2098,7 @@ static bool _attrParseRadialGradientNode(void* data, const char* key, const char } if (!strcmp(key, "id")) { + if (grad->id && value) free(grad->id); grad->id = _copyId(value); } else if (!strcmp(key, "spreadMethod")) { grad->spread = _parseSpreadValue(value); @@ -2286,6 +2287,7 @@ static bool _attrParseLinearGradientNode(void* data, const char* key, const char } if (!strcmp(key, "id")) { + if (grad->id && value) free(grad->id); grad->id = _copyId(value); } else if (!strcmp(key, "spreadMethod")) { grad->spread = _parseSpreadValue(value); -- 2.7.4 From 8f0dd6aa5c8ecde1994d9109d1c1a4c8a84ea938 Mon Sep 17 00:00:00 2001 From: jykeon Date: Thu, 23 Feb 2023 18:22:14 +0900 Subject: [PATCH 11/16] Bump up 0.7.2 Change-Id: I0d11c0712aa2e1c85ff8e0cb8a10feaf0fb2b64b 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 5f1ea32..bc811ae 100644 --- a/packaging/thorvg.spec +++ b/packaging/thorvg.spec @@ -1,6 +1,6 @@ Name: thorvg Summary: Thor Vector Graphics Library -Version: 0.7.1 +Version: 0.7.2 Release: 1 Group: Graphics System/Rendering Engine License: MIT -- 2.7.4 From 9a22c40a83de1de2e020cd649a15795029f41c00 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Fri, 7 Jan 2022 22:54:46 +0100 Subject: [PATCH 12/16] svg_loader: fix grad update The grad update should be handled after the postponed nodes are cloned. Change-Id: I7391d416a81a9cb465ea9a01f5360c126abc53a2 --- src/loaders/svg/tvgSvgLoader.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 42f85a8..70f5edc 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -2857,14 +2857,14 @@ void SvgLoader::run(unsigned tid) if (loaderData.doc) { _updateStyle(loaderData.doc, nullptr); auto defs = loaderData.doc->node.doc.defs; - if (defs) _updateGradient(loaderData.doc, &defs->node.defs.gradients); - - if (loaderData.gradients.count > 0) _updateGradient(loaderData.doc, &loaderData.gradients); _updateComposite(loaderData.doc, loaderData.doc); if (defs) _updateComposite(loaderData.doc, defs); if (loaderData.cloneNodes.count > 0) _clonePostponedNodes(&loaderData.cloneNodes); + + if (loaderData.gradients.count > 0) _updateGradient(loaderData.doc, &loaderData.gradients); + if (defs) _updateGradient(loaderData.doc, &defs->node.defs.gradients); } root = svgSceneBuild(loaderData.doc, vx, vy, vw, vh, w, h, preserveAspect, svgPath); } -- 2.7.4 From 4d5f800d4df2a53f2da27924b756f7512e91f292 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Sat, 8 Jan 2022 23:55:55 +0100 Subject: [PATCH 13/16] svg_loader: removing repeated lines The clip-path and the mask attributes are both parsed in _attrParseGNode function, which is called in th _attrParseUseNode. Change-Id: Ibef6256e25d63d52571949ead21241e3e4346bef --- 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 70f5edc..e40be9a 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -1900,10 +1900,6 @@ static bool _attrParseUseNode(void* data, const char* key, const char* value) //after the whole file is parsed _postponeCloneNode(loader, node, id); } - } else if (!strcmp(key, "clip-path")) { - _handleClipPathAttr(loader, node, value); - } else if (!strcmp(key, "mask")) { - _handleMaskAttr(loader, node, value); } else { return _attrParseGNode(data, key, value); } -- 2.7.4 From 1e77c75fc9e6a8ad80ee2ac4d4f437d75f29f4d3 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Fri, 7 Jan 2022 22:42:00 +0100 Subject: [PATCH 14/16] svg_loader: the color attribute properly inherited The color attribute hat to be inherited regardles whether it is used in the child node or not - it may be used i.e. in the grandchild node. Change-Id: If2895ec64c9ed7f7e176cb32cb4adc8a61f63551 --- src/loaders/svg/tvgSvgLoader.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index e40be9a..e4f0f50 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -2512,14 +2512,16 @@ static void _styleInherit(SvgStyleProperty* child, const SvgStyleProperty* paren { if (parent == nullptr) return; //Inherit the property of parent if not present in child. + if (!child->curColorSet) { + child->color = parent->color; + child->curColorSet = parent->curColorSet; + } //Fill if (!((int)child->fill.flags & (int)SvgFillFlags::Paint)) { 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); - } else if (child->fill.paint.curColor && !child->curColorSet) { - child->color = parent->color; } if (!((int)child->fill.flags & (int)SvgFillFlags::Opacity)) { child->fill.opacity = parent->fill.opacity; @@ -2533,8 +2535,6 @@ static void _styleInherit(SvgStyleProperty* child, const SvgStyleProperty* paren 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; - } else if (child->stroke.paint.curColor && !child->curColorSet) { - child->color = parent->color; } if (!((int)child->stroke.flags & (int)SvgStrokeFlags::Opacity)) { child->stroke.opacity = parent->stroke.opacity; -- 2.7.4 From c1a1c502574e4842f711295669e94a0e84049182 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Sun, 9 Jan 2022 17:44:24 +0100 Subject: [PATCH 15/16] svg_loader: changed the order of if conditions The weekest condition should be checked as the last one. Otherwise CDATA marker was never found. Change-Id: I42cbbe867484cb88b156e182c0452a8cb59cc53d --- src/loaders/svg/tvgXmlParser.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/loaders/svg/tvgXmlParser.cpp b/src/loaders/svg/tvgXmlParser.cpp index 2e3d592..02dd999 100644 --- a/src/loaders/svg/tvgXmlParser.cpp +++ b/src/loaders/svg/tvgXmlParser.cpp @@ -219,15 +219,15 @@ static SimpleXMLType _getXMLType(const char* itr, const char* itrEnd, size_t &to if ((itr + sizeof("") - 1 < itrEnd) && (!memcmp(itr + 2, "DOCTYPE", sizeof("DOCTYPE") - 1)) && ((itr[2 + sizeof("DOCTYPE") - 1] == '>') || (isspace((unsigned char)itr[2 + sizeof("DOCTYPE") - 1])))) { toff = sizeof("!DOCTYPE") - 1; return SimpleXMLType::Doctype; - } else if (itr + sizeof("") - 1 < itrEnd) { - toff = sizeof("!") - 1; - return SimpleXMLType::DoctypeChild; } else if ((itr + sizeof("") - 1 < itrEnd) && (!memcmp(itr + 2, "[CDATA[", sizeof("[CDATA[") - 1))) { toff = sizeof("![CDATA[") - 1; return SimpleXMLType::CData; } else if ((itr + sizeof("") - 1 < itrEnd) && (!memcmp(itr + 2, "--", sizeof("--") - 1))) { toff = sizeof("!--") - 1; return SimpleXMLType::Comment; + } else if (itr + sizeof("") - 1 < itrEnd) { + toff = sizeof("!") - 1; + return SimpleXMLType::DoctypeChild; } return SimpleXMLType::Open; } -- 2.7.4 From fd6e64576a5459da6da9a6e9075148b1ef1a233a Mon Sep 17 00:00:00 2001 From: jykeon Date: Fri, 24 Feb 2023 11:58:33 +0900 Subject: [PATCH 16/16] Bump up 0.7.3 Change-Id: I2cdb51b9c327911667d202986f1c36bef5d67e6b 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 bc811ae..ba946df 100644 --- a/packaging/thorvg.spec +++ b/packaging/thorvg.spec @@ -1,6 +1,6 @@ Name: thorvg Summary: Thor Vector Graphics Library -Version: 0.7.2 +Version: 0.7.3 Release: 1 Group: Graphics System/Rendering Engine License: MIT -- 2.7.4