From adda399b271a19da834d0b8c4ca7a7c4bf97567b Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 20 Jan 2022 12:04:19 +0900 Subject: [PATCH 01/16] svg_loader: ++robustness Prevent recursive calls by counting just in case. The size is arbitrary value, we can adjust it experimentally. @Issue: https://github.com/Samsung/thorvg/issues/1161 Change-Id: I30571e5de085c65980a240b14c592bc0b47a7860 --- src/loaders/svg/tvgSvgLoader.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 74e6144..4990c5c 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -1934,8 +1934,15 @@ static void _copyAttr(SvgNode* to, const SvgNode* from) } -static void _cloneNode(SvgNode* from, SvgNode* parent) +static void _cloneNode(SvgNode* from, SvgNode* parent, int depth) { + /* Exception handling: Prevent invalid SVG data input. + The size is the arbitrary value, we need an experimental size. */ + if (depth == 8192) { + TVGERR("SVG", "Infinite recursive call - stopped after %d calls! Svg file may be incorrectly formatted.", depth); + return; + } + SvgNode* newNode; if (!from || !parent || from == parent) return; @@ -1947,7 +1954,7 @@ static void _cloneNode(SvgNode* from, SvgNode* parent) auto child = from->child.data; for (uint32_t i = 0; i < from->child.count; ++i, ++child) { - _cloneNode(*child, newNode); + _cloneNode(*child, newNode, depth + 1); } } @@ -1965,7 +1972,7 @@ static void _clonePostponedNodes(Array* cloneNodes, SvgNode* doc) auto defs = _getDefsNode(nodeIdPair.node); auto nodeFrom = _findChildById(defs, nodeIdPair.id); if (!nodeFrom) nodeFrom = _findChildById(doc, nodeIdPair.id); - _cloneNode(nodeFrom, nodeIdPair.node); + _cloneNode(nodeFrom, nodeIdPair.node, 0); free(nodeIdPair.id); } } @@ -2006,7 +2013,7 @@ static bool _attrParseUseNode(void* data, const char* key, const char* value) defs = _getDefsNode(node); nodeFrom = _findChildById(defs, id); if (nodeFrom) { - _cloneNode(nodeFrom, node); + _cloneNode(nodeFrom, node, 0); free(id); } else { //some svg export software include element at the end of the file -- 2.7.4 From 4bf49c05bf258cb4fe237d25745645e32e2cf048 Mon Sep 17 00:00:00 2001 From: jykeon Date: Mon, 27 Feb 2023 16:53:00 +0900 Subject: [PATCH 02/16] Bump up 0.7.5 Change-Id: I0ce3f00a49467ffd990eeeaf0179171401280177 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 a2f5c0d..a53aa64 100644 --- a/packaging/thorvg.spec +++ b/packaging/thorvg.spec @@ -1,6 +1,6 @@ Name: thorvg Summary: Thor Vector Graphics Library -Version: 0.7.4 +Version: 0.7.5 Release: 1 Group: Graphics System/Rendering Engine License: MIT -- 2.7.4 From b86c6e7236df93ae3434d8dde727dfea8cf742d0 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Thu, 20 Jan 2022 13:55:05 +0100 Subject: [PATCH 03/16] sw_engine: float casted on the unsigned int type uint32_t -> int32_t Change-Id: I33a7ba842a19acafc2cbe9bfa4bc8f6f79ba7658 --- src/lib/sw_engine/tvgSwImage.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/sw_engine/tvgSwImage.cpp b/src/lib/sw_engine/tvgSwImage.cpp index 9b57700..f24d2d6 100644 --- a/src/lib/sw_engine/tvgSwImage.cpp +++ b/src/lib/sw_engine/tvgSwImage.cpp @@ -84,8 +84,8 @@ bool imagePrepare(SwImage* image, const Matrix* transform, const SwBBox& clipReg //Fast track: Non-transformed image but just shifted. if (image->direct) { - image->ox = -static_cast(round(transform->e13)); - image->oy = -static_cast(round(transform->e23)); + image->ox = -static_cast(round(transform->e13)); + image->oy = -static_cast(round(transform->e23)); //Figure out the scale factor by transform matrix } else { auto scaleX = sqrtf((transform->e11 * transform->e11) + (transform->e21 * transform->e21)); -- 2.7.4 From 8d4b1c99d7e87f6d98cc39a3c40b8a6a4bfcbd1d Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Fri, 21 Jan 2022 23:45:03 +0100 Subject: [PATCH 04/16] examples: terminate the same engine as was initialized Change-Id: I3e1b3cbee003fa18fdec8b554588d3420473aa08 --- src/examples/AnimateMasking.cpp | 2 +- src/examples/GradientMasking.cpp | 6 +++--- src/examples/GradientStroke.cpp | 2 +- src/examples/InvMasking.cpp | 2 +- src/examples/LumaMasking.cpp | 2 +- src/examples/Masking.cpp | 2 +- src/examples/MultiCanvas.cpp | 6 +++--- src/examples/PictureJpg.cpp | 2 +- src/examples/PicturePng.cpp | 4 ++-- src/examples/PictureRaw.cpp | 2 +- src/examples/Stress.cpp | 2 +- src/examples/Svg.cpp | 2 +- src/examples/Svg2.cpp | 2 +- src/examples/Tvg.cpp | 2 +- 14 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/examples/AnimateMasking.cpp b/src/examples/AnimateMasking.cpp index 7f1ba23..48cbe70 100644 --- a/src/examples/AnimateMasking.cpp +++ b/src/examples/AnimateMasking.cpp @@ -103,7 +103,7 @@ void tvgUpdateCmds(tvg::Canvas* canvas, float progress) You can update only necessary properties of this shape, while retaining other properties. */ - // Translate mask object with its stroke & update + // Translate mask object with its stroke & update pMaskShape->translate(0 , progress * 300); pMask->translate(0 , progress * 300); diff --git a/src/examples/GradientMasking.cpp b/src/examples/GradientMasking.cpp index bafc21a..b8b88ea 100644 --- a/src/examples/GradientMasking.cpp +++ b/src/examples/GradientMasking.cpp @@ -47,7 +47,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) colorStops[1] = {1,255,255,255,255}; fill->colorStops(colorStops,2); shape->fill(move(fill)); - + shape->composite(move(mask), tvg::CompositeMethod::AlphaMask); canvas->push(move(shape)); @@ -79,7 +79,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) colorStops1[1] = {1,1,255,255,255}; fill1->colorStops(colorStops1,2); shape1->fill(move(fill1)); - + shape1->composite(move(mask1), tvg::CompositeMethod::AlphaMask); canvas->push(move(shape1)); @@ -237,7 +237,7 @@ int main(int argc, char **argv) elm_shutdown(); //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); + tvg::Initializer::term(tvgEngine); } else { cout << "engine is not supported" << endl; diff --git a/src/examples/GradientStroke.cpp b/src/examples/GradientStroke.cpp index 8b04aa2..6e2b97e 100644 --- a/src/examples/GradientStroke.cpp +++ b/src/examples/GradientStroke.cpp @@ -77,7 +77,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) if (canvas->push(move(shape1)) != tvg::Result::Success) return; - // radial gradient stroke + duplicate + // radial gradient stroke + duplicate auto shape2 = tvg::Shape::gen(); shape2->appendCircle(600, 175, 100, 60); shape2->stroke(80); diff --git a/src/examples/InvMasking.cpp b/src/examples/InvMasking.cpp index cd4b0a3..4b6eb31 100644 --- a/src/examples/InvMasking.cpp +++ b/src/examples/InvMasking.cpp @@ -212,7 +212,7 @@ int main(int argc, char **argv) elm_shutdown(); //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); + tvg::Initializer::term(tvgEngine); } else { cout << "engine is not supported" << endl; diff --git a/src/examples/LumaMasking.cpp b/src/examples/LumaMasking.cpp index 45b1548..cb32d1b 100644 --- a/src/examples/LumaMasking.cpp +++ b/src/examples/LumaMasking.cpp @@ -208,7 +208,7 @@ int main(int argc, char **argv) elm_shutdown(); //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); + tvg::Initializer::term(tvgEngine); } else { cout << "engine is not supported" << endl; diff --git a/src/examples/Masking.cpp b/src/examples/Masking.cpp index 8b63b0b..88be49a 100644 --- a/src/examples/Masking.cpp +++ b/src/examples/Masking.cpp @@ -212,7 +212,7 @@ int main(int argc, char **argv) elm_shutdown(); //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); + tvg::Initializer::term(tvgEngine); } else { cout << "engine is not supported" << endl; diff --git a/src/examples/MultiCanvas.cpp b/src/examples/MultiCanvas.cpp index 006223f..f622a05 100644 --- a/src/examples/MultiCanvas.cpp +++ b/src/examples/MultiCanvas.cpp @@ -178,7 +178,7 @@ void tvgGlTest(const char* name, const char* path, void* data) objData->name = strdup(name); objData->path = strdup(path); - Eo* win = (Eo*) data; + Eo* win = (Eo*) data; Eo* view = elm_glview_add(win); elm_glview_mode_set(view, ELM_GLVIEW_ALPHA); @@ -189,7 +189,7 @@ void tvgGlTest(const char* name, const char* path, void* data) evas_object_data_set(view, "objdata", reinterpret_cast(objData)); evas_object_event_callback_add(view, EVAS_CALLBACK_DEL, gl_del, objData); evas_object_resize(view, SIZE, SIZE); - evas_object_move(view, (count % NUM_PER_LINE) * SIZE, SIZE * (count / NUM_PER_LINE)); + evas_object_move(view, (count % NUM_PER_LINE) * SIZE, SIZE * (count / NUM_PER_LINE)); evas_object_show(view); } @@ -238,7 +238,7 @@ int main(int argc, char **argv) elm_shutdown(); //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); + tvg::Initializer::term(tvgEngine); } else { cout << "engine is not supported" << endl; diff --git a/src/examples/PictureJpg.cpp b/src/examples/PictureJpg.cpp index df56f3e..c04b34b 100644 --- a/src/examples/PictureJpg.cpp +++ b/src/examples/PictureJpg.cpp @@ -169,7 +169,7 @@ int main(int argc, char **argv) elm_shutdown(); //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); + tvg::Initializer::term(tvgEngine); } else { diff --git a/src/examples/PicturePng.cpp b/src/examples/PicturePng.cpp index 0cbaedb..b43926a 100644 --- a/src/examples/PicturePng.cpp +++ b/src/examples/PicturePng.cpp @@ -31,7 +31,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) { if (!canvas) return; - //Background + //Background auto bg = tvg::Shape::gen(); bg->appendRect(0, 0, WIDTH, HEIGHT, 0, 0); //x, y, w, h, rx, ry bg->fill(255, 255, 255, 255); //r, g, b, a @@ -175,7 +175,7 @@ int main(int argc, char **argv) elm_shutdown(); //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); + tvg::Initializer::term(tvgEngine); } else { diff --git a/src/examples/PictureRaw.cpp b/src/examples/PictureRaw.cpp index dcb86fc..ea6de16 100644 --- a/src/examples/PictureRaw.cpp +++ b/src/examples/PictureRaw.cpp @@ -169,7 +169,7 @@ int main(int argc, char **argv) elm_shutdown(); //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); + tvg::Initializer::term(tvgEngine); } else { cout << "engine is not supported" << endl; diff --git a/src/examples/Stress.cpp b/src/examples/Stress.cpp index 004561b..cd8843d 100644 --- a/src/examples/Stress.cpp +++ b/src/examples/Stress.cpp @@ -236,7 +236,7 @@ int main(int argc, char **argv) elm_shutdown(); //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); + tvg::Initializer::term(tvgEngine); } else { cout << "engine is not supported" << endl; diff --git a/src/examples/Svg.cpp b/src/examples/Svg.cpp index be4f357..53e9502 100644 --- a/src/examples/Svg.cpp +++ b/src/examples/Svg.cpp @@ -181,7 +181,7 @@ int main(int argc, char **argv) elm_shutdown(); //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); + tvg::Initializer::term(tvgEngine); } else { cout << "engine is not supported" << endl; diff --git a/src/examples/Svg2.cpp b/src/examples/Svg2.cpp index a7c97da..011816e 100644 --- a/src/examples/Svg2.cpp +++ b/src/examples/Svg2.cpp @@ -147,7 +147,7 @@ int main(int argc, char **argv) elm_shutdown(); //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); + tvg::Initializer::term(tvgEngine); } else { cout << "engine is not supported" << endl; diff --git a/src/examples/Tvg.cpp b/src/examples/Tvg.cpp index 51c6af8..5512f43 100644 --- a/src/examples/Tvg.cpp +++ b/src/examples/Tvg.cpp @@ -181,7 +181,7 @@ int main(int argc, char **argv) elm_shutdown(); //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); + tvg::Initializer::term(tvgEngine); } else { cout << "engine is not supported" << endl; -- 2.7.4 From 0dfc931de3b9509ead61d02c8c4a364577a297aa Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Thu, 20 Jan 2022 13:52:57 +0100 Subject: [PATCH 05/16] portability: fixing windows warnings atan2->atan2f Change-Id: Ia7572db01a26e0b7d5a6d3ed610cda407a27375f --- src/lib/sw_engine/tvgSwRasterTexmapInternal.h | 6 +++--- src/lib/tvgMath.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRasterTexmapInternal.h b/src/lib/sw_engine/tvgSwRasterTexmapInternal.h index 0cf6cff..f31ea1e 100644 --- a/src/lib/sw_engine/tvgSwRasterTexmapInternal.h +++ b/src/lib/sw_engine/tvgSwRasterTexmapInternal.h @@ -58,8 +58,8 @@ y = yStart; while (y < yEnd) { - x1 = _xa; - x2 = _xb; + x1 = (int32_t)_xa; + x2 = (int32_t)_xb; if (!region) { minx = INT32_MAX; @@ -160,4 +160,4 @@ next: xb = _xb; ua = _ua; va = _va; -} \ No newline at end of file +} diff --git a/src/lib/tvgMath.h b/src/lib/tvgMath.h index d4d3ad9..6120216 100644 --- a/src/lib/tvgMath.h +++ b/src/lib/tvgMath.h @@ -47,7 +47,7 @@ static inline bool mathEqual(float a, float b) static inline bool mathRightAngle(const Matrix* m) { - auto radian = fabsf(atan2(m->e21, m->e11)); + auto radian = fabsf(atan2f(m->e21, m->e11)); if (radian < FLT_EPSILON || mathEqual(radian, float(M_PI_2)) || mathEqual(radian, float(M_PI))) return true; return false; } -- 2.7.4 From 8fa300f2dfb10c5c22e0da5d346cb614aa5f1c62 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 24 Jan 2022 20:48:54 +0900 Subject: [PATCH 06/16] loaders jpg: fix all memory leaks. These were detected by asan with PictureJpg example, fixed them all. Change-Id: Ie63bcef3aa40945aa511db6df3fab9cc650c595b --- src/loaders/jpg/tvgJpgLoader.cpp | 5 +++++ src/loaders/jpg/tvgJpgd.cpp | 5 +++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/loaders/jpg/tvgJpgLoader.cpp b/src/loaders/jpg/tvgJpgLoader.cpp index 6795c10..7b90b4a 100644 --- a/src/loaders/jpg/tvgJpgLoader.cpp +++ b/src/loaders/jpg/tvgJpgLoader.cpp @@ -47,6 +47,7 @@ JpgLoader::~JpgLoader() { jpgdDelete(decoder); if (freeData) free(data); + free(image); } @@ -128,5 +129,9 @@ unique_ptr JpgLoader::bitmap() void JpgLoader::run(unsigned tid) { + if (image) { + free(image); + image = nullptr; + } image = jpgdDecompress(decoder); } \ No newline at end of file diff --git a/src/loaders/jpg/tvgJpgd.cpp b/src/loaders/jpg/tvgJpgd.cpp index 0c74cdf..b80516a 100644 --- a/src/loaders/jpg/tvgJpgd.cpp +++ b/src/loaders/jpg/tvgJpgd.cpp @@ -1080,7 +1080,9 @@ namespace DCT_Upsample // Unconditionally frees all allocated m_blocks. void jpeg_decoder::free_all_blocks() { + delete(m_pStream); m_pStream = nullptr; + for (mem_block *b = m_pMem_blocks; b; ) { mem_block *n = b->m_pNext; free(b); @@ -2815,7 +2817,6 @@ int jpeg_decoder::begin_decoding() jpeg_decoder::~jpeg_decoder() { free_all_blocks(); - delete(m_pStream); } @@ -3025,4 +3026,4 @@ unsigned char* jpgdDecompress(jpeg_decoder* decoder) } } return pImage_data; -} \ No newline at end of file +} -- 2.7.4 From 9acb636f80a7343ba6a99508101041def327dbb2 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 24 Jan 2022 21:21:17 +0900 Subject: [PATCH 07/16] loader png: fix all memory leaks. These were detected by asan with PicturePng example, fixed them all. Change-Id: I4a113656a0b7c06333ced36f9a8ff1d9715d83f9 --- src/loaders/png/tvgPngLoader.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/loaders/png/tvgPngLoader.cpp b/src/loaders/png/tvgPngLoader.cpp index 6126ff0..3e29317 100644 --- a/src/loaders/png/tvgPngLoader.cpp +++ b/src/loaders/png/tvgPngLoader.cpp @@ -72,6 +72,7 @@ PngLoader::PngLoader() PngLoader::~PngLoader() { if (freeData) free(data); + free(image); } @@ -121,7 +122,7 @@ bool PngLoader::open(const char* data, uint32_t size, bool copy) clear(); lodepng_state_init(&state); - + unsigned int width, height; if (lodepng_inspect(&width, &height, &state, (unsigned char*)(data), size) > 0) return false; @@ -180,10 +181,14 @@ unique_ptr PngLoader::bitmap() void PngLoader::run(unsigned tid) { + if (image) { + free(image); + image = nullptr; + } auto width = static_cast(w); auto height = static_cast(h); lodepng_decode(&image, &width, &height, &state, data, size); _premultiply((uint32_t*)(image), width, height); -} \ No newline at end of file +} -- 2.7.4 From 3726cd4945441b98c92d5f4559dc1ee4e95074ce Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 26 Jan 2022 17:58:01 +0900 Subject: [PATCH 08/16] examples images: updated sample resources Change-Id: Ifc2a5502a8b3ffb0843d409196ab839db2f59111 --- src/examples/images/godot-icon.svg | 140 +++++++++++++++++++++++++++++++ src/examples/images/godot-icon.tvg | Bin 0 -> 2189 bytes src/examples/images/samsung-galaxy-s.svg | 1 - src/examples/images/samsung-galaxy-s.tvg | Bin 6143 -> 0 bytes 4 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 src/examples/images/godot-icon.svg create mode 100644 src/examples/images/godot-icon.tvg delete mode 100644 src/examples/images/samsung-galaxy-s.svg delete mode 100644 src/examples/images/samsung-galaxy-s.tvg diff --git a/src/examples/images/godot-icon.svg b/src/examples/images/godot-icon.svg new file mode 100644 index 0000000..2e72438 --- /dev/null +++ b/src/examples/images/godot-icon.svg @@ -0,0 +1,140 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/examples/images/godot-icon.tvg b/src/examples/images/godot-icon.tvg new file mode 100644 index 0000000000000000000000000000000000000000..5290f7e0868df699b9a053ef1e8364e4b8955f6c GIT binary patch literal 2189 zcmWl|3pkSt0|4M}GklxPzPZfY_kC?bVjLt?yAdTve$vfpo6AAUlwVS5o0)G+rpP5Z zCOW!2HT%1$-(}{KbU6~D;xJuwszY@y{;ucw-{*Pb(z5n#Sa~%%= znIHfp@&Mp#G7|tAf9(WJiXj>}v#a+gd&C(BiQr>J7&CCtot?D)nEk3;Cum>udLXr- z3LaU3Cm`q@ zn!1b!7D%tdGkTM;l#CQi?4cV)mJq@8Jz10IMaTp?mD;q=NH=)1O3;bfN_kB3HCY@X2o~^tW<^Se!?Z-m5X7l$79BW41z@B0aaH z?!zF5>j}hYI^7ul4N0S85gJ+n=Ep?dm08uMGqo!`a4B^wH(p%!lisgcO(uKOxm<$B zqR>5*#xNd7Xm34g-iU7Hd!#o&X zaB#3V5+fFBSl-46#%2yOcBVXhLqL2PJ2pNZ(0TNRM2gO(qFXy3hT|W) z)@bSu=Jq{fw;FEjb~X_6N9jhp{HPPWN`D&nKYP;=8gFB zqTR-w4GN#%OL^U~h+YOdoSjSpIb2kR;#?M2HbfFHa_rVC77Ov;p0;8t)$+{N?`7P^qVI?UD%0pUm?`mWUC8A@x12|cB@?7s%Nt92C{=wE78l}7Xa*<#DjZXb zwKseA6#D#5vL57^RXK8b1$6nqnq%f^G&w{p4#FPB*m9RnrOPGqcf)(YFB3Apl}^1e zg#d0+N0?GYvY4wwagHAN3jke7wZh;pX-h+No0o5Bm4kn`hMm@`&6YtNsw0S{=zReO zH0x|fBLv5=9&Vah#=7IKw?YAB7S7Dp9LRuGl$u~V(Aqt0ML9_rUEU$X#-w;sW`txs zBy_5XFdW^|7Voii4*DU&%KuHai8_ERNM~Y+v6?biHMZ_ujAZAOrsVQh1V2vWx^4&J zz|cm&wWjAC8Y}4a_bX`?F^N$>Zm_T!6@ng#9sw*)F{~P08zH{+M{tH6yCx|#D$j

