From ad5f147c747a2e737d7502b89d484dd87c4c1a40 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 24 Jun 2020 21:00:43 +0900 Subject: [PATCH 01/16] sw_engine: fix a regression bug. this matrix data is volatile since it's coming from stack memory. thus engine should record its own memory space for keeping it. Change-Id: I664dd56412f4d236ad04c312220c67da226274e5 --- src/lib/sw_engine/tvgSwRenderer.cpp | 13 ++++++++++--- src/lib/sw_engine/tvgSwShape.cpp | 2 -- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 2458cdb..ac5464e 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -32,7 +32,7 @@ namespace tvg { SwShape shape; const Shape* sdata; SwSize clip; - const Matrix* transform; + Matrix* transform; RenderUpdateFlag flags; future progress; }; @@ -139,6 +139,7 @@ bool SwRenderer::dispose(const Shape& sdata, void *data) if (!task) return true; if (task->progress.valid()) task->progress.get(); shapeFree(task->shape); + if (task->transform) free(task->transform); free(task); return true; } @@ -158,8 +159,14 @@ void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* task->sdata = &sdata; task->clip = {static_cast(surface.w), static_cast(surface.h)}; - if (transform) task->transform = &transform->m; - else task->transform = nullptr; + if (transform) { + if (!task->transform) task->transform = static_cast(malloc(sizeof(Matrix))); + assert(task->transform); + *task->transform = transform->m; + } else { + if (task->transform) free(task->transform); + task->transform = nullptr; + } task->flags = flags; diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 9a79c6e..29ecf27 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -201,7 +201,6 @@ static bool _updateBBox(SwOutline* outline, SwBBox& bbox) ++pt; for(uint32_t i = 1; i < outline->ptsCnt; ++i, ++pt) { - assert(pt); if (xMin > pt->x) xMin = pt->x; if (xMax < pt->x) xMax = pt->x; if (yMin > pt->y) yMin = pt->y; @@ -567,7 +566,6 @@ void shapeFree(SwShape& shape) { shapeDelOutline(shape); rleFree(shape.rle); - shapeDelFill(shape); if (shape.stroke) { -- 2.7.4 From 56e866dd36a7ac374966bb34e5854f598d741746 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 25 Jun 2020 13:52:50 +0900 Subject: [PATCH 02/16] renamed project name tizenvg => thorvg we're going to open this project as the independent one, thus removed tizen naming here. Change-Id: Ib3c898067dd9186e893f7cb0903fd70d2ce7b31f --- README | 2 +- inc/meson.build | 2 +- inc/{tizenvg.h => thorvg.h} | 26 ++++++++++++------------ meson.build | 8 ++++---- pc/thorvg.pc.in | 10 ++++++++++ pc/tizenvg.pc.in | 10 ---------- src/examples/main.cpp | 2 +- src/examples/meson.build | 2 +- src/lib/tvgCommon.h | 2 +- src/meson.build | 20 +++++++++---------- test/makefile | 40 ++++++++++++++++++------------------- test/testAsync.cpp | 8 ++++---- test/testBlending.cpp | 8 ++++---- test/testBoundary.cpp | 8 ++++---- test/testComposition.cpp | 6 +++--- test/testCustomTransform.cpp | 8 ++++---- test/testDirectUpdate.cpp | 8 ++++---- test/testGlShape.cpp | 8 ++++---- test/testGradient.cpp | 6 +++--- test/testGradientTransform.cpp | 8 ++++---- test/testLinearGradient.cpp | 8 ++++---- test/testMultiShapes.cpp | 8 ++++---- test/testPath.cpp | 8 ++++---- test/testPathCopy.cpp | 8 ++++---- test/testRadialGradient.cpp | 8 ++++---- test/testScene.cpp | 8 ++++---- test/testSceneTransform.cpp | 8 ++++---- test/testShape.cpp | 8 ++++---- test/testStroke.cpp | 8 ++++---- test/testStrokeLine.cpp | 8 ++++---- test/testSvg.cpp | 8 ++++---- test/testTransform.cpp | 8 ++++---- test/testUpdate.cpp | 8 ++++---- tizenvg.manifest => thorvg.manifest | 0 34 files changed, 148 insertions(+), 148 deletions(-) rename inc/{tizenvg.h => thorvg.h} (96%) create mode 100644 pc/thorvg.pc.in delete mode 100644 pc/tizenvg.pc.in rename tizenvg.manifest => thorvg.manifest (100%) diff --git a/README b/README index 72cf83d..31d0cbd 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -Tizen Vector Graphics 0.1.0 +Thor Vector Graphics 0.1.0 ****************************************************************************** diff --git a/inc/meson.build b/inc/meson.build index 4046844..c598ee5 100644 --- a/inc/meson.build +++ b/inc/meson.build @@ -1,3 +1,3 @@ install_headers([ - 'tizenvg.h', + 'thorvg.h', ]) diff --git a/inc/tizenvg.h b/inc/thorvg.h similarity index 96% rename from inc/tizenvg.h rename to inc/thorvg.h index a9e797f..54c7e11 100644 --- a/inc/tizenvg.h +++ b/inc/thorvg.h @@ -14,8 +14,8 @@ * limitations under the License. * */ -#ifndef _TIZENVG_H_ -#define _TIZENVG_H_ +#ifndef _THORVG_H_ +#define _THORVG_H_ #include @@ -89,7 +89,7 @@ struct Matrix /** * @class Paint * - * @ingroup TizenVG + * @ingroup ThorVG * * @brief description... * @@ -106,7 +106,7 @@ public: /** * @class Fill * - * @ingroup TizenVG + * @ingroup ThorVG * * @brief description... * @@ -136,7 +136,7 @@ public: /** * @class Canvas * - * @ingroup TizenVG + * @ingroup ThorVG * * @brief description... * @@ -164,7 +164,7 @@ public: /** * @class LinearGradient * - * @ingroup TizenVG + * @ingroup ThorVG * * @brief description... * @@ -186,7 +186,7 @@ public: /** * @class RadialGradient * - * @ingroup TizenVG + * @ingroup ThorVG * * @brief description... * @@ -209,7 +209,7 @@ public: /** * @class Shape * - * @ingroup TizenVG + * @ingroup ThorVG * * @brief description... * @@ -273,7 +273,7 @@ public: /** * @class Scene * - * @ingroup TizenVG + * @ingroup ThorVG * * @brief description... * @@ -304,7 +304,7 @@ public: /** * @class SwCanvas * - * @ingroup TizenVG + * @ingroup ThorVG * @brief description... * @@ -325,7 +325,7 @@ public: /** * @class GlCanvas * - * @ingroup TizenVG + * @ingroup ThorVG * * @brief description... * @@ -347,7 +347,7 @@ public: /** * @class Engine * - * @ingroup TizenVG + * @ingroup ThorVG * * @brief description... * @@ -379,4 +379,4 @@ public: } #endif -#endif //_TIZENVG_H_ +#endif //_THORVG_H_ diff --git a/meson.build b/meson.build index 6693650..b1cf7ac 100644 --- a/meson.build +++ b/meson.build @@ -1,4 +1,4 @@ -project('tizenvg', +project('thorvg', 'cpp', default_options : ['buildtype=debugoptimized', 'werror=false', 'cpp_std=c++14', 'optimization=s'], version : '0.1.0', @@ -19,9 +19,9 @@ subdir('src') summary = ''' Summary: - tizenvg version : @0@ - Build type : @1@ - Prefix : @2@ + thorvg version : @0@ + Build type : @1@ + Prefix : @2@ '''.format( meson.project_version(), get_option('buildtype'), diff --git a/pc/thorvg.pc.in b/pc/thorvg.pc.in new file mode 100644 index 0000000..53235fe --- /dev/null +++ b/pc/thorvg.pc.in @@ -0,0 +1,10 @@ +prefix=@PREFIX@ +libdir=@LIBDIR@ +includedir=@INCDIR@ + +Name: Thor Vector Graphics +Description: Thor Vector Graphics Library +Version: @VERSION@ +Requires: +Libs: -L${libdir} -lthorvg +Cflags: -I${includedir}/thorvg diff --git a/pc/tizenvg.pc.in b/pc/tizenvg.pc.in deleted file mode 100644 index 631bc2a..0000000 --- a/pc/tizenvg.pc.in +++ /dev/null @@ -1,10 +0,0 @@ -prefix=@PREFIX@ -libdir=@LIBDIR@ -includedir=@INCDIR@ - -Name: Tizen Vector Graphics -Description: Tizen Vector Graphics Library -Version: @VERSION@ -Requires: -Libs: -L${libdir} -ltizenvg -Cflags: -I${includedir}/tizenvg diff --git a/src/examples/main.cpp b/src/examples/main.cpp index 4b9154b..fee1aa8 100644 --- a/src/examples/main.cpp +++ b/src/examples/main.cpp @@ -21,7 +21,7 @@ using namespace std; int main(int argc, char *argv[]) { - cout << "test tizenvg!" << endl; + cout << "test thorvg!" << endl; return 0; } diff --git a/src/examples/meson.build b/src/examples/meson.build index 8954536..4ba6e9b 100644 --- a/src/examples/meson.build +++ b/src/examples/meson.build @@ -1 +1 @@ -executable('tizenvg_sample', 'main.cpp') +executable('thorvg_sample', 'main.cpp') diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index 302f4e9..79f7c18 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -23,7 +23,7 @@ #include #include #include -#include "tizenvg.h" +#include "thorvg.h" using namespace std; using namespace tvg; diff --git a/src/meson.build b/src/meson.build index b5000bc..493497b 100644 --- a/src/meson.build +++ b/src/meson.build @@ -9,30 +9,30 @@ thread_dep = meson.get_compiler('cpp').find_library('pthread') egl_dep = meson.get_compiler('cpp').find_library('EGL') gles_dep = meson.get_compiler('cpp').find_library('GLESv2') -tizenvg_lib_dep = [ src_dep, swengine_dep, glengine_dep, m_dep, egl_dep, gles_dep, svgloader_dep, thread_dep] +thorvg_lib_dep = [ src_dep, swengine_dep, glengine_dep, m_dep, egl_dep, gles_dep, svgloader_dep, thread_dep] -tizenvg_lib = library( - 'tizenvg', +thorvg_lib = library( + 'thorvg', include_directories : headers, version : meson.project_version(), - dependencies : tizenvg_lib_dep, + dependencies : thorvg_lib_dep, install : true, cpp_args : compiler_flags, gnu_symbol_visibility : 'hidden', ) -tizenvg_dep = declare_dependency( +thorvg_dep = declare_dependency( include_directories: headers, - link_with : tizenvg_lib + link_with : thorvg_lib ) pkg_mod = import('pkgconfig') pkg_mod.generate( - libraries : tizenvg_lib, + libraries : thorvg_lib, version : meson.project_version(), - name : 'libtizenvg', - filebase : 'tizenvg', - description : 'A Tizen library for rendering vector graphics' + name : 'libthorvg', + filebase : 'thorvg', + description : 'A Thor library for rendering vector graphics' ) diff --git a/test/makefile b/test/makefile index 870c3bb..33eb7d9 100644 --- a/test/makefile +++ b/test/makefile @@ -1,21 +1,21 @@ all: - gcc -o testShape testShape.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` - gcc -o testMultiShapes testMultiShapes.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` - gcc -o testBoundary testBoundary.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` - gcc -o testPath testPath.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` - gcc -o testPathCopy testPathCopy.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` - gcc -o testBlending testBlending.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` - gcc -o testUpdate testUpdate.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` - gcc -o testDirectUpdate testDirectUpdate.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` - gcc -o testScene testScene.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` - gcc -o testTransform testTransform.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` - gcc -o testCustomTransform testCustomTransform.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` - gcc -o testSceneTransform testSceneTransform.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` - gcc -o testStroke testStroke.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` - gcc -o testStrokeLine testStrokeLine.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` - gcc -o testLinearGradient testLinearGradient.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` - gcc -o testRadialGradient testRadialGradient.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` - gcc -o testGradientTransform testGradientTransform.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` - gcc -o testSvg testSvg.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` - gcc -o testGlShape testGlShape.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` - gcc -o testAsync testAsync.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` + gcc -o testShape testShape.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg` + gcc -o testMultiShapes testMultiShapes.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg` + gcc -o testBoundary testBoundary.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg` + gcc -o testPath testPath.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg` + gcc -o testPathCopy testPathCopy.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg` + gcc -o testBlending testBlending.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg` + gcc -o testUpdate testUpdate.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg` + gcc -o testDirectUpdate testDirectUpdate.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg` + gcc -o testScene testScene.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg` + gcc -o testTransform testTransform.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg` + gcc -o testCustomTransform testCustomTransform.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg` + gcc -o testSceneTransform testSceneTransform.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg` + gcc -o testStroke testStroke.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg` + gcc -o testStrokeLine testStrokeLine.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg` + gcc -o testLinearGradient testLinearGradient.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg` + gcc -o testRadialGradient testRadialGradient.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg` + gcc -o testGradientTransform testGradientTransform.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg` + gcc -o testSvg testSvg.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg` + gcc -o testGlShape testGlShape.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg` + gcc -o testAsync testAsync.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg` diff --git a/test/testAsync.cpp b/test/testAsync.cpp index 4d042dc..7172dd9 100644 --- a/test/testAsync.cpp +++ b/test/testAsync.cpp @@ -1,4 +1,4 @@ -#include +#include #include using namespace std; @@ -89,7 +89,7 @@ void win_del(void *data, Evas_Object *o, void *ev) int main(int argc, char **argv) { - //Initialize TizenVG Engine + //Initialize ThorVG Engine tvg::Initializer::init(tvg::CanvasEngine::Sw); tvgtest(); @@ -97,7 +97,7 @@ int main(int argc, char **argv) //Show the result using EFL... elm_init(argc, argv); - Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); evas_object_smart_callback_add(win, "delete,request", win_del, 0); Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); @@ -116,6 +116,6 @@ int main(int argc, char **argv) elm_run(); elm_shutdown(); - //Terminate TizenVG Engine + //Terminate ThorVG Engine tvg::Initializer::term(tvg::CanvasEngine::Sw); } diff --git a/test/testBlending.cpp b/test/testBlending.cpp index ebb3e67..82aa32d 100644 --- a/test/testBlending.cpp +++ b/test/testBlending.cpp @@ -1,4 +1,4 @@ -#include +#include #include using namespace std; @@ -10,7 +10,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; void tvgtest() { - //Initialize TizenVG Engine + //Initialize ThorVG Engine tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas @@ -62,7 +62,7 @@ void tvgtest() canvas->draw(); canvas->sync(); - //Terminate TizenVG Engine + //Terminate ThorVG Engine tvg::Initializer::term(tvg::CanvasEngine::Sw); } @@ -78,7 +78,7 @@ int main(int argc, char **argv) //Show the result using EFL... elm_init(argc, argv); - Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); evas_object_smart_callback_add(win, "delete,request", win_del, 0); Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); diff --git a/test/testBoundary.cpp b/test/testBoundary.cpp index a71374a..d7cb8fa 100644 --- a/test/testBoundary.cpp +++ b/test/testBoundary.cpp @@ -1,4 +1,4 @@ -#include +#include #include using namespace std; @@ -10,7 +10,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; void tvgtest() { - //Initialize TizenVG Engine + //Initialize ThorVG Engine tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas @@ -52,7 +52,7 @@ void tvgtest() canvas->draw(); canvas->sync(); - //Terminate TizenVG Engine + //Terminate ThorVG Engine tvg::Initializer::term(tvg::CanvasEngine::Sw); } @@ -68,7 +68,7 @@ int main(int argc, char **argv) //Show the result using EFL... elm_init(argc, argv); - Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); evas_object_smart_callback_add(win, "delete,request", win_del, 0); Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); diff --git a/test/testComposition.cpp b/test/testComposition.cpp index d8ca979..6230dc0 100644 --- a/test/testComposition.cpp +++ b/test/testComposition.cpp @@ -1,4 +1,4 @@ -#include +#include using namespace std; @@ -9,7 +9,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; int main(int argc, char **argv) { - //Initialize TizenVG Engine + //Initialize ThorVG Engine tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Composition Source Canvas @@ -30,6 +30,6 @@ int main(int argc, char **argv) canvas2->draw(); canvas2->sync(); - //Terminate TizenVG Engine + //Terminate ThorVG Engine tvg::Initializer::term(tvg::CanvasEngine::Sw); } diff --git a/test/testCustomTransform.cpp b/test/testCustomTransform.cpp index cc0c8bb..c57d4d4 100644 --- a/test/testCustomTransform.cpp +++ b/test/testCustomTransform.cpp @@ -1,4 +1,4 @@ -#include +#include #include using namespace std; @@ -103,7 +103,7 @@ void win_del(void *data, Evas_Object *o, void *ev) int main(int argc, char **argv) { - //Initialize TizenVG Engine + //Initialize ThorVG Engine tvg::Initializer::init(tvg::CanvasEngine::Sw); tvgtest(); @@ -111,7 +111,7 @@ int main(int argc, char **argv) //Show the result using EFL... elm_init(argc, argv); - Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); evas_object_smart_callback_add(win, "delete,request", win_del, 0); Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); @@ -134,6 +134,6 @@ int main(int argc, char **argv) elm_run(); elm_shutdown(); - //Terminate TizenVG Engine + //Terminate ThorVG Engine tvg::Initializer::term(tvg::CanvasEngine::Sw); } diff --git a/test/testDirectUpdate.cpp b/test/testDirectUpdate.cpp index eb3a9dc..4dbc26b 100644 --- a/test/testDirectUpdate.cpp +++ b/test/testDirectUpdate.cpp @@ -1,4 +1,4 @@ -#include +#include #include using namespace std; @@ -68,7 +68,7 @@ win_del(void *data, Evas_Object *o, void *ev) int main(int argc, char **argv) { - //Initialize TizenVG Engine + //Initialize ThorVG Engine tvg::Initializer::init(tvg::CanvasEngine::Sw); tvgtest(); @@ -76,7 +76,7 @@ int main(int argc, char **argv) //Show the result using EFL... elm_init(argc, argv); - Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); evas_object_smart_callback_add(win, "delete,request", win_del, 0); Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); @@ -99,6 +99,6 @@ int main(int argc, char **argv) elm_run(); elm_shutdown(); - //Terminate TizenVG Engine + //Terminate ThorVG Engine tvg::Initializer::term(tvg::CanvasEngine::Sw); } diff --git a/test/testGlShape.cpp b/test/testGlShape.cpp index 8ad43ae..c488091 100644 --- a/test/testGlShape.cpp +++ b/test/testGlShape.cpp @@ -1,4 +1,4 @@ -#include +#include #include using namespace std; @@ -34,7 +34,7 @@ void tvgtest() void init_gl(Evas_Object *obj) { - //Initialize TizenVG Engine + //Initialize ThorVG Engine tvg::Initializer::init(tvg::CanvasEngine::Gl); tvgtest(); @@ -42,7 +42,7 @@ void init_gl(Evas_Object *obj) void del_gl(Evas_Object *obj) { - //Terminate TizenVG Engine + //Terminate ThorVG Engine tvg::Initializer::term(tvg::CanvasEngine::Gl); } @@ -74,7 +74,7 @@ int main(int argc, char **argv) elm_config_accel_preference_set("gl"); - Eo* win = elm_win_util_standard_add(nullptr, "TizenVG Test"); + Eo* win = elm_win_util_standard_add(nullptr, "ThorVG Test"); evas_object_smart_callback_add(win, "delete,request", win_del, 0); //Create a new glview object diff --git a/test/testGradient.cpp b/test/testGradient.cpp index cf33a1e..d20cce9 100644 --- a/test/testGradient.cpp +++ b/test/testGradient.cpp @@ -1,4 +1,4 @@ -#include +#include using namespace std; @@ -9,7 +9,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; int main(int argc, char **argv) { - //Initialize TizenVG Engine + //Initialize ThorVG Engine tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas @@ -47,6 +47,6 @@ int main(int argc, char **argv) canvas->draw(); canvas->sync(); - //Terminate TizenVG Engine + //Terminate ThorVG Engine tvg::Initializer::term(tvg::CanvasEngine::Sw); } diff --git a/test/testGradientTransform.cpp b/test/testGradientTransform.cpp index 428acc5..1b5137b 100644 --- a/test/testGradientTransform.cpp +++ b/test/testGradientTransform.cpp @@ -1,4 +1,4 @@ -#include +#include #include using namespace std; @@ -133,7 +133,7 @@ void win_del(void *data, Evas_Object *o, void *ev) int main(int argc, char **argv) { - //Initialize TizenVG Engine + //Initialize ThorVG Engine tvg::Initializer::init(tvg::CanvasEngine::Sw); tvgtest(); @@ -141,7 +141,7 @@ int main(int argc, char **argv) //Show the result using EFL... elm_init(argc, argv); - Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); evas_object_smart_callback_add(win, "delete,request", win_del, 0); Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); @@ -164,6 +164,6 @@ int main(int argc, char **argv) elm_run(); elm_shutdown(); - //Terminate TizenVG Engine + //Terminate ThorVG Engine tvg::Initializer::term(tvg::CanvasEngine::Sw); } diff --git a/test/testLinearGradient.cpp b/test/testLinearGradient.cpp index 8016a45..ed0d31d 100644 --- a/test/testLinearGradient.cpp +++ b/test/testLinearGradient.cpp @@ -1,4 +1,4 @@ -#include +#include #include using namespace std; @@ -10,7 +10,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; void tvgtest() { - //Initialize TizenVG Engine + //Initialize ThorVG Engine tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas @@ -80,7 +80,7 @@ void tvgtest() canvas->draw(); canvas->sync(); - //Terminate TizenVG Engine + //Terminate ThorVG Engine tvg::Initializer::term(tvg::CanvasEngine::Sw); } @@ -96,7 +96,7 @@ int main(int argc, char **argv) //Show the result using EFL... elm_init(argc, argv); - Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); evas_object_smart_callback_add(win, "delete,request", win_del, 0); Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); diff --git a/test/testMultiShapes.cpp b/test/testMultiShapes.cpp index 9fff6f0..02101ed 100644 --- a/test/testMultiShapes.cpp +++ b/test/testMultiShapes.cpp @@ -1,4 +1,4 @@ -#include +#include #include using namespace std; @@ -10,7 +10,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; void tvgtest() { - //Initialize TizenVG Engine + //Initialize ThorVG Engine tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas @@ -40,7 +40,7 @@ void tvgtest() canvas->draw(); canvas->sync(); - //Terminate TizenVG Engine + //Terminate ThorVG Engine tvg::Initializer::term(tvg::CanvasEngine::Sw); } @@ -56,7 +56,7 @@ int main(int argc, char **argv) //Show the result using EFL... elm_init(argc, argv); - Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); evas_object_smart_callback_add(win, "delete,request", win_del, 0); Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); diff --git a/test/testPath.cpp b/test/testPath.cpp index efb784f..a5bdc9e 100644 --- a/test/testPath.cpp +++ b/test/testPath.cpp @@ -1,4 +1,4 @@ -#include +#include #include using namespace std; @@ -10,7 +10,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; void tvgtest() { - //Initialize TizenVG Engine + //Initialize ThorVG Engine tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas @@ -55,7 +55,7 @@ void tvgtest() canvas->draw(); canvas->sync(); - //Terminate TizenVG Engine + //Terminate ThorVG Engine tvg::Initializer::term(tvg::CanvasEngine::Sw); } @@ -71,7 +71,7 @@ int main(int argc, char **argv) //Show the result using EFL... elm_init(argc, argv); - Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); evas_object_smart_callback_add(win, "delete,request", win_del, 0); Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); diff --git a/test/testPathCopy.cpp b/test/testPathCopy.cpp index 4ba5941..fc3395e 100644 --- a/test/testPathCopy.cpp +++ b/test/testPathCopy.cpp @@ -1,4 +1,4 @@ -#include +#include #include using namespace std; @@ -10,7 +10,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; void tvgtest() { - //Initialize TizenVG Engine + //Initialize ThorVG Engine tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas @@ -95,7 +95,7 @@ void tvgtest() canvas->draw(); canvas->sync(); - //Terminate TizenVG Engine + //Terminate ThorVG Engine tvg::Initializer::term(tvg::CanvasEngine::Sw); } @@ -111,7 +111,7 @@ int main(int argc, char **argv) //Show the result using EFL... elm_init(argc, argv); - Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); evas_object_smart_callback_add(win, "delete,request", win_del, 0); Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); diff --git a/test/testRadialGradient.cpp b/test/testRadialGradient.cpp index e10be47..841c6e1 100644 --- a/test/testRadialGradient.cpp +++ b/test/testRadialGradient.cpp @@ -1,4 +1,4 @@ -#include +#include #include using namespace std; @@ -10,7 +10,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; void tvgtest() { - //Initialize TizenVG Engine + //Initialize ThorVG Engine tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas @@ -80,7 +80,7 @@ void tvgtest() canvas->draw(); canvas->sync(); - //Terminate TizenVG Engine + //Terminate ThorVG Engine tvg::Initializer::term(tvg::CanvasEngine::Sw); } @@ -96,7 +96,7 @@ int main(int argc, char **argv) //Show the result using EFL... elm_init(argc, argv); - Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); evas_object_smart_callback_add(win, "delete,request", win_del, 0); Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); diff --git a/test/testScene.cpp b/test/testScene.cpp index db6fd53..c5672c7 100644 --- a/test/testScene.cpp +++ b/test/testScene.cpp @@ -1,4 +1,4 @@ -#include +#include #include using namespace std; @@ -10,7 +10,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; void tvgtest() { - //Initialize TizenVG Engine + //Initialize ThorVG Engine tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas @@ -86,7 +86,7 @@ void tvgtest() canvas->draw(); canvas->sync(); - //Terminate TizenVG Engine + //Terminate ThorVG Engine tvg::Initializer::term(tvg::CanvasEngine::Sw); } @@ -103,7 +103,7 @@ int main(int argc, char **argv) //Show the result using EFL... elm_init(argc, argv); - Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); evas_object_smart_callback_add(win, "delete,request", win_del, 0); Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); diff --git a/test/testSceneTransform.cpp b/test/testSceneTransform.cpp index 1e411fe..07879c1 100644 --- a/test/testSceneTransform.cpp +++ b/test/testSceneTransform.cpp @@ -1,4 +1,4 @@ -#include +#include #include using namespace std; @@ -127,7 +127,7 @@ void win_del(void *data, Evas_Object *o, void *ev) int main(int argc, char **argv) { - //Initialize TizenVG Engine + //Initialize ThorVG Engine tvg::Initializer::init(tvg::CanvasEngine::Sw); tvgtest(); @@ -135,7 +135,7 @@ int main(int argc, char **argv) //Show the result using EFL... elm_init(argc, argv); - Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); evas_object_smart_callback_add(win, "delete,request", win_del, 0); Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); @@ -157,6 +157,6 @@ int main(int argc, char **argv) elm_run(); elm_shutdown(); - //Terminate TizenVG Engine + //Terminate ThorVG Engine tvg::Initializer::term(tvg::CanvasEngine::Sw); } diff --git a/test/testShape.cpp b/test/testShape.cpp index 4cc1f7f..a79c770 100644 --- a/test/testShape.cpp +++ b/test/testShape.cpp @@ -1,4 +1,4 @@ -#include +#include #include using namespace std; @@ -10,7 +10,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; void tvgtest() { - //Initialize TizenVG Engine + //Initialize ThorVG Engine tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas @@ -34,7 +34,7 @@ void tvgtest() canvas->draw(); canvas->sync(); - //Terminate TizenVG Engine + //Terminate ThorVG Engine tvg::Initializer::term(tvg::CanvasEngine::Sw); } @@ -51,7 +51,7 @@ int main(int argc, char **argv) //Show the result using EFL... elm_init(argc, argv); - Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); evas_object_smart_callback_add(win, "delete,request", win_del, 0); Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); diff --git a/test/testStroke.cpp b/test/testStroke.cpp index 68bffa2..bc50dca 100644 --- a/test/testStroke.cpp +++ b/test/testStroke.cpp @@ -1,4 +1,4 @@ -#include +#include #include using namespace std; @@ -11,7 +11,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; void tvgtest() { - //Initialize TizenVG Engine + //Initialize ThorVG Engine tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas @@ -79,7 +79,7 @@ void tvgtest() canvas->draw(); canvas->sync(); - //Terminate TizenVG Engine + //Terminate ThorVG Engine tvg::Initializer::term(tvg::CanvasEngine::Sw); } @@ -95,7 +95,7 @@ int main(int argc, char **argv) //Show the result using EFL... elm_init(argc, argv); - Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); evas_object_smart_callback_add(win, "delete,request", win_del, 0); Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); diff --git a/test/testStrokeLine.cpp b/test/testStrokeLine.cpp index 3b6cc9d..559479d 100644 --- a/test/testStrokeLine.cpp +++ b/test/testStrokeLine.cpp @@ -1,4 +1,4 @@ -#include +#include #include using namespace std; @@ -10,7 +10,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; void tvgtest() { - //Initialize TizenVG Engine + //Initialize ThorVG Engine tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas @@ -115,7 +115,7 @@ void tvgtest() canvas->draw(); canvas->sync(); - //Terminate TizenVG Engine + //Terminate ThorVG Engine tvg::Initializer::term(tvg::CanvasEngine::Sw); } @@ -131,7 +131,7 @@ int main(int argc, char **argv) //Show the result using EFL... elm_init(argc, argv); - Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); evas_object_smart_callback_add(win, "delete,request", win_del, 0); Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); diff --git a/test/testSvg.cpp b/test/testSvg.cpp index cad2f1b..b7671b8 100644 --- a/test/testSvg.cpp +++ b/test/testSvg.cpp @@ -1,4 +1,4 @@ -#include +#include #include using namespace std; @@ -10,7 +10,7 @@ static uint32_t buffer[WIDTH * HEIGHT]; void tvgtest() { - //Initialize TizenVG Engine + //Initialize ThorVG Engine tvg::Initializer::init(tvg::CanvasEngine::Sw); //Create a Canvas @@ -25,7 +25,7 @@ void tvgtest() canvas->draw(); canvas->sync(); - //Terminate TizenVG Engine + //Terminate ThorVG Engine tvg::Initializer::term(tvg::CanvasEngine::Sw); } @@ -42,7 +42,7 @@ int main(int argc, char **argv) //Show the result using EFL... elm_init(argc, argv); - Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); evas_object_smart_callback_add(win, "delete,request", win_del, 0); Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); diff --git a/test/testTransform.cpp b/test/testTransform.cpp index 5222743..dd3423a 100644 --- a/test/testTransform.cpp +++ b/test/testTransform.cpp @@ -1,4 +1,4 @@ -#include +#include #include using namespace std; @@ -96,7 +96,7 @@ void win_del(void *data, Evas_Object *o, void *ev) int main(int argc, char **argv) { - //Initialize TizenVG Engine + //Initialize ThorVG Engine tvg::Initializer::init(tvg::CanvasEngine::Sw); tvgtest(); @@ -104,7 +104,7 @@ int main(int argc, char **argv) //Show the result using EFL... elm_init(argc, argv); - Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); evas_object_smart_callback_add(win, "delete,request", win_del, 0); Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); @@ -127,6 +127,6 @@ int main(int argc, char **argv) elm_run(); elm_shutdown(); - //Terminate TizenVG Engine + //Terminate ThorVG Engine tvg::Initializer::term(tvg::CanvasEngine::Sw); } diff --git a/test/testUpdate.cpp b/test/testUpdate.cpp index 7111b21..3a39913 100644 --- a/test/testUpdate.cpp +++ b/test/testUpdate.cpp @@ -1,4 +1,4 @@ -#include +#include #include using namespace std; @@ -57,7 +57,7 @@ void win_del(void *data, Evas_Object *o, void *ev) int main(int argc, char **argv) { - //Initialize TizenVG Engine + //Initialize ThorVG Engine tvg::Initializer::init(tvg::CanvasEngine::Sw); tvgtest(); @@ -65,7 +65,7 @@ int main(int argc, char **argv) //Show the result using EFL... elm_init(argc, argv); - Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); evas_object_smart_callback_add(win, "delete,request", win_del, 0); Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); @@ -88,6 +88,6 @@ int main(int argc, char **argv) elm_run(); elm_shutdown(); - //Terminate TizenVG Engine + //Terminate ThorVG Engine tvg::Initializer::term(tvg::CanvasEngine::Sw); } diff --git a/tizenvg.manifest b/thorvg.manifest similarity index 100% rename from tizenvg.manifest rename to thorvg.manifest -- 2.7.4 From 4d6dee91e4c2347b4f9e97df29e3585a2a5634b3 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 29 Jun 2020 14:59:01 +0900 Subject: [PATCH 03/16] test shape: unify sw/gl test code. default is sw engine, please run sample app with "gl" argument $./testShape gl Change-Id: Iff7da624ff17827df957919341737b9f129f502e --- .gitignore | 1 - test/makefile | 1 - test/testGlShape.cpp | 107 -------------------------------------------- test/testShape.cpp | 122 +++++++++++++++++++++++++++++++++++++++++---------- 4 files changed, 100 insertions(+), 131 deletions(-) delete mode 100644 test/testGlShape.cpp diff --git a/.gitignore b/.gitignore index f6c52c5..9a64520 100644 --- a/.gitignore +++ b/.gitignore @@ -19,5 +19,4 @@ testLinearGradient testRadialGradient testGradientTransform testSvg -testGlShape testAsync diff --git a/test/makefile b/test/makefile index 33eb7d9..6455a0a 100644 --- a/test/makefile +++ b/test/makefile @@ -17,5 +17,4 @@ all: gcc -o testRadialGradient testRadialGradient.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg` gcc -o testGradientTransform testGradientTransform.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg` gcc -o testSvg testSvg.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg` - gcc -o testGlShape testGlShape.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg` gcc -o testAsync testAsync.cpp -g -lstdc++ `pkg-config --cflags --libs elementary thorvg` diff --git a/test/testGlShape.cpp b/test/testGlShape.cpp deleted file mode 100644 index c488091..0000000 --- a/test/testGlShape.cpp +++ /dev/null @@ -1,107 +0,0 @@ -#include -#include - -using namespace std; - -#define WIDTH 800 -#define HEIGHT 800 -#define BPP 4 -static Evas_GL_API *glapi; -static unique_ptr canvas; - -void tvgtest() -{ - //Create a Canvas - canvas = tvg::GlCanvas::gen(); - canvas->target(nullptr, WIDTH * BPP, WIDTH, HEIGHT); - - //Prepare a Shape (Rectangle + Rectangle + Circle + Circle) - auto shape1 = tvg::Shape::gen(); - shape1->appendRect(0, 0, 200, 200, 0); //x, y, w, h, cornerRadius - shape1->appendRect(100, 100, 300, 300, 100); //x, y, w, h, cornerRadius - shape1->appendCircle(400, 400, 100, 100); //cx, cy, radiusW, radiusH - shape1->appendCircle(400, 500, 170, 100); //cx, cy, radiusW, radiusH - shape1->fill(255, 255, 0, 255); //r, g, b, a - shape1->stroke(255, 0, 0, 255); //r, g, b, a - shape1->stroke(10.0f); - - /* 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() */ - canvas->push(move(shape1)); -} - -void init_gl(Evas_Object *obj) -{ - //Initialize ThorVG Engine - tvg::Initializer::init(tvg::CanvasEngine::Gl); - - tvgtest(); -} - -void del_gl(Evas_Object *obj) -{ - //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Gl); -} - -void draw_gl(Evas_Object *obj) -{ - Evas_GL_API *gl = elm_glview_gl_api_get(obj); - int w, h; - elm_glview_size_get(obj, &w, &h); - gl->glViewport(0, 0, w, h); - gl->glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - gl->glClear(GL_COLOR_BUFFER_BIT); - gl->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); - gl->glEnable(GL_BLEND); - - canvas->draw(); - canvas->sync(); -} - -void win_del(void *data, Evas_Object *o, void *ev) -{ - elm_exit(); -} - -int main(int argc, char **argv) -{ - //Show the result using EFL... - elm_init(argc, argv); - - elm_config_accel_preference_set("gl"); - - Eo* win = elm_win_util_standard_add(nullptr, "ThorVG Test"); - evas_object_smart_callback_add(win, "delete,request", win_del, 0); - - //Create a new glview object - Eo* gl = elm_glview_add(win); - glapi = elm_glview_gl_api_get(gl); - evas_object_size_hint_align_set(gl, EVAS_HINT_FILL, EVAS_HINT_FILL); - evas_object_size_hint_weight_set(gl, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - - elm_glview_mode_set(gl, ELM_GLVIEW_ALPHA); - elm_glview_resize_policy_set(gl, ELM_GLVIEW_RESIZE_POLICY_RECREATE); - elm_glview_render_policy_set(gl, ELM_GLVIEW_RENDER_POLICY_ON_DEMAND); - - evas_object_resize(gl, WIDTH, HEIGHT); - - //Initialize callback function gets registered here - elm_glview_init_func_set(gl, init_gl); - //Delete callback function gets registered here - elm_glview_del_func_set(gl, del_gl); - elm_glview_render_func_set(gl, draw_gl); - - evas_object_show(gl); - - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); - evas_object_show(win); - - elm_run(); - elm_shutdown(); - - return 0; -} diff --git a/test/testShape.cpp b/test/testShape.cpp index a79c770..e32142f 100644 --- a/test/testShape.cpp +++ b/test/testShape.cpp @@ -6,17 +6,8 @@ using namespace std; #define WIDTH 800 #define HEIGHT 800 -static uint32_t buffer[WIDTH * HEIGHT]; - -void tvgtest() +unique_ptr tvgDrawCmds() { - //Initialize ThorVG Engine - tvg::Initializer::init(tvg::CanvasEngine::Sw); - - //Create a Canvas - auto canvas = tvg::SwCanvas::gen(); - canvas->target(buffer, WIDTH, WIDTH, HEIGHT); - //Prepare a Shape (Rectangle + Rectangle + Circle + Circle) auto shape1 = tvg::Shape::gen(); shape1->appendRect(0, 0, 200, 200, 0); //x, y, w, h, cornerRadius @@ -25,12 +16,27 @@ void tvgtest() shape1->appendCircle(400, 500, 170, 100); //cx, cy, radiusW, radiusH shape1->fill(255, 255, 0, 255); //r, g, b, a + return move(shape1); +} + +/************************************************************************/ +/* Sw Engine Test Code */ +/************************************************************************/ + +void tvgSwTest(uint32_t* buffer) +{ + //Initialize ThorVG Engine + tvg::Initializer::init(tvg::CanvasEngine::Sw); + + //Create a Canvas + auto canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, 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() */ - canvas->push(move(shape1)); - + canvas->push(tvgDrawCmds()); canvas->draw(); canvas->sync(); @@ -38,29 +44,101 @@ void tvgtest() tvg::Initializer::term(tvg::CanvasEngine::Sw); } +/************************************************************************/ +/* GL Engine Test Code */ +/************************************************************************/ + +static unique_ptr canvas; + +void initGLview(Evas_Object *obj) +{ + static constexpr auto BPP = 4; + + //Initialize ThorVG Engine + tvg::Initializer::init(tvg::CanvasEngine::Gl); + + //Create a Canvas + canvas = tvg::GlCanvas::gen(); + canvas->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() */ + canvas->push(tvgDrawCmds()); +} + +void delGLview(Evas_Object *obj) +{ + //Terminate ThorVG Engine + tvg::Initializer::term(tvg::CanvasEngine::Gl); +} + +void drawGLview(Evas_Object *obj) +{ + auto gl = elm_glview_gl_api_get(obj); + int w, h; + elm_glview_size_get(obj, &w, &h); + gl->glViewport(0, 0, w, h); + gl->glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + gl->glClear(GL_COLOR_BUFFER_BIT); + gl->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); + gl->glEnable(GL_BLEND); + + canvas->draw(); + canvas->sync(); +} + +/************************************************************************/ +/* Common Infrastructure Code */ +/************************************************************************/ + void win_del(void *data, Evas_Object *o, void *ev) { elm_exit(); } - int main(int argc, char **argv) { - tvgtest(); + bool swEngine = true; + + if (argc > 1) { + if (!strcmp(argv[1], "gl")) swEngine = false; + } - //Show the result using EFL... elm_init(argc, argv); + //Show the result using EFL... + elm_config_accel_preference_set("gl"); + Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); evas_object_smart_callback_add(win, "delete,request", win_del, 0); - Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); - evas_object_image_size_set(img, WIDTH, HEIGHT); - evas_object_image_data_set(img, buffer); - evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_show(img); - - elm_win_resize_object_add(win, img); + Eo* viewer; + + if (swEngine) { + static uint32_t buffer[WIDTH * HEIGHT]; + viewer = evas_object_image_filled_add(evas_object_evas_get(win)); + evas_object_image_size_set(viewer, WIDTH, HEIGHT); + evas_object_image_data_set(viewer, buffer); + evas_object_size_hint_weight_set(viewer, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(viewer); + tvgSwTest(buffer); + //GlEngine + } else { + viewer = elm_glview_add(win); + evas_object_size_hint_weight_set(viewer, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_glview_mode_set(viewer, ELM_GLVIEW_ALPHA); + elm_glview_resize_policy_set(viewer, ELM_GLVIEW_RESIZE_POLICY_RECREATE); + elm_glview_render_policy_set(viewer, ELM_GLVIEW_RENDER_POLICY_ON_DEMAND); + elm_glview_init_func_set(viewer, initGLview); + elm_glview_del_func_set(viewer, delGLview); + elm_glview_render_func_set(viewer, drawGLview); + evas_object_show(viewer); + } + + elm_win_resize_object_add(win, viewer); evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); evas_object_show(win); -- 2.7.4 From 3a8d6821baf6889eccd834d6613d9bf434b36e09 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Wed, 24 Jun 2020 09:55:25 +0900 Subject: [PATCH 04/16] SvgLoader: Implement SVG Loader and SimpleXMLParser Load svg using fstream and parse it using SimpleXMLparser. And Make a document tree composed of SvgNodes using the parsed data. Change-Id: I5715b466638195844798f7b66f54f6015e7c3ae6 --- src/loaders/svg_loader/meson.build | 3 + src/loaders/svg_loader/tvgSimpleXmlParser.cpp | 346 ++++ src/loaders/svg_loader/tvgSimpleXmlParser.h | 31 + src/loaders/svg_loader/tvgSvgLoader.cpp | 2260 ++++++++++++++++++++++++- src/loaders/svg_loader/tvgSvgLoader.h | 7 +- src/loaders/svg_loader/tvgSvgLoaderCommon.h | 337 ++++ 6 files changed, 2966 insertions(+), 18 deletions(-) create mode 100644 src/loaders/svg_loader/tvgSimpleXmlParser.cpp create mode 100644 src/loaders/svg_loader/tvgSimpleXmlParser.h create mode 100644 src/loaders/svg_loader/tvgSvgLoaderCommon.h diff --git a/src/loaders/svg_loader/meson.build b/src/loaders/svg_loader/meson.build index 1bd40c1..88fd37a 100644 --- a/src/loaders/svg_loader/meson.build +++ b/src/loaders/svg_loader/meson.build @@ -1,5 +1,8 @@ source_file = [ + 'tvgSimpleXmlParser.h', 'tvgSvgLoader.h', + 'tvgSvgLoaderCommon.h', + 'tvgSimpleXmlParser.cpp', 'tvgSvgLoader.cpp', ] diff --git a/src/loaders/svg_loader/tvgSimpleXmlParser.cpp b/src/loaders/svg_loader/tvgSimpleXmlParser.cpp new file mode 100644 index 0000000..4081453 --- /dev/null +++ b/src/loaders/svg_loader/tvgSimpleXmlParser.cpp @@ -0,0 +1,346 @@ +#include "tvgSimpleXmlParser.h" + +static const char* _simpleXmlFindWhiteSpace(const char* itr, const char* itrEnd) +{ + for (; itr < itrEnd; itr++) { + if (isspace((unsigned char)*itr)) break; + } + return itr; +} + + +static const char* _simpleXmlSkipWhiteSpace(const char* itr, const char* itrEnd) +{ + for (; itr < itrEnd; itr++) { + if (!isspace((unsigned char)*itr)) break; + } + return itr; +} + + +static const char* _simpleXmlUnskipWhiteSpace(const char* itr, const char* itrStart) +{ + for (itr--; itr > itrStart; itr--) { + if (!isspace((unsigned char)*itr)) break; + } + return itr + 1; +} + + +static const char* _simpleXmlFindStartTag(const char* itr, const char* itrEnd) +{ + return (const char*)memchr(itr, '<', itrEnd - itr); +} + + +static const char* _simpleXmlFindEndTag(const char* itr, const char* itrEnd) +{ + bool insideQuote = false; + for (; itr < itrEnd; itr++) { + if (*itr == '"') insideQuote = !insideQuote; + if (!insideQuote) { + if ((*itr == '>') || (*itr == '<')) + return itr; + } + } + return nullptr; +} + + +static const char* _simpleXmlFindEndCommentTag(const char* itr, const char* itrEnd) +{ + for (; itr < itrEnd; itr++) { + if ((*itr == '-') && ((itr + 1 < itrEnd) && (*(itr + 1) == '-')) && ((itr + 2 < itrEnd) && (*(itr + 2) == '>'))) return itr + 2; + } + return nullptr; +} + + +static const char* _simpleXmlFindEndCdataTag(const char* itr, const char* itrEnd) +{ + for (; itr < itrEnd; itr++) { + if ((*itr == ']') && ((itr + 1 < itrEnd) && (*(itr + 1) == ']')) && ((itr + 2 < itrEnd) && (*(itr + 2) == '>'))) return itr + 2; + } + return nullptr; +} + + +static const char* _simpleXmlFindDoctypeChildEndTag(const char* itr, const char* itrEnd) +{ + for (; itr < itrEnd; itr++) { + if (*itr == '>') return itr; + } + return nullptr; +} + + +bool simpleXmlParseAttributes(const char* buf, unsigned bufLength, simpleXMLAttributeCb func, const void* data) +{ + const char *itr = buf, *itrEnd = buf + bufLength; + char* tmpBuf = (char*)alloca(bufLength + 1); + + if (!buf) return false; + if (!func) return false; + + while (itr < itrEnd) { + const char* p = _simpleXmlSkipWhiteSpace(itr, itrEnd); + const char *key, *keyEnd, *value, *valueEnd; + char* tval; + + if (p == itrEnd) return true; + + key = p; + for (keyEnd = key; keyEnd < itrEnd; keyEnd++) { + if ((*keyEnd == '=') || (isspace((unsigned char)*keyEnd))) break; + } + if (keyEnd == itrEnd) return false; + if (keyEnd == key) continue; + + if (*keyEnd == '=') value = keyEnd + 1; + else { + value = (const char*)memchr(keyEnd, '=', itrEnd - keyEnd); + if (!value) return false; + value++; + } + for (; value < itrEnd; value++) { + if (!isspace((unsigned char)*value)) break; + } + if (value == itrEnd) return false; + + if ((*value == '"') || (*value == '\'')) { + valueEnd = (const char*)memchr(value + 1, *value, itrEnd - value); + if (!valueEnd) return false; + value++; + } else { + valueEnd = _simpleXmlFindWhiteSpace(value, itrEnd); + } + + memcpy(tmpBuf, key, keyEnd - key); + tmpBuf[keyEnd - key] = '\0'; + + tval = tmpBuf + (keyEnd - key) + 1; + memcpy(tval, value, valueEnd - value); + tval[valueEnd - value] = '\0'; + + if (!func((void*)data, tmpBuf, tval)) return false; + + itr = valueEnd + 1; + } + return true; +} + + +bool simpleXmlParse(const char* buf, unsigned bufLength, bool strip, simpleXMLCb func, const void* data) +{ + const char *itr = buf, *itrEnd = buf + bufLength; + + if (!buf) return false; + if (!func) return false; + +#define CB(type, start, end) \ + do { \ + size_t _sz = end - start; \ + bool _ret; \ + _ret = func((void*)data, type, start, start - buf, _sz); \ + if (!_ret) \ + return false; \ + } while (0) + + while (itr < itrEnd) { + if (itr[0] == '<') { + if (itr + 1 >= itrEnd) { + CB(SimpleXMLType::Error, itr, itrEnd); + return false; + } else { + SimpleXMLType type; + size_t toff; + const char* p; + + if (itr[1] == '/') { + type = SimpleXMLType::Close; + toff = 1; + } else if (itr[1] == '?') { + type = SimpleXMLType::Processing; + toff = 1; + } else if (itr[1] == '!') { + 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])))) { + type = SimpleXMLType::Doctype; + toff = sizeof("!DOCTYPE") - 1; + } else if ((itr + sizeof("") - 1 < itrEnd) && (!memcmp(itr + 2, "--", sizeof("--") - 1))) { + type = SimpleXMLType::Comment; + toff = sizeof("!--") - 1; + } else if ((itr + sizeof("") - 1 < itrEnd) && (!memcmp(itr + 2, "[CDATA[", sizeof("[CDATA[") - 1))) { + type = SimpleXMLType::CData; + toff = sizeof("![CDATA[") - 1; + } else if (itr + sizeof("") - 1 < itrEnd) { + type = SimpleXMLType::DoctypeChild; + toff = sizeof("!") - 1; + } else { + type = SimpleXMLType::Open; + toff = 0; + } + } else { + type = SimpleXMLType::Open; + toff = 0; + } + + if (type == SimpleXMLType::CData) p = _simpleXmlFindEndCdataTag(itr + 1 + toff, itrEnd); + else if (type == SimpleXMLType::DoctypeChild) p = _simpleXmlFindDoctypeChildEndTag(itr + 1 + toff, itrEnd); + else if (type == SimpleXMLType::Comment) p = _simpleXmlFindEndCommentTag(itr + 1 + toff, itrEnd); + else p = _simpleXmlFindEndTag(itr + 1 + toff, itrEnd); + + if ((p) && (*p == '<')) { + type = SimpleXMLType::Error; + toff = 0; + } + + if (p) { + const char *start, *end; + + start = itr + 1 + toff; + end = p; + + switch (type) { + case SimpleXMLType::Open: { + if (p[-1] == '/') { + type = SimpleXMLType::OpenEmpty; + end--; + } + break; + } + case SimpleXMLType::CData: { + if (!memcmp(p - 2, "]]", 2)) end -= 2; + break; + } + case SimpleXMLType::Processing: { + if (p[-1] == '?') end--; + break; + } + case SimpleXMLType::Comment: { + if (!memcmp(p - 2, "--", 2)) end -= 2; + break; + } + case SimpleXMLType::OpenEmpty: + case SimpleXMLType::Close: + case SimpleXMLType::Data: + case SimpleXMLType::Error: + case SimpleXMLType::Doctype: + case SimpleXMLType::DoctypeChild: + case SimpleXMLType::Ignored: { + break; + } + } + + if ((strip) && (type != SimpleXMLType::Error) && (type != SimpleXMLType::CData)) { + start = _simpleXmlSkipWhiteSpace(start, end); + end = _simpleXmlUnskipWhiteSpace(end, start + 1); + } + + CB(type, start, end); + + if (type != SimpleXMLType::Error) itr = p + 1; + else itr = p; + } else { + CB(SimpleXMLType::Error, itr, itrEnd); + return false; + } + } + } else { + const char *p, *end; + + if (strip) { + p = _simpleXmlSkipWhiteSpace(itr, itrEnd); + if (p) { + CB(SimpleXMLType::Ignored, itr, p); + itr = p; + } + } + + p = _simpleXmlFindStartTag(itr, itrEnd); + if (!p) p = itrEnd; + + end = p; + if (strip) end = _simpleXmlUnskipWhiteSpace(end, itr); + + if (itr != end) CB(SimpleXMLType::Data, itr, end); + + if ((strip) && (end < p)) CB(SimpleXMLType::Ignored, end, p); + + itr = p; + } + } + +#undef CB + + return true; +} + + +bool simpleXmlParseW3CAttribute(const char* buf, simpleXMLAttributeCb func, const void* data) +{ + const char* end; + char* key; + char* val; + char* next; + + if (!buf) return false; + + end = buf + strlen(buf); + key = (char*)alloca(end - buf + 1); + val = (char*)alloca(end - buf + 1); + + if (buf == end) return true; + + do { + char* sep = (char*)strchr(buf, ':'); + next = (char*)strchr(buf, ';'); + + key[0] = '\0'; + val[0] = '\0'; + + if (next == nullptr && sep != nullptr) { + memcpy(key, buf, sep - buf); + key[sep - buf] = '\0'; + + memcpy(val, sep + 1, end - sep - 1); + val[end - sep - 1] = '\0'; + } else if (sep < next && sep != nullptr) { + memcpy(key, buf, sep - buf); + key[sep - buf] = '\0'; + + memcpy(val, sep + 1, next - sep - 1); + val[next - sep - 1] = '\0'; + } else if (next) { + memcpy(key, buf, next - buf); + key[next - buf] = '\0'; + } + + if (key[0]) { + if (!func((void*)data, key, val)) return false; + } + + buf = next + 1; + } while (next != nullptr); + + return true; +} + + +const char* simpleXmlFindAttributesTag(const char* buf, unsigned bufLength) +{ + const char *itr = buf, *itrEnd = buf + bufLength; + + for (; itr < itrEnd; itr++) { + if (!isspace((unsigned char)*itr)) { + //User skip tagname and already gave it the attributes. + if (*itr == '=') return buf; + } else { + itr = _simpleXmlSkipWhiteSpace(itr + 1, itrEnd); + if (itr == itrEnd) return nullptr; + return itr; + } + } + + return nullptr; +} + diff --git a/src/loaders/svg_loader/tvgSimpleXmlParser.h b/src/loaders/svg_loader/tvgSimpleXmlParser.h new file mode 100644 index 0000000..4e3b3a7 --- /dev/null +++ b/src/loaders/svg_loader/tvgSimpleXmlParser.h @@ -0,0 +1,31 @@ +#ifndef _TVG_SIMPLE_XML_PARSER_H_ +#define _TVG_SIMPLE_XML_PARSER_H_ + +#include +#include +#include + +enum class SimpleXMLType +{ + Open = 0, //!< \ + OpenEmpty, //!< \ + Close, //!< \ + Data, //!< tag text data + CData, //!< \ + Error, //!< error contents + Processing, //!< \ \ + Doctype, //!< \ + Ignored, //!< whatever is ignored by parser, like whitespace + DoctypeChild //!< \ /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ +typedef SvgNode* (*FactoryMethod)(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength); +typedef SvgStyleGradient* (*GradientFactoryMethod)(SvgLoaderData* loader, const char* buf, unsigned bufLength); + + +static char* _skipSpace(const char* str, const char* end) +{ + while (((end != nullptr && str < end) || (end == nullptr && *str != '\0')) && isspace(*str)) + ++str; + return (char*)str; +} + + +static string* _copyId(const char* str) +{ + if (str == nullptr) return nullptr; + + return new string(str); +} + + +static const char* _skipComma(const char* content) +{ + content = _skipSpace(content, nullptr); + if (*content == ',') return content + 1; + return content; +} + + +static bool _parseNumber(const char** content, float* number) +{ + char* end = nullptr; + + *number = strtof(*content, &end); + //If the start of string is not number + if ((*content) == end) return false; + //Skip comma if any + *content = _skipComma(end); + return true; +} + +/** + * According to https://www.w3.org/TR/SVG/coords.html#Units + * + * TODO + * Since this documentation is not obvious, more clean recalculation with dpi + * is required, but for now default w3 constants would be used + */ +static float _toFloat(SvgParser* svgParse, const char* str, SvgParserLengthType type) +{ + float parsedValue = strtof(str, nullptr); + + if (strstr(str, "cm")) parsedValue = parsedValue * 35.43307; + else if (strstr(str, "mm")) parsedValue = parsedValue * 3.543307; + else if (strstr(str, "pt")) parsedValue = parsedValue * 1.25; + else if (strstr(str, "pc")) parsedValue = parsedValue * 15; + else if (strstr(str, "in")) parsedValue = parsedValue * 90; + else if (strstr(str, "%")) { + if (type == SvgParserLengthType::Vertical) parsedValue = (parsedValue / 100.0) * svgParse->global.h; + else if (type == SvgParserLengthType::Horizontal) parsedValue = (parsedValue / 100.0) * svgParse->global.w; + else //if other then it's radius + { + float max = svgParse->global.w; + if (max < svgParse->global.h) + max = svgParse->global.h; + parsedValue = (parsedValue / 100.0) * max; + } + } + + //TODO: Implement 'em', 'ex' attributes + + return parsedValue; +} + + +static float _gradientToFloat(SvgParser* svgParse, const char* str, SvgParserLengthType type) +{ + char* end = nullptr; + + float parsedValue = strtof(str, &end); + float max = 1; + + /** + * That is according to Units in here + * + * https://www.w3.org/TR/2015/WD-SVG2-20150915/coords.html + */ + if (type == SvgParserLengthType::Vertical) max = svgParse->global.h; + else if (type == SvgParserLengthType::Horizontal) max = svgParse->global.w; + else if (type == SvgParserLengthType::Other) max = sqrt(pow(svgParse->global.h, 2) + pow(svgParse->global.w, 2)) / sqrt(2.0); + + if (strstr(str, "%")) parsedValue = parsedValue / 100.0; + else if (strstr(str, "cm")) parsedValue = parsedValue * 35.43307; + else if (strstr(str, "mm")) parsedValue = parsedValue * 3.543307; + else if (strstr(str, "pt")) parsedValue = parsedValue * 1.25; + else if (strstr(str, "pc")) parsedValue = parsedValue * 15; + else if (strstr(str, "in")) parsedValue = parsedValue * 90; + //TODO: Implement 'em', 'ex' attributes + + //Transform into global percentage + parsedValue = parsedValue / max; + + return parsedValue; +} + + +static float _toOffset(const char* str) +{ + char* end = nullptr; + + float parsedValue = strtof(str, &end); + + if (strstr(str, "%")) parsedValue = parsedValue / 100.0; + + return parsedValue; +} + + +static int _toOpacity(const char* str) +{ + char* end = nullptr; + int a = 0; + float opacity = strtof(str, &end); + + if (end && (*end == '\0')) a = lrint(opacity * 255); + return a; +} + + +#define _PARSE_TAG(Type, Name, Name1, Tags_Array, Default) \ + static Type _to##Name1(const char* str) \ + { \ + unsigned int i; \ + \ + for (i = 0; i < sizeof(Tags_Array) / sizeof(Tags_Array[0]); i++) { \ + if (!strcmp(str, Tags_Array[i].tag)) return Tags_Array[i].Name; \ + } \ + return Default; \ + } + + +/* parse the line cap used during stroking a path. + * Value: butt | round | square | inherit + * Initial: butt + * https://www.w3.org/TR/SVG/painting.html + */ +static constexpr struct +{ + StrokeCap lineCap; + const char* tag; +} lineCapTags[] = { + { StrokeCap::Butt, "butt" }, + { StrokeCap::Round, "round" }, + { StrokeCap::Square, "square" } +}; + + +_PARSE_TAG(StrokeCap, lineCap, LineCap, lineCapTags, StrokeCap::Butt); + + +/* parse the line join used during stroking a path. + * Value: miter | round | bevel | inherit + * Initial: miter + * https://www.w3.org/TR/SVG/painting.html + */ +static constexpr struct +{ + StrokeJoin lineJoin; + const char* tag; +} lineJoinTags[] = { + { StrokeJoin::Miter, "miter" }, + { StrokeJoin::Round, "round" }, + { StrokeJoin::Bevel, "bevel" } +}; + + +_PARSE_TAG(StrokeJoin, lineJoin, LineJoin, lineJoinTags, StrokeJoin::Miter); + + +/* parse the fill rule used during filling a path. + * Value: nonzero | evenodd | inherit + * Initial: nonzero + * https://www.w3.org/TR/SVG/painting.html + */ +static constexpr struct +{ + SvgFillRule fillRule; + const char* tag; +} fillRuleTags[] = { + { SvgFillRule::OddEven, "evenodd" } +}; + + +_PARSE_TAG(SvgFillRule, fillRule, FillRule, fillRuleTags, SvgFillRule::Winding); + + +static string* _idFromUrl(const char* url) +{ + char tmp[50]; + int i = 0; + + url = _skipSpace(url, nullptr); + if ((*url) == '(') { + ++url; + url = _skipSpace(url, nullptr); + } + + if ((*url) == '#') ++url; + + while ((*url) != ')') { + tmp[i++] = *url; + ++url; + } + tmp[i] = '\0'; + + return new string(tmp); +} + + +static unsigned char _parserColor(const char* value, char** end) +{ + float r; + + r = strtof(value + 4, end); + *end = _skipSpace(*end, nullptr); + if (**end == '%') r = 255 * r / 100; + *end = _skipSpace(*end, nullptr); + + if (r < 0 || r > 255) { + *end = nullptr; + return 0; + } + + return lrint(r); +} + + +static constexpr struct +{ + const char* name; + unsigned int value; +} colors[] = { + { "aliceblue", 0xfff0f8ff }, + { "antiquewhite", 0xfffaebd7 }, + { "aqua", 0xff00ffff }, + { "aquamarine", 0xff7fffd4 }, + { "azure", 0xfff0ffff }, + { "beige", 0xfff5f5dc }, + { "bisque", 0xffffe4c4 }, + { "black", 0xff000000 }, + { "blanchedalmond", 0xffffebcd }, + { "blue", 0xff0000ff }, + { "blueviolet", 0xff8a2be2 }, + { "brown", 0xffa52a2a }, + { "burlywood", 0xffdeb887 }, + { "cadetblue", 0xff5f9ea0 }, + { "chartreuse", 0xff7fff00 }, + { "chocolate", 0xffd2691e }, + { "coral", 0xffff7f50 }, + { "cornflowerblue", 0xff6495ed }, + { "cornsilk", 0xfffff8dc }, + { "crimson", 0xffdc143c }, + { "cyan", 0xff00ffff }, + { "darkblue", 0xff00008b }, + { "darkcyan", 0xff008b8b }, + { "darkgoldenrod", 0xffb8860b }, + { "darkgray", 0xffa9a9a9 }, + { "darkgrey", 0xffa9a9a9 }, + { "darkgreen", 0xff006400 }, + { "darkkhaki", 0xffbdb76b }, + { "darkmagenta", 0xff8b008b }, + { "darkolivegreen", 0xff556b2f }, + { "darkorange", 0xffff8c00 }, + { "darkorchid", 0xff9932cc }, + { "darkred", 0xff8b0000 }, + { "darksalmon", 0xffe9967a }, + { "darkseagreen", 0xff8fbc8f }, + { "darkslateblue", 0xff483d8b }, + { "darkslategray", 0xff2f4f4f }, + { "darkslategrey", 0xff2f4f4f }, + { "darkturquoise", 0xff00ced1 }, + { "darkviolet", 0xff9400d3 }, + { "deeppink", 0xffff1493 }, + { "deepskyblue", 0xff00bfff }, + { "dimgray", 0xff696969 }, + { "dimgrey", 0xff696969 }, + { "dodgerblue", 0xff1e90ff }, + { "firebrick", 0xffb22222 }, + { "floralwhite", 0xfffffaf0 }, + { "forestgreen", 0xff228b22 }, + { "fuchsia", 0xffff00ff }, + { "gainsboro", 0xffdcdcdc }, + { "ghostwhite", 0xfff8f8ff }, + { "gold", 0xffffd700 }, + { "goldenrod", 0xffdaa520 }, + { "gray", 0xff808080 }, + { "grey", 0xff808080 }, + { "green", 0xff008000 }, + { "greenyellow", 0xffadff2f }, + { "honeydew", 0xfff0fff0 }, + { "hotpink", 0xffff69b4 }, + { "indianred", 0xffcd5c5c }, + { "indigo", 0xff4b0082 }, + { "ivory", 0xfffffff0 }, + { "khaki", 0xfff0e68c }, + { "lavender", 0xffe6e6fa }, + { "lavenderblush", 0xfffff0f5 }, + { "lawngreen", 0xff7cfc00 }, + { "lemonchiffon", 0xfffffacd }, + { "lightblue", 0xffadd8e6 }, + { "lightcoral", 0xfff08080 }, + { "lightcyan", 0xffe0ffff }, + { "lightgoldenrodyellow", 0xfffafad2 }, + { "lightgray", 0xffd3d3d3 }, + { "lightgrey", 0xffd3d3d3 }, + { "lightgreen", 0xff90ee90 }, + { "lightpink", 0xffffb6c1 }, + { "lightsalmon", 0xffffa07a }, + { "lightseagreen", 0xff20b2aa }, + { "lightskyblue", 0xff87cefa }, + { "lightslategray", 0xff778899 }, + { "lightslategrey", 0xff778899 }, + { "lightsteelblue", 0xffb0c4de }, + { "lightyellow", 0xffffffe0 }, + { "lime", 0xff00ff00 }, + { "limegreen", 0xff32cd32 }, + { "linen", 0xfffaf0e6 }, + { "magenta", 0xffff00ff }, + { "maroon", 0xff800000 }, + { "mediumaquamarine", 0xff66cdaa }, + { "mediumblue", 0xff0000cd }, + { "mediumorchid", 0xffba55d3 }, + { "mediumpurple", 0xff9370d8 }, + { "mediumseagreen", 0xff3cb371 }, + { "mediumslateblue", 0xff7b68ee }, + { "mediumspringgreen", 0xff00fa9a }, + { "mediumturquoise", 0xff48d1cc }, + { "mediumvioletred", 0xffc71585 }, + { "midnightblue", 0xff191970 }, + { "mintcream", 0xfff5fffa }, + { "mistyrose", 0xffffe4e1 }, + { "moccasin", 0xffffe4b5 }, + { "navajowhite", 0xffffdead }, + { "navy", 0xff000080 }, + { "oldlace", 0xfffdf5e6 }, + { "olive", 0xff808000 }, + { "olivedrab", 0xff6b8e23 }, + { "orange", 0xffffa500 }, + { "orangered", 0xffff4500 }, + { "orchid", 0xffda70d6 }, + { "palegoldenrod", 0xffeee8aa }, + { "palegreen", 0xff98fb98 }, + { "paleturquoise", 0xffafeeee }, + { "palevioletred", 0xffd87093 }, + { "papayawhip", 0xffffefd5 }, + { "peachpuff", 0xffffdab9 }, + { "peru", 0xffcd853f }, + { "pink", 0xffffc0cb }, + { "plum", 0xffdda0dd }, + { "powderblue", 0xffb0e0e6 }, + { "purple", 0xff800080 }, + { "red", 0xffff0000 }, + { "rosybrown", 0xffbc8f8f }, + { "royalblue", 0xff4169e1 }, + { "saddlebrown", 0xff8b4513 }, + { "salmon", 0xfffa8072 }, + { "sandybrown", 0xfff4a460 }, + { "seagreen", 0xff2e8b57 }, + { "seashell", 0xfffff5ee }, + { "sienna", 0xffa0522d }, + { "silver", 0xffc0c0c0 }, + { "skyblue", 0xff87ceeb }, + { "slateblue", 0xff6a5acd }, + { "slategray", 0xff708090 }, + { "slategrey", 0xff708090 }, + { "snow", 0xfffffafa }, + { "springgreen", 0xff00ff7f }, + { "steelblue", 0xff4682b4 }, + { "tan", 0xffd2b48c }, + { "teal", 0xff008080 }, + { "thistle", 0xffd8bfd8 }, + { "tomato", 0xffff6347 }, + { "turquoise", 0xff40e0d0 }, + { "violet", 0xffee82ee }, + { "wheat", 0xfff5deb3 }, + { "white", 0xffffffff }, + { "whitesmoke", 0xfff5f5f5 }, + { "yellow", 0xffffff00 }, + { "yellowgreen", 0xff9acd32 } +}; + + +static void _toColor(const char* str, uint8_t* r, uint8_t* g, uint8_t* b, string** ref) +{ + unsigned int i, len = strlen(str); + char *red, *green, *blue; + unsigned char tr, tg, tb; + + if (len == 4 && str[0] == '#') { + //Case for "#456" should be interprete as "#445566" + if (isxdigit(str[1]) && isxdigit(str[2]) && isxdigit(str[3])) { + char tmp[3] = { '\0', '\0', '\0' }; + tmp[0] = str[1]; + tmp[1] = str[1]; + *r = strtol(tmp, nullptr, 16); + tmp[0] = str[2]; + tmp[1] = str[2]; + *g = strtol(tmp, nullptr, 16); + tmp[0] = str[3]; + tmp[1] = str[3]; + *b = strtol(tmp, nullptr, 16); + } + } else if (len == 7 && str[0] == '#') { + if (isxdigit(str[1]) && isxdigit(str[2]) && isxdigit(str[3]) && isxdigit(str[4]) && isxdigit(str[5]) && isxdigit(str[6])) { + char tmp[3] = { '\0', '\0', '\0' }; + tmp[0] = str[1]; + tmp[1] = str[2]; + *r = strtol(tmp, nullptr, 16); + tmp[0] = str[3]; + tmp[1] = str[4]; + *g = strtol(tmp, nullptr, 16); + tmp[0] = str[5]; + tmp[1] = str[6]; + *b = strtol(tmp, nullptr, 16); + } + } else if (len >= 10 && (str[0] == 'r' || str[0] == 'R') && (str[1] == 'g' || str[1] == 'G') && (str[2] == 'b' || str[2] == 'B') && str[3] == '(' && str[len - 1] == ')') { + tr = _parserColor(str + 4, &red); + if (red && *red == ',') { + tg = _parserColor(red + 1, &green); + if (green && *green == ',') { + tb = _parserColor(green + 1, &blue); + if (blue && blue[0] == ')' && blue[1] == '\0') { + *r = tr; + *g = tg; + *b = tb; + } + } + } + } else if (len >= 3 && !strncmp(str, "url", 3)) { + *ref = _idFromUrl((const char*)(str + 3)); + } else { + //Handle named color + for (i = 0; i < (sizeof(colors) / sizeof(colors[0])); i++) { + if (!strcasecmp(colors[i].name, str)) { + *r = (((uint8_t*)(&(colors[i].value)))[2]); + *g = (((uint8_t*)(&(colors[i].value)))[1]); + *b = (((uint8_t*)(&(colors[i].value)))[0]); + } + } + } +} + + +static char* _parseNumbersArray(char* str, float* points, int* ptCount) +{ + int count = 0; + char* end = nullptr; + + str = _skipSpace(str, nullptr); + while (isdigit(*str) || *str == '-' || *str == '+' || *str == '.') { + points[count++] = strtof(str, &end); + str = end; + str = _skipSpace(str, nullptr); + if (*str == ',') ++str; + //Eat the rest of space + str = _skipSpace(str, nullptr); + } + *ptCount = count; + return str; +} + + +enum class MatrixState { + Unknown, + Matrix, + Translate, + Rotate, + Scale, + SkewX, + SkewY +}; + + +#define MATRIX_DEF(Name, Value) \ + { \ +#Name, sizeof(#Name), Value \ + } + + +static constexpr struct +{ + const char* tag; + int sz; + MatrixState state; +} matrixTags[] = { + MATRIX_DEF(matrix, MatrixState::Matrix), + MATRIX_DEF(translate, MatrixState::Translate), + MATRIX_DEF(rotate, MatrixState::Rotate), + MATRIX_DEF(scale, MatrixState::Scale), + MATRIX_DEF(skewX, MatrixState::SkewX), + MATRIX_DEF(skewY, MatrixState::SkewY) +}; + + +static void _matrixCompose(const Matrix* m1, + const Matrix* m2, + Matrix* dst) +{ + float a11, a12, a13, a21, a22, a23, a31, a32, a33; + + a11 = (m1->e11 * m2->e11) + (m1->e12 * m2->e21) + (m1->e13 * m2->e31); + a12 = (m1->e11 * m2->e12) + (m1->e12 * m2->e22) + (m1->e13 * m2->e32); + a13 = (m1->e11 * m2->e13) + (m1->e12 * m2->e23) + (m1->e13 * m2->e33); + + a21 = (m1->e21 * m2->e11) + (m1->e22 * m2->e21) + (m1->e23 * m2->e31); + a22 = (m1->e21 * m2->e12) + (m1->e22 * m2->e22) + (m1->e23 * m2->e32); + a23 = (m1->e21 * m2->e13) + (m1->e22 * m2->e23) + (m1->e23 * m2->e33); + + a31 = (m1->e31 * m2->e11) + (m1->e32 * m2->e21) + (m1->e33 * m2->e31); + a32 = (m1->e31 * m2->e12) + (m1->e32 * m2->e22) + (m1->e33 * m2->e32); + a33 = (m1->e31 * m2->e13) + (m1->e32 * m2->e23) + (m1->e33 * m2->e33); + + dst->e11 = a11; + dst->e12 = a12; + dst->e13 = a13; + dst->e21 = a21; + dst->e22 = a22; + dst->e23 = a23; + dst->e31 = a31; + dst->e32 = a32; + dst->e33 = a33; +} + + +/* parse transform attribute + * https://www.w3.org/TR/SVG/coords.html#TransformAttribute + */ +static Matrix* _parseTransformationMatrix(const char* value) +{ + unsigned int i; + float points[8]; + int ptCount = 0; + float sx, sy; + MatrixState state = MatrixState::Unknown; + Matrix* matrix = (Matrix*)calloc(1, sizeof(Matrix)); + char* str = (char*)value; + char* end = str + strlen(str); + + *matrix = { 1, 0, 0, 0, 1, 0, 0, 0, 1 }; + while (str < end) { + if (isspace(*str) || (*str == ',')) { + ++str; + continue; + } + for (i = 0; i < sizeof(matrixTags) / sizeof(matrixTags[0]); i++) { + if (!strncmp(matrixTags[i].tag, str, matrixTags[i].sz - 1)) { + state = matrixTags[i].state; + str += (matrixTags[i].sz - 1); + } + } + if (state == MatrixState::Unknown) goto error; + + str = _skipSpace(str, end); + if (*str != '(') goto error; + ++str; + str = _parseNumbersArray(str, points, &ptCount); + if (*str != ')') goto error; + ++str; + + if (state == MatrixState::Matrix) { + Matrix tmp; + + if (ptCount != 6) goto error; + + tmp = { points[0], points[2], points[4], points[1], points[3], points[5], 0, 0, 1 }; + _matrixCompose(matrix, &tmp, matrix); + } else if (state == MatrixState::Translate) { + Matrix tmp; + + if (ptCount == 1) { + tmp = { 1, 0, points[0], 0, 1, 0, 0, 0, 1 }; + _matrixCompose(matrix, &tmp, matrix); + } else if (ptCount == 2) { + tmp = { 1, 0, points[0], 0, 1, points[1], 0, 0, 1 }; + _matrixCompose(matrix, &tmp, matrix); + } else goto error; + } else if (state == MatrixState::Rotate) { + Matrix tmp; + float c, s; + //Transform to signed. + points[0] = fmod(points[0], 360); + if (points[0] < 0) points[0] += 360; + + c = cosf(points[0] * (M_PI / 180.0)); + s = sinf(points[0] * (M_PI / 180.0)); + if (ptCount == 1) { + tmp = { c, -s, 0, s, c, 0, 0, 0, 1 }; + _matrixCompose(matrix, &tmp, matrix); + } else if (ptCount == 3) { + tmp = { 1, 0, points[0], 0, 1, points[1], 0, 0, 1 }; + _matrixCompose(matrix, &tmp, matrix); + + tmp = { c, -s, 0, s, c, 0, 0, 0, 1 }; + _matrixCompose(matrix, &tmp, matrix); + + tmp = { 1, 0, points[0], 0, 1, points[1], 0, 0, 1 }; + _matrixCompose(matrix, &tmp, matrix); + } else { + goto error; + } + } else if (state == MatrixState::Scale) { + Matrix tmp; + if (ptCount < 1 || ptCount > 2) goto error; + + sx = points[0]; + sy = sx; + if (ptCount == 2) sy = points[1]; + tmp = { sx, 0, 0, 0, sy, 0, 0, 0, 1 }; + _matrixCompose(matrix, &tmp, matrix); + } + } +error: + return matrix; +} + + +#define LENGTH_DEF(Name, Value) \ + { \ +#Name, sizeof(#Name), Value \ + } + + +static constexpr struct +{ + const char* tag; + int sz; + SvgLengthType type; +} lengthTags[] = { + LENGTH_DEF(%, SvgLengthType::Percent), + LENGTH_DEF(px, SvgLengthType::Px), + LENGTH_DEF(pc, SvgLengthType::Pc), + LENGTH_DEF(pt, SvgLengthType::Pt), + LENGTH_DEF(mm, SvgLengthType::Mm), + LENGTH_DEF(cm, SvgLengthType::Cm), + LENGTH_DEF(in, SvgLengthType::In) +}; + + +static float _parseLength(const char* str, SvgLengthType* type) +{ + unsigned int i; + float value; + int sz = strlen(str); + + *type = SvgLengthType::Px; + for (i = 0; i < sizeof(lengthTags) / sizeof(lengthTags[0]); i++) { + if (lengthTags[i].sz - 1 == sz && !strncmp(lengthTags[i].tag, str, sz)) *type = lengthTags[i].type; + } + value = strtof(str, nullptr); + return value; +} + + +static bool _parseStyleAttr(void* data, const char* key, const char* value); + + +static bool _attrParseSvgNode(void* data, const char* key, const char* value) +{ + SvgLoaderData* loader = (SvgLoaderData*)data; + SvgNode* node = loader->svgParse->node; + SvgDocNode* doc = &(node->node.doc); + SvgLengthType type; + + //@TODO handle lenght unit. + if (!strcmp(key, "width")) { + doc->w = _parseLength(value, &type); + } else if (!strcmp(key, "height")) { + doc->h = _parseLength(value, &type); + } else if (!strcmp(key, "viewBox")) { + if (_parseNumber(&value, &doc->vx)) { + if (_parseNumber(&value, &doc->vy)) { + if (_parseNumber(&value, &doc->vw)) { + _parseNumber(&value, &doc->vh); + loader->svgParse->global.h = doc->vh; + } + loader->svgParse->global.w = doc->vw; + } + loader->svgParse->global.y = doc->vy; + } + loader->svgParse->global.x = doc->vx; + } else if (!strcmp(key, "preserveAspectRatio")) { + if (!strcmp(value, "none")) doc->preserveAspect = false; + } else if (!strcmp(key, "style")) { + return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); + } else { + return _parseStyleAttr(loader, key, value); + } + return true; +} + + +//https://www.w3.org/TR/SVGTiny12/painting.html#SpecifyingPaint +static void _handlePaintAttr(SvgLoaderData* loader, SvgPaint* paint, const char* value) +{ + if (!strcmp(value, "none")) { + //No paint property + paint->none = true; + return; + } + paint->none = false; + if (!strcmp(value, "currentColor")) { + paint->curColor = true; + return; + } + _toColor(value, &paint->r, &paint->g, &paint->b, &paint->url); +} + + +static void _handleColorAttr(SvgLoaderData* loader, SvgNode* node, const char* value) +{ + SvgStyleProperty* style = node->style; + _toColor(value, &style->r, &style->g, &style->b, nullptr); +} + + +static void _handleFillAttr(SvgLoaderData* loader, SvgNode* node, const char* value) +{ + SvgStyleProperty* style = node->style; + style->fill.flags = (SvgFillFlags)((int)style->fill.flags | (int)SvgFillFlags::Paint); + _handlePaintAttr(loader, &style->fill.paint, value); +} + + +static void _handleStrokeAttr(SvgLoaderData* loader, SvgNode* node, const char* value) +{ + SvgStyleProperty* style = node->style; + style->stroke.flags = (SvgStrokeFlags)((int)style->stroke.flags | (int)SvgStrokeFlags::Paint); + _handlePaintAttr(loader, &style->stroke.paint, value); +} + + +static void _handleStrokeOpacityAttr(SvgLoaderData* loader, SvgNode* node, const char* value) +{ + node->style->stroke.flags = (SvgStrokeFlags)((int)node->style->stroke.flags | (int)SvgStrokeFlags::Opacity); + node->style->stroke.opacity = _toOpacity(value); +} + + +static void _handleStrokeWidthAttr(SvgLoaderData* loader, SvgNode* node, const char* value) +{ + node->style->stroke.flags = (SvgStrokeFlags)((int)node->style->stroke.flags | (int)SvgStrokeFlags::Width); + node->style->stroke.width = _toFloat(loader->svgParse, value, SvgParserLengthType::Horizontal); +} + + +static void _handleStrokeLineCapAttr(SvgLoaderData* loader, SvgNode* node, const char* value) +{ + node->style->stroke.flags = (SvgStrokeFlags)((int)node->style->stroke.flags | (int)SvgStrokeFlags::Cap); + node->style->stroke.cap = _toLineCap(value); +} + + +static void _handleStrokeLineJoinAttr(SvgLoaderData* loader, SvgNode* node, const char* value) +{ + node->style->stroke.flags = (SvgStrokeFlags)((int)node->style->stroke.flags | (int)SvgStrokeFlags::Join); + node->style->stroke.join = _toLineJoin(value); +} + + +static void _handleFillRuleAttr(SvgLoaderData* loader, SvgNode* node, const char* value) +{ + node->style->fill.flags = (SvgFillFlags)((int)node->style->fill.flags | (int)SvgFillFlags::FillRule); + node->style->fill.fillRule = _toFillRule(value); +} + + +static void _handleOpacityAttr(SvgLoaderData* loader, SvgNode* node, const char* value) +{ + node->style->opacity = _toOpacity(value); +} + + +static void _handleFillOpacityAttr(SvgLoaderData* loader, SvgNode* node, const char* value) +{ + node->style->fill.flags = (SvgFillFlags)((int)node->style->fill.flags | (int)SvgFillFlags::Opacity); + node->style->fill.opacity = _toOpacity(value); +} + + +static void _handleTransformAttr(SvgLoaderData* loader, SvgNode* node, const char* value) +{ + node->transform = _parseTransformationMatrix(value); +} + + +static void _handleDisplayAttr(SvgLoaderData* loader, SvgNode* node, const char* value) +{ + //TODO : The display attribute can have various values as well as "none". + // The default is "inline" which means visible and "none" means invisible. + // Depending on the type of node, additional functionality may be required. + // refer to https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/display + if (!strcmp(value, "none")) node->display = false; + else node->display = true; +} + + +typedef void (*styleMethod)(SvgLoaderData* loader, SvgNode* node, const char* value); + + +#define STYLE_DEF(Name, Name1) \ + { \ +#Name, sizeof(#Name), _handle##Name1##Attr \ + } + + +static constexpr struct +{ + const char* tag; + int sz; + styleMethod tagHandler; +} styleTags[] = { + STYLE_DEF(color, Color), + STYLE_DEF(fill, Fill), + STYLE_DEF(fill-rule, FillRule), + STYLE_DEF(fill-opacity, FillOpacity), + STYLE_DEF(opacity, Opacity), + STYLE_DEF(stroke, Stroke), + STYLE_DEF(stroke-width, StrokeWidth), + STYLE_DEF(stroke-linejoin, StrokeLineJoin), + STYLE_DEF(stroke-linecap, StrokeLineCap), + STYLE_DEF(stroke-opacity, StrokeOpacity), + STYLE_DEF(transform, Transform), + STYLE_DEF(display, Display) +}; + + +static bool _parseStyleAttr(void* data, const char* key, const char* value) +{ + SvgLoaderData* loader = (SvgLoaderData*)data; + SvgNode* node = loader->svgParse->node; + unsigned int i; + int sz; + if (!key || !value) return false; + + //Trim the white space + key = _skipSpace(key, nullptr); + + value = _skipSpace(value, nullptr); + + sz = strlen(key); + for (i = 0; i < sizeof(styleTags) / sizeof(styleTags[0]); i++) { + if (styleTags[i].sz - 1 == sz && !strncmp(styleTags[i].tag, key, sz)) { + styleTags[i].tagHandler(loader, node, value); + return true; + } + } + + return true; +} + +/* parse g node + * https://www.w3.org/TR/SVG/struct.html#Groups + */ +static bool _attrParseGNode(void* data, const char* key, const char* value) +{ + SvgLoaderData* loader = (SvgLoaderData*)data; + SvgNode* node = loader->svgParse->node; + + if (!strcmp(key, "style")) { + return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); + } else if (!strcmp(key, "transform")) { + node->transform = _parseTransformationMatrix(value); + } else if (!strcmp(key, "id")) { + node->id = _copyId(value); + } else { + return _parseStyleAttr(loader, key, value); + } + return true; +} + + +static SvgNode* _createNode(SvgNode* parent, SvgNodeType type) +{ + SvgNode* node = (SvgNode*)calloc(1, sizeof(SvgNode)); + + //Default fill property + node->style = (SvgStyleProperty*)calloc(1, sizeof(SvgStyleProperty)); + + //Update the default value of stroke and fill + //https://www.w3.org/TR/SVGTiny12/painting.html#SpecifyingPaint + node->style->fill.paint.none = false; + //Default fill opacity is 1 + node->style->fill.opacity = 255; + node->style->opacity = 255; + + //Default fill rule is nonzero + node->style->fill.fillRule = SvgFillRule::Winding; + + //Default stroke is none + node->style->stroke.paint.none = true; + //Default stroke opacity is 1 + node->style->stroke.opacity = 255; + //Default stroke width is 1 + node->style->stroke.width = 1; + //Default line cap is butt + node->style->stroke.cap = StrokeCap::Butt; + //Default line join is miter + node->style->stroke.join = StrokeJoin::Miter; + node->style->stroke.scale = 1.0; + + //Default display is true("inline"). + node->display = true; + + node->parent = parent; + node->type = type; + + if (parent) parent->child.push_back(node); + return node; +} + + +static SvgNode* _createDefsNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +{ + SvgNode* node = _createNode(nullptr, SvgNodeType::Defs); + simpleXmlParseAttributes(buf, bufLength, nullptr, node); + return node; +} + + +static SvgNode* _createGNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +{ + loader->svgParse->node = _createNode(parent, SvgNodeType::G); + + simpleXmlParseAttributes(buf, bufLength, _attrParseGNode, loader); + return loader->svgParse->node; +} + + +static SvgNode* _createSvgNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +{ + loader->svgParse->node = _createNode(parent, SvgNodeType::Doc); + SvgDocNode* doc = &(loader->svgParse->node->node.doc); + + doc->preserveAspect = true; + simpleXmlParseAttributes(buf, bufLength, _attrParseSvgNode, loader); + + return loader->svgParse->node; +} + + +static bool _attrParsePathNode(void* data, const char* key, const char* value) +{ + SvgLoaderData* loader = (SvgLoaderData*)data; + SvgNode* node = loader->svgParse->node; + SvgPathNode* path = &(node->node.path); + + if (!strcmp(key, "d")) { + //Temporary: need to copy + path->path = _copyId(value); + } else if (!strcmp(key, "style")) { + return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); + } else if (!strcmp(key, "id")) { + node->id = _copyId(value); + } else { + return _parseStyleAttr(loader, key, value); + } + return true; +} + + +static SvgNode* _createPathNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +{ + loader->svgParse->node = _createNode(parent, SvgNodeType::Path); + + simpleXmlParseAttributes(buf, bufLength, _attrParsePathNode, loader); + + return loader->svgParse->node; +} + + +#define CIRCLE_DEF(Name, Field, Type) \ + { \ +#Name, Type, sizeof(#Name), offsetof(SvgCircleNode, Field) \ + } + + +static constexpr struct +{ + const char* tag; + SvgParserLengthType type; + int sz; + size_t offset; +} circleTags[] = { + CIRCLE_DEF(cx, cx, SvgParserLengthType::Horizontal), + CIRCLE_DEF(cy, cy, SvgParserLengthType::Vertical), + CIRCLE_DEF(r, r, SvgParserLengthType::Other) +}; + + +/* parse the attributes for a circle element. + * https://www.w3.org/TR/SVG/shapes.html#CircleElement + */ +static bool _attrParseCircleNode(void* data, const char* key, const char* value) +{ + SvgLoaderData* loader = (SvgLoaderData*)data; + SvgNode* node = loader->svgParse->node; + SvgCircleNode* circle = &(node->node.circle); + unsigned int i; + unsigned char* array; + int sz = strlen(key); + + array = (unsigned char*)circle; + for (i = 0; i < sizeof(circleTags) / sizeof(circleTags[0]); i++) { + if (circleTags[i].sz - 1 == sz && !strncmp(circleTags[i].tag, key, sz)) { + *((float*)(array + circleTags[i].offset)) = _toFloat(loader->svgParse, value, circleTags[i].type); + return true; + } + } + + if (!strcmp(key, "style")) { + return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); + } else if (!strcmp(key, "id")) { + node->id = _copyId(value); + } else { + return _parseStyleAttr(loader, key, value); + } + return true; +} + + +static SvgNode* _createCircleNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +{ + loader->svgParse->node = _createNode(parent, SvgNodeType::Circle); + + simpleXmlParseAttributes(buf, bufLength, _attrParseCircleNode, loader); + return loader->svgParse->node; +} + + +#define ELLIPSE_DEF(Name, Field, Type) \ + { \ +#Name, Type, sizeof(#Name), offsetof(SvgEllipseNode, Field) \ + } + + +static constexpr struct +{ + const char* tag; + SvgParserLengthType type; + int sz; + size_t offset; +} ellipseTags[] = { + ELLIPSE_DEF(cx, cx, SvgParserLengthType::Horizontal), + ELLIPSE_DEF(cy, cy, SvgParserLengthType::Vertical), + ELLIPSE_DEF(rx, rx, SvgParserLengthType::Horizontal), + ELLIPSE_DEF(ry, ry, SvgParserLengthType::Vertical) +}; + + +/* parse the attributes for an ellipse element. + * https://www.w3.org/TR/SVG/shapes.html#EllipseElement + */ +static bool _attrParseEllipseNode(void* data, const char* key, const char* value) +{ + SvgLoaderData* loader = (SvgLoaderData*)data; + SvgNode* node = loader->svgParse->node; + SvgEllipseNode* ellipse = &(node->node.ellipse); + unsigned int i; + unsigned char* array; + int sz = strlen(key); + + array = (unsigned char*)ellipse; + for (i = 0; i < sizeof(ellipseTags) / sizeof(ellipseTags[0]); i++) { + if (ellipseTags[i].sz - 1 == sz && !strncmp(ellipseTags[i].tag, key, sz)) { + *((float*)(array + ellipseTags[i].offset)) = _toFloat(loader->svgParse, value, ellipseTags[i].type); + return true; + } + } + + if (!strcmp(key, "id")) { + node->id = _copyId(value); + } else if (!strcmp(key, "style")) { + return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); + } else { + return _parseStyleAttr(loader, key, value); + } + return true; +} + + +static SvgNode* _createEllipseNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +{ + loader->svgParse->node = _createNode(parent, SvgNodeType::Ellipse); + + simpleXmlParseAttributes(buf, bufLength, _attrParseEllipseNode, loader); + return loader->svgParse->node; +} + + +static void _attrParsePolygonPoints(const char* str, float** points, int* ptCount) +{ + float tmp[50]; + int tmpCount = 0; + int count = 0; + float num; + float *pointArray = nullptr, *tmpArray; + + while (_parseNumber(&str, &num)) { + tmp[tmpCount++] = num; + if (tmpCount == 50) { + tmpArray = (float*)realloc(pointArray, (count + tmpCount) * sizeof(float)); + if (!tmpArray) goto error_alloc; + pointArray = tmpArray; + memcpy(&pointArray[count], tmp, tmpCount * sizeof(float)); + count += tmpCount; + tmpCount = 0; + } + } + + if (tmpCount > 0) { + tmpArray = (float*)realloc(pointArray, (count + tmpCount) * sizeof(float)); + if (!tmpArray) goto error_alloc; + pointArray = tmpArray; + memcpy(&pointArray[count], tmp, tmpCount * sizeof(float)); + count += tmpCount; + } + *ptCount = count; + *points = pointArray; + return; + +error_alloc: + printf("ERR : allocation for point array failed. out of memory"); + abort(); +} + + +/* parse the attributes for a polygon element. + * https://www.w3.org/TR/SVG/shapes.html#PolylineElement + */ +static bool _attrParsePolygonNode(void* data, const char* key, const char* value) +{ + SvgLoaderData* loader = (SvgLoaderData*)data; + SvgNode* node = loader->svgParse->node; + SvgPolygonNode* polygon = nullptr; + + if (node->type == SvgNodeType::Polygon) polygon = &(node->node.polygon); + else polygon = &(node->node.polyline); + + if (!strcmp(key, "points")) { + _attrParsePolygonPoints(value, &polygon->points, &polygon->pointsCount); + } else if (!strcmp(key, "style")) { + return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); + } else if (!strcmp(key, "id")) { + node->id = _copyId(value); + } else { + return _parseStyleAttr(loader, key, value); + } + return true; +} + + +static SvgNode* _createPolygonNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +{ + loader->svgParse->node = _createNode(parent, SvgNodeType::Polygon); + + simpleXmlParseAttributes(buf, bufLength, _attrParsePolygonNode, loader); + return loader->svgParse->node; +} + + +static SvgNode* _createPolylineNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +{ + loader->svgParse->node = _createNode(parent, SvgNodeType::Polyline); + + simpleXmlParseAttributes(buf, bufLength, _attrParsePolygonNode, loader); + return loader->svgParse->node; +} + + +#define RECT_DEF(Name, Field, Type) \ + { \ +#Name, Type, sizeof(#Name), offsetof(SvgRectNode, Field) \ + } + + +static constexpr struct +{ + const char* tag; + SvgParserLengthType type; + int sz; + size_t offset; +} rectTags[] = { + RECT_DEF(x, x, SvgParserLengthType::Horizontal), + RECT_DEF(y, y, SvgParserLengthType::Vertical), + RECT_DEF(w, w, SvgParserLengthType::Horizontal), + RECT_DEF(h, h, SvgParserLengthType::Vertical), + RECT_DEF(rx, rx, SvgParserLengthType::Horizontal), + RECT_DEF(ry, ry, SvgParserLengthType::Vertical) +}; + + +/* parse the attributes for a rect element. + * https://www.w3.org/TR/SVG/shapes.html#RectElement + */ +static bool _attrParseRectNode(void* data, const char* key, const char* value) +{ + SvgLoaderData* loader = (SvgLoaderData*)data; + SvgNode* node = loader->svgParse->node; + SvgRectNode* rect = &(node->node.rect); + unsigned int i; + unsigned char* array; + bool ret = true; + int sz = strlen(key); + + array = (unsigned char*)rect; + for (i = 0; i < sizeof(rectTags) / sizeof(rectTags[0]); i++) { + if (rectTags[i].sz - 1 == sz && !strncmp(rectTags[i].tag, key, sz)) { + *((float*)(array + rectTags[i].offset)) = _toFloat(loader->svgParse, value, rectTags[i].type); + return ret; + } + } + + + if (!strcmp(key, "id")) { + node->id = _copyId(value); + } else if (!strcmp(key, "style")) { + ret = simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); + } else { + ret = _parseStyleAttr(loader, key, value); + } + + if (!(rect->rx - 0 <= FLT_EPSILON) && (rect->ry - 0 <= FLT_EPSILON)) rect->ry = rect->rx; + if (!(rect->ry - 0 <= FLT_EPSILON) && (rect->rx - 0 <= FLT_EPSILON)) rect->rx = rect->ry; + + return ret; +} + + +static SvgNode* _createRectNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +{ + loader->svgParse->node = _createNode(parent, SvgNodeType::Rect); + + simpleXmlParseAttributes(buf, bufLength, _attrParseRectNode, loader); + return loader->svgParse->node; +} + + +#define LINE_DEF(Name, Field, Type) \ + { \ +#Name, Type, sizeof(#Name), offsetof(SvgLineNode, Field) \ + } + + +static constexpr struct +{ + const char* tag; + SvgParserLengthType type; + int sz; + size_t offset; +} lineTags[] = { + LINE_DEF(x1, x1, SvgParserLengthType::Horizontal), + LINE_DEF(y1, y1, SvgParserLengthType::Vertical), + LINE_DEF(x2, x2, SvgParserLengthType::Horizontal), + LINE_DEF(y2, y2, SvgParserLengthType::Vertical) +}; + + +/* parse the attributes for a rect element. + * https://www.w3.org/TR/SVG/shapes.html#LineElement + */ +static bool _attrParseLineNode(void* data, const char* key, const char* value) +{ + SvgLoaderData* loader = (SvgLoaderData*)data; + SvgNode* node = loader->svgParse->node; + SvgLineNode* line = &(node->node.line); + unsigned int i; + unsigned char* array; + int sz = strlen(key); + + array = (unsigned char*)line; + for (i = 0; i < sizeof(lineTags) / sizeof(lineTags[0]); i++) { + if (lineTags[i].sz - 1 == sz && !strncmp(lineTags[i].tag, key, sz)) { + *((float*)(array + lineTags[i].offset)) = _toFloat(loader->svgParse, value, lineTags[i].type); + return true; + } + } + + if (!strcmp(key, "id")) { + node->id = _copyId(value); + } else if (!strcmp(key, "style")) { + return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); + } else { + return _parseStyleAttr(loader, key, value); + } + return true; +} + + +static SvgNode* _createLineNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +{ + loader->svgParse->node = _createNode(parent, SvgNodeType::Line); + + simpleXmlParseAttributes(buf, bufLength, _attrParseLineNode, loader); + return loader->svgParse->node; +} + + +static string* _idFromHref(const char* href) +{ + href = _skipSpace(href, nullptr); + if ((*href) == '#') href++; + return new string(href); +} + + +static SvgNode* _getDefsNode(SvgNode* node) +{ + if (!node) return nullptr; + + while (node->parent != nullptr) { + node = node->parent; + } + + if (node->type == SvgNodeType::Doc) return node->node.doc.defs; + + return nullptr; +} + + +static SvgNode* _findChildById(SvgNode* node, const char* id) +{ + + if (!node) return nullptr; + + for (vector::iterator itrChild = node->child.begin(); itrChild != node->child.end(); itrChild++) { + if (((*itrChild)->id != nullptr) && !strcmp((*itrChild)->id->c_str(), id)) return *itrChild; + } + return nullptr; +} + + +static vector _cloneGradStops(vector src) +{ + vector dst; + copy(src.begin(), src.end(), dst.begin()); + return dst; +} + + +static SvgStyleGradient* _cloneGradient(SvgStyleGradient* from) +{ + SvgStyleGradient* grad; + + if (!from) return nullptr; + + grad = (SvgStyleGradient*)calloc(1, sizeof(SvgStyleGradient)); + grad->type = from->type; + grad->id = _copyId(from->id->c_str()); + grad->ref = _copyId(from->ref->c_str()); + grad->spread = from->spread; + grad->usePercentage = from->usePercentage; + grad->userSpace = from->userSpace; + if (from->transform) { + grad->transform = (Matrix*)calloc(1, sizeof(Matrix)); + memcpy(grad->transform, from->transform, sizeof(Matrix)); + } + grad->stops = _cloneGradStops(from->stops); + if (grad->type == SvgGradientType::Linear) { + grad->linear = (SvgLinearGradient*)calloc(1, sizeof(SvgLinearGradient)); + memcpy(grad->linear, from->linear, sizeof(SvgLinearGradient)); + } else if (grad->type == SvgGradientType::Radial) { + grad->radial = (SvgRadialGradient*)calloc(1, sizeof(SvgRadialGradient)); + memcpy(grad->radial, from->radial, sizeof(SvgRadialGradient)); + } + + return grad; +} + + +static void _copyAttr(SvgNode* to, SvgNode* from) +{ + //Copy matrix attribute + if (from->transform) { + to->transform = (Matrix*)calloc(1, sizeof(Matrix)); + memcpy(to->transform, from->transform, sizeof(Matrix)); + } + //Copy style attribute; + memcpy(to->style, from->style, sizeof(SvgStyleProperty)); + + //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; + 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: { + to->node.path.path = new string(from->node.path.path->c_str()); + break; + } + case SvgNodeType::Polygon: { + to->node.polygon.pointsCount = from->node.polygon.pointsCount; + to->node.polygon.points = (float*)calloc(to->node.polygon.pointsCount, sizeof(float)); + break; + } + case SvgNodeType::Polyline: { + to->node.polyline.pointsCount = from->node.polyline.pointsCount; + to->node.polyline.points = (float*)calloc(to->node.polyline.pointsCount, sizeof(float)); + break; + } + default: { + break; + } + } +} + + +static void _cloneNode(SvgNode* from, SvgNode* parent) +{ + SvgNode* newNode; + if (!from) return; + + newNode = _createNode(parent, from->type); + _copyAttr(newNode, from); + + for (vector::iterator itrChild = from->child.begin(); itrChild != from->child.end(); itrChild++) { + _cloneNode(*itrChild, newNode); + } +} + + +static bool _attrParseUseNode(void* data, const char* key, const char* value) +{ + SvgLoaderData* loader = (SvgLoaderData*)data; + SvgNode *defs, *nodeFrom, *node = loader->svgParse->node; + string* id; + + if (!strcmp(key, "xlink:href")) { + id = _idFromHref(value); + defs = _getDefsNode(node); + nodeFrom = _findChildById(defs, id->c_str()); + _cloneNode(nodeFrom, node); + delete id; + } else { + _attrParseGNode(data, key, value); + } + return true; +} + + +static SvgNode* _createUseNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength) +{ + loader->svgParse->node = _createNode(parent, SvgNodeType::G); + + simpleXmlParseAttributes(buf, bufLength, _attrParseUseNode, loader); + return loader->svgParse->node; +} + + +#define TAG_DEF(Name, Name1) \ + { \ +#Name, sizeof(#Name), _create##Name1##Node \ + } + + +//TODO: Implement 'text' primitive +static constexpr struct +{ + const char* tag; + int sz; + FactoryMethod tagHandler; +} graphicsTags[] = { + TAG_DEF(use, Use), + TAG_DEF(circle, Circle), + TAG_DEF(ellipse, Ellipse), + TAG_DEF(path, Path), + TAG_DEF(polygon, Polygon), + TAG_DEF(rect, Rect), + TAG_DEF(polyline, Polyline), + TAG_DEF(line, Line), +}; + + +static constexpr struct +{ + const char* tag; + int sz; + FactoryMethod tagHandler; +} groupTags[] = { + TAG_DEF(defs, Defs), + TAG_DEF(g, G), + TAG_DEF(svg, Svg), +}; + + +#define FIND_FACTORY(Short_Name, Tags_Array) \ + static FactoryMethod \ + _find##Short_Name##Factory(const char* name) \ + { \ + unsigned int i; \ + int sz = strlen(name); \ + \ + for (i = 0; i < sizeof(Tags_Array) / sizeof(Tags_Array[0]); i++) { \ + if (Tags_Array[i].sz - 1 == sz && !strncmp(Tags_Array[i].tag, name, sz)) { \ + return Tags_Array[i].tagHandler; \ + } \ + } \ + return nullptr; \ + } + +FIND_FACTORY(Group, groupTags); +FIND_FACTORY(Graphics, graphicsTags); + + +SvgGradientSpread _parseSpreadValue(const char* value) +{ + SvgGradientSpread spread = SvgGradientSpread::Pad; + + if (!strcmp(value, "reflect")) { + spread = SvgGradientSpread::Reflect; + } else if (!strcmp(value, "repeat")) { + spread = SvgGradientSpread::Repeat; + } + + return spread; +} + + +static void _handleRadialCxAttr(SvgLoaderData* loader, SvgRadialGradient* radial, const char* value) +{ + radial->cx = _gradientToFloat(loader->svgParse, value, SvgParserLengthType::Horizontal); + if (!loader->svgParse->gradient.parsedFx) radial->fx = radial->cx; +} + + +static void _handleRadialCyAttr(SvgLoaderData* loader, SvgRadialGradient* radial, const char* value) +{ + radial->cy = _gradientToFloat(loader->svgParse, value, SvgParserLengthType::Vertical); + if (!loader->svgParse->gradient.parsedFy) radial->fy = radial->cy; +} + + +static void _handleRadialFxAttr(SvgLoaderData* loader, SvgRadialGradient* radial, const char* value) +{ + radial->fx = _gradientToFloat(loader->svgParse, value, SvgParserLengthType::Horizontal); + loader->svgParse->gradient.parsedFx = true; +} + + +static void _handleRadialFyAttr(SvgLoaderData* loader, SvgRadialGradient* radial, const char* value) +{ + radial->fy = _gradientToFloat(loader->svgParse, value, SvgParserLengthType::Vertical); + loader->svgParse->gradient.parsedFy = true; +} + + +static void _handleRadialRAttr(SvgLoaderData* loader, SvgRadialGradient* radial, const char* value) +{ + radial->r = _gradientToFloat(loader->svgParse, value, SvgParserLengthType::Other); +} + + +static void _recalcRadialCxAttr(SvgLoaderData* loader, SvgRadialGradient* radial, bool userSpace) +{ + if (!userSpace) radial->cx = radial->cx * loader->svgParse->global.w; +} + + +static void _recalcRadialCyAttr(SvgLoaderData* loader, SvgRadialGradient* radial, bool userSpace) +{ + if (!userSpace) radial->cy = radial->cy * loader->svgParse->global.h; +} + + +static void _recalcRadialFxAttr(SvgLoaderData* loader, SvgRadialGradient* radial, bool userSpace) +{ + if (!userSpace) radial->fx = radial->fx * loader->svgParse->global.w; +} + + +static void _recalcRadialFyAttr(SvgLoaderData* loader, SvgRadialGradient* radial, bool userSpace) +{ + if (!userSpace) radial->fy = radial->fy * loader->svgParse->global.h; +} + + +static void _recalcRadialRAttr(SvgLoaderData* loader, SvgRadialGradient* radial, bool userSpace) +{ + if (!userSpace) radial->r = radial->r * (sqrt(pow(loader->svgParse->global.h, 2) + pow(loader->svgParse->global.w, 2)) / sqrt(2.0)); +} + + +typedef void (*radialMethod)(SvgLoaderData* loader, SvgRadialGradient* radial, const char* value); +typedef void (*radialMethodRecalc)(SvgLoaderData* loader, SvgRadialGradient* radial, bool userSpace); + + +#define RADIAL_DEF(Name, Name1) \ + { \ +#Name, sizeof(#Name), _handleRadial##Name1##Attr, _recalcRadial##Name1##Attr \ + } + + +static constexpr struct +{ + const char* tag; + int sz; + radialMethod tagHandler; + radialMethodRecalc tagRecalc; +} radialTags[] = { + RADIAL_DEF(cx, Cx), + RADIAL_DEF(cy, Cy), + RADIAL_DEF(fx, Fx), + RADIAL_DEF(fy, Fy), + RADIAL_DEF(r, R) +}; + + +static bool _attrParseRadialGradientNode(void* data, const char* key, const char* value) +{ + SvgLoaderData* loader = (SvgLoaderData*)data; + SvgStyleGradient* grad = loader->svgParse->styleGrad; + SvgRadialGradient* radial = grad->radial; + unsigned int i; + int sz = strlen(key); + + for (i = 0; i < sizeof(radialTags) / sizeof(radialTags[0]); i++) { + if (radialTags[i].sz - 1 == sz && !strncmp(radialTags[i].tag, key, sz)) { + radialTags[i].tagHandler(loader, radial, value); + return true; + } + } + + if (!strcmp(key, "id")) { + grad->id = _copyId(value); + } else if (!strcmp(key, "spreadMethod")) { + grad->spread = _parseSpreadValue(value); + } else if (!strcmp(key, "xlink:href")) { + grad->ref = _idFromHref(value); + } else if (!strcmp(key, "gradientUnits") && !strcmp(value, "userSpaceOnUse")) { + grad->userSpace = true; + } + + return true; +} + + +static SvgStyleGradient* _createRadialGradient(SvgLoaderData* loader, const char* buf, unsigned bufLength) +{ + unsigned int i = 0; + SvgStyleGradient* grad = (SvgStyleGradient*)calloc(1, sizeof(SvgStyleGradient)); + loader->svgParse->styleGrad = grad; + + grad->type = SvgGradientType::Radial; + grad->userSpace = false; + grad->radial = (SvgRadialGradient*)calloc(1, sizeof(SvgRadialGradient)); + /** + * Default values of gradient + */ + grad->radial->cx = 0.5; + grad->radial->cy = 0.5; + grad->radial->fx = 0.5; + grad->radial->fy = 0.5; + grad->radial->r = 0.5; + + loader->svgParse->gradient.parsedFx = false; + loader->svgParse->gradient.parsedFy = false; + simpleXmlParseAttributes(buf, bufLength, + _attrParseRadialGradientNode, loader); + + for (i = 0; i < sizeof(radialTags) / sizeof(radialTags[0]); i++) { + radialTags[i].tagRecalc(loader, grad->radial, grad->userSpace); + } + + grad->usePercentage = true; + + return loader->svgParse->styleGrad; +} + + +static bool _attrParseStops(void* data, const char* key, const char* value) +{ + SvgLoaderData* loader = (SvgLoaderData*)data; + SvgGradientStop* stop = loader->svgParse->gradStop; + + if (!strcmp(key, "offset")) { + stop->offset = _toOffset(value); + } else if (!strcmp(key, "stop-opacity")) { + stop->a = _toOpacity(value); + } else if (!strcmp(key, "stop-color")) { + _toColor(value, &stop->r, &stop->g, &stop->b, nullptr); + } else if (!strcmp(key, "style")) { + simpleXmlParseW3CAttribute(value, + _attrParseStops, data); + } + + return true; +} + + +static void _handleLinearX1Attr(SvgLoaderData* loader, SvgLinearGradient* linear, const char* value) +{ + linear->x1 = _gradientToFloat(loader->svgParse, value, SvgParserLengthType::Horizontal); +} + + +static void _handleLinearY1Attr(SvgLoaderData* loader, SvgLinearGradient* linear, const char* value) +{ + linear->y1 = _gradientToFloat(loader->svgParse, value, SvgParserLengthType::Vertical); +} + + +static void _handleLinearX2Attr(SvgLoaderData* loader, SvgLinearGradient* linear, const char* value) +{ + linear->x2 = _gradientToFloat(loader->svgParse, value, SvgParserLengthType::Horizontal); +} + + +static void _handleLinearY2Attr(SvgLoaderData* loader, SvgLinearGradient* linear, const char* value) +{ + linear->y2 = _gradientToFloat(loader->svgParse, value, SvgParserLengthType::Vertical); +} + + +static void _recalcLinearX1Attr(SvgLoaderData* loader, SvgLinearGradient* linear, bool userSpace) +{ + if (!userSpace) linear->x1 = linear->x1 * loader->svgParse->global.w; +} + + +static void _recalcLinearY1Attr(SvgLoaderData* loader, SvgLinearGradient* linear, bool userSpace) +{ + if (!userSpace) linear->y1 = linear->y1 * loader->svgParse->global.h; +} + + +static void _recalcLinearX2Attr(SvgLoaderData* loader, SvgLinearGradient* linear, bool userSpace) +{ + if (!userSpace) linear->x2 = linear->x2 * loader->svgParse->global.w; +} + + +static void _recalcLinearY2Attr(SvgLoaderData* loader, SvgLinearGradient* linear, bool userSpace) +{ + if (!userSpace) linear->y2 = linear->y2 * loader->svgParse->global.h; +} + + +typedef void (*Linear_Method)(SvgLoaderData* loader, SvgLinearGradient* linear, const char* value); +typedef void (*Linear_Method_Recalc)(SvgLoaderData* loader, SvgLinearGradient* linear, bool userSpace); + + +#define LINEAR_DEF(Name, Name1) \ + { \ +#Name, sizeof(#Name), _handleLinear##Name1##Attr, _recalcLinear##Name1##Attr \ + } + + +static constexpr struct +{ + const char* tag; + int sz; + Linear_Method tagHandler; + Linear_Method_Recalc tagRecalc; +} linear_tags[] = { + LINEAR_DEF(x1, X1), + LINEAR_DEF(y1, Y1), + LINEAR_DEF(x2, X2), + LINEAR_DEF(y2, Y2) +}; + + +static bool _attrParseLinearGradientNode(void* data, const char* key, const char* value) +{ + SvgLoaderData* loader = (SvgLoaderData*)data; + SvgStyleGradient* grad = loader->svgParse->styleGrad; + SvgLinearGradient* linear = grad->linear; + unsigned int i; + int sz = strlen(key); + + for (i = 0; i < sizeof(linear_tags) / sizeof(linear_tags[0]); i++) { + if (linear_tags[i].sz - 1 == sz && !strncmp(linear_tags[i].tag, key, sz)) { + linear_tags[i].tagHandler(loader, linear, value); + return true; + } + } + + if (!strcmp(key, "id")) { + grad->id = _copyId(value); + } else if (!strcmp(key, "spreadMethod")) { + grad->spread = _parseSpreadValue(value); + } else if (!strcmp(key, "xlink:href")) { + grad->ref = _idFromHref(value); + } else if (!strcmp(key, "gradientUnits") && !strcmp(value, "userSpaceOnUse")) { + grad->userSpace = true; + } else if (!strcmp(key, "gradientTransform")) { + grad->transform = _parseTransformationMatrix(value); + } + + return true; +} + + +static SvgStyleGradient* _createLinearGradient(SvgLoaderData* loader, const char* buf, unsigned bufLength) +{ + SvgStyleGradient* grad = (SvgStyleGradient*)calloc(1, sizeof(SvgStyleGradient)); + loader->svgParse->styleGrad = grad; + unsigned int i; + + grad->type = SvgGradientType::Linear; + grad->userSpace = false; + grad->linear = (SvgLinearGradient*)calloc(1, sizeof(SvgLinearGradient)); + /** + * Default value of x2 is 100% + */ + grad->linear->x2 = 1; + simpleXmlParseAttributes(buf, bufLength, _attrParseLinearGradientNode, loader); + + for (i = 0; i < sizeof(linear_tags) / sizeof(linear_tags[0]); i++) { + linear_tags[i].tagRecalc(loader, grad->linear, grad->userSpace); + } + + grad->usePercentage = true; + + return loader->svgParse->styleGrad; +} + + +#define GRADIENT_DEF(Name, Name1) \ + { \ +#Name, sizeof(#Name), _create##Name1 \ + } + + +/** + * For all Gradients lengths would be calculated into percentages related to + * canvas width and height. + * + * if user then recalculate actual pixels into percentages + */ +static constexpr struct +{ + const char* tag; + int sz; + GradientFactoryMethod tagHandler; +} gradientTags[] = { + GRADIENT_DEF(linearGradient, LinearGradient), + GRADIENT_DEF(radialGradient, RadialGradient) +}; + + +static GradientFactoryMethod _findGradientFactory(const char* name) +{ + unsigned int i; + int sz = strlen(name); + + for (i = 0; i < sizeof(gradientTags) / sizeof(gradientTags[0]); i++) { + if (gradientTags[i].sz - 1 == sz && !strncmp(gradientTags[i].tag, name, sz)) { + return gradientTags[i].tagHandler; + } + } + return nullptr; +} + + +#define POP_TAG(Tag) \ + { \ +#Tag, sizeof(#Tag) \ + } + + +static constexpr struct +{ + const char* tag; + size_t sz; +} popArray[] = { + POP_TAG(g), + POP_TAG(svg), + POP_TAG(defs) +}; + + +static void _svgLoaderParerXmlClose(SvgLoaderData* loader, const char* content, unsigned int length) +{ + unsigned int i; + + content = _skipSpace(content, nullptr); + + for (i = 0; i < sizeof(popArray) / sizeof(popArray[0]); i++) { + if (!strncmp(content, popArray[i].tag, popArray[i].sz - 1)) { + loader->stack.pop_back(); + break; + } + } + + loader->level--; +} + + +static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content, unsigned int length) +{ + const char* attrs = nullptr; + int attrsLength = 0; + int sz = length; + char tagName[20] = ""; + FactoryMethod method; + GradientFactoryMethod gradientMethod; + SvgNode *node = nullptr, *parent = nullptr; + loader->level++; + attrs = simpleXmlFindAttributesTag(content, length); + + if (!attrs) { + //Parse the empty tag + attrs = content; + while ((attrs != nullptr) && *attrs != '>') attrs++; + } + + if (attrs) { + //Find out the tag name starting from content till sz length + sz = attrs - content; + attrsLength = length - sz; + while ((sz > 0) && (isspace(content[sz - 1]))) sz--; + strncpy(tagName, content, sz); + tagName[sz] = '\0'; + } + + if ((method = _findGroupFactory(tagName))) { + //Group + if (!loader->doc) { + if (strcmp(tagName, "svg")) return; //Not a valid svg document + node = method(loader, nullptr, attrs, attrsLength); + loader->doc = node; + } else { + if (loader->stack.size() > 0) parent = loader->stack.at(loader->stack.size() - 1); + node = method(loader, parent, attrs, attrsLength); + } + loader->stack.push_back(node); + + if (node->type == SvgNodeType::Defs) { + loader->doc->node.doc.defs = node; + loader->def = node; + } + } else if ((method = _findGraphicsFactory(tagName))) { + parent = loader->stack.at(loader->stack.size() - 1); + node = method(loader, parent, attrs, attrsLength); + } else if ((gradientMethod = _findGradientFactory(tagName))) { + SvgStyleGradient* gradient; + gradient = gradientMethod(loader, attrs, attrsLength); + //FIXME: The current parsing structure does not distinguish end tags. + // There is no way to know if the currently parsed gradient is in defs. + // If a gradient is declared outside of defs after defs is set, it is included in the gradients of defs. + // But finally, the loader has a gradient style list regardless of defs. + // This is only to support this when multiple gradients are declared, even if no defs are declared. + // refer to: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/defs + if (loader->doc->node.doc.defs) { + loader->def->node.defs.gradients.push_back(gradient); + } else { + loader->gradients.push_back(gradient); + } + loader->latestGradient = gradient; + } else if (!strcmp(tagName, "stop")) { + SvgGradientStop* stop = (SvgGradientStop*)calloc(1, sizeof(SvgGradientStop)); + loader->svgParse->gradStop = stop; + /* default value for opacity */ + stop->a = 255; + simpleXmlParseAttributes(attrs, attrsLength, _attrParseStops, loader); + if (loader->latestGradient) { + loader->latestGradient->stops.push_back(stop); + } + } +} + + +static bool _svgLoaderParser(void* data, SimpleXMLType type, const char* content, unsigned int offset, unsigned int length) +{ + SvgLoaderData* loader = (SvgLoaderData*)data; + + switch (type) { + case SimpleXMLType::Open: { + _svgLoaderParserXmlOpen(loader, content, length); + break; + } + case SimpleXMLType::OpenEmpty: { + _svgLoaderParserXmlOpen(loader, content, length); + break; + } + case SimpleXMLType::Close: { + _svgLoaderParerXmlClose(loader, content, length); + break; + } + case SimpleXMLType::Data: + case SimpleXMLType::CData: + case SimpleXMLType::DoctypeChild: { + break; + } + case SimpleXMLType::Ignored: + case SimpleXMLType::Comment: + case SimpleXMLType::Doctype: { + break; + } + default: { + break; + } + } + + return true; +} + + +static void _styleInherit(SvgStyleProperty* child, SvgStyleProperty* parent) +{ + if (parent == nullptr) return; + //Inherit the property of parent if not present in child. + //Fill + if (!((int)child->fill.flags & (int)SvgFillFlags::Paint)) { + child->fill.paint.r = parent->fill.paint.r; + child->fill.paint.g = parent->fill.paint.g; + child->fill.paint.b = parent->fill.paint.b; + child->fill.paint.none = parent->fill.paint.none; + child->fill.paint.curColor = parent->fill.paint.curColor; + child->fill.paint.url = parent->fill.paint.url ? _copyId(parent->fill.paint.url->c_str()) : nullptr; + } + if (!((int)child->fill.flags & (int)SvgFillFlags::Opacity)) { + child->fill.opacity = parent->fill.opacity; + } + if (!((int)child->fill.flags & (int)SvgFillFlags::FillRule)) { + child->fill.fillRule = parent->fill.fillRule; + } + //Stroke + if (!((int)child->stroke.flags & (int)SvgStrokeFlags::Paint)) { + child->stroke.paint.r = parent->stroke.paint.r; + child->stroke.paint.g = parent->stroke.paint.g; + child->stroke.paint.b = parent->stroke.paint.b; + 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->c_str()) : nullptr; + } + if (!((int)child->stroke.flags & (int)SvgStrokeFlags::Opacity)) { + child->stroke.opacity = parent->stroke.opacity; + } + if (!((int)child->stroke.flags & (int)SvgStrokeFlags::Width)) { + child->stroke.width = parent->stroke.width; + } + if (!((int)child->stroke.flags & (int)SvgStrokeFlags::Cap)) { + child->stroke.cap = parent->stroke.cap; + } + if (!((int)child->stroke.flags & (int)SvgStrokeFlags::Join)) { + child->stroke.join = parent->stroke.join; + } +} + + +static void _updateStyle(SvgNode* node, SvgStyleProperty* parentStyle) +{ + _styleInherit(node->style, parentStyle); + + for (vector::iterator itrChild = node->child.begin(); itrChild != node->child.end(); itrChild++) { + _updateStyle(*itrChild, node->style); + } +} + + +static SvgStyleGradient* _gradientDup(vector gradList, const char* id) +{ + SvgStyleGradient* result = nullptr; + + for (vector::iterator itrGrad = gradList.begin(); itrGrad != gradList.end(); itrGrad++) { + if ((*itrGrad)->id->compare(string(id))) { + result = _cloneGradient(*itrGrad); + break; + } + } + + if (result && result->ref) { + for (vector::iterator itrGrad = gradList.begin(); itrGrad != gradList.end(); itrGrad++) { + if ((*itrGrad)->id->compare(*result->ref)) { + if (!result->stops.empty()) { + result->stops = _cloneGradStops((*itrGrad)->stops); + } + //TODO: Properly inherit other property + break; + } + } + } + + return result; +} + + +static void _updateGradient(SvgNode* node, vector gradList) +{ + if (node->child.empty()) { + for (vector::iterator itrChild = node->child.begin(); itrChild != node->child.end(); itrChild++) { + _updateGradient(*itrChild, gradList); + } + } else { + if (node->style->fill.paint.url) { + node->style->fill.paint.gradient = _gradientDup(gradList, node->style->fill.paint.url->c_str()); + } else if (node->style->stroke.paint.url) { + node->style->stroke.paint.gradient = _gradientDup(gradList, node->style->stroke.paint.url->c_str()); + } + } +} + +static void _freeGradientStyle(SvgStyleGradient* grad) +{ + if (!grad) return; + + delete grad->id; + delete grad->ref; + free(grad->radial); + free(grad->linear); + if (grad->transform) free(grad->transform); + + for(vector::iterator itrStop = grad->stops.begin(); itrStop != grad->stops.end(); itrStop++) { + free(*itrStop); + } + free(grad); +} + +static void _freeNodeStyle(SvgStyleProperty* style) +{ + if (!style) return; + + _freeGradientStyle(style->fill.paint.gradient); + delete style->fill.paint.url; + _freeGradientStyle(style->stroke.paint.gradient); + delete style->stroke.paint.url; + free(style); +} + +static void _freeSvgNode(SvgNode* node) +{ + if (!node) return; + + for(vector::iterator itrChild = node->child.begin(); itrChild != node->child.end(); itrChild++) { + _freeSvgNode(*itrChild); + } + node->child.clear(); + + delete node->id; + free(node->transform); + _freeNodeStyle(node->style); + switch (node->type) { + case SvgNodeType::Path: { + delete node->node.path.path; + break; + } + case SvgNodeType::Polygon: { + free(node->node.polygon.points); + break; + } + case SvgNodeType::Polyline: { + free(node->node.polyline.points); + break; + } + case SvgNodeType::Doc: { + _freeSvgNode(node->node.doc.defs); + break; + } + case SvgNodeType::Defs: { + for(vector::iterator itrGrad = node->node.defs.gradients.begin(); itrGrad != node->node.defs.gradients.end(); itrGrad++) { + _freeGradientStyle(*itrGrad); + } + break; + } + default: { + break; + } + } + if (!node->child.empty()) node->child.clear(); + free(node); +} /************************************************************************/ /* External Class Implementation */ /************************************************************************/ + SvgLoader::SvgLoader() { - cout << "SvgLoader()" << endl; } SvgLoader::~SvgLoader() { - cout << "~SvgLoader()" << endl; } bool SvgLoader::open(const char* path) { - //TODO: - cout << "SvgLoader::open()" << endl; + ifstream f; + f.open(path); - return false; + if (!f.is_open()) + { + cout << "ERROR: Failed to open file = " << path; + return false; + } else { + getline(f, content, '\0'); + f.close(); + + if (content.empty()) return false; + } + + return true; } bool SvgLoader::read() { - //TODO: - cout << "SvgLoader::read()" << endl; + if (content.empty()) return false; - return false; + loaderData = {vector(), + nullptr, + nullptr, + vector(), + nullptr, + nullptr, + 0, + false}; + + loaderData.svgParse = (SvgParser*)malloc(sizeof(SvgParser)); + + bool res = simpleXmlParse(content.c_str(), content.size(), true, _svgLoaderParser, &loaderData); + + if (loaderData.doc) { + SvgNode *defs; + _updateStyle(loaderData.doc, nullptr); + defs = loaderData.doc->node.doc.defs; + if (defs) _updateGradient(loaderData.doc, defs->node.defs.gradients); + else { + if (!loaderData.gradients.empty()) { + vector gradientList; + std::copy(loaderData.gradients.begin(), loaderData.gradients.end(), gradientList.begin()); + _updateGradient(loaderData.doc, gradientList); + gradientList.clear(); + } + } + } + + if (!res) return false; + return true; } bool SvgLoader::close() { - //TODO: - cout << "SvgLoader::close()" << endl; - + if (loaderData.svgParse) free(loaderData.svgParse); + _freeSvgNode(loaderData.doc); return false; } unique_ptr SvgLoader::data() { - //TODO: - cout << "SvgLoader::data()" << endl; - return nullptr; } -#endif //_TVG_SVG_LOADER_CPP_ \ No newline at end of file +#endif //_TVG_SVG_LOADER_CPP_ diff --git a/src/loaders/svg_loader/tvgSvgLoader.h b/src/loaders/svg_loader/tvgSvgLoader.h index 2b4d8b1..13441f3 100644 --- a/src/loaders/svg_loader/tvgSvgLoader.h +++ b/src/loaders/svg_loader/tvgSvgLoader.h @@ -17,12 +17,13 @@ #ifndef _TVG_SVG_LOADER_H_ #define _TVG_SVG_LOADER_H_ -#include "tvgCommon.h" +#include "tvgSvgLoaderCommon.h" class SvgLoader : public Loader { private: - //TODO: + string content; + SvgLoaderData loaderData; public: SvgLoader(); @@ -35,4 +36,4 @@ public: }; -#endif //_TVG_SVG_LOADER_H_ \ No newline at end of file +#endif //_TVG_SVG_LOADER_H_ diff --git a/src/loaders/svg_loader/tvgSvgLoaderCommon.h b/src/loaders/svg_loader/tvgSvgLoaderCommon.h new file mode 100644 index 0000000..a909e54 --- /dev/null +++ b/src/loaders/svg_loader/tvgSvgLoaderCommon.h @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _TVG_SVG_LOADER_COMMON_H_ +#define _TVG_SVG_LOADER_COMMON_H_ + +#include "tvgCommon.h" +#include "tvgSimpleXmlParser.h" + +enum class SvgNodeType +{ + Doc, + G, + Defs, + //Switch, //Not support + Animation, + Arc, + Circle, + Ellipse, + Image, + Line, + Path, + Polygon, + Polyline, + Rect, + Text, + TextArea, + Tspan, + Use, + Video, + //Custome_command, //Not support + Unknown +}; + +enum class SvgLengthType +{ + Percent, + Px, + Pc, + Pt, + Mm, + Cm, + In, +}; + +enum class SvgFillFlags +{ + Paint = 0x1, + Opacity = 0x2, + Gradient = 0x4, + FillRule = 0x8 +}; + +enum class SvgStrokeFlags +{ + Paint = 0x1, + Opacity = 0x2, + Gradient = 0x4, + Scale = 0x8, + Width = 0x10, + Cap = 0x20, + Join = 0x40, + Dash = 0x80, +}; + +enum class SvgGradientType +{ + Linear, + Radial +}; + +enum class SvgStyleType +{ + Quality, + Fill, + ViewportFill, + Font, + Stroke, + SolidColor, + Gradient, + Transform, + Opacity, + CompOp +}; + +enum class SvgGradientSpread +{ + Pad = 0, + Reflect, + Repeat, + Last +}; + +enum class SvgFillRule +{ + Winding = 0, + OddEven = 1 +}; + +//Length type to recalculate %, pt, pc, mm, cm etc +enum class SvgParserLengthType +{ + Vertical, + Horizontal, + //In case of, for example, radius of radial gradient + Other +}; + +typedef struct _SvgNode SvgNode; +typedef struct _SvgStyleGradient SvgStyleGradient; + +struct SvgDocNode +{ + float w; + float h; + float vx; + float vy; + float vw; + float vh; + SvgNode* defs; + bool preserveAspect; +}; + +struct SvgGNode +{ +}; + +struct SvgDefsNode +{ + vector gradients; +}; + +struct SvgArcNode +{ +}; + +struct SvgEllipseNode +{ + float cx; + float cy; + float rx; + float ry; +}; + +struct SvgCircleNode +{ + float cx; + float cy; + float r; +}; + +struct SvgRectNode +{ + float x; + float y; + float w; + float h; + float rx; + float ry; +}; + +struct SvgLineNode +{ + float x1; + float y1; + float x2; + float y2; +}; + +struct SvgPathNode +{ + string* path; +}; + +struct SvgPolygonNode +{ + int pointsCount; + float* points; +}; + +struct SvgLinearGradient +{ + float x1; + float y1; + float x2; + float y2; +}; + +struct SvgRadialGradient +{ + float cx; + float cy; + float fx; + float fy; + float r; +}; + +struct SvgGradientStop +{ + float offset; + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; +}; + +struct SvgPaint +{ + SvgStyleGradient* gradient; + string* url; + uint8_t r; + uint8_t g; + uint8_t b; + bool none; + bool curColor; +}; + +struct SvgDash +{ + float length; + float gap; +}; + +struct _SvgStyleGradient +{ + SvgGradientType type; + string* id; + string* ref; + SvgGradientSpread spread; + vector stops; + SvgRadialGradient* radial; + SvgLinearGradient* linear; + Matrix* transform; + bool userSpace; + bool usePercentage; +}; + +struct SvgStyleFill +{ + SvgFillFlags flags; + SvgPaint paint; + int opacity; + SvgFillRule fillRule; +}; + +struct SvgStyleStroke +{ + SvgStrokeFlags flags; + SvgPaint paint; + int opacity; + float scale; + float width; + float centered; + StrokeCap cap; + StrokeJoin join; + SvgDash* dash; + int dashCount; +}; + +struct SvgStyleProperty +{ + SvgStyleFill fill; + SvgStyleStroke stroke; + int opacity; + uint8_t r; + uint8_t g; + uint8_t b; +}; + +struct _SvgNode +{ + SvgNodeType type; + SvgNode* parent; + vector child; + string* id; + SvgStyleProperty* style; + Matrix* transform; + union { + SvgGNode g; + SvgDocNode doc; + SvgDefsNode defs; + SvgArcNode arc; + SvgCircleNode circle; + SvgEllipseNode ellipse; + SvgPolygonNode polygon; + SvgPolygonNode polyline; + SvgRectNode rect; + SvgPathNode path; + SvgLineNode line; + } node; + bool display; +}; + +struct SvgParser +{ + SvgNode* node; + SvgStyleGradient* styleGrad; + SvgGradientStop* gradStop; + struct + { + int x, y; + uint32_t w, h; + } global; + struct + { + bool parsedFx; + bool parsedFy; + } gradient; +}; + +struct SvgLoaderData +{ + vector stack; + SvgNode* doc; + SvgNode* def; + vector gradients; + SvgStyleGradient* latestGradient; //For stops + SvgParser* svgParse; + int level; + bool result; +}; + +#endif -- 2.7.4 From ac3c46cf363a6a4e45494baea30e686b6a034ccb Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 29 Jun 2020 16:16:01 +0900 Subject: [PATCH 05/16] updated AUTHORS Change-Id: Ife45b8ec1ad39822491e57b6031927a42f6a113b --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index bcfd4d6..3e778fe 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,2 +1,3 @@ Hermet Park Prudhvi Raj Vasireddi +Junsu Choi -- 2.7.4 From e9d6bd7833232e754d751cb7fcaf5407eb5a1295 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Wed, 24 Jun 2020 19:35:40 +0900 Subject: [PATCH 06/16] SvgLoader: Implement SvgSceneBuilder using SvgNode SvgSceneBuilder builds Scene using SvgNode tree. build(root node) function return the root scene. Following SVG tags are supported. Polygon, Polyline, Circle, Rect, Line Change-Id: I8c9b8c28d9a4799af6ddc45c35f77a75f696b2a5 --- src/loaders/svg_loader/meson.build | 2 + src/loaders/svg_loader/tvgSvgLoader.cpp | 4 +- src/loaders/svg_loader/tvgSvgLoader.h | 4 + src/loaders/svg_loader/tvgSvgSceneBuilder.cpp | 188 ++++++++++++++++++++++++++ src/loaders/svg_loader/tvgSvgSceneBuilder.h | 42 ++++++ 5 files changed, 239 insertions(+), 1 deletion(-) create mode 100644 src/loaders/svg_loader/tvgSvgSceneBuilder.cpp create mode 100644 src/loaders/svg_loader/tvgSvgSceneBuilder.h diff --git a/src/loaders/svg_loader/meson.build b/src/loaders/svg_loader/meson.build index 88fd37a..21967af 100644 --- a/src/loaders/svg_loader/meson.build +++ b/src/loaders/svg_loader/meson.build @@ -2,8 +2,10 @@ source_file = [ 'tvgSimpleXmlParser.h', 'tvgSvgLoader.h', 'tvgSvgLoaderCommon.h', + 'tvgSvgSceneBuilder.h', 'tvgSimpleXmlParser.cpp', 'tvgSvgLoader.cpp', + 'tvgSvgSceneBuilder.cpp', ] svgloader_dep = declare_dependency( diff --git a/src/loaders/svg_loader/tvgSvgLoader.cpp b/src/loaders/svg_loader/tvgSvgLoader.cpp index 4db8200..4dd5fd4 100644 --- a/src/loaders/svg_loader/tvgSvgLoader.cpp +++ b/src/loaders/svg_loader/tvgSvgLoader.cpp @@ -2289,6 +2289,8 @@ bool SvgLoader::read() } } + root = builder.build(loaderData.doc); + if (!res) return false; return true; } @@ -2304,7 +2306,7 @@ bool SvgLoader::close() unique_ptr SvgLoader::data() { - return nullptr; + return move(root); } #endif //_TVG_SVG_LOADER_CPP_ diff --git a/src/loaders/svg_loader/tvgSvgLoader.h b/src/loaders/svg_loader/tvgSvgLoader.h index 13441f3..eba74c3 100644 --- a/src/loaders/svg_loader/tvgSvgLoader.h +++ b/src/loaders/svg_loader/tvgSvgLoader.h @@ -18,12 +18,16 @@ #define _TVG_SVG_LOADER_H_ #include "tvgSvgLoaderCommon.h" +#include "tvgSvgSceneBuilder.h" + class SvgLoader : public Loader { private: string content; SvgLoaderData loaderData; + SvgSceneBuilder builder; + unique_ptr root; public: SvgLoader(); diff --git a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp new file mode 100644 index 0000000..601ed0c --- /dev/null +++ b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef _TVG_SVG_SCENE_BUILDER_CPP_ +#define _TVG_SVG_SCENE_BUILDER_CPP_ + + +#include "tvgSvgSceneBuilder.h" + + +unique_ptr _applyProperty(SvgNode* node, unique_ptr vg) +{ + SvgStyleProperty* style = node->style; + + //Apply the transformation + if (node->transform) vg->transform(*node->transform); + + if (node->type == SvgNodeType::Doc) return vg; + + //If fill property is nullptr then do nothing + if (style->fill.paint.none) { + //Do nothing + } else if (style->fill.paint.gradient) { + //TODO: Support gradient style + } else if (style->fill.paint.curColor) { + //Apply the current style color + float fa = ((float)style->fill.opacity / 255.0); + vg->fill(((float)style->r) * fa, ((float)style->g) * fa, ((float)style->b) * fa, style->fill.opacity); + } else { + //Apply the fill color + float fa = ((float)style->fill.opacity / 255.0); + vg->fill(((float)style->fill.paint.r) * fa, ((float)style->fill.paint.g) * fa, ((float)style->fill.paint.b) * fa, style->fill.opacity); + } + + //Apply node opacity + if (style->opacity < 255) { + uint8_t r, g, b, a; + vg->fill(&r, &g, &b, &a); + float fa = ((float)style->opacity / 255.0); + vg->fill(((float)r) * fa, ((float)g) * fa, ((float)b) * fa, ((float)a) * fa); + } + + if (node->type == SvgNodeType::G) return vg; + + //Apply the stroke style property + vg->stroke(style->stroke.width); + vg->stroke(style->stroke.cap); + vg->stroke(style->stroke.join); + + + //If stroke property is nullptr then do nothing + if (style->stroke.paint.none) { + //Do nothing + } else if (style->stroke.paint.gradient) { + //TODO: Support gradient style + } else if (style->stroke.paint.url) { + //TODO: Apply the color pointed by url + } else if (style->stroke.paint.curColor) { + //Apply the current style color + vg->stroke(style->r, style->g, style->b, style->stroke.opacity); + + } else { + //Apply the stroke color + vg->stroke(style->stroke.paint.r, style->stroke.paint.g, style->stroke.paint.b, style->stroke.opacity); + } + + //Apply node opacity to stroke color + if (style->opacity < 255) { + uint8_t r, g, b, a; + vg->strokeColor(&r, &g, &b, &a); + float fa = ((float)style->opacity / 255.0); + vg->stroke(((float)r) * fa, ((float)g) * fa, ((float)b) * fa, ((float)a) * fa); + } + return vg; +} + + +unique_ptr _shapeBuildHelper(SvgNode* node) +{ + auto shape = tvg::Shape::gen(); + switch (node->type) { + case SvgNodeType::Path: { + //TODO: Support path + break; + } + case SvgNodeType::Ellipse: { + //TODO: Support ellipse + break; + } + case SvgNodeType::Polygon: { + if (node->node.polygon.pointsCount < 2) break; + shape->moveTo(node->node.polygon.points[0], node->node.polygon.points[1]); + for (int i = 2; i < node->node.polygon.pointsCount; i += 2) { + shape->lineTo(node->node.polygon.points[i], node->node.polygon.points[i + 1]); + } + shape->close(); + break; + } + case SvgNodeType::Polyline: { + if (node->node.polygon.pointsCount < 2) break; + shape->moveTo(node->node.polygon.points[0], node->node.polygon.points[1]); + for (int i = 2; i < node->node.polygon.pointsCount; i += 2) { + shape->lineTo(node->node.polygon.points[i], node->node.polygon.points[i + 1]); + } + break; + } + case SvgNodeType::Circle: { + shape->appendCircle(node->node.circle.cx, node->node.circle.cy, node->node.circle.r, node->node.circle.r); + break; + } + case SvgNodeType::Rect: { + if (node->node.rect.rx == node->node.rect.ry) { + shape->appendRect(node->node.rect.x, node->node.rect.y, node->node.rect.w, node->node.rect.h, node->node.rect.rx); + } + else { + //TODO: Support rounded rectangle + } + break; + } + case SvgNodeType::Line: { + shape->moveTo(node->node.line.x1, node->node.line.y1); + shape->lineTo(node->node.line.x2, node->node.line.y2); + break; + } + default: { + break; + } + } + shape = move(_applyProperty(node, move(shape))); + return shape; +} + + +unique_ptr _sceneBuildHelper(SvgNode* node) +{ + if (node->type == SvgNodeType::Doc || node->type == SvgNodeType::G) { + auto scene = tvg::Scene::gen(); + if (node->transform) scene->transform(*node->transform); + + for (vector::iterator itrChild = node->child.begin(); itrChild != node->child.end(); itrChild++) { + SvgNode* child = *itrChild; + if (child->type == SvgNodeType::Doc || child->type == SvgNodeType::G) scene->push(_sceneBuildHelper(*itrChild)); + else scene->push(_shapeBuildHelper(*itrChild)); + } + return move(scene); + } + return nullptr; +} + + +SvgSceneBuilder::SvgSceneBuilder() +{ +} + + +SvgSceneBuilder::~SvgSceneBuilder() +{ +} + + +unique_ptr SvgSceneBuilder::build(SvgNode* node) +{ + if (!node || (node->type != SvgNodeType::Doc)) return nullptr; + + viewBox.x = node->node.doc.vx; + viewBox.y = node->node.doc.vy; + viewBox.w = node->node.doc.vw; + viewBox.h = node->node.doc.vh; + preserveAspect = node->node.doc.preserveAspect; + staticViewBox = true; + return _sceneBuildHelper(node); +} + + +#endif //_TVG_SVG_SCENE_BUILDER_CPP_ diff --git a/src/loaders/svg_loader/tvgSvgSceneBuilder.h b/src/loaders/svg_loader/tvgSvgSceneBuilder.h new file mode 100644 index 0000000..20a41a7 --- /dev/null +++ b/src/loaders/svg_loader/tvgSvgSceneBuilder.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef _TVG_SVG_SCENE_BUILDER_H_ +#define _TVG_SVG_SCENE_BUILDER_H_ + +#include "tvgSvgLoaderCommon.h" + +class SvgSceneBuilder +{ +private: + struct { + int x, y; + uint32_t w, h; + } viewBox; + int ref; + uint32_t w, h; //Default size + bool staticViewBox; + bool preserveAspect; //Used in SVG + bool shareable; + +public: + SvgSceneBuilder(); + ~SvgSceneBuilder(); + + unique_ptr build(SvgNode* node); +}; + +#endif //_TVG_SVG_SCENE_BUILDER_H_ -- 2.7.4 From 3fe2eedd897faed9e7ce259e44418c2e404a8225 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Fri, 26 Jun 2020 18:51:36 +0900 Subject: [PATCH 07/16] SvgLoader: Implement svgpath draw Convert Svg path in string to tvg::PathCommand. Draw converted data by adding it as path to shape. Following tags are supported. Move, Line, Cubic, SCubic, Vertical, Horizontal and Close. Change-Id: I3cb31e05bcb233b4c187e0c9e7eef8cdadf84695 --- src/loaders/svg_loader/meson.build | 2 + src/loaders/svg_loader/tvgSvgPath.cpp | 297 ++++++++++++++++++++++++++ src/loaders/svg_loader/tvgSvgPath.h | 8 + src/loaders/svg_loader/tvgSvgSceneBuilder.cpp | 5 +- src/loaders/svg_loader/tvgSvgSceneBuilder.h | 1 + 5 files changed, 312 insertions(+), 1 deletion(-) create mode 100644 src/loaders/svg_loader/tvgSvgPath.cpp create mode 100644 src/loaders/svg_loader/tvgSvgPath.h diff --git a/src/loaders/svg_loader/meson.build b/src/loaders/svg_loader/meson.build index 21967af..de7adf7 100644 --- a/src/loaders/svg_loader/meson.build +++ b/src/loaders/svg_loader/meson.build @@ -2,9 +2,11 @@ source_file = [ 'tvgSimpleXmlParser.h', 'tvgSvgLoader.h', 'tvgSvgLoaderCommon.h', + 'tvgSvgPath.h', 'tvgSvgSceneBuilder.h', 'tvgSimpleXmlParser.cpp', 'tvgSvgLoader.cpp', + 'tvgSvgPath.cpp', 'tvgSvgSceneBuilder.cpp', ] diff --git a/src/loaders/svg_loader/tvgSvgPath.cpp b/src/loaders/svg_loader/tvgSvgPath.cpp new file mode 100644 index 0000000..70058e0 --- /dev/null +++ b/src/loaders/svg_loader/tvgSvgPath.cpp @@ -0,0 +1,297 @@ +#ifndef __TVG_SVG_PATH_CPP_ +#define __TVG_SVG_PATH_CPP_ + +#include "tvgSvgPath.h" + + +static char* _skipComma(const char* content) +{ + while (*content && isspace(*content)) { + content++; + } + if (*content == ',') return (char*)content + 1; + return (char*)content; +} + + +static inline bool _parseNumber(char** content, float* number) +{ + char* end = NULL; + *number = strtof(*content, &end); + //If the start of string is not number + if ((*content) == end) return false; + //Skip comma if any + *content = _skipComma(end); + return true; +} + + +static inline bool _parseLong(char** content, int* number) +{ + char* end = NULL; + *number = strtol(*content, &end, 10) ? 1 : 0; + //If the start of string is not number + if ((*content) == end) return false; + *content = _skipComma(end); + return true; +} + + +static int _numberCount(char cmd) +{ + int count = 0; + switch (cmd) { + case 'M': + case 'm': + case 'L': + case 'l': { + count = 2; + break; + } + case 'C': + case 'c': + case 'E': + case 'e': { + count = 6; + break; + } + case 'H': + case 'h': + case 'V': + case 'v': { + count = 1; + break; + } + case 'S': + case 's': + case 'Q': + case 'q': + case 'T': + case 't': { + count = 4; + break; + } + case 'A': + case 'a': { + count = 7; + break; + } + default: + break; + } + return count; +} + + +static void _processCommand(vector* cmds, vector* pts, char cmd, float* arr, int count, Point* cur, Point* curCtl) +{ + int i; + switch (cmd) { + case 'm': + case 'l': + case 'c': + case 's': + case 'q': + case 't': { + for (i = 0; i < count - 1; i += 2) { + arr[i] = arr[i] + cur->x; + arr[i + 1] = arr[i + 1] + cur->y; + } + break; + } + case 'h': { + arr[0] = arr[0] + cur->x; + break; + } + case 'v': { + arr[0] = arr[0] + cur->y; + break; + } + case 'a': { + arr[5] = arr[5] + cur->x; + arr[6] = arr[6] + cur->y; + break; + } + default: { + break; + } + } + + switch (cmd) { + case 'm': + case 'M': { + Point p = {arr[0], arr[1]}; + cmds->push_back(PathCommand::MoveTo); + pts->push_back(p); + *cur = {arr[0] ,arr[1]}; + break; + } + case 'l': + case 'L': { + Point p = {arr[0], arr[1]}; + cmds->push_back(PathCommand::LineTo); + pts->push_back(p); + *cur = {arr[0] ,arr[1]}; + break; + } + case 'c': + case 'C': { + Point p[3]; + cmds->push_back(PathCommand::CubicTo); + p[0] = {arr[0], arr[1]}; + p[1] = {arr[2], arr[3]}; + p[2] = {arr[4], arr[5]}; + pts->push_back(p[0]); + pts->push_back(p[1]); + pts->push_back(p[2]); + *curCtl = p[1]; + *cur = p[2]; + break; + } + case 's': + case 'S': { + Point p[3], ctrl; + if ((cmds->size() > 1) && (cmds->at(cmds->size() - 2) == PathCommand::CubicTo)) { + ctrl.x = 2 * cur->x - curCtl->x; + ctrl.y = 2 * cur->x - curCtl->y; + } else { + ctrl = *cur; + } + cmds->push_back(PathCommand::CubicTo); + p[0] = ctrl; + p[1] = {arr[0], arr[1]}; + p[2] = {arr[2], arr[3]}; + pts->push_back(p[0]); + pts->push_back(p[1]); + pts->push_back(p[2]); + *curCtl = p[1]; + *cur = p[2]; + break; + } + case 'q': + case 'Q': { + //TODO: Implement quadratic_to + break; + } + case 't': + case 'T': { + Point p = {arr[0], arr[1]}; + cmds->push_back(PathCommand::MoveTo); + pts->push_back(p); + *cur = {arr[0] ,arr[1]}; + break; + } + case 'h': + case 'H': { + Point p = {arr[0], cur->y}; + cmds->push_back(PathCommand::LineTo); + pts->push_back(p); + cur->x = arr[0]; + break; + } + case 'v': + case 'V': { + Point p = {cur->x, arr[0]}; + cmds->push_back(PathCommand::LineTo); + pts->push_back(p); + cur->y = arr[0]; + break; + } + case 'z': + case 'Z': { + cmds->push_back(PathCommand::Close); + break; + } + case 'a': + case 'A': { + //TODO: Implement arc_to + break; + } + case 'E': + case 'e': { + //TODO: Implement arc + break; + } + default: { + break; + } + } +} + + +static char* _nextCommand(char* path, char* cmd, float* arr, int* count) +{ + int i = 0, large, sweep; + + path = _skipComma(path); + if (isalpha(*path)) { + *cmd = *path; + path++; + *count = _numberCount(*cmd); + } else { + if (*cmd == 'm') *cmd = 'l'; + else if (*cmd == 'M') *cmd = 'L'; + } + if (*count == 7) { + //Special case for arc command + if (_parseNumber(&path, &arr[0])) { + if (_parseNumber(&path, &arr[1])) { + if (_parseNumber(&path, &arr[2])) { + if (_parseLong(&path, &large)) { + if (_parseLong(&path, &sweep)) { + if (_parseNumber(&path, &arr[5])) { + if (_parseNumber(&path, &arr[6])) { + arr[3] = large; + arr[4] = sweep; + return path; + } + } + } + } + } + } + } + *count = 0; + return NULL; + } + for (i = 0; i < *count; i++) { + if (!_parseNumber(&path, &arr[i])) { + *count = 0; + return NULL; + } + path = _skipComma(path); + } + return path; +} + + +tuple, vector> svgPathToTvgPath(const char* svgPath) +{ + vector cmds; + vector pts; + + float numberArray[7]; + int numberCount = 0; + Point cur = { 0, 0 }; + Point curCtl = { 0, 0 }; + char cmd = 0; + char* path = (char*)svgPath; + char* curLocale; + + curLocale = setlocale(LC_NUMERIC, NULL); + if (curLocale) curLocale = strdup(curLocale); + setlocale(LC_NUMERIC, "POSIX"); + + while ((path[0] != '\0')) { + path = _nextCommand(path, &cmd, numberArray, &numberCount); + if (!path) break; + _processCommand(&cmds, &pts, cmd, numberArray, numberCount, &cur, &curCtl); + } + + setlocale(LC_NUMERIC, curLocale); + if (curLocale) free(curLocale); + + return make_tuple(cmds, pts); +} + +#endif //__TVG_SVG_PATH_CPP_ diff --git a/src/loaders/svg_loader/tvgSvgPath.h b/src/loaders/svg_loader/tvgSvgPath.h new file mode 100644 index 0000000..47a35d8 --- /dev/null +++ b/src/loaders/svg_loader/tvgSvgPath.h @@ -0,0 +1,8 @@ +#ifndef _TVG_SVG_PATH_H_ +#define _TVG_SVG_PATH_H_ + +#include "tvgCommon.h" + +tuple, vector> svgPathToTvgPath(const char* svg_path_data); + +#endif //_TVG_SVG_PATH_H_ diff --git a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp index 601ed0c..b3fe81d 100644 --- a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp @@ -93,7 +93,10 @@ unique_ptr _shapeBuildHelper(SvgNode* node) auto shape = tvg::Shape::gen(); switch (node->type) { case SvgNodeType::Path: { - //TODO: Support path + if (node->node.path.path) { + auto pathResult = svgPathToTvgPath(node->node.path.path->c_str()); + shape->appendPath(get<0>(pathResult).data(), get<0>(pathResult).size(), get<1>(pathResult).data(), get<1>(pathResult).size()); + } break; } case SvgNodeType::Ellipse: { diff --git a/src/loaders/svg_loader/tvgSvgSceneBuilder.h b/src/loaders/svg_loader/tvgSvgSceneBuilder.h index 20a41a7..1bd779b 100644 --- a/src/loaders/svg_loader/tvgSvgSceneBuilder.h +++ b/src/loaders/svg_loader/tvgSvgSceneBuilder.h @@ -18,6 +18,7 @@ #define _TVG_SVG_SCENE_BUILDER_H_ #include "tvgSvgLoaderCommon.h" +#include "tvgSvgPath.h" class SvgSceneBuilder { -- 2.7.4 From 0a562a4ae26e5f6c3d6dffc4d45982b7dc1e625b Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 29 Jun 2020 16:26:02 +0900 Subject: [PATCH 08/16] test: print current backend engine name Change-Id: Iaafa521556a614b47994914c09228b8e8ae9c9e9 --- test/testShape.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/testShape.cpp b/test/testShape.cpp index e32142f..cd1bab1 100644 --- a/test/testShape.cpp +++ b/test/testShape.cpp @@ -1,4 +1,5 @@ #include +#include #include using namespace std; @@ -107,6 +108,9 @@ int main(int argc, char **argv) if (!strcmp(argv[1], "gl")) swEngine = false; } + if (swEngine) cout << "engine: software" << endl; + else cout << "engine: opengl" << endl; + elm_init(argc, argv); //Show the result using EFL... -- 2.7.4 From be6615d93e0488f239edf62b61dd6ed33a9a36c5 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Mon, 29 Jun 2020 16:35:21 +0900 Subject: [PATCH 09/16] SvgLoader: Supports Path's quadratic_to draw Convert quadratic bezier to cubic Change-Id: I885138dcdfb9f0e85bf3ca1ca5c9fc4eb0d8f1f8 --- src/loaders/svg_loader/tvgSvgPath.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/loaders/svg_loader/tvgSvgPath.cpp b/src/loaders/svg_loader/tvgSvgPath.cpp index 70058e0..c3d3cac 100644 --- a/src/loaders/svg_loader/tvgSvgPath.cpp +++ b/src/loaders/svg_loader/tvgSvgPath.cpp @@ -170,7 +170,20 @@ static void _processCommand(vector* cmds, vector* pts, char } case 'q': case 'Q': { - //TODO: Implement quadratic_to + tvg::Point p[3]; + float ctrl_x0 = (cur->x + 2 * arr[0]) * (1.0 / 3.0); + float ctrl_y0 = (cur->y + 2 * arr[1]) * (1.0 / 3.0); + float ctrl_x1 = (arr[2] + 2 * arr[0]) * (1.0 / 3.0); + float ctrl_y1 = (arr[3] + 2 * arr[1]) * (1.0 / 3.0); + cmds->push_back(tvg::PathCommand::CubicTo); + p[0] = {ctrl_x0, ctrl_y0}; + p[1] = {ctrl_x1, ctrl_y1}; + p[2] = {arr[2], arr[3]}; + pts->push_back(p[0]); + pts->push_back(p[1]); + pts->push_back(p[2]); + *curCtl = p[1]; + *cur = p[2]; break; } case 't': -- 2.7.4 From 9ba6bd654e310f5c3896a8043df1fcb3fbb753f9 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Mon, 29 Jun 2020 19:24:54 +0900 Subject: [PATCH 10/16] SvgLoader: Fix typo rect types w, h -> width, height Change-Id: I5e85360644d9b8c2b2d84f182a0de16fefe9edbf --- src/loaders/svg_loader/tvgSvgLoader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/loaders/svg_loader/tvgSvgLoader.cpp b/src/loaders/svg_loader/tvgSvgLoader.cpp index 4dd5fd4..99bb689 100644 --- a/src/loaders/svg_loader/tvgSvgLoader.cpp +++ b/src/loaders/svg_loader/tvgSvgLoader.cpp @@ -1218,8 +1218,8 @@ static constexpr struct } rectTags[] = { RECT_DEF(x, x, SvgParserLengthType::Horizontal), RECT_DEF(y, y, SvgParserLengthType::Vertical), - RECT_DEF(w, w, SvgParserLengthType::Horizontal), - RECT_DEF(h, h, SvgParserLengthType::Vertical), + RECT_DEF(width, w, SvgParserLengthType::Horizontal), + RECT_DEF(height, h, SvgParserLengthType::Vertical), RECT_DEF(rx, rx, SvgParserLengthType::Horizontal), RECT_DEF(ry, ry, SvgParserLengthType::Vertical) }; -- 2.7.4 From 654299d0ab6b3eeb0a5c21aafba036b93f1e995e Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Mon, 29 Jun 2020 19:30:29 +0900 Subject: [PATCH 11/16] test: Improve svg test Displays svg files located in "./svgs" dir. Change-Id: I4b9a281dc31fefb28c969780fa28adb74a5f5c02 --- test/svgs/bojo.svg | 15 ++++++++++++++ test/svgs/bzrfeed.svg | 23 +++++++++++++++++++++ test/svgs/cartman.svg | 11 ++++++++++ test/svgs/dst.svg | 15 ++++++++++++++ test/svgs/shape.svg | 18 ++++++++++++++++ test/testSvg.cpp | 57 +++++++++++++++++++++++++++++++++++---------------- 6 files changed, 121 insertions(+), 18 deletions(-) create mode 100644 test/svgs/bojo.svg create mode 100644 test/svgs/bzrfeed.svg create mode 100644 test/svgs/cartman.svg create mode 100644 test/svgs/dst.svg create mode 100644 test/svgs/shape.svg diff --git a/test/svgs/bojo.svg b/test/svgs/bojo.svg new file mode 100644 index 0000000..fe62615 --- /dev/null +++ b/test/svgs/bojo.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + diff --git a/test/svgs/bzrfeed.svg b/test/svgs/bzrfeed.svg new file mode 100644 index 0000000..e5d210f --- /dev/null +++ b/test/svgs/bzrfeed.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/svgs/cartman.svg b/test/svgs/cartman.svg new file mode 100644 index 0000000..d4b2740 --- /dev/null +++ b/test/svgs/cartman.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/test/svgs/dst.svg b/test/svgs/dst.svg new file mode 100644 index 0000000..bce75d8 --- /dev/null +++ b/test/svgs/dst.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/test/svgs/shape.svg b/test/svgs/shape.svg new file mode 100644 index 0000000..a0b3677 --- /dev/null +++ b/test/svgs/shape.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + diff --git a/test/testSvg.cpp b/test/testSvg.cpp index b7671b8..1ae4fe0 100644 --- a/test/testSvg.cpp +++ b/test/testSvg.cpp @@ -8,36 +8,54 @@ using namespace std; static uint32_t buffer[WIDTH * HEIGHT]; -void tvgtest() -{ - //Initialize ThorVG Engine - tvg::Initializer::init(tvg::CanvasEngine::Sw); +unique_ptr canvas = nullptr; +int count = 0; +static const int numberPerLine = 3; + +static int x = 30; +static int y = 30; - //Create a Canvas - auto canvas = tvg::SwCanvas::gen(); - canvas->target(buffer, WIDTH, WIDTH, HEIGHT); - // Create a SVG scene, request the original size, +void svgDirCallback(const char* name, const char* path, void* data) +{ auto scene = tvg::Scene::gen(); - scene->load("sample.svg"); + char buf[255]; + sprintf(buf,"%s/%s", path, name); + scene->load(buf); + printf("SVG Load : %s\n", buf); + scene->translate(((WIDTH - (x * 2)) / numberPerLine) * (count % numberPerLine) + x, ((HEIGHT - (y * 2))/ numberPerLine) * (int)((float)count / (float)numberPerLine) + y); canvas->push(move(scene)); - - canvas->draw(); - canvas->sync(); - - //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); + count++; } -void win_del(void *data, Evas_Object *o, void *ev) + +void win_del(void* data, Evas_Object* o, void* ev) { elm_exit(); } -int main(int argc, char **argv) +int main(int argc, char** argv) { - tvgtest(); + //Initialize ThorVG Engine + tvg::Initializer::init(tvg::CanvasEngine::Sw); + + //Create a Canvas + canvas = tvg::SwCanvas::gen(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); + + //Draw white background + auto scene = tvg::Scene::gen(); + auto shape1 = tvg::Shape::gen(); + shape1->appendRect(0, 0, WIDTH, HEIGHT, 0); + shape1->fill(255, 255, 255, 255); + scene->push(move(shape1)); + canvas->push(move(scene)); + + eina_file_dir_list("./svgs", EINA_TRUE, svgDirCallback, NULL); + + canvas->draw(); + canvas->sync(); //Show the result using EFL... elm_init(argc, argv); @@ -57,4 +75,7 @@ int main(int argc, char **argv) elm_run(); elm_shutdown(); + + //Terminate ThorVG Engine + tvg::Initializer::term(tvg::CanvasEngine::Sw); } -- 2.7.4 From 918b6c69d837bb6c181aa62d4e325bfe32454837 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 29 Jun 2020 17:35:04 +0900 Subject: [PATCH 12/16] test: unify test code for supporting gl engine from all test cases. now you can launch tests with gl engine by "gl" option ex) $ testTransform gl $ testScene gl Change-Id: Idb720ed369a2fbfb908c977fdaebd7289986fb6f --- test/testAsync.cpp | 142 ++++++++++++++++++++++++++------------ test/testBlending.cpp | 130 +++++++++++++++++++++++++---------- test/testBoundary.cpp | 129 +++++++++++++++++++++++++---------- test/testCommon.h | 70 +++++++++++++++++++ test/testComposition.cpp | 35 ---------- test/testCustomTransform.cpp | 147 ++++++++++++++++++++++++++++----------- test/testDirectUpdate.cpp | 148 ++++++++++++++++++++++++++++------------ test/testGradient.cpp | 52 -------------- test/testGradientTransform.cpp | 147 ++++++++++++++++++++++++++++----------- test/testLinearGradient.cpp | 130 +++++++++++++++++++++++++---------- test/testMultiShapes.cpp | 130 +++++++++++++++++++++++++---------- test/testPath.cpp | 129 +++++++++++++++++++++++++---------- test/testPathCopy.cpp | 129 +++++++++++++++++++++++++---------- test/testRadialGradient.cpp | 130 +++++++++++++++++++++++++---------- test/testScene.cpp | 130 +++++++++++++++++++++++++---------- test/testSceneTransform.cpp | 147 ++++++++++++++++++++++++++++----------- test/testShape.cpp | 117 ++++++++++++------------------- test/testStroke.cpp | 130 +++++++++++++++++++++++++---------- test/testStrokeLine.cpp | 131 +++++++++++++++++++++++++---------- test/testSvg.cpp | 151 +++++++++++++++++++++++++++++------------ test/testTransform.cpp | 147 ++++++++++++++++++++++++++++----------- test/testUpdate.cpp | 147 ++++++++++++++++++++++++++++----------- 22 files changed, 1893 insertions(+), 855 deletions(-) create mode 100644 test/testCommon.h delete mode 100644 test/testComposition.cpp delete mode 100644 test/testGradient.cpp diff --git a/test/testAsync.cpp b/test/testAsync.cpp index 7172dd9..a8ac2b0 100644 --- a/test/testAsync.cpp +++ b/test/testAsync.cpp @@ -1,25 +1,14 @@ -#include -#include +#include "testCommon.h" -using namespace std; - -#define WIDTH 1920 -#define HEIGHT 1080 +/************************************************************************/ +/* Drawing Commands */ +/************************************************************************/ #define COUNT 50 -static uint32_t buffer[WIDTH * HEIGHT]; -unique_ptr canvas = nullptr; static double t1, t2, t3, t4; static unsigned cnt = 0; -void tvgtest() -{ - //Create a Canvas - canvas = tvg::SwCanvas::gen(); - canvas->target(buffer, WIDTH, WIDTH, HEIGHT); -} - -Eina_Bool anim_cb(void *data) +bool tvgUpdateCmds(tvg::Canvas* canvas) { auto t = ecore_time_get(); @@ -27,7 +16,7 @@ Eina_Bool anim_cb(void *data) if (canvas->clear() != tvg::Result::Success) { //Logically wrong! Probably, you missed to call sync() before. - return ECORE_CALLBACK_RENEW; + return false; } t1 = t; @@ -38,8 +27,8 @@ Eina_Bool anim_cb(void *data) float x = rand() % (WIDTH/2); float y = rand() % (HEIGHT/2); - float w = 1 + rand() % 1200; - float h = 1 + rand() % 800; + float w = 1 + rand() % (int)(WIDTH * 1.3 / 2); + float h = 1 + rand() % (int)(HEIGHT * 1.3 / 2); shape->appendRect(x, y, w, h, rand() % 400); @@ -61,8 +50,29 @@ Eina_Bool anim_cb(void *data) t3 = ecore_time_get(); + return true; +} + + +/************************************************************************/ +/* 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); +} + +Eina_Bool animSwCb(void* data) +{ + if (!tvgUpdateCmds(swCanvas.get())) return ECORE_CALLBACK_RENEW; + //Drawing task can be performed asynchronously. - canvas->draw(); + swCanvas->draw(); //Update Efl Canvas Eo* img = (Eo*) data; @@ -72,50 +82,96 @@ Eina_Bool anim_cb(void *data) return ECORE_CALLBACK_RENEW; } -void render_cb(void* data, Eo* obj) +void drawSwView(void* data, Eo* obj) { //Make it guarantee finishing drawing task. - canvas->sync(); + swCanvas->sync(); t4 = ecore_time_get(); printf("[%5d]: total[%fms] = clear[%fms], update[%fms], render[%fms]\n", ++cnt, t4 - t1, t2 - t1, t3 - t2, t4 - t3); } -void win_del(void *data, Evas_Object *o, void *ev) + +/************************************************************************/ +/* 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); +} + +void drawGLview(Evas_Object *obj) { - elm_exit(); + auto gl = elm_glview_gl_api_get(obj); + int w, h; + elm_glview_size_get(obj, &w, &h); + gl->glViewport(0, 0, w, h); + gl->glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + gl->glClear(GL_COLOR_BUFFER_BIT); + gl->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); + gl->glEnable(GL_BLEND); + + glCanvas->sync(); } +Eina_Bool animGlCb(void* data) +{ + if (!tvgUpdateCmds(glCanvas.get())) return ECORE_CALLBACK_RENEW; + + //Drawing task can be performed asynchronously. + glCanvas->draw(); + + return ECORE_CALLBACK_RENEW; +} + + +/************************************************************************/ +/* Main Code */ +/************************************************************************/ + int main(int argc, char **argv) { - //Initialize ThorVG Engine - tvg::Initializer::init(tvg::CanvasEngine::Sw); + tvg::CanvasEngine tvgEngine = tvg::CanvasEngine::Sw; - tvgtest(); + if (argc > 1) { + if (!strcmp(argv[1], "gl")) tvgEngine = tvg::CanvasEngine::Gl; + } - //Show the result using EFL... - elm_init(argc, argv); + //Initialize ThorVG Engine + if (tvgEngine == tvg::CanvasEngine::Sw) { + cout << "tvg engine: software" << endl; + } else { + cout << "tvg engine: opengl" << endl; + } - Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); - evas_object_smart_callback_add(win, "delete,request", win_del, 0); + //Initialize ThorVG Engine + tvg::Initializer::init(tvgEngine); - Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); - evas_object_image_size_set(img, WIDTH, HEIGHT); - evas_object_image_data_set(img, buffer); - evas_object_image_pixels_get_callback_set(img, render_cb, nullptr); - evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_show(img); + elm_init(argc, argv); - elm_win_resize_object_add(win, img); - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); - evas_object_show(win); + elm_config_accel_preference_set("gl"); - ecore_animator_add(anim_cb, img); + if (tvgEngine == tvg::CanvasEngine::Sw) { + auto view = createSwView(); + evas_object_image_pixels_get_callback_set(view, drawSwView, nullptr); + ecore_animator_add(animSwCb, view); + } else { + auto view = createGlView(); + ecore_animator_add(animGlCb, view); + } elm_run(); elm_shutdown(); //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); -} + tvg::Initializer::term(tvgEngine); +} \ No newline at end of file diff --git a/test/testBlending.cpp b/test/testBlending.cpp index 82aa32d..7794689 100644 --- a/test/testBlending.cpp +++ b/test/testBlending.cpp @@ -1,21 +1,11 @@ -#include -#include +#include "testCommon.h" -using namespace std; +/************************************************************************/ +/* Drawing Commands */ +/************************************************************************/ -#define WIDTH 800 -#define HEIGHT 800 - -static uint32_t buffer[WIDTH * HEIGHT]; - -void tvgtest() +void tvgDrawCmds(tvg::Canvas* canvas) { - //Initialize ThorVG Engine - tvg::Initializer::init(tvg::CanvasEngine::Sw); - - //Create a Canvas - auto canvas = tvg::SwCanvas::gen(); - canvas->target(buffer, WIDTH, WIDTH, HEIGHT); canvas->reserve(5); //Prepare Round Rectangle @@ -57,40 +47,108 @@ void tvgtest() shape5->appendCircle(600, 650, 200, 150); shape5->fill(0, 0, 255, 255); canvas->push(move(shape5)); +} - //Draw the Shapes onto the Canvas - canvas->draw(); - canvas->sync(); - //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); +/************************************************************************/ +/* 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); + + /* 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 win_del(void *data, Evas_Object *o, void *ev) +void drawSwView(void* data, Eo* obj) { - elm_exit(); + swCanvas->draw(); + 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); + int w, h; + elm_glview_size_get(obj, &w, &h); + gl->glViewport(0, 0, w, h); + gl->glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + gl->glClear(GL_COLOR_BUFFER_BIT); + gl->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); + gl->glEnable(GL_BLEND); + + glCanvas->draw(); + glCanvas->sync(); +} + + +/************************************************************************/ +/* Main Code */ +/************************************************************************/ + int main(int argc, char **argv) { - tvgtest(); + tvg::CanvasEngine tvgEngine = tvg::CanvasEngine::Sw; - //Show the result using EFL... - elm_init(argc, argv); + if (argc > 1) { + if (!strcmp(argv[1], "gl")) tvgEngine = tvg::CanvasEngine::Gl; + } - Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); - evas_object_smart_callback_add(win, "delete,request", win_del, 0); + //Initialize ThorVG Engine + if (tvgEngine == tvg::CanvasEngine::Sw) { + cout << "tvg engine: software" << endl; + } else { + cout << "tvg engine: opengl" << endl; + } + + //Initialize ThorVG Engine + tvg::Initializer::init(tvgEngine); + + elm_init(argc, argv); - Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); - evas_object_image_size_set(img, WIDTH, HEIGHT); - evas_object_image_data_set(img, buffer); - evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_show(img); + elm_config_accel_preference_set("gl"); - elm_win_resize_object_add(win, img); - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); - evas_object_show(win); + if (tvgEngine == tvg::CanvasEngine::Sw) { + createSwView(); + } else { + createGlView(); + } elm_run(); elm_shutdown(); -} + + //Terminate ThorVG Engine + tvg::Initializer::term(tvgEngine); +} \ No newline at end of file diff --git a/test/testBoundary.cpp b/test/testBoundary.cpp index d7cb8fa..e74ac5e 100644 --- a/test/testBoundary.cpp +++ b/test/testBoundary.cpp @@ -1,21 +1,11 @@ -#include -#include +#include "testCommon.h" -using namespace std; +/************************************************************************/ +/* Drawing Commands */ +/************************************************************************/ -#define WIDTH 800 -#define HEIGHT 800 - -static uint32_t buffer[WIDTH * HEIGHT]; - -void tvgtest() +void tvgDrawCmds(tvg::Canvas* canvas) { - //Initialize ThorVG Engine - tvg::Initializer::init(tvg::CanvasEngine::Sw); - - //Create a Canvas - auto canvas = tvg::SwCanvas::gen(); - canvas->target(buffer, WIDTH, WIDTH, HEIGHT); canvas->reserve(5); //reserve 5 shape nodes (optional) //Prepare Shape1 @@ -47,40 +37,107 @@ void tvgtest() shape5->appendCircle(200, 650, 250, 200); shape5->fill(0, 0, 0, 255); canvas->push(move(shape5)); +} - //Draw the Shapes onto the Canvas - canvas->draw(); - canvas->sync(); +/************************************************************************/ +/* Sw Engine Test Code */ +/************************************************************************/ - //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); +static unique_ptr swCanvas; + +void tvgSwTest(uint32_t* buffer) +{ + //Create a Canvas + swCanvas = tvg::SwCanvas::gen(); + swCanvas->target(buffer, WIDTH, 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(swCanvas.get()); +} + +void drawSwView(void* data, Eo* obj) +{ + swCanvas->draw(); + 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 win_del(void *data, Evas_Object *o, void *ev) +void drawGLview(Evas_Object *obj) { - elm_exit(); + auto gl = elm_glview_gl_api_get(obj); + int w, h; + elm_glview_size_get(obj, &w, &h); + gl->glViewport(0, 0, w, h); + gl->glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + gl->glClear(GL_COLOR_BUFFER_BIT); + gl->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); + gl->glEnable(GL_BLEND); + + glCanvas->draw(); + glCanvas->sync(); } + +/************************************************************************/ +/* Main Code */ +/************************************************************************/ + int main(int argc, char **argv) { - tvgtest(); + tvg::CanvasEngine tvgEngine = tvg::CanvasEngine::Sw; - //Show the result using EFL... - elm_init(argc, argv); + if (argc > 1) { + if (!strcmp(argv[1], "gl")) tvgEngine = tvg::CanvasEngine::Gl; + } - Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); - evas_object_smart_callback_add(win, "delete,request", win_del, 0); + //Initialize ThorVG Engine + if (tvgEngine == tvg::CanvasEngine::Sw) { + cout << "tvg engine: software" << endl; + } else { + cout << "tvg engine: opengl" << endl; + } + + //Initialize ThorVG Engine + tvg::Initializer::init(tvgEngine); + + elm_init(argc, argv); - Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); - evas_object_image_size_set(img, WIDTH, HEIGHT); - evas_object_image_data_set(img, buffer); - evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_show(img); + elm_config_accel_preference_set("gl"); - elm_win_resize_object_add(win, img); - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); - evas_object_show(win); + if (tvgEngine == tvg::CanvasEngine::Sw) { + createSwView(); + } else { + createGlView(); + } elm_run(); elm_shutdown(); -} + + //Terminate ThorVG Engine + tvg::Initializer::term(tvgEngine); +} \ No newline at end of file diff --git a/test/testCommon.h b/test/testCommon.h new file mode 100644 index 0000000..c47723a --- /dev/null +++ b/test/testCommon.h @@ -0,0 +1,70 @@ +#include +#include +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 + +/************************************************************************/ +/* Common Infrastructure Code */ +/************************************************************************/ + +void tvgSwTest(uint32_t* buffer); + +void win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} + +void drawSwView(void* data, Eo* obj); + +static Eo* createSwView() +{ + static uint32_t buffer[WIDTH * HEIGHT]; + + Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); + evas_object_smart_callback_add(win, "delete,request", win_del, 0); + + Eo* view = evas_object_image_filled_add(evas_object_evas_get(win)); + evas_object_image_size_set(view, WIDTH, HEIGHT); + evas_object_image_data_set(view, buffer); + evas_object_image_pixels_get_callback_set(view, drawSwView, nullptr); + evas_object_image_pixels_dirty_set(view, EINA_TRUE); + evas_object_image_data_update_add(view, 0, 0, WIDTH, HEIGHT); + evas_object_size_hint_weight_set(view, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(view); + + elm_win_resize_object_add(win, view); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + tvgSwTest(buffer); + + return view; +} + +void initGLview(Evas_Object *obj); +void drawGLview(Evas_Object *obj); + +static Eo* createGlView() +{ + Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); + evas_object_smart_callback_add(win, "delete,request", win_del, 0); + + Eo* view = elm_glview_add(win); + evas_object_size_hint_weight_set(view, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_glview_mode_set(view, ELM_GLVIEW_ALPHA); + elm_glview_resize_policy_set(view, ELM_GLVIEW_RESIZE_POLICY_RECREATE); + elm_glview_render_policy_set(view, ELM_GLVIEW_RENDER_POLICY_ON_DEMAND); + elm_glview_init_func_set(view, initGLview); + elm_glview_render_func_set(view, drawGLview); + evas_object_show(view); + + elm_win_resize_object_add(win, view); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + return view; +} diff --git a/test/testComposition.cpp b/test/testComposition.cpp deleted file mode 100644 index 6230dc0..0000000 --- a/test/testComposition.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include - -using namespace std; - -#define WIDTH 800 -#define HEIGHT 800 - -static uint32_t buffer[WIDTH * HEIGHT]; - -int main(int argc, char **argv) -{ - //Initialize ThorVG Engine - tvg::Initializer::init(tvg::CanvasEngine::Sw); - - //Create a Composition Source Canvas - auto canvas1 = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); - - //Draw something onto the Canvas and leaving sync to the target. - canvas1->draw(); - - //Create a Main Canvas - auto canvas2 = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); - - //Create a Shape - auto shape = tvg::Shape::gen(); - shape->composite(canvas, tvg::CompMaskAdd); - - //Draw the Scene onto the Canvas - canvas2->push(move(shape)); - canvas2->draw(); - canvas2->sync(); - - //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); -} diff --git a/test/testCustomTransform.cpp b/test/testCustomTransform.cpp index c57d4d4..1109a21 100644 --- a/test/testCustomTransform.cpp +++ b/test/testCustomTransform.cpp @@ -1,21 +1,12 @@ -#include -#include +#include "testCommon.h" -using namespace std; - -#define WIDTH 800 -#define HEIGHT 800 - -static uint32_t buffer[WIDTH * HEIGHT]; -unique_ptr canvas = nullptr; +/************************************************************************/ +/* Drawing Commands */ +/************************************************************************/ tvg::Shape* pShape = nullptr; -void tvgtest() +void tvgDrawCmds(tvg::Canvas* canvas) { - //Create a Canvas - canvas = tvg::SwCanvas::gen(); - canvas->target(buffer, WIDTH, WIDTH, HEIGHT); - //Shape1 auto shape = tvg::Shape::gen(); @@ -36,13 +27,9 @@ void tvgtest() shape->close(); shape->fill(0, 0, 255, 255); canvas->push(move(shape)); - - //Draw first frame - canvas->draw(); - canvas->sync(); } -void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) +void tvgUpdateCmds(tvg::Canvas* canvas, float progress) { /* Update shape directly. You can update only necessary properties of this shape, @@ -86,46 +73,124 @@ void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progres //Update shape for drawing (this may work asynchronously) canvas->update(pShape); +} + + +/************************************************************************/ +/* Sw Engine Test Code */ +/************************************************************************/ + +static unique_ptr swCanvas; - //Draw Next frames - canvas->draw(); - canvas->sync(); +void tvgSwTest(uint32_t* buffer) +{ + //Create a Canvas + swCanvas = tvg::SwCanvas::gen(); + swCanvas->target(buffer, WIDTH, 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(swCanvas.get()); +} + +void transitSwCb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) +{ + tvgUpdateCmds(swCanvas.get(), progress); //Update Efl Canvas Eo* img = (Eo*) effect; evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT); + evas_object_image_pixels_dirty_set(img, EINA_TRUE); +} + +void drawSwView(void* data, Eo* obj) +{ + swCanvas->draw(); + 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); + int w, h; + elm_glview_size_get(obj, &w, &h); + gl->glViewport(0, 0, w, h); + gl->glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + gl->glClear(GL_COLOR_BUFFER_BIT); + gl->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); + gl->glEnable(GL_BLEND); + + glCanvas->draw(); + glCanvas->sync(); } -void win_del(void *data, Evas_Object *o, void *ev) +void transitGlCb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) { - elm_exit(); + tvgUpdateCmds(glCanvas.get(), progress); } + +/************************************************************************/ +/* 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 - tvg::Initializer::init(tvg::CanvasEngine::Sw); + if (tvgEngine == tvg::CanvasEngine::Sw) { + cout << "tvg engine: software" << endl; + } else { + cout << "tvg engine: opengl" << endl; + } - tvgtest(); + //Initialize ThorVG Engine + tvg::Initializer::init(tvgEngine); - //Show the result using EFL... elm_init(argc, argv); - Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); - evas_object_smart_callback_add(win, "delete,request", win_del, 0); + elm_config_accel_preference_set("gl"); - Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); - evas_object_image_size_set(img, WIDTH, HEIGHT); - evas_object_image_data_set(img, buffer); - evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_show(img); + Elm_Transit *transit = elm_transit_add(); - elm_win_resize_object_add(win, img); - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); - evas_object_show(win); + if (tvgEngine == tvg::CanvasEngine::Sw) { + auto view = createSwView(); + elm_transit_effect_add(transit, transitSwCb, view, nullptr); + } else { + auto view = createGlView(); + elm_transit_effect_add(transit, transitGlCb, view, nullptr); + } - Elm_Transit *transit = elm_transit_add(); - elm_transit_effect_add(transit, transit_cb, img, nullptr); elm_transit_duration_set(transit, 2); elm_transit_repeat_times_set(transit, -1); elm_transit_auto_reverse_set(transit, EINA_TRUE); @@ -135,5 +200,5 @@ int main(int argc, char **argv) elm_shutdown(); //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); -} + tvg::Initializer::term(tvgEngine); +} \ No newline at end of file diff --git a/test/testDirectUpdate.cpp b/test/testDirectUpdate.cpp index 4dbc26b..93b2dfb 100644 --- a/test/testDirectUpdate.cpp +++ b/test/testDirectUpdate.cpp @@ -1,21 +1,12 @@ -#include -#include +#include "testCommon.h" -using namespace std; - -#define WIDTH 800 -#define HEIGHT 800 - -static uint32_t buffer[WIDTH * HEIGHT]; -unique_ptr canvas = nullptr; +/************************************************************************/ +/* Drawing Commands */ +/************************************************************************/ tvg::Shape* pShape = nullptr; -void tvgtest() +void tvgDrawCmds(tvg::Canvas* canvas) { - //Create a Canvas - canvas = tvg::SwCanvas::gen(); - canvas->target(buffer, WIDTH, WIDTH, HEIGHT); - //Shape auto shape = tvg::Shape::gen(); @@ -31,13 +22,9 @@ void tvgtest() shape->stroke(1); canvas->push(move(shape)); - - //Draw first frame - canvas->draw(); - canvas->sync(); } -void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) +void tvgUpdateCmds(tvg::Canvas* canvas, float progress) { /* Update shape directly. You can update only necessary properties of this shape, @@ -50,47 +37,124 @@ void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progres //Update shape for drawing (this may work asynchronously) canvas->update(pShape); +} + + +/************************************************************************/ +/* Sw Engine Test Code */ +/************************************************************************/ + +static unique_ptr swCanvas; - //Draw Next frames - canvas->draw(); - canvas->sync(); +void tvgSwTest(uint32_t* buffer) +{ + //Create a Canvas + swCanvas = tvg::SwCanvas::gen(); + swCanvas->target(buffer, WIDTH, 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(swCanvas.get()); +} + +void transitSwCb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) +{ + tvgUpdateCmds(swCanvas.get(), progress); //Update Efl Canvas Eo* img = (Eo*) effect; evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT); + evas_object_image_pixels_dirty_set(img, EINA_TRUE); +} + +void drawSwView(void* data, Eo* obj) +{ + swCanvas->draw(); + 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); + int w, h; + elm_glview_size_get(obj, &w, &h); + gl->glViewport(0, 0, w, h); + gl->glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + gl->glClear(GL_COLOR_BUFFER_BIT); + gl->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); + gl->glEnable(GL_BLEND); + + glCanvas->draw(); + glCanvas->sync(); } -void -win_del(void *data, Evas_Object *o, void *ev) +void transitGlCb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) { - elm_exit(); + tvgUpdateCmds(glCanvas.get(), progress); } + +/************************************************************************/ +/* 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 - tvg::Initializer::init(tvg::CanvasEngine::Sw); + if (tvgEngine == tvg::CanvasEngine::Sw) { + cout << "tvg engine: software" << endl; + } else { + cout << "tvg engine: opengl" << endl; + } - tvgtest(); + //Initialize ThorVG Engine + tvg::Initializer::init(tvgEngine); - //Show the result using EFL... elm_init(argc, argv); - Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); - evas_object_smart_callback_add(win, "delete,request", win_del, 0); + elm_config_accel_preference_set("gl"); - Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); - evas_object_image_size_set(img, WIDTH, HEIGHT); - evas_object_image_data_set(img, buffer); - evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_show(img); + Elm_Transit *transit = elm_transit_add(); - elm_win_resize_object_add(win, img); - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); - evas_object_show(win); + if (tvgEngine == tvg::CanvasEngine::Sw) { + auto view = createSwView(); + elm_transit_effect_add(transit, transitSwCb, view, nullptr); + } else { + auto view = createGlView(); + elm_transit_effect_add(transit, transitGlCb, view, nullptr); + } - Elm_Transit *transit = elm_transit_add(); - elm_transit_effect_add(transit, transit_cb, img, nullptr); elm_transit_duration_set(transit, 2); elm_transit_repeat_times_set(transit, -1); elm_transit_auto_reverse_set(transit, EINA_TRUE); @@ -100,5 +164,5 @@ int main(int argc, char **argv) elm_shutdown(); //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); -} + tvg::Initializer::term(tvgEngine); +} \ No newline at end of file diff --git a/test/testGradient.cpp b/test/testGradient.cpp deleted file mode 100644 index d20cce9..0000000 --- a/test/testGradient.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include - -using namespace std; - -#define WIDTH 800 -#define HEIGHT 800 - -static uint32_t buffer[WIDTH * HEIGHT]; - -int main(int argc, char **argv) -{ - //Initialize ThorVG Engine - tvg::Initializer::init(tvg::CanvasEngine::Sw); - - //Create a Canvas - auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); - - //Prepare a Shape - auto shape1 = tvg::Shape::gen(); - shape1->rect(0, 0, 400, 400, 0.1); //x, y, w, h, corner_radius - - //Linear Gradient Fill - auto fill1 = tvg::LinearFill::gen(); - fill1->range(fill1, 0, 0, 400, 400); //from(x, y), to(x, y) - fill1->color(0, 255, 0, 0, 255); //color Stop 0: Red - fill1->color(0.5, 0, 255, 0, 255); //color Stop 1: Green - fill1->color(1, 0, 0, 255, 255); //color Stop 2: Blue - shape1.fill(fill1); - - canvas->push(move(shape1)); - - //Prepare Circle - auto shape2 = tvg::Shape::gen(); - shape2->circle(400, 400, 200); //cx, cy, radius - - //Radial Gradient Fill - auto fill2 = tvg::RadialFill::gen(); - fill2->range(400, 400, 200); //center(x, y), radius - fill2->color(0, 255, 0, 0, 255); //color Stop 0: Red - fill2->color(0.5, 0, 255, 0, 255); //color Stop 1: Green - fill2->color(1, 0, 0, 255, 255); //color Stop 2: Blue - shape2.fill(fill2); - - canvas->push(move(shape2)); - - //Draw the Shapes onto the Canvas - canvas->draw(); - canvas->sync(); - - //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); -} diff --git a/test/testGradientTransform.cpp b/test/testGradientTransform.cpp index 1b5137b..b77062b 100644 --- a/test/testGradientTransform.cpp +++ b/test/testGradientTransform.cpp @@ -1,23 +1,14 @@ -#include -#include +#include "testCommon.h" -using namespace std; - -#define WIDTH 800 -#define HEIGHT 800 - -static uint32_t buffer[WIDTH * HEIGHT]; -unique_ptr canvas = nullptr; +/************************************************************************/ +/* Drawing Commands */ +/************************************************************************/ tvg::Shape* pShape = nullptr; tvg::Shape* pShape2 = nullptr; tvg::Shape* pShape3 = nullptr; -void tvgtest() +void tvgDrawCmds(tvg::Canvas* canvas) { - //Create a Canvas - canvas = tvg::SwCanvas::gen(); - canvas->target(buffer, WIDTH, WIDTH, HEIGHT); - //Shape1 auto shape = tvg::Shape::gen(); @@ -88,13 +79,9 @@ void tvgtest() shape3->fill(move(fill3)); shape3->translate(400, 400); canvas->push(move(shape3)); - - //Draw first frame - canvas->draw(); - canvas->sync(); } -void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) +void tvgUpdateCmds(tvg::Canvas* canvas, float progress) { /* Update shape directly. You can update only necessary properties of this shape, @@ -116,46 +103,124 @@ void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progres pShape3->rotate(-360 * progress); pShape3->scale(0.5 + progress); canvas->update(pShape3); +} + + +/************************************************************************/ +/* Sw Engine Test Code */ +/************************************************************************/ + +static unique_ptr swCanvas; - //Draw Next frames - canvas->draw(); - canvas->sync(); +void tvgSwTest(uint32_t* buffer) +{ + //Create a Canvas + swCanvas = tvg::SwCanvas::gen(); + swCanvas->target(buffer, WIDTH, 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(swCanvas.get()); +} + +void transitSwCb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) +{ + tvgUpdateCmds(swCanvas.get(), progress); //Update Efl Canvas Eo* img = (Eo*) effect; evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT); + evas_object_image_pixels_dirty_set(img, EINA_TRUE); +} + +void drawSwView(void* data, Eo* obj) +{ + swCanvas->draw(); + 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); + int w, h; + elm_glview_size_get(obj, &w, &h); + gl->glViewport(0, 0, w, h); + gl->glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + gl->glClear(GL_COLOR_BUFFER_BIT); + gl->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); + gl->glEnable(GL_BLEND); + + glCanvas->draw(); + glCanvas->sync(); } -void win_del(void *data, Evas_Object *o, void *ev) +void transitGlCb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) { - elm_exit(); + tvgUpdateCmds(glCanvas.get(), progress); } + +/************************************************************************/ +/* 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 - tvg::Initializer::init(tvg::CanvasEngine::Sw); + if (tvgEngine == tvg::CanvasEngine::Sw) { + cout << "tvg engine: software" << endl; + } else { + cout << "tvg engine: opengl" << endl; + } - tvgtest(); + //Initialize ThorVG Engine + tvg::Initializer::init(tvgEngine); - //Show the result using EFL... elm_init(argc, argv); - Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); - evas_object_smart_callback_add(win, "delete,request", win_del, 0); + elm_config_accel_preference_set("gl"); - Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); - evas_object_image_size_set(img, WIDTH, HEIGHT); - evas_object_image_data_set(img, buffer); - evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_show(img); + Elm_Transit *transit = elm_transit_add(); - elm_win_resize_object_add(win, img); - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); - evas_object_show(win); + if (tvgEngine == tvg::CanvasEngine::Sw) { + auto view = createSwView(); + elm_transit_effect_add(transit, transitSwCb, view, nullptr); + } else { + auto view = createGlView(); + elm_transit_effect_add(transit, transitGlCb, view, nullptr); + } - Elm_Transit *transit = elm_transit_add(); - elm_transit_effect_add(transit, transit_cb, img, nullptr); elm_transit_duration_set(transit, 2); elm_transit_repeat_times_set(transit, -1); elm_transit_auto_reverse_set(transit, EINA_TRUE); @@ -165,5 +230,5 @@ int main(int argc, char **argv) elm_shutdown(); //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); -} + tvg::Initializer::term(tvgEngine); +} \ No newline at end of file diff --git a/test/testLinearGradient.cpp b/test/testLinearGradient.cpp index ed0d31d..36251f5 100644 --- a/test/testLinearGradient.cpp +++ b/test/testLinearGradient.cpp @@ -1,21 +1,11 @@ -#include -#include +#include "testCommon.h" -using namespace std; +/************************************************************************/ +/* Drawing Commands */ +/************************************************************************/ -#define WIDTH 800 -#define HEIGHT 800 - -static uint32_t buffer[WIDTH * HEIGHT]; - -void tvgtest() +void tvgDrawCmds(tvg::Canvas* canvas) { - //Initialize ThorVG Engine - tvg::Initializer::init(tvg::CanvasEngine::Sw); - - //Create a Canvas - auto canvas = tvg::SwCanvas::gen(); - canvas->target(buffer, WIDTH, WIDTH, HEIGHT); canvas->reserve(3); //reserve 3 shape nodes (optional) //Prepare Round Rectangle @@ -75,40 +65,108 @@ void tvgtest() shape3->fill(move(fill3)); canvas->push(move(shape3)); +} - //Draw the Shapes onto the Canvas - canvas->draw(); - canvas->sync(); - //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); +/************************************************************************/ +/* 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); + + /* 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 win_del(void *data, Evas_Object *o, void *ev) +void drawSwView(void* data, Eo* obj) { - elm_exit(); + swCanvas->draw(); + 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); + int w, h; + elm_glview_size_get(obj, &w, &h); + gl->glViewport(0, 0, w, h); + gl->glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + gl->glClear(GL_COLOR_BUFFER_BIT); + gl->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); + gl->glEnable(GL_BLEND); + + glCanvas->draw(); + glCanvas->sync(); +} + + +/************************************************************************/ +/* Main Code */ +/************************************************************************/ + int main(int argc, char **argv) { - tvgtest(); + tvg::CanvasEngine tvgEngine = tvg::CanvasEngine::Sw; - //Show the result using EFL... - elm_init(argc, argv); + if (argc > 1) { + if (!strcmp(argv[1], "gl")) tvgEngine = tvg::CanvasEngine::Gl; + } - Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); - evas_object_smart_callback_add(win, "delete,request", win_del, 0); + //Initialize ThorVG Engine + if (tvgEngine == tvg::CanvasEngine::Sw) { + cout << "tvg engine: software" << endl; + } else { + cout << "tvg engine: opengl" << endl; + } + + //Initialize ThorVG Engine + tvg::Initializer::init(tvgEngine); + + elm_init(argc, argv); - Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); - evas_object_image_size_set(img, WIDTH, HEIGHT); - evas_object_image_data_set(img, buffer); - evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_show(img); + elm_config_accel_preference_set("gl"); - elm_win_resize_object_add(win, img); - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); - evas_object_show(win); + if (tvgEngine == tvg::CanvasEngine::Sw) { + createSwView(); + } else { + createGlView(); + } elm_run(); elm_shutdown(); -} + + //Terminate ThorVG Engine + tvg::Initializer::term(tvgEngine); +} \ No newline at end of file diff --git a/test/testMultiShapes.cpp b/test/testMultiShapes.cpp index 02101ed..195547d 100644 --- a/test/testMultiShapes.cpp +++ b/test/testMultiShapes.cpp @@ -1,21 +1,11 @@ -#include -#include +#include "testCommon.h" -using namespace std; +/************************************************************************/ +/* Drawing Commands */ +/************************************************************************/ -#define WIDTH 800 -#define HEIGHT 800 - -static uint32_t buffer[WIDTH * HEIGHT]; - -void tvgtest() +void tvgDrawCmds(tvg::Canvas* canvas) { - //Initialize ThorVG Engine - tvg::Initializer::init(tvg::CanvasEngine::Sw); - - //Create a Canvas - auto canvas = tvg::SwCanvas::gen(); - canvas->target(buffer, WIDTH, WIDTH, HEIGHT); canvas->reserve(3); //reserve 3 shape nodes (optional) //Prepare Round Rectangle @@ -35,40 +25,108 @@ void tvgtest() shape3->appendCircle(600, 600, 150, 100); //cx, cy, radiusW, radiusH shape3->fill(0, 255, 255, 255); //r, g, b, a canvas->push(move(shape3)); +} - //Draw the Shapes onto the Canvas - canvas->draw(); - canvas->sync(); - //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); +/************************************************************************/ +/* 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); + + /* 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 win_del(void *data, Evas_Object *o, void *ev) +void drawSwView(void* data, Eo* obj) { - elm_exit(); + swCanvas->draw(); + 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); + int w, h; + elm_glview_size_get(obj, &w, &h); + gl->glViewport(0, 0, w, h); + gl->glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + gl->glClear(GL_COLOR_BUFFER_BIT); + gl->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); + gl->glEnable(GL_BLEND); + + glCanvas->draw(); + glCanvas->sync(); +} + + +/************************************************************************/ +/* Main Code */ +/************************************************************************/ + int main(int argc, char **argv) { - tvgtest(); + tvg::CanvasEngine tvgEngine = tvg::CanvasEngine::Sw; - //Show the result using EFL... - elm_init(argc, argv); + if (argc > 1) { + if (!strcmp(argv[1], "gl")) tvgEngine = tvg::CanvasEngine::Gl; + } - Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); - evas_object_smart_callback_add(win, "delete,request", win_del, 0); + //Initialize ThorVG Engine + if (tvgEngine == tvg::CanvasEngine::Sw) { + cout << "tvg engine: software" << endl; + } else { + cout << "tvg engine: opengl" << endl; + } + + //Initialize ThorVG Engine + tvg::Initializer::init(tvgEngine); + + elm_init(argc, argv); - Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); - evas_object_image_size_set(img, WIDTH, HEIGHT); - evas_object_image_data_set(img, buffer); - evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_show(img); + elm_config_accel_preference_set("gl"); - elm_win_resize_object_add(win, img); - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); - evas_object_show(win); + if (tvgEngine == tvg::CanvasEngine::Sw) { + createSwView(); + } else { + createGlView(); + } elm_run(); elm_shutdown(); -} + + //Terminate ThorVG Engine + tvg::Initializer::term(tvgEngine); +} \ No newline at end of file diff --git a/test/testPath.cpp b/test/testPath.cpp index a5bdc9e..49bd738 100644 --- a/test/testPath.cpp +++ b/test/testPath.cpp @@ -1,22 +1,11 @@ -#include -#include +#include "testCommon.h" -using namespace std; +/************************************************************************/ +/* Drawing Commands */ +/************************************************************************/ -#define WIDTH 800 -#define HEIGHT 800 - -static uint32_t buffer[WIDTH * HEIGHT]; - -void tvgtest() +void tvgDrawCmds(tvg::Canvas* canvas) { - //Initialize ThorVG Engine - tvg::Initializer::init(tvg::CanvasEngine::Sw); - - //Create a Canvas - auto canvas = tvg::SwCanvas::gen(); - canvas->target(buffer, WIDTH, WIDTH, HEIGHT); - //Star auto shape1 = tvg::Shape::gen(); @@ -51,39 +40,107 @@ void tvgtest() shape2->cubicTo(cx - radius, cy - halfRadius, cx - halfRadius, cy - radius, cx, cy - radius); shape2->fill(255, 0, 0, 255); canvas->push(move(shape2)); +} - canvas->draw(); - canvas->sync(); +/************************************************************************/ +/* Sw Engine Test Code */ +/************************************************************************/ - //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); +static unique_ptr swCanvas; + +void tvgSwTest(uint32_t* buffer) +{ + //Create a Canvas + swCanvas = tvg::SwCanvas::gen(); + swCanvas->target(buffer, WIDTH, 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(swCanvas.get()); } -void win_del(void *data, Evas_Object *o, void *ev) +void drawSwView(void* data, Eo* obj) { - elm_exit(); + swCanvas->draw(); + 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); + int w, h; + elm_glview_size_get(obj, &w, &h); + gl->glViewport(0, 0, w, h); + gl->glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + gl->glClear(GL_COLOR_BUFFER_BIT); + gl->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); + gl->glEnable(GL_BLEND); + + glCanvas->draw(); + glCanvas->sync(); +} + + +/************************************************************************/ +/* Main Code */ +/************************************************************************/ + int main(int argc, char **argv) { - tvgtest(); + tvg::CanvasEngine tvgEngine = tvg::CanvasEngine::Sw; - //Show the result using EFL... - elm_init(argc, argv); + if (argc > 1) { + if (!strcmp(argv[1], "gl")) tvgEngine = tvg::CanvasEngine::Gl; + } - Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); - evas_object_smart_callback_add(win, "delete,request", win_del, 0); + //Initialize ThorVG Engine + if (tvgEngine == tvg::CanvasEngine::Sw) { + cout << "tvg engine: software" << endl; + } else { + cout << "tvg engine: opengl" << endl; + } + + //Initialize ThorVG Engine + tvg::Initializer::init(tvgEngine); + + elm_init(argc, argv); - Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); - evas_object_image_size_set(img, WIDTH, HEIGHT); - evas_object_image_data_set(img, buffer); - evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_show(img); + elm_config_accel_preference_set("gl"); - elm_win_resize_object_add(win, img); - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); - evas_object_show(win); + if (tvgEngine == tvg::CanvasEngine::Sw) { + createSwView(); + } else { + createGlView(); + } elm_run(); elm_shutdown(); -} + + //Terminate ThorVG Engine + tvg::Initializer::term(tvgEngine); +} \ No newline at end of file diff --git a/test/testPathCopy.cpp b/test/testPathCopy.cpp index fc3395e..b619f78 100644 --- a/test/testPathCopy.cpp +++ b/test/testPathCopy.cpp @@ -1,22 +1,11 @@ -#include -#include +#include "testCommon.h" -using namespace std; +/************************************************************************/ +/* Drawing Commands */ +/************************************************************************/ -#define WIDTH 800 -#define HEIGHT 800 - -static uint32_t buffer[WIDTH * HEIGHT]; - -void tvgtest() +void tvgDrawCmds(tvg::Canvas* canvas) { - //Initialize ThorVG Engine - tvg::Initializer::init(tvg::CanvasEngine::Sw); - - //Create a Canvas - auto canvas = tvg::SwCanvas::gen(); - canvas->target(buffer, WIDTH, WIDTH, HEIGHT); - /* Star */ //Prepare Path Commands @@ -91,39 +80,107 @@ void tvgtest() shape2->appendPath(cmds2, 6, pts2, 13); //copy path data shape2->fill(255, 255, 0, 255); canvas->push(move(shape2)); +} - canvas->draw(); - canvas->sync(); +/************************************************************************/ +/* Sw Engine Test Code */ +/************************************************************************/ - //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); +static unique_ptr swCanvas; + +void tvgSwTest(uint32_t* buffer) +{ + //Create a Canvas + swCanvas = tvg::SwCanvas::gen(); + swCanvas->target(buffer, WIDTH, 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(swCanvas.get()); } -void win_del(void *data, Evas_Object *o, void *ev) +void drawSwView(void* data, Eo* obj) { - elm_exit(); + swCanvas->draw(); + 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); + int w, h; + elm_glview_size_get(obj, &w, &h); + gl->glViewport(0, 0, w, h); + gl->glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + gl->glClear(GL_COLOR_BUFFER_BIT); + gl->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); + gl->glEnable(GL_BLEND); + + glCanvas->draw(); + glCanvas->sync(); +} + + +/************************************************************************/ +/* Main Code */ +/************************************************************************/ + int main(int argc, char **argv) { - tvgtest(); + tvg::CanvasEngine tvgEngine = tvg::CanvasEngine::Sw; - //Show the result using EFL... - elm_init(argc, argv); + if (argc > 1) { + if (!strcmp(argv[1], "gl")) tvgEngine = tvg::CanvasEngine::Gl; + } - Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); - evas_object_smart_callback_add(win, "delete,request", win_del, 0); + //Initialize ThorVG Engine + if (tvgEngine == tvg::CanvasEngine::Sw) { + cout << "tvg engine: software" << endl; + } else { + cout << "tvg engine: opengl" << endl; + } + + //Initialize ThorVG Engine + tvg::Initializer::init(tvgEngine); + + elm_init(argc, argv); - Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); - evas_object_image_size_set(img, WIDTH, HEIGHT); - evas_object_image_data_set(img, buffer); - evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_show(img); + elm_config_accel_preference_set("gl"); - elm_win_resize_object_add(win, img); - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); - evas_object_show(win); + if (tvgEngine == tvg::CanvasEngine::Sw) { + createSwView(); + } else { + createGlView(); + } elm_run(); elm_shutdown(); -} + + //Terminate ThorVG Engine + tvg::Initializer::term(tvgEngine); +} \ No newline at end of file diff --git a/test/testRadialGradient.cpp b/test/testRadialGradient.cpp index 841c6e1..f12777c 100644 --- a/test/testRadialGradient.cpp +++ b/test/testRadialGradient.cpp @@ -1,21 +1,11 @@ -#include -#include +#include "testCommon.h" -using namespace std; +/************************************************************************/ +/* Drawing Commands */ +/************************************************************************/ -#define WIDTH 800 -#define HEIGHT 800 - -static uint32_t buffer[WIDTH * HEIGHT]; - -void tvgtest() +void tvgDrawCmds(tvg::Canvas* canvas) { - //Initialize ThorVG Engine - tvg::Initializer::init(tvg::CanvasEngine::Sw); - - //Create a Canvas - auto canvas = tvg::SwCanvas::gen(); - canvas->target(buffer, WIDTH, WIDTH, HEIGHT); canvas->reserve(3); //reserve 3 shape nodes (optional) //Prepare Round Rectangle @@ -75,40 +65,108 @@ void tvgtest() shape3->fill(move(fill3)); canvas->push(move(shape3)); +} - //Draw the Shapes onto the Canvas - canvas->draw(); - canvas->sync(); - //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); +/************************************************************************/ +/* 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); + + /* 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 win_del(void *data, Evas_Object *o, void *ev) +void drawSwView(void* data, Eo* obj) { - elm_exit(); + swCanvas->draw(); + 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); + int w, h; + elm_glview_size_get(obj, &w, &h); + gl->glViewport(0, 0, w, h); + gl->glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + gl->glClear(GL_COLOR_BUFFER_BIT); + gl->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); + gl->glEnable(GL_BLEND); + + glCanvas->draw(); + glCanvas->sync(); +} + + +/************************************************************************/ +/* Main Code */ +/************************************************************************/ + int main(int argc, char **argv) { - tvgtest(); + tvg::CanvasEngine tvgEngine = tvg::CanvasEngine::Sw; - //Show the result using EFL... - elm_init(argc, argv); + if (argc > 1) { + if (!strcmp(argv[1], "gl")) tvgEngine = tvg::CanvasEngine::Gl; + } - Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); - evas_object_smart_callback_add(win, "delete,request", win_del, 0); + //Initialize ThorVG Engine + if (tvgEngine == tvg::CanvasEngine::Sw) { + cout << "tvg engine: software" << endl; + } else { + cout << "tvg engine: opengl" << endl; + } + + //Initialize ThorVG Engine + tvg::Initializer::init(tvgEngine); + + elm_init(argc, argv); - Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); - evas_object_image_size_set(img, WIDTH, HEIGHT); - evas_object_image_data_set(img, buffer); - evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_show(img); + elm_config_accel_preference_set("gl"); - elm_win_resize_object_add(win, img); - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); - evas_object_show(win); + if (tvgEngine == tvg::CanvasEngine::Sw) { + createSwView(); + } else { + createGlView(); + } elm_run(); elm_shutdown(); -} + + //Terminate ThorVG Engine + tvg::Initializer::term(tvgEngine); +} \ No newline at end of file diff --git a/test/testScene.cpp b/test/testScene.cpp index c5672c7..e16772a 100644 --- a/test/testScene.cpp +++ b/test/testScene.cpp @@ -1,22 +1,11 @@ -#include -#include +#include "testCommon.h" -using namespace std; +/************************************************************************/ +/* Drawing Commands */ +/************************************************************************/ -#define WIDTH 800 -#define HEIGHT 800 - -static uint32_t buffer[WIDTH * HEIGHT]; - -void tvgtest() +void tvgDrawCmds(tvg::Canvas* canvas) { - //Initialize ThorVG Engine - tvg::Initializer::init(tvg::CanvasEngine::Sw); - - //Create a Canvas - auto canvas = tvg::SwCanvas::gen(); - canvas->target(buffer, WIDTH, WIDTH, HEIGHT); - //Create a Scene auto scene = tvg::Scene::gen(); scene->reserve(3); //reserve 3 shape nodes (optional) @@ -83,39 +72,108 @@ void tvgtest() //Draw the Scene onto the Canvas canvas->push(move(scene)); - canvas->draw(); - canvas->sync(); +} - //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); + +/************************************************************************/ +/* 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); + + /* 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) +{ + swCanvas->draw(); + 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 win_del(void *data, Evas_Object *o, void *ev) +void drawGLview(Evas_Object *obj) { - elm_exit(); + auto gl = elm_glview_gl_api_get(obj); + int w, h; + elm_glview_size_get(obj, &w, &h); + gl->glViewport(0, 0, w, h); + gl->glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + gl->glClear(GL_COLOR_BUFFER_BIT); + gl->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); + gl->glEnable(GL_BLEND); + + glCanvas->draw(); + glCanvas->sync(); } +/************************************************************************/ +/* Main Code */ +/************************************************************************/ + int main(int argc, char **argv) { - tvgtest(); + tvg::CanvasEngine tvgEngine = tvg::CanvasEngine::Sw; - //Show the result using EFL... - elm_init(argc, argv); + if (argc > 1) { + if (!strcmp(argv[1], "gl")) tvgEngine = tvg::CanvasEngine::Gl; + } - Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); - evas_object_smart_callback_add(win, "delete,request", win_del, 0); + //Initialize ThorVG Engine + if (tvgEngine == tvg::CanvasEngine::Sw) { + cout << "tvg engine: software" << endl; + } else { + cout << "tvg engine: opengl" << endl; + } + + //Initialize ThorVG Engine + tvg::Initializer::init(tvgEngine); + + elm_init(argc, argv); - Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); - evas_object_image_size_set(img, WIDTH, HEIGHT); - evas_object_image_data_set(img, buffer); - evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_show(img); + elm_config_accel_preference_set("gl"); - elm_win_resize_object_add(win, img); - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); - evas_object_show(win); + if (tvgEngine == tvg::CanvasEngine::Sw) { + createSwView(); + } else { + createGlView(); + } elm_run(); elm_shutdown(); -} + + //Terminate ThorVG Engine + tvg::Initializer::term(tvgEngine); +} \ No newline at end of file diff --git a/test/testSceneTransform.cpp b/test/testSceneTransform.cpp index 07879c1..7bd8b41 100644 --- a/test/testSceneTransform.cpp +++ b/test/testSceneTransform.cpp @@ -1,22 +1,13 @@ -#include -#include +#include "testCommon.h" -using namespace std; - -#define WIDTH 800 -#define HEIGHT 800 - -static uint32_t buffer[WIDTH * HEIGHT]; -unique_ptr canvas = nullptr; +/************************************************************************/ +/* Drawing Commands */ +/************************************************************************/ tvg::Scene* pScene1 = nullptr; tvg::Scene* pScene2 = nullptr; -void tvgtest() +void tvgDrawCmds(tvg::Canvas* canvas) { - //Create a Canvas - canvas = tvg::SwCanvas::gen(); - canvas->target(buffer, WIDTH, WIDTH, HEIGHT); - //Create a Scene1 auto scene = tvg::Scene::gen(); pScene1 = scene.get(); @@ -94,12 +85,9 @@ void tvgtest() //Draw the Scene onto the Canvas canvas->push(move(scene)); - - canvas->draw(); - canvas->sync(); } -void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) +void tvgUpdateCmds(tvg::Canvas* canvas, float progress) { /* Update scene directly. You can update only necessary properties of this scene, @@ -110,53 +98,132 @@ void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progres //Update shape for drawing (this may work asynchronously) canvas->update(pScene1); +} + + +/************************************************************************/ +/* Sw Engine Test Code */ +/************************************************************************/ + +static unique_ptr swCanvas; - //Draw Next frames - canvas->draw(); - canvas->sync(); +void tvgSwTest(uint32_t* buffer) +{ + //Create a Canvas + swCanvas = tvg::SwCanvas::gen(); + swCanvas->target(buffer, WIDTH, 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(swCanvas.get()); +} + +void transitSwCb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) +{ + tvgUpdateCmds(swCanvas.get(), progress); //Update Efl Canvas Eo* img = (Eo*) effect; evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT); + evas_object_image_pixels_dirty_set(img, EINA_TRUE); +} + +void drawSwView(void* data, Eo* obj) +{ + swCanvas->draw(); + 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); + int w, h; + elm_glview_size_get(obj, &w, &h); + gl->glViewport(0, 0, w, h); + gl->glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + gl->glClear(GL_COLOR_BUFFER_BIT); + gl->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); + gl->glEnable(GL_BLEND); + + glCanvas->draw(); + glCanvas->sync(); } -void win_del(void *data, Evas_Object *o, void *ev) +void transitGlCb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) { - elm_exit(); + tvgUpdateCmds(glCanvas.get(), progress); } + +/************************************************************************/ +/* 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 - tvg::Initializer::init(tvg::CanvasEngine::Sw); + if (tvgEngine == tvg::CanvasEngine::Sw) { + cout << "tvg engine: software" << endl; + } else { + cout << "tvg engine: opengl" << endl; + } - tvgtest(); + //Initialize ThorVG Engine + tvg::Initializer::init(tvgEngine); - //Show the result using EFL... elm_init(argc, argv); - Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); - evas_object_smart_callback_add(win, "delete,request", win_del, 0); + elm_config_accel_preference_set("gl"); - Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); - evas_object_image_size_set(img, WIDTH, HEIGHT); - evas_object_image_data_set(img, buffer); - evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_show(img); + Elm_Transit *transit = elm_transit_add(); - elm_win_resize_object_add(win, img); - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); - evas_object_show(win); + if (tvgEngine == tvg::CanvasEngine::Sw) { + auto view = createSwView(); + elm_transit_effect_add(transit, transitSwCb, view, nullptr); + } else { + auto view = createGlView(); + elm_transit_effect_add(transit, transitGlCb, view, nullptr); + } - Elm_Transit *transit = elm_transit_add(); - elm_transit_effect_add(transit, transit_cb, img, nullptr); elm_transit_duration_set(transit, 2); elm_transit_repeat_times_set(transit, -1); + elm_transit_auto_reverse_set(transit, EINA_TRUE); elm_transit_go(transit); elm_run(); elm_shutdown(); //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); -} + tvg::Initializer::term(tvgEngine); +} \ No newline at end of file diff --git a/test/testShape.cpp b/test/testShape.cpp index cd1bab1..9aa284d 100644 --- a/test/testShape.cpp +++ b/test/testShape.cpp @@ -1,13 +1,10 @@ -#include -#include -#include +#include "testCommon.h" -using namespace std; - -#define WIDTH 800 -#define HEIGHT 800 +/************************************************************************/ +/* Drawing Commands */ +/************************************************************************/ -unique_ptr tvgDrawCmds() +void tvgDrawCmds(tvg::Canvas* canvas) { //Prepare a Shape (Rectangle + Rectangle + Circle + Circle) auto shape1 = tvg::Shape::gen(); @@ -17,62 +14,55 @@ unique_ptr tvgDrawCmds() shape1->appendCircle(400, 500, 170, 100); //cx, cy, radiusW, radiusH shape1->fill(255, 255, 0, 255); //r, g, b, a - return move(shape1); + canvas->push(move(shape1)); } + /************************************************************************/ /* Sw Engine Test Code */ /************************************************************************/ +static unique_ptr swCanvas; + void tvgSwTest(uint32_t* buffer) { - //Initialize ThorVG Engine - tvg::Initializer::init(tvg::CanvasEngine::Sw); - //Create a Canvas - auto canvas = tvg::SwCanvas::gen(); - canvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas = tvg::SwCanvas::gen(); + swCanvas->target(buffer, WIDTH, 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() */ - canvas->push(tvgDrawCmds()); - canvas->draw(); - canvas->sync(); + tvgDrawCmds(swCanvas.get()); +} - //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); +void drawSwView(void* data, Eo* obj) +{ + swCanvas->draw(); + swCanvas->sync(); } + /************************************************************************/ /* GL Engine Test Code */ /************************************************************************/ -static unique_ptr canvas; +static unique_ptr glCanvas; void initGLview(Evas_Object *obj) { static constexpr auto BPP = 4; - //Initialize ThorVG Engine - tvg::Initializer::init(tvg::CanvasEngine::Gl); - //Create a Canvas - canvas = tvg::GlCanvas::gen(); - canvas->target(nullptr, WIDTH * BPP, WIDTH, HEIGHT); + 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() */ - canvas->push(tvgDrawCmds()); -} - -void delGLview(Evas_Object *obj) -{ - //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Gl); + tvgDrawCmds(glCanvas.get()); } void drawGLview(Evas_Object *obj) @@ -87,65 +77,46 @@ void drawGLview(Evas_Object *obj) gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); gl->glEnable(GL_BLEND); - canvas->draw(); - canvas->sync(); + glCanvas->draw(); + glCanvas->sync(); } + /************************************************************************/ -/* Common Infrastructure Code */ +/* Main Code */ /************************************************************************/ -void win_del(void *data, Evas_Object *o, void *ev) -{ - elm_exit(); -} - int main(int argc, char **argv) { - bool swEngine = true; + tvg::CanvasEngine tvgEngine = tvg::CanvasEngine::Sw; if (argc > 1) { - if (!strcmp(argv[1], "gl")) swEngine = false; + 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; } - if (swEngine) cout << "engine: software" << endl; - else cout << "engine: opengl" << endl; + //Initialize ThorVG Engine + tvg::Initializer::init(tvgEngine); elm_init(argc, argv); - //Show the result using EFL... elm_config_accel_preference_set("gl"); - Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); - evas_object_smart_callback_add(win, "delete,request", win_del, 0); - - Eo* viewer; - - if (swEngine) { - static uint32_t buffer[WIDTH * HEIGHT]; - viewer = evas_object_image_filled_add(evas_object_evas_get(win)); - evas_object_image_size_set(viewer, WIDTH, HEIGHT); - evas_object_image_data_set(viewer, buffer); - evas_object_size_hint_weight_set(viewer, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_show(viewer); - tvgSwTest(buffer); - //GlEngine + if (tvgEngine == tvg::CanvasEngine::Sw) { + createSwView(); } else { - viewer = elm_glview_add(win); - evas_object_size_hint_weight_set(viewer, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - elm_glview_mode_set(viewer, ELM_GLVIEW_ALPHA); - elm_glview_resize_policy_set(viewer, ELM_GLVIEW_RESIZE_POLICY_RECREATE); - elm_glview_render_policy_set(viewer, ELM_GLVIEW_RENDER_POLICY_ON_DEMAND); - elm_glview_init_func_set(viewer, initGLview); - elm_glview_del_func_set(viewer, delGLview); - elm_glview_render_func_set(viewer, drawGLview); - evas_object_show(viewer); + createGlView(); } - elm_win_resize_object_add(win, viewer); - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); - evas_object_show(win); - elm_run(); elm_shutdown(); -} + + //Terminate ThorVG Engine + tvg::Initializer::term(tvgEngine); +} \ No newline at end of file diff --git a/test/testStroke.cpp b/test/testStroke.cpp index bc50dca..493bbde 100644 --- a/test/testStroke.cpp +++ b/test/testStroke.cpp @@ -1,23 +1,11 @@ -#include -#include +#include "testCommon.h" -using namespace std; +/************************************************************************/ +/* Drawing Commands */ +/************************************************************************/ -#define WIDTH 800 -#define HEIGHT 800 - -static uint32_t buffer[WIDTH * HEIGHT]; - - -void tvgtest() +void tvgDrawCmds(tvg::Canvas* canvas) { - //Initialize ThorVG Engine - tvg::Initializer::init(tvg::CanvasEngine::Sw); - - //Create a Canvas - auto canvas = tvg::SwCanvas::gen(); - canvas->target(buffer, WIDTH, WIDTH, HEIGHT); - //Shape 1 auto shape1 = tvg::Shape::gen(); shape1->appendRect(50, 50, 200, 200, 0); @@ -74,40 +62,108 @@ void tvgtest() shape6->stroke(4); canvas->push(move(shape6)); +} - canvas->draw(); - canvas->sync(); +/************************************************************************/ +/* Sw Engine Test Code */ +/************************************************************************/ - //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); +static unique_ptr swCanvas; + +void tvgSwTest(uint32_t* buffer) +{ + //Create a Canvas + swCanvas = tvg::SwCanvas::gen(); + swCanvas->target(buffer, WIDTH, 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(swCanvas.get()); +} + +void drawSwView(void* data, Eo* obj) +{ + swCanvas->draw(); + 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 win_del(void *data, Evas_Object *o, void *ev) +void drawGLview(Evas_Object *obj) { - elm_exit(); + auto gl = elm_glview_gl_api_get(obj); + int w, h; + elm_glview_size_get(obj, &w, &h); + gl->glViewport(0, 0, w, h); + gl->glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + gl->glClear(GL_COLOR_BUFFER_BIT); + gl->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); + gl->glEnable(GL_BLEND); + + glCanvas->draw(); + glCanvas->sync(); } + +/************************************************************************/ +/* Main Code */ +/************************************************************************/ + int main(int argc, char **argv) { - tvgtest(); + tvg::CanvasEngine tvgEngine = tvg::CanvasEngine::Sw; - //Show the result using EFL... - elm_init(argc, argv); + if (argc > 1) { + if (!strcmp(argv[1], "gl")) tvgEngine = tvg::CanvasEngine::Gl; + } - Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); - evas_object_smart_callback_add(win, "delete,request", win_del, 0); + //Initialize ThorVG Engine + if (tvgEngine == tvg::CanvasEngine::Sw) { + cout << "tvg engine: software" << endl; + } else { + cout << "tvg engine: opengl" << endl; + } + + //Initialize ThorVG Engine + tvg::Initializer::init(tvgEngine); + + elm_init(argc, argv); - Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); - evas_object_image_size_set(img, WIDTH, HEIGHT); - evas_object_image_data_set(img, buffer); - evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_show(img); + elm_config_accel_preference_set("gl"); - elm_win_resize_object_add(win, img); - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); - evas_object_show(win); + if (tvgEngine == tvg::CanvasEngine::Sw) { + createSwView(); + } else { + createGlView(); + } elm_run(); elm_shutdown(); -} + + //Terminate ThorVG Engine + tvg::Initializer::term(tvgEngine); +} \ No newline at end of file diff --git a/test/testStrokeLine.cpp b/test/testStrokeLine.cpp index 559479d..d57bf1f 100644 --- a/test/testStrokeLine.cpp +++ b/test/testStrokeLine.cpp @@ -1,22 +1,11 @@ -#include -#include +#include "testCommon.h" -using namespace std; +/************************************************************************/ +/* Drawing Commands */ +/************************************************************************/ -#define WIDTH 800 -#define HEIGHT 800 - -static uint32_t buffer[WIDTH * HEIGHT]; - -void tvgtest() +void tvgDrawCmds(tvg::Canvas* canvas) { - //Initialize ThorVG Engine - tvg::Initializer::init(tvg::CanvasEngine::Sw); - - //Create a Canvas - auto canvas = tvg::SwCanvas::gen(); - canvas->target(buffer, WIDTH, WIDTH, HEIGHT); - //Test for Stroke Width for (int i = 0; i < 10; ++i) { auto shape = tvg::Shape::gen(); @@ -28,7 +17,6 @@ void tvgtest() canvas->push(move(shape)); } - //Test for StrokeJoin & StrokeCap auto shape1 = tvg::Shape::gen(); shape1->moveTo(20, 350); @@ -111,39 +99,108 @@ void tvgtest() float dashPattern3[2] = {10, 10}; shape6->stroke(dashPattern3, 2); canvas->push(move(shape6)); +} - canvas->draw(); - canvas->sync(); - //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); +/************************************************************************/ +/* 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); + + /* 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) +{ + swCanvas->draw(); + 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 win_del(void *data, Evas_Object *o, void *ev) +void drawGLview(Evas_Object *obj) { - elm_exit(); + auto gl = elm_glview_gl_api_get(obj); + int w, h; + elm_glview_size_get(obj, &w, &h); + gl->glViewport(0, 0, w, h); + gl->glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + gl->glClear(GL_COLOR_BUFFER_BIT); + gl->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); + gl->glEnable(GL_BLEND); + + glCanvas->draw(); + glCanvas->sync(); } + +/************************************************************************/ +/* Main Code */ +/************************************************************************/ + int main(int argc, char **argv) { - tvgtest(); + tvg::CanvasEngine tvgEngine = tvg::CanvasEngine::Sw; - //Show the result using EFL... - elm_init(argc, argv); + if (argc > 1) { + if (!strcmp(argv[1], "gl")) tvgEngine = tvg::CanvasEngine::Gl; + } - Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); - evas_object_smart_callback_add(win, "delete,request", win_del, 0); + //Initialize ThorVG Engine + if (tvgEngine == tvg::CanvasEngine::Sw) { + cout << "tvg engine: software" << endl; + } else { + cout << "tvg engine: opengl" << endl; + } - Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); - evas_object_image_size_set(img, WIDTH, HEIGHT); - evas_object_image_data_set(img, buffer); - evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_show(img); + //Initialize ThorVG Engine + tvg::Initializer::init(tvgEngine); - elm_win_resize_object_add(win, img); - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); - evas_object_show(win); + elm_init(argc, argv); + + elm_config_accel_preference_set("gl"); + + if (tvgEngine == tvg::CanvasEngine::Sw) { + createSwView(); + } else { + createGlView(); + } elm_run(); elm_shutdown(); -} + + //Terminate ThorVG Engine + tvg::Initializer::term(tvgEngine); +} \ No newline at end of file diff --git a/test/testSvg.cpp b/test/testSvg.cpp index 1ae4fe0..938d37a 100644 --- a/test/testSvg.cpp +++ b/test/testSvg.cpp @@ -1,77 +1,140 @@ -#include -#include +#include "testCommon.h" -using namespace std; +/************************************************************************/ +/* Drawing Commands */ +/************************************************************************/ -#define WIDTH 800 -#define HEIGHT 800 +#define NUM_PER_LINE 3 -static uint32_t buffer[WIDTH * HEIGHT]; - -unique_ptr canvas = nullptr; +int x = 30; +int y = 30; int count = 0; -static const int numberPerLine = 3; - -static int x = 30; -static int y = 30; - void svgDirCallback(const char* name, const char* path, void* data) { + tvg::Canvas* canvas = static_cast(data); + auto scene = tvg::Scene::gen(); + char buf[255]; sprintf(buf,"%s/%s", path, name); + scene->load(buf); - printf("SVG Load : %s\n", buf); - scene->translate(((WIDTH - (x * 2)) / numberPerLine) * (count % numberPerLine) + x, ((HEIGHT - (y * 2))/ numberPerLine) * (int)((float)count / (float)numberPerLine) + y); + scene->translate(((WIDTH - (x * 2)) / NUM_PER_LINE) * (count % NUM_PER_LINE) + x, ((HEIGHT - (y * 2))/ NUM_PER_LINE) * (int)((float)count / (float)NUM_PER_LINE) + y); canvas->push(move(scene)); + count++; + + cout << "SVG: " << buf << endl; } +void tvgDrawCmds(tvg::Canvas* canvas) +{ + auto shape1 = tvg::Shape::gen(); + shape1->appendRect(0, 0, WIDTH, HEIGHT, 0); //x, y, w, h, cornerRadius + shape1->fill(255, 255, 255, 255); //r, g, b, a -void win_del(void* data, Evas_Object* o, void* ev) + canvas->push(move(shape1)); + + eina_file_dir_list("./svgs", EINA_TRUE, svgDirCallback, canvas); +} + + +/************************************************************************/ +/* Sw Engine Test Code */ +/************************************************************************/ + +static unique_ptr swCanvas; + +void tvgSwTest(uint32_t* buffer) { - elm_exit(); + //Create a Canvas + swCanvas = tvg::SwCanvas::gen(); + swCanvas->target(buffer, WIDTH, 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(swCanvas.get()); } +void drawSwView(void* data, Eo* obj) +{ + swCanvas->draw(); + swCanvas->sync(); +} -int main(int argc, char** argv) + +/************************************************************************/ +/* GL Engine Test Code */ +/************************************************************************/ + +static unique_ptr glCanvas; + +void initGLview(Evas_Object *obj) { - //Initialize ThorVG Engine - tvg::Initializer::init(tvg::CanvasEngine::Sw); + static constexpr auto BPP = 4; //Create a Canvas - canvas = tvg::SwCanvas::gen(); - canvas->target(buffer, WIDTH, WIDTH, HEIGHT); + 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()); +} - //Draw white background - auto scene = tvg::Scene::gen(); - auto shape1 = tvg::Shape::gen(); - shape1->appendRect(0, 0, WIDTH, HEIGHT, 0); - shape1->fill(255, 255, 255, 255); - scene->push(move(shape1)); - canvas->push(move(scene)); +void drawGLview(Evas_Object *obj) +{ + auto gl = elm_glview_gl_api_get(obj); + int w, h; + elm_glview_size_get(obj, &w, &h); + gl->glViewport(0, 0, w, h); + gl->glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + gl->glClear(GL_COLOR_BUFFER_BIT); + gl->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); + gl->glEnable(GL_BLEND); + + glCanvas->draw(); + glCanvas->sync(); +} - eina_file_dir_list("./svgs", EINA_TRUE, svgDirCallback, NULL); - canvas->draw(); - canvas->sync(); +/************************************************************************/ +/* Main Code */ +/************************************************************************/ - //Show the result using EFL... - elm_init(argc, argv); +int main(int argc, char **argv) +{ + tvg::CanvasEngine tvgEngine = tvg::CanvasEngine::Sw; - Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); - evas_object_smart_callback_add(win, "delete,request", win_del, 0); + 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; + } + + //Initialize ThorVG Engine + tvg::Initializer::init(tvgEngine); + + elm_init(argc, argv); - Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); - evas_object_image_size_set(img, WIDTH, HEIGHT); - evas_object_image_data_set(img, buffer); - evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_show(img); + elm_config_accel_preference_set("gl"); - elm_win_resize_object_add(win, img); - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); - evas_object_show(win); + if (tvgEngine == tvg::CanvasEngine::Sw) { + createSwView(); + } else { + createGlView(); + } elm_run(); elm_shutdown(); diff --git a/test/testTransform.cpp b/test/testTransform.cpp index dd3423a..c017f24 100644 --- a/test/testTransform.cpp +++ b/test/testTransform.cpp @@ -1,23 +1,14 @@ -#include -#include +#include "testCommon.h" -using namespace std; - -#define WIDTH 800 -#define HEIGHT 800 - -static uint32_t buffer[WIDTH * HEIGHT]; -unique_ptr canvas = nullptr; +/************************************************************************/ +/* Drawing Commands */ +/************************************************************************/ tvg::Shape* pShape = nullptr; tvg::Shape* pShape2 = nullptr; tvg::Shape* pShape3 = nullptr; -void tvgtest() +void tvgDrawCmds(tvg::Canvas* canvas) { - //Create a Canvas - canvas = tvg::SwCanvas::gen(); - canvas->target(buffer, WIDTH, WIDTH, HEIGHT); - //Shape1 auto shape = tvg::Shape::gen(); @@ -51,13 +42,9 @@ void tvgtest() shape3->fill(255, 0, 255, 255); shape3->translate(400, 400); canvas->push(move(shape3)); - - //Draw first frame - canvas->draw(); - canvas->sync(); } -void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) +void tvgUpdateCmds(tvg::Canvas* canvas, float progress) { /* Update shape directly. You can update only necessary properties of this shape, @@ -79,46 +66,124 @@ void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progres pShape3->rotate(-360 * progress); pShape3->scale(0.5 + progress); canvas->update(pShape3); +} + + +/************************************************************************/ +/* Sw Engine Test Code */ +/************************************************************************/ + +static unique_ptr swCanvas; - //Draw Next frames - canvas->draw(); - canvas->sync(); +void tvgSwTest(uint32_t* buffer) +{ + //Create a Canvas + swCanvas = tvg::SwCanvas::gen(); + swCanvas->target(buffer, WIDTH, 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(swCanvas.get()); +} + +void transitSwCb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) +{ + tvgUpdateCmds(swCanvas.get(), progress); //Update Efl Canvas Eo* img = (Eo*) effect; evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT); + evas_object_image_pixels_dirty_set(img, EINA_TRUE); +} + +void drawSwView(void* data, Eo* obj) +{ + swCanvas->draw(); + 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); + int w, h; + elm_glview_size_get(obj, &w, &h); + gl->glViewport(0, 0, w, h); + gl->glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + gl->glClear(GL_COLOR_BUFFER_BIT); + gl->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); + gl->glEnable(GL_BLEND); + + glCanvas->draw(); + glCanvas->sync(); } -void win_del(void *data, Evas_Object *o, void *ev) +void transitGlCb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) { - elm_exit(); + tvgUpdateCmds(glCanvas.get(), progress); } + +/************************************************************************/ +/* 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 - tvg::Initializer::init(tvg::CanvasEngine::Sw); + if (tvgEngine == tvg::CanvasEngine::Sw) { + cout << "tvg engine: software" << endl; + } else { + cout << "tvg engine: opengl" << endl; + } - tvgtest(); + //Initialize ThorVG Engine + tvg::Initializer::init(tvgEngine); - //Show the result using EFL... elm_init(argc, argv); - Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); - evas_object_smart_callback_add(win, "delete,request", win_del, 0); + elm_config_accel_preference_set("gl"); - Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); - evas_object_image_size_set(img, WIDTH, HEIGHT); - evas_object_image_data_set(img, buffer); - evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_show(img); + Elm_Transit *transit = elm_transit_add(); - elm_win_resize_object_add(win, img); - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); - evas_object_show(win); + if (tvgEngine == tvg::CanvasEngine::Sw) { + auto view = createSwView(); + elm_transit_effect_add(transit, transitSwCb, view, nullptr); + } else { + auto view = createGlView(); + elm_transit_effect_add(transit, transitGlCb, view, nullptr); + } - Elm_Transit *transit = elm_transit_add(); - elm_transit_effect_add(transit, transit_cb, img, nullptr); elm_transit_duration_set(transit, 2); elm_transit_repeat_times_set(transit, -1); elm_transit_auto_reverse_set(transit, EINA_TRUE); @@ -128,5 +193,5 @@ int main(int argc, char **argv) elm_shutdown(); //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); -} + tvg::Initializer::term(tvgEngine); +} \ No newline at end of file diff --git a/test/testUpdate.cpp b/test/testUpdate.cpp index 3a39913..d28207a 100644 --- a/test/testUpdate.cpp +++ b/test/testUpdate.cpp @@ -1,32 +1,19 @@ -#include -#include +#include "testCommon.h" -using namespace std; +/************************************************************************/ +/* Drawing Commands */ +/************************************************************************/ -#define WIDTH 800 -#define HEIGHT 800 - -static uint32_t buffer[WIDTH * HEIGHT]; -unique_ptr canvas = nullptr; - -void tvgtest() +void tvgDrawCmds(tvg::Canvas* canvas) { - //Create a Canvas - canvas = tvg::SwCanvas::gen(); - canvas->target(buffer, WIDTH, WIDTH, HEIGHT); - //Shape auto shape = tvg::Shape::gen(); shape->appendRect(-100, -100, 200, 200, 0); shape->fill(255, 255, 255, 255); canvas->push(move(shape)); - - //Draw first frame - canvas->draw(); - canvas->sync(); } -void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) +void tvgUpdateCmds(tvg::Canvas* canvas, float progress) { //Explicitly clear all retained paint nodes. canvas->clear(); @@ -40,46 +27,124 @@ void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progres shape->rotate(360 * progress); canvas->push(move(shape)); +} + + +/************************************************************************/ +/* Sw Engine Test Code */ +/************************************************************************/ + +static unique_ptr swCanvas; - //Draw Next frames - canvas->draw(); - canvas->sync(); +void tvgSwTest(uint32_t* buffer) +{ + //Create a Canvas + swCanvas = tvg::SwCanvas::gen(); + swCanvas->target(buffer, WIDTH, 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(swCanvas.get()); +} + +void transitSwCb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) +{ + tvgUpdateCmds(swCanvas.get(), progress); //Update Efl Canvas Eo* img = (Eo*) effect; evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT); + evas_object_image_pixels_dirty_set(img, EINA_TRUE); +} + +void drawSwView(void* data, Eo* obj) +{ + swCanvas->draw(); + 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); + int w, h; + elm_glview_size_get(obj, &w, &h); + gl->glViewport(0, 0, w, h); + gl->glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + gl->glClear(GL_COLOR_BUFFER_BIT); + gl->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); + gl->glEnable(GL_BLEND); + + glCanvas->draw(); + glCanvas->sync(); } -void win_del(void *data, Evas_Object *o, void *ev) +void transitGlCb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) { - elm_exit(); + tvgUpdateCmds(glCanvas.get(), progress); } + +/************************************************************************/ +/* 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 - tvg::Initializer::init(tvg::CanvasEngine::Sw); + if (tvgEngine == tvg::CanvasEngine::Sw) { + cout << "tvg engine: software" << endl; + } else { + cout << "tvg engine: opengl" << endl; + } - tvgtest(); + //Initialize ThorVG Engine + tvg::Initializer::init(tvgEngine); - //Show the result using EFL... elm_init(argc, argv); - Eo* win = elm_win_util_standard_add(NULL, "ThorVG Test"); - evas_object_smart_callback_add(win, "delete,request", win_del, 0); + elm_config_accel_preference_set("gl"); - Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); - evas_object_image_size_set(img, WIDTH, HEIGHT); - evas_object_image_data_set(img, buffer); - evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_show(img); + Elm_Transit *transit = elm_transit_add(); - elm_win_resize_object_add(win, img); - evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); - evas_object_show(win); + if (tvgEngine == tvg::CanvasEngine::Sw) { + auto view = createSwView(); + elm_transit_effect_add(transit, transitSwCb, view, nullptr); + } else { + auto view = createGlView(); + elm_transit_effect_add(transit, transitGlCb, view, nullptr); + } - Elm_Transit *transit = elm_transit_add(); - elm_transit_effect_add(transit, transit_cb, img, nullptr); elm_transit_duration_set(transit, 2); elm_transit_repeat_times_set(transit, -1); elm_transit_auto_reverse_set(transit, EINA_TRUE); @@ -89,5 +154,5 @@ int main(int argc, char **argv) elm_shutdown(); //Terminate ThorVG Engine - tvg::Initializer::term(tvg::CanvasEngine::Sw); -} + tvg::Initializer::term(tvgEngine); +} \ No newline at end of file -- 2.7.4 From 8bb8710815d37302b3821514d5d03efb021e718e Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 30 Jun 2020 10:24:56 +0900 Subject: [PATCH 13/16] test svg: remove white trailings Change-Id: Ie23ffdd420eb9742b21350dfffd5b29ae0515be3 --- test/testSvg.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/testSvg.cpp b/test/testSvg.cpp index 938d37a..4da0349 100644 --- a/test/testSvg.cpp +++ b/test/testSvg.cpp @@ -20,7 +20,7 @@ void svgDirCallback(const char* name, const char* path, void* data) sprintf(buf,"%s/%s", path, name); scene->load(buf); - scene->translate(((WIDTH - (x * 2)) / NUM_PER_LINE) * (count % NUM_PER_LINE) + x, ((HEIGHT - (y * 2))/ NUM_PER_LINE) * (int)((float)count / (float)NUM_PER_LINE) + y); + scene->translate(((WIDTH - (x * 2)) / NUM_PER_LINE) * (count % NUM_PER_LINE) + x, ((HEIGHT - (y * 2))/ NUM_PER_LINE) * (int)((float)count / (float)NUM_PER_LINE) + y); canvas->push(move(scene)); count++; -- 2.7.4 From 4bc0b584f3a50540042ddaec39f930e3e52575db Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 30 Jun 2020 12:38:01 +0900 Subject: [PATCH 14/16] sw_engine: flush all processing data when clear() is requested. there was a missing point which occured corrupted data in multi-processing. Change-Id: Ifb28ee82852e488d23d45b4b75f0a6c70bb428b2 --- src/lib/sw_engine/tvgSwRenderer.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index ac5464e..4f09c60 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -47,16 +47,16 @@ static RenderInitializer renderInit; SwRenderer::~SwRenderer() { - if (progress.valid()) progress.get(); + flush(); } bool SwRenderer::clear() { - if (progress.valid()) return false; - return true; + return flush(); } + bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) { if (!buffer || stride == 0 || w == 0 || h == 0) return false; @@ -117,11 +117,15 @@ void SwRenderer::doRender() bool SwRenderer::flush() { - if (progress.valid()) { - progress.get(); - return true; + while (prepareTasks.size() > 0) { + auto task = prepareTasks.front(); + if (task->progress.valid()) task->progress.get(); + prepareTasks.pop(); } - return false; + + if (progress.valid()) progress.get(); + + return true; } -- 2.7.4 From 61cb144122f381c2bb32e44ff6a41f162ad96ea4 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 30 Jun 2020 13:08:09 +0900 Subject: [PATCH 15/16] test: revise sample. this patch adds the showcase how to handle exceptional cases. Change-Id: Ic8e3c740bbf613f4dccace511b6c8d93b987a10c --- test/testAsync.cpp | 18 ++++++++++-------- test/testBlending.cpp | 20 +++++++++++--------- test/testBoundary.cpp | 20 +++++++++++--------- test/testCustomTransform.cpp | 12 +++++++----- test/testDirectUpdate.cpp | 25 ++++++++++++++----------- test/testGradientTransform.cpp | 22 ++++++++++++---------- test/testLinearGradient.cpp | 16 +++++++++------- test/testMultiShapes.cpp | 16 +++++++++------- test/testPath.cpp | 16 ++++++++++------ test/testPathCopy.cpp | 16 +++++++++------- test/testRadialGradient.cpp | 16 +++++++++------- test/testScene.cpp | 10 ++++++---- test/testSceneTransform.cpp | 10 ++++++---- test/testShape.cpp | 10 ++++++---- test/testStroke.cpp | 22 ++++++++++++---------- test/testStrokeLine.cpp | 24 +++++++++++++----------- test/testSvg.cpp | 24 ++++++++++++++---------- test/testTransform.cpp | 22 ++++++++++++---------- test/testUpdate.cpp | 12 +++++++----- 19 files changed, 187 insertions(+), 144 deletions(-) diff --git a/test/testAsync.cpp b/test/testAsync.cpp index a8ac2b0..666e7bb 100644 --- a/test/testAsync.cpp +++ b/test/testAsync.cpp @@ -13,11 +13,10 @@ bool tvgUpdateCmds(tvg::Canvas* canvas) auto t = ecore_time_get(); //Explicitly clear all retained paint nodes. - if (canvas->clear() != tvg::Result::Success) - { - //Logically wrong! Probably, you missed to call sync() before. - return false; - } + if (canvas->clear() != tvg::Result::Success) { + //Logically wrong! Probably, you missed to call sync() before. + return false; + } t1 = t; t2 = ecore_time_get(); @@ -45,7 +44,10 @@ bool tvgUpdateCmds(tvg::Canvas* canvas) fill->colorStops(colorStops, 3); shape->fill(move(fill)); - canvas->push(move(shape)); + if (canvas->push(move(shape)) != tvg::Result::Success) { + //Did you call clear()? Make it sure if canvas is on rendering + break; + } } t3 = ecore_time_get(); @@ -72,7 +74,7 @@ Eina_Bool animSwCb(void* data) if (!tvgUpdateCmds(swCanvas.get())) return ECORE_CALLBACK_RENEW; //Drawing task can be performed asynchronously. - swCanvas->draw(); + if (swCanvas->draw() != tvg::Result::Success) return false; //Update Efl Canvas Eo* img = (Eo*) data; @@ -174,4 +176,4 @@ int main(int argc, char **argv) //Terminate ThorVG Engine tvg::Initializer::term(tvgEngine); -} \ No newline at end of file +} diff --git a/test/testBlending.cpp b/test/testBlending.cpp index 7794689..733e60b 100644 --- a/test/testBlending.cpp +++ b/test/testBlending.cpp @@ -12,19 +12,19 @@ void tvgDrawCmds(tvg::Canvas* canvas) auto shape1 = tvg::Shape::gen(); shape1->appendRect(0, 0, 400, 400, 50); //x, y, w, h, cornerRadius shape1->fill(0, 255, 0, 255); //r, g, b, a - canvas->push(move(shape1)); + if (canvas->push(move(shape1)) != tvg::Result::Success) return; //Prepare Circle auto shape2 = tvg::Shape::gen(); shape2->appendCircle(400, 400, 200, 200); //cx, cy, radiusW, radiusH shape2->fill(170, 170, 0, 170); //r, g, b, a - canvas->push(move(shape2)); + if (canvas->push(move(shape2)) != tvg::Result::Success) return; //Prepare Ellipse auto shape3 = tvg::Shape::gen(); shape3->appendCircle(400, 400, 250, 100); //cx, cy, radiusW, radiusH shape3->fill(100, 100, 100, 100); //r, g, b, a - canvas->push(move(shape3)); + if (canvas->push(move(shape3)) != tvg::Result::Success) return; //Prepare Star auto shape4 = tvg::Shape::gen(); @@ -40,13 +40,13 @@ void tvgDrawCmds(tvg::Canvas* canvas) shape4->lineTo(146, 343); shape4->close(); shape4->fill(200, 0, 200, 200); - canvas->push(move(shape4)); + if (canvas->push(move(shape4)) != tvg::Result::Success) return; //Prepare Opaque Ellipse auto shape5 = tvg::Shape::gen(); shape5->appendCircle(600, 650, 200, 150); shape5->fill(0, 0, 255, 255); - canvas->push(move(shape5)); + if (canvas->push(move(shape5)) != tvg::Result::Success) return; } @@ -71,8 +71,9 @@ void tvgSwTest(uint32_t* buffer) void drawSwView(void* data, Eo* obj) { - swCanvas->draw(); - swCanvas->sync(); + if (swCanvas->draw() == tvg::Result::Success) { + swCanvas->sync(); + } } @@ -109,8 +110,9 @@ void drawGLview(Evas_Object *obj) gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); gl->glEnable(GL_BLEND); - glCanvas->draw(); - glCanvas->sync(); + if (glCanvas->draw() == tvg::Result::Success) { + glCanvas->sync(); + } } diff --git a/test/testBoundary.cpp b/test/testBoundary.cpp index e74ac5e..fcfcd68 100644 --- a/test/testBoundary.cpp +++ b/test/testBoundary.cpp @@ -12,31 +12,31 @@ void tvgDrawCmds(tvg::Canvas* canvas) auto shape1 = tvg::Shape::gen(); shape1->appendRect(-100, -100, 1000, 1000, 50); shape1->fill(255, 255, 255, 255); - canvas->push(move(shape1)); + if (canvas->push(move(shape1)) != tvg::Result::Success) return; //Prepare Shape2 auto shape2 = tvg::Shape::gen(); shape2->appendRect(-100, -100, 250, 250, 50); shape2->fill(0, 0, 255, 255); - canvas->push(move(shape2)); + if (canvas->push(move(shape2)) != tvg::Result::Success) return; //Prepare Shape3 auto shape3 = tvg::Shape::gen(); shape3->appendRect(500, 500, 550, 550, 0); shape3->fill(0, 255, 255, 255); - canvas->push(move(shape3)); + if (canvas->push(move(shape3)) != tvg::Result::Success) return; //Prepare Shape4 auto shape4 = tvg::Shape::gen(); shape4->appendCircle(800, 100, 200, 200); shape4->fill(255, 255, 0, 255); - canvas->push(move(shape4)); + if (canvas->push(move(shape4)) != tvg::Result::Success) return; //Prepare Shape5 auto shape5 = tvg::Shape::gen(); shape5->appendCircle(200, 650, 250, 200); shape5->fill(0, 0, 0, 255); - canvas->push(move(shape5)); + if (canvas->push(move(shape5)) != tvg::Result::Success) return; } /************************************************************************/ @@ -60,8 +60,9 @@ void tvgSwTest(uint32_t* buffer) void drawSwView(void* data, Eo* obj) { - swCanvas->draw(); - swCanvas->sync(); + if (swCanvas->draw() == tvg::Result::Success) { + swCanvas->sync(); + } } @@ -98,8 +99,9 @@ void drawGLview(Evas_Object *obj) gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); gl->glEnable(GL_BLEND); - glCanvas->draw(); - glCanvas->sync(); + if (glCanvas->draw() == tvg::Result::Success) { + glCanvas->sync(); + } } diff --git a/test/testCustomTransform.cpp b/test/testCustomTransform.cpp index 1109a21..d87b481 100644 --- a/test/testCustomTransform.cpp +++ b/test/testCustomTransform.cpp @@ -26,7 +26,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) shape->lineTo(-53, -5.5); shape->close(); shape->fill(0, 0, 255, 255); - canvas->push(move(shape)); + if (canvas->push(move(shape)) != tvg::Result::Success) return; } void tvgUpdateCmds(tvg::Canvas* canvas, float progress) @@ -107,8 +107,9 @@ void transitSwCb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progre void drawSwView(void* data, Eo* obj) { - swCanvas->draw(); - swCanvas->sync(); + if (swCanvas->draw() == tvg::Result::Success) { + swCanvas->sync(); + } } @@ -145,8 +146,9 @@ void drawGLview(Evas_Object *obj) gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); gl->glEnable(GL_BLEND); - glCanvas->draw(); - glCanvas->sync(); + if (glCanvas->draw() == tvg::Result::Success) { + glCanvas->sync(); + } } void transitGlCb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) diff --git a/test/testDirectUpdate.cpp b/test/testDirectUpdate.cpp index 93b2dfb..529e067 100644 --- a/test/testDirectUpdate.cpp +++ b/test/testDirectUpdate.cpp @@ -21,7 +21,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) shape->stroke(0, 0, 255, 255); shape->stroke(1); - canvas->push(move(shape)); + if (canvas->push(move(shape)) != tvg::Result::Success) return; } void tvgUpdateCmds(tvg::Canvas* canvas, float progress) @@ -30,13 +30,14 @@ void tvgUpdateCmds(tvg::Canvas* canvas, float progress) You can update only necessary properties of this shape, while retaining other properties. */ - pShape->reset(); //reset path + //Reset Shape + if (pShape->reset() == tvg::Result::Success) { + pShape->appendRect(-100 + (800 * progress), -100 + (800 * progress), 200, 200, (100 * progress)); + pShape->stroke(30 * progress); - pShape->appendRect(-100 + (800 * progress), -100 + (800 * progress), 200, 200, (100 * progress)); - pShape->stroke(30 * progress); - - //Update shape for drawing (this may work asynchronously) - canvas->update(pShape); + //Update shape for drawing (this may work asynchronously) + canvas->update(pShape); + } } @@ -71,8 +72,9 @@ void transitSwCb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progre void drawSwView(void* data, Eo* obj) { - swCanvas->draw(); - swCanvas->sync(); + if (swCanvas->draw() == tvg::Result::Success) { + swCanvas->sync(); + } } @@ -109,8 +111,9 @@ void drawGLview(Evas_Object *obj) gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); gl->glEnable(GL_BLEND); - glCanvas->draw(); - glCanvas->sync(); + if (glCanvas->draw() == tvg::Result::Success) { + glCanvas->sync(); + } } void transitGlCb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) diff --git a/test/testGradientTransform.cpp b/test/testGradientTransform.cpp index b77062b..3edb5d8 100644 --- a/test/testGradientTransform.cpp +++ b/test/testGradientTransform.cpp @@ -34,7 +34,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) fill->colorStops(colorStops, 3); shape->fill(move(fill)); shape->translate(385, 400); - canvas->push(move(shape)); + if (canvas->push(move(shape)) != tvg::Result::Success) return; //Shape2 auto shape2 = tvg::Shape::gen(); @@ -53,7 +53,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) fill2->colorStops(colorStops2, 2); shape2->fill(move(fill2)); - canvas->push(move(shape2)); + if (canvas->push(move(shape2)) != tvg::Result::Success) return; //Shape3 auto shape3 = tvg::Shape::gen(); @@ -78,7 +78,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) shape3->fill(move(fill3)); shape3->translate(400, 400); - canvas->push(move(shape3)); + if (canvas->push(move(shape3)) != tvg::Result::Success) return; } void tvgUpdateCmds(tvg::Canvas* canvas, float progress) @@ -92,17 +92,17 @@ void tvgUpdateCmds(tvg::Canvas* canvas, float progress) pShape->rotate(360 * progress); //Update shape for drawing (this may work asynchronously) - canvas->update(pShape); + if (canvas->update(pShape) != tvg::Result::Success) return; //Update Shape2 pShape2->rotate(360 * progress); pShape2->translate(400 + progress * 300, 400); - canvas->update(pShape2); + if (canvas->update(pShape2) != tvg::Result::Success) return; //Update Shape3 pShape3->rotate(-360 * progress); pShape3->scale(0.5 + progress); - canvas->update(pShape3); + if (canvas->update(pShape3) != tvg::Result::Success) return; } @@ -137,8 +137,9 @@ void transitSwCb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progre void drawSwView(void* data, Eo* obj) { - swCanvas->draw(); - swCanvas->sync(); + if (swCanvas->draw() == tvg::Result::Success) { + swCanvas->sync(); + } } @@ -175,8 +176,9 @@ void drawGLview(Evas_Object *obj) gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); gl->glEnable(GL_BLEND); - glCanvas->draw(); - glCanvas->sync(); + if (glCanvas->draw() == tvg::Result::Success) { + glCanvas->sync(); + } } void transitGlCb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) diff --git a/test/testLinearGradient.cpp b/test/testLinearGradient.cpp index 36251f5..63e690a 100644 --- a/test/testLinearGradient.cpp +++ b/test/testLinearGradient.cpp @@ -24,7 +24,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) fill->colorStops(colorStops, 2); shape1->fill(move(fill)); - canvas->push(move(shape1)); + if (canvas->push(move(shape1)) != tvg::Result::Success) return; //Prepare Circle auto shape2 = tvg::Shape::gen(); @@ -43,7 +43,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) fill2->colorStops(colorStops2, 3); shape2->fill(move(fill2)); - canvas->push(move(shape2)); + if (canvas->push(move(shape2)) != tvg::Result::Success) return; //Prepare Ellipse @@ -64,7 +64,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) fill3->colorStops(colorStops3, 4); shape3->fill(move(fill3)); - canvas->push(move(shape3)); + if (canvas->push(move(shape3)) != tvg::Result::Success) return; } @@ -89,8 +89,9 @@ void tvgSwTest(uint32_t* buffer) void drawSwView(void* data, Eo* obj) { - swCanvas->draw(); - swCanvas->sync(); + if (swCanvas->draw() == tvg::Result::Success) { + swCanvas->sync(); + } } @@ -127,8 +128,9 @@ void drawGLview(Evas_Object *obj) gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); gl->glEnable(GL_BLEND); - glCanvas->draw(); - glCanvas->sync(); + if (glCanvas->draw() == tvg::Result::Success) { + glCanvas->sync(); + } } diff --git a/test/testMultiShapes.cpp b/test/testMultiShapes.cpp index 195547d..73992b6 100644 --- a/test/testMultiShapes.cpp +++ b/test/testMultiShapes.cpp @@ -12,19 +12,19 @@ void tvgDrawCmds(tvg::Canvas* canvas) auto shape1 = tvg::Shape::gen(); shape1->appendRect(0, 0, 400, 400, 50); //x, y, w, h, cornerRadius shape1->fill(0, 255, 0, 255); //r, g, b, a - canvas->push(move(shape1)); + if (canvas->push(move(shape1)) != tvg::Result::Success) return; //Prepare Circle auto shape2 = tvg::Shape::gen(); shape2->appendCircle(400, 400, 200, 200); //cx, cy, radiusW, radiusH shape2->fill(255, 255, 0, 255); //r, g, b, a - canvas->push(move(shape2)); + if (canvas->push(move(shape2)) != tvg::Result::Success) return; //Prepare Ellipse auto shape3 = tvg::Shape::gen(); shape3->appendCircle(600, 600, 150, 100); //cx, cy, radiusW, radiusH shape3->fill(0, 255, 255, 255); //r, g, b, a - canvas->push(move(shape3)); + if (canvas->push(move(shape3)) != tvg::Result::Success) return; } @@ -49,8 +49,9 @@ void tvgSwTest(uint32_t* buffer) void drawSwView(void* data, Eo* obj) { - swCanvas->draw(); - swCanvas->sync(); + if (swCanvas->draw() == tvg::Result::Success) { + swCanvas->sync(); + } } @@ -87,8 +88,9 @@ void drawGLview(Evas_Object *obj) gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); gl->glEnable(GL_BLEND); - glCanvas->draw(); - glCanvas->sync(); + if (glCanvas->draw() == tvg::Result::Success) { + glCanvas->sync(); + } } diff --git a/test/testPath.cpp b/test/testPath.cpp index 49bd738..3fbb834 100644 --- a/test/testPath.cpp +++ b/test/testPath.cpp @@ -22,7 +22,8 @@ void tvgDrawCmds(tvg::Canvas* canvas) shape1->lineTo(146, 143); shape1->close(); shape1->fill(0, 0, 255, 255); - canvas->push(move(shape1)); + if (canvas->push(move(shape1)) != tvg::Result::Success) return; + //Circle auto shape2 = tvg::Shape::gen(); @@ -39,7 +40,8 @@ void tvgDrawCmds(tvg::Canvas* canvas) shape2->cubicTo(cx - halfRadius, cy + radius, cx - radius, cy + halfRadius, cx - radius, cy); shape2->cubicTo(cx - radius, cy - halfRadius, cx - halfRadius, cy - radius, cx, cy - radius); shape2->fill(255, 0, 0, 255); - canvas->push(move(shape2)); + if (canvas->push(move(shape2)) != tvg::Result::Success) return; + } /************************************************************************/ @@ -63,8 +65,9 @@ void tvgSwTest(uint32_t* buffer) void drawSwView(void* data, Eo* obj) { - swCanvas->draw(); - swCanvas->sync(); + if (swCanvas->draw() == tvg::Result::Success) { + swCanvas->sync(); + } } @@ -101,8 +104,9 @@ void drawGLview(Evas_Object *obj) gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); gl->glEnable(GL_BLEND); - glCanvas->draw(); - glCanvas->sync(); + if (glCanvas->draw() == tvg::Result::Success) { + glCanvas->sync(); + } } diff --git a/test/testPathCopy.cpp b/test/testPathCopy.cpp index b619f78..3407f92 100644 --- a/test/testPathCopy.cpp +++ b/test/testPathCopy.cpp @@ -38,8 +38,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) auto shape1 = tvg::Shape::gen(); shape1->appendPath(cmds, 11, pts, 10); //copy path data shape1->fill(0, 255, 0, 255); - canvas->push(move(shape1)); - + if (canvas->push(move(shape1)) != tvg::Result::Success) return; /* Circle */ auto cx = 550.0f; @@ -79,7 +78,8 @@ void tvgDrawCmds(tvg::Canvas* canvas) auto shape2 = tvg::Shape::gen(); shape2->appendPath(cmds2, 6, pts2, 13); //copy path data shape2->fill(255, 255, 0, 255); - canvas->push(move(shape2)); + if (canvas->push(move(shape2)) != tvg::Result::Success) return; + } /************************************************************************/ @@ -103,8 +103,9 @@ void tvgSwTest(uint32_t* buffer) void drawSwView(void* data, Eo* obj) { - swCanvas->draw(); - swCanvas->sync(); + if (swCanvas->draw() == tvg::Result::Success) { + swCanvas->sync(); + } } @@ -141,8 +142,9 @@ void drawGLview(Evas_Object *obj) gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); gl->glEnable(GL_BLEND); - glCanvas->draw(); - glCanvas->sync(); + if (glCanvas->draw() == tvg::Result::Success) { + glCanvas->sync(); + } } diff --git a/test/testRadialGradient.cpp b/test/testRadialGradient.cpp index f12777c..ffec5fa 100644 --- a/test/testRadialGradient.cpp +++ b/test/testRadialGradient.cpp @@ -24,7 +24,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) fill->colorStops(colorStops, 2); shape1->fill(move(fill)); - canvas->push(move(shape1)); + if (canvas->push(move(shape1)) != tvg::Result::Success) return; //Prepare Circle auto shape2 = tvg::Shape::gen(); @@ -43,7 +43,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) fill2->colorStops(colorStops2, 3); shape2->fill(move(fill2)); - canvas->push(move(shape2)); + if (canvas->push(move(shape2)) != tvg::Result::Success) return; //Prepare Ellipse @@ -64,7 +64,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) fill3->colorStops(colorStops3, 4); shape3->fill(move(fill3)); - canvas->push(move(shape3)); + if (canvas->push(move(shape3)) != tvg::Result::Success) return; } @@ -89,8 +89,9 @@ void tvgSwTest(uint32_t* buffer) void drawSwView(void* data, Eo* obj) { - swCanvas->draw(); - swCanvas->sync(); + if (swCanvas->draw() == tvg::Result::Success) { + swCanvas->sync(); + } } @@ -127,8 +128,9 @@ void drawGLview(Evas_Object *obj) gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); gl->glEnable(GL_BLEND); - glCanvas->draw(); - glCanvas->sync(); + if (glCanvas->draw() == tvg::Result::Success) { + glCanvas->sync(); + } } diff --git a/test/testScene.cpp b/test/testScene.cpp index e16772a..5a6b25f 100644 --- a/test/testScene.cpp +++ b/test/testScene.cpp @@ -96,8 +96,9 @@ void tvgSwTest(uint32_t* buffer) void drawSwView(void* data, Eo* obj) { - swCanvas->draw(); - swCanvas->sync(); + if (swCanvas->draw() == tvg::Result::Success) { + swCanvas->sync(); + } } @@ -134,8 +135,9 @@ void drawGLview(Evas_Object *obj) gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); gl->glEnable(GL_BLEND); - glCanvas->draw(); - glCanvas->sync(); + if (glCanvas->draw() == tvg::Result::Success) { + glCanvas->sync(); + } } diff --git a/test/testSceneTransform.cpp b/test/testSceneTransform.cpp index 7bd8b41..8c0898f 100644 --- a/test/testSceneTransform.cpp +++ b/test/testSceneTransform.cpp @@ -132,8 +132,9 @@ void transitSwCb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progre void drawSwView(void* data, Eo* obj) { - swCanvas->draw(); - swCanvas->sync(); + if (swCanvas->draw() == tvg::Result::Success) { + swCanvas->sync(); + } } @@ -170,8 +171,9 @@ void drawGLview(Evas_Object *obj) gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); gl->glEnable(GL_BLEND); - glCanvas->draw(); - glCanvas->sync(); + if (glCanvas->draw() == tvg::Result::Success) { + glCanvas->sync(); + } } void transitGlCb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) diff --git a/test/testShape.cpp b/test/testShape.cpp index 9aa284d..406b369 100644 --- a/test/testShape.cpp +++ b/test/testShape.cpp @@ -39,8 +39,9 @@ void tvgSwTest(uint32_t* buffer) void drawSwView(void* data, Eo* obj) { - swCanvas->draw(); - swCanvas->sync(); + if (swCanvas->draw() == tvg::Result::Success) { + swCanvas->sync(); + } } @@ -77,8 +78,9 @@ void drawGLview(Evas_Object *obj) gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); gl->glEnable(GL_BLEND); - glCanvas->draw(); - glCanvas->sync(); + if (glCanvas->draw() == tvg::Result::Success) { + glCanvas->sync(); + } } diff --git a/test/testStroke.cpp b/test/testStroke.cpp index 493bbde..c7f95df 100644 --- a/test/testStroke.cpp +++ b/test/testStroke.cpp @@ -14,7 +14,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) shape1->stroke(tvg::StrokeJoin::Bevel); //default is Bevel shape1->stroke(10); //width: 10px - canvas->push(move(shape1)); + if (canvas->push(move(shape1)) != tvg::Result::Success) return; //Shape 2 auto shape2 = tvg::Shape::gen(); @@ -24,7 +24,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) shape2->stroke(tvg::StrokeJoin::Round); shape2->stroke(10); - canvas->push(move(shape2)); + if (canvas->push(move(shape2)) != tvg::Result::Success) return; //Shape 3 auto shape3 = tvg::Shape::gen(); @@ -34,7 +34,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) shape3->stroke(tvg::StrokeJoin::Miter); shape3->stroke(10); - canvas->push(move(shape3)); + if (canvas->push(move(shape3)) != tvg::Result::Success) return; //Shape 4 auto shape4 = tvg::Shape::gen(); @@ -43,7 +43,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) shape4->stroke(255, 255, 255, 255); shape4->stroke(1); - canvas->push(move(shape4)); + if (canvas->push(move(shape4)) != tvg::Result::Success) return; //Shape 5 auto shape5 = tvg::Shape::gen(); @@ -52,7 +52,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) shape5->stroke(255, 255, 255, 255); shape5->stroke(2); - canvas->push(move(shape5)); + if (canvas->push(move(shape5)) != tvg::Result::Success) return; //Shape 6 auto shape6 = tvg::Shape::gen(); @@ -61,7 +61,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) shape6->stroke(255, 255, 255, 255); shape6->stroke(4); - canvas->push(move(shape6)); + if (canvas->push(move(shape6)) != tvg::Result::Success) return; } @@ -86,8 +86,9 @@ void tvgSwTest(uint32_t* buffer) void drawSwView(void* data, Eo* obj) { - swCanvas->draw(); - swCanvas->sync(); + if (swCanvas->draw() == tvg::Result::Success) { + swCanvas->sync(); + } } @@ -124,8 +125,9 @@ void drawGLview(Evas_Object *obj) gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); gl->glEnable(GL_BLEND); - glCanvas->draw(); - glCanvas->sync(); + if (glCanvas->draw() == tvg::Result::Success) { + glCanvas->sync(); + } } diff --git a/test/testStrokeLine.cpp b/test/testStrokeLine.cpp index d57bf1f..31e670e 100644 --- a/test/testStrokeLine.cpp +++ b/test/testStrokeLine.cpp @@ -14,7 +14,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) shape->stroke(255, 255, 255, 255); //color: r, g, b, a shape->stroke(i + 1); //stroke width shape->stroke(tvg::StrokeCap::Round); //default is Square - canvas->push(move(shape)); + if (canvas->push(move(shape)) != tvg::Result::Success) return; } //Test for StrokeJoin & StrokeCap @@ -28,7 +28,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) shape1->stroke(10); shape1->stroke(tvg::StrokeJoin::Round); shape1->stroke(tvg::StrokeCap::Round); - canvas->push(move(shape1)); + if (canvas->push(move(shape1)) != tvg::Result::Success) return; auto shape2 = tvg::Shape::gen(); shape2->moveTo(270, 350); @@ -40,7 +40,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) shape2->stroke(10); shape2->stroke(tvg::StrokeJoin::Bevel); shape2->stroke(tvg::StrokeCap::Square); - canvas->push(move(shape2)); + if (canvas->push(move(shape2)) != tvg::Result::Success) return; auto shape3 = tvg::Shape::gen(); shape3->moveTo(520, 350); @@ -52,7 +52,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) shape3->stroke(10); shape3->stroke(tvg::StrokeJoin::Miter); shape3->stroke(tvg::StrokeCap::Butt); - canvas->push(move(shape3)); + if (canvas->push(move(shape3)) != tvg::Result::Success) return; //Test for Stroke Dash auto shape4 = tvg::Shape::gen(); @@ -68,7 +68,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) float dashPattern1[2] = {10, 10}; shape4->stroke(dashPattern1, 2); - canvas->push(move(shape4)); + if (canvas->push(move(shape4)) != tvg::Result::Success) return; auto shape5 = tvg::Shape::gen(); shape5->moveTo(270, 600); @@ -83,7 +83,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) float dashPattern2[4] = {10, 10}; shape5->stroke(dashPattern2, 4); - canvas->push(move(shape5)); + if (canvas->push(move(shape5)) != tvg::Result::Success) return; auto shape6 = tvg::Shape::gen(); shape6->moveTo(520, 600); @@ -98,7 +98,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) float dashPattern3[2] = {10, 10}; shape6->stroke(dashPattern3, 2); - canvas->push(move(shape6)); + if (canvas->push(move(shape6)) != tvg::Result::Success) return; } @@ -123,8 +123,9 @@ void tvgSwTest(uint32_t* buffer) void drawSwView(void* data, Eo* obj) { - swCanvas->draw(); - swCanvas->sync(); + if (swCanvas->draw() == tvg::Result::Success) { + swCanvas->sync(); + } } @@ -161,8 +162,9 @@ void drawGLview(Evas_Object *obj) gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); gl->glEnable(GL_BLEND); - glCanvas->draw(); - glCanvas->sync(); + if (glCanvas->draw() == tvg::Result::Success) { + glCanvas->sync(); + } } diff --git a/test/testSvg.cpp b/test/testSvg.cpp index 4da0349..13f3e4c 100644 --- a/test/testSvg.cpp +++ b/test/testSvg.cpp @@ -16,10 +16,11 @@ void svgDirCallback(const char* name, const char* path, void* data) auto scene = tvg::Scene::gen(); - char buf[255]; + char buf[PATH_MAX]; sprintf(buf,"%s/%s", path, name); - scene->load(buf); + if (scene->load(buf) != tvg::Result::Success) return; + scene->translate(((WIDTH - (x * 2)) / NUM_PER_LINE) * (count % NUM_PER_LINE) + x, ((HEIGHT - (y * 2))/ NUM_PER_LINE) * (int)((float)count / (float)NUM_PER_LINE) + y); canvas->push(move(scene)); @@ -30,11 +31,12 @@ void svgDirCallback(const char* name, const char* path, void* data) void tvgDrawCmds(tvg::Canvas* canvas) { - auto shape1 = tvg::Shape::gen(); - shape1->appendRect(0, 0, WIDTH, HEIGHT, 0); //x, y, w, h, cornerRadius - shape1->fill(255, 255, 255, 255); //r, g, b, a + //Background + auto shape = tvg::Shape::gen(); + shape->appendRect(0, 0, WIDTH, HEIGHT, 0); //x, y, w, h, cornerRadius + shape->fill(255, 255, 255, 255); //r, g, b, a - canvas->push(move(shape1)); + if (canvas->push(move(shape)) != tvg::Result::Success) return; eina_file_dir_list("./svgs", EINA_TRUE, svgDirCallback, canvas); } @@ -61,8 +63,9 @@ void tvgSwTest(uint32_t* buffer) void drawSwView(void* data, Eo* obj) { - swCanvas->draw(); - swCanvas->sync(); + if (swCanvas->draw() == tvg::Result::Success) { + swCanvas->sync(); + } } @@ -99,8 +102,9 @@ void drawGLview(Evas_Object *obj) gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); gl->glEnable(GL_BLEND); - glCanvas->draw(); - glCanvas->sync(); + if (glCanvas->draw() == tvg::Result::Success) { + glCanvas->sync(); + } } diff --git a/test/testTransform.cpp b/test/testTransform.cpp index c017f24..7376f97 100644 --- a/test/testTransform.cpp +++ b/test/testTransform.cpp @@ -22,7 +22,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) shape->appendCircle(115, 200, 170, 100); shape->fill(255, 255, 255, 255); shape->translate(385, 400); - canvas->push(move(shape)); + if (canvas->push(move(shape)) != tvg::Result::Success) return; //Shape2 auto shape2 = tvg::Shape::gen(); @@ -30,7 +30,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) shape2->appendRect(-50, -50, 100, 100, 0); shape2->fill(0, 255, 255, 255); shape2->translate(400, 400); - canvas->push(move(shape2)); + if (canvas->push(move(shape2)) != tvg::Result::Success) return; //Shape3 auto shape3 = tvg::Shape::gen(); @@ -41,7 +41,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) shape3->appendRect(100, 100, 150, 50, 20); shape3->fill(255, 0, 255, 255); shape3->translate(400, 400); - canvas->push(move(shape3)); + if (canvas->push(move(shape3)) != tvg::Result::Success) return; } void tvgUpdateCmds(tvg::Canvas* canvas, float progress) @@ -55,17 +55,17 @@ void tvgUpdateCmds(tvg::Canvas* canvas, float progress) pShape->rotate(360 * progress); //Update shape for drawing (this may work asynchronously) - canvas->update(pShape); + if (canvas->update(pShape) != tvg::Result::Success) return; //Update Shape2 pShape2->rotate(360 * progress); pShape2->translate(400 + progress * 300, 400); - canvas->update(pShape2); + if (canvas->update(pShape2) != tvg::Result::Success) return; //Update Shape3 pShape3->rotate(-360 * progress); pShape3->scale(0.5 + progress); - canvas->update(pShape3); + if (canvas->update(pShape3) != tvg::Result::Success) return; } @@ -100,8 +100,9 @@ void transitSwCb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progre void drawSwView(void* data, Eo* obj) { - swCanvas->draw(); - swCanvas->sync(); + if (swCanvas->draw() == tvg::Result::Success) { + swCanvas->sync(); + } } @@ -138,8 +139,9 @@ void drawGLview(Evas_Object *obj) gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); gl->glEnable(GL_BLEND); - glCanvas->draw(); - glCanvas->sync(); + if (glCanvas->draw() == tvg::Result::Success) { + glCanvas->sync(); + } } void transitGlCb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) diff --git a/test/testUpdate.cpp b/test/testUpdate.cpp index d28207a..e1b0212 100644 --- a/test/testUpdate.cpp +++ b/test/testUpdate.cpp @@ -16,7 +16,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) void tvgUpdateCmds(tvg::Canvas* canvas, float progress) { //Explicitly clear all retained paint nodes. - canvas->clear(); + if (canvas->clear() != tvg::Result::Success) return; //Shape auto shape = tvg::Shape::gen(); @@ -61,8 +61,9 @@ void transitSwCb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progre void drawSwView(void* data, Eo* obj) { - swCanvas->draw(); - swCanvas->sync(); + if (swCanvas->draw() == tvg::Result::Success) { + swCanvas->sync(); + } } @@ -99,8 +100,9 @@ void drawGLview(Evas_Object *obj) gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); gl->glEnable(GL_BLEND); - glCanvas->draw(); - glCanvas->sync(); + if (glCanvas->draw() == tvg::Result::Success) { + glCanvas->sync(); + } } void transitGlCb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) -- 2.7.4 From f377f339935f60eb276a0eee7648863746413a59 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 30 Jun 2020 16:57:31 +0900 Subject: [PATCH 16/16] sw_engine: fix to update stroking transform when shape doesn't have fill color, stroking is missed in update. this fixs that issue. Change-Id: I49292475e56caa834e79497a16db705b965bcf5f --- src/lib/sw_engine/tvgSwRenderer.cpp | 17 ++++++++++------- src/lib/sw_engine/tvgSwShape.cpp | 5 ++++- test/testCustomTransform.cpp | 4 +++- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 4f09c60..f6fc88b 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -175,12 +175,19 @@ void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* task->flags = flags; auto asyncTask = [](SwTask* task) { + + //Valid Stroking? + uint8_t strokeAlpha = 0; + if (task->sdata->strokeWidth() > FLT_EPSILON) { + task->sdata->strokeColor(nullptr, nullptr, nullptr, &strokeAlpha); + } + //Shape if (task->flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Transform)) { shapeReset(task->shape); uint8_t alpha = 0; task->sdata->fill(nullptr, nullptr, nullptr, &alpha); - if (alpha > 0 || task->sdata->fill()) { + if (alpha > 0 || task->sdata->fill() || strokeAlpha > 0) { if (!shapeGenRle(task->shape, task->sdata, task->clip, task->transform)) return; } } @@ -197,13 +204,9 @@ void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* } //Stroke if (task->flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) { - if (task->sdata->strokeWidth() > FLT_EPSILON) { + if (strokeAlpha > 0) { shapeResetStroke(task->shape, task->sdata); - uint8_t alpha = 0; - task->sdata->strokeColor(nullptr, nullptr, nullptr, &alpha); - if (alpha > 0) { - if (!shapeGenStrokeRle(task->shape, task->sdata, task->clip)) return; - } + if (!shapeGenStrokeRle(task->shape, task->sdata, task->clip)) return; } else { shapeDelStroke(task->shape); } diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 29ecf27..a4c811a 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -211,7 +211,7 @@ static bool _updateBBox(SwOutline* outline, SwBBox& bbox) bbox.min.y = yMin >> 6; bbox.max.y = (yMax + 63) >> 6; - if (xMax - xMin < 1 || yMax - yMin < 1) return false; + if (xMax - xMin < 1 && yMax - yMin < 1) return false; return true; } @@ -451,6 +451,9 @@ bool shapeGenRle(SwShape& shape, const Shape* sdata, const SwSize& clip, const M if (!_checkValid(shape.outline, shape.bbox, clip)) goto end; + //Case: Stroke Line + if (shape.outline->opened) return true; + shape.rle = rleRender(shape.outline, shape.bbox, clip); end: if (shape.rle) return true; diff --git a/test/testCustomTransform.cpp b/test/testCustomTransform.cpp index d87b481..27e3c6e 100644 --- a/test/testCustomTransform.cpp +++ b/test/testCustomTransform.cpp @@ -26,6 +26,8 @@ void tvgDrawCmds(tvg::Canvas* canvas) shape->lineTo(-53, -5.5); shape->close(); shape->fill(0, 0, 255, 255); + shape->stroke(3); + shape->stroke(255, 255, 255, 255); if (canvas->push(move(shape)) != tvg::Result::Success) return; } @@ -203,4 +205,4 @@ int main(int argc, char **argv) //Terminate ThorVG Engine tvg::Initializer::term(tvgEngine); -} \ No newline at end of file +} -- 2.7.4