f3=j7;v$YSf^Rmg9riL0XqC&-bFs`Bj3I;2Zw+P&ERvSG zF(-mstU#7hBX-egn}67D<=##o=*_SpI_TKmR~=2K? zB-r1>X1qV~Bvc+KM_hTd4-0HMHka6Q=j5Fa4VUYmuY0n3X#b`C$E!c5x+EAot3)VI zB1Vgx1TcBf=YqdT_I!h$(&1?y(l?m?!=#@}U9)^=#2OsbdM5c?xCsW!mdAx?s2^#D zpZf}EXb;kJ3I}!`kt5~EjSl`x@CfYufCm_ zoa1_s@r{kaKYN>uv^%}n-PO3dL6l0J(R-&}yM^SWzF5Q1L \ No newline at end of file diff --git a/src/examples/images/samsung-galaxy-s.tvg b/src/examples/images/samsung-galaxy-s.tvg deleted file mode 100644 index ac642325e1f0169960299c23d382df2958f0330e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6143 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 -- 2.7.4 From 412fc993d1ea6be71a424845f4ce3c415f1e7dab Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Mon, 31 Jan 2022 14:05:58 +0100 Subject: [PATCH 09/16] common: styling++ (tabs -> spaces) Change-Id: I101d1d536e932924cfb0f70d174d51cddc0ff9e5 --- src/lib/gl_engine/tvgGlRenderer.cpp | 4 ++-- src/lib/gl_engine/tvgGlShaderSrc.cpp | 18 ++++++++-------- src/lib/sw_engine/tvgSwRasterNeon.h | 4 ++-- src/loaders/external_jpg/meson.build | 2 +- src/meson.build | 40 ++++++++++++++++++------------------ 5 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index 6123bf4..4384d52 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -147,8 +147,8 @@ bool GlRenderer::renderShape(RenderData data) const Fill* gradient = sdata->shape->fill(); if (gradient != nullptr) { - drawPrimitive(*sdata, gradient, i, RenderUpdateFlag::Gradient); - } + drawPrimitive(*sdata, gradient, i, RenderUpdateFlag::Gradient); + } } if(flags & (RenderUpdateFlag::Color | RenderUpdateFlag::Transform)) diff --git a/src/lib/gl_engine/tvgGlShaderSrc.cpp b/src/lib/gl_engine/tvgGlShaderSrc.cpp index ef8d8f9..bba73dc 100644 --- a/src/lib/gl_engine/tvgGlShaderSrc.cpp +++ b/src/lib/gl_engine/tvgGlShaderSrc.cpp @@ -26,13 +26,13 @@ #define TVG_COMPOSE_SHADER(shader) #shader const char* COLOR_VERT_SHADER = TVG_COMPOSE_SHADER( - attribute mediump vec4 aLocation; \n - uniform highp mat4 uTransform; \n - varying highp float vOpacity; \n - void main() \n - { \n + attribute mediump vec4 aLocation; \n + uniform highp mat4 uTransform; \n + varying highp float vOpacity; \n + void main() \n + { \n gl_Position = uTransform * vec4(aLocation.xy, 0.0, 1.0); \n - vOpacity = aLocation.z; \n + vOpacity = aLocation.z; \n }); const char* COLOR_FRAG_SHADER = TVG_COMPOSE_SHADER( @@ -47,11 +47,11 @@ const char* GRADIENT_VERT_SHADER = TVG_COMPOSE_SHADER( attribute highp vec4 aLocation; \n varying highp float vOpacity; \n varying highp vec2 vPos; \n -uniform highp mat4 uTransform; \n +uniform highp mat4 uTransform; \n \n void main() \n { \n - gl_Position = uTransform * vec4(aLocation.xy, 0.0, 1.0); \n + gl_Position = uTransform * vec4(aLocation.xy, 0.0, 1.0); \n vOpacity = aLocation.z; \n vPos = vec2((aLocation.x + 1.0) / 2.0, ((-1.0 * aLocation.y) +1.0) / 2.0); \n }); @@ -62,7 +62,7 @@ precision highp float; const int MAX_STOP_COUNT = 4; \n uniform highp vec2 uSize; \n uniform highp vec2 uCanvasSize; \n -uniform float nStops; \n +uniform float nStops; \n uniform float noise_level; \n uniform float stopPoints[MAX_STOP_COUNT]; \n uniform vec4 stopColors[MAX_STOP_COUNT]; \n diff --git a/src/lib/sw_engine/tvgSwRasterNeon.h b/src/lib/sw_engine/tvgSwRasterNeon.h index 593e4d3..a4b3cda 100644 --- a/src/lib/sw_engine/tvgSwRasterNeon.h +++ b/src/lib/sw_engine/tvgSwRasterNeon.h @@ -26,8 +26,8 @@ static inline uint8x8_t ALPHA_BLEND(uint8x8_t c, uint8x8_t a) { - uint16x8_t t = vmull_u8(c, a); - return vshrn_n_u16(t, 8); + uint16x8_t t = vmull_u8(c, a); + return vshrn_n_u16(t, 8); } diff --git a/src/loaders/external_jpg/meson.build b/src/loaders/external_jpg/meson.build index aeecf9f..ce657ba 100644 --- a/src/loaders/external_jpg/meson.build +++ b/src/loaders/external_jpg/meson.build @@ -6,7 +6,7 @@ source_file = [ jpg_dep = dependency('libturbojpeg', required: false) if not jpg_dep.found() - jpg_dep = cc.find_library('turbojpeg', required: false) + jpg_dep = cc.find_library('turbojpeg', required: false) endif if jpg_dep.found() diff --git a/src/meson.build b/src/meson.build index 8d1a270..26aba33 100644 --- a/src/meson.build +++ b/src/meson.build @@ -29,38 +29,38 @@ if host_machine.system() != 'windows' endif thorvg_lib = library( - 'thorvg', - include_directories : headers, - version : meson.project_version(), - dependencies : thorvg_lib_dep, - install : true, - cpp_args : compiler_flags, - gnu_symbol_visibility : 'hidden', + 'thorvg', + include_directories : headers, + version : meson.project_version(), + dependencies : thorvg_lib_dep, + install : true, + cpp_args : compiler_flags, + gnu_symbol_visibility : 'hidden', ) thorvg_dep = declare_dependency( - include_directories: headers, - link_with : thorvg_lib + include_directories: headers, + link_with : thorvg_lib ) if (cc.get_id() == 'emscripten') - subdir('wasm') + subdir('wasm') - executable('thorvg-wasm', - [], - include_directories : headers, - dependencies : [thorvg_lib_dep, thorvg_wasm_dep], - ) + executable('thorvg-wasm', + [], + include_directories : headers, + dependencies : [thorvg_lib_dep, thorvg_wasm_dep], + ) endif pkg_mod = import('pkgconfig') pkg_mod.generate( - libraries : thorvg_lib, - version : meson.project_version(), - name : 'libthorvg', - filebase : 'thorvg', - description : 'A Thor library for rendering vector graphics' + libraries : thorvg_lib, + version : meson.project_version(), + name : 'libthorvg', + filebase : 'thorvg', + description : 'A Thor library for rendering vector graphics' ) subdir('bin') -- 2.7.4 From 249e337e7792490d287e195e33a8cd0653bdee6e Mon Sep 17 00:00:00 2001 From: Michal Maciola Date: Fri, 4 Feb 2022 14:50:12 +0100 Subject: [PATCH 10/16] loader png external: fix potential memory leak if read fails Change-Id: I09cc563cbd7144112c5d8f593b3608a9bcdb7e40 --- src/loaders/external_png/tvgPngLoader.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/loaders/external_png/tvgPngLoader.cpp b/src/loaders/external_png/tvgPngLoader.cpp index 2991d25..05db65c 100644 --- a/src/loaders/external_png/tvgPngLoader.cpp +++ b/src/loaders/external_png/tvgPngLoader.cpp @@ -93,7 +93,10 @@ bool PngLoader::read() png_image_free(image); return false; } - if (!png_image_finish_read(image, NULL, buffer, 0, NULL)) return false; + if (!png_image_finish_read(image, NULL, buffer, 0, NULL)) { + free(buffer); + return false; + } content = reinterpret_cast(buffer); _premultiply(reinterpret_cast(buffer), image->width, image->height); -- 2.7.4 From 60e17287c1a21a1b91936ed8170b536c26b67cb8 Mon Sep 17 00:00:00 2001 From: jykeon Date: Mon, 27 Feb 2023 17:40:43 +0900 Subject: [PATCH 11/16] Bump up 0.7.6 Change-Id: I767a52803a91fc74456ea5d25196ffd7a1864882 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 a53aa64..295f2a1 100644 --- a/packaging/thorvg.spec +++ b/packaging/thorvg.spec @@ -1,6 +1,6 @@ Name: thorvg Summary: Thor Vector Graphics Library -Version: 0.7.5 +Version: 0.7.6 Release: 1 Group: Graphics System/Rendering Engine License: MIT -- 2.7.4 From 0a3689cfe19e5b276f80fdfe78a7cedf27eac1e1 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Sat, 8 Jan 2022 20:59:50 +0100 Subject: [PATCH 12/16] svg_loader: class attribute added It's the first step in introducing the css inline style sheets into tvg. For now the class attribute is set only for SvgNodes (not for grads), it's not used yet. Change-Id: Ib81c47b38f5f1355125dc0bff44f07cfbd7c12af --- src/loaders/svg/tvgSvgLoader.cpp | 30 ++++++++++++++++++++++++++++++ src/loaders/svg/tvgSvgLoaderCommon.h | 1 + 2 files changed, 31 insertions(+) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 4990c5c..7def62d 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -947,6 +947,15 @@ static void _handleDisplayAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, } +static void _handleCssClassAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value) +{ + auto cssClass = &node->style->cssClass; + + if (*cssClass && value) free(*cssClass); + *cssClass = _copyId(value); +} + + typedef void (*styleMethod)(SvgLoaderData* loader, SvgNode* node, const char* value); #define STYLE_DEF(Name, Name1, Flag) { #Name, sizeof(#Name), _handle##Name1##Attr, Flag } @@ -1027,6 +1036,8 @@ static bool _attrParseGNode(void* data, const char* key, const char* value) } else if (!strcmp(key, "id")) { if (node->id && value) free(node->id); node->id = _copyId(value); + } else if (!strcmp(key, "class")) { + _handleCssClassAttr(loader, node, value); } else if (!strcmp(key, "clip-path")) { _handleClipPathAttr(loader, node, value); } else if (!strcmp(key, "mask")) { @@ -1054,6 +1065,8 @@ static bool _attrParseClipPathNode(void* data, const char* key, const char* valu } else if (!strcmp(key, "id")) { if (node->id && value) free(node->id); node->id = _copyId(value); + } else if (!strcmp(key, "class")) { + _handleCssClassAttr(loader, node, value); } else if (!strcmp(key, "clipPathUnits")) { if (!strcmp(value, "objectBoundingBox")) clip->userSpace = false; } else { @@ -1076,6 +1089,8 @@ static bool _attrParseMaskNode(void* data, const char* key, const char* value) } else if (!strcmp(key, "id")) { if (node->id && value) free(node->id); node->id = _copyId(value); + } else if (!strcmp(key, "class")) { + _handleCssClassAttr(loader, node, value); } else if (!strcmp(key, "maskContentUnits")) { if (!strcmp(value, "objectBoundingBox")) mask->userSpace = false; } else if (!strcmp(key, "mask-type")) { @@ -1229,6 +1244,8 @@ static bool _attrParsePathNode(void* data, const char* key, const char* value) } else if (!strcmp(key, "id")) { if (node->id && value) free(node->id); node->id = _copyId(value); + } else if (!strcmp(key, "class")) { + _handleCssClassAttr(loader, node, value); } else { return _parseStyleAttr(loader, key, value, false); } @@ -1289,6 +1306,8 @@ static bool _attrParseCircleNode(void* data, const char* key, const char* value) } else if (!strcmp(key, "id")) { if (node->id && value) free(node->id); node->id = _copyId(value); + } else if (!strcmp(key, "class")) { + _handleCssClassAttr(loader, node, value); } else { return _parseStyleAttr(loader, key, value, false); } @@ -1343,6 +1362,8 @@ static bool _attrParseEllipseNode(void* data, const char* key, const char* value if (!strcmp(key, "id")) { if (node->id && value) free(node->id); node->id = _copyId(value); + } else if (!strcmp(key, "class")) { + _handleCssClassAttr(loader, node, value); } else if (!strcmp(key, "style")) { return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); } else if (!strcmp(key, "clip-path")) { @@ -1426,6 +1447,8 @@ static bool _attrParsePolygonNode(void* data, const char* key, const char* value } else if (!strcmp(key, "id")) { if (node->id && value) free(node->id); node->id = _copyId(value); + } else if (!strcmp(key, "class")) { + _handleCssClassAttr(loader, node, value); } else { return _parseStyleAttr(loader, key, value, false); } @@ -1500,6 +1523,8 @@ static bool _attrParseRectNode(void* data, const char* key, const char* value) if (!strcmp(key, "id")) { if (node->id && value) free(node->id); node->id = _copyId(value); + } else if (!strcmp(key, "class")) { + _handleCssClassAttr(loader, node, value); } else if (!strcmp(key, "style")) { ret = simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); } else if (!strcmp(key, "clip-path")) { @@ -1563,6 +1588,8 @@ static bool _attrParseLineNode(void* data, const char* key, const char* value) if (!strcmp(key, "id")) { if (node->id && value) free(node->id); node->id = _copyId(value); + } else if (!strcmp(key, "class")) { + _handleCssClassAttr(loader, node, value); } else if (!strcmp(key, "style")) { return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); } else if (!strcmp(key, "clip-path")) { @@ -1634,6 +1661,8 @@ static bool _attrParseImageNode(void* data, const char* key, const char* value) } else if (!strcmp(key, "id")) { if (node->id && value) free(node->id); node->id = _copyId(value); + } else if (!strcmp(key, "class")) { + _handleCssClassAttr(loader, node, value); } else if (!strcmp(key, "style")) { return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); } else if (!strcmp(key, "clip-path")) { @@ -2767,6 +2796,7 @@ static void _freeNodeStyle(SvgStyleProperty* style) //style->clipPath.node and style->mask.node has only the addresses of node. Therefore, node is released from _freeNode. free(style->clipPath.url); free(style->mask.url); + free(style->cssClass); if (style->fill.paint.gradient) { style->fill.paint.gradient->clear(); diff --git a/src/loaders/svg/tvgSvgLoaderCommon.h b/src/loaders/svg/tvgSvgLoaderCommon.h index c6685c6..04f5b34 100644 --- a/src/loaders/svg/tvgSvgLoaderCommon.h +++ b/src/loaders/svg/tvgSvgLoaderCommon.h @@ -341,6 +341,7 @@ struct SvgStyleProperty int opacity; SvgColor color; bool curColorSet; + char* cssClass; SvgStyleFlags flags; }; -- 2.7.4 From fee0c9f5f34d8a4ee7ab3777b69074aa63b94d0d Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Sun, 9 Jan 2022 21:31:24 +0100 Subject: [PATCH 13/16] svg_loader: css style node introduced For now it is assumed that only one style element is defined in an svg file, although it can be easily changed if needed. The style node will be used to define the style applied to a node of a given type or in a case when a class attrib was used. Change-Id: I53e95dadfbf8a1a48903bc9f07bd2cbec82a4eda --- src/loaders/svg/tvgSvgLoader.cpp | 33 +++++++++++++++++++++++++++++++-- src/loaders/svg/tvgSvgLoaderCommon.h | 7 +++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 7def62d..2a9cba5 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -1102,6 +1102,21 @@ static bool _attrParseMaskNode(void* data, const char* key, const char* value) } +static bool _attrParseCssStyleNode(void* data, const char* key, const char* value) +{ + SvgLoaderData* loader = (SvgLoaderData*)data; + SvgNode* node = loader->svgParse->node; + + if (!strcmp(key, "id")) { + if (node->id && value) free(node->id); + node->id = _copyId(value); + } else { + return _parseStyleAttr(loader, key, value, false); + } + return true; +} + + static SvgNode* _createNode(SvgNode* parent, SvgNodeType type) { SvgNode* node = (SvgNode*)calloc(1, sizeof(SvgNode)); @@ -1226,6 +1241,17 @@ static SvgNode* _createClipPathNode(SvgLoaderData* loader, SvgNode* parent, cons return loader->svgParse->node; } + +static SvgNode* _createCssStyleNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +{ + loader->svgParse->node = _createNode(parent, SvgNodeType::CssStyle); + if (!loader->svgParse->node) return nullptr; + + simpleXmlParseAttributes(buf, bufLength, _attrParseCssStyleNode, loader); + return loader->svgParse->node; +} + + static bool _attrParsePathNode(void* data, const char* key, const char* value) { SvgLoaderData* loader = (SvgLoaderData*)data; @@ -2096,7 +2122,8 @@ static constexpr struct {"g", sizeof("g"), _createGNode}, {"svg", sizeof("svg"), _createSvgNode}, {"mask", sizeof("mask"), _createMaskNode}, - {"clipPath", sizeof("clipPath"), _createClipPathNode} + {"clipPath", sizeof("clipPath"), _createClipPathNode}, + {"style", sizeof("style"), _createCssStyleNode} }; @@ -2526,7 +2553,8 @@ static constexpr struct {"svg", sizeof("svg")}, {"defs", sizeof("defs")}, {"mask", sizeof("mask")}, - {"clipPath", sizeof("clipPath")} + {"clipPath", sizeof("clipPath")}, + {"style", sizeof("style")} }; @@ -2585,6 +2613,7 @@ 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; node = method(loader, parent, attrs, attrsLength); + if (!strcmp(tagName, "style")) loader->cssStyle = node; } if (!node) return; diff --git a/src/loaders/svg/tvgSvgLoaderCommon.h b/src/loaders/svg/tvgSvgLoaderCommon.h index 04f5b34..41c4184 100644 --- a/src/loaders/svg/tvgSvgLoaderCommon.h +++ b/src/loaders/svg/tvgSvgLoaderCommon.h @@ -51,6 +51,7 @@ enum class SvgNodeType Video, ClipPath, Mask, + CssStyle, Unknown }; @@ -233,6 +234,10 @@ struct SvgMaskNode bool userSpace; }; +struct SvgCssStyleNode +{ +}; + struct SvgLinearGradient { float x1; @@ -368,6 +373,7 @@ struct SvgNode SvgImageNode image; SvgMaskNode mask; SvgClipNode clip; + SvgCssStyleNode cssStyle; } node; bool display; ~SvgNode(); @@ -402,6 +408,7 @@ struct SvgLoaderData Array stack = {nullptr, 0, 0}; SvgNode* doc = nullptr; SvgNode* def = nullptr; + SvgNode* cssStyle = nullptr; Array gradients; SvgStyleGradient* latestGradient = nullptr; //For stops SvgParser* svgParse = nullptr; -- 2.7.4 From 36f52d998c92c6c982d9bc7208e4cb0fda7459eb Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Wed, 12 Jan 2022 16:23:22 +0100 Subject: [PATCH 14/16] svg_loader: intro to the implementation of the css internal style sheets parsing Function simpleXmlParseCSSAttribute() used to parse the data inside the style tag. For now the supported formats are: tag {}, .name {}, tag.name{} _svgLoaderParserXmlStyle() used to deal with the results of the above - to create the proper nodes. Will work after create...Node() are changed. Note: The geometric attributes are not copied from the node defining the style to the node using it. The SVG2 standard has to be checked to decide whether it should be supported. Change-Id: I0b910bbb88d1142909f997219621c9011ed4e39c --- src/loaders/svg/tvgSvgLoader.cpp | 189 ++++++++++++++++++++++++----------- src/loaders/svg/tvgSvgLoaderCommon.h | 1 + src/loaders/svg/tvgXmlParser.cpp | 41 ++++++++ src/loaders/svg/tvgXmlParser.h | 7 +- 4 files changed, 176 insertions(+), 62 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 2a9cba5..274b198 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -80,6 +80,9 @@ typedef SvgNode* (*FactoryMethod)(SvgLoaderData* loader, SvgNode* parent, const typedef SvgStyleGradient* (*GradientFactoryMethod)(SvgLoaderData* loader, const char* buf, unsigned bufLength); +static void _copyAttr(SvgNode* to, const SvgNode* from, bool copyGeomAttrib = true); + + static char* _skipSpace(const char* str, const char* end) { while (((end && str < end) || (!end && *str != '\0')) && isspace(*str)) { @@ -947,12 +950,32 @@ static void _handleDisplayAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, } -static void _handleCssClassAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value) +static SvgNode* _findCssStyleNode(const SvgNode* cssStyle, const char* title) +{ + if (!cssStyle) return nullptr; + + auto child = cssStyle->child.data; + for (uint32_t i = 0; i < cssStyle->child.count; ++i, ++child) { + if (((*child)->id) && !strcmp((*child)->id, title)) return (*child); + } + return nullptr; + + +} + + +static void _handleCssClassAttr(SvgLoaderData* loader, SvgNode* node, const char* value) { auto cssClass = &node->style->cssClass; if (*cssClass && value) free(*cssClass); *cssClass = _copyId(value); + + //TODO: works only if style was defined before it is used + if (auto cssNode = _findCssStyleNode(loader->cssStyle, *cssClass)) { + //TODO: check SVG2 stndard - should the geometric properties be copied? + _copyAttr(node, cssNode, false); + } } @@ -1908,7 +1931,7 @@ static void _styleCopy(SvgStyleProperty* to, const SvgStyleProperty* from) } -static void _copyAttr(SvgNode* to, const SvgNode* from) +static void _copyAttr(SvgNode* to, const SvgNode* from, bool copyGeomAttrib) { //Copy matrix attribute if (from->transform) { @@ -1923,67 +1946,67 @@ static void _copyAttr(SvgNode* to, const SvgNode* from) 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); - //Copy node attribute - switch (from->type) { - case SvgNodeType::Circle: { - to->node.circle.cx = from->node.circle.cx; - to->node.circle.cy = from->node.circle.cy; - to->node.circle.r = from->node.circle.r; - break; - } - case SvgNodeType::Ellipse: { - to->node.ellipse.cx = from->node.ellipse.cx; - to->node.ellipse.cy = from->node.ellipse.cy; - to->node.ellipse.rx = from->node.ellipse.rx; - to->node.ellipse.ry = from->node.ellipse.ry; - break; - } - case SvgNodeType::Rect: { - to->node.rect.x = from->node.rect.x; - to->node.rect.y = from->node.rect.y; - to->node.rect.w = from->node.rect.w; - to->node.rect.h = from->node.rect.h; - to->node.rect.rx = from->node.rect.rx; - to->node.rect.ry = from->node.rect.ry; - to->node.rect.hasRx = from->node.rect.hasRx; - to->node.rect.hasRy = from->node.rect.hasRy; - break; - } - case SvgNodeType::Line: { - to->node.line.x1 = from->node.line.x1; - to->node.line.y1 = from->node.line.y1; - to->node.line.x2 = from->node.line.x2; - to->node.line.y2 = from->node.line.y2; - break; - } - case SvgNodeType::Path: { - if (from->node.path.path) to->node.path.path = strdup(from->node.path.path); - break; - } - case SvgNodeType::Polygon: { - if ((to->node.polygon.pointsCount = from->node.polygon.pointsCount)) { + if (copyGeomAttrib) { + //Copy node attribute + switch (from->type) { + case SvgNodeType::Circle: { + to->node.circle.cx = from->node.circle.cx; + to->node.circle.cy = from->node.circle.cy; + to->node.circle.r = from->node.circle.r; + break; + } + case SvgNodeType::Ellipse: { + to->node.ellipse.cx = from->node.ellipse.cx; + to->node.ellipse.cy = from->node.ellipse.cy; + to->node.ellipse.rx = from->node.ellipse.rx; + to->node.ellipse.ry = from->node.ellipse.ry; + break; + } + case SvgNodeType::Rect: { + to->node.rect.x = from->node.rect.x; + to->node.rect.y = from->node.rect.y; + to->node.rect.w = from->node.rect.w; + to->node.rect.h = from->node.rect.h; + to->node.rect.rx = from->node.rect.rx; + to->node.rect.ry = from->node.rect.ry; + to->node.rect.hasRx = from->node.rect.hasRx; + to->node.rect.hasRy = from->node.rect.hasRy; + break; + } + case SvgNodeType::Line: { + to->node.line.x1 = from->node.line.x1; + to->node.line.y1 = from->node.line.y1; + to->node.line.x2 = from->node.line.x2; + to->node.line.y2 = from->node.line.y2; + break; + } + case SvgNodeType::Path: { + if (from->node.path.path) to->node.path.path = strdup(from->node.path.path); + break; + } + case SvgNodeType::Polygon: { + to->node.polygon.pointsCount = from->node.polygon.pointsCount; to->node.polygon.points = (float*)malloc(to->node.polygon.pointsCount * sizeof(float)); memcpy(to->node.polygon.points, from->node.polygon.points, to->node.polygon.pointsCount * sizeof(float)); + break; } - break; - } - case SvgNodeType::Polyline: { - if ((to->node.polyline.pointsCount = from->node.polyline.pointsCount)) { + case SvgNodeType::Polyline: { + to->node.polyline.pointsCount = from->node.polyline.pointsCount; to->node.polyline.points = (float*)malloc(to->node.polyline.pointsCount * sizeof(float)); memcpy(to->node.polyline.points, from->node.polyline.points, to->node.polyline.pointsCount * sizeof(float)); + break; + } + case SvgNodeType::Image: { + to->node.image.x = from->node.image.x; + 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); + break; + } + default: { + break; } - break; - } - case SvgNodeType::Image: { - to->node.image.x = from->node.image.x; - 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); - break; - } - default: { - break; } } } @@ -2093,6 +2116,7 @@ static SvgNode* _createUseNode(SvgLoaderData* loader, SvgNode* parent, const cha return loader->svgParse->node; } + //TODO: Implement 'text' primitive static constexpr struct { @@ -2583,6 +2607,7 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content, GradientFactoryMethod gradientMethod; SvgNode *node = nullptr, *parent = nullptr; loader->level++; + loader->style = false; attrs = simpleXmlFindAttributesTag(content, length); if (!attrs) { @@ -2613,7 +2638,10 @@ 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; node = method(loader, parent, attrs, attrsLength); - if (!strcmp(tagName, "style")) loader->cssStyle = node; + if (!strcmp(tagName, "style")) { + loader->cssStyle = node; + loader->style = true; + } } if (!node) return; @@ -2654,6 +2682,46 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content, } +static void _svgLoaderParserXmlStyle(SvgLoaderData* loader, const char* content, unsigned int length) +{ + char* tag; + char* name; + const char* attrs = nullptr; + unsigned int attrsLength = 0; + + FactoryMethod method; + GradientFactoryMethod gradientMethod; + SvgNode *node = nullptr; + + const char *buf = content; + unsigned buflen = length; + + + while (auto next = simpleXmlParseCSSAttribute(buf, buflen, &tag, &name, &attrs, &attrsLength)) { + if ((method = _findGroupFactory(tag))) { + //TODO - node->id ??? add additional var for svgnode? + if ((node = method(loader, loader->cssStyle, attrs, attrsLength))) node->id = _copyId(name); + } else if ((method = _findGraphicsFactory(tag))) { + if ((node = method(loader, loader->cssStyle, attrs, attrsLength))) node->id = _copyId(name); + //TODO - implement + } else if ((gradientMethod = _findGradientFactory(tag))) { + //TODO - implement + //SvgStyleGradient* gradient = gradientMethod(loader, attrs, attrsLength); + } else if (!strcmp(tag, "stop")) { + //TODO - implement + } else if (!isIgnoreUnsupportedLogElements(tag)) { + TVGLOG("SVG", "Unsupported elements used [Elements: %s]", tag); + } + + buflen -= next - buf; + buf = next; + + free(tag); + free(name); + } +} + + static bool _svgLoaderParser(void* data, SimpleXMLType type, const char* content, unsigned int length) { SvgLoaderData* loader = (SvgLoaderData*)data; @@ -2672,7 +2740,10 @@ static bool _svgLoaderParser(void* data, SimpleXMLType type, const char* content break; } case SimpleXMLType::Data: - case SimpleXMLType::CData: + case SimpleXMLType::CData: { + if (loader->style) _svgLoaderParserXmlStyle(loader, content, length); + break; + } case SimpleXMLType::DoctypeChild: { break; } diff --git a/src/loaders/svg/tvgSvgLoaderCommon.h b/src/loaders/svg/tvgSvgLoaderCommon.h index 41c4184..9669660 100644 --- a/src/loaders/svg/tvgSvgLoaderCommon.h +++ b/src/loaders/svg/tvgSvgLoaderCommon.h @@ -415,6 +415,7 @@ struct SvgLoaderData Array cloneNodes; int level = 0; bool result = false; + bool style = false; //TODO: find a better sollution? }; /* diff --git a/src/loaders/svg/tvgXmlParser.cpp b/src/loaders/svg/tvgXmlParser.cpp index d182bc2..8381ade 100644 --- a/src/loaders/svg/tvgXmlParser.cpp +++ b/src/loaders/svg/tvgXmlParser.cpp @@ -509,6 +509,47 @@ bool simpleXmlParseW3CAttribute(const char* buf, simpleXMLAttributeCb func, cons } +/* + * Supported formats: + * tag {}, .name {}, tag.name{} + */ +const char* simpleXmlParseCSSAttribute(const char* buf, unsigned bufLength, char** tag, char** name, const char** attrs, unsigned* attrsLength) +{ + if (!buf) return nullptr; + + *tag = *name = nullptr; + *attrsLength = 0; + + auto itr = _simpleXmlSkipWhiteSpace(buf, buf + bufLength); + auto itrEnd = (const char*)memchr(buf, '{', bufLength); + + if (!itrEnd || itr == itrEnd) return nullptr; + + auto nextElement = (const char*)memchr(itrEnd, '}', bufLength - (itrEnd - buf)); + if (!nextElement) return nullptr; + + *attrs = itrEnd + 1; + *attrsLength = nextElement - *attrs; + + const char *p; + + itrEnd = _simpleXmlUnskipWhiteSpace(itrEnd, itr); + if (*(itrEnd - 1) == '.') return nullptr; + + for (p = itr; p < itrEnd; p++) { + if (*p == '.') break; + } + + if (p == itr) *tag = strdup("all"); + else *tag = strndup(itr, p - itr); + + if (p == itrEnd) *name = nullptr; + else *name = strndup(p + 1, itrEnd - p - 1); + + return (nextElement ? nextElement + 1 : nullptr); +} + + const char* simpleXmlFindAttributesTag(const char* buf, unsigned bufLength) { const char *itr = buf, *itrEnd = buf + bufLength; diff --git a/src/loaders/svg/tvgXmlParser.h b/src/loaders/svg/tvgXmlParser.h index aa00668..3f703bf 100644 --- a/src/loaders/svg/tvgXmlParser.h +++ b/src/loaders/svg/tvgXmlParser.h @@ -32,7 +32,7 @@ const int xmlEntityLength[] = {6, 6, 6, 5, 4, 4, 6, 6}; enum class SimpleXMLType { Open = 0, //!< \ - OpenEmpty, //!< \ + OpenEmpty, //!< \ Close, //!< \ Data, //!< tag text data CData, //!< \ @@ -41,7 +41,7 @@ enum class SimpleXMLType Doctype, //!< \ Ignored, //!< whatever is ignored by parser, like whitespace - DoctypeChild //!< \ Date: Mon, 17 Jan 2022 19:35:05 +0100 Subject: [PATCH 15/16] svg_loader: additional arg added into create...Node() functions A function pointer added as an additional arg in order to make it possible to use these functions to create a normal nodes and also nodes defined inside a style tag. These two cases need to be parsed using different functions: simpleXmlParseAttributes() and simpleXmlParseW3CAttribute(). Change-Id: Ic039b5b21172326bea15060195b2cb14153036a4 --- src/loaders/svg/tvgSvgLoader.cpp | 97 ++++++++++++++++++++-------------------- src/loaders/svg/tvgXmlParser.cpp | 2 +- src/loaders/svg/tvgXmlParser.h | 2 +- 3 files changed, 51 insertions(+), 50 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 274b198..e074f20 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -76,7 +76,8 @@ #define PX_PER_CM 37.79528f //1 in = 2.54 cm -> PX_PER_IN/2.54 -typedef SvgNode* (*FactoryMethod)(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength); +typedef bool (*parseAttributes)(const char*, unsigned, simpleXMLAttributeCb, const void*); +typedef SvgNode* (*FactoryMethod)(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func); typedef SvgStyleGradient* (*GradientFactoryMethod)(SvgLoaderData* loader, const char* buf, unsigned bufLength); @@ -797,7 +798,7 @@ static bool _attrParseSvgNode(void* data, const char* key, const char* value) } else if (!strcmp(key, "preserveAspectRatio")) { if (!strcmp(value, "none")) doc->preserveAspect = false; } else if (!strcmp(key, "style")) { - return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); + return simpleXmlParseW3CAttribute(value, 0, _parseStyleAttr, loader); } #ifdef THORVG_LOG_ENABLED else if ((!strcmp(key, "x") || !strcmp(key, "y")) && fabsf(svgUtilStrtof(value, nullptr)) > FLT_EPSILON) { @@ -1053,7 +1054,7 @@ static bool _attrParseGNode(void* data, const char* key, const char* value) SvgNode* node = loader->svgParse->node; if (!strcmp(key, "style")) { - return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); + return simpleXmlParseW3CAttribute(value, 0, _parseStyleAttr, loader); } else if (!strcmp(key, "transform")) { node->transform = _parseTransformationMatrix(value); } else if (!strcmp(key, "id")) { @@ -1082,7 +1083,7 @@ static bool _attrParseClipPathNode(void* data, const char* key, const char* valu SvgClipNode* clip = &(node->node.clip); if (!strcmp(key, "style")) { - return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); + return simpleXmlParseW3CAttribute(value, 0, _parseStyleAttr, loader); } else if (!strcmp(key, "transform")) { node->transform = _parseTransformationMatrix(value); } else if (!strcmp(key, "id")) { @@ -1106,7 +1107,7 @@ static bool _attrParseMaskNode(void* data, const char* key, const char* value) SvgMaskNode* mask = &(node->node.mask); if (!strcmp(key, "style")) { - return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); + return simpleXmlParseW3CAttribute(value, 0, _parseStyleAttr, loader); } else if (!strcmp(key, "transform")) { node->transform = _parseTransformationMatrix(value); } else if (!strcmp(key, "id")) { @@ -1191,7 +1192,7 @@ static SvgNode* _createNode(SvgNode* parent, SvgNodeType type) } -static SvgNode* _createDefsNode(TVG_UNUSED SvgLoaderData* loader, TVG_UNUSED SvgNode* parent, const char* buf, unsigned bufLength) +static SvgNode* _createDefsNode(TVG_UNUSED SvgLoaderData* loader, TVG_UNUSED SvgNode* parent, const char* buf, unsigned bufLength, TVG_UNUSED parseAttributes func) { if (loader->def && loader->doc->node.doc.defs) return loader->def; SvgNode* node = _createNode(nullptr, SvgNodeType::Defs); @@ -1202,17 +1203,17 @@ static SvgNode* _createDefsNode(TVG_UNUSED SvgLoaderData* loader, TVG_UNUSED Svg } -static SvgNode* _createGNode(TVG_UNUSED SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +static SvgNode* _createGNode(TVG_UNUSED SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func) { loader->svgParse->node = _createNode(parent, SvgNodeType::G); if (!loader->svgParse->node) return nullptr; - simpleXmlParseAttributes(buf, bufLength, _attrParseGNode, loader); + func(buf, bufLength, _attrParseGNode, loader); return loader->svgParse->node; } -static SvgNode* _createSvgNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +static SvgNode* _createSvgNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func) { loader->svgParse->node = _createNode(parent, SvgNodeType::Doc); if (!loader->svgParse->node) return nullptr; @@ -1222,7 +1223,7 @@ static SvgNode* _createSvgNode(SvgLoaderData* loader, SvgNode* parent, const cha loader->svgParse->global.h = 0; doc->preserveAspect = true; - simpleXmlParseAttributes(buf, bufLength, _attrParseSvgNode, loader); + func(buf, bufLength, _attrParseSvgNode, loader); if (loader->svgParse->global.w == 0) { if (doc->w < FLT_EPSILON) loader->svgParse->global.w = 1; @@ -1237,7 +1238,7 @@ static SvgNode* _createSvgNode(SvgLoaderData* loader, SvgNode* parent, const cha } -static SvgNode* _createMaskNode(SvgLoaderData* loader, SvgNode* parent, TVG_UNUSED const char* buf, TVG_UNUSED unsigned bufLength) +static SvgNode* _createMaskNode(SvgLoaderData* loader, SvgNode* parent, TVG_UNUSED const char* buf, TVG_UNUSED unsigned bufLength, parseAttributes func) { loader->svgParse->node = _createNode(parent, SvgNodeType::Mask); if (!loader->svgParse->node) return nullptr; @@ -1245,13 +1246,13 @@ static SvgNode* _createMaskNode(SvgLoaderData* loader, SvgNode* parent, TVG_UNUS loader->svgParse->node->node.mask.userSpace = true; loader->svgParse->node->node.mask.type = SvgMaskType::Luminance; - simpleXmlParseAttributes(buf, bufLength, _attrParseMaskNode, loader); + func(buf, bufLength, _attrParseMaskNode, loader); return loader->svgParse->node; } -static SvgNode* _createClipPathNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +static SvgNode* _createClipPathNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func) { loader->svgParse->node = _createNode(parent, SvgNodeType::ClipPath); if (!loader->svgParse->node) return nullptr; @@ -1259,18 +1260,18 @@ static SvgNode* _createClipPathNode(SvgLoaderData* loader, SvgNode* parent, cons loader->svgParse->node->display = false; loader->svgParse->node->node.clip.userSpace = true; - simpleXmlParseAttributes(buf, bufLength, _attrParseClipPathNode, loader); + func(buf, bufLength, _attrParseClipPathNode, loader); return loader->svgParse->node; } -static SvgNode* _createCssStyleNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +static SvgNode* _createCssStyleNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func) { loader->svgParse->node = _createNode(parent, SvgNodeType::CssStyle); if (!loader->svgParse->node) return nullptr; - simpleXmlParseAttributes(buf, bufLength, _attrParseCssStyleNode, loader); + func(buf, bufLength, _attrParseCssStyleNode, loader); return loader->svgParse->node; } @@ -1285,7 +1286,7 @@ static bool _attrParsePathNode(void* data, const char* key, const char* value) //Temporary: need to copy path->path = _copyId(value); } else if (!strcmp(key, "style")) { - return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); + return simpleXmlParseW3CAttribute(value, 0, _parseStyleAttr, loader); } else if (!strcmp(key, "clip-path")) { _handleClipPathAttr(loader, node, value); } else if (!strcmp(key, "mask")) { @@ -1302,13 +1303,13 @@ static bool _attrParsePathNode(void* data, const char* key, const char* value) } -static SvgNode* _createPathNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +static SvgNode* _createPathNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func) { loader->svgParse->node = _createNode(parent, SvgNodeType::Path); if (!loader->svgParse->node) return nullptr; - simpleXmlParseAttributes(buf, bufLength, _attrParsePathNode, loader); + func(buf, bufLength, _attrParsePathNode, loader); return loader->svgParse->node; } @@ -1347,7 +1348,7 @@ static bool _attrParseCircleNode(void* data, const char* key, const char* value) } if (!strcmp(key, "style")) { - return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); + return simpleXmlParseW3CAttribute(value, 0, _parseStyleAttr, loader); } else if (!strcmp(key, "clip-path")) { _handleClipPathAttr(loader, node, value); } else if (!strcmp(key, "mask")) { @@ -1364,13 +1365,13 @@ static bool _attrParseCircleNode(void* data, const char* key, const char* value) } -static SvgNode* _createCircleNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +static SvgNode* _createCircleNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func) { loader->svgParse->node = _createNode(parent, SvgNodeType::Circle); if (!loader->svgParse->node) return nullptr; - simpleXmlParseAttributes(buf, bufLength, _attrParseCircleNode, loader); + func(buf, bufLength, _attrParseCircleNode, loader); return loader->svgParse->node; } @@ -1414,7 +1415,7 @@ static bool _attrParseEllipseNode(void* data, const char* key, const char* value } else if (!strcmp(key, "class")) { _handleCssClassAttr(loader, node, value); } else if (!strcmp(key, "style")) { - return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); + return simpleXmlParseW3CAttribute(value, 0, _parseStyleAttr, loader); } else if (!strcmp(key, "clip-path")) { _handleClipPathAttr(loader, node, value); } else if (!strcmp(key, "mask")) { @@ -1426,13 +1427,13 @@ static bool _attrParseEllipseNode(void* data, const char* key, const char* value } -static SvgNode* _createEllipseNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +static SvgNode* _createEllipseNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func) { loader->svgParse->node = _createNode(parent, SvgNodeType::Ellipse); if (!loader->svgParse->node) return nullptr; - simpleXmlParseAttributes(buf, bufLength, _attrParseEllipseNode, loader); + func(buf, bufLength, _attrParseEllipseNode, loader); return loader->svgParse->node; } @@ -1488,7 +1489,7 @@ static bool _attrParsePolygonNode(void* data, const char* key, const char* value if (!strcmp(key, "points")) { return _attrParsePolygonPoints(value, &polygon->points, &polygon->pointsCount); } else if (!strcmp(key, "style")) { - return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); + return simpleXmlParseW3CAttribute(value, 0, _parseStyleAttr, loader); } else if (!strcmp(key, "clip-path")) { _handleClipPathAttr(loader, node, value); } else if (!strcmp(key, "mask")) { @@ -1505,24 +1506,24 @@ static bool _attrParsePolygonNode(void* data, const char* key, const char* value } -static SvgNode* _createPolygonNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +static SvgNode* _createPolygonNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func) { loader->svgParse->node = _createNode(parent, SvgNodeType::Polygon); if (!loader->svgParse->node) return nullptr; - simpleXmlParseAttributes(buf, bufLength, _attrParsePolygonNode, loader); + func(buf, bufLength, _attrParsePolygonNode, loader); return loader->svgParse->node; } -static SvgNode* _createPolylineNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +static SvgNode* _createPolylineNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func) { loader->svgParse->node = _createNode(parent, SvgNodeType::Polyline); if (!loader->svgParse->node) return nullptr; - simpleXmlParseAttributes(buf, bufLength, _attrParsePolygonNode, loader); + func(buf, bufLength, _attrParsePolygonNode, loader); return loader->svgParse->node; } @@ -1575,7 +1576,7 @@ static bool _attrParseRectNode(void* data, const char* key, const char* value) } else if (!strcmp(key, "class")) { _handleCssClassAttr(loader, node, value); } else if (!strcmp(key, "style")) { - ret = simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); + ret = simpleXmlParseW3CAttribute(value, 0, _parseStyleAttr, loader); } else if (!strcmp(key, "clip-path")) { _handleClipPathAttr(loader, node, value); } else if (!strcmp(key, "mask")) { @@ -1588,7 +1589,7 @@ static bool _attrParseRectNode(void* data, const char* key, const char* value) } -static SvgNode* _createRectNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +static SvgNode* _createRectNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func) { loader->svgParse->node = _createNode(parent, SvgNodeType::Rect); @@ -1596,7 +1597,7 @@ static SvgNode* _createRectNode(SvgLoaderData* loader, SvgNode* parent, const ch loader->svgParse->node->node.rect.hasRx = loader->svgParse->node->node.rect.hasRy = false; - simpleXmlParseAttributes(buf, bufLength, _attrParseRectNode, loader); + func(buf, bufLength, _attrParseRectNode, loader); return loader->svgParse->node; } @@ -1640,7 +1641,7 @@ static bool _attrParseLineNode(void* data, const char* key, const char* value) } else if (!strcmp(key, "class")) { _handleCssClassAttr(loader, node, value); } else if (!strcmp(key, "style")) { - return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); + return simpleXmlParseW3CAttribute(value, 0, _parseStyleAttr, loader); } else if (!strcmp(key, "clip-path")) { _handleClipPathAttr(loader, node, value); } else if (!strcmp(key, "mask")) { @@ -1652,13 +1653,13 @@ static bool _attrParseLineNode(void* data, const char* key, const char* value) } -static SvgNode* _createLineNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +static SvgNode* _createLineNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func) { loader->svgParse->node = _createNode(parent, SvgNodeType::Line); if (!loader->svgParse->node) return nullptr; - simpleXmlParseAttributes(buf, bufLength, _attrParseLineNode, loader); + func(buf, bufLength, _attrParseLineNode, loader); return loader->svgParse->node; } @@ -1713,7 +1714,7 @@ static bool _attrParseImageNode(void* data, const char* key, const char* value) } else if (!strcmp(key, "class")) { _handleCssClassAttr(loader, node, value); } else if (!strcmp(key, "style")) { - return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); + return simpleXmlParseW3CAttribute(value, 0, _parseStyleAttr, loader); } else if (!strcmp(key, "clip-path")) { _handleClipPathAttr(loader, node, value); } else if (!strcmp(key, "mask")) { @@ -1725,13 +1726,13 @@ static bool _attrParseImageNode(void* data, const char* key, const char* value) } -static SvgNode* _createImageNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +static SvgNode* _createImageNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func) { loader->svgParse->node = _createNode(parent, SvgNodeType::Image); if (!loader->svgParse->node) return nullptr; - simpleXmlParseAttributes(buf, bufLength, _attrParseImageNode, loader); + func(buf, bufLength, _attrParseImageNode, loader); return loader->svgParse->node; } @@ -2106,13 +2107,13 @@ static bool _attrParseUseNode(void* data, const char* key, const char* value) } -static SvgNode* _createUseNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +static SvgNode* _createUseNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func) { loader->svgParse->node = _createNode(parent, SvgNodeType::Use); if (!loader->svgParse->node) return nullptr; - simpleXmlParseAttributes(buf, bufLength, _attrParseUseNode, loader); + func(buf, bufLength, _attrParseUseNode, loader); return loader->svgParse->node; } @@ -2389,7 +2390,7 @@ static bool _attrParseStops(void* data, const char* key, const char* value) _toColor(value, &stop->r, &stop->g, &stop->b, nullptr); } } else if (!strcmp(key, "style")) { - simpleXmlParseW3CAttribute(value, _attrParseStopsStyle, data); + simpleXmlParseW3CAttribute(value, 0, _attrParseStopsStyle, data); } else { return false; } @@ -2631,13 +2632,13 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content, if (empty) return; if (!loader->doc) { if (strcmp(tagName, "svg")) return; //Not a valid svg document - node = method(loader, nullptr, attrs, attrsLength); + node = method(loader, nullptr, attrs, attrsLength, simpleXmlParseAttributes); loader->doc = node; } else { 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); + node = method(loader, parent, attrs, attrsLength, simpleXmlParseAttributes); if (!strcmp(tagName, "style")) { loader->cssStyle = node; loader->style = true; @@ -2651,7 +2652,7 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content, } else if ((method = _findGraphicsFactory(tagName))) { if (loader->stack.count > 0) parent = loader->stack.data[loader->stack.count - 1]; else parent = loader->doc; - node = method(loader, parent, attrs, attrsLength); + node = method(loader, parent, attrs, attrsLength, simpleXmlParseAttributes); } else if ((gradientMethod = _findGradientFactory(tagName))) { SvgStyleGradient* gradient; gradient = gradientMethod(loader, attrs, attrsLength); @@ -2700,9 +2701,9 @@ static void _svgLoaderParserXmlStyle(SvgLoaderData* loader, const char* content, while (auto next = simpleXmlParseCSSAttribute(buf, buflen, &tag, &name, &attrs, &attrsLength)) { if ((method = _findGroupFactory(tag))) { //TODO - node->id ??? add additional var for svgnode? - if ((node = method(loader, loader->cssStyle, attrs, attrsLength))) node->id = _copyId(name); + if ((node = method(loader, loader->cssStyle, attrs, attrsLength, simpleXmlParseW3CAttribute))) node->id = _copyId(name); } else if ((method = _findGraphicsFactory(tag))) { - if ((node = method(loader, loader->cssStyle, attrs, attrsLength))) node->id = _copyId(name); + if ((node = method(loader, loader->cssStyle, attrs, attrsLength, simpleXmlParseW3CAttribute))) node->id = _copyId(name); //TODO - implement } else if ((gradientMethod = _findGradientFactory(tag))) { //TODO - implement @@ -2994,7 +2995,7 @@ static bool _svgLoaderParserForValidCheckXmlOpen(SvgLoaderData* loader, const ch if ((method = _findGroupFactory(tagName))) { if (!loader->doc) { if (strcmp(tagName, "svg")) return true; //Not a valid svg document - node = method(loader, nullptr, attrs, attrsLength); + node = method(loader, nullptr, attrs, attrsLength, simpleXmlParseAttributes); loader->doc = node; loader->stack.push(node); return false; diff --git a/src/loaders/svg/tvgXmlParser.cpp b/src/loaders/svg/tvgXmlParser.cpp index 8381ade..4b54e06 100644 --- a/src/loaders/svg/tvgXmlParser.cpp +++ b/src/loaders/svg/tvgXmlParser.cpp @@ -450,7 +450,7 @@ bool simpleXmlParse(const char* buf, unsigned bufLength, bool strip, simpleXMLCb } -bool simpleXmlParseW3CAttribute(const char* buf, simpleXMLAttributeCb func, const void* data) +bool simpleXmlParseW3CAttribute(const char* buf, TVG_UNUSED unsigned buflen, simpleXMLAttributeCb func, const void* data) { const char* end; char* key; diff --git a/src/loaders/svg/tvgXmlParser.h b/src/loaders/svg/tvgXmlParser.h index 3f703bf..832fb18 100644 --- a/src/loaders/svg/tvgXmlParser.h +++ b/src/loaders/svg/tvgXmlParser.h @@ -49,7 +49,7 @@ typedef bool (*simpleXMLAttributeCb)(void* data, const char* key, const char* va bool simpleXmlParseAttributes(const char* buf, unsigned buflen, simpleXMLAttributeCb func, const void* data); bool simpleXmlParse(const char* buf, unsigned buflen, bool strip, simpleXMLCb func, const void* data); -bool simpleXmlParseW3CAttribute(const char* buf, simpleXMLAttributeCb func, const void* data); +bool simpleXmlParseW3CAttribute(const char* buf, TVG_UNUSED unsigned buflen, simpleXMLAttributeCb func, const void* data); const char* simpleXmlParseCSSAttribute(const char* buf, unsigned bufLength, char** tag, char** name, const char** attrs, unsigned* attrsLength); const char* simpleXmlFindAttributesTag(const char* buf, unsigned buflen); bool isIgnoreUnsupportedLogElements(const char* tagName); -- 2.7.4 From bf89e88b07936b623901dc9bc41c781ec38fbb90 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Mon, 17 Jan 2022 22:32:19 +0100 Subject: [PATCH 16/16] svg_loader: additional check while style parsing This check is needed so the function can be used to parse not only the inline styles, but also the css internal style sheet. Change-Id: I6e325d81781326deaccdad8170f11f1acf5f43f2 --- src/loaders/svg/tvgXmlParser.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/loaders/svg/tvgXmlParser.cpp b/src/loaders/svg/tvgXmlParser.cpp index 4b54e06..20fd85c 100644 --- a/src/loaders/svg/tvgXmlParser.cpp +++ b/src/loaders/svg/tvgXmlParser.cpp @@ -468,6 +468,13 @@ bool simpleXmlParseW3CAttribute(const char* buf, TVG_UNUSED unsigned buflen, sim do { char* sep = (char*)strchr(buf, ':'); next = (char*)strchr(buf, ';'); + if (sep >= end) + { + next = nullptr; + sep = nullptr; + } + if (next >= end) next = nullptr; + key[0] = '\0'; val[0] = '\0'; -- 2.7.4